X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fbio%2Fbss_conn.c;h=91e47e92eb45baf1b93827871dccfc5a388803a3;hp=4e31e3c1f8a527ffd8b2c8539d9c3a5e742ea28e;hb=16bc45ba956fdf07c7cda7feda88de597569df63;hpb=b7896b3cb86d80206af14a14d69b0717786f2729 diff --git a/crypto/bio/bss_conn.c b/crypto/bio/bss_conn.c index 4e31e3c1f8..91e47e92eb 100644 --- a/crypto/bio/bss_conn.c +++ b/crypto/bio/bss_conn.c @@ -1,5 +1,5 @@ /* crypto/bio/bss_conn.c */ -/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written @@ -56,22 +56,26 @@ * [including the GNU Public Licence.] */ -#ifndef NO_SOCK - #include #include #define USE_SOCKETS #include "cryptlib.h" -#include "bio.h" +#include -/* BIOerr(BIO_F_WSASTARTUP,BIO_R_WSASTARTUP ); */ +#ifndef OPENSSL_NO_SOCK -#ifdef WIN16 +#ifdef OPENSSL_SYS_WIN16 #define SOCKET_PROTOCOL 0 /* more microsoft stupidity */ #else #define SOCKET_PROTOCOL IPPROTO_TCP #endif +#if (defined(OPENSSL_SYS_VMS) && __VMS_VER < 70000000) +/* FIONBIO used as a switch to enable ioctl, and that isn't in VMS < 7.0 */ +#undef FIONBIO +#endif + + typedef struct bio_connect_st { int state; @@ -81,59 +85,36 @@ typedef struct bio_connect_st int nbio; unsigned char ip[4]; - short port; + unsigned short port; struct sockaddr_in them; /* int socket; this will be kept in bio->num so that it is - * compatable with the bss_sock bio */ - int error; + * compatible with the bss_sock bio */ + + /* called when the connection is initially made + * callback(BIO,state,ret); The callback should return + * 'ret'. state is for compatibility with the ssl info_callback */ + int (*info_callback)(const BIO *bio,int state,int ret); } BIO_CONNECT; -#ifndef NOPROTO -static int conn_write(BIO *h,char *buf,int num); -static int conn_read(BIO *h,char *buf,int size); -static int conn_puts(BIO *h,char *str); -static long conn_ctrl(BIO *h,int cmd,long arg1,char *arg2); +static int conn_write(BIO *h, const char *buf, int num); +static int conn_read(BIO *h, char *buf, int size); +static int conn_puts(BIO *h, const char *str); +static long conn_ctrl(BIO *h, int cmd, long arg1, void *arg2); static int conn_new(BIO *h); static int conn_free(BIO *data); -#else -static int conn_write(); -static int conn_read(); -static int conn_puts(); -static long conn_ctrl(); -static int conn_new(); -static int conn_free(); -#endif - -#ifndef NOPROTO +static long conn_callback_ctrl(BIO *h, int cmd, bio_info_cb *); static int conn_state(BIO *b, BIO_CONNECT *c); static void conn_close_socket(BIO *data); BIO_CONNECT *BIO_CONNECT_new(void ); void BIO_CONNECT_free(BIO_CONNECT *a); -#else - -static int conn_state(); -static void conn_close_socket(); -BIO_CONNECT *BIO_CONNECT_new(); -void BIO_CONNECT_free(); - -#endif - -#define CONN_S_BEFORE 1 -#define CONN_S_GET_IP 2 -#define CONN_S_GET_PORT 3 -#define CONN_S_CREATE_SOCKET 4 -#define CONN_S_CONNECT 5 -#define CONN_S_OK 6 -#define CONN_S_BLOCKED_CONNECT 7 -#define CONN_S_NBIO 8 - static BIO_METHOD methods_connectp= { - BIO_TYPE_CONNECT,"socket connect", + BIO_TYPE_CONNECT, + "socket connect", conn_write, conn_read, conn_puts, @@ -141,164 +122,212 @@ static BIO_METHOD methods_connectp= conn_ctrl, conn_new, conn_free, + conn_callback_ctrl, }; -static int conn_state(b,c) -BIO *b; -BIO_CONNECT *c; +static int conn_state(BIO *b, BIO_CONNECT *c) { int ret= -1,i; unsigned long l; char *p,*q; + int (*cb)(const BIO *,int,int)=NULL; - switch (c->state) - { - case CONN_S_BEFORE: - p=c->param_hostname; - if (p == NULL) - { - BIOerr(BIO_F_CONN_STATE,BIO_R_NO_HOSTHNAME_SPECIFIED); - break; - } - for ( ; *p != '\0'; p++) - { - if ((*p == ':') || (*p == '/')) break; - } + if (c->info_callback != NULL) + cb=c->info_callback; - i= *p; - if ((i == ':') || (i == '/')) + for (;;) + { + switch (c->state) { + case BIO_CONN_S_BEFORE: + p=c->param_hostname; + if (p == NULL) + { + BIOerr(BIO_F_CONN_STATE,BIO_R_NO_HOSTNAME_SPECIFIED); + goto exit_loop; + } + for ( ; *p != '\0'; p++) + { + if ((*p == ':') || (*p == '/')) break; + } - *(p++)='\0'; - if (i == ':') + i= *p; + if ((i == ':') || (i == '/')) { - for (q=p; *q; q++) - if (*q == '/') - { - *q='\0'; - break; - } - if (c->param_port != NULL) - Free(c->param_port); - c->param_port=BUF_strdup(p); + + *(p++)='\0'; + if (i == ':') + { + for (q=p; *q; q++) + if (*q == '/') + { + *q='\0'; + break; + } + if (c->param_port != NULL) + OPENSSL_free(c->param_port); + c->param_port=BUF_strdup(p); + } } - } - if (p == NULL) - { - BIOerr(BIO_F_CONN_STATE,BIO_R_NO_PORT_SPECIFIED); + if (c->param_port == NULL) + { + BIOerr(BIO_F_CONN_STATE,BIO_R_NO_PORT_SPECIFIED); + ERR_add_error_data(2,"host=",c->param_hostname); + goto exit_loop; + } + c->state=BIO_CONN_S_GET_IP; break; - } - c->state=CONN_S_GET_IP; - case CONN_S_GET_IP: - if (BIO_get_host_ip(c->param_hostname,&(c->ip[0])) <= 0) + case BIO_CONN_S_GET_IP: + if (BIO_get_host_ip(c->param_hostname,&(c->ip[0])) <= 0) + goto exit_loop; + c->state=BIO_CONN_S_GET_PORT; break; - c->state=CONN_S_GET_PORT; - case CONN_S_GET_PORT: - if (BIO_get_port(c->param_port,&c->port) <= 0) + case BIO_CONN_S_GET_PORT: + if (c->param_port == NULL) + { + /* abort(); */ + goto exit_loop; + } + else if (BIO_get_port(c->param_port,&c->port) <= 0) + goto exit_loop; + c->state=BIO_CONN_S_CREATE_SOCKET; break; - c->state=CONN_S_CREATE_SOCKET; - - case CONN_S_CREATE_SOCKET: - /* now setup address */ - memset((char *)&c->them,0,sizeof(c->them)); - c->them.sin_family=AF_INET; - c->them.sin_port=htons((unsigned short)c->port); - l=(unsigned long) - ((unsigned long)c->ip[0]<<24L)| - ((unsigned long)c->ip[1]<<16L)| - ((unsigned long)c->ip[2]<< 8L)| - ((unsigned long)c->ip[3]); - c->them.sin_addr.s_addr=htonl(l); - c->state=CONN_S_CREATE_SOCKET; - - ret=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL); - if (ret == INVALID_SOCKET) - { - SYSerr(SYS_F_SOCKET,errno); - BIOerr(BIO_F_CONN_STATE,BIO_R_UNABLE_TO_CREATE_SOCKET); + + case BIO_CONN_S_CREATE_SOCKET: + /* now setup address */ + memset((char *)&c->them,0,sizeof(c->them)); + c->them.sin_family=AF_INET; + c->them.sin_port=htons((unsigned short)c->port); + l=(unsigned long) + ((unsigned long)c->ip[0]<<24L)| + ((unsigned long)c->ip[1]<<16L)| + ((unsigned long)c->ip[2]<< 8L)| + ((unsigned long)c->ip[3]); + c->them.sin_addr.s_addr=htonl(l); + c->state=BIO_CONN_S_CREATE_SOCKET; + + ret=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL); + if (ret == INVALID_SOCKET) + { + SYSerr(SYS_F_SOCKET,get_last_socket_error()); + ERR_add_error_data(4,"host=",c->param_hostname, + ":",c->param_port); + BIOerr(BIO_F_CONN_STATE,BIO_R_UNABLE_TO_CREATE_SOCKET); + goto exit_loop; + } + b->num=ret; + c->state=BIO_CONN_S_NBIO; break; - } - b->num=ret; - c->state=CONN_S_NBIO; - case CONN_S_NBIO: -#ifdef FIONBIO - if (c->nbio) - { - l=1; - ret=BIO_socket_ioctl(b->num,FIONBIO,&l); - if (ret < 0) + case BIO_CONN_S_NBIO: + if (c->nbio) { - BIOerr(BIO_F_CONN_STATE,BIO_R_ERROR_SETTING_NBIO); - break; + if (!BIO_socket_nbio(b->num,1)) + { + BIOerr(BIO_F_CONN_STATE,BIO_R_ERROR_SETTING_NBIO); + ERR_add_error_data(4,"host=", + c->param_hostname, + ":",c->param_port); + goto exit_loop; + } + } + c->state=BIO_CONN_S_CONNECT; + +#if defined(SO_KEEPALIVE) && !defined(OPENSSL_SYS_MPE) + i=1; + i=setsockopt(b->num,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i)); + if (i < 0) + { + SYSerr(SYS_F_SOCKET,get_last_socket_error()); + ERR_add_error_data(4,"host=",c->param_hostname, + ":",c->param_port); + BIOerr(BIO_F_CONN_STATE,BIO_R_KEEPALIVE); + goto exit_loop; } - } #endif - c->state=CONN_S_CONNECT; + break; - case CONN_S_CONNECT: - BIO_clear_retry_flags(b); - ret=connect(b->num, - (struct sockaddr *)&c->them, - sizeof(c->them)); - b->retry_reason=0; - if (ret < 0) - { - if (BIO_sock_should_retry(ret)) + case BIO_CONN_S_CONNECT: + BIO_clear_retry_flags(b); + ret=connect(b->num, + (struct sockaddr *)&c->them, + sizeof(c->them)); + b->retry_reason=0; + if (ret < 0) { - BIO_set_retry_special(b); - c->state=CONN_S_BLOCKED_CONNECT; - b->retry_reason=BIO_RR_CONNECT; + if (BIO_sock_should_retry(ret)) + { + BIO_set_retry_special(b); + c->state=BIO_CONN_S_BLOCKED_CONNECT; + b->retry_reason=BIO_RR_CONNECT; + } + else + { + SYSerr(SYS_F_CONNECT,get_last_socket_error()); + ERR_add_error_data(4,"host=", + c->param_hostname, + ":",c->param_port); + BIOerr(BIO_F_CONN_STATE,BIO_R_CONNECT_ERROR); + } + goto exit_loop; } else + c->state=BIO_CONN_S_OK; + break; + + case BIO_CONN_S_BLOCKED_CONNECT: + i=BIO_sock_error(b->num); + if (i) { - SYSerr(SYS_F_CONNECT,errno); - BIOerr(BIO_F_CONN_STATE,BIO_R_CONNECT_ERROR); + BIO_clear_retry_flags(b); + SYSerr(SYS_F_CONNECT,i); + ERR_add_error_data(4,"host=", + c->param_hostname, + ":",c->param_port); + BIOerr(BIO_F_CONN_STATE,BIO_R_NBIO_CONNECT_ERROR); + ret=0; + goto exit_loop; } - } - else - { + else + c->state=BIO_CONN_S_OK; + break; + + case BIO_CONN_S_OK: ret=1; - c->state=CONN_S_OK; + goto exit_loop; + default: + /* abort(); */ + goto exit_loop; } - break; - case CONN_S_BLOCKED_CONNECT: - BIO_clear_retry_flags(b); - i=BIO_sock_error(b->num); - if (i) - { - SYSerr(SYS_F_CONNECT,i); - BIOerr(BIO_F_CONN_STATE,BIO_R_NBIO_CONNECT_ERROR); - } - else + if (cb != NULL) { - c->state=CONN_S_OK; - ret=1; + if (!(ret=cb((BIO *)b,c->state,ret))) + goto end; } - break; - - case CONN_S_OK: - ret=1; - break; - default: - abort(); } + + /* Loop does not exit */ +exit_loop: + if (cb != NULL) + ret=cb((BIO *)b,c->state,ret); +end: return(ret); } -BIO_CONNECT *BIO_CONNECT_new() +BIO_CONNECT *BIO_CONNECT_new(void) { BIO_CONNECT *ret; - if ((ret=(BIO_CONNECT *)Malloc(sizeof(BIO_CONNECT))) == NULL) + if ((ret=(BIO_CONNECT *)OPENSSL_malloc(sizeof(BIO_CONNECT))) == NULL) return(NULL); - ret->state=CONN_S_BEFORE; + ret->state=BIO_CONN_S_BEFORE; ret->param_hostname=NULL; ret->param_port=NULL; + ret->info_callback=NULL; ret->nbio=0; ret->ip[0]=0; ret->ip[1]=0; @@ -306,27 +335,27 @@ BIO_CONNECT *BIO_CONNECT_new() ret->ip[3]=0; ret->port=0; memset((char *)&ret->them,0,sizeof(ret->them)); - ret->error=0; return(ret); } -void BIO_CONNECT_free(a) -BIO_CONNECT *a; +void BIO_CONNECT_free(BIO_CONNECT *a) { + if(a == NULL) + return; + if (a->param_hostname != NULL) - Free(a->param_hostname); + OPENSSL_free(a->param_hostname); if (a->param_port != NULL) - Free(a->param_port); - Free(a); + OPENSSL_free(a->param_port); + OPENSSL_free(a); } -BIO_METHOD *BIO_s_connect() +BIO_METHOD *BIO_s_connect(void) { return(&methods_connectp); } -static int conn_new(bi) -BIO *bi; +static int conn_new(BIO *bi) { bi->init=0; bi->num=INVALID_SOCKET; @@ -337,8 +366,7 @@ BIO *bi; return(1); } -static void conn_close_socket(bio) -BIO *bio; +static void conn_close_socket(BIO *bio) { BIO_CONNECT *c; @@ -346,19 +374,14 @@ BIO *bio; if (bio->num != INVALID_SOCKET) { /* Only do a shutdown if things were established */ - if (c->state == CONN_S_OK) + if (c->state == BIO_CONN_S_OK) shutdown(bio->num,2); -# ifdef WINDOWS closesocket(bio->num); -# else - close(bio->num); -# endif bio->num=INVALID_SOCKET; } } -static int conn_free(a) -BIO *a; +static int conn_free(BIO *a) { BIO_CONNECT *data; @@ -376,29 +399,23 @@ BIO *a; return(1); } -static int conn_read(b,out,outl) -BIO *b; -char *out; -int outl; +static int conn_read(BIO *b, char *out, int outl) { int ret=0; BIO_CONNECT *data; data=(BIO_CONNECT *)b->ptr; - if (data->state != CONN_S_OK) + if (data->state != BIO_CONN_S_OK) { ret=conn_state(b,data); - if (ret <= 0) return(ret); + if (ret <= 0) + return(ret); } if (out != NULL) { - errno=0; -#if defined(WINDOWS) - ret=recv(b->num,out,outl,0); -#else - ret=read(b->num,out,outl); -#endif + clear_socket_error(); + ret=readsocket(b->num,out,outl); BIO_clear_retry_flags(b); if (ret <= 0) { @@ -409,27 +426,20 @@ int outl; return(ret); } -static int conn_write(b,in,inl) -BIO *b; -char *in; -int inl; +static int conn_write(BIO *b, const char *in, int inl) { int ret; BIO_CONNECT *data; data=(BIO_CONNECT *)b->ptr; - if (data->state != CONN_S_OK) + if (data->state != BIO_CONN_S_OK) { ret=conn_state(b,data); if (ret <= 0) return(ret); } - errno=0; -#if defined(WINDOWS) - ret=send(b->num,in,inl,0); -#else - ret=write(b->num,in,inl); -#endif + clear_socket_error(); + ret=writesocket(b->num,in,inl); BIO_clear_retry_flags(b); if (ret <= 0) { @@ -439,14 +449,11 @@ int inl; return(ret); } -static long conn_ctrl(b,cmd,num,ptr) -BIO *b; -int cmd; -long num; -char *ptr; +static long conn_ctrl(BIO *b, int cmd, long num, void *ptr) { BIO *dbio; int *ip; + const char **pptr; long ret=1; BIO_CONNECT *data; @@ -456,17 +463,43 @@ char *ptr; { case BIO_CTRL_RESET: ret=0; - data->state=CONN_S_BEFORE; + data->state=BIO_CONN_S_BEFORE; conn_close_socket(b); b->flags=0; break; case BIO_C_DO_STATE_MACHINE: /* use this one to start the connection */ - if (!data->state != CONN_S_OK) + if (data->state != BIO_CONN_S_OK) ret=(long)conn_state(b,data); else ret=1; break; + case BIO_C_GET_CONNECT: + if (ptr != NULL) + { + pptr=(const char **)ptr; + if (num == 0) + { + *pptr=data->param_hostname; + + } + else if (num == 1) + { + *pptr=data->param_port; + } + else if (num == 2) + { + *pptr= (char *)&(data->ip[0]); + } + else if (num == 3) + { + *((int *)ptr)=data->port; + } + if ((!b->init) || (ptr == NULL)) + *pptr="not initialized"; + ret=1; + } + break; case BIO_C_SET_CONNECT: if (ptr != NULL) { @@ -474,15 +507,37 @@ char *ptr; if (num == 0) { if (data->param_hostname != NULL) - Free(data->param_hostname); + OPENSSL_free(data->param_hostname); data->param_hostname=BUF_strdup(ptr); } else if (num == 1) { if (data->param_port != NULL) - Free(data->param_port); + OPENSSL_free(data->param_port); data->param_port=BUF_strdup(ptr); } + else if (num == 2) + { + char buf[16]; + unsigned char *p = ptr; + + BIO_snprintf(buf,sizeof buf,"%d.%d.%d.%d", + p[0],p[1],p[2],p[3]); + if (data->param_hostname != NULL) + OPENSSL_free(data->param_hostname); + data->param_hostname=BUF_strdup(buf); + memcpy(&(data->ip[0]),ptr,4); + } + else if (num == 3) + { + char buf[DECIMAL_SIZE(int)+1]; + + BIO_snprintf(buf,sizeof buf,"%d",*(int *)ptr); + if (data->param_port != NULL) + OPENSSL_free(data->param_port); + data->param_port=BUF_strdup(buf); + data->port= *(int *)ptr; + } } break; case BIO_C_SET_NBIO: @@ -512,14 +567,56 @@ char *ptr; case BIO_CTRL_FLUSH: break; case BIO_CTRL_DUP: + { dbio=(BIO *)ptr; if (data->param_port) - BIO_set_port(dbio,data->param_port); + BIO_set_conn_port(dbio,data->param_port); if (data->param_hostname) - BIO_set_hostname(dbio,data->param_hostname); + BIO_set_conn_hostname(dbio,data->param_hostname); BIO_set_nbio(dbio,data->nbio); + /* FIXME: the cast of the function seems unlikely to be a good idea */ + (void)BIO_set_info_callback(dbio,(bio_info_cb *)data->info_callback); + } + break; + case BIO_CTRL_SET_CALLBACK: + { +#if 0 /* FIXME: Should this be used? -- Richard Levitte */ + BIOerr(BIO_F_CONN_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + ret = -1; +#else + ret=0; +#endif + } + break; + case BIO_CTRL_GET_CALLBACK: + { + int (**fptr)(const BIO *bio,int state,int xret); + + fptr=(int (**)(const BIO *bio,int state,int xret))ptr; + *fptr=data->info_callback; + } + break; + default: + ret=0; break; + } + return(ret); + } + +static long conn_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) + { + long ret=1; + BIO_CONNECT *data; + + data=(BIO_CONNECT *)b->ptr; + switch (cmd) + { + case BIO_CTRL_SET_CALLBACK: + { + data->info_callback=(int (*)(const struct bio_st *, int, int))fp; + } + break; default: ret=0; break; @@ -527,9 +624,7 @@ char *ptr; return(ret); } -static int conn_puts(bp,str) -BIO *bp; -char *str; +static int conn_puts(BIO *bp, const char *str) { int n,ret; @@ -538,14 +633,13 @@ char *str; return(ret); } -BIO *BIO_new_connect(str) -char *str; +BIO *BIO_new_connect(const char *str) { BIO *ret; ret=BIO_new(BIO_s_connect()); if (ret == NULL) return(NULL); - if (BIO_set_hostname(ret,str)) + if (BIO_set_conn_hostname(ret,str)) return(ret); else {