155714Skris/* crypto/bio/bss_acpt.c */
255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
355714Skris * All rights reserved.
455714Skris *
555714Skris * This package is an SSL implementation written
655714Skris * by Eric Young (eay@cryptsoft.com).
755714Skris * The implementation was written so as to conform with Netscapes SSL.
8296465Sdelphij *
955714Skris * This library is free for commercial and non-commercial use as long as
1055714Skris * the following conditions are aheared to.  The following conditions
1155714Skris * apply to all code found in this distribution, be it the RC4, RSA,
1255714Skris * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1355714Skris * included with this distribution is covered by the same copyright terms
1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15296465Sdelphij *
1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in
1755714Skris * the code are not to be removed.
1855714Skris * If this package is used in a product, Eric Young should be given attribution
1955714Skris * as the author of the parts of the library used.
2055714Skris * This can be in the form of a textual message at program startup or
2155714Skris * in documentation (online or textual) provided with the package.
22296465Sdelphij *
2355714Skris * Redistribution and use in source and binary forms, with or without
2455714Skris * modification, are permitted provided that the following conditions
2555714Skris * are met:
2655714Skris * 1. Redistributions of source code must retain the copyright
2755714Skris *    notice, this list of conditions and the following disclaimer.
2855714Skris * 2. Redistributions in binary form must reproduce the above copyright
2955714Skris *    notice, this list of conditions and the following disclaimer in the
3055714Skris *    documentation and/or other materials provided with the distribution.
3155714Skris * 3. All advertising materials mentioning features or use of this software
3255714Skris *    must display the following acknowledgement:
3355714Skris *    "This product includes cryptographic software written by
3455714Skris *     Eric Young (eay@cryptsoft.com)"
3555714Skris *    The word 'cryptographic' can be left out if the rouines from the library
3655714Skris *    being used are not cryptographic related :-).
37296465Sdelphij * 4. If you include any Windows specific code (or a derivative thereof) from
3855714Skris *    the apps directory (application code) you must include an acknowledgement:
3955714Skris *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40296465Sdelphij *
4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4455714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5155714Skris * SUCH DAMAGE.
52296465Sdelphij *
5355714Skris * The licence and distribution terms for any publically available version or
5455714Skris * derivative of this code cannot be changed.  i.e. this code cannot simply be
5555714Skris * copied and put under another distribution licence
5655714Skris * [including the GNU Public Licence.]
5755714Skris */
5855714Skris
5955714Skris#include <stdio.h>
6055714Skris#include <errno.h>
6155714Skris#define USE_SOCKETS
6255714Skris#include "cryptlib.h"
6355714Skris#include <openssl/bio.h>
6455714Skris
65160814Ssimon#ifndef OPENSSL_NO_SOCK
66160814Ssimon
67296465Sdelphij# ifdef OPENSSL_SYS_WIN16
68296465Sdelphij#  define SOCKET_PROTOCOL 0     /* more microsoft stupidity */
69296465Sdelphij# else
70296465Sdelphij#  define SOCKET_PROTOCOL IPPROTO_TCP
71296465Sdelphij# endif
7255714Skris
73296465Sdelphij# if (defined(OPENSSL_SYS_VMS) && __VMS_VER < 70000000)
7455714Skris/* FIONBIO used as a switch to enable ioctl, and that isn't in VMS < 7.0 */
75296465Sdelphij#  undef FIONBIO
76296465Sdelphij# endif
7755714Skris
78296465Sdelphijtypedef struct bio_accept_st {
79296465Sdelphij    int state;
80296465Sdelphij    char *param_addr;
81296465Sdelphij    int accept_sock;
82296465Sdelphij    int accept_nbio;
83296465Sdelphij    char *addr;
84296465Sdelphij    int nbio;
85296465Sdelphij    /*
86296465Sdelphij     * If 0, it means normal, if 1, do a connect on bind failure, and if
87296465Sdelphij     * there is no-one listening, bind with SO_REUSEADDR. If 2, always use
88296465Sdelphij     * SO_REUSEADDR.
89296465Sdelphij     */
90296465Sdelphij    int bind_mode;
91296465Sdelphij    BIO *bio_chain;
92296465Sdelphij} BIO_ACCEPT;
9355714Skris
9468651Skrisstatic int acpt_write(BIO *h, const char *buf, int num);
9568651Skrisstatic int acpt_read(BIO *h, char *buf, int size);
9668651Skrisstatic int acpt_puts(BIO *h, const char *str);
9768651Skrisstatic long acpt_ctrl(BIO *h, int cmd, long arg1, void *arg2);
9855714Skrisstatic int acpt_new(BIO *h);
9955714Skrisstatic int acpt_free(BIO *data);
10055714Skrisstatic int acpt_state(BIO *b, BIO_ACCEPT *c);
10155714Skrisstatic void acpt_close_socket(BIO *data);
102296465SdelphijBIO_ACCEPT *BIO_ACCEPT_new(void);
10355714Skrisvoid BIO_ACCEPT_free(BIO_ACCEPT *a);
10455714Skris
105296465Sdelphij# define ACPT_S_BEFORE                   1
106296465Sdelphij# define ACPT_S_GET_ACCEPT_SOCKET        2
107296465Sdelphij# define ACPT_S_OK                       3
10855714Skris
109296465Sdelphijstatic BIO_METHOD methods_acceptp = {
110296465Sdelphij    BIO_TYPE_ACCEPT,
111296465Sdelphij    "socket accept",
112296465Sdelphij    acpt_write,
113296465Sdelphij    acpt_read,
114296465Sdelphij    acpt_puts,
115296465Sdelphij    NULL,                       /* connect_gets, */
116296465Sdelphij    acpt_ctrl,
117296465Sdelphij    acpt_new,
118296465Sdelphij    acpt_free,
119296465Sdelphij    NULL,
120296465Sdelphij};
12155714Skris
12255714SkrisBIO_METHOD *BIO_s_accept(void)
123296465Sdelphij{
124296465Sdelphij    return (&methods_acceptp);
125296465Sdelphij}
12655714Skris
12755714Skrisstatic int acpt_new(BIO *bi)
128296465Sdelphij{
129296465Sdelphij    BIO_ACCEPT *ba;
13055714Skris
131296465Sdelphij    bi->init = 0;
132296465Sdelphij    bi->num = INVALID_SOCKET;
133296465Sdelphij    bi->flags = 0;
134296465Sdelphij    if ((ba = BIO_ACCEPT_new()) == NULL)
135296465Sdelphij        return (0);
136296465Sdelphij    bi->ptr = (char *)ba;
137296465Sdelphij    ba->state = ACPT_S_BEFORE;
138296465Sdelphij    bi->shutdown = 1;
139296465Sdelphij    return (1);
140296465Sdelphij}
14155714Skris
14255714SkrisBIO_ACCEPT *BIO_ACCEPT_new(void)
143296465Sdelphij{
144296465Sdelphij    BIO_ACCEPT *ret;
14555714Skris
146296465Sdelphij    if ((ret = (BIO_ACCEPT *)OPENSSL_malloc(sizeof(BIO_ACCEPT))) == NULL)
147296465Sdelphij        return (NULL);
14855714Skris
149296465Sdelphij    memset(ret, 0, sizeof(BIO_ACCEPT));
150296465Sdelphij    ret->accept_sock = INVALID_SOCKET;
151296465Sdelphij    ret->bind_mode = BIO_BIND_NORMAL;
152296465Sdelphij    return (ret);
153296465Sdelphij}
15455714Skris
15555714Skrisvoid BIO_ACCEPT_free(BIO_ACCEPT *a)
156296465Sdelphij{
157296465Sdelphij    if (a == NULL)
158296465Sdelphij        return;
15955714Skris
160296465Sdelphij    if (a->param_addr != NULL)
161296465Sdelphij        OPENSSL_free(a->param_addr);
162296465Sdelphij    if (a->addr != NULL)
163296465Sdelphij        OPENSSL_free(a->addr);
164296465Sdelphij    if (a->bio_chain != NULL)
165296465Sdelphij        BIO_free(a->bio_chain);
166296465Sdelphij    OPENSSL_free(a);
167296465Sdelphij}
16855714Skris
16955714Skrisstatic void acpt_close_socket(BIO *bio)
170296465Sdelphij{
171296465Sdelphij    BIO_ACCEPT *c;
17255714Skris
173296465Sdelphij    c = (BIO_ACCEPT *)bio->ptr;
174296465Sdelphij    if (c->accept_sock != INVALID_SOCKET) {
175296465Sdelphij        shutdown(c->accept_sock, 2);
176296465Sdelphij        closesocket(c->accept_sock);
177296465Sdelphij        c->accept_sock = INVALID_SOCKET;
178296465Sdelphij        bio->num = INVALID_SOCKET;
179296465Sdelphij    }
180296465Sdelphij}
18155714Skris
18255714Skrisstatic int acpt_free(BIO *a)
183296465Sdelphij{
184296465Sdelphij    BIO_ACCEPT *data;
18555714Skris
186296465Sdelphij    if (a == NULL)
187296465Sdelphij        return (0);
188296465Sdelphij    data = (BIO_ACCEPT *)a->ptr;
189296465Sdelphij
190296465Sdelphij    if (a->shutdown) {
191296465Sdelphij        acpt_close_socket(a);
192296465Sdelphij        BIO_ACCEPT_free(data);
193296465Sdelphij        a->ptr = NULL;
194296465Sdelphij        a->flags = 0;
195296465Sdelphij        a->init = 0;
196296465Sdelphij    }
197296465Sdelphij    return (1);
198296465Sdelphij}
199296465Sdelphij
20055714Skrisstatic int acpt_state(BIO *b, BIO_ACCEPT *c)
201296465Sdelphij{
202296465Sdelphij    BIO *bio = NULL, *dbio;
203296465Sdelphij    int s = -1;
204296465Sdelphij    int i;
20555714Skris
206296465Sdelphij again:
207296465Sdelphij    switch (c->state) {
208296465Sdelphij    case ACPT_S_BEFORE:
209296465Sdelphij        if (c->param_addr == NULL) {
210296465Sdelphij            BIOerr(BIO_F_ACPT_STATE, BIO_R_NO_ACCEPT_PORT_SPECIFIED);
211296465Sdelphij            return (-1);
212296465Sdelphij        }
213296465Sdelphij        s = BIO_get_accept_socket(c->param_addr, c->bind_mode);
214296465Sdelphij        if (s == INVALID_SOCKET)
215296465Sdelphij            return (-1);
21655714Skris
217296465Sdelphij        if (c->accept_nbio) {
218296465Sdelphij            if (!BIO_socket_nbio(s, 1)) {
219296465Sdelphij                closesocket(s);
220296465Sdelphij                BIOerr(BIO_F_ACPT_STATE,
221296465Sdelphij                       BIO_R_ERROR_SETTING_NBIO_ON_ACCEPT_SOCKET);
222296465Sdelphij                return (-1);
223296465Sdelphij            }
224296465Sdelphij        }
225296465Sdelphij        c->accept_sock = s;
226296465Sdelphij        b->num = s;
227296465Sdelphij        c->state = ACPT_S_GET_ACCEPT_SOCKET;
228296465Sdelphij        return (1);
229296465Sdelphij        /* break; */
230296465Sdelphij    case ACPT_S_GET_ACCEPT_SOCKET:
231296465Sdelphij        if (b->next_bio != NULL) {
232296465Sdelphij            c->state = ACPT_S_OK;
233296465Sdelphij            goto again;
234296465Sdelphij        }
235296465Sdelphij        BIO_clear_retry_flags(b);
236296465Sdelphij        b->retry_reason = 0;
237296465Sdelphij        i = BIO_accept(c->accept_sock, &(c->addr));
238109998Smarkm
239296465Sdelphij        /* -2 return means we should retry */
240296465Sdelphij        if (i == -2) {
241296465Sdelphij            BIO_set_retry_special(b);
242296465Sdelphij            b->retry_reason = BIO_RR_ACCEPT;
243296465Sdelphij            return -1;
244296465Sdelphij        }
245109998Smarkm
246296465Sdelphij        if (i < 0)
247296465Sdelphij            return (i);
248109998Smarkm
249296465Sdelphij        bio = BIO_new_socket(i, BIO_CLOSE);
250296465Sdelphij        if (bio == NULL)
251296465Sdelphij            goto err;
25255714Skris
253296465Sdelphij        BIO_set_callback(bio, BIO_get_callback(b));
254296465Sdelphij        BIO_set_callback_arg(bio, BIO_get_callback_arg(b));
25555714Skris
256296465Sdelphij        if (c->nbio) {
257296465Sdelphij            if (!BIO_socket_nbio(i, 1)) {
258296465Sdelphij                BIOerr(BIO_F_ACPT_STATE,
259296465Sdelphij                       BIO_R_ERROR_SETTING_NBIO_ON_ACCEPTED_SOCKET);
260296465Sdelphij                goto err;
261296465Sdelphij            }
262296465Sdelphij        }
26355714Skris
264296465Sdelphij        /*
265296465Sdelphij         * If the accept BIO has an bio_chain, we dup it and put the new
266296465Sdelphij         * socket at the end.
267296465Sdelphij         */
268296465Sdelphij        if (c->bio_chain != NULL) {
269296465Sdelphij            if ((dbio = BIO_dup_chain(c->bio_chain)) == NULL)
270296465Sdelphij                goto err;
271296465Sdelphij            if (!BIO_push(dbio, bio))
272296465Sdelphij                goto err;
273296465Sdelphij            bio = dbio;
274296465Sdelphij        }
275296465Sdelphij        if (BIO_push(b, bio) == NULL)
276296465Sdelphij            goto err;
27755714Skris
278296465Sdelphij        c->state = ACPT_S_OK;
279296465Sdelphij        return (1);
280296465Sdelphij err:
281296465Sdelphij        if (bio != NULL)
282296465Sdelphij            BIO_free(bio);
283296465Sdelphij        else if (s >= 0)
284296465Sdelphij            closesocket(s);
285296465Sdelphij        return (0);
286296465Sdelphij        /* break; */
287296465Sdelphij    case ACPT_S_OK:
288296465Sdelphij        if (b->next_bio == NULL) {
289296465Sdelphij            c->state = ACPT_S_GET_ACCEPT_SOCKET;
290296465Sdelphij            goto again;
291296465Sdelphij        }
292296465Sdelphij        return (1);
293296465Sdelphij        /* break; */
294296465Sdelphij    default:
295296465Sdelphij        return (0);
296296465Sdelphij        /* break; */
297296465Sdelphij    }
29855714Skris
299296465Sdelphij}
30055714Skris
30155714Skrisstatic int acpt_read(BIO *b, char *out, int outl)
302296465Sdelphij{
303296465Sdelphij    int ret = 0;
304296465Sdelphij    BIO_ACCEPT *data;
30555714Skris
306296465Sdelphij    BIO_clear_retry_flags(b);
307296465Sdelphij    data = (BIO_ACCEPT *)b->ptr;
30855714Skris
309296465Sdelphij    while (b->next_bio == NULL) {
310296465Sdelphij        ret = acpt_state(b, data);
311296465Sdelphij        if (ret <= 0)
312296465Sdelphij            return (ret);
313296465Sdelphij    }
31455714Skris
315296465Sdelphij    ret = BIO_read(b->next_bio, out, outl);
316296465Sdelphij    BIO_copy_next_retry(b);
317296465Sdelphij    return (ret);
318296465Sdelphij}
31955714Skris
32068651Skrisstatic int acpt_write(BIO *b, const char *in, int inl)
321296465Sdelphij{
322296465Sdelphij    int ret;
323296465Sdelphij    BIO_ACCEPT *data;
32455714Skris
325296465Sdelphij    BIO_clear_retry_flags(b);
326296465Sdelphij    data = (BIO_ACCEPT *)b->ptr;
32755714Skris
328296465Sdelphij    while (b->next_bio == NULL) {
329296465Sdelphij        ret = acpt_state(b, data);
330296465Sdelphij        if (ret <= 0)
331296465Sdelphij            return (ret);
332296465Sdelphij    }
33355714Skris
334296465Sdelphij    ret = BIO_write(b->next_bio, in, inl);
335296465Sdelphij    BIO_copy_next_retry(b);
336296465Sdelphij    return (ret);
337296465Sdelphij}
33855714Skris
33968651Skrisstatic long acpt_ctrl(BIO *b, int cmd, long num, void *ptr)
340296465Sdelphij{
341296465Sdelphij    int *ip;
342296465Sdelphij    long ret = 1;
343296465Sdelphij    BIO_ACCEPT *data;
344296465Sdelphij    char **pp;
34555714Skris
346296465Sdelphij    data = (BIO_ACCEPT *)b->ptr;
34755714Skris
348296465Sdelphij    switch (cmd) {
349296465Sdelphij    case BIO_CTRL_RESET:
350296465Sdelphij        ret = 0;
351296465Sdelphij        data->state = ACPT_S_BEFORE;
352296465Sdelphij        acpt_close_socket(b);
353296465Sdelphij        b->flags = 0;
354296465Sdelphij        break;
355296465Sdelphij    case BIO_C_DO_STATE_MACHINE:
356296465Sdelphij        /* use this one to start the connection */
357296465Sdelphij        ret = (long)acpt_state(b, data);
358296465Sdelphij        break;
359296465Sdelphij    case BIO_C_SET_ACCEPT:
360296465Sdelphij        if (ptr != NULL) {
361296465Sdelphij            if (num == 0) {
362296465Sdelphij                b->init = 1;
363296465Sdelphij                if (data->param_addr != NULL)
364296465Sdelphij                    OPENSSL_free(data->param_addr);
365296465Sdelphij                data->param_addr = BUF_strdup(ptr);
366296465Sdelphij            } else if (num == 1) {
367296465Sdelphij                data->accept_nbio = (ptr != NULL);
368296465Sdelphij            } else if (num == 2) {
369296465Sdelphij                if (data->bio_chain != NULL)
370296465Sdelphij                    BIO_free(data->bio_chain);
371296465Sdelphij                data->bio_chain = (BIO *)ptr;
372296465Sdelphij            }
373296465Sdelphij        }
374296465Sdelphij        break;
375296465Sdelphij    case BIO_C_SET_NBIO:
376296465Sdelphij        data->nbio = (int)num;
377296465Sdelphij        break;
378296465Sdelphij    case BIO_C_SET_FD:
379296465Sdelphij        b->init = 1;
380296465Sdelphij        b->num = *((int *)ptr);
381296465Sdelphij        data->accept_sock = b->num;
382296465Sdelphij        data->state = ACPT_S_GET_ACCEPT_SOCKET;
383296465Sdelphij        b->shutdown = (int)num;
384296465Sdelphij        b->init = 1;
385296465Sdelphij        break;
386296465Sdelphij    case BIO_C_GET_FD:
387296465Sdelphij        if (b->init) {
388296465Sdelphij            ip = (int *)ptr;
389296465Sdelphij            if (ip != NULL)
390296465Sdelphij                *ip = data->accept_sock;
391296465Sdelphij            ret = data->accept_sock;
392296465Sdelphij        } else
393296465Sdelphij            ret = -1;
394296465Sdelphij        break;
395296465Sdelphij    case BIO_C_GET_ACCEPT:
396296465Sdelphij        if (b->init) {
397296465Sdelphij            if (ptr != NULL) {
398296465Sdelphij                pp = (char **)ptr;
399296465Sdelphij                *pp = data->param_addr;
400296465Sdelphij            } else
401296465Sdelphij                ret = -1;
402296465Sdelphij        } else
403296465Sdelphij            ret = -1;
404296465Sdelphij        break;
405296465Sdelphij    case BIO_CTRL_GET_CLOSE:
406296465Sdelphij        ret = b->shutdown;
407296465Sdelphij        break;
408296465Sdelphij    case BIO_CTRL_SET_CLOSE:
409296465Sdelphij        b->shutdown = (int)num;
410296465Sdelphij        break;
411296465Sdelphij    case BIO_CTRL_PENDING:
412296465Sdelphij    case BIO_CTRL_WPENDING:
413296465Sdelphij        ret = 0;
414296465Sdelphij        break;
415296465Sdelphij    case BIO_CTRL_FLUSH:
416296465Sdelphij        break;
417296465Sdelphij    case BIO_C_SET_BIND_MODE:
418296465Sdelphij        data->bind_mode = (int)num;
419296465Sdelphij        break;
420296465Sdelphij    case BIO_C_GET_BIND_MODE:
421296465Sdelphij        ret = (long)data->bind_mode;
422296465Sdelphij        break;
423296465Sdelphij    case BIO_CTRL_DUP:
424296465Sdelphij/*-     dbio=(BIO *)ptr;
425296465Sdelphij        if (data->param_port) EAY EAY
426296465Sdelphij                BIO_set_port(dbio,data->param_port);
427296465Sdelphij        if (data->param_hostname)
428296465Sdelphij                BIO_set_hostname(dbio,data->param_hostname);
429296465Sdelphij        BIO_set_nbio(dbio,data->nbio); */
430296465Sdelphij        break;
43155714Skris
432296465Sdelphij    default:
433296465Sdelphij        ret = 0;
434296465Sdelphij        break;
435296465Sdelphij    }
436296465Sdelphij    return (ret);
437296465Sdelphij}
43855714Skris
43968651Skrisstatic int acpt_puts(BIO *bp, const char *str)
440296465Sdelphij{
441296465Sdelphij    int n, ret;
44255714Skris
443296465Sdelphij    n = strlen(str);
444296465Sdelphij    ret = acpt_write(bp, str, n);
445296465Sdelphij    return (ret);
446296465Sdelphij}
44755714Skris
44855714SkrisBIO *BIO_new_accept(char *str)
449296465Sdelphij{
450296465Sdelphij    BIO *ret;
45155714Skris
452296465Sdelphij    ret = BIO_new(BIO_s_accept());
453296465Sdelphij    if (ret == NULL)
454296465Sdelphij        return (NULL);
455296465Sdelphij    if (BIO_set_accept_port(ret, str))
456296465Sdelphij        return (ret);
457296465Sdelphij    else {
458296465Sdelphij        BIO_free(ret);
459296465Sdelphij        return (NULL);
460296465Sdelphij    }
461296465Sdelphij}
46255714Skris
46355714Skris#endif
464