Temporary pragma to have GCC quiet down about deprecated functions
[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 /*
67  * We are currently using deprecated functions here, and GCC warns
68  * us about them, but since we know, we don't want to hear it.
69  */
70 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
71
72 # if (defined(OPENSSL_SYS_VMS) && __VMS_VER < 70000000)
73 /* FIONBIO used as a switch to enable ioctl, and that isn't in VMS < 7.0 */
74 #  undef FIONBIO
75 # endif
76
77 typedef struct bio_connect_st {
78     int state;
79     char *param_hostname;
80     char *param_port;
81     int nbio;
82     unsigned char ip[4];
83     unsigned short port;
84     struct sockaddr_in them;
85     /*
86      * int socket; this will be kept in bio->num so that it is compatible
87      * with the bss_sock bio
88      */
89     /*
90      * called when the connection is initially made callback(BIO,state,ret);
91      * The callback should return 'ret'.  state is for compatibility with the
92      * ssl info_callback
93      */
94     int (*info_callback) (const BIO *bio, int state, int ret);
95 } BIO_CONNECT;
96
97 static int conn_write(BIO *h, const char *buf, int num);
98 static int conn_read(BIO *h, char *buf, int size);
99 static int conn_puts(BIO *h, const char *str);
100 static long conn_ctrl(BIO *h, int cmd, long arg1, void *arg2);
101 static int conn_new(BIO *h);
102 static int conn_free(BIO *data);
103 static long conn_callback_ctrl(BIO *h, int cmd, bio_info_cb *);
104
105 static int conn_state(BIO *b, BIO_CONNECT *c);
106 static void conn_close_socket(BIO *data);
107 BIO_CONNECT *BIO_CONNECT_new(void);
108 void BIO_CONNECT_free(BIO_CONNECT *a);
109
110 static BIO_METHOD methods_connectp = {
111     BIO_TYPE_CONNECT,
112     "socket connect",
113     conn_write,
114     conn_read,
115     conn_puts,
116     NULL,                       /* connect_gets, */
117     conn_ctrl,
118     conn_new,
119     conn_free,
120     conn_callback_ctrl,
121 };
122
123 static int conn_state(BIO *b, BIO_CONNECT *c)
124 {
125     int ret = -1, i;
126     unsigned long l;
127     char *p, *q;
128     int (*cb) (const BIO *, int, int) = NULL;
129
130     if (c->info_callback != NULL)
131         cb = c->info_callback;
132
133     for (;;) {
134         switch (c->state) {
135         case BIO_CONN_S_BEFORE:
136             p = c->param_hostname;
137             if (p == NULL) {
138                 BIOerr(BIO_F_CONN_STATE, BIO_R_NO_HOSTNAME_SPECIFIED);
139                 goto exit_loop;
140             }
141             for (; *p != '\0'; p++) {
142                 if ((*p == ':') || (*p == '/'))
143                     break;
144             }
145
146             i = *p;
147             if ((i == ':') || (i == '/')) {
148
149                 *(p++) = '\0';
150                 if (i == ':') {
151                     for (q = p; *q; q++)
152                         if (*q == '/') {
153                             *q = '\0';
154                             break;
155                         }
156                     OPENSSL_free(c->param_port);
157                     c->param_port = OPENSSL_strdup(p);
158                 }
159             }
160
161             if (c->param_port == NULL) {
162                 BIOerr(BIO_F_CONN_STATE, BIO_R_NO_PORT_SPECIFIED);
163                 ERR_add_error_data(2, "host=", c->param_hostname);
164                 goto exit_loop;
165             }
166             c->state = BIO_CONN_S_GET_IP;
167             break;
168
169         case BIO_CONN_S_GET_IP:
170             if (BIO_get_host_ip(c->param_hostname, &(c->ip[0])) <= 0)
171                 goto exit_loop;
172             c->state = BIO_CONN_S_GET_PORT;
173             break;
174
175         case BIO_CONN_S_GET_PORT:
176             if (c->param_port == NULL) {
177                 /* abort(); */
178                 goto exit_loop;
179             } else if (BIO_get_port(c->param_port, &c->port) <= 0)
180                 goto exit_loop;
181             c->state = BIO_CONN_S_CREATE_SOCKET;
182             break;
183
184         case BIO_CONN_S_CREATE_SOCKET:
185             /* now setup address */
186             memset(&c->them, 0, sizeof(c->them));
187             c->them.sin_family = AF_INET;
188             c->them.sin_port = htons((unsigned short)c->port);
189             l = (unsigned long)
190                 ((unsigned long)c->ip[0] << 24L) |
191                 ((unsigned long)c->ip[1] << 16L) |
192                 ((unsigned long)c->ip[2] << 8L) | ((unsigned long)c->ip[3]);
193             c->them.sin_addr.s_addr = htonl(l);
194             c->state = BIO_CONN_S_CREATE_SOCKET;
195
196             ret = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
197             if (ret == (int)INVALID_SOCKET) {
198                 SYSerr(SYS_F_SOCKET, get_last_socket_error());
199                 ERR_add_error_data(4, "host=", c->param_hostname,
200                                    ":", c->param_port);
201                 BIOerr(BIO_F_CONN_STATE, BIO_R_UNABLE_TO_CREATE_SOCKET);
202                 goto exit_loop;
203             }
204             b->num = ret;
205             c->state = BIO_CONN_S_NBIO;
206             break;
207
208         case BIO_CONN_S_NBIO:
209             if (c->nbio) {
210                 if (!BIO_socket_nbio(b->num, 1)) {
211                     BIOerr(BIO_F_CONN_STATE, BIO_R_ERROR_SETTING_NBIO);
212                     ERR_add_error_data(4, "host=",
213                                        c->param_hostname, ":", c->param_port);
214                     goto exit_loop;
215                 }
216             }
217             c->state = BIO_CONN_S_CONNECT;
218
219 # if defined(SO_KEEPALIVE)
220             i = 1;
221             i = setsockopt(b->num, SOL_SOCKET, SO_KEEPALIVE, (char *)&i,
222                            sizeof(i));
223             if (i < 0) {
224                 SYSerr(SYS_F_SOCKET, get_last_socket_error());
225                 ERR_add_error_data(4, "host=", c->param_hostname,
226                                    ":", c->param_port);
227                 BIOerr(BIO_F_CONN_STATE, BIO_R_KEEPALIVE);
228                 goto exit_loop;
229             }
230 # endif
231             break;
232
233         case BIO_CONN_S_CONNECT:
234             BIO_clear_retry_flags(b);
235             ret = connect(b->num,
236                           (struct sockaddr *)&c->them, sizeof(c->them));
237             b->retry_reason = 0;
238             if (ret < 0) {
239                 if (BIO_sock_should_retry(ret)) {
240                     BIO_set_retry_special(b);
241                     c->state = BIO_CONN_S_BLOCKED_CONNECT;
242                     b->retry_reason = BIO_RR_CONNECT;
243                 } else {
244                     SYSerr(SYS_F_CONNECT, get_last_socket_error());
245                     ERR_add_error_data(4, "host=",
246                                        c->param_hostname, ":", c->param_port);
247                     BIOerr(BIO_F_CONN_STATE, BIO_R_CONNECT_ERROR);
248                 }
249                 goto exit_loop;
250             } else
251                 c->state = BIO_CONN_S_OK;
252             break;
253
254         case BIO_CONN_S_BLOCKED_CONNECT:
255             i = BIO_sock_error(b->num);
256             if (i) {
257                 BIO_clear_retry_flags(b);
258                 SYSerr(SYS_F_CONNECT, i);
259                 ERR_add_error_data(4, "host=",
260                                    c->param_hostname, ":", c->param_port);
261                 BIOerr(BIO_F_CONN_STATE, BIO_R_NBIO_CONNECT_ERROR);
262                 ret = 0;
263                 goto exit_loop;
264             } else
265                 c->state = BIO_CONN_S_OK;
266             break;
267
268         case BIO_CONN_S_OK:
269             ret = 1;
270             goto exit_loop;
271         default:
272             /* abort(); */
273             goto exit_loop;
274         }
275
276         if (cb != NULL) {
277             if ((ret = cb((BIO *)b, c->state, ret)) == 0)
278                 goto end;
279         }
280     }
281
282     /* Loop does not exit */
283  exit_loop:
284     if (cb != NULL)
285         ret = cb((BIO *)b, c->state, ret);
286  end:
287     return (ret);
288 }
289
290 BIO_CONNECT *BIO_CONNECT_new(void)
291 {
292     BIO_CONNECT *ret;
293
294     if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL)
295         return (NULL);
296     ret->state = BIO_CONN_S_BEFORE;
297     ret->param_hostname = NULL;
298     ret->param_port = NULL;
299     ret->info_callback = NULL;
300     return (ret);
301 }
302
303 void BIO_CONNECT_free(BIO_CONNECT *a)
304 {
305     if (a == NULL)
306         return;
307
308     OPENSSL_free(a->param_hostname);
309     OPENSSL_free(a->param_port);
310     OPENSSL_free(a);
311 }
312
313 BIO_METHOD *BIO_s_connect(void)
314 {
315     return (&methods_connectp);
316 }
317
318 static int conn_new(BIO *bi)
319 {
320     bi->init = 0;
321     bi->num = (int)INVALID_SOCKET;
322     bi->flags = 0;
323     if ((bi->ptr = (char *)BIO_CONNECT_new()) == NULL)
324         return (0);
325     else
326         return (1);
327 }
328
329 static void conn_close_socket(BIO *bio)
330 {
331     BIO_CONNECT *c;
332
333     c = (BIO_CONNECT *)bio->ptr;
334     if (bio->num != (int)INVALID_SOCKET) {
335         /* Only do a shutdown if things were established */
336         if (c->state == BIO_CONN_S_OK)
337             shutdown(bio->num, 2);
338         closesocket(bio->num);
339         bio->num = (int)INVALID_SOCKET;
340     }
341 }
342
343 static int conn_free(BIO *a)
344 {
345     BIO_CONNECT *data;
346
347     if (a == NULL)
348         return (0);
349     data = (BIO_CONNECT *)a->ptr;
350
351     if (a->shutdown) {
352         conn_close_socket(a);
353         BIO_CONNECT_free(data);
354         a->ptr = NULL;
355         a->flags = 0;
356         a->init = 0;
357     }
358     return (1);
359 }
360
361 static int conn_read(BIO *b, char *out, int outl)
362 {
363     int ret = 0;
364     BIO_CONNECT *data;
365
366     data = (BIO_CONNECT *)b->ptr;
367     if (data->state != BIO_CONN_S_OK) {
368         ret = conn_state(b, data);
369         if (ret <= 0)
370             return (ret);
371     }
372
373     if (out != NULL) {
374         clear_socket_error();
375         ret = readsocket(b->num, out, outl);
376         BIO_clear_retry_flags(b);
377         if (ret <= 0) {
378             if (BIO_sock_should_retry(ret))
379                 BIO_set_retry_read(b);
380         }
381     }
382     return (ret);
383 }
384
385 static int conn_write(BIO *b, const char *in, int inl)
386 {
387     int ret;
388     BIO_CONNECT *data;
389
390     data = (BIO_CONNECT *)b->ptr;
391     if (data->state != BIO_CONN_S_OK) {
392         ret = conn_state(b, data);
393         if (ret <= 0)
394             return (ret);
395     }
396
397     clear_socket_error();
398     ret = writesocket(b->num, in, inl);
399     BIO_clear_retry_flags(b);
400     if (ret <= 0) {
401         if (BIO_sock_should_retry(ret))
402             BIO_set_retry_write(b);
403     }
404     return (ret);
405 }
406
407 static long conn_ctrl(BIO *b, int cmd, long num, void *ptr)
408 {
409     BIO *dbio;
410     int *ip;
411     const char **pptr = NULL;
412     long ret = 1;
413     BIO_CONNECT *data;
414
415     data = (BIO_CONNECT *)b->ptr;
416
417     switch (cmd) {
418     case BIO_CTRL_RESET:
419         ret = 0;
420         data->state = BIO_CONN_S_BEFORE;
421         conn_close_socket(b);
422         b->flags = 0;
423         break;
424     case BIO_C_DO_STATE_MACHINE:
425         /* use this one to start the connection */
426         if (data->state != BIO_CONN_S_OK)
427             ret = (long)conn_state(b, data);
428         else
429             ret = 1;
430         break;
431     case BIO_C_GET_CONNECT:
432         if (ptr != NULL) {
433             pptr = (const char **)ptr;
434         }
435
436         if (b->init) {
437             if (pptr != NULL) {
438                 ret = 1;
439                 if (num == 0) {
440                     *pptr = data->param_hostname;
441                 } else if (num == 1) {
442                     *pptr = data->param_port;
443                 } else if (num == 2) {
444                     *pptr = (char *)&(data->ip[0]);
445                 } else {
446                     ret = 0;
447                 }
448             }
449             if (num == 3) {
450                 ret = data->port;
451             }
452         } else {
453             if (pptr != NULL)
454                 *pptr = "not initialized";
455             ret = 0;
456         }
457         break;
458     case BIO_C_SET_CONNECT:
459         if (ptr != NULL) {
460             b->init = 1;
461             if (num == 0) {
462                 OPENSSL_free(data->param_hostname);
463                 data->param_hostname = OPENSSL_strdup(ptr);
464             } else if (num == 1) {
465                 OPENSSL_free(data->param_port);
466                 data->param_port = OPENSSL_strdup(ptr);
467             } else if (num == 2) {
468                 char buf[16];
469                 unsigned char *p = ptr;
470
471                 BIO_snprintf(buf, sizeof buf, "%d.%d.%d.%d",
472                              p[0], p[1], p[2], p[3]);
473                 OPENSSL_free(data->param_hostname);
474                 data->param_hostname = OPENSSL_strdup(buf);
475                 memcpy(&(data->ip[0]), ptr, 4);
476             } else if (num == 3) {
477                 char buf[DECIMAL_SIZE(int) + 1];
478
479                 BIO_snprintf(buf, sizeof buf, "%d", *(int *)ptr);
480                 OPENSSL_free(data->param_port);
481                 data->param_port = OPENSSL_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