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