16a660800d6b888b2d01facc5b1f5b358da1369c
[openssl.git] / crypto / bio / bss_acpt.c
1 /* crypto/bio/bss_acpt.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_accept_st {
73     int state;
74     char *param_addr;
75     int accept_sock;
76     int accept_nbio;
77     char *addr;
78     int nbio;
79     /*
80      * If 0, it means normal, if 1, do a connect on bind failure, and if
81      * there is no-one listening, bind with SO_REUSEADDR. If 2, always use
82      * SO_REUSEADDR.
83      */
84     int bind_mode;
85     BIO *bio_chain;
86 } BIO_ACCEPT;
87
88 static int acpt_write(BIO *h, const char *buf, int num);
89 static int acpt_read(BIO *h, char *buf, int size);
90 static int acpt_puts(BIO *h, const char *str);
91 static long acpt_ctrl(BIO *h, int cmd, long arg1, void *arg2);
92 static int acpt_new(BIO *h);
93 static int acpt_free(BIO *data);
94 static int acpt_state(BIO *b, BIO_ACCEPT *c);
95 static void acpt_close_socket(BIO *data);
96 static BIO_ACCEPT *BIO_ACCEPT_new(void);
97 static void BIO_ACCEPT_free(BIO_ACCEPT *a);
98
99 # define ACPT_S_BEFORE                   1
100 # define ACPT_S_GET_ACCEPT_SOCKET        2
101 # define ACPT_S_OK                       3
102
103 static BIO_METHOD methods_acceptp = {
104     BIO_TYPE_ACCEPT,
105     "socket accept",
106     acpt_write,
107     acpt_read,
108     acpt_puts,
109     NULL,                       /* connect_gets, */
110     acpt_ctrl,
111     acpt_new,
112     acpt_free,
113     NULL,
114 };
115
116 BIO_METHOD *BIO_s_accept(void)
117 {
118     return (&methods_acceptp);
119 }
120
121 static int acpt_new(BIO *bi)
122 {
123     BIO_ACCEPT *ba;
124
125     bi->init = 0;
126     bi->num = INVALID_SOCKET;
127     bi->flags = 0;
128     if ((ba = BIO_ACCEPT_new()) == NULL)
129         return (0);
130     bi->ptr = (char *)ba;
131     ba->state = ACPT_S_BEFORE;
132     bi->shutdown = 1;
133     return (1);
134 }
135
136 static BIO_ACCEPT *BIO_ACCEPT_new(void)
137 {
138     BIO_ACCEPT *ret;
139
140     if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL)
141         return (NULL);
142
143     memset(ret, 0, sizeof(*ret));
144     ret->accept_sock = INVALID_SOCKET;
145     ret->bind_mode = BIO_BIND_NORMAL;
146     return (ret);
147 }
148
149 static void BIO_ACCEPT_free(BIO_ACCEPT *a)
150 {
151     if (a == NULL)
152         return;
153
154     OPENSSL_free(a->param_addr);
155     OPENSSL_free(a->addr);
156     BIO_free(a->bio_chain);
157     OPENSSL_free(a);
158 }
159
160 static void acpt_close_socket(BIO *bio)
161 {
162     BIO_ACCEPT *c;
163
164     c = (BIO_ACCEPT *)bio->ptr;
165     if (c->accept_sock != INVALID_SOCKET) {
166         shutdown(c->accept_sock, 2);
167         closesocket(c->accept_sock);
168         c->accept_sock = INVALID_SOCKET;
169         bio->num = INVALID_SOCKET;
170     }
171 }
172
173 static int acpt_free(BIO *a)
174 {
175     BIO_ACCEPT *data;
176
177     if (a == NULL)
178         return (0);
179     data = (BIO_ACCEPT *)a->ptr;
180
181     if (a->shutdown) {
182         acpt_close_socket(a);
183         BIO_ACCEPT_free(data);
184         a->ptr = NULL;
185         a->flags = 0;
186         a->init = 0;
187     }
188     return (1);
189 }
190
191 static int acpt_state(BIO *b, BIO_ACCEPT *c)
192 {
193     BIO *bio = NULL, *dbio;
194     int s = -1;
195     int i;
196
197  again:
198     switch (c->state) {
199     case ACPT_S_BEFORE:
200         if (c->param_addr == NULL) {
201             BIOerr(BIO_F_ACPT_STATE, BIO_R_NO_ACCEPT_PORT_SPECIFIED);
202             return (-1);
203         }
204         s = BIO_get_accept_socket(c->param_addr, c->bind_mode);
205         if (s == INVALID_SOCKET)
206             return (-1);
207
208         if (c->accept_nbio) {
209             if (!BIO_socket_nbio(s, 1)) {
210                 closesocket(s);
211                 BIOerr(BIO_F_ACPT_STATE,
212                        BIO_R_ERROR_SETTING_NBIO_ON_ACCEPT_SOCKET);
213                 return (-1);
214             }
215         }
216         c->accept_sock = s;
217         b->num = s;
218         c->state = ACPT_S_GET_ACCEPT_SOCKET;
219         return (1);
220         /* break; */
221     case ACPT_S_GET_ACCEPT_SOCKET:
222         if (b->next_bio != NULL) {
223             c->state = ACPT_S_OK;
224             goto again;
225         }
226         BIO_clear_retry_flags(b);
227         b->retry_reason = 0;
228         i = BIO_accept(c->accept_sock, &(c->addr));
229
230         /* -2 return means we should retry */
231         if (i == -2) {
232             BIO_set_retry_special(b);
233             b->retry_reason = BIO_RR_ACCEPT;
234             return -1;
235         }
236
237         if (i < 0)
238             return (i);
239
240         bio = BIO_new_socket(i, BIO_CLOSE);
241         if (bio == NULL)
242             goto err;
243
244         BIO_set_callback(bio, BIO_get_callback(b));
245         BIO_set_callback_arg(bio, BIO_get_callback_arg(b));
246
247         if (c->nbio) {
248             if (!BIO_socket_nbio(i, 1)) {
249                 BIOerr(BIO_F_ACPT_STATE,
250                        BIO_R_ERROR_SETTING_NBIO_ON_ACCEPTED_SOCKET);
251                 goto err;
252             }
253         }
254
255         /*
256          * If the accept BIO has an bio_chain, we dup it and put the new
257          * socket at the end.
258          */
259         if (c->bio_chain != NULL) {
260             if ((dbio = BIO_dup_chain(c->bio_chain)) == NULL)
261                 goto err;
262             if (!BIO_push(dbio, bio))
263                 goto err;
264             bio = dbio;
265         }
266         if (BIO_push(b, bio) == NULL)
267             goto err;
268
269         c->state = ACPT_S_OK;
270         return (1);
271  err:
272         if (bio != NULL)
273             BIO_free(bio);
274         else if (s >= 0)
275             closesocket(s);
276         return (0);
277         /* break; */
278     case ACPT_S_OK:
279         if (b->next_bio == NULL) {
280             c->state = ACPT_S_GET_ACCEPT_SOCKET;
281             goto again;
282         }
283         return (1);
284         /* break; */
285     default:
286         return (0);
287         /* break; */
288     }
289
290 }
291
292 static int acpt_read(BIO *b, char *out, int outl)
293 {
294     int ret = 0;
295     BIO_ACCEPT *data;
296
297     BIO_clear_retry_flags(b);
298     data = (BIO_ACCEPT *)b->ptr;
299
300     while (b->next_bio == NULL) {
301         ret = acpt_state(b, data);
302         if (ret <= 0)
303             return (ret);
304     }
305
306     ret = BIO_read(b->next_bio, out, outl);
307     BIO_copy_next_retry(b);
308     return (ret);
309 }
310
311 static int acpt_write(BIO *b, const char *in, int inl)
312 {
313     int ret;
314     BIO_ACCEPT *data;
315
316     BIO_clear_retry_flags(b);
317     data = (BIO_ACCEPT *)b->ptr;
318
319     while (b->next_bio == NULL) {
320         ret = acpt_state(b, data);
321         if (ret <= 0)
322             return (ret);
323     }
324
325     ret = BIO_write(b->next_bio, in, inl);
326     BIO_copy_next_retry(b);
327     return (ret);
328 }
329
330 static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr)
331 {
332     int *ip;
333     long ret = 1;
334     BIO_ACCEPT *data;
335     char **pp;
336
337     data = (BIO_ACCEPT *)b->ptr;
338
339     switch (cmd) {
340     case BIO_CTRL_RESET:
341         ret = 0;
342         data->state = ACPT_S_BEFORE;
343         acpt_close_socket(b);
344         b->flags = 0;
345         break;
346     case BIO_C_DO_STATE_MACHINE:
347         /* use this one to start the connection */
348         ret = (long)acpt_state(b, data);
349         break;
350     case BIO_C_SET_ACCEPT:
351         if (ptr != NULL) {
352             if (num == 0) {
353                 b->init = 1;
354                 OPENSSL_free(data->param_addr);
355                 data->param_addr = BUF_strdup(ptr);
356             } else if (num == 1) {
357                 data->accept_nbio = (ptr != NULL);
358             } else if (num == 2) {
359                 BIO_free(data->bio_chain);
360                 data->bio_chain = (BIO *)ptr;
361             }
362         }
363         break;
364     case BIO_C_SET_NBIO:
365         data->nbio = (int)num;
366         break;
367     case BIO_C_SET_FD:
368         b->init = 1;
369         b->num = *((int *)ptr);
370         data->accept_sock = b->num;
371         data->state = ACPT_S_GET_ACCEPT_SOCKET;
372         b->shutdown = (int)num;
373         b->init = 1;
374         break;
375     case BIO_C_GET_FD:
376         if (b->init) {
377             ip = (int *)ptr;
378             if (ip != NULL)
379                 *ip = data->accept_sock;
380             ret = data->accept_sock;
381         } else
382             ret = -1;
383         break;
384     case BIO_C_GET_ACCEPT:
385         if (b->init) {
386             if (ptr != NULL) {
387                 pp = (char **)ptr;
388                 *pp = data->param_addr;
389             } else
390                 ret = -1;
391         } else
392             ret = -1;
393         break;
394     case BIO_CTRL_GET_CLOSE:
395         ret = b->shutdown;
396         break;
397     case BIO_CTRL_SET_CLOSE:
398         b->shutdown = (int)num;
399         break;
400     case BIO_CTRL_PENDING:
401     case BIO_CTRL_WPENDING:
402         ret = 0;
403         break;
404     case BIO_CTRL_FLUSH:
405         break;
406     case BIO_C_SET_BIND_MODE:
407         data->bind_mode = (int)num;
408         break;
409     case BIO_C_GET_BIND_MODE:
410         ret = (long)data->bind_mode;
411         break;
412     case BIO_CTRL_DUP:
413 /*-     dbio=(BIO *)ptr;
414         if (data->param_port) EAY EAY
415                 BIO_set_port(dbio,data->param_port);
416         if (data->param_hostname)
417                 BIO_set_hostname(dbio,data->param_hostname);
418         BIO_set_nbio(dbio,data->nbio); */
419         break;
420
421     default:
422         ret = 0;
423         break;
424     }
425     return (ret);
426 }
427
428 static int acpt_puts(BIO *bp, const char *str)
429 {
430     int n, ret;
431
432     n = strlen(str);
433     ret = acpt_write(bp, str, n);
434     return (ret);
435 }
436
437 BIO *BIO_new_accept(const char *str)
438 {
439     BIO *ret;
440
441     ret = BIO_new(BIO_s_accept());
442     if (ret == NULL)
443         return (NULL);
444     if (BIO_set_accept_port(ret, str))
445         return (ret);
446     BIO_free(ret);
447     return (NULL);
448 }
449
450 #endif