1*80f19918Stb /* $OpenBSD: bss_conn.c,v 1.41 2024/04/19 09:54:36 tb Exp $ */
25b37fcf3Sryker /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
35b37fcf3Sryker * All rights reserved.
45b37fcf3Sryker *
55b37fcf3Sryker * This package is an SSL implementation written
65b37fcf3Sryker * by Eric Young (eay@cryptsoft.com).
75b37fcf3Sryker * The implementation was written so as to conform with Netscapes SSL.
85b37fcf3Sryker *
95b37fcf3Sryker * This library is free for commercial and non-commercial use as long as
105b37fcf3Sryker * the following conditions are aheared to. The following conditions
115b37fcf3Sryker * apply to all code found in this distribution, be it the RC4, RSA,
125b37fcf3Sryker * lhash, DES, etc., code; not just the SSL code. The SSL documentation
135b37fcf3Sryker * included with this distribution is covered by the same copyright terms
145b37fcf3Sryker * except that the holder is Tim Hudson (tjh@cryptsoft.com).
155b37fcf3Sryker *
165b37fcf3Sryker * Copyright remains Eric Young's, and as such any Copyright notices in
175b37fcf3Sryker * the code are not to be removed.
185b37fcf3Sryker * If this package is used in a product, Eric Young should be given attribution
195b37fcf3Sryker * as the author of the parts of the library used.
205b37fcf3Sryker * This can be in the form of a textual message at program startup or
215b37fcf3Sryker * in documentation (online or textual) provided with the package.
225b37fcf3Sryker *
235b37fcf3Sryker * Redistribution and use in source and binary forms, with or without
245b37fcf3Sryker * modification, are permitted provided that the following conditions
255b37fcf3Sryker * are met:
265b37fcf3Sryker * 1. Redistributions of source code must retain the copyright
275b37fcf3Sryker * notice, this list of conditions and the following disclaimer.
285b37fcf3Sryker * 2. Redistributions in binary form must reproduce the above copyright
295b37fcf3Sryker * notice, this list of conditions and the following disclaimer in the
305b37fcf3Sryker * documentation and/or other materials provided with the distribution.
315b37fcf3Sryker * 3. All advertising materials mentioning features or use of this software
325b37fcf3Sryker * must display the following acknowledgement:
335b37fcf3Sryker * "This product includes cryptographic software written by
345b37fcf3Sryker * Eric Young (eay@cryptsoft.com)"
355b37fcf3Sryker * The word 'cryptographic' can be left out if the rouines from the library
365b37fcf3Sryker * being used are not cryptographic related :-).
375b37fcf3Sryker * 4. If you include any Windows specific code (or a derivative thereof) from
385b37fcf3Sryker * the apps directory (application code) you must include an acknowledgement:
395b37fcf3Sryker * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
405b37fcf3Sryker *
415b37fcf3Sryker * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
425b37fcf3Sryker * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
435b37fcf3Sryker * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
445b37fcf3Sryker * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
455b37fcf3Sryker * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
465b37fcf3Sryker * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
475b37fcf3Sryker * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
485b37fcf3Sryker * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
495b37fcf3Sryker * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
505b37fcf3Sryker * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
515b37fcf3Sryker * SUCH DAMAGE.
525b37fcf3Sryker *
535b37fcf3Sryker * The licence and distribution terms for any publically available version or
545b37fcf3Sryker * derivative of this code cannot be changed. i.e. this code cannot simply be
555b37fcf3Sryker * copied and put under another distribution licence
565b37fcf3Sryker * [including the GNU Public Licence.]
575b37fcf3Sryker */
585b37fcf3Sryker
59edd82e4aSderaadt #include <sys/socket.h>
60a8913c44Sjsing
61edd82e4aSderaadt #include <netinet/in.h>
625b37fcf3Sryker
63a8913c44Sjsing #include <errno.h>
64a8913c44Sjsing #include <netdb.h>
65a8913c44Sjsing #include <stdio.h>
66a8913c44Sjsing #include <string.h>
67a8913c44Sjsing #include <unistd.h>
68a8913c44Sjsing
69a8913c44Sjsing #include <openssl/bio.h>
70b6ab114eSjsing #include <openssl/buffer.h>
71b6ab114eSjsing #include <openssl/err.h>
724fcf65c5Sdjm
7394b1984eStb #include "bio_local.h"
7494b1984eStb
755b37fcf3Sryker #define SOCKET_PROTOCOL IPPROTO_TCP
76913ec974Sbeck
77c3d505beSjsing typedef struct bio_connect_st {
785b37fcf3Sryker int state;
795b37fcf3Sryker
805b37fcf3Sryker char *param_hostname;
815b37fcf3Sryker char *param_port;
825b37fcf3Sryker int nbio;
835b37fcf3Sryker
845b37fcf3Sryker unsigned char ip[4];
85913ec974Sbeck unsigned short port;
865b37fcf3Sryker
875b37fcf3Sryker struct sockaddr_in them;
885b37fcf3Sryker
895b37fcf3Sryker /* int socket; this will be kept in bio->num so that it is
90ba5406e9Sbeck * compatible with the bss_sock bio */
915b37fcf3Sryker
925b37fcf3Sryker /* called when the connection is initially made
935b37fcf3Sryker * callback(BIO,state,ret); The callback should return
94ba5406e9Sbeck * 'ret'. state is for compatibility with the ssl info_callback */
95818427c5Stb BIO_info_cb *info_callback;
965b37fcf3Sryker } BIO_CONNECT;
975b37fcf3Sryker
98c109e398Sbeck static int conn_write(BIO *h, const char *buf, int num);
995b37fcf3Sryker static int conn_read(BIO *h, char *buf, int size);
100c109e398Sbeck static int conn_puts(BIO *h, const char *str);
101c109e398Sbeck static long conn_ctrl(BIO *h, int cmd, long arg1, void *arg2);
1025b37fcf3Sryker static int conn_new(BIO *h);
1035b37fcf3Sryker static int conn_free(BIO *data);
104818427c5Stb static long conn_callback_ctrl(BIO *h, int cmd, BIO_info_cb *);
1055b37fcf3Sryker
1065b37fcf3Sryker static int conn_state(BIO *b, BIO_CONNECT *c);
1075b37fcf3Sryker static void conn_close_socket(BIO *data);
1082054f1f1Stb static BIO_CONNECT *BIO_CONNECT_new(void);
1092054f1f1Stb static void BIO_CONNECT_free(BIO_CONNECT *a);
1105b37fcf3Sryker
1116dc76777Stb static const BIO_METHOD methods_connectp = {
112e402ce74Smiod .type = BIO_TYPE_CONNECT,
113e402ce74Smiod .name = "socket connect",
114e402ce74Smiod .bwrite = conn_write,
115e402ce74Smiod .bread = conn_read,
116e402ce74Smiod .bputs = conn_puts,
117e402ce74Smiod .ctrl = conn_ctrl,
118e402ce74Smiod .create = conn_new,
119e402ce74Smiod .destroy = conn_free,
120e402ce74Smiod .callback_ctrl = conn_callback_ctrl
1215b37fcf3Sryker };
1225b37fcf3Sryker
123c3d505beSjsing static int
conn_state(BIO * b,BIO_CONNECT * c)124c3d505beSjsing conn_state(BIO *b, BIO_CONNECT *c)
1255b37fcf3Sryker {
1265b37fcf3Sryker int ret = -1, i;
1275b37fcf3Sryker unsigned long l;
1285b37fcf3Sryker char *p, *q;
129818427c5Stb BIO_info_cb *cb = NULL;
1305b37fcf3Sryker
1315b37fcf3Sryker if (c->info_callback != NULL)
1325b37fcf3Sryker cb = c->info_callback;
1335b37fcf3Sryker
134c3d505beSjsing for (;;) {
135c3d505beSjsing switch (c->state) {
1365b37fcf3Sryker case BIO_CONN_S_BEFORE:
1375b37fcf3Sryker p = c->param_hostname;
138c3d505beSjsing if (p == NULL) {
1395067ae9fSbeck BIOerror(BIO_R_NO_HOSTNAME_SPECIFIED);
1405b37fcf3Sryker goto exit_loop;
1415b37fcf3Sryker }
142c3d505beSjsing for (; *p != '\0'; p++) {
143c3d505beSjsing if ((*p == ':') || (*p == '/'))
144c3d505beSjsing break;
1455b37fcf3Sryker }
1465b37fcf3Sryker
1475b37fcf3Sryker i= *p;
148c3d505beSjsing if ((i == ':') || (i == '/')) {
1495b37fcf3Sryker *(p++) = '\0';
150c3d505beSjsing if (i == ':') {
1515b37fcf3Sryker for (q = p; *q; q++)
152c3d505beSjsing if (*q == '/') {
1535b37fcf3Sryker *q = '\0';
1545b37fcf3Sryker break;
1555b37fcf3Sryker }
1566f3a6cb1Sbeck free(c->param_port);
15774a2cbdcSbeck c->param_port = strdup(p);
1585b37fcf3Sryker }
1595b37fcf3Sryker }
1605b37fcf3Sryker
161c3d505beSjsing if (c->param_port == NULL) {
1625067ae9fSbeck BIOerror(BIO_R_NO_PORT_SPECIFIED);
1630f637b92Sbeck ERR_asprintf_error_data("host=%s",
1640f637b92Sbeck c->param_hostname);
1655b37fcf3Sryker goto exit_loop;
1665b37fcf3Sryker }
1675b37fcf3Sryker c->state = BIO_CONN_S_GET_IP;
1685b37fcf3Sryker break;
1695b37fcf3Sryker
1705b37fcf3Sryker case BIO_CONN_S_GET_IP:
1715b37fcf3Sryker if (BIO_get_host_ip(c->param_hostname, &(c->ip[0])) <= 0)
1725b37fcf3Sryker goto exit_loop;
1735b37fcf3Sryker c->state = BIO_CONN_S_GET_PORT;
1745b37fcf3Sryker break;
1755b37fcf3Sryker
1765b37fcf3Sryker case BIO_CONN_S_GET_PORT:
177c3d505beSjsing if (c->param_port == NULL) {
178c109e398Sbeck /* abort(); */
179913ec974Sbeck goto exit_loop;
180c3d505beSjsing } else if (BIO_get_port(c->param_port, &c->port) <= 0)
1815b37fcf3Sryker goto exit_loop;
1825b37fcf3Sryker c->state = BIO_CONN_S_CREATE_SOCKET;
1835b37fcf3Sryker break;
1845b37fcf3Sryker
1855b37fcf3Sryker case BIO_CONN_S_CREATE_SOCKET:
1865b37fcf3Sryker /* now setup address */
1875b37fcf3Sryker memset((char *)&c->them, 0, sizeof(c->them));
1885b37fcf3Sryker c->them.sin_family = AF_INET;
1895b37fcf3Sryker c->them.sin_port = htons((unsigned short)c->port);
1905b37fcf3Sryker l = (unsigned long)
1915b37fcf3Sryker ((unsigned long)c->ip[0] << 24L)|
1925b37fcf3Sryker ((unsigned long)c->ip[1] << 16L)|
1935b37fcf3Sryker ((unsigned long)c->ip[2] << 8L)|
1945b37fcf3Sryker ((unsigned long)c->ip[3]);
1955b37fcf3Sryker c->them.sin_addr.s_addr = htonl(l);
1965b37fcf3Sryker c->state = BIO_CONN_S_CREATE_SOCKET;
1975b37fcf3Sryker
1985b37fcf3Sryker ret = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL);
199c3d505beSjsing if (ret == -1) {
2005067ae9fSbeck SYSerror(errno);
2010f637b92Sbeck ERR_asprintf_error_data("host=%s:%s",
2020f637b92Sbeck c->param_hostname, c->param_port);
2035067ae9fSbeck BIOerror(BIO_R_UNABLE_TO_CREATE_SOCKET);
2045b37fcf3Sryker goto exit_loop;
2055b37fcf3Sryker }
2065b37fcf3Sryker b->num = ret;
2075b37fcf3Sryker c->state = BIO_CONN_S_NBIO;
2085b37fcf3Sryker break;
2095b37fcf3Sryker
2105b37fcf3Sryker case BIO_CONN_S_NBIO:
211c3d505beSjsing if (c->nbio) {
212c3d505beSjsing if (!BIO_socket_nbio(b->num, 1)) {
2135067ae9fSbeck BIOerror(BIO_R_ERROR_SETTING_NBIO);
2140f637b92Sbeck ERR_asprintf_error_data("host=%s:%s",
2150f637b92Sbeck c->param_hostname, c->param_port);
2165b37fcf3Sryker goto exit_loop;
2175b37fcf3Sryker }
2185b37fcf3Sryker }
2195b37fcf3Sryker c->state = BIO_CONN_S_CONNECT;
2205b37fcf3Sryker
221f02102f5Sderaadt #if defined(SO_KEEPALIVE)
2225b37fcf3Sryker i = 1;
223c0f961d4Sbcook i = setsockopt(b->num, SOL_SOCKET, SO_KEEPALIVE, &i, sizeof(i));
224c3d505beSjsing if (i < 0) {
2255067ae9fSbeck SYSerror(errno);
2260f637b92Sbeck ERR_asprintf_error_data("host=%s:%s",
2270f637b92Sbeck c->param_hostname, c->param_port);
2285067ae9fSbeck BIOerror(BIO_R_KEEPALIVE);
2295b37fcf3Sryker goto exit_loop;
2305b37fcf3Sryker }
2315b37fcf3Sryker #endif
2325b37fcf3Sryker break;
2335b37fcf3Sryker
2345b37fcf3Sryker case BIO_CONN_S_CONNECT:
2355b37fcf3Sryker BIO_clear_retry_flags(b);
2365b37fcf3Sryker ret = connect(b->num,
2375b37fcf3Sryker (struct sockaddr *)&c->them,
2385b37fcf3Sryker sizeof(c->them));
2395b37fcf3Sryker b->retry_reason = 0;
240c3d505beSjsing if (ret < 0) {
241c3d505beSjsing if (BIO_sock_should_retry(ret)) {
2425b37fcf3Sryker BIO_set_retry_special(b);
2435b37fcf3Sryker c->state = BIO_CONN_S_BLOCKED_CONNECT;
2445b37fcf3Sryker b->retry_reason = BIO_RR_CONNECT;
245c3d505beSjsing } else {
2465067ae9fSbeck SYSerror(errno);
2470f637b92Sbeck ERR_asprintf_error_data("host=%s:%s",
2480f637b92Sbeck c->param_hostname, c->param_port);
2495067ae9fSbeck BIOerror(BIO_R_CONNECT_ERROR);
2505b37fcf3Sryker }
2515b37fcf3Sryker goto exit_loop;
252c3d505beSjsing } else
2535b37fcf3Sryker c->state = BIO_CONN_S_OK;
2545b37fcf3Sryker break;
2555b37fcf3Sryker
2565b37fcf3Sryker case BIO_CONN_S_BLOCKED_CONNECT:
2575b37fcf3Sryker i = BIO_sock_error(b->num);
258c3d505beSjsing if (i) {
2595b37fcf3Sryker BIO_clear_retry_flags(b);
2605067ae9fSbeck SYSerror(i);
2610f637b92Sbeck ERR_asprintf_error_data("host=%s:%s",
2620f637b92Sbeck c->param_hostname, c->param_port);
2635067ae9fSbeck BIOerror(BIO_R_NBIO_CONNECT_ERROR);
2645b37fcf3Sryker ret = 0;
2655b37fcf3Sryker goto exit_loop;
266c3d505beSjsing } else
2675b37fcf3Sryker c->state = BIO_CONN_S_OK;
2685b37fcf3Sryker break;
2695b37fcf3Sryker
2705b37fcf3Sryker case BIO_CONN_S_OK:
2715b37fcf3Sryker ret = 1;
2725b37fcf3Sryker goto exit_loop;
2735b37fcf3Sryker default:
274c109e398Sbeck /* abort(); */
2755b37fcf3Sryker goto exit_loop;
2765b37fcf3Sryker }
2775b37fcf3Sryker
278c3d505beSjsing if (cb != NULL) {
2795b37fcf3Sryker if (!(ret = cb((BIO *)b, c->state, ret)))
2805b37fcf3Sryker goto end;
2815b37fcf3Sryker }
2825b37fcf3Sryker }
2835b37fcf3Sryker
284913ec974Sbeck /* Loop does not exit */
2855b37fcf3Sryker exit_loop:
2865b37fcf3Sryker if (cb != NULL)
2875b37fcf3Sryker ret = cb((BIO *)b, c->state, ret);
2885b37fcf3Sryker end:
2895b37fcf3Sryker return (ret);
2905b37fcf3Sryker }
2915b37fcf3Sryker
2922054f1f1Stb static BIO_CONNECT *
BIO_CONNECT_new(void)293ae7f143bSderaadt BIO_CONNECT_new(void)
2945b37fcf3Sryker {
2955b37fcf3Sryker BIO_CONNECT *ret;
2965b37fcf3Sryker
2973c6fe066Sderaadt if ((ret = malloc(sizeof(BIO_CONNECT))) == NULL)
2985b37fcf3Sryker return (NULL);
2995b37fcf3Sryker ret->state = BIO_CONN_S_BEFORE;
3005b37fcf3Sryker ret->param_hostname = NULL;
3015b37fcf3Sryker ret->param_port = NULL;
3025b37fcf3Sryker ret->info_callback = NULL;
3035b37fcf3Sryker ret->nbio = 0;
3045b37fcf3Sryker ret->ip[0] = 0;
3055b37fcf3Sryker ret->ip[1] = 0;
3065b37fcf3Sryker ret->ip[2] = 0;
3075b37fcf3Sryker ret->ip[3] = 0;
3085b37fcf3Sryker ret->port = 0;
3095b37fcf3Sryker memset((char *)&ret->them, 0, sizeof(ret->them));
3105b37fcf3Sryker return (ret);
3115b37fcf3Sryker }
3125b37fcf3Sryker
3132054f1f1Stb static void
BIO_CONNECT_free(BIO_CONNECT * a)314c3d505beSjsing BIO_CONNECT_free(BIO_CONNECT *a)
3155b37fcf3Sryker {
316913ec974Sbeck if (a == NULL)
317913ec974Sbeck return;
318913ec974Sbeck
3196f3a6cb1Sbeck free(a->param_hostname);
3206f3a6cb1Sbeck free(a->param_port);
3216f3a6cb1Sbeck free(a);
3225b37fcf3Sryker }
3235b37fcf3Sryker
3246dc76777Stb const BIO_METHOD *
BIO_s_connect(void)325ae7f143bSderaadt BIO_s_connect(void)
3265b37fcf3Sryker {
3275b37fcf3Sryker return (&methods_connectp);
3285b37fcf3Sryker }
329acf64401Sbeck LCRYPTO_ALIAS(BIO_s_connect);
3305b37fcf3Sryker
331c3d505beSjsing static int
conn_new(BIO * bi)332c3d505beSjsing conn_new(BIO *bi)
3335b37fcf3Sryker {
3345b37fcf3Sryker bi->init = 0;
3359ee38ff1Sderaadt bi->num = -1;
3365b37fcf3Sryker bi->flags = 0;
3375b37fcf3Sryker if ((bi->ptr = (char *)BIO_CONNECT_new()) == NULL)
3385b37fcf3Sryker return (0);
3395b37fcf3Sryker else
3405b37fcf3Sryker return (1);
3415b37fcf3Sryker }
3425b37fcf3Sryker
343c3d505beSjsing static void
conn_close_socket(BIO * bio)344c3d505beSjsing conn_close_socket(BIO *bio)
3455b37fcf3Sryker {
3465b37fcf3Sryker BIO_CONNECT *c;
3475b37fcf3Sryker
3485b37fcf3Sryker c = (BIO_CONNECT *)bio->ptr;
349c3d505beSjsing if (bio->num != -1) {
3505b37fcf3Sryker /* Only do a shutdown if things were established */
3515b37fcf3Sryker if (c->state == BIO_CONN_S_OK)
352483aac3eSmatthew shutdown(bio->num, SHUT_RDWR);
3539ee38ff1Sderaadt close(bio->num);
3549ee38ff1Sderaadt bio->num = -1;
3555b37fcf3Sryker }
3565b37fcf3Sryker }
3575b37fcf3Sryker
358c3d505beSjsing static int
conn_free(BIO * a)359c3d505beSjsing conn_free(BIO *a)
3605b37fcf3Sryker {
3615b37fcf3Sryker BIO_CONNECT *data;
3625b37fcf3Sryker
363c3d505beSjsing if (a == NULL)
364c3d505beSjsing return (0);
3655b37fcf3Sryker data = (BIO_CONNECT *)a->ptr;
3665b37fcf3Sryker
367c3d505beSjsing if (a->shutdown) {
3685b37fcf3Sryker conn_close_socket(a);
3695b37fcf3Sryker BIO_CONNECT_free(data);
3705b37fcf3Sryker a->ptr = NULL;
3715b37fcf3Sryker a->flags = 0;
3725b37fcf3Sryker a->init = 0;
3735b37fcf3Sryker }
3745b37fcf3Sryker return (1);
3755b37fcf3Sryker }
3765b37fcf3Sryker
377c3d505beSjsing static int
conn_read(BIO * b,char * out,int outl)378c3d505beSjsing conn_read(BIO *b, char *out, int outl)
3795b37fcf3Sryker {
3805b37fcf3Sryker int ret = 0;
3815b37fcf3Sryker BIO_CONNECT *data;
3825b37fcf3Sryker
3835b37fcf3Sryker data = (BIO_CONNECT *)b->ptr;
384c3d505beSjsing if (data->state != BIO_CONN_S_OK) {
3855b37fcf3Sryker ret = conn_state(b, data);
3865b37fcf3Sryker if (ret <= 0)
3875b37fcf3Sryker return (ret);
3885b37fcf3Sryker }
3895b37fcf3Sryker
390c3d505beSjsing if (out != NULL) {
3919ee38ff1Sderaadt errno = 0;
3929ee38ff1Sderaadt ret = read(b->num, out, outl);
3935b37fcf3Sryker BIO_clear_retry_flags(b);
394c3d505beSjsing if (ret <= 0) {
3955b37fcf3Sryker if (BIO_sock_should_retry(ret))
3965b37fcf3Sryker BIO_set_retry_read(b);
3975b37fcf3Sryker }
3985b37fcf3Sryker }
3995b37fcf3Sryker return (ret);
4005b37fcf3Sryker }
4015b37fcf3Sryker
402c3d505beSjsing static int
conn_write(BIO * b,const char * in,int inl)403c3d505beSjsing conn_write(BIO *b, const char *in, int inl)
4045b37fcf3Sryker {
4055b37fcf3Sryker int ret;
4065b37fcf3Sryker BIO_CONNECT *data;
4075b37fcf3Sryker
4085b37fcf3Sryker data = (BIO_CONNECT *)b->ptr;
409c3d505beSjsing if (data->state != BIO_CONN_S_OK) {
4105b37fcf3Sryker ret = conn_state(b, data);
411c3d505beSjsing if (ret <= 0)
412c3d505beSjsing return (ret);
4135b37fcf3Sryker }
4145b37fcf3Sryker
4159ee38ff1Sderaadt errno = 0;
4169ee38ff1Sderaadt ret = write(b->num, in, inl);
4175b37fcf3Sryker BIO_clear_retry_flags(b);
418c3d505beSjsing if (ret <= 0) {
4195b37fcf3Sryker if (BIO_sock_should_retry(ret))
4205b37fcf3Sryker BIO_set_retry_write(b);
4215b37fcf3Sryker }
4225b37fcf3Sryker return (ret);
4235b37fcf3Sryker }
4245b37fcf3Sryker
425c3d505beSjsing static long
conn_ctrl(BIO * b,int cmd,long num,void * ptr)426c3d505beSjsing conn_ctrl(BIO *b, int cmd, long num, void *ptr)
4275b37fcf3Sryker {
4285b37fcf3Sryker BIO *dbio;
4295b37fcf3Sryker int *ip;
430913ec974Sbeck const char **pptr;
4315b37fcf3Sryker long ret = 1;
4325b37fcf3Sryker BIO_CONNECT *data;
4335b37fcf3Sryker
4345b37fcf3Sryker data = (BIO_CONNECT *)b->ptr;
4355b37fcf3Sryker
436c3d505beSjsing switch (cmd) {
4375b37fcf3Sryker case BIO_CTRL_RESET:
4385b37fcf3Sryker ret = 0;
4395b37fcf3Sryker data->state = BIO_CONN_S_BEFORE;
4405b37fcf3Sryker conn_close_socket(b);
4415b37fcf3Sryker b->flags = 0;
4425b37fcf3Sryker break;
4435b37fcf3Sryker case BIO_C_DO_STATE_MACHINE:
4445b37fcf3Sryker /* use this one to start the connection */
4456d388760Sdjm if (data->state != BIO_CONN_S_OK)
4465b37fcf3Sryker ret = (long)conn_state(b, data);
4475b37fcf3Sryker else
4485b37fcf3Sryker ret = 1;
4495b37fcf3Sryker break;
4505b37fcf3Sryker case BIO_C_GET_CONNECT:
451c3d505beSjsing if (ptr != NULL) {
452913ec974Sbeck pptr = (const char **)ptr;
453c3d505beSjsing if (num == 0) {
4545b37fcf3Sryker *pptr = data->param_hostname;
4555b37fcf3Sryker
456c3d505beSjsing } else if (num == 1) {
4575b37fcf3Sryker *pptr = data->param_port;
458c3d505beSjsing } else if (num == 2) {
4595b37fcf3Sryker *pptr = (char *)&(data->ip[0]);
460c3d505beSjsing } else if (num == 3) {
4615b37fcf3Sryker *((int *)ptr) = data->port;
4625b37fcf3Sryker }
4635b37fcf3Sryker if ((!b->init) || (ptr == NULL))
464ba5406e9Sbeck *pptr = "not initialized";
4655b37fcf3Sryker ret = 1;
4665b37fcf3Sryker }
4675b37fcf3Sryker break;
4685b37fcf3Sryker case BIO_C_SET_CONNECT:
469c3d505beSjsing if (ptr != NULL) {
4705b37fcf3Sryker b->init = 1;
471c3d505beSjsing if (num == 0) {
4726f3a6cb1Sbeck free(data->param_hostname);
47374a2cbdcSbeck data->param_hostname = strdup(ptr);
474c3d505beSjsing } else if (num == 1) {
4756f3a6cb1Sbeck free(data->param_port);
47674a2cbdcSbeck data->param_port = strdup(ptr);
477c3d505beSjsing } else if (num == 2) {
478767fe2ffSmarkus unsigned char *p = ptr;
4796f3a6cb1Sbeck free(data->param_hostname);
480a670ac58Sbeck if (asprintf(&data->param_hostname,
481a670ac58Sbeck "%u.%u.%u.%u", p[0], p[1],
482a670ac58Sbeck p[2], p[3]) == -1)
483a670ac58Sbeck data->param_hostname = NULL;
484913ec974Sbeck memcpy(&(data->ip[0]), ptr, 4);
485c3d505beSjsing } else if (num == 3) {
4866f3a6cb1Sbeck free(data->param_port);
4875b37fcf3Sryker data->port= *(int *)ptr;
488a670ac58Sbeck if (asprintf(&data->param_port, "%d",
489a670ac58Sbeck data->port) == -1)
490a670ac58Sbeck data->param_port = NULL;
4915b37fcf3Sryker }
492913ec974Sbeck }
4935b37fcf3Sryker break;
4945b37fcf3Sryker case BIO_C_SET_NBIO:
4955b37fcf3Sryker data->nbio = (int)num;
4965b37fcf3Sryker break;
4975b37fcf3Sryker case BIO_C_GET_FD:
498c3d505beSjsing if (b->init) {
4995b37fcf3Sryker ip = (int *)ptr;
5005b37fcf3Sryker if (ip != NULL)
5015b37fcf3Sryker *ip = b->num;
5025b37fcf3Sryker ret = b->num;
503c3d505beSjsing } else
5045b37fcf3Sryker ret = -1;
5055b37fcf3Sryker break;
5065b37fcf3Sryker case BIO_CTRL_GET_CLOSE:
5075b37fcf3Sryker ret = b->shutdown;
5085b37fcf3Sryker break;
5095b37fcf3Sryker case BIO_CTRL_SET_CLOSE:
5105b37fcf3Sryker b->shutdown = (int)num;
5115b37fcf3Sryker break;
5125b37fcf3Sryker case BIO_CTRL_PENDING:
5135b37fcf3Sryker case BIO_CTRL_WPENDING:
5145b37fcf3Sryker ret = 0;
5155b37fcf3Sryker break;
5165b37fcf3Sryker case BIO_CTRL_FLUSH:
5175b37fcf3Sryker break;
5185b37fcf3Sryker case BIO_CTRL_DUP:
519ba5406e9Sbeck {
5205b37fcf3Sryker dbio = (BIO *)ptr;
5215b37fcf3Sryker if (data->param_port)
5225b37fcf3Sryker BIO_set_conn_port(dbio, data->param_port);
5235b37fcf3Sryker if (data->param_hostname)
524c3d505beSjsing BIO_set_conn_hostname(dbio,
525c3d505beSjsing data->param_hostname);
5265b37fcf3Sryker BIO_set_nbio(dbio, data->nbio);
527818427c5Stb (void)BIO_set_info_callback(dbio, data->info_callback);
528ba5406e9Sbeck }
5295b37fcf3Sryker break;
5305b37fcf3Sryker case BIO_CTRL_SET_CALLBACK:
531ba5406e9Sbeck {
532ba5406e9Sbeck #if 0 /* FIXME: Should this be used? -- Richard Levitte */
5335067ae9fSbeck BIOerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
534ba5406e9Sbeck ret = -1;
535ba5406e9Sbeck #else
536ba5406e9Sbeck ret = 0;
537ba5406e9Sbeck #endif
538ba5406e9Sbeck }
5395b37fcf3Sryker break;
5405b37fcf3Sryker case BIO_CTRL_GET_CALLBACK:
5415b37fcf3Sryker {
542818427c5Stb BIO_info_cb **fptr = ptr;
5435b37fcf3Sryker
5445b37fcf3Sryker *fptr = data->info_callback;
5455b37fcf3Sryker }
5465b37fcf3Sryker break;
5475b37fcf3Sryker default:
5485b37fcf3Sryker ret = 0;
5495b37fcf3Sryker break;
5505b37fcf3Sryker }
5515b37fcf3Sryker return (ret);
5525b37fcf3Sryker }
5535b37fcf3Sryker
554c3d505beSjsing static long
conn_callback_ctrl(BIO * b,int cmd,BIO_info_cb * fp)555818427c5Stb conn_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
556ba5406e9Sbeck {
557ba5406e9Sbeck long ret = 1;
558ba5406e9Sbeck BIO_CONNECT *data;
559ba5406e9Sbeck
560ba5406e9Sbeck data = (BIO_CONNECT *)b->ptr;
561ba5406e9Sbeck
562c3d505beSjsing switch (cmd) {
563ba5406e9Sbeck case BIO_CTRL_SET_CALLBACK:
564818427c5Stb data->info_callback = (BIO_info_cb *)fp;
565ba5406e9Sbeck break;
566ba5406e9Sbeck default:
567ba5406e9Sbeck ret = 0;
568ba5406e9Sbeck break;
569ba5406e9Sbeck }
570ba5406e9Sbeck return (ret);
571ba5406e9Sbeck }
572ba5406e9Sbeck
573c3d505beSjsing static int
conn_puts(BIO * bp,const char * str)574c3d505beSjsing conn_puts(BIO *bp, const char *str)
5755b37fcf3Sryker {
5765b37fcf3Sryker int n, ret;
5775b37fcf3Sryker
5785b37fcf3Sryker n = strlen(str);
5795b37fcf3Sryker ret = conn_write(bp, str, n);
5805b37fcf3Sryker return (ret);
5815b37fcf3Sryker }
5825b37fcf3Sryker
583ae7f143bSderaadt BIO *
BIO_new_connect(const char * str)58491427bf7Stb BIO_new_connect(const char *str)
5855b37fcf3Sryker {
5865b37fcf3Sryker BIO *ret;
5875b37fcf3Sryker
5885b37fcf3Sryker ret = BIO_new(BIO_s_connect());
589c3d505beSjsing if (ret == NULL)
590c3d505beSjsing return (NULL);
5915b37fcf3Sryker if (BIO_set_conn_hostname(ret, str))
5925b37fcf3Sryker return (ret);
593c3d505beSjsing else {
5945b37fcf3Sryker BIO_free(ret);
5955b37fcf3Sryker return (NULL);
5965b37fcf3Sryker }
5975b37fcf3Sryker }
598acf64401Sbeck LCRYPTO_ALIAS(BIO_new_connect);
599