/src/openssl30/crypto/bio/bss_conn.c
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | /* | 
| 2 |  |  * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. | 
| 3 |  |  * | 
| 4 |  |  * Licensed under the Apache License 2.0 (the "License").  You may not use | 
| 5 |  |  * this file except in compliance with the License.  You can obtain a copy | 
| 6 |  |  * in the file LICENSE in the source distribution or at | 
| 7 |  |  * https://www.openssl.org/source/license.html | 
| 8 |  |  */ | 
| 9 |  |  | 
| 10 |  | #include <stdio.h> | 
| 11 |  | #include <errno.h> | 
| 12 |  |  | 
| 13 |  | #include "bio_local.h" | 
| 14 |  | #include "internal/ktls.h" | 
| 15 |  |  | 
| 16 |  | #ifndef OPENSSL_NO_SOCK | 
| 17 |  |  | 
| 18 |  | typedef struct bio_connect_st { | 
| 19 |  |     int state; | 
| 20 |  |     int connect_family; | 
| 21 |  |     char *param_hostname; | 
| 22 |  |     char *param_service; | 
| 23 |  |     int connect_mode; | 
| 24 |  | # ifndef OPENSSL_NO_KTLS | 
| 25 |  |     unsigned char record_type; | 
| 26 |  | # endif | 
| 27 |  |  | 
| 28 |  |     BIO_ADDRINFO *addr_first; | 
| 29 |  |     const BIO_ADDRINFO *addr_iter; | 
| 30 |  |     /* | 
| 31 |  |      * int socket; this will be kept in bio->num so that it is compatible | 
| 32 |  |      * with the bss_sock bio | 
| 33 |  |      */ | 
| 34 |  |     /* | 
| 35 |  |      * called when the connection is initially made callback(BIO,state,ret); | 
| 36 |  |      * The callback should return 'ret'.  state is for compatibility with the | 
| 37 |  |      * ssl info_callback | 
| 38 |  |      */ | 
| 39 |  |     BIO_info_cb *info_callback; | 
| 40 |  | } BIO_CONNECT; | 
| 41 |  |  | 
| 42 |  | static int conn_write(BIO *h, const char *buf, int num); | 
| 43 |  | static int conn_read(BIO *h, char *buf, int size); | 
| 44 |  | static int conn_puts(BIO *h, const char *str); | 
| 45 |  | static long conn_ctrl(BIO *h, int cmd, long arg1, void *arg2); | 
| 46 |  | static int conn_new(BIO *h); | 
| 47 |  | static int conn_free(BIO *data); | 
| 48 |  | static long conn_callback_ctrl(BIO *h, int cmd, BIO_info_cb *); | 
| 49 |  |  | 
| 50 |  | static int conn_state(BIO *b, BIO_CONNECT *c); | 
| 51 |  | static void conn_close_socket(BIO *data); | 
| 52 |  | BIO_CONNECT *BIO_CONNECT_new(void); | 
| 53 |  | void BIO_CONNECT_free(BIO_CONNECT *a); | 
| 54 |  |  | 
| 55 | 0 | #define BIO_CONN_S_BEFORE                1 | 
| 56 | 0 | #define BIO_CONN_S_GET_ADDR              2 | 
| 57 | 0 | #define BIO_CONN_S_CREATE_SOCKET         3 | 
| 58 | 0 | #define BIO_CONN_S_CONNECT               4 | 
| 59 | 0 | #define BIO_CONN_S_OK                    5 | 
| 60 | 0 | #define BIO_CONN_S_BLOCKED_CONNECT       6 | 
| 61 | 0 | #define BIO_CONN_S_CONNECT_ERROR         7 | 
| 62 |  |  | 
| 63 |  | static const BIO_METHOD methods_connectp = { | 
| 64 |  |     BIO_TYPE_CONNECT, | 
| 65 |  |     "socket connect", | 
| 66 |  |     bwrite_conv, | 
| 67 |  |     conn_write, | 
| 68 |  |     bread_conv, | 
| 69 |  |     conn_read, | 
| 70 |  |     conn_puts, | 
| 71 |  |     NULL,                       /* conn_gets, */ | 
| 72 |  |     conn_ctrl, | 
| 73 |  |     conn_new, | 
| 74 |  |     conn_free, | 
| 75 |  |     conn_callback_ctrl, | 
| 76 |  | }; | 
| 77 |  |  | 
| 78 |  | static int conn_state(BIO *b, BIO_CONNECT *c) | 
| 79 | 0 | { | 
| 80 | 0 |     int ret = -1, i; | 
| 81 | 0 |     BIO_info_cb *cb = NULL; | 
| 82 |  | 
 | 
| 83 | 0 |     if (c->info_callback != NULL) | 
| 84 | 0 |         cb = c->info_callback; | 
| 85 |  | 
 | 
| 86 | 0 |     for (;;) { | 
| 87 | 0 |         switch (c->state) { | 
| 88 | 0 |         case BIO_CONN_S_BEFORE: | 
| 89 | 0 |             if (c->param_hostname == NULL && c->param_service == NULL) { | 
| 90 | 0 |                 ERR_raise_data(ERR_LIB_BIO, | 
| 91 | 0 |                                BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED, | 
| 92 | 0 |                                "hostname=%s service=%s", | 
| 93 | 0 |                                c->param_hostname, c->param_service); | 
| 94 | 0 |                 goto exit_loop; | 
| 95 | 0 |             } | 
| 96 | 0 |             c->state = BIO_CONN_S_GET_ADDR; | 
| 97 | 0 |             break; | 
| 98 |  |  | 
| 99 | 0 |         case BIO_CONN_S_GET_ADDR: | 
| 100 | 0 |             { | 
| 101 | 0 |                 int family = AF_UNSPEC; | 
| 102 | 0 |                 switch (c->connect_family) { | 
| 103 | 0 |                 case BIO_FAMILY_IPV6: | 
| 104 | 0 |                     if (1) { /* This is a trick we use to avoid bit rot. | 
| 105 |  |                               * at least the "else" part will always be | 
| 106 |  |                               * compiled. | 
| 107 |  |                               */ | 
| 108 | 0 | #ifdef AF_INET6 | 
| 109 | 0 |                         family = AF_INET6; | 
| 110 | 0 |                     } else { | 
| 111 | 0 | #endif | 
| 112 | 0 |                         ERR_raise(ERR_LIB_BIO, BIO_R_UNAVAILABLE_IP_FAMILY); | 
| 113 | 0 |                         goto exit_loop; | 
| 114 | 0 |                     } | 
| 115 | 0 |                     break; | 
| 116 | 0 |                 case BIO_FAMILY_IPV4: | 
| 117 | 0 |                     family = AF_INET; | 
| 118 | 0 |                     break; | 
| 119 | 0 |                 case BIO_FAMILY_IPANY: | 
| 120 | 0 |                     family = AF_UNSPEC; | 
| 121 | 0 |                     break; | 
| 122 | 0 |                 default: | 
| 123 | 0 |                     ERR_raise(ERR_LIB_BIO, BIO_R_UNSUPPORTED_IP_FAMILY); | 
| 124 | 0 |                     goto exit_loop; | 
| 125 | 0 |                 } | 
| 126 | 0 |                 if (BIO_lookup(c->param_hostname, c->param_service, | 
| 127 | 0 |                                BIO_LOOKUP_CLIENT, | 
| 128 | 0 |                                family, SOCK_STREAM, &c->addr_first) == 0) | 
| 129 | 0 |                     goto exit_loop; | 
| 130 | 0 |             } | 
| 131 | 0 |             if (c->addr_first == NULL) { | 
| 132 | 0 |                 ERR_raise(ERR_LIB_BIO, BIO_R_LOOKUP_RETURNED_NOTHING); | 
| 133 | 0 |                 goto exit_loop; | 
| 134 | 0 |             } | 
| 135 | 0 |             c->addr_iter = c->addr_first; | 
| 136 | 0 |             c->state = BIO_CONN_S_CREATE_SOCKET; | 
| 137 | 0 |             break; | 
| 138 |  |  | 
| 139 | 0 |         case BIO_CONN_S_CREATE_SOCKET: | 
| 140 | 0 |             ret = BIO_socket(BIO_ADDRINFO_family(c->addr_iter), | 
| 141 | 0 |                              BIO_ADDRINFO_socktype(c->addr_iter), | 
| 142 | 0 |                              BIO_ADDRINFO_protocol(c->addr_iter), 0); | 
| 143 | 0 |             if (ret == (int)INVALID_SOCKET) { | 
| 144 | 0 |                 ERR_raise_data(ERR_LIB_SYS, get_last_socket_error(), | 
| 145 | 0 |                                "calling socket(%s, %s)", | 
| 146 | 0 |                                c->param_hostname, c->param_service); | 
| 147 | 0 |                 ERR_raise(ERR_LIB_BIO, BIO_R_UNABLE_TO_CREATE_SOCKET); | 
| 148 | 0 |                 goto exit_loop; | 
| 149 | 0 |             } | 
| 150 | 0 |             b->num = ret; | 
| 151 | 0 |             c->state = BIO_CONN_S_CONNECT; | 
| 152 | 0 |             break; | 
| 153 |  |  | 
| 154 | 0 |         case BIO_CONN_S_CONNECT: | 
| 155 | 0 |             BIO_clear_retry_flags(b); | 
| 156 | 0 |             ERR_set_mark(); | 
| 157 | 0 |             ret = BIO_connect(b->num, BIO_ADDRINFO_address(c->addr_iter), | 
| 158 | 0 |                               BIO_SOCK_KEEPALIVE | c->connect_mode); | 
| 159 | 0 |             b->retry_reason = 0; | 
| 160 | 0 |             if (ret == 0) { | 
| 161 | 0 |                 if (BIO_sock_should_retry(ret)) { | 
| 162 | 0 |                     BIO_set_retry_special(b); | 
| 163 | 0 |                     c->state = BIO_CONN_S_BLOCKED_CONNECT; | 
| 164 | 0 |                     b->retry_reason = BIO_RR_CONNECT; | 
| 165 | 0 |                     ERR_pop_to_mark(); | 
| 166 | 0 |                 } else if ((c->addr_iter = BIO_ADDRINFO_next(c->addr_iter)) | 
| 167 | 0 |                            != NULL) { | 
| 168 |  |                     /* | 
| 169 |  |                      * if there are more addresses to try, do that first | 
| 170 |  |                      */ | 
| 171 | 0 |                     BIO_closesocket(b->num); | 
| 172 | 0 |                     c->state = BIO_CONN_S_CREATE_SOCKET; | 
| 173 | 0 |                     ERR_pop_to_mark(); | 
| 174 | 0 |                     break; | 
| 175 | 0 |                 } else { | 
| 176 | 0 |                     ERR_clear_last_mark(); | 
| 177 | 0 |                     ERR_raise_data(ERR_LIB_SYS, get_last_socket_error(), | 
| 178 | 0 |                                    "calling connect(%s, %s)", | 
| 179 | 0 |                                     c->param_hostname, c->param_service); | 
| 180 | 0 |                     c->state = BIO_CONN_S_CONNECT_ERROR; | 
| 181 | 0 |                     break; | 
| 182 | 0 |                 } | 
| 183 | 0 |                 goto exit_loop; | 
| 184 | 0 |             } else { | 
| 185 | 0 |                 ERR_clear_last_mark(); | 
| 186 | 0 |                 c->state = BIO_CONN_S_OK; | 
| 187 | 0 |             } | 
| 188 | 0 |             break; | 
| 189 |  |  | 
| 190 | 0 |         case BIO_CONN_S_BLOCKED_CONNECT: | 
| 191 |  |             /* wait for socket being writable, before querying BIO_sock_error */ | 
| 192 | 0 |             if (BIO_socket_wait(b->num, 0, time(NULL)) == 0) | 
| 193 | 0 |                 break; | 
| 194 | 0 |             i = BIO_sock_error(b->num); | 
| 195 | 0 |             if (i != 0) { | 
| 196 | 0 |                 BIO_clear_retry_flags(b); | 
| 197 | 0 |                 if ((c->addr_iter = BIO_ADDRINFO_next(c->addr_iter)) != NULL) { | 
| 198 |  |                     /* | 
| 199 |  |                      * if there are more addresses to try, do that first | 
| 200 |  |                      */ | 
| 201 | 0 |                     BIO_closesocket(b->num); | 
| 202 | 0 |                     c->state = BIO_CONN_S_CREATE_SOCKET; | 
| 203 | 0 |                     break; | 
| 204 | 0 |                 } | 
| 205 | 0 |                 ERR_raise_data(ERR_LIB_SYS, i, | 
| 206 | 0 |                                "calling connect(%s, %s)", | 
| 207 | 0 |                                 c->param_hostname, c->param_service); | 
| 208 | 0 |                 ERR_raise(ERR_LIB_BIO, BIO_R_NBIO_CONNECT_ERROR); | 
| 209 | 0 |                 ret = 0; | 
| 210 | 0 |                 goto exit_loop; | 
| 211 | 0 |             } else { | 
| 212 | 0 |                 c->state = BIO_CONN_S_OK; | 
| 213 |  | # ifndef OPENSSL_NO_KTLS | 
| 214 |  |                 /* | 
| 215 |  |                  * The new socket is created successfully regardless of ktls_enable. | 
| 216 |  |                  * ktls_enable doesn't change any functionality of the socket, except | 
| 217 |  |                  * changing the setsockopt to enable the processing of ktls_start. | 
| 218 |  |                  * Thus, it is not a problem to call it for non-TLS sockets. | 
| 219 |  |                  */ | 
| 220 |  |                 ktls_enable(b->num); | 
| 221 |  | # endif | 
| 222 | 0 |             } | 
| 223 | 0 |             break; | 
| 224 |  |  | 
| 225 | 0 |         case BIO_CONN_S_CONNECT_ERROR: | 
| 226 | 0 |             ERR_raise(ERR_LIB_BIO, BIO_R_CONNECT_ERROR); | 
| 227 | 0 |             ret = 0; | 
| 228 | 0 |             goto exit_loop; | 
| 229 |  |  | 
| 230 | 0 |         case BIO_CONN_S_OK: | 
| 231 | 0 |             ret = 1; | 
| 232 | 0 |             goto exit_loop; | 
| 233 | 0 |         default: | 
| 234 |  |             /* abort(); */ | 
| 235 | 0 |             goto exit_loop; | 
| 236 | 0 |         } | 
| 237 |  |  | 
| 238 | 0 |         if (cb != NULL) { | 
| 239 | 0 |             if ((ret = cb((BIO *)b, c->state, ret)) == 0) | 
| 240 | 0 |                 goto end; | 
| 241 | 0 |         } | 
| 242 | 0 |     } | 
| 243 |  |  | 
| 244 |  |     /* Loop does not exit */ | 
| 245 | 0 |  exit_loop: | 
| 246 | 0 |     if (cb != NULL) | 
| 247 | 0 |         ret = cb((BIO *)b, c->state, ret); | 
| 248 | 0 |  end: | 
| 249 | 0 |     return ret; | 
| 250 | 0 | } | 
| 251 |  |  | 
| 252 |  | BIO_CONNECT *BIO_CONNECT_new(void) | 
| 253 | 0 | { | 
| 254 | 0 |     BIO_CONNECT *ret; | 
| 255 |  | 
 | 
| 256 | 0 |     if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) { | 
| 257 | 0 |         ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE); | 
| 258 | 0 |         return NULL; | 
| 259 | 0 |     } | 
| 260 | 0 |     ret->state = BIO_CONN_S_BEFORE; | 
| 261 | 0 |     ret->connect_family = BIO_FAMILY_IPANY; | 
| 262 | 0 |     return ret; | 
| 263 | 0 | } | 
| 264 |  |  | 
| 265 |  | void BIO_CONNECT_free(BIO_CONNECT *a) | 
| 266 | 0 | { | 
| 267 | 0 |     if (a == NULL) | 
| 268 | 0 |         return; | 
| 269 | 0 |     OPENSSL_free(a->param_hostname); | 
| 270 | 0 |     OPENSSL_free(a->param_service); | 
| 271 | 0 |     BIO_ADDRINFO_free(a->addr_first); | 
| 272 | 0 |     OPENSSL_free(a); | 
| 273 | 0 | } | 
| 274 |  |  | 
| 275 |  | const BIO_METHOD *BIO_s_connect(void) | 
| 276 | 0 | { | 
| 277 | 0 |     return &methods_connectp; | 
| 278 | 0 | } | 
| 279 |  |  | 
| 280 |  | static int conn_new(BIO *bi) | 
| 281 | 0 | { | 
| 282 | 0 |     bi->init = 0; | 
| 283 | 0 |     bi->num = (int)INVALID_SOCKET; | 
| 284 | 0 |     bi->flags = 0; | 
| 285 | 0 |     if ((bi->ptr = (char *)BIO_CONNECT_new()) == NULL) | 
| 286 | 0 |         return 0; | 
| 287 | 0 |     else | 
| 288 | 0 |         return 1; | 
| 289 | 0 | } | 
| 290 |  |  | 
| 291 |  | static void conn_close_socket(BIO *bio) | 
| 292 | 0 | { | 
| 293 | 0 |     BIO_CONNECT *c; | 
| 294 |  | 
 | 
| 295 | 0 |     c = (BIO_CONNECT *)bio->ptr; | 
| 296 | 0 |     if (bio->num != (int)INVALID_SOCKET) { | 
| 297 |  |         /* Only do a shutdown if things were established */ | 
| 298 | 0 |         if (c->state == BIO_CONN_S_OK) | 
| 299 | 0 |             shutdown(bio->num, 2); | 
| 300 | 0 |         BIO_closesocket(bio->num); | 
| 301 | 0 |         bio->num = (int)INVALID_SOCKET; | 
| 302 | 0 |     } | 
| 303 | 0 | } | 
| 304 |  |  | 
| 305 |  | static int conn_free(BIO *a) | 
| 306 | 0 | { | 
| 307 | 0 |     BIO_CONNECT *data; | 
| 308 |  | 
 | 
| 309 | 0 |     if (a == NULL) | 
| 310 | 0 |         return 0; | 
| 311 | 0 |     data = (BIO_CONNECT *)a->ptr; | 
| 312 |  | 
 | 
| 313 | 0 |     if (a->shutdown) { | 
| 314 | 0 |         conn_close_socket(a); | 
| 315 | 0 |         BIO_CONNECT_free(data); | 
| 316 | 0 |         a->ptr = NULL; | 
| 317 | 0 |         a->flags = 0; | 
| 318 | 0 |         a->init = 0; | 
| 319 | 0 |     } | 
| 320 | 0 |     return 1; | 
| 321 | 0 | } | 
| 322 |  |  | 
| 323 |  | static int conn_read(BIO *b, char *out, int outl) | 
| 324 | 0 | { | 
| 325 | 0 |     int ret = 0; | 
| 326 | 0 |     BIO_CONNECT *data; | 
| 327 |  | 
 | 
| 328 | 0 |     data = (BIO_CONNECT *)b->ptr; | 
| 329 | 0 |     if (data->state != BIO_CONN_S_OK) { | 
| 330 | 0 |         ret = conn_state(b, data); | 
| 331 | 0 |         if (ret <= 0) | 
| 332 | 0 |             return ret; | 
| 333 | 0 |     } | 
| 334 |  |  | 
| 335 | 0 |     if (out != NULL) { | 
| 336 | 0 |         clear_socket_error(); | 
| 337 |  | # ifndef OPENSSL_NO_KTLS | 
| 338 |  |         if (BIO_get_ktls_recv(b)) | 
| 339 |  |             ret = ktls_read_record(b->num, out, outl); | 
| 340 |  |         else | 
| 341 |  | # endif | 
| 342 | 0 |             ret = readsocket(b->num, out, outl); | 
| 343 | 0 |         BIO_clear_retry_flags(b); | 
| 344 | 0 |         if (ret <= 0) { | 
| 345 | 0 |             if (BIO_sock_should_retry(ret)) | 
| 346 | 0 |                 BIO_set_retry_read(b); | 
| 347 | 0 |             else if (ret == 0) | 
| 348 | 0 |                 b->flags |= BIO_FLAGS_IN_EOF; | 
| 349 | 0 |         } | 
| 350 | 0 |     } | 
| 351 | 0 |     return ret; | 
| 352 | 0 | } | 
| 353 |  |  | 
| 354 |  | static int conn_write(BIO *b, const char *in, int inl) | 
| 355 | 0 | { | 
| 356 | 0 |     int ret; | 
| 357 | 0 |     BIO_CONNECT *data; | 
| 358 |  | 
 | 
| 359 | 0 |     data = (BIO_CONNECT *)b->ptr; | 
| 360 | 0 |     if (data->state != BIO_CONN_S_OK) { | 
| 361 | 0 |         ret = conn_state(b, data); | 
| 362 | 0 |         if (ret <= 0) | 
| 363 | 0 |             return ret; | 
| 364 | 0 |     } | 
| 365 |  |  | 
| 366 | 0 |     clear_socket_error(); | 
| 367 |  | # ifndef OPENSSL_NO_KTLS | 
| 368 |  |     if (BIO_should_ktls_ctrl_msg_flag(b)) { | 
| 369 |  |         ret = ktls_send_ctrl_message(b->num, data->record_type, in, inl); | 
| 370 |  |         if (ret >= 0) { | 
| 371 |  |             ret = inl; | 
| 372 |  |             BIO_clear_ktls_ctrl_msg_flag(b); | 
| 373 |  |         } | 
| 374 |  |     } else | 
| 375 |  | # endif | 
| 376 | 0 |         ret = writesocket(b->num, in, inl); | 
| 377 | 0 |     BIO_clear_retry_flags(b); | 
| 378 | 0 |     if (ret <= 0) { | 
| 379 | 0 |         if (BIO_sock_should_retry(ret)) | 
| 380 | 0 |             BIO_set_retry_write(b); | 
| 381 | 0 |     } | 
| 382 | 0 |     return ret; | 
| 383 | 0 | } | 
| 384 |  |  | 
| 385 |  | static long conn_ctrl(BIO *b, int cmd, long num, void *ptr) | 
| 386 | 0 | { | 
| 387 | 0 |     BIO *dbio; | 
| 388 | 0 |     int *ip; | 
| 389 | 0 |     const char **pptr = NULL; | 
| 390 | 0 |     long ret = 1; | 
| 391 | 0 |     BIO_CONNECT *data; | 
| 392 |  | # ifndef OPENSSL_NO_KTLS | 
| 393 |  |     ktls_crypto_info_t *crypto_info; | 
| 394 |  | # endif | 
| 395 |  | 
 | 
| 396 | 0 |     data = (BIO_CONNECT *)b->ptr; | 
| 397 |  | 
 | 
| 398 | 0 |     switch (cmd) { | 
| 399 | 0 |     case BIO_CTRL_RESET: | 
| 400 | 0 |         ret = 0; | 
| 401 | 0 |         data->state = BIO_CONN_S_BEFORE; | 
| 402 | 0 |         conn_close_socket(b); | 
| 403 | 0 |         BIO_ADDRINFO_free(data->addr_first); | 
| 404 | 0 |         data->addr_first = NULL; | 
| 405 | 0 |         b->flags = 0; | 
| 406 | 0 |         break; | 
| 407 | 0 |     case BIO_C_DO_STATE_MACHINE: | 
| 408 |  |         /* use this one to start the connection */ | 
| 409 | 0 |         if (data->state != BIO_CONN_S_OK) | 
| 410 | 0 |             ret = (long)conn_state(b, data); | 
| 411 | 0 |         else | 
| 412 | 0 |             ret = 1; | 
| 413 | 0 |         break; | 
| 414 | 0 |     case BIO_C_GET_CONNECT: | 
| 415 | 0 |         if (ptr != NULL) { | 
| 416 | 0 |             pptr = (const char **)ptr; | 
| 417 | 0 |             if (num == 0) { | 
| 418 | 0 |                 *pptr = data->param_hostname; | 
| 419 | 0 |             } else if (num == 1) { | 
| 420 | 0 |                 *pptr = data->param_service; | 
| 421 | 0 |             } else if (num == 2) { | 
| 422 | 0 |                 *pptr = (const char *)BIO_ADDRINFO_address(data->addr_iter); | 
| 423 | 0 |             } else if (num == 3) { | 
| 424 | 0 |                 switch (BIO_ADDRINFO_family(data->addr_iter)) { | 
| 425 | 0 | # ifdef AF_INET6 | 
| 426 | 0 |                 case AF_INET6: | 
| 427 | 0 |                     ret = BIO_FAMILY_IPV6; | 
| 428 | 0 |                     break; | 
| 429 | 0 | # endif | 
| 430 | 0 |                 case AF_INET: | 
| 431 | 0 |                     ret = BIO_FAMILY_IPV4; | 
| 432 | 0 |                     break; | 
| 433 | 0 |                 case 0: | 
| 434 | 0 |                     ret = data->connect_family; | 
| 435 | 0 |                     break; | 
| 436 | 0 |                 default: | 
| 437 | 0 |                     ret = -1; | 
| 438 | 0 |                     break; | 
| 439 | 0 |                 } | 
| 440 | 0 |             } else { | 
| 441 | 0 |                 ret = 0; | 
| 442 | 0 |             } | 
| 443 | 0 |         } else { | 
| 444 | 0 |             ret = 0; | 
| 445 | 0 |         } | 
| 446 | 0 |         break; | 
| 447 | 0 |     case BIO_C_SET_CONNECT: | 
| 448 | 0 |         if (ptr != NULL) { | 
| 449 | 0 |             b->init = 1; | 
| 450 | 0 |             if (num == 0) { /* BIO_set_conn_hostname */ | 
| 451 | 0 |                 char *hold_service = data->param_service; | 
| 452 |  |                 /* We affect the hostname regardless.  However, the input | 
| 453 |  |                  * string might contain a host:service spec, so we must | 
| 454 |  |                  * parse it, which might or might not affect the service | 
| 455 |  |                  */ | 
| 456 |  | 
 | 
| 457 | 0 |                 OPENSSL_free(data->param_hostname); | 
| 458 | 0 |                 data->param_hostname = NULL; | 
| 459 | 0 |                 ret = BIO_parse_hostserv(ptr, | 
| 460 | 0 |                                          &data->param_hostname, | 
| 461 | 0 |                                          &data->param_service, | 
| 462 | 0 |                                          BIO_PARSE_PRIO_HOST); | 
| 463 | 0 |                 if (hold_service != data->param_service) | 
| 464 | 0 |                     OPENSSL_free(hold_service); | 
| 465 | 0 |             } else if (num == 1) { /* BIO_set_conn_port */ | 
| 466 | 0 |                 OPENSSL_free(data->param_service); | 
| 467 | 0 |                 if ((data->param_service = OPENSSL_strdup(ptr)) == NULL) | 
| 468 | 0 |                     ret = 0; | 
| 469 | 0 |             } else if (num == 2) { /* BIO_set_conn_address */ | 
| 470 | 0 |                 const BIO_ADDR *addr = (const BIO_ADDR *)ptr; | 
| 471 | 0 |                 char *host = BIO_ADDR_hostname_string(addr, 1); | 
| 472 | 0 |                 char *service = BIO_ADDR_service_string(addr, 1); | 
| 473 |  | 
 | 
| 474 | 0 |                 ret = host != NULL && service != NULL; | 
| 475 | 0 |                 if (ret) { | 
| 476 | 0 |                     OPENSSL_free(data->param_hostname); | 
| 477 | 0 |                     data->param_hostname = host; | 
| 478 | 0 |                     OPENSSL_free(data->param_service); | 
| 479 | 0 |                     data->param_service = service; | 
| 480 | 0 |                     BIO_ADDRINFO_free(data->addr_first); | 
| 481 | 0 |                     data->addr_first = NULL; | 
| 482 | 0 |                     data->addr_iter = NULL; | 
| 483 | 0 |                 } else { | 
| 484 | 0 |                     OPENSSL_free(host); | 
| 485 | 0 |                     OPENSSL_free(service); | 
| 486 | 0 |                 } | 
| 487 | 0 |             } else if (num == 3) { /* BIO_set_conn_ip_family */ | 
| 488 | 0 |                 data->connect_family = *(int *)ptr; | 
| 489 | 0 |             } else { | 
| 490 | 0 |                 ret = 0; | 
| 491 | 0 |             } | 
| 492 | 0 |         } | 
| 493 | 0 |         break; | 
| 494 | 0 |     case BIO_C_SET_NBIO: | 
| 495 | 0 |         if (num != 0) | 
| 496 | 0 |             data->connect_mode |= BIO_SOCK_NONBLOCK; | 
| 497 | 0 |         else | 
| 498 | 0 |             data->connect_mode &= ~BIO_SOCK_NONBLOCK; | 
| 499 | 0 |         break; | 
| 500 | 0 |     case BIO_C_SET_CONNECT_MODE: | 
| 501 | 0 |         data->connect_mode = (int)num; | 
| 502 | 0 |         break; | 
| 503 | 0 |     case BIO_C_GET_FD: | 
| 504 | 0 |         if (b->init) { | 
| 505 | 0 |             ip = (int *)ptr; | 
| 506 | 0 |             if (ip != NULL) | 
| 507 | 0 |                 *ip = b->num; | 
| 508 | 0 |             ret = b->num; | 
| 509 | 0 |         } else | 
| 510 | 0 |             ret = -1; | 
| 511 | 0 |         break; | 
| 512 | 0 |     case BIO_CTRL_GET_CLOSE: | 
| 513 | 0 |         ret = b->shutdown; | 
| 514 | 0 |         break; | 
| 515 | 0 |     case BIO_CTRL_SET_CLOSE: | 
| 516 | 0 |         b->shutdown = (int)num; | 
| 517 | 0 |         break; | 
| 518 | 0 |     case BIO_CTRL_PENDING: | 
| 519 | 0 |     case BIO_CTRL_WPENDING: | 
| 520 | 0 |         ret = 0; | 
| 521 | 0 |         break; | 
| 522 | 0 |     case BIO_CTRL_FLUSH: | 
| 523 | 0 |         break; | 
| 524 | 0 |     case BIO_CTRL_DUP: | 
| 525 | 0 |         { | 
| 526 | 0 |             dbio = (BIO *)ptr; | 
| 527 | 0 |             if (data->param_hostname) | 
| 528 | 0 |                 BIO_set_conn_hostname(dbio, data->param_hostname); | 
| 529 | 0 |             if (data->param_service) | 
| 530 | 0 |                 BIO_set_conn_port(dbio, data->param_service); | 
| 531 | 0 |             BIO_set_conn_ip_family(dbio, data->connect_family); | 
| 532 | 0 |             BIO_set_conn_mode(dbio, data->connect_mode); | 
| 533 |  |             /* | 
| 534 |  |              * FIXME: the cast of the function seems unlikely to be a good | 
| 535 |  |              * idea | 
| 536 |  |              */ | 
| 537 | 0 |             (void)BIO_set_info_callback(dbio, data->info_callback); | 
| 538 | 0 |         } | 
| 539 | 0 |         break; | 
| 540 | 0 |     case BIO_CTRL_SET_CALLBACK: | 
| 541 | 0 |         ret = 0; /* use callback ctrl */ | 
| 542 | 0 |         break; | 
| 543 | 0 |     case BIO_CTRL_GET_CALLBACK: | 
| 544 | 0 |         { | 
| 545 | 0 |             BIO_info_cb **fptr; | 
| 546 |  | 
 | 
| 547 | 0 |             fptr = (BIO_info_cb **)ptr; | 
| 548 | 0 |             *fptr = data->info_callback; | 
| 549 | 0 |         } | 
| 550 | 0 |         break; | 
| 551 | 0 |     case BIO_CTRL_EOF: | 
| 552 | 0 |         ret = (b->flags & BIO_FLAGS_IN_EOF) != 0; | 
| 553 | 0 |         break; | 
| 554 |  | # ifndef OPENSSL_NO_KTLS | 
| 555 |  |     case BIO_CTRL_SET_KTLS: | 
| 556 |  |         crypto_info = (ktls_crypto_info_t *)ptr; | 
| 557 |  |         ret = ktls_start(b->num, crypto_info, num); | 
| 558 |  |         if (ret) | 
| 559 |  |             BIO_set_ktls_flag(b, num); | 
| 560 |  |         break; | 
| 561 |  |     case BIO_CTRL_GET_KTLS_SEND: | 
| 562 |  |         return BIO_should_ktls_flag(b, 1) != 0; | 
| 563 |  |     case BIO_CTRL_GET_KTLS_RECV: | 
| 564 |  |         return BIO_should_ktls_flag(b, 0) != 0; | 
| 565 |  |     case BIO_CTRL_SET_KTLS_TX_SEND_CTRL_MSG: | 
| 566 |  |         BIO_set_ktls_ctrl_msg_flag(b); | 
| 567 |  |         data->record_type = num; | 
| 568 |  |         ret = 0; | 
| 569 |  |         break; | 
| 570 |  |     case BIO_CTRL_CLEAR_KTLS_TX_CTRL_MSG: | 
| 571 |  |         BIO_clear_ktls_ctrl_msg_flag(b); | 
| 572 |  |         ret = 0; | 
| 573 |  |         break; | 
| 574 |  | # endif | 
| 575 | 0 |     default: | 
| 576 | 0 |         ret = 0; | 
| 577 | 0 |         break; | 
| 578 | 0 |     } | 
| 579 | 0 |     return ret; | 
| 580 | 0 | } | 
| 581 |  |  | 
| 582 |  | static long conn_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) | 
| 583 | 0 | { | 
| 584 | 0 |     long ret = 1; | 
| 585 | 0 |     BIO_CONNECT *data; | 
| 586 |  | 
 | 
| 587 | 0 |     data = (BIO_CONNECT *)b->ptr; | 
| 588 |  | 
 | 
| 589 | 0 |     switch (cmd) { | 
| 590 | 0 |     case BIO_CTRL_SET_CALLBACK: | 
| 591 | 0 |         { | 
| 592 | 0 |             data->info_callback = fp; | 
| 593 | 0 |         } | 
| 594 | 0 |         break; | 
| 595 | 0 |     default: | 
| 596 | 0 |         ret = 0; | 
| 597 | 0 |         break; | 
| 598 | 0 |     } | 
| 599 | 0 |     return ret; | 
| 600 | 0 | } | 
| 601 |  |  | 
| 602 |  | static int conn_puts(BIO *bp, const char *str) | 
| 603 | 0 | { | 
| 604 | 0 |     int n, ret; | 
| 605 |  | 
 | 
| 606 | 0 |     n = strlen(str); | 
| 607 | 0 |     ret = conn_write(bp, str, n); | 
| 608 | 0 |     return ret; | 
| 609 | 0 | } | 
| 610 |  |  | 
| 611 |  | BIO *BIO_new_connect(const char *str) | 
| 612 | 0 | { | 
| 613 | 0 |     BIO *ret; | 
| 614 |  | 
 | 
| 615 | 0 |     ret = BIO_new(BIO_s_connect()); | 
| 616 | 0 |     if (ret == NULL) | 
| 617 | 0 |         return NULL; | 
| 618 | 0 |     if (BIO_set_conn_hostname(ret, str)) | 
| 619 | 0 |         return ret; | 
| 620 | 0 |     BIO_free(ret); | 
| 621 | 0 |     return NULL; | 
| 622 | 0 | } | 
| 623 |  |  | 
| 624 |  | #endif |