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