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