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