155714Skris/* crypto/bio/b_sock.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 <stdlib.h>
6155714Skris#include <errno.h>
6255714Skris#define USE_SOCKETS
6355714Skris#include "cryptlib.h"
6455714Skris#include <openssl/bio.h>
65160814Ssimon#if defined(OPENSSL_SYS_NETWARE) && defined(NETWARE_BSDSOCK)
66296465Sdelphij# include <netdb.h>
67296465Sdelphij# if defined(NETWARE_CLIB)
68296465Sdelphij#  include <sys/ioctl.h>
69194206SsimonNETDB_DEFINE_CONTEXT
70296465Sdelphij# endif
71160814Ssimon#endif
72160814Ssimon#ifndef OPENSSL_NO_SOCK
73296465Sdelphij# ifdef OPENSSL_SYS_WIN16
74296465Sdelphij#  define SOCKET_PROTOCOL 0     /* more microsoft stupidity */
75296465Sdelphij# else
76296465Sdelphij#  define SOCKET_PROTOCOL IPPROTO_TCP
77296465Sdelphij# endif
78296465Sdelphij# ifdef SO_MAXCONN
79296465Sdelphij#  define MAX_LISTEN  SO_MAXCONN
80296465Sdelphij# elif defined(SOMAXCONN)
81296465Sdelphij#  define MAX_LISTEN  SOMAXCONN
82296465Sdelphij# else
83296465Sdelphij#  define MAX_LISTEN  32
84296465Sdelphij# endif
85296465Sdelphij# if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK))
86296465Sdelphijstatic int wsa_init_done = 0;
87296465Sdelphij# endif
88160814Ssimon
89296465Sdelphij# if 0
90296465Sdelphijstatic unsigned long BIO_ghbn_hits = 0L;
91296465Sdelphijstatic unsigned long BIO_ghbn_miss = 0L;
9255714Skris
93296465Sdelphij#  define GHBN_NUM        4
94296465Sdelphijstatic struct ghbn_cache_st {
95296465Sdelphij    char name[129];
96296465Sdelphij    struct hostent *ent;
97296465Sdelphij    unsigned long order;
98296465Sdelphij} ghbn_cache[GHBN_NUM];
99296465Sdelphij# endif
10055714Skris
101296465Sdelphijstatic int get_ip(const char *str, unsigned char *ip);
102296465Sdelphij# if 0
10355714Skrisstatic void ghbn_free(struct hostent *a);
10455714Skrisstatic struct hostent *ghbn_dup(struct hostent *a);
105296465Sdelphij# endif
10655714Skrisint BIO_get_host_ip(const char *str, unsigned char *ip)
107296465Sdelphij{
108296465Sdelphij    int i;
109296465Sdelphij    int err = 1;
110296465Sdelphij    int locked = 0;
111296465Sdelphij    struct hostent *he;
11255714Skris
113296465Sdelphij    i = get_ip(str, ip);
114296465Sdelphij    if (i < 0) {
115296465Sdelphij        BIOerr(BIO_F_BIO_GET_HOST_IP, BIO_R_INVALID_IP_ADDRESS);
116296465Sdelphij        goto err;
117296465Sdelphij    }
11855714Skris
119296465Sdelphij    /*
120296465Sdelphij     * At this point, we have something that is most probably correct in some
121296465Sdelphij     * way, so let's init the socket.
122296465Sdelphij     */
123296465Sdelphij    if (BIO_sock_init() != 1)
124296465Sdelphij        return 0;               /* don't generate another error code here */
12555714Skris
126296465Sdelphij    /*
127296465Sdelphij     * If the string actually contained an IP address, we need not do
128296465Sdelphij     * anything more
129296465Sdelphij     */
130296465Sdelphij    if (i > 0)
131296465Sdelphij        return (1);
13268651Skris
133296465Sdelphij    /* do a gethostbyname */
134296465Sdelphij    CRYPTO_w_lock(CRYPTO_LOCK_GETHOSTBYNAME);
135296465Sdelphij    locked = 1;
136296465Sdelphij    he = BIO_gethostbyname(str);
137296465Sdelphij    if (he == NULL) {
138296465Sdelphij        BIOerr(BIO_F_BIO_GET_HOST_IP, BIO_R_BAD_HOSTNAME_LOOKUP);
139296465Sdelphij        goto err;
140296465Sdelphij    }
14155714Skris
142296465Sdelphij    /* cast to short because of win16 winsock definition */
143296465Sdelphij    if ((short)he->h_addrtype != AF_INET) {
144296465Sdelphij        BIOerr(BIO_F_BIO_GET_HOST_IP,
145296465Sdelphij               BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET);
146296465Sdelphij        goto err;
147296465Sdelphij    }
148296465Sdelphij    for (i = 0; i < 4; i++)
149296465Sdelphij        ip[i] = he->h_addr_list[0][i];
150296465Sdelphij    err = 0;
15155714Skris
15255714Skris err:
153296465Sdelphij    if (locked)
154296465Sdelphij        CRYPTO_w_unlock(CRYPTO_LOCK_GETHOSTBYNAME);
155296465Sdelphij    if (err) {
156296465Sdelphij        ERR_add_error_data(2, "host=", str);
157296465Sdelphij        return 0;
158296465Sdelphij    } else
159296465Sdelphij        return 1;
160296465Sdelphij}
16155714Skris
16255714Skrisint BIO_get_port(const char *str, unsigned short *port_ptr)
163296465Sdelphij{
164296465Sdelphij    int i;
165296465Sdelphij    struct servent *s;
16655714Skris
167296465Sdelphij    if (str == NULL) {
168296465Sdelphij        BIOerr(BIO_F_BIO_GET_PORT, BIO_R_NO_PORT_DEFINED);
169296465Sdelphij        return (0);
170296465Sdelphij    }
171296465Sdelphij    i = atoi(str);
172296465Sdelphij    if (i != 0)
173296465Sdelphij        *port_ptr = (unsigned short)i;
174296465Sdelphij    else {
175296465Sdelphij        CRYPTO_w_lock(CRYPTO_LOCK_GETSERVBYNAME);
176296465Sdelphij        /*
177296465Sdelphij         * Note: under VMS with SOCKETSHR, it seems like the first parameter
178296465Sdelphij         * is 'char *', instead of 'const char *'
179296465Sdelphij         */
180296465Sdelphij# ifndef CONST_STRICT
181296465Sdelphij        s = getservbyname((char *)str, "tcp");
182296465Sdelphij# else
183296465Sdelphij        s = getservbyname(str, "tcp");
184296465Sdelphij# endif
185296465Sdelphij        if (s != NULL)
186296465Sdelphij            *port_ptr = ntohs((unsigned short)s->s_port);
187296465Sdelphij        CRYPTO_w_unlock(CRYPTO_LOCK_GETSERVBYNAME);
188296465Sdelphij        if (s == NULL) {
189296465Sdelphij            if (strcmp(str, "http") == 0)
190296465Sdelphij                *port_ptr = 80;
191296465Sdelphij            else if (strcmp(str, "telnet") == 0)
192296465Sdelphij                *port_ptr = 23;
193296465Sdelphij            else if (strcmp(str, "socks") == 0)
194296465Sdelphij                *port_ptr = 1080;
195296465Sdelphij            else if (strcmp(str, "https") == 0)
196296465Sdelphij                *port_ptr = 443;
197296465Sdelphij            else if (strcmp(str, "ssl") == 0)
198296465Sdelphij                *port_ptr = 443;
199296465Sdelphij            else if (strcmp(str, "ftp") == 0)
200296465Sdelphij                *port_ptr = 21;
201296465Sdelphij            else if (strcmp(str, "gopher") == 0)
202296465Sdelphij                *port_ptr = 70;
203296465Sdelphij# if 0
204296465Sdelphij            else if (strcmp(str, "wais") == 0)
205296465Sdelphij                *port_ptr = 21;
206296465Sdelphij# endif
207296465Sdelphij            else {
208296465Sdelphij                SYSerr(SYS_F_GETSERVBYNAME, get_last_socket_error());
209296465Sdelphij                ERR_add_error_data(3, "service='", str, "'");
210296465Sdelphij                return (0);
211296465Sdelphij            }
212296465Sdelphij        }
213296465Sdelphij    }
214296465Sdelphij    return (1);
215296465Sdelphij}
21655714Skris
21755714Skrisint BIO_sock_error(int sock)
218296465Sdelphij{
219296465Sdelphij    int j, i;
220296465Sdelphij    int size;
22155714Skris
222296465Sdelphij    size = sizeof(int);
223296465Sdelphij    /*
224296465Sdelphij     * Note: under Windows the third parameter is of type (char *) whereas
225296465Sdelphij     * under other systems it is (void *) if you don't have a cast it will
226296465Sdelphij     * choke the compiler: if you do have a cast then you can either go for
227296465Sdelphij     * (char *) or (void *).
228296465Sdelphij     */
229296465Sdelphij    i = getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *)&j, (void *)&size);
230296465Sdelphij    if (i < 0)
231296465Sdelphij        return (1);
232296465Sdelphij    else
233296465Sdelphij        return (j);
234296465Sdelphij}
235296465Sdelphij
236296465Sdelphij# if 0
23755714Skrislong BIO_ghbn_ctrl(int cmd, int iarg, char *parg)
238296465Sdelphij{
239296465Sdelphij    int i;
240296465Sdelphij    char **p;
24155714Skris
242296465Sdelphij    switch (cmd) {
243296465Sdelphij    case BIO_GHBN_CTRL_HITS:
244296465Sdelphij        return (BIO_ghbn_hits);
245296465Sdelphij        /* break; */
246296465Sdelphij    case BIO_GHBN_CTRL_MISSES:
247296465Sdelphij        return (BIO_ghbn_miss);
248296465Sdelphij        /* break; */
249296465Sdelphij    case BIO_GHBN_CTRL_CACHE_SIZE:
250296465Sdelphij        return (GHBN_NUM);
251296465Sdelphij        /* break; */
252296465Sdelphij    case BIO_GHBN_CTRL_GET_ENTRY:
253296465Sdelphij        if ((iarg >= 0) && (iarg < GHBN_NUM) && (ghbn_cache[iarg].order > 0)) {
254296465Sdelphij            p = (char **)parg;
255296465Sdelphij            if (p == NULL)
256296465Sdelphij                return (0);
257296465Sdelphij            *p = ghbn_cache[iarg].name;
258296465Sdelphij            ghbn_cache[iarg].name[128] = '\0';
259296465Sdelphij            return (1);
260296465Sdelphij        }
261296465Sdelphij        return (0);
262296465Sdelphij        /* break; */
263296465Sdelphij    case BIO_GHBN_CTRL_FLUSH:
264296465Sdelphij        for (i = 0; i < GHBN_NUM; i++)
265296465Sdelphij            ghbn_cache[i].order = 0;
266296465Sdelphij        break;
267296465Sdelphij    default:
268296465Sdelphij        return (0);
269296465Sdelphij    }
270296465Sdelphij    return (1);
271296465Sdelphij}
272296465Sdelphij# endif
27355714Skris
274296465Sdelphij# if 0
27555714Skrisstatic struct hostent *ghbn_dup(struct hostent *a)
276296465Sdelphij{
277296465Sdelphij    struct hostent *ret;
278296465Sdelphij    int i, j;
27955714Skris
280296465Sdelphij    MemCheck_off();
281296465Sdelphij    ret = (struct hostent *)OPENSSL_malloc(sizeof(struct hostent));
282296465Sdelphij    if (ret == NULL)
283296465Sdelphij        return (NULL);
284296465Sdelphij    memset(ret, 0, sizeof(struct hostent));
28555714Skris
286296465Sdelphij    for (i = 0; a->h_aliases[i] != NULL; i++) ;
287296465Sdelphij    i++;
288296465Sdelphij    ret->h_aliases = (char **)OPENSSL_malloc(i * sizeof(char *));
289296465Sdelphij    if (ret->h_aliases == NULL)
290296465Sdelphij        goto err;
291296465Sdelphij    memset(ret->h_aliases, 0, i * sizeof(char *));
29255714Skris
293296465Sdelphij    for (i = 0; a->h_addr_list[i] != NULL; i++) ;
294296465Sdelphij    i++;
295296465Sdelphij    ret->h_addr_list = (char **)OPENSSL_malloc(i * sizeof(char *));
296296465Sdelphij    if (ret->h_addr_list == NULL)
297296465Sdelphij        goto err;
298296465Sdelphij    memset(ret->h_addr_list, 0, i * sizeof(char *));
29955714Skris
300296465Sdelphij    j = strlen(a->h_name) + 1;
301296465Sdelphij    if ((ret->h_name = OPENSSL_malloc(j)) == NULL)
302296465Sdelphij        goto err;
303296465Sdelphij    memcpy((char *)ret->h_name, a->h_name, j);
304296465Sdelphij    for (i = 0; a->h_aliases[i] != NULL; i++) {
305296465Sdelphij        j = strlen(a->h_aliases[i]) + 1;
306296465Sdelphij        if ((ret->h_aliases[i] = OPENSSL_malloc(j)) == NULL)
307296465Sdelphij            goto err;
308296465Sdelphij        memcpy(ret->h_aliases[i], a->h_aliases[i], j);
309296465Sdelphij    }
310296465Sdelphij    ret->h_length = a->h_length;
311296465Sdelphij    ret->h_addrtype = a->h_addrtype;
312296465Sdelphij    for (i = 0; a->h_addr_list[i] != NULL; i++) {
313296465Sdelphij        if ((ret->h_addr_list[i] = OPENSSL_malloc(a->h_length)) == NULL)
314296465Sdelphij            goto err;
315296465Sdelphij        memcpy(ret->h_addr_list[i], a->h_addr_list[i], a->h_length);
316296465Sdelphij    }
317296465Sdelphij    if (0) {
318296465Sdelphij err:
319296465Sdelphij        if (ret != NULL)
320296465Sdelphij            ghbn_free(ret);
321296465Sdelphij        ret = NULL;
322296465Sdelphij    }
323296465Sdelphij    MemCheck_on();
324296465Sdelphij    return (ret);
325296465Sdelphij}
32655714Skris
32755714Skrisstatic void ghbn_free(struct hostent *a)
328296465Sdelphij{
329296465Sdelphij    int i;
33055714Skris
331296465Sdelphij    if (a == NULL)
332296465Sdelphij        return;
33355714Skris
334296465Sdelphij    if (a->h_aliases != NULL) {
335296465Sdelphij        for (i = 0; a->h_aliases[i] != NULL; i++)
336296465Sdelphij            OPENSSL_free(a->h_aliases[i]);
337296465Sdelphij        OPENSSL_free(a->h_aliases);
338296465Sdelphij    }
339296465Sdelphij    if (a->h_addr_list != NULL) {
340296465Sdelphij        for (i = 0; a->h_addr_list[i] != NULL; i++)
341296465Sdelphij            OPENSSL_free(a->h_addr_list[i]);
342296465Sdelphij        OPENSSL_free(a->h_addr_list);
343296465Sdelphij    }
344296465Sdelphij    if (a->h_name != NULL)
345296465Sdelphij        OPENSSL_free(a->h_name);
346296465Sdelphij    OPENSSL_free(a);
347296465Sdelphij}
348109998Smarkm
349296465Sdelphij# endif
35055714Skris
35155714Skrisstruct hostent *BIO_gethostbyname(const char *name)
352296465Sdelphij{
353296465Sdelphij# if 1
354296465Sdelphij    /*
355296465Sdelphij     * Caching gethostbyname() results forever is wrong, so we have to let
356296465Sdelphij     * the true gethostbyname() worry about this
357296465Sdelphij     */
358296465Sdelphij#  if (defined(NETWARE_BSDSOCK) && !defined(__NOVELL_LIBC__))
359296465Sdelphij    return gethostbyname((char *)name);
360296465Sdelphij#  else
361296465Sdelphij    return gethostbyname(name);
362296465Sdelphij#  endif
363296465Sdelphij# else
364296465Sdelphij    struct hostent *ret;
365296465Sdelphij    int i, lowi = 0, j;
366296465Sdelphij    unsigned long low = (unsigned long)-1;
36755714Skris
36889837Skris#  if 0
369296465Sdelphij    /*
370296465Sdelphij     * It doesn't make sense to use locking here: The function interface is
371296465Sdelphij     * not thread-safe, because threads can never be sure when some other
372296465Sdelphij     * thread destroys the data they were given a pointer to.
373296465Sdelphij     */
374296465Sdelphij    CRYPTO_w_lock(CRYPTO_LOCK_GETHOSTBYNAME);
37589837Skris#  endif
376296465Sdelphij    j = strlen(name);
377296465Sdelphij    if (j < 128) {
378296465Sdelphij        for (i = 0; i < GHBN_NUM; i++) {
379296465Sdelphij            if (low > ghbn_cache[i].order) {
380296465Sdelphij                low = ghbn_cache[i].order;
381296465Sdelphij                lowi = i;
382296465Sdelphij            }
383296465Sdelphij            if (ghbn_cache[i].order > 0) {
384296465Sdelphij                if (strncmp(name, ghbn_cache[i].name, 128) == 0)
385296465Sdelphij                    break;
386296465Sdelphij            }
387296465Sdelphij        }
388296465Sdelphij    } else
389296465Sdelphij        i = GHBN_NUM;
39055714Skris
391296465Sdelphij    if (i == GHBN_NUM) {        /* no hit */
392296465Sdelphij        BIO_ghbn_miss++;
393296465Sdelphij        /*
394296465Sdelphij         * Note: under VMS with SOCKETSHR, it seems like the first parameter
395296465Sdelphij         * is 'char *', instead of 'const char *'
396296465Sdelphij         */
39789837Skris#  ifndef CONST_STRICT
398296465Sdelphij        ret = gethostbyname((char *)name);
399194206Ssimon#  else
400296465Sdelphij        ret = gethostbyname(name);
40189837Skris#  endif
40255714Skris
403296465Sdelphij        if (ret == NULL)
404296465Sdelphij            goto end;
405296465Sdelphij        if (j > 128) {          /* too big to cache */
40689837Skris#  if 0
407296465Sdelphij            /*
408296465Sdelphij             * If we were trying to make this function thread-safe (which is
409296465Sdelphij             * bound to fail), we'd have to give up in this case (or allocate
410296465Sdelphij             * more memory).
411296465Sdelphij             */
412296465Sdelphij            ret = NULL;
41389837Skris#  endif
414296465Sdelphij            goto end;
415296465Sdelphij        }
41655714Skris
417296465Sdelphij        /* else add to cache */
418296465Sdelphij        if (ghbn_cache[lowi].ent != NULL)
419296465Sdelphij            ghbn_free(ghbn_cache[lowi].ent); /* XXX not thread-safe */
420296465Sdelphij        ghbn_cache[lowi].name[0] = '\0';
42155714Skris
422296465Sdelphij        if ((ret = ghbn_cache[lowi].ent = ghbn_dup(ret)) == NULL) {
423296465Sdelphij            BIOerr(BIO_F_BIO_GETHOSTBYNAME, ERR_R_MALLOC_FAILURE);
424296465Sdelphij            goto end;
425296465Sdelphij        }
426296465Sdelphij        strncpy(ghbn_cache[lowi].name, name, 128);
427296465Sdelphij        ghbn_cache[lowi].order = BIO_ghbn_miss + BIO_ghbn_hits;
428296465Sdelphij    } else {
429296465Sdelphij        BIO_ghbn_hits++;
430296465Sdelphij        ret = ghbn_cache[i].ent;
431296465Sdelphij        ghbn_cache[i].order = BIO_ghbn_miss + BIO_ghbn_hits;
432296465Sdelphij    }
433296465Sdelphij end:
43489837Skris#  if 0
435296465Sdelphij    CRYPTO_w_unlock(CRYPTO_LOCK_GETHOSTBYNAME);
43689837Skris#  endif
437296465Sdelphij    return (ret);
438296465Sdelphij# endif
439296465Sdelphij}
44055714Skris
44155714Skrisint BIO_sock_init(void)
442296465Sdelphij{
443296465Sdelphij# ifdef OPENSSL_SYS_WINDOWS
444296465Sdelphij    static struct WSAData wsa_state;
44555714Skris
446296465Sdelphij    if (!wsa_init_done) {
447296465Sdelphij        int err;
448160814Ssimon
449296465Sdelphij        wsa_init_done = 1;
450296465Sdelphij        memset(&wsa_state, 0, sizeof(wsa_state));
451296465Sdelphij        if (WSAStartup(0x0101, &wsa_state) != 0) {
452296465Sdelphij            err = WSAGetLastError();
453296465Sdelphij            SYSerr(SYS_F_WSASTARTUP, err);
454296465Sdelphij            BIOerr(BIO_F_BIO_SOCK_INIT, BIO_R_WSASTARTUP);
455296465Sdelphij            return (-1);
456296465Sdelphij        }
457296465Sdelphij    }
458296465Sdelphij# endif                         /* OPENSSL_SYS_WINDOWS */
459296465Sdelphij# ifdef WATT32
460296465Sdelphij    extern int _watt_do_exit;
461296465Sdelphij    _watt_do_exit = 0;          /* don't make sock_init() call exit() */
462296465Sdelphij    if (sock_init())
463296465Sdelphij        return (-1);
464296465Sdelphij# endif
465296465Sdelphij
466296465Sdelphij# if defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)
467160814Ssimon    WORD wVerReq;
468160814Ssimon    WSADATA wsaData;
469160814Ssimon    int err;
470160814Ssimon
471296465Sdelphij    if (!wsa_init_done) {
472296465Sdelphij        wsa_init_done = 1;
473296465Sdelphij        wVerReq = MAKEWORD(2, 0);
474296465Sdelphij        err = WSAStartup(wVerReq, &wsaData);
475296465Sdelphij        if (err != 0) {
476296465Sdelphij            SYSerr(SYS_F_WSASTARTUP, err);
477296465Sdelphij            BIOerr(BIO_F_BIO_SOCK_INIT, BIO_R_WSASTARTUP);
478296465Sdelphij            return (-1);
479296465Sdelphij        }
480296465Sdelphij    }
481296465Sdelphij# endif
482160814Ssimon
483296465Sdelphij    return (1);
484296465Sdelphij}
48555714Skris
48655714Skrisvoid BIO_sock_cleanup(void)
487296465Sdelphij{
488296465Sdelphij# ifdef OPENSSL_SYS_WINDOWS
489296465Sdelphij    if (wsa_init_done) {
490296465Sdelphij        wsa_init_done = 0;
491296465Sdelphij#  ifndef OPENSSL_SYS_WINCE
492296465Sdelphij        WSACancelBlockingCall(); /* Winsock 1.1 specific */
493296465Sdelphij#  endif
494160814Ssimon        WSACleanup();
495296465Sdelphij    }
496296465Sdelphij# elif defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)
497296465Sdelphij    if (wsa_init_done) {
498296465Sdelphij        wsa_init_done = 0;
499296465Sdelphij        WSACleanup();
500296465Sdelphij    }
501296465Sdelphij# endif
502296465Sdelphij}
50355714Skris
504296465Sdelphij# if !defined(OPENSSL_SYS_VMS) || __VMS_VER >= 70000000
50555714Skris
506111147Snectarint BIO_socket_ioctl(int fd, long type, void *arg)
507296465Sdelphij{
508296465Sdelphij    int i;
50955714Skris
510296465Sdelphij#  ifdef __DJGPP__
511296465Sdelphij    i = ioctlsocket(fd, type, (char *)arg);
512296465Sdelphij#  else
513296465Sdelphij    i = ioctlsocket(fd, type, arg);
514296465Sdelphij#  endif                        /* __DJGPP__ */
515296465Sdelphij    if (i < 0)
516296465Sdelphij        SYSerr(SYS_F_IOCTLSOCKET, get_last_socket_error());
517296465Sdelphij    return (i);
518296465Sdelphij}
519296465Sdelphij# endif                         /* __VMS_VER */
52055714Skris
521296465Sdelphij/*
522296465Sdelphij * The reason I have implemented this instead of using sscanf is because
523296465Sdelphij * Visual C 1.52c gives an unresolved external when linking a DLL :-(
524296465Sdelphij */
52555714Skrisstatic int get_ip(const char *str, unsigned char ip[4])
526296465Sdelphij{
527296465Sdelphij    unsigned int tmp[4];
528296465Sdelphij    int num = 0, c, ok = 0;
52955714Skris
530296465Sdelphij    tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0;
53155714Skris
532296465Sdelphij    for (;;) {
533296465Sdelphij        c = *(str++);
534296465Sdelphij        if ((c >= '0') && (c <= '9')) {
535296465Sdelphij            ok = 1;
536296465Sdelphij            tmp[num] = tmp[num] * 10 + c - '0';
537296465Sdelphij            if (tmp[num] > 255)
538296465Sdelphij                return (0);
539296465Sdelphij        } else if (c == '.') {
540296465Sdelphij            if (!ok)
541296465Sdelphij                return (-1);
542296465Sdelphij            if (num == 3)
543296465Sdelphij                return (0);
544296465Sdelphij            num++;
545296465Sdelphij            ok = 0;
546296465Sdelphij        } else if (c == '\0' && (num == 3) && ok)
547296465Sdelphij            break;
548296465Sdelphij        else
549296465Sdelphij            return (0);
550296465Sdelphij    }
551296465Sdelphij    ip[0] = tmp[0];
552296465Sdelphij    ip[1] = tmp[1];
553296465Sdelphij    ip[2] = tmp[2];
554296465Sdelphij    ip[3] = tmp[3];
555296465Sdelphij    return (1);
556296465Sdelphij}
55755714Skris
55855714Skrisint BIO_get_accept_socket(char *host, int bind_mode)
559296465Sdelphij{
560296465Sdelphij    int ret = 0;
561296465Sdelphij    struct sockaddr_in server, client;
562296465Sdelphij    int s = INVALID_SOCKET, cs;
563296465Sdelphij    unsigned char ip[4];
564296465Sdelphij    unsigned short port;
565296465Sdelphij    char *str = NULL, *e;
566296465Sdelphij    const char *h, *p;
567296465Sdelphij    unsigned long l;
568296465Sdelphij    int err_num;
56955714Skris
570296465Sdelphij    if (BIO_sock_init() != 1)
571296465Sdelphij        return (INVALID_SOCKET);
57255714Skris
573296465Sdelphij    if ((str = BUF_strdup(host)) == NULL)
574296465Sdelphij        return (INVALID_SOCKET);
57555714Skris
576296465Sdelphij    h = p = NULL;
577296465Sdelphij    h = str;
578296465Sdelphij    for (e = str; *e; e++) {
579296465Sdelphij        if (*e == ':') {
580296465Sdelphij            p = &(e[1]);
581296465Sdelphij            *e = '\0';
582296465Sdelphij        } else if (*e == '/') {
583296465Sdelphij            *e = '\0';
584296465Sdelphij            break;
585296465Sdelphij        }
586296465Sdelphij    }
58755714Skris
588296465Sdelphij    if (p == NULL) {
589296465Sdelphij        p = h;
590296465Sdelphij        h = "*";
591296465Sdelphij    }
59255714Skris
593296465Sdelphij    if (!BIO_get_port(p, &port))
594296465Sdelphij        goto err;
59555714Skris
596296465Sdelphij    memset((char *)&server, 0, sizeof(server));
597296465Sdelphij    server.sin_family = AF_INET;
598296465Sdelphij    server.sin_port = htons(port);
59955714Skris
600296465Sdelphij    if (strcmp(h, "*") == 0)
601296465Sdelphij        server.sin_addr.s_addr = INADDR_ANY;
602296465Sdelphij    else {
603296465Sdelphij        if (!BIO_get_host_ip(h, &(ip[0])))
604296465Sdelphij            goto err;
605296465Sdelphij        l = (unsigned long)
606296465Sdelphij            ((unsigned long)ip[0] << 24L) |
607296465Sdelphij            ((unsigned long)ip[1] << 16L) |
608296465Sdelphij            ((unsigned long)ip[2] << 8L) | ((unsigned long)ip[3]);
609296465Sdelphij        server.sin_addr.s_addr = htonl(l);
610296465Sdelphij    }
61155714Skris
612296465Sdelphij again:
613296465Sdelphij    s = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL);
614296465Sdelphij    if (s == INVALID_SOCKET) {
615296465Sdelphij        SYSerr(SYS_F_SOCKET, get_last_socket_error());
616296465Sdelphij        ERR_add_error_data(3, "port='", host, "'");
617296465Sdelphij        BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET, BIO_R_UNABLE_TO_CREATE_SOCKET);
618296465Sdelphij        goto err;
619296465Sdelphij    }
620296465Sdelphij# ifdef SO_REUSEADDR
621296465Sdelphij    if (bind_mode == BIO_BIND_REUSEADDR) {
622296465Sdelphij        int i = 1;
62355714Skris
624296465Sdelphij        ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof(i));
625296465Sdelphij        bind_mode = BIO_BIND_NORMAL;
626296465Sdelphij    }
627296465Sdelphij# endif
628296465Sdelphij    if (bind(s, (struct sockaddr *)&server, sizeof(server)) == -1) {
629296465Sdelphij# ifdef SO_REUSEADDR
630296465Sdelphij        err_num = get_last_socket_error();
631296465Sdelphij        if ((bind_mode == BIO_BIND_REUSEADDR_IF_UNUSED) &&
632296465Sdelphij#  ifdef OPENSSL_SYS_WINDOWS
633296465Sdelphij            /*
634296465Sdelphij             * Some versions of Windows define EADDRINUSE to a dummy value.
635296465Sdelphij             */
636296465Sdelphij            (err_num == WSAEADDRINUSE))
637296465Sdelphij#  else
638296465Sdelphij            (err_num == EADDRINUSE))
639296465Sdelphij#  endif
640296465Sdelphij        {
641296465Sdelphij            memcpy((char *)&client, (char *)&server, sizeof(server));
642296465Sdelphij            if (strcmp(h, "*") == 0)
643296465Sdelphij                client.sin_addr.s_addr = htonl(0x7F000001);
644296465Sdelphij            cs = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL);
645296465Sdelphij            if (cs != INVALID_SOCKET) {
646296465Sdelphij                int ii;
647296465Sdelphij                ii = connect(cs, (struct sockaddr *)&client, sizeof(client));
648296465Sdelphij                closesocket(cs);
649296465Sdelphij                if (ii == INVALID_SOCKET) {
650296465Sdelphij                    bind_mode = BIO_BIND_REUSEADDR;
651296465Sdelphij                    closesocket(s);
652296465Sdelphij                    goto again;
653296465Sdelphij                }
654296465Sdelphij                /* else error */
655296465Sdelphij            }
656296465Sdelphij            /* else error */
657296465Sdelphij        }
658296465Sdelphij# endif
659296465Sdelphij        SYSerr(SYS_F_BIND, err_num);
660296465Sdelphij        ERR_add_error_data(3, "port='", host, "'");
661296465Sdelphij        BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET, BIO_R_UNABLE_TO_BIND_SOCKET);
662296465Sdelphij        goto err;
663296465Sdelphij    }
664296465Sdelphij    if (listen(s, MAX_LISTEN) == -1) {
665296465Sdelphij        SYSerr(SYS_F_BIND, get_last_socket_error());
666296465Sdelphij        ERR_add_error_data(3, "port='", host, "'");
667296465Sdelphij        BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET, BIO_R_UNABLE_TO_LISTEN_SOCKET);
668296465Sdelphij        goto err;
669296465Sdelphij    }
670296465Sdelphij    ret = 1;
671296465Sdelphij err:
672296465Sdelphij    if (str != NULL)
673296465Sdelphij        OPENSSL_free(str);
674296465Sdelphij    if ((ret == 0) && (s != INVALID_SOCKET)) {
675296465Sdelphij        closesocket(s);
676296465Sdelphij        s = INVALID_SOCKET;
677296465Sdelphij    }
678296465Sdelphij    return (s);
679296465Sdelphij}
68055714Skris
68155714Skrisint BIO_accept(int sock, char **addr)
682296465Sdelphij{
683296465Sdelphij    int ret = INVALID_SOCKET;
684296465Sdelphij    static struct sockaddr_in from;
685296465Sdelphij    unsigned long l;
686296465Sdelphij    unsigned short port;
687296465Sdelphij    int len;
688296465Sdelphij    char *p;
68955714Skris
690296465Sdelphij    memset((char *)&from, 0, sizeof(from));
691296465Sdelphij    len = sizeof(from);
692296465Sdelphij    /*
693296465Sdelphij     * Note: under VMS with SOCKETSHR the fourth parameter is currently of
694296465Sdelphij     * type (int *) whereas under other systems it is (void *) if you don't
695296465Sdelphij     * have a cast it will choke the compiler: if you do have a cast then you
696296465Sdelphij     * can either go for (int *) or (void *).
697296465Sdelphij     */
698296465Sdelphij    ret = accept(sock, (struct sockaddr *)&from, (void *)&len);
699296465Sdelphij    if (ret == INVALID_SOCKET) {
700296465Sdelphij        if (BIO_sock_should_retry(ret))
701296465Sdelphij            return -2;
702296465Sdelphij        SYSerr(SYS_F_ACCEPT, get_last_socket_error());
703296465Sdelphij        BIOerr(BIO_F_BIO_ACCEPT, BIO_R_ACCEPT_ERROR);
704296465Sdelphij        goto end;
705296465Sdelphij    }
70655714Skris
707296465Sdelphij    if (addr == NULL)
708296465Sdelphij        goto end;
70955714Skris
710296465Sdelphij    l = ntohl(from.sin_addr.s_addr);
711296465Sdelphij    port = ntohs(from.sin_port);
712296465Sdelphij    if (*addr == NULL) {
713296465Sdelphij        if ((p = OPENSSL_malloc(24)) == NULL) {
714296465Sdelphij            BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE);
715296465Sdelphij            goto end;
716296465Sdelphij        }
717296465Sdelphij        *addr = p;
718296465Sdelphij    }
719296465Sdelphij    BIO_snprintf(*addr, 24, "%d.%d.%d.%d:%d",
720296465Sdelphij                 (unsigned char)(l >> 24L) & 0xff,
721296465Sdelphij                 (unsigned char)(l >> 16L) & 0xff,
722296465Sdelphij                 (unsigned char)(l >> 8L) & 0xff,
723296465Sdelphij                 (unsigned char)(l) & 0xff, port);
724296465Sdelphij end:
725296465Sdelphij    return (ret);
726296465Sdelphij}
72755714Skris
72855714Skrisint BIO_set_tcp_ndelay(int s, int on)
729296465Sdelphij{
730296465Sdelphij    int ret = 0;
731296465Sdelphij# if defined(TCP_NODELAY) && (defined(IPPROTO_TCP) || defined(SOL_TCP))
732296465Sdelphij    int opt;
73355714Skris
734296465Sdelphij#  ifdef SOL_TCP
735296465Sdelphij    opt = SOL_TCP;
736296465Sdelphij#  else
737296465Sdelphij#   ifdef IPPROTO_TCP
738296465Sdelphij    opt = IPPROTO_TCP;
739296465Sdelphij#   endif
740296465Sdelphij#  endif
741296465Sdelphij
742296465Sdelphij    ret = setsockopt(s, opt, TCP_NODELAY, (char *)&on, sizeof(on));
743296465Sdelphij# endif
744296465Sdelphij    return (ret == 0);
745296465Sdelphij}
74655714Skris#endif
74755714Skris
74855714Skrisint BIO_socket_nbio(int s, int mode)
749296465Sdelphij{
750296465Sdelphij    int ret = -1;
751296465Sdelphij    int l;
75255714Skris
753296465Sdelphij    l = mode;
75455714Skris#ifdef FIONBIO
755296465Sdelphij    ret = BIO_socket_ioctl(s, FIONBIO, &l);
75655714Skris#endif
757296465Sdelphij    return (ret == 0);
758296465Sdelphij}
759