/* 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
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;
+
+ /* called when the connection is initially made
+ * callback(BIO,state,ret); The callback should return
+ * 'ret'. state is for compatablity with the ssl info_callback */
+ int (*info_callback)();
} BIO_CONNECT;
#ifndef NOPROTO
#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,
conn_free,
};
-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)()=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)
+ 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;
+
+#ifdef SO_KEEPALIVE
+ 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)
+ if (cb != NULL)
{
- SYSerr(SYS_F_CONNECT,i);
- BIOerr(BIO_F_CONN_STATE,BIO_R_NBIO_CONNECT_ERROR);
+ if (!(ret=cb((BIO *)b,c->state,ret)))
+ goto end;
}
- else
- {
- c->state=CONN_S_OK;
- ret=1;
- }
- 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)
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;
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);
if (a->param_port != NULL)
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;
return(1);
}
-static void conn_close_socket(bio)
-BIO *bio;
+static void conn_close_socket(BIO *bio)
{
BIO_CONNECT *c;
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;
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)
{
return(ret);
}
-static int conn_write(b,in,inl)
-BIO *b;
-char *in;
-int inl;
+static int conn_write(BIO *b, 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)
{
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, char *ptr)
{
BIO *dbio;
int *ip;
+ const char **pptr;
long ret=1;
BIO_CONNECT *data;
{
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 initalised";
+ ret=1;
+ }
+ break;
case BIO_C_SET_CONNECT:
if (ptr != NULL)
{
Free(data->param_port);
data->param_port=BUF_strdup(ptr);
}
+ else if (num == 2)
+ {
+ char buf[16];
+
+ sprintf(buf,"%d.%d.%d.%d",
+ ptr[0],ptr[1],ptr[2],ptr[3]);
+ if (data->param_hostname != NULL)
+ Free(data->param_hostname);
+ data->param_hostname=BUF_strdup(buf);
+ memcpy(&(data->ip[0]),ptr,4);
+ }
+ else if (num == 3)
+ {
+ char buf[16];
+
+ sprintf(buf,"%d",*(int *)ptr);
+ if (data->param_port != NULL)
+ Free(data->param_port);
+ data->param_port=BUF_strdup(buf);
+ data->port= *(int *)ptr;
+ }
}
break;
case BIO_C_SET_NBIO:
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);
+ BIO_set_info_callback(dbio,data->info_callback);
+ break;
+ case BIO_CTRL_SET_CALLBACK:
+ data->info_callback=(int (*)())ptr;
break;
+ case BIO_CTRL_GET_CALLBACK:
+ {
+ int (**fptr)();
+ fptr=(int (**)())ptr;
+ *fptr=data->info_callback;
+ }
+ break;
default:
ret=0;
break;
return(ret);
}
-static int conn_puts(bp,str)
-BIO *bp;
-char *str;
+static int conn_puts(BIO *bp, char *str)
{
int n,ret;
return(ret);
}
-BIO *BIO_new_connect(str)
-char *str;
+BIO *BIO_new_connect(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
{