1/* crypto/bio/bss_acpt.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_accept_st { 79 int state; 80 char *param_addr; 81 int accept_sock; 82 int accept_nbio; 83 char *addr; 84 int nbio; 85 /* 86 * If 0, it means normal, if 1, do a connect on bind failure, and if 87 * there is no-one listening, bind with SO_REUSEADDR. If 2, always use 88 * SO_REUSEADDR. 89 */ 90 int bind_mode; 91 BIO *bio_chain; 92} BIO_ACCEPT; 93 94static int acpt_write(BIO *h, const char *buf, int num); 95static int acpt_read(BIO *h, char *buf, int size); 96static int acpt_puts(BIO *h, const char *str); 97static long acpt_ctrl(BIO *h, int cmd, long arg1, void *arg2); 98static int acpt_new(BIO *h); 99static int acpt_free(BIO *data); 100static int acpt_state(BIO *b, BIO_ACCEPT *c); 101static void acpt_close_socket(BIO *data); 102static BIO_ACCEPT *BIO_ACCEPT_new(void); 103static void BIO_ACCEPT_free(BIO_ACCEPT *a); 104 105# define ACPT_S_BEFORE 1 106# define ACPT_S_GET_ACCEPT_SOCKET 2 107# define ACPT_S_OK 3 108 109static BIO_METHOD methods_acceptp = { 110 BIO_TYPE_ACCEPT, 111 "socket accept", 112 acpt_write, 113 acpt_read, 114 acpt_puts, 115 NULL, /* connect_gets, */ 116 acpt_ctrl, 117 acpt_new, 118 acpt_free, 119 NULL, 120}; 121 122BIO_METHOD *BIO_s_accept(void) 123{ 124 return (&methods_acceptp); 125} 126 127static int acpt_new(BIO *bi) 128{ 129 BIO_ACCEPT *ba; 130 131 bi->init = 0; 132 bi->num = INVALID_SOCKET; 133 bi->flags = 0; 134 if ((ba = BIO_ACCEPT_new()) == NULL) 135 return (0); 136 bi->ptr = (char *)ba; 137 ba->state = ACPT_S_BEFORE; 138 bi->shutdown = 1; 139 return (1); 140} 141 142static BIO_ACCEPT *BIO_ACCEPT_new(void) 143{ 144 BIO_ACCEPT *ret; 145 146 if ((ret = (BIO_ACCEPT *)OPENSSL_malloc(sizeof(BIO_ACCEPT))) == NULL) 147 return (NULL); 148 149 memset(ret, 0, sizeof(BIO_ACCEPT)); 150 ret->accept_sock = INVALID_SOCKET; 151 ret->bind_mode = BIO_BIND_NORMAL; 152 return (ret); 153} 154 155static void BIO_ACCEPT_free(BIO_ACCEPT *a) 156{ 157 if (a == NULL) 158 return; 159 160 if (a->param_addr != NULL) 161 OPENSSL_free(a->param_addr); 162 if (a->addr != NULL) 163 OPENSSL_free(a->addr); 164 if (a->bio_chain != NULL) 165 BIO_free(a->bio_chain); 166 OPENSSL_free(a); 167} 168 169static void acpt_close_socket(BIO *bio) 170{ 171 BIO_ACCEPT *c; 172 173 c = (BIO_ACCEPT *)bio->ptr; 174 if (c->accept_sock != INVALID_SOCKET) { 175 shutdown(c->accept_sock, 2); 176 closesocket(c->accept_sock); 177 c->accept_sock = INVALID_SOCKET; 178 bio->num = INVALID_SOCKET; 179 } 180} 181 182static int acpt_free(BIO *a) 183{ 184 BIO_ACCEPT *data; 185 186 if (a == NULL) 187 return (0); 188 data = (BIO_ACCEPT *)a->ptr; 189 190 if (a->shutdown) { 191 acpt_close_socket(a); 192 BIO_ACCEPT_free(data); 193 a->ptr = NULL; 194 a->flags = 0; 195 a->init = 0; 196 } 197 return (1); 198} 199 200static int acpt_state(BIO *b, BIO_ACCEPT *c) 201{ 202 BIO *bio = NULL, *dbio; 203 int s = -1; 204 int i; 205 206 again: 207 switch (c->state) { 208 case ACPT_S_BEFORE: 209 if (c->param_addr == NULL) { 210 BIOerr(BIO_F_ACPT_STATE, BIO_R_NO_ACCEPT_PORT_SPECIFIED); 211 return (-1); 212 } 213 s = BIO_get_accept_socket(c->param_addr, c->bind_mode); 214 if (s == INVALID_SOCKET) 215 return (-1); 216 217 if (c->accept_nbio) { 218 if (!BIO_socket_nbio(s, 1)) { 219 closesocket(s); 220 BIOerr(BIO_F_ACPT_STATE, 221 BIO_R_ERROR_SETTING_NBIO_ON_ACCEPT_SOCKET); 222 return (-1); 223 } 224 } 225 c->accept_sock = s; 226 b->num = s; 227 c->state = ACPT_S_GET_ACCEPT_SOCKET; 228 return (1); 229 /* break; */ 230 case ACPT_S_GET_ACCEPT_SOCKET: 231 if (b->next_bio != NULL) { 232 c->state = ACPT_S_OK; 233 goto again; 234 } 235 BIO_clear_retry_flags(b); 236 b->retry_reason = 0; 237 i = BIO_accept(c->accept_sock, &(c->addr)); 238 239 /* -2 return means we should retry */ 240 if (i == -2) { 241 BIO_set_retry_special(b); 242 b->retry_reason = BIO_RR_ACCEPT; 243 return -1; 244 } 245 246 if (i < 0) 247 return (i); 248 249 bio = BIO_new_socket(i, BIO_CLOSE); 250 if (bio == NULL) 251 goto err; 252 253 BIO_set_callback(bio, BIO_get_callback(b)); 254 BIO_set_callback_arg(bio, BIO_get_callback_arg(b)); 255 256 if (c->nbio) { 257 if (!BIO_socket_nbio(i, 1)) { 258 BIOerr(BIO_F_ACPT_STATE, 259 BIO_R_ERROR_SETTING_NBIO_ON_ACCEPTED_SOCKET); 260 goto err; 261 } 262 } 263 264 /* 265 * If the accept BIO has an bio_chain, we dup it and put the new 266 * socket at the end. 267 */ 268 if (c->bio_chain != NULL) { 269 if ((dbio = BIO_dup_chain(c->bio_chain)) == NULL) 270 goto err; 271 if (!BIO_push(dbio, bio)) 272 goto err; 273 bio = dbio; 274 } 275 if (BIO_push(b, bio) == NULL) 276 goto err; 277 278 c->state = ACPT_S_OK; 279 return (1); 280 err: 281 if (bio != NULL) 282 BIO_free(bio); 283 else if (s >= 0) 284 closesocket(s); 285 return (0); 286 /* break; */ 287 case ACPT_S_OK: 288 if (b->next_bio == NULL) { 289 c->state = ACPT_S_GET_ACCEPT_SOCKET; 290 goto again; 291 } 292 return (1); 293 /* break; */ 294 default: 295 return (0); 296 /* break; */ 297 } 298 299} 300 301static int acpt_read(BIO *b, char *out, int outl) 302{ 303 int ret = 0; 304 BIO_ACCEPT *data; 305 306 BIO_clear_retry_flags(b); 307 data = (BIO_ACCEPT *)b->ptr; 308 309 while (b->next_bio == NULL) { 310 ret = acpt_state(b, data); 311 if (ret <= 0) 312 return (ret); 313 } 314 315 ret = BIO_read(b->next_bio, out, outl); 316 BIO_copy_next_retry(b); 317 return (ret); 318} 319 320static int acpt_write(BIO *b, const char *in, int inl) 321{ 322 int ret; 323 BIO_ACCEPT *data; 324 325 BIO_clear_retry_flags(b); 326 data = (BIO_ACCEPT *)b->ptr; 327 328 while (b->next_bio == NULL) { 329 ret = acpt_state(b, data); 330 if (ret <= 0) 331 return (ret); 332 } 333 334 ret = BIO_write(b->next_bio, in, inl); 335 BIO_copy_next_retry(b); 336 return (ret); 337} 338 339static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr) 340{ 341 int *ip; 342 long ret = 1; 343 BIO_ACCEPT *data; 344 char **pp; 345 346 data = (BIO_ACCEPT *)b->ptr; 347 348 switch (cmd) { 349 case BIO_CTRL_RESET: 350 ret = 0; 351 data->state = ACPT_S_BEFORE; 352 acpt_close_socket(b); 353 b->flags = 0; 354 break; 355 case BIO_C_DO_STATE_MACHINE: 356 /* use this one to start the connection */ 357 ret = (long)acpt_state(b, data); 358 break; 359 case BIO_C_SET_ACCEPT: 360 if (ptr != NULL) { 361 if (num == 0) { 362 b->init = 1; 363 if (data->param_addr != NULL) 364 OPENSSL_free(data->param_addr); 365 data->param_addr = BUF_strdup(ptr); 366 } else if (num == 1) { 367 data->accept_nbio = (ptr != NULL); 368 } else if (num == 2) { 369 if (data->bio_chain != NULL) 370 BIO_free(data->bio_chain); 371 data->bio_chain = (BIO *)ptr; 372 } 373 } 374 break; 375 case BIO_C_SET_NBIO: 376 data->nbio = (int)num; 377 break; 378 case BIO_C_SET_FD: 379 b->init = 1; 380 b->num = *((int *)ptr); 381 data->accept_sock = b->num; 382 data->state = ACPT_S_GET_ACCEPT_SOCKET; 383 b->shutdown = (int)num; 384 b->init = 1; 385 break; 386 case BIO_C_GET_FD: 387 if (b->init) { 388 ip = (int *)ptr; 389 if (ip != NULL) 390 *ip = data->accept_sock; 391 ret = data->accept_sock; 392 } else 393 ret = -1; 394 break; 395 case BIO_C_GET_ACCEPT: 396 if (b->init) { 397 if (ptr != NULL) { 398 pp = (char **)ptr; 399 *pp = data->param_addr; 400 } else 401 ret = -1; 402 } else 403 ret = -1; 404 break; 405 case BIO_CTRL_GET_CLOSE: 406 ret = b->shutdown; 407 break; 408 case BIO_CTRL_SET_CLOSE: 409 b->shutdown = (int)num; 410 break; 411 case BIO_CTRL_PENDING: 412 case BIO_CTRL_WPENDING: 413 ret = 0; 414 break; 415 case BIO_CTRL_FLUSH: 416 break; 417 case BIO_C_SET_BIND_MODE: 418 data->bind_mode = (int)num; 419 break; 420 case BIO_C_GET_BIND_MODE: 421 ret = (long)data->bind_mode; 422 break; 423 case BIO_CTRL_DUP: 424/*- dbio=(BIO *)ptr; 425 if (data->param_port) EAY EAY 426 BIO_set_port(dbio,data->param_port); 427 if (data->param_hostname) 428 BIO_set_hostname(dbio,data->param_hostname); 429 BIO_set_nbio(dbio,data->nbio); */ 430 break; 431 432 default: 433 ret = 0; 434 break; 435 } 436 return (ret); 437} 438 439static int acpt_puts(BIO *bp, const char *str) 440{ 441 int n, ret; 442 443 n = strlen(str); 444 ret = acpt_write(bp, str, n); 445 return (ret); 446} 447 448BIO *BIO_new_accept(char *str) 449{ 450 BIO *ret; 451 452 ret = BIO_new(BIO_s_accept()); 453 if (ret == NULL) 454 return (NULL); 455 if (BIO_set_accept_port(ret, str)) 456 return (ret); 457 else { 458 BIO_free(ret); 459 return (NULL); 460 } 461} 462 463#endif 464