]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/bio/bss_acpt.c
Refactoring BIO: adapt BIO_s_connect and BIO_s_accept
[thirdparty/openssl.git] / crypto / bio / bss_acpt.c
CommitLineData
58964a49 1/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
d02b48c6
RE
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.
0f113f3e 7 *
d02b48c6
RE
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).
0f113f3e 14 *
d02b48c6
RE
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.
0f113f3e 21 *
d02b48c6
RE
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 :-).
0f113f3e 36 * 4. If you include any Windows specific code (or a derivative thereof) from
d02b48c6
RE
37 * the apps directory (application code) you must include an acknowledgement:
38 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
0f113f3e 39 *
d02b48c6
RE
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.
0f113f3e 51 *
d02b48c6
RE
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
d02b48c6
RE
58#include <stdio.h>
59#include <errno.h>
417be660 60#include "bio_lcl.h"
d02b48c6 61
9ba4cc00
RL
62#ifndef OPENSSL_NO_SOCK
63
0f113f3e
MC
64typedef struct bio_accept_st {
65 int state;
417be660
RL
66 int accept_family;
67 int bind_mode; /* Socket mode for BIO_listen */
68 int accepted_mode; /* Socket mode for BIO_accept (set on accepted sock) */
0f113f3e 69 char *param_addr;
417be660
RL
70 char *param_serv;
71
0f113f3e 72 int accept_sock;
417be660
RL
73
74 BIO_ADDRINFO *addr_first;
75 const BIO_ADDRINFO *addr_iter;
76 BIO_ADDR cache_accepting_addr; /* Useful if we asked for port 0 */
77 char *cache_accepting_name, *cache_accepting_serv;
78 BIO_ADDR cache_peer_addr;
79 char *cache_peer_name, *cache_peer_serv;
80
0f113f3e
MC
81 BIO *bio_chain;
82} BIO_ACCEPT;
d02b48c6 83
0e1c0612
UM
84static int acpt_write(BIO *h, const char *buf, int num);
85static int acpt_read(BIO *h, char *buf, int size);
86static int acpt_puts(BIO *h, const char *str);
87static long acpt_ctrl(BIO *h, int cmd, long arg1, void *arg2);
d02b48c6
RE
88static int acpt_new(BIO *h);
89static int acpt_free(BIO *data);
d02b48c6
RE
90static int acpt_state(BIO *b, BIO_ACCEPT *c);
91static void acpt_close_socket(BIO *data);
0f113f3e 92static BIO_ACCEPT *BIO_ACCEPT_new(void);
b3e72fc3 93static void BIO_ACCEPT_free(BIO_ACCEPT *a);
d02b48c6 94
0f113f3e 95# define ACPT_S_BEFORE 1
417be660
RL
96# define ACPT_S_GET_ADDR 2
97# define ACPT_S_CREATE_SOCKET 3
98# define ACPT_S_LISTEN 4
99# define ACPT_S_ACCEPT 5
100# define ACPT_S_OK 6
0f113f3e
MC
101
102static 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};
d02b48c6 114
6b691a5c 115BIO_METHOD *BIO_s_accept(void)
0f113f3e
MC
116{
117 return (&methods_acceptp);
118}
d02b48c6 119
6b691a5c 120static int acpt_new(BIO *bi)
0f113f3e
MC
121{
122 BIO_ACCEPT *ba;
123
124 bi->init = 0;
b13fdc48 125 bi->num = (int)INVALID_SOCKET;
0f113f3e
MC
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}
d02b48c6 134
b3e72fc3 135static BIO_ACCEPT *BIO_ACCEPT_new(void)
0f113f3e
MC
136{
137 BIO_ACCEPT *ret;
d02b48c6 138
b51bce94 139 if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL)
0f113f3e 140 return (NULL);
417be660 141 ret->accept_family = BIO_FAMILY_IPANY;
b13fdc48 142 ret->accept_sock = (int)INVALID_SOCKET;
0f113f3e
MC
143 return (ret);
144}
d02b48c6 145
b3e72fc3 146static void BIO_ACCEPT_free(BIO_ACCEPT *a)
0f113f3e
MC
147{
148 if (a == NULL)
149 return;
150
b548a1f1 151 OPENSSL_free(a->param_addr);
417be660
RL
152 OPENSSL_free(a->param_serv);
153 BIO_ADDRINFO_free(a->addr_first);
154 OPENSSL_free(a->cache_accepting_name);
155 OPENSSL_free(a->cache_accepting_serv);
156 OPENSSL_free(a->cache_peer_name);
157 OPENSSL_free(a->cache_peer_serv);
ca3a82c3 158 BIO_free(a->bio_chain);
0f113f3e
MC
159 OPENSSL_free(a);
160}
d02b48c6 161
6b691a5c 162static void acpt_close_socket(BIO *bio)
0f113f3e
MC
163{
164 BIO_ACCEPT *c;
165
166 c = (BIO_ACCEPT *)bio->ptr;
b13fdc48 167 if (c->accept_sock != (int)INVALID_SOCKET) {
0f113f3e
MC
168 shutdown(c->accept_sock, 2);
169 closesocket(c->accept_sock);
b13fdc48
AP
170 c->accept_sock = (int)INVALID_SOCKET;
171 bio->num = (int)INVALID_SOCKET;
0f113f3e
MC
172 }
173}
d02b48c6 174
6b691a5c 175static int acpt_free(BIO *a)
0f113f3e
MC
176{
177 BIO_ACCEPT *data;
178
179 if (a == NULL)
180 return (0);
181 data = (BIO_ACCEPT *)a->ptr;
182
183 if (a->shutdown) {
184 acpt_close_socket(a);
185 BIO_ACCEPT_free(data);
186 a->ptr = NULL;
187 a->flags = 0;
188 a->init = 0;
189 }
190 return (1);
191}
192
6b691a5c 193static int acpt_state(BIO *b, BIO_ACCEPT *c)
0f113f3e
MC
194{
195 BIO *bio = NULL, *dbio;
417be660
RL
196 int s = -1, ret = -1;
197
198 for (;;) {
199 switch (c->state) {
200 case ACPT_S_BEFORE:
201 if (c->param_addr == NULL && c->param_serv == NULL) {
202 BIOerr(BIO_F_ACPT_STATE, BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED);
203 ERR_add_error_data(4,
204 "hostname=", c->param_addr,
205 " service=", c->param_serv);
206 goto exit_loop;
0f113f3e 207 }
0f113f3e 208
417be660
RL
209 /* Because we're starting a new bind, any cached name and serv
210 * are now obsolete and need to be cleaned out.
211 * QUESTION: should this be done in acpt_close_socket() instead?
212 */
213 OPENSSL_free(c->cache_accepting_name);
214 c->cache_accepting_name = NULL;
215 OPENSSL_free(c->cache_accepting_serv);
216 c->cache_accepting_serv = NULL;
217 OPENSSL_free(c->cache_peer_name);
218 c->cache_peer_name = NULL;
219 OPENSSL_free(c->cache_peer_serv);
220 c->cache_peer_serv = NULL;
221
222 c->state = ACPT_S_GET_ADDR;
223 break;
224
225 case ACPT_S_GET_ADDR:
226 {
227 int family = AF_UNSPEC;
228 switch (c->accept_family) {
229 case BIO_FAMILY_IPV6:
230 if (1) { /* This is a trick we use to avoid bit rot.
231 * at least the "else" part will always be
232 * compiled.
233 */
234#ifdef AF_INET6
235 family = AF_INET6;
236 } else {
237#endif
238 BIOerr(BIO_F_ACPT_STATE, BIO_R_UNAVAILABLE_IP_FAMILY);
239 goto exit_loop;
240 }
241 break;
242 case BIO_FAMILY_IPV4:
243 family = AF_INET;
244 break;
245 case BIO_FAMILY_IPANY:
246 family = AF_UNSPEC;
247 break;
248 default:
249 BIOerr(BIO_F_ACPT_STATE, BIO_R_UNSUPPORTED_IP_FAMILY);
250 goto exit_loop;
251 }
252 if (BIO_lookup(c->param_addr, c->param_serv, BIO_LOOKUP_SERVER,
253 family, SOCK_STREAM, &c->addr_first) == 0)
254 goto exit_loop;
255 }
256 if (c->addr_first == NULL) {
257 BIOerr(BIO_F_ACPT_STATE, BIO_R_LOOKUP_RETURNED_NOTHING);
258 goto exit_loop;
259 }
260 /* We're currently not iterating, but set this as preparation
261 * for possible future development in that regard
262 */
263 c->addr_iter = c->addr_first;
264 c->state = ACPT_S_CREATE_SOCKET;
265 break;
266
267 case ACPT_S_CREATE_SOCKET:
268 ret = BIO_socket(BIO_ADDRINFO_family(c->addr_iter),
269 BIO_ADDRINFO_socktype(c->addr_iter),
270 BIO_ADDRINFO_protocol(c->addr_iter), 0);
271 if (ret == (int)INVALID_SOCKET) {
272 SYSerr(SYS_F_SOCKET, get_last_socket_error());
273 ERR_add_error_data(4,
274 "hostname=", c->param_addr,
275 " service=", c->param_serv);
276 BIOerr(BIO_F_ACPT_STATE, BIO_R_UNABLE_TO_CREATE_SOCKET);
277 goto exit_loop;
278 }
279 c->accept_sock = ret;
280 b->num = ret;
281 c->state = ACPT_S_LISTEN;
282 break;
283
284 case ACPT_S_LISTEN:
285 {
286 if (!BIO_listen(c->accept_sock,
287 BIO_ADDRINFO_address(c->addr_iter),
288 c->bind_mode)) {
289 BIO_closesocket(c->accept_sock);
290 goto exit_loop;
291 }
292 }
0f113f3e 293
417be660
RL
294 {
295 union BIO_sock_info_u info;
0f113f3e 296
417be660
RL
297 info.addr = &c->cache_accepting_addr;
298 if (!BIO_sock_info(c->accept_sock, BIO_SOCK_INFO_ADDRESS,
299 &info)) {
300 BIO_closesocket(c->accept_sock);
301 goto exit_loop;
302 }
303 }
0f113f3e 304
417be660
RL
305 c->cache_accepting_name =
306 BIO_ADDR_hostname_string(&c->cache_accepting_addr, 1);
307 c->cache_accepting_serv =
308 BIO_ADDR_service_string(&c->cache_accepting_addr, 1);
309 c->state = ACPT_S_ACCEPT;
310 s = -1;
311 ret = 1;
312 goto end;
313
314 case ACPT_S_ACCEPT:
315 if (b->next_bio != NULL) {
316 c->state = ACPT_S_OK;
317 break;
318 }
319 BIO_clear_retry_flags(b);
320 b->retry_reason = 0;
321
322 s = BIO_accept_ex(c->accept_sock, &c->cache_peer_addr,
323 c->accepted_mode);
324
325 /* If the returned socket is invalid, this might still be
326 * retryable
327 */
328 if (s < 0) {
329 if (BIO_sock_should_retry(s)) {
330 BIO_set_retry_special(b);
331 b->retry_reason = BIO_RR_ACCEPT;
332 goto end;
333 }
0f113f3e 334 }
0f113f3e 335
417be660
RL
336 /* If it wasn't retryable, we fail */
337 if (s < 0) {
338 ret = s;
339 goto exit_loop;
340 }
341
342 bio = BIO_new_socket(s, BIO_CLOSE);
343 if (bio == NULL)
344 goto exit_loop;
345
346 BIO_set_callback(bio, BIO_get_callback(b));
347 BIO_set_callback_arg(bio, BIO_get_callback_arg(b));
348
349 /*
350 * If the accept BIO has an bio_chain, we dup it and put the new
351 * socket at the end.
352 */
353 if (c->bio_chain != NULL) {
354 if ((dbio = BIO_dup_chain(c->bio_chain)) == NULL)
355 goto exit_loop;
356 if (!BIO_push(dbio, bio))
357 goto exit_loop;
358 bio = dbio;
359 }
360 if (BIO_push(b, bio) == NULL)
361 goto exit_loop;
362
363 c->cache_peer_name =
364 BIO_ADDR_hostname_string(&c->cache_peer_addr, 1);
365 c->cache_peer_serv =
366 BIO_ADDR_service_string(&c->cache_peer_addr, 1);
367 c->state = ACPT_S_OK;
368 bio = NULL;
369 ret = 1;
370 goto end;
371
372 case ACPT_S_OK:
373 if (b->next_bio == NULL) {
374 c->state = ACPT_S_ACCEPT;
375 break;
376 }
377 ret = 1;
378 goto end;
379
380 default:
381 ret = 0;
382 goto end;
0f113f3e 383 }
0f113f3e
MC
384 }
385
417be660
RL
386 exit_loop:
387 if (bio != NULL)
388 BIO_free(bio);
389 else if (s >= 0)
390 BIO_closesocket(s);
391 end:
392 return ret;
0f113f3e 393}
d02b48c6 394
6b691a5c 395static int acpt_read(BIO *b, char *out, int outl)
0f113f3e
MC
396{
397 int ret = 0;
398 BIO_ACCEPT *data;
d02b48c6 399
0f113f3e
MC
400 BIO_clear_retry_flags(b);
401 data = (BIO_ACCEPT *)b->ptr;
d02b48c6 402
0f113f3e
MC
403 while (b->next_bio == NULL) {
404 ret = acpt_state(b, data);
405 if (ret <= 0)
406 return (ret);
407 }
d02b48c6 408
0f113f3e
MC
409 ret = BIO_read(b->next_bio, out, outl);
410 BIO_copy_next_retry(b);
411 return (ret);
412}
d02b48c6 413
0e1c0612 414static int acpt_write(BIO *b, const char *in, int inl)
0f113f3e
MC
415{
416 int ret;
417 BIO_ACCEPT *data;
d02b48c6 418
0f113f3e
MC
419 BIO_clear_retry_flags(b);
420 data = (BIO_ACCEPT *)b->ptr;
d02b48c6 421
0f113f3e
MC
422 while (b->next_bio == NULL) {
423 ret = acpt_state(b, data);
424 if (ret <= 0)
425 return (ret);
426 }
d02b48c6 427
0f113f3e
MC
428 ret = BIO_write(b->next_bio, in, inl);
429 BIO_copy_next_retry(b);
430 return (ret);
431}
d02b48c6 432
0e1c0612 433static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr)
0f113f3e
MC
434{
435 int *ip;
436 long ret = 1;
437 BIO_ACCEPT *data;
438 char **pp;
439
440 data = (BIO_ACCEPT *)b->ptr;
441
442 switch (cmd) {
443 case BIO_CTRL_RESET:
444 ret = 0;
445 data->state = ACPT_S_BEFORE;
446 acpt_close_socket(b);
417be660
RL
447 BIO_ADDRINFO_free(data->addr_first);
448 data->addr_first = NULL;
0f113f3e
MC
449 b->flags = 0;
450 break;
451 case BIO_C_DO_STATE_MACHINE:
452 /* use this one to start the connection */
453 ret = (long)acpt_state(b, data);
454 break;
455 case BIO_C_SET_ACCEPT:
456 if (ptr != NULL) {
457 if (num == 0) {
417be660
RL
458 char *hold_serv = data->param_serv;
459 /* We affect the hostname regardless. However, the input
460 * string might contain a host:service spec, so we must
461 * parse it, which might or might not affect the service
462 */
b548a1f1 463 OPENSSL_free(data->param_addr);
417be660
RL
464 data->param_addr = NULL;
465 ret = BIO_parse_hostserv(ptr,
466 &data->param_addr,
467 &data->param_serv,
468 BIO_PARSE_PRIO_SERV);
469 if (hold_serv != data->param_serv)
470 OPENSSL_free(hold_serv);
471 b->init = 1;
0f113f3e 472 } else if (num == 1) {
417be660
RL
473 OPENSSL_free(data->param_serv);
474 data->param_serv = BUF_strdup(ptr);
475 b->init = 1;
0f113f3e 476 } else if (num == 2) {
417be660
RL
477 if (ptr != NULL)
478 data->bind_mode |= BIO_SOCK_NONBLOCK;
479 else
480 data->bind_mode &= ~BIO_SOCK_NONBLOCK;
481 } else if (num == 3) {
ca3a82c3 482 BIO_free(data->bio_chain);
0f113f3e 483 data->bio_chain = (BIO *)ptr;
417be660
RL
484 } else if (num == 4) {
485 data->accept_family = *(int *)ptr;
0f113f3e
MC
486 }
487 }
488 break;
489 case BIO_C_SET_NBIO:
417be660
RL
490 if (num != 0)
491 data->accepted_mode |= BIO_SOCK_NONBLOCK;
492 else
493 data->accepted_mode &= ~BIO_SOCK_NONBLOCK;
0f113f3e
MC
494 break;
495 case BIO_C_SET_FD:
496 b->init = 1;
497 b->num = *((int *)ptr);
498 data->accept_sock = b->num;
417be660 499 data->state = ACPT_S_ACCEPT;
0f113f3e
MC
500 b->shutdown = (int)num;
501 b->init = 1;
502 break;
503 case BIO_C_GET_FD:
504 if (b->init) {
505 ip = (int *)ptr;
506 if (ip != NULL)
507 *ip = data->accept_sock;
508 ret = data->accept_sock;
509 } else
510 ret = -1;
511 break;
512 case BIO_C_GET_ACCEPT:
513 if (b->init) {
417be660
RL
514 if (num == 0 && ptr != NULL) {
515 pp = (char **)ptr;
516 *pp = data->cache_accepting_name;
517 } else if (num == 1 && ptr != NULL) {
518 pp = (char **)ptr;
519 *pp = data->cache_accepting_serv;
520 } else if (num == 2 && ptr != NULL) {
521 pp = (char **)ptr;
522 *pp = data->cache_peer_name;
523 } else if (num == 3 && ptr != NULL) {
0f113f3e 524 pp = (char **)ptr;
417be660
RL
525 *pp = data->cache_peer_serv;
526 } else if (num == 4) {
527 switch (BIO_ADDRINFO_family(data->addr_iter)) {
528#ifdef AF_INET6
529 case AF_INET6:
530 ret = BIO_FAMILY_IPV6;
531 break;
532#endif
533 case AF_INET:
534 ret = BIO_FAMILY_IPV4;
535 break;
536 case 0:
537 ret = data->accept_family;
538 break;
539 default:
540 ret = -1;
541 break;
542 }
0f113f3e
MC
543 } else
544 ret = -1;
545 } else
546 ret = -1;
547 break;
548 case BIO_CTRL_GET_CLOSE:
549 ret = b->shutdown;
550 break;
551 case BIO_CTRL_SET_CLOSE:
552 b->shutdown = (int)num;
553 break;
554 case BIO_CTRL_PENDING:
555 case BIO_CTRL_WPENDING:
556 ret = 0;
557 break;
558 case BIO_CTRL_FLUSH:
559 break;
560 case BIO_C_SET_BIND_MODE:
561 data->bind_mode = (int)num;
562 break;
563 case BIO_C_GET_BIND_MODE:
564 ret = (long)data->bind_mode;
565 break;
566 case BIO_CTRL_DUP:
35a1cc90
MC
567/*- dbio=(BIO *)ptr;
568 if (data->param_port) EAY EAY
569 BIO_set_port(dbio,data->param_port);
570 if (data->param_hostname)
571 BIO_set_hostname(dbio,data->param_hostname);
572 BIO_set_nbio(dbio,data->nbio); */
0f113f3e
MC
573 break;
574
575 default:
576 ret = 0;
577 break;
578 }
579 return (ret);
580}
d02b48c6 581
0e1c0612 582static int acpt_puts(BIO *bp, const char *str)
0f113f3e
MC
583{
584 int n, ret;
d02b48c6 585
0f113f3e
MC
586 n = strlen(str);
587 ret = acpt_write(bp, str, n);
588 return (ret);
589}
d02b48c6 590
c45a48c1 591BIO *BIO_new_accept(const char *str)
0f113f3e
MC
592{
593 BIO *ret;
594
595 ret = BIO_new(BIO_s_accept());
596 if (ret == NULL)
597 return (NULL);
598 if (BIO_set_accept_port(ret, str))
599 return (ret);
ca3a82c3
RS
600 BIO_free(ret);
601 return (NULL);
0f113f3e 602}
d02b48c6
RE
603
604#endif