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