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