155714Skris/* crypto/bio/bss_conn.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.
8296341Sdelphij *
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).
15296341Sdelphij *
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.
22296341Sdelphij *
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 :-).
37296341Sdelphij * 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)"
40296341Sdelphij *
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.
52296341Sdelphij *
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
67296341Sdelphij# ifdef OPENSSL_SYS_WIN16
68296341Sdelphij#  define SOCKET_PROTOCOL 0     /* more microsoft stupidity */
69296341Sdelphij# else
70296341Sdelphij#  define SOCKET_PROTOCOL IPPROTO_TCP
71296341Sdelphij# endif
7255714Skris
73296341Sdelphij# 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 */
75296341Sdelphij#  undef FIONBIO
76296341Sdelphij# endif
7755714Skris
78296341Sdelphijtypedef struct bio_connect_st {
79296341Sdelphij    int state;
80296341Sdelphij    char *param_hostname;
81296341Sdelphij    char *param_port;
82296341Sdelphij    int nbio;
83296341Sdelphij    unsigned char ip[4];
84296341Sdelphij    unsigned short port;
85296341Sdelphij    struct sockaddr_in them;
86296341Sdelphij    /*
87296341Sdelphij     * int socket; this will be kept in bio->num so that it is compatible
88296341Sdelphij     * with the bss_sock bio
89296341Sdelphij     */
90296341Sdelphij    /*
91296341Sdelphij     * called when the connection is initially made callback(BIO,state,ret);
92296341Sdelphij     * The callback should return 'ret'.  state is for compatibility with the
93296341Sdelphij     * ssl info_callback
94296341Sdelphij     */
95296341Sdelphij    int (*info_callback) (const BIO *bio, int state, int ret);
96296341Sdelphij} BIO_CONNECT;
9755714Skris
9868651Skrisstatic int conn_write(BIO *h, const char *buf, int num);
9968651Skrisstatic int conn_read(BIO *h, char *buf, int size);
10068651Skrisstatic int conn_puts(BIO *h, const char *str);
10168651Skrisstatic long conn_ctrl(BIO *h, int cmd, long arg1, void *arg2);
10255714Skrisstatic int conn_new(BIO *h);
10355714Skrisstatic int conn_free(BIO *data);
10468651Skrisstatic long conn_callback_ctrl(BIO *h, int cmd, bio_info_cb *);
10555714Skris
10655714Skrisstatic int conn_state(BIO *b, BIO_CONNECT *c);
10755714Skrisstatic void conn_close_socket(BIO *data);
108296341SdelphijBIO_CONNECT *BIO_CONNECT_new(void);
10955714Skrisvoid BIO_CONNECT_free(BIO_CONNECT *a);
11055714Skris
111296341Sdelphijstatic BIO_METHOD methods_connectp = {
112296341Sdelphij    BIO_TYPE_CONNECT,
113296341Sdelphij    "socket connect",
114296341Sdelphij    conn_write,
115296341Sdelphij    conn_read,
116296341Sdelphij    conn_puts,
117296341Sdelphij    NULL,                       /* connect_gets, */
118296341Sdelphij    conn_ctrl,
119296341Sdelphij    conn_new,
120296341Sdelphij    conn_free,
121296341Sdelphij    conn_callback_ctrl,
122296341Sdelphij};
12355714Skris
12455714Skrisstatic int conn_state(BIO *b, BIO_CONNECT *c)
125296341Sdelphij{
126296341Sdelphij    int ret = -1, i;
127296341Sdelphij    unsigned long l;
128296341Sdelphij    char *p, *q;
129296341Sdelphij    int (*cb) (const BIO *, int, int) = NULL;
13055714Skris
131296341Sdelphij    if (c->info_callback != NULL)
132296341Sdelphij        cb = c->info_callback;
13355714Skris
134296341Sdelphij    for (;;) {
135296341Sdelphij        switch (c->state) {
136296341Sdelphij        case BIO_CONN_S_BEFORE:
137296341Sdelphij            p = c->param_hostname;
138296341Sdelphij            if (p == NULL) {
139296341Sdelphij                BIOerr(BIO_F_CONN_STATE, BIO_R_NO_HOSTNAME_SPECIFIED);
140296341Sdelphij                goto exit_loop;
141296341Sdelphij            }
142296341Sdelphij            for (; *p != '\0'; p++) {
143296341Sdelphij                if ((*p == ':') || (*p == '/'))
144296341Sdelphij                    break;
145296341Sdelphij            }
14655714Skris
147296341Sdelphij            i = *p;
148296341Sdelphij            if ((i == ':') || (i == '/')) {
14955714Skris
150296341Sdelphij                *(p++) = '\0';
151296341Sdelphij                if (i == ':') {
152296341Sdelphij                    for (q = p; *q; q++)
153296341Sdelphij                        if (*q == '/') {
154296341Sdelphij                            *q = '\0';
155296341Sdelphij                            break;
156296341Sdelphij                        }
157296341Sdelphij                    if (c->param_port != NULL)
158296341Sdelphij                        OPENSSL_free(c->param_port);
159296341Sdelphij                    c->param_port = BUF_strdup(p);
160296341Sdelphij                }
161296341Sdelphij            }
16255714Skris
163296341Sdelphij            if (c->param_port == NULL) {
164296341Sdelphij                BIOerr(BIO_F_CONN_STATE, BIO_R_NO_PORT_SPECIFIED);
165296341Sdelphij                ERR_add_error_data(2, "host=", c->param_hostname);
166296341Sdelphij                goto exit_loop;
167296341Sdelphij            }
168296341Sdelphij            c->state = BIO_CONN_S_GET_IP;
169296341Sdelphij            break;
17055714Skris
171296341Sdelphij        case BIO_CONN_S_GET_IP:
172296341Sdelphij            if (BIO_get_host_ip(c->param_hostname, &(c->ip[0])) <= 0)
173296341Sdelphij                goto exit_loop;
174296341Sdelphij            c->state = BIO_CONN_S_GET_PORT;
175296341Sdelphij            break;
17655714Skris
177296341Sdelphij        case BIO_CONN_S_GET_PORT:
178296341Sdelphij            if (c->param_port == NULL) {
179296341Sdelphij                /* abort(); */
180296341Sdelphij                goto exit_loop;
181296341Sdelphij            } else if (BIO_get_port(c->param_port, &c->port) <= 0)
182296341Sdelphij                goto exit_loop;
183296341Sdelphij            c->state = BIO_CONN_S_CREATE_SOCKET;
184296341Sdelphij            break;
18555714Skris
186296341Sdelphij        case BIO_CONN_S_CREATE_SOCKET:
187296341Sdelphij            /* now setup address */
188296341Sdelphij            memset((char *)&c->them, 0, sizeof(c->them));
189296341Sdelphij            c->them.sin_family = AF_INET;
190296341Sdelphij            c->them.sin_port = htons((unsigned short)c->port);
191296341Sdelphij            l = (unsigned long)
192296341Sdelphij                ((unsigned long)c->ip[0] << 24L) |
193296341Sdelphij                ((unsigned long)c->ip[1] << 16L) |
194296341Sdelphij                ((unsigned long)c->ip[2] << 8L) | ((unsigned long)c->ip[3]);
195296341Sdelphij            c->them.sin_addr.s_addr = htonl(l);
196296341Sdelphij            c->state = BIO_CONN_S_CREATE_SOCKET;
19755714Skris
198296341Sdelphij            ret = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL);
199296341Sdelphij            if (ret == INVALID_SOCKET) {
200296341Sdelphij                SYSerr(SYS_F_SOCKET, get_last_socket_error());
201296341Sdelphij                ERR_add_error_data(4, "host=", c->param_hostname,
202296341Sdelphij                                   ":", c->param_port);
203296341Sdelphij                BIOerr(BIO_F_CONN_STATE, BIO_R_UNABLE_TO_CREATE_SOCKET);
204296341Sdelphij                goto exit_loop;
205296341Sdelphij            }
206296341Sdelphij            b->num = ret;
207296341Sdelphij            c->state = BIO_CONN_S_NBIO;
208296341Sdelphij            break;
20955714Skris
210296341Sdelphij        case BIO_CONN_S_NBIO:
211296341Sdelphij            if (c->nbio) {
212296341Sdelphij                if (!BIO_socket_nbio(b->num, 1)) {
213296341Sdelphij                    BIOerr(BIO_F_CONN_STATE, BIO_R_ERROR_SETTING_NBIO);
214296341Sdelphij                    ERR_add_error_data(4, "host=",
215296341Sdelphij                                       c->param_hostname, ":", c->param_port);
216296341Sdelphij                    goto exit_loop;
217296341Sdelphij                }
218296341Sdelphij            }
219296341Sdelphij            c->state = BIO_CONN_S_CONNECT;
22055714Skris
221296341Sdelphij# if defined(SO_KEEPALIVE) && !defined(OPENSSL_SYS_MPE)
222296341Sdelphij            i = 1;
223296341Sdelphij            i = setsockopt(b->num, SOL_SOCKET, SO_KEEPALIVE, (char *)&i,
224296341Sdelphij                           sizeof(i));
225296341Sdelphij            if (i < 0) {
226296341Sdelphij                SYSerr(SYS_F_SOCKET, get_last_socket_error());
227296341Sdelphij                ERR_add_error_data(4, "host=", c->param_hostname,
228296341Sdelphij                                   ":", c->param_port);
229296341Sdelphij                BIOerr(BIO_F_CONN_STATE, BIO_R_KEEPALIVE);
230296341Sdelphij                goto exit_loop;
231296341Sdelphij            }
232296341Sdelphij# endif
233296341Sdelphij            break;
23455714Skris
235296341Sdelphij        case BIO_CONN_S_CONNECT:
236296341Sdelphij            BIO_clear_retry_flags(b);
237296341Sdelphij            ret = connect(b->num,
238296341Sdelphij                          (struct sockaddr *)&c->them, sizeof(c->them));
239296341Sdelphij            b->retry_reason = 0;
240296341Sdelphij            if (ret < 0) {
241296341Sdelphij                if (BIO_sock_should_retry(ret)) {
242296341Sdelphij                    BIO_set_retry_special(b);
243296341Sdelphij                    c->state = BIO_CONN_S_BLOCKED_CONNECT;
244296341Sdelphij                    b->retry_reason = BIO_RR_CONNECT;
245296341Sdelphij                } else {
246296341Sdelphij                    SYSerr(SYS_F_CONNECT, get_last_socket_error());
247296341Sdelphij                    ERR_add_error_data(4, "host=",
248296341Sdelphij                                       c->param_hostname, ":", c->param_port);
249296341Sdelphij                    BIOerr(BIO_F_CONN_STATE, BIO_R_CONNECT_ERROR);
250296341Sdelphij                }
251296341Sdelphij                goto exit_loop;
252296341Sdelphij            } else
253296341Sdelphij                c->state = BIO_CONN_S_OK;
254296341Sdelphij            break;
25555714Skris
256296341Sdelphij        case BIO_CONN_S_BLOCKED_CONNECT:
257296341Sdelphij            i = BIO_sock_error(b->num);
258296341Sdelphij            if (i) {
259296341Sdelphij                BIO_clear_retry_flags(b);
260296341Sdelphij                SYSerr(SYS_F_CONNECT, i);
261296341Sdelphij                ERR_add_error_data(4, "host=",
262296341Sdelphij                                   c->param_hostname, ":", c->param_port);
263296341Sdelphij                BIOerr(BIO_F_CONN_STATE, BIO_R_NBIO_CONNECT_ERROR);
264296341Sdelphij                ret = 0;
265296341Sdelphij                goto exit_loop;
266296341Sdelphij            } else
267296341Sdelphij                c->state = BIO_CONN_S_OK;
268296341Sdelphij            break;
26955714Skris
270296341Sdelphij        case BIO_CONN_S_OK:
271296341Sdelphij            ret = 1;
272296341Sdelphij            goto exit_loop;
273296341Sdelphij        default:
274296341Sdelphij            /* abort(); */
275296341Sdelphij            goto exit_loop;
276296341Sdelphij        }
27755714Skris
278296341Sdelphij        if (cb != NULL) {
279296341Sdelphij            if (!(ret = cb((BIO *)b, c->state, ret)))
280296341Sdelphij                goto end;
281296341Sdelphij        }
282296341Sdelphij    }
28355714Skris
284296341Sdelphij    /* Loop does not exit */
285296341Sdelphij exit_loop:
286296341Sdelphij    if (cb != NULL)
287296341Sdelphij        ret = cb((BIO *)b, c->state, ret);
288296341Sdelphij end:
289296341Sdelphij    return (ret);
290296341Sdelphij}
29155714Skris
29255714SkrisBIO_CONNECT *BIO_CONNECT_new(void)
293296341Sdelphij{
294296341Sdelphij    BIO_CONNECT *ret;
29555714Skris
296296341Sdelphij    if ((ret = (BIO_CONNECT *)OPENSSL_malloc(sizeof(BIO_CONNECT))) == NULL)
297296341Sdelphij        return (NULL);
298296341Sdelphij    ret->state = BIO_CONN_S_BEFORE;
299296341Sdelphij    ret->param_hostname = NULL;
300296341Sdelphij    ret->param_port = NULL;
301296341Sdelphij    ret->info_callback = NULL;
302296341Sdelphij    ret->nbio = 0;
303296341Sdelphij    ret->ip[0] = 0;
304296341Sdelphij    ret->ip[1] = 0;
305296341Sdelphij    ret->ip[2] = 0;
306296341Sdelphij    ret->ip[3] = 0;
307296341Sdelphij    ret->port = 0;
308296341Sdelphij    memset((char *)&ret->them, 0, sizeof(ret->them));
309296341Sdelphij    return (ret);
310296341Sdelphij}
31155714Skris
31255714Skrisvoid BIO_CONNECT_free(BIO_CONNECT *a)
313296341Sdelphij{
314296341Sdelphij    if (a == NULL)
315296341Sdelphij        return;
31655714Skris
317296341Sdelphij    if (a->param_hostname != NULL)
318296341Sdelphij        OPENSSL_free(a->param_hostname);
319296341Sdelphij    if (a->param_port != NULL)
320296341Sdelphij        OPENSSL_free(a->param_port);
321296341Sdelphij    OPENSSL_free(a);
322296341Sdelphij}
32355714Skris
32455714SkrisBIO_METHOD *BIO_s_connect(void)
325296341Sdelphij{
326296341Sdelphij    return (&methods_connectp);
327296341Sdelphij}
32855714Skris
32955714Skrisstatic int conn_new(BIO *bi)
330296341Sdelphij{
331296341Sdelphij    bi->init = 0;
332296341Sdelphij    bi->num = INVALID_SOCKET;
333296341Sdelphij    bi->flags = 0;
334296341Sdelphij    if ((bi->ptr = (char *)BIO_CONNECT_new()) == NULL)
335296341Sdelphij        return (0);
336296341Sdelphij    else
337296341Sdelphij        return (1);
338296341Sdelphij}
33955714Skris
34055714Skrisstatic void conn_close_socket(BIO *bio)
341296341Sdelphij{
342296341Sdelphij    BIO_CONNECT *c;
34355714Skris
344296341Sdelphij    c = (BIO_CONNECT *)bio->ptr;
345296341Sdelphij    if (bio->num != INVALID_SOCKET) {
346296341Sdelphij        /* Only do a shutdown if things were established */
347296341Sdelphij        if (c->state == BIO_CONN_S_OK)
348296341Sdelphij            shutdown(bio->num, 2);
349296341Sdelphij        closesocket(bio->num);
350296341Sdelphij        bio->num = INVALID_SOCKET;
351296341Sdelphij    }
352296341Sdelphij}
35355714Skris
35455714Skrisstatic int conn_free(BIO *a)
355296341Sdelphij{
356296341Sdelphij    BIO_CONNECT *data;
35755714Skris
358296341Sdelphij    if (a == NULL)
359296341Sdelphij        return (0);
360296341Sdelphij    data = (BIO_CONNECT *)a->ptr;
361296341Sdelphij
362296341Sdelphij    if (a->shutdown) {
363296341Sdelphij        conn_close_socket(a);
364296341Sdelphij        BIO_CONNECT_free(data);
365296341Sdelphij        a->ptr = NULL;
366296341Sdelphij        a->flags = 0;
367296341Sdelphij        a->init = 0;
368296341Sdelphij    }
369296341Sdelphij    return (1);
370296341Sdelphij}
371296341Sdelphij
37255714Skrisstatic int conn_read(BIO *b, char *out, int outl)
373296341Sdelphij{
374296341Sdelphij    int ret = 0;
375296341Sdelphij    BIO_CONNECT *data;
37655714Skris
377296341Sdelphij    data = (BIO_CONNECT *)b->ptr;
378296341Sdelphij    if (data->state != BIO_CONN_S_OK) {
379296341Sdelphij        ret = conn_state(b, data);
380296341Sdelphij        if (ret <= 0)
381296341Sdelphij            return (ret);
382296341Sdelphij    }
38355714Skris
384296341Sdelphij    if (out != NULL) {
385296341Sdelphij        clear_socket_error();
386296341Sdelphij        ret = readsocket(b->num, out, outl);
387296341Sdelphij        BIO_clear_retry_flags(b);
388296341Sdelphij        if (ret <= 0) {
389296341Sdelphij            if (BIO_sock_should_retry(ret))
390296341Sdelphij                BIO_set_retry_read(b);
391296341Sdelphij        }
392296341Sdelphij    }
393296341Sdelphij    return (ret);
394296341Sdelphij}
39555714Skris
39668651Skrisstatic int conn_write(BIO *b, const char *in, int inl)
397296341Sdelphij{
398296341Sdelphij    int ret;
399296341Sdelphij    BIO_CONNECT *data;
40055714Skris
401296341Sdelphij    data = (BIO_CONNECT *)b->ptr;
402296341Sdelphij    if (data->state != BIO_CONN_S_OK) {
403296341Sdelphij        ret = conn_state(b, data);
404296341Sdelphij        if (ret <= 0)
405296341Sdelphij            return (ret);
406296341Sdelphij    }
40755714Skris
408296341Sdelphij    clear_socket_error();
409296341Sdelphij    ret = writesocket(b->num, in, inl);
410296341Sdelphij    BIO_clear_retry_flags(b);
411296341Sdelphij    if (ret <= 0) {
412296341Sdelphij        if (BIO_sock_should_retry(ret))
413296341Sdelphij            BIO_set_retry_write(b);
414296341Sdelphij    }
415296341Sdelphij    return (ret);
416296341Sdelphij}
41755714Skris
41868651Skrisstatic long conn_ctrl(BIO *b, int cmd, long num, void *ptr)
419296341Sdelphij{
420296341Sdelphij    BIO *dbio;
421296341Sdelphij    int *ip;
422296341Sdelphij    const char **pptr;
423296341Sdelphij    long ret = 1;
424296341Sdelphij    BIO_CONNECT *data;
42555714Skris
426296341Sdelphij    data = (BIO_CONNECT *)b->ptr;
42755714Skris
428296341Sdelphij    switch (cmd) {
429296341Sdelphij    case BIO_CTRL_RESET:
430296341Sdelphij        ret = 0;
431296341Sdelphij        data->state = BIO_CONN_S_BEFORE;
432296341Sdelphij        conn_close_socket(b);
433296341Sdelphij        b->flags = 0;
434296341Sdelphij        break;
435296341Sdelphij    case BIO_C_DO_STATE_MACHINE:
436296341Sdelphij        /* use this one to start the connection */
437296341Sdelphij        if (data->state != BIO_CONN_S_OK)
438296341Sdelphij            ret = (long)conn_state(b, data);
439296341Sdelphij        else
440296341Sdelphij            ret = 1;
441296341Sdelphij        break;
442296341Sdelphij    case BIO_C_GET_CONNECT:
443296341Sdelphij        if (ptr != NULL) {
444296341Sdelphij            pptr = (const char **)ptr;
445296341Sdelphij            if (num == 0) {
446296341Sdelphij                *pptr = data->param_hostname;
44755714Skris
448296341Sdelphij            } else if (num == 1) {
449296341Sdelphij                *pptr = data->param_port;
450296341Sdelphij            } else if (num == 2) {
451296341Sdelphij                *pptr = (char *)&(data->ip[0]);
452296341Sdelphij            } else if (num == 3) {
453296341Sdelphij                *((int *)ptr) = data->port;
454296341Sdelphij            }
455296341Sdelphij            if ((!b->init) || (ptr == NULL))
456296341Sdelphij                *pptr = "not initialized";
457296341Sdelphij            ret = 1;
458296341Sdelphij        }
459296341Sdelphij        break;
460296341Sdelphij    case BIO_C_SET_CONNECT:
461296341Sdelphij        if (ptr != NULL) {
462296341Sdelphij            b->init = 1;
463296341Sdelphij            if (num == 0) {
464296341Sdelphij                if (data->param_hostname != NULL)
465296341Sdelphij                    OPENSSL_free(data->param_hostname);
466296341Sdelphij                data->param_hostname = BUF_strdup(ptr);
467296341Sdelphij            } else if (num == 1) {
468296341Sdelphij                if (data->param_port != NULL)
469296341Sdelphij                    OPENSSL_free(data->param_port);
470296341Sdelphij                data->param_port = BUF_strdup(ptr);
471296341Sdelphij            } else if (num == 2) {
472296341Sdelphij                char buf[16];
473296341Sdelphij                unsigned char *p = ptr;
47455714Skris
475296341Sdelphij                BIO_snprintf(buf, sizeof buf, "%d.%d.%d.%d",
476296341Sdelphij                             p[0], p[1], p[2], p[3]);
477296341Sdelphij                if (data->param_hostname != NULL)
478296341Sdelphij                    OPENSSL_free(data->param_hostname);
479296341Sdelphij                data->param_hostname = BUF_strdup(buf);
480296341Sdelphij                memcpy(&(data->ip[0]), ptr, 4);
481296341Sdelphij            } else if (num == 3) {
482296341Sdelphij                char buf[DECIMAL_SIZE(int) + 1];
48355714Skris
484296341Sdelphij                BIO_snprintf(buf, sizeof buf, "%d", *(int *)ptr);
485296341Sdelphij                if (data->param_port != NULL)
486296341Sdelphij                    OPENSSL_free(data->param_port);
487296341Sdelphij                data->param_port = BUF_strdup(buf);
488296341Sdelphij                data->port = *(int *)ptr;
489296341Sdelphij            }
490296341Sdelphij        }
491296341Sdelphij        break;
492296341Sdelphij    case BIO_C_SET_NBIO:
493296341Sdelphij        data->nbio = (int)num;
494296341Sdelphij        break;
495296341Sdelphij    case BIO_C_GET_FD:
496296341Sdelphij        if (b->init) {
497296341Sdelphij            ip = (int *)ptr;
498296341Sdelphij            if (ip != NULL)
499296341Sdelphij                *ip = b->num;
500296341Sdelphij            ret = b->num;
501296341Sdelphij        } else
502296341Sdelphij            ret = -1;
503296341Sdelphij        break;
504296341Sdelphij    case BIO_CTRL_GET_CLOSE:
505296341Sdelphij        ret = b->shutdown;
506296341Sdelphij        break;
507296341Sdelphij    case BIO_CTRL_SET_CLOSE:
508296341Sdelphij        b->shutdown = (int)num;
509296341Sdelphij        break;
510296341Sdelphij    case BIO_CTRL_PENDING:
511296341Sdelphij    case BIO_CTRL_WPENDING:
512296341Sdelphij        ret = 0;
513296341Sdelphij        break;
514296341Sdelphij    case BIO_CTRL_FLUSH:
515296341Sdelphij        break;
516296341Sdelphij    case BIO_CTRL_DUP:
517296341Sdelphij        {
518296341Sdelphij            dbio = (BIO *)ptr;
519296341Sdelphij            if (data->param_port)
520296341Sdelphij                BIO_set_conn_port(dbio, data->param_port);
521296341Sdelphij            if (data->param_hostname)
522296341Sdelphij                BIO_set_conn_hostname(dbio, data->param_hostname);
523296341Sdelphij            BIO_set_nbio(dbio, data->nbio);
524296341Sdelphij            /*
525296341Sdelphij             * FIXME: the cast of the function seems unlikely to be a good
526296341Sdelphij             * idea
527296341Sdelphij             */
528296341Sdelphij            (void)BIO_set_info_callback(dbio,
529296341Sdelphij                                        (bio_info_cb *)data->info_callback);
530296341Sdelphij        }
531296341Sdelphij        break;
532296341Sdelphij    case BIO_CTRL_SET_CALLBACK:
533296341Sdelphij        {
534296341Sdelphij# if 0                          /* FIXME: Should this be used? -- Richard
535296341Sdelphij                                 * Levitte */
536296341Sdelphij            BIOerr(BIO_F_CONN_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
537296341Sdelphij            ret = -1;
538296341Sdelphij# else
539296341Sdelphij            ret = 0;
540296341Sdelphij# endif
541296341Sdelphij        }
542296341Sdelphij        break;
543296341Sdelphij    case BIO_CTRL_GET_CALLBACK:
544296341Sdelphij        {
545296341Sdelphij            int (**fptr) (const BIO *bio, int state, int xret);
54655714Skris
547296341Sdelphij            fptr = (int (**)(const BIO *bio, int state, int xret))ptr;
548296341Sdelphij            *fptr = data->info_callback;
549296341Sdelphij        }
550296341Sdelphij        break;
551296341Sdelphij    default:
552296341Sdelphij        ret = 0;
553296341Sdelphij        break;
554296341Sdelphij    }
555296341Sdelphij    return (ret);
556296341Sdelphij}
55755714Skris
55868651Skrisstatic long conn_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
559296341Sdelphij{
560296341Sdelphij    long ret = 1;
561296341Sdelphij    BIO_CONNECT *data;
56259191Skris
563296341Sdelphij    data = (BIO_CONNECT *)b->ptr;
56459191Skris
565296341Sdelphij    switch (cmd) {
566296341Sdelphij    case BIO_CTRL_SET_CALLBACK:
567296341Sdelphij        {
568296341Sdelphij            data->info_callback =
569296341Sdelphij                (int (*)(const struct bio_st *, int, int))fp;
570296341Sdelphij        }
571296341Sdelphij        break;
572296341Sdelphij    default:
573296341Sdelphij        ret = 0;
574296341Sdelphij        break;
575296341Sdelphij    }
576296341Sdelphij    return (ret);
577296341Sdelphij}
57859191Skris
57968651Skrisstatic int conn_puts(BIO *bp, const char *str)
580296341Sdelphij{
581296341Sdelphij    int n, ret;
58255714Skris
583296341Sdelphij    n = strlen(str);
584296341Sdelphij    ret = conn_write(bp, str, n);
585296341Sdelphij    return (ret);
586296341Sdelphij}
58755714Skris
58855714SkrisBIO *BIO_new_connect(char *str)
589296341Sdelphij{
590296341Sdelphij    BIO *ret;
59155714Skris
592296341Sdelphij    ret = BIO_new(BIO_s_connect());
593296341Sdelphij    if (ret == NULL)
594296341Sdelphij        return (NULL);
595296341Sdelphij    if (BIO_set_conn_hostname(ret, str))
596296341Sdelphij        return (ret);
597296341Sdelphij    else {
598296341Sdelphij        BIO_free(ret);
599296341Sdelphij        return (NULL);
600296341Sdelphij    }
601296341Sdelphij}
60255714Skris
60355714Skris#endif
604