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