6e547bf86669c852be420a1d1c3e482e5861cd77
[openssl.git] / crypto / bio / bss_conn.c
1 /* crypto/bio/bss_conn.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 #ifndef NO_SOCK
60
61 #include <stdio.h>
62 #include <errno.h>
63 #define USE_SOCKETS
64 #include "cryptlib.h"
65 #include "bio.h"
66
67 /*      BIOerr(BIO_F_WSASTARTUP,BIO_R_WSASTARTUP ); */
68
69 #ifdef WIN16
70 #define SOCKET_PROTOCOL 0 /* more microsoft stupidity */
71 #else
72 #define SOCKET_PROTOCOL IPPROTO_TCP
73 #endif
74
75 typedef struct bio_connect_st
76         {
77         int state;
78
79         char *param_hostname;
80         char *param_port;
81         int nbio;
82
83         unsigned char ip[4];
84         short port;
85
86         struct sockaddr_in them;
87
88         /* int socket; this will be kept in bio->num so that it is
89          * compatable with the bss_sock bio */ 
90         int error;
91
92         /* called when the connection is initially made
93          *  callback(BIO,state,ret);  The callback should return
94          * 'ret'.  state is for compatablity with the ssl info_callback */
95         int (*info_callback)();
96         } BIO_CONNECT;
97
98 #ifndef NOPROTO
99 static int conn_write(BIO *h,char *buf,int num);
100 static int conn_read(BIO *h,char *buf,int size);
101 static int conn_puts(BIO *h,char *str);
102 static long conn_ctrl(BIO *h,int cmd,long arg1,char *arg2);
103 static int conn_new(BIO *h);
104 static int conn_free(BIO *data);
105 #else
106 static int conn_write();
107 static int conn_read();
108 static int conn_puts();
109 static long conn_ctrl();
110 static int conn_new();
111 static int conn_free();
112 #endif
113
114 #ifndef NOPROTO
115
116 static int conn_state(BIO *b, BIO_CONNECT *c);
117 static void conn_close_socket(BIO *data);
118 BIO_CONNECT *BIO_CONNECT_new(void );
119 void BIO_CONNECT_free(BIO_CONNECT *a);
120
121 #else
122
123 static int conn_state();
124 static void conn_close_socket();
125 BIO_CONNECT *BIO_CONNECT_new();
126 void BIO_CONNECT_free();
127
128 #endif
129
130 static BIO_METHOD methods_connectp=
131         {
132         BIO_TYPE_CONNECT,
133         "socket connect",
134         conn_write,
135         conn_read,
136         conn_puts,
137         NULL, /* connect_gets, */
138         conn_ctrl,
139         conn_new,
140         conn_free,
141         };
142
143 static int conn_state(b,c)
144 BIO *b;
145 BIO_CONNECT *c;
146         {
147         int ret= -1,i;
148         unsigned long l;
149         char *p,*q;
150         int (*cb)()=NULL;
151
152         if (c->info_callback != NULL)
153                 cb=c->info_callback;
154
155         for (;;)
156                 {
157                 switch (c->state)
158                         {
159                 case BIO_CONN_S_BEFORE:
160                         p=c->param_hostname;
161                         if (p == NULL)
162                                 {
163                                 BIOerr(BIO_F_CONN_STATE,BIO_R_NO_HOSTHNAME_SPECIFIED);
164                                 goto exit_loop;
165                                 }
166                         for ( ; *p != '\0'; p++)
167                                 {
168                                 if ((*p == ':') || (*p == '/')) break;
169                                 }
170
171                         i= *p;
172                         if ((i == ':') || (i == '/'))
173                                 {
174
175                                 *(p++)='\0';
176                                 if (i == ':')
177                                         {
178                                         for (q=p; *q; q++)
179                                                 if (*q == '/')
180                                                         {
181                                                         *q='\0';
182                                                         break;
183                                                         }
184                                         if (c->param_port != NULL)
185                                                 Free(c->param_port);
186                                         c->param_port=BUF_strdup(p);
187                                         }
188                                 }
189
190                         if (p == NULL)
191                                 {
192                                 BIOerr(BIO_F_CONN_STATE,BIO_R_NO_PORT_SPECIFIED);
193                                 ERR_add_error_data(2,"host=",c->param_hostname);
194                                 goto exit_loop;
195                                 }
196                         c->state=BIO_CONN_S_GET_IP;
197                         break;
198
199                 case BIO_CONN_S_GET_IP:
200                         if (BIO_get_host_ip(c->param_hostname,&(c->ip[0])) <= 0)
201                                 goto exit_loop;
202                         c->state=BIO_CONN_S_GET_PORT;
203                         break;
204
205                 case BIO_CONN_S_GET_PORT:
206                         if (BIO_get_port(c->param_port,&c->port) <= 0)
207                                 goto exit_loop;
208                         c->state=BIO_CONN_S_CREATE_SOCKET;
209                         break;
210
211                 case BIO_CONN_S_CREATE_SOCKET:
212                         /* now setup address */
213                         memset((char *)&c->them,0,sizeof(c->them));
214                         c->them.sin_family=AF_INET;
215                         c->them.sin_port=htons((unsigned short)c->port);
216                         l=(unsigned long)
217                                 ((unsigned long)c->ip[0]<<24L)|
218                                 ((unsigned long)c->ip[1]<<16L)|
219                                 ((unsigned long)c->ip[2]<< 8L)|
220                                 ((unsigned long)c->ip[3]);
221                         c->them.sin_addr.s_addr=htonl(l);
222                         c->state=BIO_CONN_S_CREATE_SOCKET;
223
224                         ret=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
225                         if (ret == INVALID_SOCKET)
226                                 {
227                                 SYSerr(SYS_F_SOCKET,get_last_socket_error());
228                                 ERR_add_error_data(4,"host=",c->param_hostname,
229                                         ":",c->param_port);
230                                 BIOerr(BIO_F_CONN_STATE,BIO_R_UNABLE_TO_CREATE_SOCKET);
231                                 goto exit_loop;
232                                 }
233                         b->num=ret;
234                         c->state=BIO_CONN_S_NBIO;
235                         break;
236
237                 case BIO_CONN_S_NBIO:
238 #ifdef FIONBIO
239                         if (c->nbio)
240                                 {
241                                 l=1;
242                                 ret=BIO_socket_ioctl(b->num,FIONBIO,&l);
243                                 if (ret < 0)
244                                         {
245                                         BIOerr(BIO_F_CONN_STATE,BIO_R_ERROR_SETTING_NBIO);
246                                         ERR_add_error_data(4,"host=",
247                                                 c->param_hostname,
248                                                 ":",c->param_port);
249                                         goto exit_loop;
250                                         }
251                                 }
252 #endif
253                         c->state=BIO_CONN_S_CONNECT;
254
255 #ifdef SO_KEEPALIVE
256                         i=1;
257                         i=setsockopt(b->num,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
258                         if (i < 0)
259                                 {
260                                 SYSerr(SYS_F_SOCKET,get_last_socket_error());
261                                 ERR_add_error_data(4,"host=",c->param_hostname,
262                                         ":",c->param_port);
263                                 BIOerr(BIO_F_CONN_STATE,BIO_R_KEEPALIVE);
264                                 goto exit_loop;
265                                 }
266 #endif
267                         break;
268
269                 case BIO_CONN_S_CONNECT:
270                         BIO_clear_retry_flags(b);
271                         ret=connect(b->num,
272                                 (struct sockaddr *)&c->them,
273                                 sizeof(c->them));
274                         b->retry_reason=0;
275                         if (ret < 0)
276                                 {
277                                 if (BIO_sock_should_retry(ret))
278                                         {
279                                         BIO_set_retry_special(b);
280                                         c->state=BIO_CONN_S_BLOCKED_CONNECT;
281                                         b->retry_reason=BIO_RR_CONNECT;
282                                         }
283                                 else
284                                         {
285                                         SYSerr(SYS_F_CONNECT,get_last_socket_error());
286                                         ERR_add_error_data(4,"host=",
287                                                 c->param_hostname,
288                                                 ":",c->param_port);
289                                         BIOerr(BIO_F_CONN_STATE,BIO_R_CONNECT_ERROR);
290                                         }
291                                 goto exit_loop;
292                                 }
293                         else
294                                 c->state=BIO_CONN_S_OK;
295                         break;
296
297                 case BIO_CONN_S_BLOCKED_CONNECT:
298                         i=BIO_sock_error(b->num);
299                         if (i)
300                                 {
301                                 BIO_clear_retry_flags(b);
302                                 SYSerr(SYS_F_CONNECT,i);
303                                 ERR_add_error_data(4,"host=",
304                                         c->param_hostname,
305                                         ":",c->param_port);
306                                 BIOerr(BIO_F_CONN_STATE,BIO_R_NBIO_CONNECT_ERROR);
307                                 ret=0;
308                                 goto exit_loop;
309                                 }
310                         else
311                                 c->state=BIO_CONN_S_OK;
312                         break;
313
314                 case BIO_CONN_S_OK:
315                         ret=1;
316                         goto exit_loop;
317                 default:
318                         abort();
319                         goto exit_loop;
320                         }
321
322                 if (cb != NULL)
323                         {
324                         if (!(ret=cb((BIO *)b,c->state,ret)))
325                                 goto end;
326                         }
327                 }
328
329         if (1)
330                 {
331 exit_loop:
332                 if (cb != NULL)
333                         ret=cb((BIO *)b,c->state,ret);
334                 }
335 end:
336         return(ret);
337         }
338
339 BIO_CONNECT *BIO_CONNECT_new()
340         {
341         BIO_CONNECT *ret;
342
343         if ((ret=(BIO_CONNECT *)Malloc(sizeof(BIO_CONNECT))) == NULL)
344                 return(NULL);
345         ret->state=BIO_CONN_S_BEFORE;
346         ret->param_hostname=NULL;
347         ret->param_port=NULL;
348         ret->info_callback=NULL;
349         ret->nbio=0;
350         ret->ip[0]=0;
351         ret->ip[1]=0;
352         ret->ip[2]=0;
353         ret->ip[3]=0;
354         ret->port=0;
355         memset((char *)&ret->them,0,sizeof(ret->them));
356         ret->error=0;
357         return(ret);
358         }
359
360 void BIO_CONNECT_free(a)
361 BIO_CONNECT *a;
362         {
363         if (a->param_hostname != NULL)
364                 Free(a->param_hostname);
365         if (a->param_port != NULL)
366                 Free(a->param_port);
367         Free(a);
368         }
369
370 BIO_METHOD *BIO_s_connect()
371         {
372         return(&methods_connectp);
373         }
374
375 static int conn_new(bi)
376 BIO *bi;
377         {
378         bi->init=0;
379         bi->num=INVALID_SOCKET;
380         bi->flags=0;
381         if ((bi->ptr=(char *)BIO_CONNECT_new()) == NULL)
382                 return(0);
383         else
384                 return(1);
385         }
386
387 static void conn_close_socket(bio)
388 BIO *bio;
389         {
390         BIO_CONNECT *c;
391
392         c=(BIO_CONNECT *)bio->ptr;
393         if (bio->num != INVALID_SOCKET)
394                 {
395                 /* Only do a shutdown if things were established */
396                 if (c->state == BIO_CONN_S_OK)
397                         shutdown(bio->num,2);
398 # ifdef WINDOWS
399                 closesocket(bio->num);
400 # else
401                 close(bio->num);
402 # endif
403                 bio->num=INVALID_SOCKET;
404                 }
405         }
406
407 static int conn_free(a)
408 BIO *a;
409         {
410         BIO_CONNECT *data;
411
412         if (a == NULL) return(0);
413         data=(BIO_CONNECT *)a->ptr;
414          
415         if (a->shutdown)
416                 {
417                 conn_close_socket(a);
418                 BIO_CONNECT_free(data);
419                 a->ptr=NULL;
420                 a->flags=0;
421                 a->init=0;
422                 }
423         return(1);
424         }
425         
426 static int conn_read(b,out,outl)
427 BIO *b;
428 char *out;
429 int outl;
430         {
431         int ret=0;
432         BIO_CONNECT *data;
433
434         data=(BIO_CONNECT *)b->ptr;
435         if (data->state != BIO_CONN_S_OK)
436                 {
437                 ret=conn_state(b,data);
438                 if (ret <= 0)
439                                 return(ret);
440                 }
441
442         if (out != NULL)
443                 {
444                 clear_socket_error();
445 #if defined(WINDOWS)
446                 ret=recv(b->num,out,outl,0);
447 #else
448                 ret=read(b->num,out,outl);
449 #endif
450                 BIO_clear_retry_flags(b);
451                 if (ret <= 0)
452                         {
453                         if (BIO_sock_should_retry(ret))
454                                 BIO_set_retry_read(b);
455                         }
456                 }
457         return(ret);
458         }
459
460 static int conn_write(b,in,inl)
461 BIO *b;
462 char *in;
463 int inl;
464         {
465         int ret;
466         BIO_CONNECT *data;
467
468         data=(BIO_CONNECT *)b->ptr;
469         if (data->state != BIO_CONN_S_OK)
470                 {
471                 ret=conn_state(b,data);
472                 if (ret <= 0) return(ret);
473                 }
474
475         clear_socket_error();
476 #if defined(WINDOWS)
477         ret=send(b->num,in,inl,0);
478 #else
479         ret=write(b->num,in,inl);
480 #endif
481         BIO_clear_retry_flags(b);
482         if (ret <= 0)
483                 {
484                 if (BIO_sock_should_retry(ret))
485                         BIO_set_retry_write(b);
486                 }
487         return(ret);
488         }
489
490 static long conn_ctrl(b,cmd,num,ptr)
491 BIO *b;
492 int cmd;
493 long num;
494 char *ptr;
495         {
496         BIO *dbio;
497         int *ip;
498         char **pptr;
499         long ret=1;
500         BIO_CONNECT *data;
501
502         data=(BIO_CONNECT *)b->ptr;
503
504         switch (cmd)
505                 {
506         case BIO_CTRL_RESET:
507                 ret=0;
508                 data->state=BIO_CONN_S_BEFORE;
509                 conn_close_socket(b);
510                 b->flags=0;
511                 break;
512         case BIO_C_DO_STATE_MACHINE:
513                 /* use this one to start the connection */
514                 if (!data->state != BIO_CONN_S_OK)
515                         ret=(long)conn_state(b,data);
516                 else
517                         ret=1;
518                 break;
519         case BIO_C_GET_CONNECT:
520                 if (ptr != NULL)
521                         {
522                         pptr=(char **)ptr;
523                         if (num == 0)
524                                 {
525                                 *pptr=data->param_hostname;
526
527                                 }
528                         else if (num == 1)
529                                 {
530                                 *pptr=data->param_port;
531                                 }
532                         else if (num == 2)
533                                 {
534                                 *pptr= (char *)&(data->ip[0]);
535                                 }
536                         else if (num == 3)
537                                 {
538                                 *((int *)ptr)=data->port;
539                                 }
540                         if ((!b->init) || (ptr == NULL))
541                                 *pptr="not initalised";
542                         ret=1;
543                         }
544                 break;
545         case BIO_C_SET_CONNECT:
546                 if (ptr != NULL)
547                         {
548                         b->init=1;
549                         if (num == 0)
550                                 {
551                                 if (data->param_hostname != NULL)
552                                         Free(data->param_hostname);
553                                 data->param_hostname=BUF_strdup(ptr);
554                                 }
555                         else if (num == 1)
556                                 {
557                                 if (data->param_port != NULL)
558                                         Free(data->param_port);
559                                 data->param_port=BUF_strdup(ptr);
560                                 }
561                         else if (num == 2)
562                                 memcpy(data->ip,ptr,4);
563                         else if (num == 3)
564                                 data->port= *(int *)ptr;
565                         }
566                 break;
567         case BIO_C_SET_NBIO:
568                 data->nbio=(int)num;
569                 break;
570         case BIO_C_GET_FD:
571                 if (b->init)
572                         {
573                         ip=(int *)ptr;
574                         if (ip != NULL)
575                                 *ip=b->num;
576                         ret=b->num;
577                         }
578                 else
579                         ret= -1;
580                 break;
581         case BIO_CTRL_GET_CLOSE:
582                 ret=b->shutdown;
583                 break;
584         case BIO_CTRL_SET_CLOSE:
585                 b->shutdown=(int)num;
586                 break;
587         case BIO_CTRL_PENDING:
588         case BIO_CTRL_WPENDING:
589                 ret=0;
590                 break;
591         case BIO_CTRL_FLUSH:
592                 break;
593         case BIO_CTRL_DUP:
594                 dbio=(BIO *)ptr;
595                 if (data->param_port)
596                         BIO_set_conn_port(dbio,data->param_port);
597                 if (data->param_hostname)
598                         BIO_set_conn_hostname(dbio,data->param_hostname);
599                 BIO_set_nbio(dbio,data->nbio);
600                 BIO_set_info_callback(dbio,data->info_callback);
601                 break;
602         case BIO_CTRL_SET_CALLBACK:
603                 data->info_callback=(int (*)())ptr;
604                 break;
605         case BIO_CTRL_GET_CALLBACK:
606                 {
607                 int (**fptr)();
608
609                 fptr=(int (**)())ptr;
610                 *fptr=data->info_callback;
611                 }
612                 break;
613         default:
614                 ret=0;
615                 break;
616                 }
617         return(ret);
618         }
619
620 static int conn_puts(bp,str)
621 BIO *bp;
622 char *str;
623         {
624         int n,ret;
625
626         n=strlen(str);
627         ret=conn_write(bp,str,n);
628         return(ret);
629         }
630
631 BIO *BIO_new_connect(str)
632 char *str;
633         {
634         BIO *ret;
635
636         ret=BIO_new(BIO_s_connect());
637         if (ret == NULL) return(NULL);
638         if (BIO_set_conn_hostname(ret,str))
639                 return(ret);
640         else
641                 {
642                 BIO_free(ret);
643                 return(NULL);
644                 }
645         }
646
647 #endif
648