155714Skris/* crypto/bio/bss_conn.c */ 255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 355714Skris * All rights reserved. 455714Skris * 555714Skris * This package is an SSL implementation written 655714Skris * by Eric Young (eay@cryptsoft.com). 755714Skris * The implementation was written so as to conform with Netscapes SSL. 8296341Sdelphij * 955714Skris * This library is free for commercial and non-commercial use as long as 1055714Skris * the following conditions are aheared to. The following conditions 1155714Skris * apply to all code found in this distribution, be it the RC4, RSA, 1255714Skris * lhash, DES, etc., code; not just the SSL code. The SSL documentation 1355714Skris * included with this distribution is covered by the same copyright terms 1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15296341Sdelphij * 1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in 1755714Skris * the code are not to be removed. 1855714Skris * If this package is used in a product, Eric Young should be given attribution 1955714Skris * as the author of the parts of the library used. 2055714Skris * This can be in the form of a textual message at program startup or 2155714Skris * in documentation (online or textual) provided with the package. 22296341Sdelphij * 2355714Skris * Redistribution and use in source and binary forms, with or without 2455714Skris * modification, are permitted provided that the following conditions 2555714Skris * are met: 2655714Skris * 1. Redistributions of source code must retain the copyright 2755714Skris * notice, this list of conditions and the following disclaimer. 2855714Skris * 2. Redistributions in binary form must reproduce the above copyright 2955714Skris * notice, this list of conditions and the following disclaimer in the 3055714Skris * documentation and/or other materials provided with the distribution. 3155714Skris * 3. All advertising materials mentioning features or use of this software 3255714Skris * must display the following acknowledgement: 3355714Skris * "This product includes cryptographic software written by 3455714Skris * Eric Young (eay@cryptsoft.com)" 3555714Skris * The word 'cryptographic' can be left out if the rouines from the library 3655714Skris * being used are not cryptographic related :-). 37296341Sdelphij * 4. If you include any Windows specific code (or a derivative thereof) from 3855714Skris * the apps directory (application code) you must include an acknowledgement: 3955714Skris * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40296341Sdelphij * 4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4455714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5155714Skris * SUCH DAMAGE. 52296341Sdelphij * 5355714Skris * The licence and distribution terms for any publically available version or 5455714Skris * derivative of this code cannot be changed. i.e. this code cannot simply be 5555714Skris * copied and put under another distribution licence 5655714Skris * [including the GNU Public Licence.] 5755714Skris */ 5855714Skris 5955714Skris#include <stdio.h> 6055714Skris#include <errno.h> 6155714Skris#define USE_SOCKETS 6255714Skris#include "cryptlib.h" 6355714Skris#include <openssl/bio.h> 6455714Skris 65160814Ssimon#ifndef OPENSSL_NO_SOCK 66160814Ssimon 67296341Sdelphij# ifdef OPENSSL_SYS_WIN16 68296341Sdelphij# define SOCKET_PROTOCOL 0 /* more microsoft stupidity */ 69296341Sdelphij# else 70296341Sdelphij# define SOCKET_PROTOCOL IPPROTO_TCP 71296341Sdelphij# endif 7255714Skris 73296341Sdelphij# if (defined(OPENSSL_SYS_VMS) && __VMS_VER < 70000000) 7455714Skris/* FIONBIO used as a switch to enable ioctl, and that isn't in VMS < 7.0 */ 75296341Sdelphij# undef FIONBIO 76296341Sdelphij# endif 7755714Skris 78296341Sdelphijtypedef struct bio_connect_st { 79296341Sdelphij int state; 80296341Sdelphij char *param_hostname; 81296341Sdelphij char *param_port; 82296341Sdelphij int nbio; 83296341Sdelphij unsigned char ip[4]; 84296341Sdelphij unsigned short port; 85296341Sdelphij struct sockaddr_in them; 86296341Sdelphij /* 87296341Sdelphij * int socket; this will be kept in bio->num so that it is compatible 88296341Sdelphij * with the bss_sock bio 89296341Sdelphij */ 90296341Sdelphij /* 91296341Sdelphij * called when the connection is initially made callback(BIO,state,ret); 92296341Sdelphij * The callback should return 'ret'. state is for compatibility with the 93296341Sdelphij * ssl info_callback 94296341Sdelphij */ 95296341Sdelphij int (*info_callback) (const BIO *bio, int state, int ret); 96296341Sdelphij} BIO_CONNECT; 9755714Skris 9868651Skrisstatic int conn_write(BIO *h, const char *buf, int num); 9968651Skrisstatic int conn_read(BIO *h, char *buf, int size); 10068651Skrisstatic int conn_puts(BIO *h, const char *str); 10168651Skrisstatic long conn_ctrl(BIO *h, int cmd, long arg1, void *arg2); 10255714Skrisstatic int conn_new(BIO *h); 10355714Skrisstatic int conn_free(BIO *data); 10468651Skrisstatic long conn_callback_ctrl(BIO *h, int cmd, bio_info_cb *); 10555714Skris 10655714Skrisstatic int conn_state(BIO *b, BIO_CONNECT *c); 10755714Skrisstatic void conn_close_socket(BIO *data); 108296341SdelphijBIO_CONNECT *BIO_CONNECT_new(void); 10955714Skrisvoid BIO_CONNECT_free(BIO_CONNECT *a); 11055714Skris 111296341Sdelphijstatic BIO_METHOD methods_connectp = { 112296341Sdelphij BIO_TYPE_CONNECT, 113296341Sdelphij "socket connect", 114296341Sdelphij conn_write, 115296341Sdelphij conn_read, 116296341Sdelphij conn_puts, 117296341Sdelphij NULL, /* connect_gets, */ 118296341Sdelphij conn_ctrl, 119296341Sdelphij conn_new, 120296341Sdelphij conn_free, 121296341Sdelphij conn_callback_ctrl, 122296341Sdelphij}; 12355714Skris 12455714Skrisstatic int conn_state(BIO *b, BIO_CONNECT *c) 125296341Sdelphij{ 126296341Sdelphij int ret = -1, i; 127296341Sdelphij unsigned long l; 128296341Sdelphij char *p, *q; 129296341Sdelphij int (*cb) (const BIO *, int, int) = NULL; 13055714Skris 131296341Sdelphij if (c->info_callback != NULL) 132296341Sdelphij cb = c->info_callback; 13355714Skris 134296341Sdelphij for (;;) { 135296341Sdelphij switch (c->state) { 136296341Sdelphij case BIO_CONN_S_BEFORE: 137296341Sdelphij p = c->param_hostname; 138296341Sdelphij if (p == NULL) { 139296341Sdelphij BIOerr(BIO_F_CONN_STATE, BIO_R_NO_HOSTNAME_SPECIFIED); 140296341Sdelphij goto exit_loop; 141296341Sdelphij } 142296341Sdelphij for (; *p != '\0'; p++) { 143296341Sdelphij if ((*p == ':') || (*p == '/')) 144296341Sdelphij break; 145296341Sdelphij } 14655714Skris 147296341Sdelphij i = *p; 148296341Sdelphij if ((i == ':') || (i == '/')) { 14955714Skris 150296341Sdelphij *(p++) = '\0'; 151296341Sdelphij if (i == ':') { 152296341Sdelphij for (q = p; *q; q++) 153296341Sdelphij if (*q == '/') { 154296341Sdelphij *q = '\0'; 155296341Sdelphij break; 156296341Sdelphij } 157296341Sdelphij if (c->param_port != NULL) 158296341Sdelphij OPENSSL_free(c->param_port); 159296341Sdelphij c->param_port = BUF_strdup(p); 160296341Sdelphij } 161296341Sdelphij } 16255714Skris 163296341Sdelphij if (c->param_port == NULL) { 164296341Sdelphij BIOerr(BIO_F_CONN_STATE, BIO_R_NO_PORT_SPECIFIED); 165296341Sdelphij ERR_add_error_data(2, "host=", c->param_hostname); 166296341Sdelphij goto exit_loop; 167296341Sdelphij } 168296341Sdelphij c->state = BIO_CONN_S_GET_IP; 169296341Sdelphij break; 17055714Skris 171296341Sdelphij case BIO_CONN_S_GET_IP: 172296341Sdelphij if (BIO_get_host_ip(c->param_hostname, &(c->ip[0])) <= 0) 173296341Sdelphij goto exit_loop; 174296341Sdelphij c->state = BIO_CONN_S_GET_PORT; 175296341Sdelphij break; 17655714Skris 177296341Sdelphij case BIO_CONN_S_GET_PORT: 178296341Sdelphij if (c->param_port == NULL) { 179296341Sdelphij /* abort(); */ 180296341Sdelphij goto exit_loop; 181296341Sdelphij } else if (BIO_get_port(c->param_port, &c->port) <= 0) 182296341Sdelphij goto exit_loop; 183296341Sdelphij c->state = BIO_CONN_S_CREATE_SOCKET; 184296341Sdelphij break; 18555714Skris 186296341Sdelphij case BIO_CONN_S_CREATE_SOCKET: 187296341Sdelphij /* now setup address */ 188296341Sdelphij memset((char *)&c->them, 0, sizeof(c->them)); 189296341Sdelphij c->them.sin_family = AF_INET; 190296341Sdelphij c->them.sin_port = htons((unsigned short)c->port); 191296341Sdelphij l = (unsigned long) 192296341Sdelphij ((unsigned long)c->ip[0] << 24L) | 193296341Sdelphij ((unsigned long)c->ip[1] << 16L) | 194296341Sdelphij ((unsigned long)c->ip[2] << 8L) | ((unsigned long)c->ip[3]); 195296341Sdelphij c->them.sin_addr.s_addr = htonl(l); 196296341Sdelphij c->state = BIO_CONN_S_CREATE_SOCKET; 19755714Skris 198296341Sdelphij ret = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL); 199296341Sdelphij if (ret == INVALID_SOCKET) { 200296341Sdelphij SYSerr(SYS_F_SOCKET, get_last_socket_error()); 201296341Sdelphij ERR_add_error_data(4, "host=", c->param_hostname, 202296341Sdelphij ":", c->param_port); 203296341Sdelphij BIOerr(BIO_F_CONN_STATE, BIO_R_UNABLE_TO_CREATE_SOCKET); 204296341Sdelphij goto exit_loop; 205296341Sdelphij } 206296341Sdelphij b->num = ret; 207296341Sdelphij c->state = BIO_CONN_S_NBIO; 208296341Sdelphij break; 20955714Skris 210296341Sdelphij case BIO_CONN_S_NBIO: 211296341Sdelphij if (c->nbio) { 212296341Sdelphij if (!BIO_socket_nbio(b->num, 1)) { 213296341Sdelphij BIOerr(BIO_F_CONN_STATE, BIO_R_ERROR_SETTING_NBIO); 214296341Sdelphij ERR_add_error_data(4, "host=", 215296341Sdelphij c->param_hostname, ":", c->param_port); 216296341Sdelphij goto exit_loop; 217296341Sdelphij } 218296341Sdelphij } 219296341Sdelphij c->state = BIO_CONN_S_CONNECT; 22055714Skris 221296341Sdelphij# if defined(SO_KEEPALIVE) && !defined(OPENSSL_SYS_MPE) 222296341Sdelphij i = 1; 223296341Sdelphij i = setsockopt(b->num, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, 224296341Sdelphij sizeof(i)); 225296341Sdelphij if (i < 0) { 226296341Sdelphij SYSerr(SYS_F_SOCKET, get_last_socket_error()); 227296341Sdelphij ERR_add_error_data(4, "host=", c->param_hostname, 228296341Sdelphij ":", c->param_port); 229296341Sdelphij BIOerr(BIO_F_CONN_STATE, BIO_R_KEEPALIVE); 230296341Sdelphij goto exit_loop; 231296341Sdelphij } 232296341Sdelphij# endif 233296341Sdelphij break; 23455714Skris 235296341Sdelphij case BIO_CONN_S_CONNECT: 236296341Sdelphij BIO_clear_retry_flags(b); 237296341Sdelphij ret = connect(b->num, 238296341Sdelphij (struct sockaddr *)&c->them, sizeof(c->them)); 239296341Sdelphij b->retry_reason = 0; 240296341Sdelphij if (ret < 0) { 241296341Sdelphij if (BIO_sock_should_retry(ret)) { 242296341Sdelphij BIO_set_retry_special(b); 243296341Sdelphij c->state = BIO_CONN_S_BLOCKED_CONNECT; 244296341Sdelphij b->retry_reason = BIO_RR_CONNECT; 245296341Sdelphij } else { 246296341Sdelphij SYSerr(SYS_F_CONNECT, get_last_socket_error()); 247296341Sdelphij ERR_add_error_data(4, "host=", 248296341Sdelphij c->param_hostname, ":", c->param_port); 249296341Sdelphij BIOerr(BIO_F_CONN_STATE, BIO_R_CONNECT_ERROR); 250296341Sdelphij } 251296341Sdelphij goto exit_loop; 252296341Sdelphij } else 253296341Sdelphij c->state = BIO_CONN_S_OK; 254296341Sdelphij break; 25555714Skris 256296341Sdelphij case BIO_CONN_S_BLOCKED_CONNECT: 257296341Sdelphij i = BIO_sock_error(b->num); 258296341Sdelphij if (i) { 259296341Sdelphij BIO_clear_retry_flags(b); 260296341Sdelphij SYSerr(SYS_F_CONNECT, i); 261296341Sdelphij ERR_add_error_data(4, "host=", 262296341Sdelphij c->param_hostname, ":", c->param_port); 263296341Sdelphij BIOerr(BIO_F_CONN_STATE, BIO_R_NBIO_CONNECT_ERROR); 264296341Sdelphij ret = 0; 265296341Sdelphij goto exit_loop; 266296341Sdelphij } else 267296341Sdelphij c->state = BIO_CONN_S_OK; 268296341Sdelphij break; 26955714Skris 270296341Sdelphij case BIO_CONN_S_OK: 271296341Sdelphij ret = 1; 272296341Sdelphij goto exit_loop; 273296341Sdelphij default: 274296341Sdelphij /* abort(); */ 275296341Sdelphij goto exit_loop; 276296341Sdelphij } 27755714Skris 278296341Sdelphij if (cb != NULL) { 279296341Sdelphij if (!(ret = cb((BIO *)b, c->state, ret))) 280296341Sdelphij goto end; 281296341Sdelphij } 282296341Sdelphij } 28355714Skris 284296341Sdelphij /* Loop does not exit */ 285296341Sdelphij exit_loop: 286296341Sdelphij if (cb != NULL) 287296341Sdelphij ret = cb((BIO *)b, c->state, ret); 288296341Sdelphij end: 289296341Sdelphij return (ret); 290296341Sdelphij} 29155714Skris 29255714SkrisBIO_CONNECT *BIO_CONNECT_new(void) 293296341Sdelphij{ 294296341Sdelphij BIO_CONNECT *ret; 29555714Skris 296296341Sdelphij if ((ret = (BIO_CONNECT *)OPENSSL_malloc(sizeof(BIO_CONNECT))) == NULL) 297296341Sdelphij return (NULL); 298296341Sdelphij ret->state = BIO_CONN_S_BEFORE; 299296341Sdelphij ret->param_hostname = NULL; 300296341Sdelphij ret->param_port = NULL; 301296341Sdelphij ret->info_callback = NULL; 302296341Sdelphij ret->nbio = 0; 303296341Sdelphij ret->ip[0] = 0; 304296341Sdelphij ret->ip[1] = 0; 305296341Sdelphij ret->ip[2] = 0; 306296341Sdelphij ret->ip[3] = 0; 307296341Sdelphij ret->port = 0; 308296341Sdelphij memset((char *)&ret->them, 0, sizeof(ret->them)); 309296341Sdelphij return (ret); 310296341Sdelphij} 31155714Skris 31255714Skrisvoid BIO_CONNECT_free(BIO_CONNECT *a) 313296341Sdelphij{ 314296341Sdelphij if (a == NULL) 315296341Sdelphij return; 31655714Skris 317296341Sdelphij if (a->param_hostname != NULL) 318296341Sdelphij OPENSSL_free(a->param_hostname); 319296341Sdelphij if (a->param_port != NULL) 320296341Sdelphij OPENSSL_free(a->param_port); 321296341Sdelphij OPENSSL_free(a); 322296341Sdelphij} 32355714Skris 32455714SkrisBIO_METHOD *BIO_s_connect(void) 325296341Sdelphij{ 326296341Sdelphij return (&methods_connectp); 327296341Sdelphij} 32855714Skris 32955714Skrisstatic int conn_new(BIO *bi) 330296341Sdelphij{ 331296341Sdelphij bi->init = 0; 332296341Sdelphij bi->num = INVALID_SOCKET; 333296341Sdelphij bi->flags = 0; 334296341Sdelphij if ((bi->ptr = (char *)BIO_CONNECT_new()) == NULL) 335296341Sdelphij return (0); 336296341Sdelphij else 337296341Sdelphij return (1); 338296341Sdelphij} 33955714Skris 34055714Skrisstatic void conn_close_socket(BIO *bio) 341296341Sdelphij{ 342296341Sdelphij BIO_CONNECT *c; 34355714Skris 344296341Sdelphij c = (BIO_CONNECT *)bio->ptr; 345296341Sdelphij if (bio->num != INVALID_SOCKET) { 346296341Sdelphij /* Only do a shutdown if things were established */ 347296341Sdelphij if (c->state == BIO_CONN_S_OK) 348296341Sdelphij shutdown(bio->num, 2); 349296341Sdelphij closesocket(bio->num); 350296341Sdelphij bio->num = INVALID_SOCKET; 351296341Sdelphij } 352296341Sdelphij} 35355714Skris 35455714Skrisstatic int conn_free(BIO *a) 355296341Sdelphij{ 356296341Sdelphij BIO_CONNECT *data; 35755714Skris 358296341Sdelphij if (a == NULL) 359296341Sdelphij return (0); 360296341Sdelphij data = (BIO_CONNECT *)a->ptr; 361296341Sdelphij 362296341Sdelphij if (a->shutdown) { 363296341Sdelphij conn_close_socket(a); 364296341Sdelphij BIO_CONNECT_free(data); 365296341Sdelphij a->ptr = NULL; 366296341Sdelphij a->flags = 0; 367296341Sdelphij a->init = 0; 368296341Sdelphij } 369296341Sdelphij return (1); 370296341Sdelphij} 371296341Sdelphij 37255714Skrisstatic int conn_read(BIO *b, char *out, int outl) 373296341Sdelphij{ 374296341Sdelphij int ret = 0; 375296341Sdelphij BIO_CONNECT *data; 37655714Skris 377296341Sdelphij data = (BIO_CONNECT *)b->ptr; 378296341Sdelphij if (data->state != BIO_CONN_S_OK) { 379296341Sdelphij ret = conn_state(b, data); 380296341Sdelphij if (ret <= 0) 381296341Sdelphij return (ret); 382296341Sdelphij } 38355714Skris 384296341Sdelphij if (out != NULL) { 385296341Sdelphij clear_socket_error(); 386296341Sdelphij ret = readsocket(b->num, out, outl); 387296341Sdelphij BIO_clear_retry_flags(b); 388296341Sdelphij if (ret <= 0) { 389296341Sdelphij if (BIO_sock_should_retry(ret)) 390296341Sdelphij BIO_set_retry_read(b); 391296341Sdelphij } 392296341Sdelphij } 393296341Sdelphij return (ret); 394296341Sdelphij} 39555714Skris 39668651Skrisstatic int conn_write(BIO *b, const char *in, int inl) 397296341Sdelphij{ 398296341Sdelphij int ret; 399296341Sdelphij BIO_CONNECT *data; 40055714Skris 401296341Sdelphij data = (BIO_CONNECT *)b->ptr; 402296341Sdelphij if (data->state != BIO_CONN_S_OK) { 403296341Sdelphij ret = conn_state(b, data); 404296341Sdelphij if (ret <= 0) 405296341Sdelphij return (ret); 406296341Sdelphij } 40755714Skris 408296341Sdelphij clear_socket_error(); 409296341Sdelphij ret = writesocket(b->num, in, inl); 410296341Sdelphij BIO_clear_retry_flags(b); 411296341Sdelphij if (ret <= 0) { 412296341Sdelphij if (BIO_sock_should_retry(ret)) 413296341Sdelphij BIO_set_retry_write(b); 414296341Sdelphij } 415296341Sdelphij return (ret); 416296341Sdelphij} 41755714Skris 41868651Skrisstatic long conn_ctrl(BIO *b, int cmd, long num, void *ptr) 419296341Sdelphij{ 420296341Sdelphij BIO *dbio; 421296341Sdelphij int *ip; 422296341Sdelphij const char **pptr; 423296341Sdelphij long ret = 1; 424296341Sdelphij BIO_CONNECT *data; 42555714Skris 426296341Sdelphij data = (BIO_CONNECT *)b->ptr; 42755714Skris 428296341Sdelphij switch (cmd) { 429296341Sdelphij case BIO_CTRL_RESET: 430296341Sdelphij ret = 0; 431296341Sdelphij data->state = BIO_CONN_S_BEFORE; 432296341Sdelphij conn_close_socket(b); 433296341Sdelphij b->flags = 0; 434296341Sdelphij break; 435296341Sdelphij case BIO_C_DO_STATE_MACHINE: 436296341Sdelphij /* use this one to start the connection */ 437296341Sdelphij if (data->state != BIO_CONN_S_OK) 438296341Sdelphij ret = (long)conn_state(b, data); 439296341Sdelphij else 440296341Sdelphij ret = 1; 441296341Sdelphij break; 442296341Sdelphij case BIO_C_GET_CONNECT: 443296341Sdelphij if (ptr != NULL) { 444296341Sdelphij pptr = (const char **)ptr; 445296341Sdelphij if (num == 0) { 446296341Sdelphij *pptr = data->param_hostname; 44755714Skris 448296341Sdelphij } else if (num == 1) { 449296341Sdelphij *pptr = data->param_port; 450296341Sdelphij } else if (num == 2) { 451296341Sdelphij *pptr = (char *)&(data->ip[0]); 452296341Sdelphij } else if (num == 3) { 453296341Sdelphij *((int *)ptr) = data->port; 454296341Sdelphij } 455296341Sdelphij if ((!b->init) || (ptr == NULL)) 456296341Sdelphij *pptr = "not initialized"; 457296341Sdelphij ret = 1; 458296341Sdelphij } 459296341Sdelphij break; 460296341Sdelphij case BIO_C_SET_CONNECT: 461296341Sdelphij if (ptr != NULL) { 462296341Sdelphij b->init = 1; 463296341Sdelphij if (num == 0) { 464296341Sdelphij if (data->param_hostname != NULL) 465296341Sdelphij OPENSSL_free(data->param_hostname); 466296341Sdelphij data->param_hostname = BUF_strdup(ptr); 467296341Sdelphij } else if (num == 1) { 468296341Sdelphij if (data->param_port != NULL) 469296341Sdelphij OPENSSL_free(data->param_port); 470296341Sdelphij data->param_port = BUF_strdup(ptr); 471296341Sdelphij } else if (num == 2) { 472296341Sdelphij char buf[16]; 473296341Sdelphij unsigned char *p = ptr; 47455714Skris 475296341Sdelphij BIO_snprintf(buf, sizeof buf, "%d.%d.%d.%d", 476296341Sdelphij p[0], p[1], p[2], p[3]); 477296341Sdelphij if (data->param_hostname != NULL) 478296341Sdelphij OPENSSL_free(data->param_hostname); 479296341Sdelphij data->param_hostname = BUF_strdup(buf); 480296341Sdelphij memcpy(&(data->ip[0]), ptr, 4); 481296341Sdelphij } else if (num == 3) { 482296341Sdelphij char buf[DECIMAL_SIZE(int) + 1]; 48355714Skris 484296341Sdelphij BIO_snprintf(buf, sizeof buf, "%d", *(int *)ptr); 485296341Sdelphij if (data->param_port != NULL) 486296341Sdelphij OPENSSL_free(data->param_port); 487296341Sdelphij data->param_port = BUF_strdup(buf); 488296341Sdelphij data->port = *(int *)ptr; 489296341Sdelphij } 490296341Sdelphij } 491296341Sdelphij break; 492296341Sdelphij case BIO_C_SET_NBIO: 493296341Sdelphij data->nbio = (int)num; 494296341Sdelphij break; 495296341Sdelphij case BIO_C_GET_FD: 496296341Sdelphij if (b->init) { 497296341Sdelphij ip = (int *)ptr; 498296341Sdelphij if (ip != NULL) 499296341Sdelphij *ip = b->num; 500296341Sdelphij ret = b->num; 501296341Sdelphij } else 502296341Sdelphij ret = -1; 503296341Sdelphij break; 504296341Sdelphij case BIO_CTRL_GET_CLOSE: 505296341Sdelphij ret = b->shutdown; 506296341Sdelphij break; 507296341Sdelphij case BIO_CTRL_SET_CLOSE: 508296341Sdelphij b->shutdown = (int)num; 509296341Sdelphij break; 510296341Sdelphij case BIO_CTRL_PENDING: 511296341Sdelphij case BIO_CTRL_WPENDING: 512296341Sdelphij ret = 0; 513296341Sdelphij break; 514296341Sdelphij case BIO_CTRL_FLUSH: 515296341Sdelphij break; 516296341Sdelphij case BIO_CTRL_DUP: 517296341Sdelphij { 518296341Sdelphij dbio = (BIO *)ptr; 519296341Sdelphij if (data->param_port) 520296341Sdelphij BIO_set_conn_port(dbio, data->param_port); 521296341Sdelphij if (data->param_hostname) 522296341Sdelphij BIO_set_conn_hostname(dbio, data->param_hostname); 523296341Sdelphij BIO_set_nbio(dbio, data->nbio); 524296341Sdelphij /* 525296341Sdelphij * FIXME: the cast of the function seems unlikely to be a good 526296341Sdelphij * idea 527296341Sdelphij */ 528296341Sdelphij (void)BIO_set_info_callback(dbio, 529296341Sdelphij (bio_info_cb *)data->info_callback); 530296341Sdelphij } 531296341Sdelphij break; 532296341Sdelphij case BIO_CTRL_SET_CALLBACK: 533296341Sdelphij { 534296341Sdelphij# if 0 /* FIXME: Should this be used? -- Richard 535296341Sdelphij * Levitte */ 536296341Sdelphij BIOerr(BIO_F_CONN_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 537296341Sdelphij ret = -1; 538296341Sdelphij# else 539296341Sdelphij ret = 0; 540296341Sdelphij# endif 541296341Sdelphij } 542296341Sdelphij break; 543296341Sdelphij case BIO_CTRL_GET_CALLBACK: 544296341Sdelphij { 545296341Sdelphij int (**fptr) (const BIO *bio, int state, int xret); 54655714Skris 547296341Sdelphij fptr = (int (**)(const BIO *bio, int state, int xret))ptr; 548296341Sdelphij *fptr = data->info_callback; 549296341Sdelphij } 550296341Sdelphij break; 551296341Sdelphij default: 552296341Sdelphij ret = 0; 553296341Sdelphij break; 554296341Sdelphij } 555296341Sdelphij return (ret); 556296341Sdelphij} 55755714Skris 55868651Skrisstatic long conn_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 559296341Sdelphij{ 560296341Sdelphij long ret = 1; 561296341Sdelphij BIO_CONNECT *data; 56259191Skris 563296341Sdelphij data = (BIO_CONNECT *)b->ptr; 56459191Skris 565296341Sdelphij switch (cmd) { 566296341Sdelphij case BIO_CTRL_SET_CALLBACK: 567296341Sdelphij { 568296341Sdelphij data->info_callback = 569296341Sdelphij (int (*)(const struct bio_st *, int, int))fp; 570296341Sdelphij } 571296341Sdelphij break; 572296341Sdelphij default: 573296341Sdelphij ret = 0; 574296341Sdelphij break; 575296341Sdelphij } 576296341Sdelphij return (ret); 577296341Sdelphij} 57859191Skris 57968651Skrisstatic int conn_puts(BIO *bp, const char *str) 580296341Sdelphij{ 581296341Sdelphij int n, ret; 58255714Skris 583296341Sdelphij n = strlen(str); 584296341Sdelphij ret = conn_write(bp, str, n); 585296341Sdelphij return (ret); 586296341Sdelphij} 58755714Skris 58855714SkrisBIO *BIO_new_connect(char *str) 589296341Sdelphij{ 590296341Sdelphij BIO *ret; 59155714Skris 592296341Sdelphij ret = BIO_new(BIO_s_connect()); 593296341Sdelphij if (ret == NULL) 594296341Sdelphij return (NULL); 595296341Sdelphij if (BIO_set_conn_hostname(ret, str)) 596296341Sdelphij return (ret); 597296341Sdelphij else { 598296341Sdelphij BIO_free(ret); 599296341Sdelphij return (NULL); 600296341Sdelphij } 601296341Sdelphij} 60255714Skris 60355714Skris#endif 604