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.
8280297Sjkim *
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).
15280297Sjkim *
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.
22280297Sjkim *
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 :-).
37280297Sjkim * 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)"
40280297Sjkim *
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.
52280297Sjkim *
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
67280297Sjkim# ifdef OPENSSL_SYS_WIN16
68280297Sjkim#  define SOCKET_PROTOCOL 0     /* more microsoft stupidity */
69280297Sjkim# else
70280297Sjkim#  define SOCKET_PROTOCOL IPPROTO_TCP
71280297Sjkim# endif
7255714Skris
73280297Sjkim# 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 */
75280297Sjkim#  undef FIONBIO
76280297Sjkim# endif
7755714Skris
78280297Sjkimtypedef struct bio_accept_st {
79280297Sjkim    int state;
80280297Sjkim    char *param_addr;
81280297Sjkim    int accept_sock;
82280297Sjkim    int accept_nbio;
83280297Sjkim    char *addr;
84280297Sjkim    int nbio;
85280297Sjkim    /*
86280297Sjkim     * If 0, it means normal, if 1, do a connect on bind failure, and if
87280297Sjkim     * there is no-one listening, bind with SO_REUSEADDR. If 2, always use
88280297Sjkim     * SO_REUSEADDR.
89280297Sjkim     */
90280297Sjkim    int bind_mode;
91280297Sjkim    BIO *bio_chain;
92280297Sjkim} 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);
102280297Sjkimstatic BIO_ACCEPT *BIO_ACCEPT_new(void);
103238405Sjkimstatic void BIO_ACCEPT_free(BIO_ACCEPT *a);
10455714Skris
105280297Sjkim# define ACPT_S_BEFORE                   1
106280297Sjkim# define ACPT_S_GET_ACCEPT_SOCKET        2
107280297Sjkim# define ACPT_S_OK                       3
10855714Skris
109280297Sjkimstatic BIO_METHOD methods_acceptp = {
110280297Sjkim    BIO_TYPE_ACCEPT,
111280297Sjkim    "socket accept",
112280297Sjkim    acpt_write,
113280297Sjkim    acpt_read,
114280297Sjkim    acpt_puts,
115280297Sjkim    NULL,                       /* connect_gets, */
116280297Sjkim    acpt_ctrl,
117280297Sjkim    acpt_new,
118280297Sjkim    acpt_free,
119280297Sjkim    NULL,
120280297Sjkim};
12155714Skris
12255714SkrisBIO_METHOD *BIO_s_accept(void)
123280297Sjkim{
124280297Sjkim    return (&methods_acceptp);
125280297Sjkim}
12655714Skris
12755714Skrisstatic int acpt_new(BIO *bi)
128280297Sjkim{
129280297Sjkim    BIO_ACCEPT *ba;
13055714Skris
131280297Sjkim    bi->init = 0;
132280297Sjkim    bi->num = INVALID_SOCKET;
133280297Sjkim    bi->flags = 0;
134280297Sjkim    if ((ba = BIO_ACCEPT_new()) == NULL)
135280297Sjkim        return (0);
136280297Sjkim    bi->ptr = (char *)ba;
137280297Sjkim    ba->state = ACPT_S_BEFORE;
138280297Sjkim    bi->shutdown = 1;
139280297Sjkim    return (1);
140280297Sjkim}
14155714Skris
142238405Sjkimstatic BIO_ACCEPT *BIO_ACCEPT_new(void)
143280297Sjkim{
144280297Sjkim    BIO_ACCEPT *ret;
14555714Skris
146280297Sjkim    if ((ret = (BIO_ACCEPT *)OPENSSL_malloc(sizeof(BIO_ACCEPT))) == NULL)
147280297Sjkim        return (NULL);
14855714Skris
149280297Sjkim    memset(ret, 0, sizeof(BIO_ACCEPT));
150280297Sjkim    ret->accept_sock = INVALID_SOCKET;
151280297Sjkim    ret->bind_mode = BIO_BIND_NORMAL;
152280297Sjkim    return (ret);
153280297Sjkim}
15455714Skris
155238405Sjkimstatic void BIO_ACCEPT_free(BIO_ACCEPT *a)
156280297Sjkim{
157280297Sjkim    if (a == NULL)
158280297Sjkim        return;
15955714Skris
160280297Sjkim    if (a->param_addr != NULL)
161280297Sjkim        OPENSSL_free(a->param_addr);
162280297Sjkim    if (a->addr != NULL)
163280297Sjkim        OPENSSL_free(a->addr);
164280297Sjkim    if (a->bio_chain != NULL)
165280297Sjkim        BIO_free(a->bio_chain);
166280297Sjkim    OPENSSL_free(a);
167280297Sjkim}
16855714Skris
16955714Skrisstatic void acpt_close_socket(BIO *bio)
170280297Sjkim{
171280297Sjkim    BIO_ACCEPT *c;
17255714Skris
173280297Sjkim    c = (BIO_ACCEPT *)bio->ptr;
174280297Sjkim    if (c->accept_sock != INVALID_SOCKET) {
175280297Sjkim        shutdown(c->accept_sock, 2);
176280297Sjkim        closesocket(c->accept_sock);
177280297Sjkim        c->accept_sock = INVALID_SOCKET;
178280297Sjkim        bio->num = INVALID_SOCKET;
179280297Sjkim    }
180280297Sjkim}
18155714Skris
18255714Skrisstatic int acpt_free(BIO *a)
183280297Sjkim{
184280297Sjkim    BIO_ACCEPT *data;
18555714Skris
186280297Sjkim    if (a == NULL)
187280297Sjkim        return (0);
188280297Sjkim    data = (BIO_ACCEPT *)a->ptr;
189280297Sjkim
190280297Sjkim    if (a->shutdown) {
191280297Sjkim        acpt_close_socket(a);
192280297Sjkim        BIO_ACCEPT_free(data);
193280297Sjkim        a->ptr = NULL;
194280297Sjkim        a->flags = 0;
195280297Sjkim        a->init = 0;
196280297Sjkim    }
197280297Sjkim    return (1);
198280297Sjkim}
199280297Sjkim
20055714Skrisstatic int acpt_state(BIO *b, BIO_ACCEPT *c)
201280297Sjkim{
202280297Sjkim    BIO *bio = NULL, *dbio;
203280297Sjkim    int s = -1;
204280297Sjkim    int i;
20555714Skris
206280297Sjkim again:
207280297Sjkim    switch (c->state) {
208280297Sjkim    case ACPT_S_BEFORE:
209280297Sjkim        if (c->param_addr == NULL) {
210280297Sjkim            BIOerr(BIO_F_ACPT_STATE, BIO_R_NO_ACCEPT_PORT_SPECIFIED);
211280297Sjkim            return (-1);
212280297Sjkim        }
213280297Sjkim        s = BIO_get_accept_socket(c->param_addr, c->bind_mode);
214280297Sjkim        if (s == INVALID_SOCKET)
215280297Sjkim            return (-1);
21655714Skris
217280297Sjkim        if (c->accept_nbio) {
218280297Sjkim            if (!BIO_socket_nbio(s, 1)) {
219280297Sjkim                closesocket(s);
220280297Sjkim                BIOerr(BIO_F_ACPT_STATE,
221280297Sjkim                       BIO_R_ERROR_SETTING_NBIO_ON_ACCEPT_SOCKET);
222280297Sjkim                return (-1);
223280297Sjkim            }
224280297Sjkim        }
225280297Sjkim        c->accept_sock = s;
226280297Sjkim        b->num = s;
227280297Sjkim        c->state = ACPT_S_GET_ACCEPT_SOCKET;
228280297Sjkim        return (1);
229280297Sjkim        /* break; */
230280297Sjkim    case ACPT_S_GET_ACCEPT_SOCKET:
231280297Sjkim        if (b->next_bio != NULL) {
232280297Sjkim            c->state = ACPT_S_OK;
233280297Sjkim            goto again;
234280297Sjkim        }
235280297Sjkim        BIO_clear_retry_flags(b);
236280297Sjkim        b->retry_reason = 0;
237280297Sjkim        i = BIO_accept(c->accept_sock, &(c->addr));
238109998Smarkm
239280297Sjkim        /* -2 return means we should retry */
240280297Sjkim        if (i == -2) {
241280297Sjkim            BIO_set_retry_special(b);
242280297Sjkim            b->retry_reason = BIO_RR_ACCEPT;
243280297Sjkim            return -1;
244280297Sjkim        }
245109998Smarkm
246280297Sjkim        if (i < 0)
247280297Sjkim            return (i);
248109998Smarkm
249280297Sjkim        bio = BIO_new_socket(i, BIO_CLOSE);
250280297Sjkim        if (bio == NULL)
251280297Sjkim            goto err;
25255714Skris
253280297Sjkim        BIO_set_callback(bio, BIO_get_callback(b));
254280297Sjkim        BIO_set_callback_arg(bio, BIO_get_callback_arg(b));
25555714Skris
256280297Sjkim        if (c->nbio) {
257280297Sjkim            if (!BIO_socket_nbio(i, 1)) {
258280297Sjkim                BIOerr(BIO_F_ACPT_STATE,
259280297Sjkim                       BIO_R_ERROR_SETTING_NBIO_ON_ACCEPTED_SOCKET);
260280297Sjkim                goto err;
261280297Sjkim            }
262280297Sjkim        }
26355714Skris
264280297Sjkim        /*
265280297Sjkim         * If the accept BIO has an bio_chain, we dup it and put the new
266280297Sjkim         * socket at the end.
267280297Sjkim         */
268280297Sjkim        if (c->bio_chain != NULL) {
269280297Sjkim            if ((dbio = BIO_dup_chain(c->bio_chain)) == NULL)
270280297Sjkim                goto err;
271280297Sjkim            if (!BIO_push(dbio, bio))
272280297Sjkim                goto err;
273280297Sjkim            bio = dbio;
274280297Sjkim        }
275280297Sjkim        if (BIO_push(b, bio) == NULL)
276280297Sjkim            goto err;
27755714Skris
278280297Sjkim        c->state = ACPT_S_OK;
279280297Sjkim        return (1);
280280297Sjkim err:
281280297Sjkim        if (bio != NULL)
282280297Sjkim            BIO_free(bio);
283280297Sjkim        else if (s >= 0)
284280297Sjkim            closesocket(s);
285280297Sjkim        return (0);
286280297Sjkim        /* break; */
287280297Sjkim    case ACPT_S_OK:
288280297Sjkim        if (b->next_bio == NULL) {
289280297Sjkim            c->state = ACPT_S_GET_ACCEPT_SOCKET;
290280297Sjkim            goto again;
291280297Sjkim        }
292280297Sjkim        return (1);
293280297Sjkim        /* break; */
294280297Sjkim    default:
295280297Sjkim        return (0);
296280297Sjkim        /* break; */
297280297Sjkim    }
29855714Skris
299280297Sjkim}
30055714Skris
30155714Skrisstatic int acpt_read(BIO *b, char *out, int outl)
302280297Sjkim{
303280297Sjkim    int ret = 0;
304280297Sjkim    BIO_ACCEPT *data;
30555714Skris
306280297Sjkim    BIO_clear_retry_flags(b);
307280297Sjkim    data = (BIO_ACCEPT *)b->ptr;
30855714Skris
309280297Sjkim    while (b->next_bio == NULL) {
310280297Sjkim        ret = acpt_state(b, data);
311280297Sjkim        if (ret <= 0)
312280297Sjkim            return (ret);
313280297Sjkim    }
31455714Skris
315280297Sjkim    ret = BIO_read(b->next_bio, out, outl);
316280297Sjkim    BIO_copy_next_retry(b);
317280297Sjkim    return (ret);
318280297Sjkim}
31955714Skris
32068651Skrisstatic int acpt_write(BIO *b, const char *in, int inl)
321280297Sjkim{
322280297Sjkim    int ret;
323280297Sjkim    BIO_ACCEPT *data;
32455714Skris
325280297Sjkim    BIO_clear_retry_flags(b);
326280297Sjkim    data = (BIO_ACCEPT *)b->ptr;
32755714Skris
328280297Sjkim    while (b->next_bio == NULL) {
329280297Sjkim        ret = acpt_state(b, data);
330280297Sjkim        if (ret <= 0)
331280297Sjkim            return (ret);
332280297Sjkim    }
33355714Skris
334280297Sjkim    ret = BIO_write(b->next_bio, in, inl);
335280297Sjkim    BIO_copy_next_retry(b);
336280297Sjkim    return (ret);
337280297Sjkim}
33855714Skris
33968651Skrisstatic long acpt_ctrl(BIO *b, int cmd, long num, void *ptr)
340280297Sjkim{
341280297Sjkim    int *ip;
342280297Sjkim    long ret = 1;
343280297Sjkim    BIO_ACCEPT *data;
344280297Sjkim    char **pp;
34555714Skris
346280297Sjkim    data = (BIO_ACCEPT *)b->ptr;
34755714Skris
348280297Sjkim    switch (cmd) {
349280297Sjkim    case BIO_CTRL_RESET:
350280297Sjkim        ret = 0;
351280297Sjkim        data->state = ACPT_S_BEFORE;
352280297Sjkim        acpt_close_socket(b);
353280297Sjkim        b->flags = 0;
354280297Sjkim        break;
355280297Sjkim    case BIO_C_DO_STATE_MACHINE:
356280297Sjkim        /* use this one to start the connection */
357280297Sjkim        ret = (long)acpt_state(b, data);
358280297Sjkim        break;
359280297Sjkim    case BIO_C_SET_ACCEPT:
360280297Sjkim        if (ptr != NULL) {
361280297Sjkim            if (num == 0) {
362280297Sjkim                b->init = 1;
363280297Sjkim                if (data->param_addr != NULL)
364280297Sjkim                    OPENSSL_free(data->param_addr);
365280297Sjkim                data->param_addr = BUF_strdup(ptr);
366280297Sjkim            } else if (num == 1) {
367280297Sjkim                data->accept_nbio = (ptr != NULL);
368280297Sjkim            } else if (num == 2) {
369280297Sjkim                if (data->bio_chain != NULL)
370280297Sjkim                    BIO_free(data->bio_chain);
371280297Sjkim                data->bio_chain = (BIO *)ptr;
372280297Sjkim            }
373280297Sjkim        }
374280297Sjkim        break;
375280297Sjkim    case BIO_C_SET_NBIO:
376280297Sjkim        data->nbio = (int)num;
377280297Sjkim        break;
378280297Sjkim    case BIO_C_SET_FD:
379280297Sjkim        b->init = 1;
380280297Sjkim        b->num = *((int *)ptr);
381280297Sjkim        data->accept_sock = b->num;
382280297Sjkim        data->state = ACPT_S_GET_ACCEPT_SOCKET;
383280297Sjkim        b->shutdown = (int)num;
384280297Sjkim        b->init = 1;
385280297Sjkim        break;
386280297Sjkim    case BIO_C_GET_FD:
387280297Sjkim        if (b->init) {
388280297Sjkim            ip = (int *)ptr;
389280297Sjkim            if (ip != NULL)
390280297Sjkim                *ip = data->accept_sock;
391280297Sjkim            ret = data->accept_sock;
392280297Sjkim        } else
393280297Sjkim            ret = -1;
394280297Sjkim        break;
395280297Sjkim    case BIO_C_GET_ACCEPT:
396280297Sjkim        if (b->init) {
397280297Sjkim            if (ptr != NULL) {
398280297Sjkim                pp = (char **)ptr;
399280297Sjkim                *pp = data->param_addr;
400280297Sjkim            } else
401280297Sjkim                ret = -1;
402280297Sjkim        } else
403280297Sjkim            ret = -1;
404280297Sjkim        break;
405280297Sjkim    case BIO_CTRL_GET_CLOSE:
406280297Sjkim        ret = b->shutdown;
407280297Sjkim        break;
408280297Sjkim    case BIO_CTRL_SET_CLOSE:
409280297Sjkim        b->shutdown = (int)num;
410280297Sjkim        break;
411280297Sjkim    case BIO_CTRL_PENDING:
412280297Sjkim    case BIO_CTRL_WPENDING:
413280297Sjkim        ret = 0;
414280297Sjkim        break;
415280297Sjkim    case BIO_CTRL_FLUSH:
416280297Sjkim        break;
417280297Sjkim    case BIO_C_SET_BIND_MODE:
418280297Sjkim        data->bind_mode = (int)num;
419280297Sjkim        break;
420280297Sjkim    case BIO_C_GET_BIND_MODE:
421280297Sjkim        ret = (long)data->bind_mode;
422280297Sjkim        break;
423280297Sjkim    case BIO_CTRL_DUP:
424280297Sjkim/*-     dbio=(BIO *)ptr;
425280297Sjkim        if (data->param_port) EAY EAY
426280297Sjkim                BIO_set_port(dbio,data->param_port);
427280297Sjkim        if (data->param_hostname)
428280297Sjkim                BIO_set_hostname(dbio,data->param_hostname);
429280297Sjkim        BIO_set_nbio(dbio,data->nbio); */
430280297Sjkim        break;
43155714Skris
432280297Sjkim    default:
433280297Sjkim        ret = 0;
434280297Sjkim        break;
435280297Sjkim    }
436280297Sjkim    return (ret);
437280297Sjkim}
43855714Skris
43968651Skrisstatic int acpt_puts(BIO *bp, const char *str)
440280297Sjkim{
441280297Sjkim    int n, ret;
44255714Skris
443280297Sjkim    n = strlen(str);
444280297Sjkim    ret = acpt_write(bp, str, n);
445280297Sjkim    return (ret);
446280297Sjkim}
44755714Skris
448290207SjkimBIO *BIO_new_accept(const char *str)
449280297Sjkim{
450280297Sjkim    BIO *ret;
45155714Skris
452280297Sjkim    ret = BIO_new(BIO_s_accept());
453280297Sjkim    if (ret == NULL)
454280297Sjkim        return (NULL);
455280297Sjkim    if (BIO_set_accept_port(ret, str))
456280297Sjkim        return (ret);
457280297Sjkim    else {
458280297Sjkim        BIO_free(ret);
459280297Sjkim        return (NULL);
460280297Sjkim    }
461280297Sjkim}
46255714Skris
46355714Skris#endif
464