2308ad210f80b9a7057e61fec06fb13b3e2ab4eb
[openssl.git] / crypto / bio / bss_conn.c
1 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2  * All rights reserved.
3  *
4  * This package is an SSL implementation written
5  * by Eric Young (eay@cryptsoft.com).
6  * The implementation was written so as to conform with Netscapes SSL.
7  *
8  * This library is free for commercial and non-commercial use as long as
9  * the following conditions are aheared to.  The following conditions
10  * apply to all code found in this distribution, be it the RC4, RSA,
11  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
12  * included with this distribution is covered by the same copyright terms
13  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14  *
15  * Copyright remains Eric Young's, and as such any Copyright notices in
16  * the code are not to be removed.
17  * If this package is used in a product, Eric Young should be given attribution
18  * as the author of the parts of the library used.
19  * This can be in the form of a textual message at program startup or
20  * in documentation (online or textual) provided with the package.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  * 1. Redistributions of source code must retain the copyright
26  *    notice, this list of conditions and the following disclaimer.
27  * 2. Redistributions in binary form must reproduce the above copyright
28  *    notice, this list of conditions and the following disclaimer in the
29  *    documentation and/or other materials provided with the distribution.
30  * 3. All advertising materials mentioning features or use of this software
31  *    must display the following acknowledgement:
32  *    "This product includes cryptographic software written by
33  *     Eric Young (eay@cryptsoft.com)"
34  *    The word 'cryptographic' can be left out if the rouines from the library
35  *    being used are not cryptographic related :-).
36  * 4. If you include any Windows specific code (or a derivative thereof) from
37  *    the apps directory (application code) you must include an acknowledgement:
38  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39  *
40  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50  * SUCH DAMAGE.
51  *
52  * The licence and distribution terms for any publically available version or
53  * derivative of this code cannot be changed.  i.e. this code cannot simply be
54  * copied and put under another distribution licence
55  * [including the GNU Public Licence.]
56  */
57
58 #include <stdio.h>
59 #include <errno.h>
60 #define USE_SOCKETS
61 #include "internal/cryptlib.h"
62 #include <openssl/bio.h>
63
64 #ifndef OPENSSL_NO_SOCK
65
66 # if (defined(OPENSSL_SYS_VMS) && __VMS_VER < 70000000)
67 /* FIONBIO used as a switch to enable ioctl, and that isn't in VMS < 7.0 */
68 #  undef FIONBIO
69 # endif
70
71 typedef struct bio_connect_st {
72     int state;
73     char *param_hostname;
74     char *param_port;
75     int nbio;
76     unsigned char ip[4];
77     unsigned short port;
78     struct sockaddr_in them;
79     /*
80      * int socket; this will be kept in bio->num so that it is compatible
81      * with the bss_sock bio
82      */
83     /*
84      * called when the connection is initially made callback(BIO,state,ret);
85      * The callback should return 'ret'.  state is for compatibility with the
86      * ssl info_callback
87      */
88     int (*info_callback) (const BIO *bio, int state, int ret);
89 } BIO_CONNECT;
90
91 static int conn_write(BIO *h, const char *buf, int num);
92 static int conn_read(BIO *h, char *buf, int size);
93 static int conn_puts(BIO *h, const char *str);
94 static long conn_ctrl(BIO *h, int cmd, long arg1, void *arg2);
95 static int conn_new(BIO *h);
96 static int conn_free(BIO *data);
97 static long conn_callback_ctrl(BIO *h, int cmd, bio_info_cb *);
98
99 static int conn_state(BIO *b, BIO_CONNECT *c);
100 static void conn_close_socket(BIO *data);
101 BIO_CONNECT *BIO_CONNECT_new(void);
102 void BIO_CONNECT_free(BIO_CONNECT *a);
103
104 static BIO_METHOD methods_connectp = {
105     BIO_TYPE_CONNECT,
106     "socket connect",
107     conn_write,
108     conn_read,
109     conn_puts,
110     NULL,                       /* connect_gets, */
111     conn_ctrl,
112     conn_new,
113     conn_free,
114     conn_callback_ctrl,
115 };
116
117 static int conn_state(BIO *b, BIO_CONNECT *c)
118 {
119     int ret = -1, i;
120     unsigned long l;
121     char *p, *q;
122     int (*cb) (const BIO *, int, int) = NULL;
123
124     if (c->info_callback != NULL)
125         cb = c->info_callback;
126
127     for (;;) {
128         switch (c->state) {
129         case BIO_CONN_S_BEFORE:
130             p = c->param_hostname;
131             if (p == NULL) {
132                 BIOerr(BIO_F_CONN_STATE, BIO_R_NO_HOSTNAME_SPECIFIED);
133                 goto exit_loop;
134             }
135             for (; *p != '\0'; p++) {
136                 if ((*p == ':') || (*p == '/'))
137                     break;
138             }
139
140             i = *p;
141             if ((i == ':') || (i == '/')) {
142
143                 *(p++) = '\0';
144                 if (i == ':') {
145                     for (q = p; *q; q++)
146                         if (*q == '/') {
147                             *q = '\0';
148                             break;
149                         }
150                     OPENSSL_free(c->param_port);
151                     c->param_port = OPENSSL_strdup(p);
152                 }
153             }
154
155             if (c->param_port == NULL) {
156                 BIOerr(BIO_F_CONN_STATE, BIO_R_NO_PORT_SPECIFIED);
157                 ERR_add_error_data(2, "host=", c->param_hostname);
158                 goto exit_loop;
159             }
160             c->state = BIO_CONN_S_GET_IP;
161             break;
162
163         case BIO_CONN_S_GET_IP:
164             if (BIO_get_host_ip(c->param_hostname, &(c->ip[0])) <= 0)
165                 goto exit_loop;
166             c->state = BIO_CONN_S_GET_PORT;
167             break;
168
169         case BIO_CONN_S_GET_PORT:
170             if (c->param_port == NULL) {
171                 /* abort(); */
172                 goto exit_loop;
173             } else if (BIO_get_port(c->param_port, &c->port) <= 0)
174                 goto exit_loop;
175             c->state = BIO_CONN_S_CREATE_SOCKET;
176             break;
177
178         case BIO_CONN_S_CREATE_SOCKET:
179             /* now setup address */
180             memset(&c->them, 0, sizeof(c->them));
181             c->them.sin_family = AF_INET;
182             c->them.sin_port = htons((unsigned short)c->port);
183             l = (unsigned long)
184                 ((unsigned long)c->ip[0] << 24L) |
185                 ((unsigned long)c->ip[1] << 16L) |
186                 ((unsigned long)c->ip[2] << 8L) | ((unsigned long)c->ip[3]);
187             c->them.sin_addr.s_addr = htonl(l);
188             c->state = BIO_CONN_S_CREATE_SOCKET;
189
190             ret = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
191             if (ret == (int)INVALID_SOCKET) {
192                 SYSerr(SYS_F_SOCKET, get_last_socket_error());
193                 ERR_add_error_data(4, "host=", c->param_hostname,
194                                    ":", c->param_port);
195                 BIOerr(BIO_F_CONN_STATE, BIO_R_UNABLE_TO_CREATE_SOCKET);
196                 goto exit_loop;
197             }
198             b->num = ret;
199             c->state = BIO_CONN_S_NBIO;
200             break;
201
202         case BIO_CONN_S_NBIO:
203             if (c->nbio) {
204                 if (!BIO_socket_nbio(b->num, 1)) {
205                     BIOerr(BIO_F_CONN_STATE, BIO_R_ERROR_SETTING_NBIO);
206                     ERR_add_error_data(4, "host=",
207                                        c->param_hostname, ":", c->param_port);
208                     goto exit_loop;
209                 }
210             }
211             c->state = BIO_CONN_S_CONNECT;
212
213 # if defined(SO_KEEPALIVE)
214             i = 1;
215             i = setsockopt(b->num, SOL_SOCKET, SO_KEEPALIVE, (char *)&i,
216                            sizeof(i));
217             if (i < 0) {
218                 SYSerr(SYS_F_SOCKET, get_last_socket_error());
219                 ERR_add_error_data(4, "host=", c->param_hostname,
220                                    ":", c->param_port);
221                 BIOerr(BIO_F_CONN_STATE, BIO_R_KEEPALIVE);
222                 goto exit_loop;
223             }
224 # endif
225             break;
226
227         case BIO_CONN_S_CONNECT:
228             BIO_clear_retry_flags(b);
229             ret = connect(b->num,
230                           (struct sockaddr *)&c->them, sizeof(c->them));
231             b->retry_reason = 0;
232             if (ret < 0) {
233                 if (BIO_sock_should_retry(ret)) {
234                     BIO_set_retry_special(b);
235                     c->state = BIO_CONN_S_BLOCKED_CONNECT;
236                     b->retry_reason = BIO_RR_CONNECT;
237                 } else {
238                     SYSerr(SYS_F_CONNECT, get_last_socket_error());
239                     ERR_add_error_data(4, "host=",
240                                        c->param_hostname, ":", c->param_port);
241                     BIOerr(BIO_F_CONN_STATE, BIO_R_CONNECT_ERROR);
242                 }
243                 goto exit_loop;
244             } else
245                 c->state = BIO_CONN_S_OK;
246             break;
247
248         case BIO_CONN_S_BLOCKED_CONNECT:
249             i = BIO_sock_error(b->num);
250             if (i) {
251                 BIO_clear_retry_flags(b);
252                 SYSerr(SYS_F_CONNECT, i);
253                 ERR_add_error_data(4, "host=",
254                                    c->param_hostname, ":", c->param_port);
255                 BIOerr(BIO_F_CONN_STATE, BIO_R_NBIO_CONNECT_ERROR);
256                 ret = 0;
257                 goto exit_loop;
258             } else
259                 c->state = BIO_CONN_S_OK;
260             break;
261
262         case BIO_CONN_S_OK:
263             ret = 1;
264             goto exit_loop;
265         default:
266             /* abort(); */
267             goto exit_loop;
268         }
269
270         if (cb != NULL) {
271             if ((ret = cb((BIO *)b, c->state, ret)) == 0)
272                 goto end;
273         }
274     }
275
276     /* Loop does not exit */
277  exit_loop:
278     if (cb != NULL)
279         ret = cb((BIO *)b, c->state, ret);
280  end:
281     return (ret);
282 }
283
284 BIO_CONNECT *BIO_CONNECT_new(void)
285 {
286     BIO_CONNECT *ret;
287
288     if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL)
289         return (NULL);
290     ret->state = BIO_CONN_S_BEFORE;
291     ret->param_hostname = NULL;
292     ret->param_port = NULL;
293     ret->info_callback = NULL;
294     return (ret);
295 }
296
297 void BIO_CONNECT_free(BIO_CONNECT *a)
298 {
299     if (a == NULL)
300         return;
301
302     OPENSSL_free(a->param_hostname);
303     OPENSSL_free(a->param_port);
304     OPENSSL_free(a);
305 }
306
307 BIO_METHOD *BIO_s_connect(void)
308 {
309     return (&methods_connectp);
310 }
311
312 static int conn_new(BIO *bi)
313 {
314     bi->init = 0;
315     bi->num = (int)INVALID_SOCKET;
316     bi->flags = 0;
317     if ((bi->ptr = (char *)BIO_CONNECT_new()) == NULL)
318         return (0);
319     else
320         return (1);
321 }
322
323 static void conn_close_socket(BIO *bio)
324 {
325     BIO_CONNECT *c;
326
327     c = (BIO_CONNECT *)bio->ptr;
328     if (bio->num != (int)INVALID_SOCKET) {
329         /* Only do a shutdown if things were established */
330         if (c->state == BIO_CONN_S_OK)
331             shutdown(bio->num, 2);
332         closesocket(bio->num);
333         bio->num = (int)INVALID_SOCKET;
334     }
335 }
336
337 static int conn_free(BIO *a)
338 {
339     BIO_CONNECT *data;
340
341     if (a == NULL)
342         return (0);
343     data = (BIO_CONNECT *)a->ptr;
344
345     if (a->shutdown) {
346         conn_close_socket(a);
347         BIO_CONNECT_free(data);
348         a->ptr = NULL;
349         a->flags = 0;
350         a->init = 0;
351     }
352     return (1);
353 }
354
355 static int conn_read(BIO *b, char *out, int outl)
356 {
357     int ret = 0;
358     BIO_CONNECT *data;
359
360     data = (BIO_CONNECT *)b->ptr;
361     if (data->state != BIO_CONN_S_OK) {
362         ret = conn_state(b, data);
363         if (ret <= 0)
364             return (ret);
365     }
366
367     if (out != NULL) {
368         clear_socket_error();
369         ret = readsocket(b->num, out, outl);
370         BIO_clear_retry_flags(b);
371         if (ret <= 0) {
372             if (BIO_sock_should_retry(ret))
373                 BIO_set_retry_read(b);
374         }
375     }
376     return (ret);
377 }
378
379 static int conn_write(BIO *b, const char *in, int inl)
380 {
381     int ret;
382     BIO_CONNECT *data;
383
384     data = (BIO_CONNECT *)b->ptr;
385     if (data->state != BIO_CONN_S_OK) {
386         ret = conn_state(b, data);
387         if (ret <= 0)
388             return (ret);
389     }
390
391     clear_socket_error();
392     ret = writesocket(b->num, in, inl);
393     BIO_clear_retry_flags(b);
394     if (ret <= 0) {
395         if (BIO_sock_should_retry(ret))
396             BIO_set_retry_write(b);
397     }
398     return (ret);
399 }
400
401 static long conn_ctrl(BIO *b, int cmd, long num, void *ptr)
402 {
403     BIO *dbio;
404     int *ip;
405     const char **pptr = NULL;
406     long ret = 1;
407     BIO_CONNECT *data;
408
409     data = (BIO_CONNECT *)b->ptr;
410
411     switch (cmd) {
412     case BIO_CTRL_RESET:
413         ret = 0;
414         data->state = BIO_CONN_S_BEFORE;
415         conn_close_socket(b);
416         b->flags = 0;
417         break;
418     case BIO_C_DO_STATE_MACHINE:
419         /* use this one to start the connection */
420         if (data->state != BIO_CONN_S_OK)
421             ret = (long)conn_state(b, data);
422         else
423             ret = 1;
424         break;
425     case BIO_C_GET_CONNECT:
426         if (ptr != NULL) {
427             pptr = (const char **)ptr;
428         }
429
430         if (b->init) {
431             if (pptr != NULL) {
432                 ret = 1;
433                 if (num == 0) {
434                     *pptr = data->param_hostname;
435                 } else if (num == 1) {
436                     *pptr = data->param_port;
437                 } else if (num == 2) {
438                     *pptr = (char *)&(data->ip[0]);
439                 } else {
440                     ret = 0;
441                 }
442             }
443             if (num == 3) {
444                 ret = data->port;
445             }
446         } else {
447             if (pptr != NULL)
448                 *pptr = "not initialized";
449             ret = 0;
450         }
451         break;
452     case BIO_C_SET_CONNECT:
453         if (ptr != NULL) {
454             b->init = 1;
455             if (num == 0) {
456                 OPENSSL_free(data->param_hostname);
457                 data->param_hostname = OPENSSL_strdup(ptr);
458             } else if (num == 1) {
459                 OPENSSL_free(data->param_port);
460                 data->param_port = OPENSSL_strdup(ptr);
461             } else if (num == 2) {
462                 char buf[16];
463                 unsigned char *p = ptr;
464
465                 BIO_snprintf(buf, sizeof buf, "%d.%d.%d.%d",
466                              p[0], p[1], p[2], p[3]);
467                 OPENSSL_free(data->param_hostname);
468                 data->param_hostname = OPENSSL_strdup(buf);
469                 memcpy(&(data->ip[0]), ptr, 4);
470             } else if (num == 3) {
471                 char buf[DECIMAL_SIZE(int) + 1];
472
473                 BIO_snprintf(buf, sizeof buf, "%d", *(int *)ptr);
474                 OPENSSL_free(data->param_port);
475                 data->param_port = OPENSSL_strdup(buf);
476                 data->port = *(int *)ptr;
477             }
478         }
479         break;
480     case BIO_C_SET_NBIO:
481         data->nbio = (int)num;
482         break;
483     case BIO_C_GET_FD:
484         if (b->init) {
485             ip = (int *)ptr;
486             if (ip != NULL)
487                 *ip = b->num;
488             ret = b->num;
489         } else
490             ret = -1;
491         break;
492     case BIO_CTRL_GET_CLOSE:
493         ret = b->shutdown;
494         break;
495     case BIO_CTRL_SET_CLOSE:
496         b->shutdown = (int)num;
497         break;
498     case BIO_CTRL_PENDING:
499     case BIO_CTRL_WPENDING:
500         ret = 0;
501         break;
502     case BIO_CTRL_FLUSH:
503         break;
504     case BIO_CTRL_DUP:
505         {
506             dbio = (BIO *)ptr;
507             if (data->param_port)
508                 BIO_set_conn_port(dbio, data->param_port);
509             if (data->param_hostname)
510                 BIO_set_conn_hostname(dbio, data->param_hostname);
511             BIO_set_nbio(dbio, data->nbio);
512             /*
513              * FIXME: the cast of the function seems unlikely to be a good
514              * idea
515              */
516             (void)BIO_set_info_callback(dbio,
517                                         (bio_info_cb *)data->info_callback);
518         }
519         break;
520     case BIO_CTRL_SET_CALLBACK:
521         {
522 # if 0                          /* FIXME: Should this be used? -- Richard
523                                  * Levitte */
524             BIOerr(BIO_F_CONN_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
525             ret = -1;
526 # else
527             ret = 0;
528 # endif
529         }
530         break;
531     case BIO_CTRL_GET_CALLBACK:
532         {
533             int (**fptr) (const BIO *bio, int state, int xret);
534
535             fptr = (int (**)(const BIO *bio, int state, int xret))ptr;
536             *fptr = data->info_callback;
537         }
538         break;
539     default:
540         ret = 0;
541         break;
542     }
543     return (ret);
544 }
545
546 static long conn_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
547 {
548     long ret = 1;
549     BIO_CONNECT *data;
550
551     data = (BIO_CONNECT *)b->ptr;
552
553     switch (cmd) {
554     case BIO_CTRL_SET_CALLBACK:
555         {
556             data->info_callback =
557                 (int (*)(const struct bio_st *, int, int))fp;
558         }
559         break;
560     default:
561         ret = 0;
562         break;
563     }
564     return (ret);
565 }
566
567 static int conn_puts(BIO *bp, const char *str)
568 {
569     int n, ret;
570
571     n = strlen(str);
572     ret = conn_write(bp, str, n);
573     return (ret);
574 }
575
576 BIO *BIO_new_connect(const char *str)
577 {
578     BIO *ret;
579
580     ret = BIO_new(BIO_s_connect());
581     if (ret == NULL)
582         return (NULL);
583     if (BIO_set_conn_hostname(ret, str))
584         return (ret);
585     BIO_free(ret);
586     return (NULL);
587 }
588
589 #endif