]>
Commit | Line | Data |
---|---|---|
b1322259 | 1 | /* |
6738bf14 | 2 | * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. |
d02b48c6 | 3 | * |
09abbca1 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
b1322259 RS |
5 | * this file except in compliance with the License. You can obtain a copy |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
d02b48c6 RE |
8 | */ |
9 | ||
d02b48c6 RE |
10 | #include <stdio.h> |
11 | #include <errno.h> | |
417be660 | 12 | #include "bio_lcl.h" |
d02b48c6 | 13 | |
9ba4cc00 RL |
14 | #ifndef OPENSSL_NO_SOCK |
15 | ||
0f113f3e MC |
16 | typedef struct bio_accept_st { |
17 | int state; | |
417be660 RL |
18 | int accept_family; |
19 | int bind_mode; /* Socket mode for BIO_listen */ | |
20 | int accepted_mode; /* Socket mode for BIO_accept (set on accepted sock) */ | |
0f113f3e | 21 | char *param_addr; |
417be660 RL |
22 | char *param_serv; |
23 | ||
0f113f3e | 24 | int accept_sock; |
417be660 RL |
25 | |
26 | BIO_ADDRINFO *addr_first; | |
27 | const BIO_ADDRINFO *addr_iter; | |
28 | BIO_ADDR cache_accepting_addr; /* Useful if we asked for port 0 */ | |
29 | char *cache_accepting_name, *cache_accepting_serv; | |
30 | BIO_ADDR cache_peer_addr; | |
31 | char *cache_peer_name, *cache_peer_serv; | |
32 | ||
0f113f3e MC |
33 | BIO *bio_chain; |
34 | } BIO_ACCEPT; | |
d02b48c6 | 35 | |
0e1c0612 UM |
36 | static int acpt_write(BIO *h, const char *buf, int num); |
37 | static int acpt_read(BIO *h, char *buf, int size); | |
38 | static int acpt_puts(BIO *h, const char *str); | |
39 | static long acpt_ctrl(BIO *h, int cmd, long arg1, void *arg2); | |
d02b48c6 RE |
40 | static int acpt_new(BIO *h); |
41 | static int acpt_free(BIO *data); | |
d02b48c6 RE |
42 | static int acpt_state(BIO *b, BIO_ACCEPT *c); |
43 | static void acpt_close_socket(BIO *data); | |
0f113f3e | 44 | static BIO_ACCEPT *BIO_ACCEPT_new(void); |
b3e72fc3 | 45 | static void BIO_ACCEPT_free(BIO_ACCEPT *a); |
d02b48c6 | 46 | |
0f113f3e | 47 | # define ACPT_S_BEFORE 1 |
417be660 RL |
48 | # define ACPT_S_GET_ADDR 2 |
49 | # define ACPT_S_CREATE_SOCKET 3 | |
50 | # define ACPT_S_LISTEN 4 | |
51 | # define ACPT_S_ACCEPT 5 | |
52 | # define ACPT_S_OK 6 | |
0f113f3e | 53 | |
04f6b0fd | 54 | static const BIO_METHOD methods_acceptp = { |
0f113f3e MC |
55 | BIO_TYPE_ACCEPT, |
56 | "socket accept", | |
3befffa3 MC |
57 | /* TODO: Convert to new style write function */ |
58 | bwrite_conv, | |
0f113f3e | 59 | acpt_write, |
d07aee2c MC |
60 | /* TODO: Convert to new style read function */ |
61 | bread_conv, | |
0f113f3e MC |
62 | acpt_read, |
63 | acpt_puts, | |
b4ff6622 | 64 | NULL, /* connect_gets, */ |
0f113f3e MC |
65 | acpt_ctrl, |
66 | acpt_new, | |
67 | acpt_free, | |
b4ff6622 | 68 | NULL, /* connect_callback_ctrl */ |
0f113f3e | 69 | }; |
d02b48c6 | 70 | |
04f6b0fd | 71 | const BIO_METHOD *BIO_s_accept(void) |
0f113f3e | 72 | { |
26a7d938 | 73 | return &methods_acceptp; |
0f113f3e | 74 | } |
d02b48c6 | 75 | |
6b691a5c | 76 | static int acpt_new(BIO *bi) |
0f113f3e MC |
77 | { |
78 | BIO_ACCEPT *ba; | |
79 | ||
80 | bi->init = 0; | |
b13fdc48 | 81 | bi->num = (int)INVALID_SOCKET; |
0f113f3e MC |
82 | bi->flags = 0; |
83 | if ((ba = BIO_ACCEPT_new()) == NULL) | |
26a7d938 | 84 | return 0; |
0f113f3e MC |
85 | bi->ptr = (char *)ba; |
86 | ba->state = ACPT_S_BEFORE; | |
87 | bi->shutdown = 1; | |
208fb891 | 88 | return 1; |
0f113f3e | 89 | } |
d02b48c6 | 90 | |
b3e72fc3 | 91 | static BIO_ACCEPT *BIO_ACCEPT_new(void) |
0f113f3e MC |
92 | { |
93 | BIO_ACCEPT *ret; | |
d02b48c6 | 94 | |
f06080cb F |
95 | if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) { |
96 | BIOerr(BIO_F_BIO_ACCEPT_NEW, ERR_R_MALLOC_FAILURE); | |
26a7d938 | 97 | return NULL; |
f06080cb | 98 | } |
417be660 | 99 | ret->accept_family = BIO_FAMILY_IPANY; |
b13fdc48 | 100 | ret->accept_sock = (int)INVALID_SOCKET; |
26a7d938 | 101 | return ret; |
0f113f3e | 102 | } |
d02b48c6 | 103 | |
b3e72fc3 | 104 | static void BIO_ACCEPT_free(BIO_ACCEPT *a) |
0f113f3e | 105 | { |
e6e9170d RS |
106 | if (a == NULL) |
107 | return; | |
b548a1f1 | 108 | OPENSSL_free(a->param_addr); |
417be660 RL |
109 | OPENSSL_free(a->param_serv); |
110 | BIO_ADDRINFO_free(a->addr_first); | |
111 | OPENSSL_free(a->cache_accepting_name); | |
112 | OPENSSL_free(a->cache_accepting_serv); | |
113 | OPENSSL_free(a->cache_peer_name); | |
114 | OPENSSL_free(a->cache_peer_serv); | |
ca3a82c3 | 115 | BIO_free(a->bio_chain); |
0f113f3e MC |
116 | OPENSSL_free(a); |
117 | } | |
d02b48c6 | 118 | |
6b691a5c | 119 | static void acpt_close_socket(BIO *bio) |
0f113f3e MC |
120 | { |
121 | BIO_ACCEPT *c; | |
122 | ||
123 | c = (BIO_ACCEPT *)bio->ptr; | |
b13fdc48 | 124 | if (c->accept_sock != (int)INVALID_SOCKET) { |
0f113f3e MC |
125 | shutdown(c->accept_sock, 2); |
126 | closesocket(c->accept_sock); | |
b13fdc48 AP |
127 | c->accept_sock = (int)INVALID_SOCKET; |
128 | bio->num = (int)INVALID_SOCKET; | |
0f113f3e MC |
129 | } |
130 | } | |
d02b48c6 | 131 | |
6b691a5c | 132 | static int acpt_free(BIO *a) |
0f113f3e MC |
133 | { |
134 | BIO_ACCEPT *data; | |
135 | ||
136 | if (a == NULL) | |
26a7d938 | 137 | return 0; |
0f113f3e MC |
138 | data = (BIO_ACCEPT *)a->ptr; |
139 | ||
140 | if (a->shutdown) { | |
141 | acpt_close_socket(a); | |
142 | BIO_ACCEPT_free(data); | |
143 | a->ptr = NULL; | |
144 | a->flags = 0; | |
145 | a->init = 0; | |
146 | } | |
208fb891 | 147 | return 1; |
0f113f3e MC |
148 | } |
149 | ||
6b691a5c | 150 | static int acpt_state(BIO *b, BIO_ACCEPT *c) |
0f113f3e MC |
151 | { |
152 | BIO *bio = NULL, *dbio; | |
417be660 RL |
153 | int s = -1, ret = -1; |
154 | ||
155 | for (;;) { | |
156 | switch (c->state) { | |
157 | case ACPT_S_BEFORE: | |
158 | if (c->param_addr == NULL && c->param_serv == NULL) { | |
159 | BIOerr(BIO_F_ACPT_STATE, BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED); | |
160 | ERR_add_error_data(4, | |
161 | "hostname=", c->param_addr, | |
162 | " service=", c->param_serv); | |
163 | goto exit_loop; | |
0f113f3e | 164 | } |
0f113f3e | 165 | |
417be660 RL |
166 | /* Because we're starting a new bind, any cached name and serv |
167 | * are now obsolete and need to be cleaned out. | |
168 | * QUESTION: should this be done in acpt_close_socket() instead? | |
169 | */ | |
170 | OPENSSL_free(c->cache_accepting_name); | |
171 | c->cache_accepting_name = NULL; | |
172 | OPENSSL_free(c->cache_accepting_serv); | |
173 | c->cache_accepting_serv = NULL; | |
174 | OPENSSL_free(c->cache_peer_name); | |
175 | c->cache_peer_name = NULL; | |
176 | OPENSSL_free(c->cache_peer_serv); | |
177 | c->cache_peer_serv = NULL; | |
178 | ||
179 | c->state = ACPT_S_GET_ADDR; | |
180 | break; | |
181 | ||
182 | case ACPT_S_GET_ADDR: | |
183 | { | |
184 | int family = AF_UNSPEC; | |
185 | switch (c->accept_family) { | |
186 | case BIO_FAMILY_IPV6: | |
187 | if (1) { /* This is a trick we use to avoid bit rot. | |
188 | * at least the "else" part will always be | |
189 | * compiled. | |
190 | */ | |
191 | #ifdef AF_INET6 | |
192 | family = AF_INET6; | |
193 | } else { | |
194 | #endif | |
195 | BIOerr(BIO_F_ACPT_STATE, BIO_R_UNAVAILABLE_IP_FAMILY); | |
196 | goto exit_loop; | |
197 | } | |
198 | break; | |
199 | case BIO_FAMILY_IPV4: | |
200 | family = AF_INET; | |
201 | break; | |
202 | case BIO_FAMILY_IPANY: | |
203 | family = AF_UNSPEC; | |
204 | break; | |
205 | default: | |
206 | BIOerr(BIO_F_ACPT_STATE, BIO_R_UNSUPPORTED_IP_FAMILY); | |
207 | goto exit_loop; | |
208 | } | |
209 | if (BIO_lookup(c->param_addr, c->param_serv, BIO_LOOKUP_SERVER, | |
210 | family, SOCK_STREAM, &c->addr_first) == 0) | |
211 | goto exit_loop; | |
212 | } | |
213 | if (c->addr_first == NULL) { | |
214 | BIOerr(BIO_F_ACPT_STATE, BIO_R_LOOKUP_RETURNED_NOTHING); | |
215 | goto exit_loop; | |
216 | } | |
217 | /* We're currently not iterating, but set this as preparation | |
218 | * for possible future development in that regard | |
219 | */ | |
220 | c->addr_iter = c->addr_first; | |
221 | c->state = ACPT_S_CREATE_SOCKET; | |
222 | break; | |
223 | ||
224 | case ACPT_S_CREATE_SOCKET: | |
225 | ret = BIO_socket(BIO_ADDRINFO_family(c->addr_iter), | |
226 | BIO_ADDRINFO_socktype(c->addr_iter), | |
227 | BIO_ADDRINFO_protocol(c->addr_iter), 0); | |
228 | if (ret == (int)INVALID_SOCKET) { | |
229 | SYSerr(SYS_F_SOCKET, get_last_socket_error()); | |
230 | ERR_add_error_data(4, | |
231 | "hostname=", c->param_addr, | |
232 | " service=", c->param_serv); | |
233 | BIOerr(BIO_F_ACPT_STATE, BIO_R_UNABLE_TO_CREATE_SOCKET); | |
234 | goto exit_loop; | |
235 | } | |
236 | c->accept_sock = ret; | |
237 | b->num = ret; | |
238 | c->state = ACPT_S_LISTEN; | |
239 | break; | |
240 | ||
241 | case ACPT_S_LISTEN: | |
242 | { | |
243 | if (!BIO_listen(c->accept_sock, | |
244 | BIO_ADDRINFO_address(c->addr_iter), | |
245 | c->bind_mode)) { | |
246 | BIO_closesocket(c->accept_sock); | |
247 | goto exit_loop; | |
248 | } | |
249 | } | |
0f113f3e | 250 | |
417be660 RL |
251 | { |
252 | union BIO_sock_info_u info; | |
0f113f3e | 253 | |
417be660 RL |
254 | info.addr = &c->cache_accepting_addr; |
255 | if (!BIO_sock_info(c->accept_sock, BIO_SOCK_INFO_ADDRESS, | |
256 | &info)) { | |
257 | BIO_closesocket(c->accept_sock); | |
258 | goto exit_loop; | |
259 | } | |
260 | } | |
0f113f3e | 261 | |
417be660 RL |
262 | c->cache_accepting_name = |
263 | BIO_ADDR_hostname_string(&c->cache_accepting_addr, 1); | |
264 | c->cache_accepting_serv = | |
265 | BIO_ADDR_service_string(&c->cache_accepting_addr, 1); | |
266 | c->state = ACPT_S_ACCEPT; | |
267 | s = -1; | |
268 | ret = 1; | |
269 | goto end; | |
270 | ||
271 | case ACPT_S_ACCEPT: | |
272 | if (b->next_bio != NULL) { | |
273 | c->state = ACPT_S_OK; | |
274 | break; | |
275 | } | |
276 | BIO_clear_retry_flags(b); | |
277 | b->retry_reason = 0; | |
278 | ||
4e075253 VD |
279 | OPENSSL_free(c->cache_peer_name); |
280 | c->cache_peer_name = NULL; | |
281 | OPENSSL_free(c->cache_peer_serv); | |
282 | c->cache_peer_serv = NULL; | |
283 | ||
417be660 RL |
284 | s = BIO_accept_ex(c->accept_sock, &c->cache_peer_addr, |
285 | c->accepted_mode); | |
286 | ||
287 | /* If the returned socket is invalid, this might still be | |
288 | * retryable | |
289 | */ | |
290 | if (s < 0) { | |
291 | if (BIO_sock_should_retry(s)) { | |
292 | BIO_set_retry_special(b); | |
293 | b->retry_reason = BIO_RR_ACCEPT; | |
294 | goto end; | |
295 | } | |
0f113f3e | 296 | } |
0f113f3e | 297 | |
417be660 RL |
298 | /* If it wasn't retryable, we fail */ |
299 | if (s < 0) { | |
300 | ret = s; | |
301 | goto exit_loop; | |
302 | } | |
303 | ||
304 | bio = BIO_new_socket(s, BIO_CLOSE); | |
305 | if (bio == NULL) | |
306 | goto exit_loop; | |
307 | ||
308 | BIO_set_callback(bio, BIO_get_callback(b)); | |
309 | BIO_set_callback_arg(bio, BIO_get_callback_arg(b)); | |
310 | ||
311 | /* | |
312 | * If the accept BIO has an bio_chain, we dup it and put the new | |
313 | * socket at the end. | |
314 | */ | |
315 | if (c->bio_chain != NULL) { | |
316 | if ((dbio = BIO_dup_chain(c->bio_chain)) == NULL) | |
317 | goto exit_loop; | |
318 | if (!BIO_push(dbio, bio)) | |
319 | goto exit_loop; | |
320 | bio = dbio; | |
321 | } | |
322 | if (BIO_push(b, bio) == NULL) | |
323 | goto exit_loop; | |
324 | ||
325 | c->cache_peer_name = | |
326 | BIO_ADDR_hostname_string(&c->cache_peer_addr, 1); | |
327 | c->cache_peer_serv = | |
328 | BIO_ADDR_service_string(&c->cache_peer_addr, 1); | |
329 | c->state = ACPT_S_OK; | |
330 | bio = NULL; | |
331 | ret = 1; | |
332 | goto end; | |
333 | ||
334 | case ACPT_S_OK: | |
335 | if (b->next_bio == NULL) { | |
336 | c->state = ACPT_S_ACCEPT; | |
337 | break; | |
338 | } | |
339 | ret = 1; | |
340 | goto end; | |
341 | ||
342 | default: | |
343 | ret = 0; | |
344 | goto end; | |
0f113f3e | 345 | } |
0f113f3e MC |
346 | } |
347 | ||
417be660 RL |
348 | exit_loop: |
349 | if (bio != NULL) | |
350 | BIO_free(bio); | |
351 | else if (s >= 0) | |
352 | BIO_closesocket(s); | |
353 | end: | |
354 | return ret; | |
0f113f3e | 355 | } |
d02b48c6 | 356 | |
6b691a5c | 357 | static int acpt_read(BIO *b, char *out, int outl) |
0f113f3e MC |
358 | { |
359 | int ret = 0; | |
360 | BIO_ACCEPT *data; | |
d02b48c6 | 361 | |
0f113f3e MC |
362 | BIO_clear_retry_flags(b); |
363 | data = (BIO_ACCEPT *)b->ptr; | |
d02b48c6 | 364 | |
0f113f3e MC |
365 | while (b->next_bio == NULL) { |
366 | ret = acpt_state(b, data); | |
367 | if (ret <= 0) | |
26a7d938 | 368 | return ret; |
0f113f3e | 369 | } |
d02b48c6 | 370 | |
0f113f3e MC |
371 | ret = BIO_read(b->next_bio, out, outl); |
372 | BIO_copy_next_retry(b); | |
26a7d938 | 373 | return ret; |
0f113f3e | 374 | } |
d02b48c6 | 375 | |
0e1c0612 | 376 | static int acpt_write(BIO *b, const char *in, int inl) |
0f113f3e MC |
377 | { |
378 | int ret; | |
379 | BIO_ACCEPT *data; | |
d02b48c6 | 380 | |
0f113f3e MC |
381 | BIO_clear_retry_flags(b); |
382 | data = (BIO_ACCEPT *)b->ptr; | |
d02b48c6 | 383 | |
0f113f3e MC |
384 | while (b->next_bio == NULL) { |
385 | ret = acpt_state(b, data); | |
386 | if (ret <= 0) | |
26a7d938 | 387 | return ret; |
0f113f3e | 388 | } |
d02b48c6 | 389 | |
0f113f3e MC |
390 | ret = BIO_write(b->next_bio, in, inl); |
391 | BIO_copy_next_retry(b); | |
26a7d938 | 392 | return ret; |
0f113f3e | 393 | } |
d02b48c6 | 394 | |
0e1c0612 | 395 | static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr) |
0f113f3e MC |
396 | { |
397 | int *ip; | |
398 | long ret = 1; | |
399 | BIO_ACCEPT *data; | |
400 | char **pp; | |
401 | ||
402 | data = (BIO_ACCEPT *)b->ptr; | |
403 | ||
404 | switch (cmd) { | |
405 | case BIO_CTRL_RESET: | |
406 | ret = 0; | |
407 | data->state = ACPT_S_BEFORE; | |
408 | acpt_close_socket(b); | |
417be660 RL |
409 | BIO_ADDRINFO_free(data->addr_first); |
410 | data->addr_first = NULL; | |
0f113f3e MC |
411 | b->flags = 0; |
412 | break; | |
413 | case BIO_C_DO_STATE_MACHINE: | |
414 | /* use this one to start the connection */ | |
415 | ret = (long)acpt_state(b, data); | |
416 | break; | |
417 | case BIO_C_SET_ACCEPT: | |
418 | if (ptr != NULL) { | |
419 | if (num == 0) { | |
417be660 RL |
420 | char *hold_serv = data->param_serv; |
421 | /* We affect the hostname regardless. However, the input | |
422 | * string might contain a host:service spec, so we must | |
423 | * parse it, which might or might not affect the service | |
424 | */ | |
b548a1f1 | 425 | OPENSSL_free(data->param_addr); |
417be660 RL |
426 | data->param_addr = NULL; |
427 | ret = BIO_parse_hostserv(ptr, | |
428 | &data->param_addr, | |
429 | &data->param_serv, | |
430 | BIO_PARSE_PRIO_SERV); | |
431 | if (hold_serv != data->param_serv) | |
432 | OPENSSL_free(hold_serv); | |
433 | b->init = 1; | |
0f113f3e | 434 | } else if (num == 1) { |
417be660 RL |
435 | OPENSSL_free(data->param_serv); |
436 | data->param_serv = BUF_strdup(ptr); | |
437 | b->init = 1; | |
0f113f3e | 438 | } else if (num == 2) { |
68423b14 | 439 | data->bind_mode |= BIO_SOCK_NONBLOCK; |
417be660 | 440 | } else if (num == 3) { |
ca3a82c3 | 441 | BIO_free(data->bio_chain); |
0f113f3e | 442 | data->bio_chain = (BIO *)ptr; |
417be660 RL |
443 | } else if (num == 4) { |
444 | data->accept_family = *(int *)ptr; | |
0f113f3e | 445 | } |
68423b14 RL |
446 | } else { |
447 | if (num == 2) { | |
448 | data->bind_mode &= ~BIO_SOCK_NONBLOCK; | |
449 | } | |
0f113f3e MC |
450 | } |
451 | break; | |
452 | case BIO_C_SET_NBIO: | |
417be660 RL |
453 | if (num != 0) |
454 | data->accepted_mode |= BIO_SOCK_NONBLOCK; | |
455 | else | |
456 | data->accepted_mode &= ~BIO_SOCK_NONBLOCK; | |
0f113f3e MC |
457 | break; |
458 | case BIO_C_SET_FD: | |
0f113f3e MC |
459 | b->num = *((int *)ptr); |
460 | data->accept_sock = b->num; | |
417be660 | 461 | data->state = ACPT_S_ACCEPT; |
0f113f3e MC |
462 | b->shutdown = (int)num; |
463 | b->init = 1; | |
464 | break; | |
465 | case BIO_C_GET_FD: | |
466 | if (b->init) { | |
467 | ip = (int *)ptr; | |
468 | if (ip != NULL) | |
469 | *ip = data->accept_sock; | |
470 | ret = data->accept_sock; | |
471 | } else | |
472 | ret = -1; | |
473 | break; | |
474 | case BIO_C_GET_ACCEPT: | |
475 | if (b->init) { | |
417be660 RL |
476 | if (num == 0 && ptr != NULL) { |
477 | pp = (char **)ptr; | |
478 | *pp = data->cache_accepting_name; | |
479 | } else if (num == 1 && ptr != NULL) { | |
480 | pp = (char **)ptr; | |
481 | *pp = data->cache_accepting_serv; | |
482 | } else if (num == 2 && ptr != NULL) { | |
483 | pp = (char **)ptr; | |
484 | *pp = data->cache_peer_name; | |
485 | } else if (num == 3 && ptr != NULL) { | |
0f113f3e | 486 | pp = (char **)ptr; |
417be660 RL |
487 | *pp = data->cache_peer_serv; |
488 | } else if (num == 4) { | |
489 | switch (BIO_ADDRINFO_family(data->addr_iter)) { | |
490 | #ifdef AF_INET6 | |
491 | case AF_INET6: | |
492 | ret = BIO_FAMILY_IPV6; | |
493 | break; | |
494 | #endif | |
495 | case AF_INET: | |
496 | ret = BIO_FAMILY_IPV4; | |
497 | break; | |
498 | case 0: | |
499 | ret = data->accept_family; | |
500 | break; | |
501 | default: | |
502 | ret = -1; | |
503 | break; | |
504 | } | |
0f113f3e MC |
505 | } else |
506 | ret = -1; | |
507 | } else | |
508 | ret = -1; | |
509 | break; | |
510 | case BIO_CTRL_GET_CLOSE: | |
511 | ret = b->shutdown; | |
512 | break; | |
513 | case BIO_CTRL_SET_CLOSE: | |
514 | b->shutdown = (int)num; | |
515 | break; | |
516 | case BIO_CTRL_PENDING: | |
517 | case BIO_CTRL_WPENDING: | |
518 | ret = 0; | |
519 | break; | |
520 | case BIO_CTRL_FLUSH: | |
521 | break; | |
522 | case BIO_C_SET_BIND_MODE: | |
523 | data->bind_mode = (int)num; | |
524 | break; | |
525 | case BIO_C_GET_BIND_MODE: | |
526 | ret = (long)data->bind_mode; | |
527 | break; | |
528 | case BIO_CTRL_DUP: | |
0f113f3e MC |
529 | break; |
530 | ||
531 | default: | |
532 | ret = 0; | |
533 | break; | |
534 | } | |
26a7d938 | 535 | return ret; |
0f113f3e | 536 | } |
d02b48c6 | 537 | |
0e1c0612 | 538 | static int acpt_puts(BIO *bp, const char *str) |
0f113f3e MC |
539 | { |
540 | int n, ret; | |
d02b48c6 | 541 | |
0f113f3e MC |
542 | n = strlen(str); |
543 | ret = acpt_write(bp, str, n); | |
26a7d938 | 544 | return ret; |
0f113f3e | 545 | } |
d02b48c6 | 546 | |
c45a48c1 | 547 | BIO *BIO_new_accept(const char *str) |
0f113f3e MC |
548 | { |
549 | BIO *ret; | |
550 | ||
551 | ret = BIO_new(BIO_s_accept()); | |
552 | if (ret == NULL) | |
26a7d938 | 553 | return NULL; |
b4c1d72e | 554 | if (BIO_set_accept_name(ret, str)) |
26a7d938 | 555 | return ret; |
ca3a82c3 | 556 | BIO_free(ret); |
26a7d938 | 557 | return NULL; |
0f113f3e | 558 | } |
d02b48c6 RE |
559 | |
560 | #endif |