49b0f69c1a1bdffc55d7f0a4d4d1d7bba73f43d8
[oweals/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 "internal/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(&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 == (int)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)) == 0)
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_zalloc(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     return (ret);
296 }
297
298 void BIO_CONNECT_free(BIO_CONNECT *a)
299 {
300     if (a == NULL)
301         return;
302
303     OPENSSL_free(a->param_hostname);
304     OPENSSL_free(a->param_port);
305     OPENSSL_free(a);
306 }
307
308 BIO_METHOD *BIO_s_connect(void)
309 {
310     return (&methods_connectp);
311 }
312
313 static int conn_new(BIO *bi)
314 {
315     bi->init = 0;
316     bi->num = (int)INVALID_SOCKET;
317     bi->flags = 0;
318     if ((bi->ptr = (char *)BIO_CONNECT_new()) == NULL)
319         return (0);
320     else
321         return (1);
322 }
323
324 static void conn_close_socket(BIO *bio)
325 {
326     BIO_CONNECT *c;
327
328     c = (BIO_CONNECT *)bio->ptr;
329     if (bio->num != (int)INVALID_SOCKET) {
330         /* Only do a shutdown if things were established */
331         if (c->state == BIO_CONN_S_OK)
332             shutdown(bio->num, 2);
333         closesocket(bio->num);
334         bio->num = (int)INVALID_SOCKET;
335     }
336 }
337
338 static int conn_free(BIO *a)
339 {
340     BIO_CONNECT *data;
341
342     if (a == NULL)
343         return (0);
344     data = (BIO_CONNECT *)a->ptr;
345
346     if (a->shutdown) {
347         conn_close_socket(a);
348         BIO_CONNECT_free(data);
349         a->ptr = NULL;
350         a->flags = 0;
351         a->init = 0;
352     }
353     return (1);
354 }
355
356 static int conn_read(BIO *b, char *out, int outl)
357 {
358     int ret = 0;
359     BIO_CONNECT *data;
360
361     data = (BIO_CONNECT *)b->ptr;
362     if (data->state != BIO_CONN_S_OK) {
363         ret = conn_state(b, data);
364         if (ret <= 0)
365             return (ret);
366     }
367
368     if (out != NULL) {
369         clear_socket_error();
370         ret = readsocket(b->num, out, outl);
371         BIO_clear_retry_flags(b);
372         if (ret <= 0) {
373             if (BIO_sock_should_retry(ret))
374                 BIO_set_retry_read(b);
375         }
376     }
377     return (ret);
378 }
379
380 static int conn_write(BIO *b, const char *in, int inl)
381 {
382     int ret;
383     BIO_CONNECT *data;
384
385     data = (BIO_CONNECT *)b->ptr;
386     if (data->state != BIO_CONN_S_OK) {
387         ret = conn_state(b, data);
388         if (ret <= 0)
389             return (ret);
390     }
391
392     clear_socket_error();
393     ret = writesocket(b->num, in, inl);
394     BIO_clear_retry_flags(b);
395     if (ret <= 0) {
396         if (BIO_sock_should_retry(ret))
397             BIO_set_retry_write(b);
398     }
399     return (ret);
400 }
401
402 static long conn_ctrl(BIO *b, int cmd, long num, void *ptr)
403 {
404     BIO *dbio;
405     int *ip;
406     const char **pptr;
407     long ret = 1;
408     BIO_CONNECT *data;
409
410     data = (BIO_CONNECT *)b->ptr;
411
412     switch (cmd) {
413     case BIO_CTRL_RESET:
414         ret = 0;
415         data->state = BIO_CONN_S_BEFORE;
416         conn_close_socket(b);
417         b->flags = 0;
418         break;
419     case BIO_C_DO_STATE_MACHINE:
420         /* use this one to start the connection */
421         if (data->state != BIO_CONN_S_OK)
422             ret = (long)conn_state(b, data);
423         else
424             ret = 1;
425         break;
426     case BIO_C_GET_CONNECT:
427         if (ptr != NULL) {
428             pptr = (const char **)ptr;
429             if (num == 0) {
430                 *pptr = data->param_hostname;
431
432             } else if (num == 1) {
433                 *pptr = data->param_port;
434             } else if (num == 2) {
435                 *pptr = (char *)&(data->ip[0]);
436             } else if (num == 3) {
437                 *((int *)ptr) = data->port;
438             }
439             if ((!b->init) || (ptr == NULL))
440                 *pptr = "not initialized";
441             ret = 1;
442         }
443         break;
444     case BIO_C_SET_CONNECT:
445         if (ptr != NULL) {
446             b->init = 1;
447             if (num == 0) {
448                 OPENSSL_free(data->param_hostname);
449                 data->param_hostname = BUF_strdup(ptr);
450             } else if (num == 1) {
451                 OPENSSL_free(data->param_port);
452                 data->param_port = BUF_strdup(ptr);
453             } else if (num == 2) {
454                 char buf[16];
455                 unsigned char *p = ptr;
456
457                 BIO_snprintf(buf, sizeof buf, "%d.%d.%d.%d",
458                              p[0], p[1], p[2], p[3]);
459                 OPENSSL_free(data->param_hostname);
460                 data->param_hostname = BUF_strdup(buf);
461                 memcpy(&(data->ip[0]), ptr, 4);
462             } else if (num == 3) {
463                 char buf[DECIMAL_SIZE(int) + 1];
464
465                 BIO_snprintf(buf, sizeof buf, "%d", *(int *)ptr);
466                 OPENSSL_free(data->param_port);
467                 data->param_port = BUF_strdup(buf);
468                 data->port = *(int *)ptr;
469             }
470         }
471         break;
472     case BIO_C_SET_NBIO:
473         data->nbio = (int)num;
474         break;
475     case BIO_C_GET_FD:
476         if (b->init) {
477             ip = (int *)ptr;
478             if (ip != NULL)
479                 *ip = b->num;
480             ret = b->num;
481         } else
482             ret = -1;
483         break;
484     case BIO_CTRL_GET_CLOSE:
485         ret = b->shutdown;
486         break;
487     case BIO_CTRL_SET_CLOSE:
488         b->shutdown = (int)num;
489         break;
490     case BIO_CTRL_PENDING:
491     case BIO_CTRL_WPENDING:
492         ret = 0;
493         break;
494     case BIO_CTRL_FLUSH:
495         break;
496     case BIO_CTRL_DUP:
497         {
498             dbio = (BIO *)ptr;
499             if (data->param_port)
500                 BIO_set_conn_port(dbio, data->param_port);
501             if (data->param_hostname)
502                 BIO_set_conn_hostname(dbio, data->param_hostname);
503             BIO_set_nbio(dbio, data->nbio);
504             /*
505              * FIXME: the cast of the function seems unlikely to be a good
506              * idea
507              */
508             (void)BIO_set_info_callback(dbio,
509                                         (bio_info_cb *)data->info_callback);
510         }
511         break;
512     case BIO_CTRL_SET_CALLBACK:
513         {
514 # if 0                          /* FIXME: Should this be used? -- Richard
515                                  * Levitte */
516             BIOerr(BIO_F_CONN_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
517             ret = -1;
518 # else
519             ret = 0;
520 # endif
521         }
522         break;
523     case BIO_CTRL_GET_CALLBACK:
524         {
525             int (**fptr) (const BIO *bio, int state, int xret);
526
527             fptr = (int (**)(const BIO *bio, int state, int xret))ptr;
528             *fptr = data->info_callback;
529         }
530         break;
531     default:
532         ret = 0;
533         break;
534     }
535     return (ret);
536 }
537
538 static long conn_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
539 {
540     long ret = 1;
541     BIO_CONNECT *data;
542
543     data = (BIO_CONNECT *)b->ptr;
544
545     switch (cmd) {
546     case BIO_CTRL_SET_CALLBACK:
547         {
548             data->info_callback =
549                 (int (*)(const struct bio_st *, int, int))fp;
550         }
551         break;
552     default:
553         ret = 0;
554         break;
555     }
556     return (ret);
557 }
558
559 static int conn_puts(BIO *bp, const char *str)
560 {
561     int n, ret;
562
563     n = strlen(str);
564     ret = conn_write(bp, str, n);
565     return (ret);
566 }
567
568 BIO *BIO_new_connect(const char *str)
569 {
570     BIO *ret;
571
572     ret = BIO_new(BIO_s_connect());
573     if (ret == NULL)
574         return (NULL);
575     if (BIO_set_conn_hostname(ret, str))
576         return (ret);
577     BIO_free(ret);
578     return (NULL);
579 }
580
581 #endif