/* crypto/bio/bss_acpt.c */ /* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ #ifndef NO_SOCK #include #include #define USE_SOCKETS #include "cryptlib.h" #include "bio.h" /* BIOerr(BIO_F_WSASTARTUP,BIO_R_WSASTARTUP ); */ #ifdef WIN16 #define SOCKET_PROTOCOL 0 /* more microsoft stupidity */ #else #define SOCKET_PROTOCOL IPPROTO_TCP #endif typedef struct bio_accept_st { int state; char *param_addr; int accept_sock; int accept_nbio; char *addr; int nbio; BIO *bio_chain; } BIO_ACCEPT; #ifndef NOPROTO static int acpt_write(BIO *h,char *buf,int num); static int acpt_read(BIO *h,char *buf,int size); static int acpt_puts(BIO *h,char *str); static long acpt_ctrl(BIO *h,int cmd,long arg1,char *arg2); static int acpt_new(BIO *h); static int acpt_free(BIO *data); #else static int acpt_write(); static int acpt_read(); static int acpt_puts(); static long acpt_ctrl(); static int acpt_new(); static int acpt_free(); #endif #ifndef NOPROTO static int acpt_state(BIO *b, BIO_ACCEPT *c); static void acpt_close_socket(BIO *data); BIO_ACCEPT *BIO_ACCEPT_new(void ); void BIO_ACCEPT_free(BIO_ACCEPT *a); #else static int acpt_state(); static void acpt_close_socket(); BIO_ACCEPT *BIO_ACCEPT_new(); void BIO_ACCEPT_free(); #endif #define ACPT_S_BEFORE 1 #define ACPT_S_GET_ACCEPT_SOCKET 2 #define ACPT_S_OK 3 static BIO_METHOD methods_acceptp= { BIO_TYPE_ACCEPT,"socket accept", acpt_write, acpt_read, acpt_puts, NULL, /* connect_gets, */ acpt_ctrl, acpt_new, acpt_free, }; BIO_METHOD *BIO_s_accept() { return(&methods_acceptp); } static int acpt_new(bi) BIO *bi; { BIO_ACCEPT *ba; bi->init=0; bi->num=INVALID_SOCKET; bi->flags=0; if ((ba=BIO_ACCEPT_new()) == NULL) return(0); bi->ptr=(char *)ba; ba->state=ACPT_S_BEFORE; bi->shutdown=1; return(1); } BIO_ACCEPT *BIO_ACCEPT_new() { BIO_ACCEPT *ret; if ((ret=(BIO_ACCEPT *)Malloc(sizeof(BIO_ACCEPT))) == NULL) return(NULL); memset(ret,0,sizeof(BIO_ACCEPT)); ret->accept_sock=INVALID_SOCKET; return(ret); } void BIO_ACCEPT_free(a) BIO_ACCEPT *a; { if (a->param_addr != NULL) Free(a->param_addr); if (a->addr != NULL) Free(a->addr); if (a->bio_chain != NULL) BIO_free(a->bio_chain); Free(a); } static void acpt_close_socket(bio) BIO *bio; { BIO_ACCEPT *c; c=(BIO_ACCEPT *)bio->ptr; if (c->accept_sock != INVALID_SOCKET) { shutdown(c->accept_sock,2); # ifdef WINDOWS closesocket(c->accept_sock); # else close(c->accept_sock); # endif c->accept_sock=INVALID_SOCKET; bio->num=INVALID_SOCKET; } } static int acpt_free(a) BIO *a; { BIO_ACCEPT *data; if (a == NULL) return(0); data=(BIO_ACCEPT *)a->ptr; if (a->shutdown) { acpt_close_socket(a); BIO_ACCEPT_free(data); a->ptr=NULL; a->flags=0; a->init=0; } return(1); } static int acpt_state(b,c) BIO *b; BIO_ACCEPT *c; { BIO *bio=NULL,*dbio; unsigned long l=1; int s= -1; int i; again: switch (c->state) { case ACPT_S_BEFORE: if (c->param_addr == NULL) { BIOerr(BIO_F_ACPT_STATE,BIO_R_NO_ACCEPT_PORT_SPECIFIED); return(-1); } s=BIO_get_accept_socket(c->param_addr); if (s == INVALID_SOCKET) return(-1); #ifdef FIONBIO if (c->accept_nbio) { i=BIO_socket_ioctl(b->num,FIONBIO,&l); if (i < 0) { #ifdef WINDOWS closesocket(s); #else close(s); # endif BIOerr(BIO_F_ACPT_STATE,BIO_R_ERROR_SETTING_NBIO_ON_ACCEPT_SOCKET); return(-1); } } #endif c->accept_sock=s; b->num=s; c->state=ACPT_S_GET_ACCEPT_SOCKET; return(1); break; case ACPT_S_GET_ACCEPT_SOCKET: if (b->next_bio != NULL) { c->state=ACPT_S_OK; goto again; } i=BIO_accept(c->accept_sock,&(c->addr)); if (i < 0) return(i); bio=BIO_new_socket(i,BIO_CLOSE); if (bio == NULL) goto err; BIO_set_callback(bio,BIO_get_callback(b)); BIO_set_callback_arg(bio,BIO_get_callback_arg(b)); #ifdef FIONBIO if (c->nbio) { i=BIO_socket_ioctl(i,FIONBIO,&l); if (i < 0) { BIOerr(BIO_F_ACPT_STATE,BIO_R_ERROR_SETTING_NBIO_ON_ACCEPTED_SOCKET); goto err; } } #endif /* If the accept BIO has an bio_chain, we dup it and * put the new socket at the end. */ if (c->bio_chain != NULL) { if ((dbio=BIO_dup_chain(c->bio_chain)) == NULL) goto err; if (!BIO_push(dbio,bio)) goto err; bio=dbio; } if (BIO_push(b,bio) == NULL) goto err; c->state=ACPT_S_OK; return(1); err: if (bio != NULL) BIO_free(bio); else if (s >= 0) { #ifdef WINDOWS closesocket(s); #else close(s); # endif } return(0); break; case ACPT_S_OK: if (b->next_bio == NULL) { c->state=ACPT_S_GET_ACCEPT_SOCKET; goto again; } return(1); break; default: return(0); break; } } static int acpt_read(b,out,outl) BIO *b; char *out; int outl; { int ret=0; BIO_ACCEPT *data; BIO_clear_retry_flags(b); data=(BIO_ACCEPT *)b->ptr; while (b->next_bio == NULL) { ret=acpt_state(b,data); if (ret <= 0) return(ret); } ret=BIO_read(b->next_bio,out,outl); BIO_copy_next_retry(b); return(ret); } static int acpt_write(b,in,inl) BIO *b; char *in; int inl; { int ret; BIO_ACCEPT *data; BIO_clear_retry_flags(b); data=(BIO_ACCEPT *)b->ptr; while (b->next_bio == NULL) { ret=acpt_state(b,data); if (ret <= 0) return(ret); } ret=BIO_write(b->next_bio,in,inl); BIO_copy_next_retry(b); return(ret); } static long acpt_ctrl(b,cmd,num,ptr) BIO *b; int cmd; long num; char *ptr; { BIO *dbio; int *ip; long ret=1; BIO_ACCEPT *data; data=(BIO_ACCEPT *)b->ptr; switch (cmd) { case BIO_CTRL_RESET: ret=0; data->state=ACPT_S_BEFORE; acpt_close_socket(b); b->flags=0; break; case BIO_C_DO_STATE_MACHINE: /* use this one to start the connection */ ret=(long)acpt_state(b,data); break; case BIO_C_SET_ACCEPT: if (ptr != NULL) { if (num == 0) { b->init=1; if (data->param_addr != NULL) Free(data->param_addr); data->param_addr=BUF_strdup(ptr); } else if (num == 1) { data->accept_nbio=(ptr != NULL); } else if (num == 2) { if (data->bio_chain != NULL) BIO_free(data->bio_chain); data->bio_chain=(BIO *)ptr; } } break; case BIO_C_SET_NBIO: data->nbio=(int)num; break; case BIO_C_GET_FD: if (b->init) { ip=(int *)ptr; if (ip != NULL) *ip=data->accept_sock; ret=b->num; } else ret= -1; break; case BIO_CTRL_GET_CLOSE: ret=b->shutdown; break; case BIO_CTRL_SET_CLOSE: b->shutdown=(int)num; break; case BIO_CTRL_PENDING: case BIO_CTRL_WPENDING: ret=0; break; case BIO_CTRL_FLUSH: break; case BIO_CTRL_DUP: dbio=(BIO *)ptr; /* if (data->param_port) EAY EAY BIO_set_port(dbio,data->param_port); if (data->param_hostname) BIO_set_hostname(dbio,data->param_hostname); BIO_set_nbio(dbio,data->nbio); */ break; default: ret=0; break; } return(ret); } static int acpt_puts(bp,str) BIO *bp; char *str; { int n,ret; n=strlen(str); ret=acpt_write(bp,str,n); return(ret); } BIO *BIO_new_accept(str) char *str; { BIO *ret; ret=BIO_new(BIO_s_accept()); if (ret == NULL) return(NULL); if (BIO_set_accept_port(ret,str)) return(ret); else { BIO_free(ret); return(NULL); } } #endif