Hi,

this patch adds a new macro BIO_set_conn_localport(bio, "hostname:port") to be used
with BIO connection streams.


The function binds the client side of the socket to the given host and port
before it tries connecting to the server.

Usage of this function is optional. If it isn't called, a port assigned by
the operating system is used. That's exactly the behaviour of the current implementation.


The patch bases on OpenSSL 0.9.7e and has been testen on Windows 2000,
AIX 4.3, SunOS 5.6, SuSE Linux 8.1 and  HP-UX 10.20.


Example code:

BIO *cbio, *out;
int len;
char tmpbuf[1024];

ERR_load_crypto_strings();
cbio = BIO_new_connect("localhost:http");

BIO_set_conn_localport("localhost:4444"); /* use port 4444 on client side */

out = BIO_new_fp(stdout, BIO_NOCLOSE);
if(BIO_do_connect(cbio) <= 0) {
       fprintf(stderr, "Error connecting to server\n");
       ERR_print_errors_fp(stderr);
       /* whatever ... */
       }
BIO_puts(cbio, "GET / HTTP/1.0\n\n");
for(;;) {
       len = BIO_read(cbio, tmpbuf, 1024);
       if(len <= 0) break;
       BIO_write(out, tmpbuf, len);
}
BIO_free(cbio);
BIO_free(out);



J�rg Matysiak
Software Development Systems Management
CENIT AG Systemhaus

mailto: j.matysiak (at) cenit.de
http://www.cenit-group.com


diff -ur -x CVS -x '*.exe' -x '*.o' -x '*.bak' -x Configure -x apps -x '*.0' -x 
'*.s' -x Makefile -x lib -x test -x '*.obj' -x opensslconf.h 
openssl_orig/crypto/bio/bio.h openssl/crypto/bio/bio.h
--- openssl_orig/crypto/bio/bio.h       2004-11-24 11:10:15.000000000 +0100
+++ openssl/crypto/bio/bio.h    2005-02-07 17:08:25.000000000 +0100
@@ -291,6 +291,7 @@
 #define BIO_CONN_S_BEFORE              1
 #define BIO_CONN_S_GET_IP              2
 #define BIO_CONN_S_GET_PORT            3
+#define BIO_CONN_S_BIND_SOCKET 31 /* 31 means 3.1 here (new status is between 
GET_PORT and CREATE_SOCKET) */
 #define BIO_CONN_S_CREATE_SOCKET       4
 #define BIO_CONN_S_CONNECT             5
 #define BIO_CONN_S_OK                  6
@@ -358,6 +359,8 @@
 #define BIO_set_conn_port(b,port) BIO_ctrl(b,BIO_C_SET_CONNECT,1,(char *)port)
 #define BIO_set_conn_ip(b,ip)    BIO_ctrl(b,BIO_C_SET_CONNECT,2,(char *)ip)
 #define BIO_set_conn_int_port(b,port) BIO_ctrl(b,BIO_C_SET_CONNECT,3,(char 
*)port)
+#define BIO_set_conn_localport(b,name) BIO_ctrl(b,BIO_C_SET_CONNECT,4,(char*) 
name)
+
 #define BIO_get_conn_hostname(b)  BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,0)
 #define BIO_get_conn_port(b)      BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,1)
 #define BIO_get_conn_ip(b)              BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,2)
diff -ur -x CVS -x '*.exe' -x '*.o' -x '*.bak' -x Configure -x apps -x '*.0' -x 
'*.s' -x Makefile -x lib -x test -x '*.obj' -x opensslconf.h 
openssl_orig/crypto/bio/bss_conn.c openssl/crypto/bio/bss_conn.c
--- openssl_orig/crypto/bio/bss_conn.c  2004-11-24 11:10:15.000000000 +0100
+++ openssl/crypto/bio/bss_conn.c       2005-02-07 17:08:25.000000000 +0100
@@ -87,6 +87,9 @@
        unsigned char ip[4];
        unsigned short port;
 
+   char *local_hostname;
+   unsigned short local_port;
+
        struct sockaddr_in them;
 
        /* int socket; this will be kept in bio->num so that it is
@@ -219,9 +222,82 @@
                                goto exit_loop;
                                }
                        b->num=ret;
-                       c->state=BIO_CONN_S_NBIO;
+                       c->state=BIO_CONN_S_BIND_SOCKET;
                        break;
 
+      case BIO_CONN_S_BIND_SOCKET:
+         if (NULL != c->local_hostname)
+         {
+            char *p = c->local_hostname;
+            struct sockaddr_in local_addr;
+            
+
+            /* seach for ':' */
+            for (; (*p != '\0') && (*p != ':') ; p++); /* no body */
+            if (*p == ':')
+            {
+               char *q = p+1;            
+               
+               for(;(*q != '\0') && ('0' <= *q) && (*q <= '9');q++)
+               {
+                  c->local_port=10*(c->local_port) + (*q - '0');
+               }
+            }
+            *p = '\0';
+
+            memset((char *)&local_addr,0,sizeof(local_addr));
+            local_addr.sin_family=AF_INET;
+
+            if (c->local_port > 0)
+            {
+               local_addr.sin_port=htons(c->local_port);
+            }
+            else
+            {
+               local_addr.sin_port=0;
+            }
+            
+            if ((strlen(c->local_hostname) != 0) && (strcmp("*", 
c->local_hostname) != 0))
+            {
+               unsigned char ip[4];
+
+               if (BIO_get_host_ip(c->local_hostname,&(ip[0])))
+               {
+                  unsigned long l;
+                  l=(unsigned long)
+                     ((unsigned long)ip[0]<<24L)|
+                     ((unsigned long)ip[1]<<16L)|
+                     ((unsigned long)ip[2]<< 8L)|
+                     ((unsigned long)ip[3]);
+                  local_addr.sin_addr.s_addr=htonl(l);
+               }
+            }
+            else
+            {
+               local_addr.sin_addr.s_addr=INADDR_ANY;
+            }
+
+            if (bind(b->num,(struct sockaddr *)&local_addr,sizeof(local_addr)) 
== -1)
+            {
+               int err_num=get_last_socket_error();
+               char local_port[10];
+
+               sprintf(local_port, "%d", c->local_port);
+
+               closesocket(b->num);
+               b->num = -1;
+
+               SYSerr(SYS_F_SOCKET,get_last_socket_error());
+               ERR_add_error_data(4,"local_address=",c->local_hostname,
+                                  ":", local_port);
+               
+               BIOerr(BIO_F_CONN_STATE,BIO_R_UNABLE_TO_CREATE_SOCKET);
+               goto exit_loop;
+            }
+         } /* endif c->local_hostname */
+         c->state=BIO_CONN_S_NBIO;
+      break;
+
                case BIO_CONN_S_NBIO:
                        if (c->nbio)
                                {
@@ -334,6 +410,8 @@
        ret->ip[2]=0;
        ret->ip[3]=0;
        ret->port=0;
+   ret->local_hostname=NULL;
+   ret->local_port=0;
        memset((char *)&ret->them,0,sizeof(ret->them));
        return(ret);
        }
@@ -538,7 +616,13 @@
                                data->param_port=BUF_strdup(buf);
                                data->port= *(int *)ptr;
                                }
-                       }
+         else if (num == 4)
+         {
+            if (data->local_hostname != NULL)
+                                       OPENSSL_free(data->local_hostname);
+            data->local_hostname=strdup(ptr);
+         }
+               }
                break;
        case BIO_C_SET_NBIO:
                data->nbio=(int)num;

Reply via email to