bss_conn.c revision 296341
1/* crypto/bio/bss_conn.c */ 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 59#include <stdio.h> 60#include <errno.h> 61#define USE_SOCKETS 62#include "cryptlib.h" 63#include <openssl/bio.h> 64 65#ifndef OPENSSL_NO_SOCK 66 67# ifdef OPENSSL_SYS_WIN16 68# define SOCKET_PROTOCOL 0 /* more microsoft stupidity */ 69# else 70# define SOCKET_PROTOCOL IPPROTO_TCP 71# endif 72 73# if (defined(OPENSSL_SYS_VMS) && __VMS_VER < 70000000) 74/* FIONBIO used as a switch to enable ioctl, and that isn't in VMS < 7.0 */ 75# undef FIONBIO 76# endif 77 78typedef struct bio_connect_st { 79 int state; 80 char *param_hostname; 81 char *param_port; 82 int nbio; 83 unsigned char ip[4]; 84 unsigned short port; 85 struct sockaddr_in them; 86 /* 87 * int socket; this will be kept in bio->num so that it is compatible 88 * with the bss_sock bio 89 */ 90 /* 91 * called when the connection is initially made callback(BIO,state,ret); 92 * The callback should return 'ret'. state is for compatibility with the 93 * ssl info_callback 94 */ 95 int (*info_callback) (const BIO *bio, int state, int ret); 96} BIO_CONNECT; 97 98static int conn_write(BIO *h, const char *buf, int num); 99static int conn_read(BIO *h, char *buf, int size); 100static int conn_puts(BIO *h, const char *str); 101static long conn_ctrl(BIO *h, int cmd, long arg1, void *arg2); 102static int conn_new(BIO *h); 103static int conn_free(BIO *data); 104static long conn_callback_ctrl(BIO *h, int cmd, bio_info_cb *); 105 106static int conn_state(BIO *b, BIO_CONNECT *c); 107static void conn_close_socket(BIO *data); 108BIO_CONNECT *BIO_CONNECT_new(void); 109void BIO_CONNECT_free(BIO_CONNECT *a); 110 111static BIO_METHOD methods_connectp = { 112 BIO_TYPE_CONNECT, 113 "socket connect", 114 conn_write, 115 conn_read, 116 conn_puts, 117 NULL, /* connect_gets, */ 118 conn_ctrl, 119 conn_new, 120 conn_free, 121 conn_callback_ctrl, 122}; 123 124static int conn_state(BIO *b, BIO_CONNECT *c) 125{ 126 int ret = -1, i; 127 unsigned long l; 128 char *p, *q; 129 int (*cb) (const BIO *, int, int) = NULL; 130 131 if (c->info_callback != NULL) 132 cb = c->info_callback; 133 134 for (;;) { 135 switch (c->state) { 136 case BIO_CONN_S_BEFORE: 137 p = c->param_hostname; 138 if (p == NULL) { 139 BIOerr(BIO_F_CONN_STATE, BIO_R_NO_HOSTNAME_SPECIFIED); 140 goto exit_loop; 141 } 142 for (; *p != '\0'; p++) { 143 if ((*p == ':') || (*p == '/')) 144 break; 145 } 146 147 i = *p; 148 if ((i == ':') || (i == '/')) { 149 150 *(p++) = '\0'; 151 if (i == ':') { 152 for (q = p; *q; q++) 153 if (*q == '/') { 154 *q = '\0'; 155 break; 156 } 157 if (c->param_port != NULL) 158 OPENSSL_free(c->param_port); 159 c->param_port = BUF_strdup(p); 160 } 161 } 162 163 if (c->param_port == NULL) { 164 BIOerr(BIO_F_CONN_STATE, BIO_R_NO_PORT_SPECIFIED); 165 ERR_add_error_data(2, "host=", c->param_hostname); 166 goto exit_loop; 167 } 168 c->state = BIO_CONN_S_GET_IP; 169 break; 170 171 case BIO_CONN_S_GET_IP: 172 if (BIO_get_host_ip(c->param_hostname, &(c->ip[0])) <= 0) 173 goto exit_loop; 174 c->state = BIO_CONN_S_GET_PORT; 175 break; 176 177 case BIO_CONN_S_GET_PORT: 178 if (c->param_port == NULL) { 179 /* abort(); */ 180 goto exit_loop; 181 } else if (BIO_get_port(c->param_port, &c->port) <= 0) 182 goto exit_loop; 183 c->state = BIO_CONN_S_CREATE_SOCKET; 184 break; 185 186 case BIO_CONN_S_CREATE_SOCKET: 187 /* now setup address */ 188 memset((char *)&c->them, 0, sizeof(c->them)); 189 c->them.sin_family = AF_INET; 190 c->them.sin_port = htons((unsigned short)c->port); 191 l = (unsigned long) 192 ((unsigned long)c->ip[0] << 24L) | 193 ((unsigned long)c->ip[1] << 16L) | 194 ((unsigned long)c->ip[2] << 8L) | ((unsigned long)c->ip[3]); 195 c->them.sin_addr.s_addr = htonl(l); 196 c->state = BIO_CONN_S_CREATE_SOCKET; 197 198 ret = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL); 199 if (ret == INVALID_SOCKET) { 200 SYSerr(SYS_F_SOCKET, get_last_socket_error()); 201 ERR_add_error_data(4, "host=", c->param_hostname, 202 ":", c->param_port); 203 BIOerr(BIO_F_CONN_STATE, BIO_R_UNABLE_TO_CREATE_SOCKET); 204 goto exit_loop; 205 } 206 b->num = ret; 207 c->state = BIO_CONN_S_NBIO; 208 break; 209 210 case BIO_CONN_S_NBIO: 211 if (c->nbio) { 212 if (!BIO_socket_nbio(b->num, 1)) { 213 BIOerr(BIO_F_CONN_STATE, BIO_R_ERROR_SETTING_NBIO); 214 ERR_add_error_data(4, "host=", 215 c->param_hostname, ":", c->param_port); 216 goto exit_loop; 217 } 218 } 219 c->state = BIO_CONN_S_CONNECT; 220 221# if defined(SO_KEEPALIVE) && !defined(OPENSSL_SYS_MPE) 222 i = 1; 223 i = setsockopt(b->num, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, 224 sizeof(i)); 225 if (i < 0) { 226 SYSerr(SYS_F_SOCKET, get_last_socket_error()); 227 ERR_add_error_data(4, "host=", c->param_hostname, 228 ":", c->param_port); 229 BIOerr(BIO_F_CONN_STATE, BIO_R_KEEPALIVE); 230 goto exit_loop; 231 } 232# endif 233 break; 234 235 case BIO_CONN_S_CONNECT: 236 BIO_clear_retry_flags(b); 237 ret = connect(b->num, 238 (struct sockaddr *)&c->them, sizeof(c->them)); 239 b->retry_reason = 0; 240 if (ret < 0) { 241 if (BIO_sock_should_retry(ret)) { 242 BIO_set_retry_special(b); 243 c->state = BIO_CONN_S_BLOCKED_CONNECT; 244 b->retry_reason = BIO_RR_CONNECT; 245 } else { 246 SYSerr(SYS_F_CONNECT, get_last_socket_error()); 247 ERR_add_error_data(4, "host=", 248 c->param_hostname, ":", c->param_port); 249 BIOerr(BIO_F_CONN_STATE, BIO_R_CONNECT_ERROR); 250 } 251 goto exit_loop; 252 } else 253 c->state = BIO_CONN_S_OK; 254 break; 255 256 case BIO_CONN_S_BLOCKED_CONNECT: 257 i = BIO_sock_error(b->num); 258 if (i) { 259 BIO_clear_retry_flags(b); 260 SYSerr(SYS_F_CONNECT, i); 261 ERR_add_error_data(4, "host=", 262 c->param_hostname, ":", c->param_port); 263 BIOerr(BIO_F_CONN_STATE, BIO_R_NBIO_CONNECT_ERROR); 264 ret = 0; 265 goto exit_loop; 266 } else 267 c->state = BIO_CONN_S_OK; 268 break; 269 270 case BIO_CONN_S_OK: 271 ret = 1; 272 goto exit_loop; 273 default: 274 /* abort(); */ 275 goto exit_loop; 276 } 277 278 if (cb != NULL) { 279 if (!(ret = cb((BIO *)b, c->state, ret))) 280 goto end; 281 } 282 } 283 284 /* Loop does not exit */ 285 exit_loop: 286 if (cb != NULL) 287 ret = cb((BIO *)b, c->state, ret); 288 end: 289 return (ret); 290} 291 292BIO_CONNECT *BIO_CONNECT_new(void) 293{ 294 BIO_CONNECT *ret; 295 296 if ((ret = (BIO_CONNECT *)OPENSSL_malloc(sizeof(BIO_CONNECT))) == NULL) 297 return (NULL); 298 ret->state = BIO_CONN_S_BEFORE; 299 ret->param_hostname = NULL; 300 ret->param_port = NULL; 301 ret->info_callback = NULL; 302 ret->nbio = 0; 303 ret->ip[0] = 0; 304 ret->ip[1] = 0; 305 ret->ip[2] = 0; 306 ret->ip[3] = 0; 307 ret->port = 0; 308 memset((char *)&ret->them, 0, sizeof(ret->them)); 309 return (ret); 310} 311 312void BIO_CONNECT_free(BIO_CONNECT *a) 313{ 314 if (a == NULL) 315 return; 316 317 if (a->param_hostname != NULL) 318 OPENSSL_free(a->param_hostname); 319 if (a->param_port != NULL) 320 OPENSSL_free(a->param_port); 321 OPENSSL_free(a); 322} 323 324BIO_METHOD *BIO_s_connect(void) 325{ 326 return (&methods_connectp); 327} 328 329static int conn_new(BIO *bi) 330{ 331 bi->init = 0; 332 bi->num = INVALID_SOCKET; 333 bi->flags = 0; 334 if ((bi->ptr = (char *)BIO_CONNECT_new()) == NULL) 335 return (0); 336 else 337 return (1); 338} 339 340static void conn_close_socket(BIO *bio) 341{ 342 BIO_CONNECT *c; 343 344 c = (BIO_CONNECT *)bio->ptr; 345 if (bio->num != INVALID_SOCKET) { 346 /* Only do a shutdown if things were established */ 347 if (c->state == BIO_CONN_S_OK) 348 shutdown(bio->num, 2); 349 closesocket(bio->num); 350 bio->num = INVALID_SOCKET; 351 } 352} 353 354static int conn_free(BIO *a) 355{ 356 BIO_CONNECT *data; 357 358 if (a == NULL) 359 return (0); 360 data = (BIO_CONNECT *)a->ptr; 361 362 if (a->shutdown) { 363 conn_close_socket(a); 364 BIO_CONNECT_free(data); 365 a->ptr = NULL; 366 a->flags = 0; 367 a->init = 0; 368 } 369 return (1); 370} 371 372static int conn_read(BIO *b, char *out, int outl) 373{ 374 int ret = 0; 375 BIO_CONNECT *data; 376 377 data = (BIO_CONNECT *)b->ptr; 378 if (data->state != BIO_CONN_S_OK) { 379 ret = conn_state(b, data); 380 if (ret <= 0) 381 return (ret); 382 } 383 384 if (out != NULL) { 385 clear_socket_error(); 386 ret = readsocket(b->num, out, outl); 387 BIO_clear_retry_flags(b); 388 if (ret <= 0) { 389 if (BIO_sock_should_retry(ret)) 390 BIO_set_retry_read(b); 391 } 392 } 393 return (ret); 394} 395 396static int conn_write(BIO *b, const char *in, int inl) 397{ 398 int ret; 399 BIO_CONNECT *data; 400 401 data = (BIO_CONNECT *)b->ptr; 402 if (data->state != BIO_CONN_S_OK) { 403 ret = conn_state(b, data); 404 if (ret <= 0) 405 return (ret); 406 } 407 408 clear_socket_error(); 409 ret = writesocket(b->num, in, inl); 410 BIO_clear_retry_flags(b); 411 if (ret <= 0) { 412 if (BIO_sock_should_retry(ret)) 413 BIO_set_retry_write(b); 414 } 415 return (ret); 416} 417 418static long conn_ctrl(BIO *b, int cmd, long num, void *ptr) 419{ 420 BIO *dbio; 421 int *ip; 422 const char **pptr; 423 long ret = 1; 424 BIO_CONNECT *data; 425 426 data = (BIO_CONNECT *)b->ptr; 427 428 switch (cmd) { 429 case BIO_CTRL_RESET: 430 ret = 0; 431 data->state = BIO_CONN_S_BEFORE; 432 conn_close_socket(b); 433 b->flags = 0; 434 break; 435 case BIO_C_DO_STATE_MACHINE: 436 /* use this one to start the connection */ 437 if (data->state != BIO_CONN_S_OK) 438 ret = (long)conn_state(b, data); 439 else 440 ret = 1; 441 break; 442 case BIO_C_GET_CONNECT: 443 if (ptr != NULL) { 444 pptr = (const char **)ptr; 445 if (num == 0) { 446 *pptr = data->param_hostname; 447 448 } else if (num == 1) { 449 *pptr = data->param_port; 450 } else if (num == 2) { 451 *pptr = (char *)&(data->ip[0]); 452 } else if (num == 3) { 453 *((int *)ptr) = data->port; 454 } 455 if ((!b->init) || (ptr == NULL)) 456 *pptr = "not initialized"; 457 ret = 1; 458 } 459 break; 460 case BIO_C_SET_CONNECT: 461 if (ptr != NULL) { 462 b->init = 1; 463 if (num == 0) { 464 if (data->param_hostname != NULL) 465 OPENSSL_free(data->param_hostname); 466 data->param_hostname = BUF_strdup(ptr); 467 } else if (num == 1) { 468 if (data->param_port != NULL) 469 OPENSSL_free(data->param_port); 470 data->param_port = BUF_strdup(ptr); 471 } else if (num == 2) { 472 char buf[16]; 473 unsigned char *p = ptr; 474 475 BIO_snprintf(buf, sizeof buf, "%d.%d.%d.%d", 476 p[0], p[1], p[2], p[3]); 477 if (data->param_hostname != NULL) 478 OPENSSL_free(data->param_hostname); 479 data->param_hostname = BUF_strdup(buf); 480 memcpy(&(data->ip[0]), ptr, 4); 481 } else if (num == 3) { 482 char buf[DECIMAL_SIZE(int) + 1]; 483 484 BIO_snprintf(buf, sizeof buf, "%d", *(int *)ptr); 485 if (data->param_port != NULL) 486 OPENSSL_free(data->param_port); 487 data->param_port = BUF_strdup(buf); 488 data->port = *(int *)ptr; 489 } 490 } 491 break; 492 case BIO_C_SET_NBIO: 493 data->nbio = (int)num; 494 break; 495 case BIO_C_GET_FD: 496 if (b->init) { 497 ip = (int *)ptr; 498 if (ip != NULL) 499 *ip = b->num; 500 ret = b->num; 501 } else 502 ret = -1; 503 break; 504 case BIO_CTRL_GET_CLOSE: 505 ret = b->shutdown; 506 break; 507 case BIO_CTRL_SET_CLOSE: 508 b->shutdown = (int)num; 509 break; 510 case BIO_CTRL_PENDING: 511 case BIO_CTRL_WPENDING: 512 ret = 0; 513 break; 514 case BIO_CTRL_FLUSH: 515 break; 516 case BIO_CTRL_DUP: 517 { 518 dbio = (BIO *)ptr; 519 if (data->param_port) 520 BIO_set_conn_port(dbio, data->param_port); 521 if (data->param_hostname) 522 BIO_set_conn_hostname(dbio, data->param_hostname); 523 BIO_set_nbio(dbio, data->nbio); 524 /* 525 * FIXME: the cast of the function seems unlikely to be a good 526 * idea 527 */ 528 (void)BIO_set_info_callback(dbio, 529 (bio_info_cb *)data->info_callback); 530 } 531 break; 532 case BIO_CTRL_SET_CALLBACK: 533 { 534# if 0 /* FIXME: Should this be used? -- Richard 535 * Levitte */ 536 BIOerr(BIO_F_CONN_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 537 ret = -1; 538# else 539 ret = 0; 540# endif 541 } 542 break; 543 case BIO_CTRL_GET_CALLBACK: 544 { 545 int (**fptr) (const BIO *bio, int state, int xret); 546 547 fptr = (int (**)(const BIO *bio, int state, int xret))ptr; 548 *fptr = data->info_callback; 549 } 550 break; 551 default: 552 ret = 0; 553 break; 554 } 555 return (ret); 556} 557 558static long conn_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 559{ 560 long ret = 1; 561 BIO_CONNECT *data; 562 563 data = (BIO_CONNECT *)b->ptr; 564 565 switch (cmd) { 566 case BIO_CTRL_SET_CALLBACK: 567 { 568 data->info_callback = 569 (int (*)(const struct bio_st *, int, int))fp; 570 } 571 break; 572 default: 573 ret = 0; 574 break; 575 } 576 return (ret); 577} 578 579static int conn_puts(BIO *bp, const char *str) 580{ 581 int n, ret; 582 583 n = strlen(str); 584 ret = conn_write(bp, str, n); 585 return (ret); 586} 587 588BIO *BIO_new_connect(char *str) 589{ 590 BIO *ret; 591 592 ret = BIO_new(BIO_s_connect()); 593 if (ret == NULL) 594 return (NULL); 595 if (BIO_set_conn_hostname(ret, str)) 596 return (ret); 597 else { 598 BIO_free(ret); 599 return (NULL); 600 } 601} 602 603#endif 604