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