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.
855714Skris *
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).
1555714Skris *
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.
2255714Skris *
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 :-).
3755714Skris * 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)"
4055714Skris *
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.
5255714Skris *
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
67109998Smarkm#ifdef OPENSSL_SYS_WIN16
6855714Skris#define SOCKET_PROTOCOL 0 /* more microsoft stupidity */
6955714Skris#else
7055714Skris#define SOCKET_PROTOCOL IPPROTO_TCP
7155714Skris#endif
7255714Skris
73109998Smarkm#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 */
7555714Skris#undef FIONBIO
7655714Skris#endif
7755714Skris
7855714Skris
7955714Skristypedef struct bio_connect_st
8055714Skris	{
8155714Skris	int state;
8255714Skris
8355714Skris	char *param_hostname;
8455714Skris	char *param_port;
8555714Skris	int nbio;
8655714Skris
8755714Skris	unsigned char ip[4];
8855714Skris	unsigned short port;
8955714Skris
9055714Skris	struct sockaddr_in them;
9155714Skris
9255714Skris	/* int socket; this will be kept in bio->num so that it is
9359191Skris	 * compatible with the bss_sock bio */
9455714Skris
9555714Skris	/* called when the connection is initially made
9655714Skris	 *  callback(BIO,state,ret);  The callback should return
9759191Skris	 * 'ret'.  state is for compatibility with the ssl info_callback */
98109998Smarkm	int (*info_callback)(const BIO *bio,int state,int ret);
9955714Skris	} BIO_CONNECT;
10055714Skris
10168651Skrisstatic int conn_write(BIO *h, const char *buf, int num);
10268651Skrisstatic int conn_read(BIO *h, char *buf, int size);
10368651Skrisstatic int conn_puts(BIO *h, const char *str);
10468651Skrisstatic long conn_ctrl(BIO *h, int cmd, long arg1, void *arg2);
10555714Skrisstatic int conn_new(BIO *h);
10655714Skrisstatic int conn_free(BIO *data);
10768651Skrisstatic long conn_callback_ctrl(BIO *h, int cmd, bio_info_cb *);
10855714Skris
10955714Skrisstatic int conn_state(BIO *b, BIO_CONNECT *c);
11055714Skrisstatic void conn_close_socket(BIO *data);
11155714SkrisBIO_CONNECT *BIO_CONNECT_new(void );
11255714Skrisvoid BIO_CONNECT_free(BIO_CONNECT *a);
11355714Skris
11455714Skrisstatic BIO_METHOD methods_connectp=
11555714Skris	{
11655714Skris	BIO_TYPE_CONNECT,
11755714Skris	"socket connect",
11855714Skris	conn_write,
11955714Skris	conn_read,
12055714Skris	conn_puts,
12155714Skris	NULL, /* connect_gets, */
12255714Skris	conn_ctrl,
12355714Skris	conn_new,
12455714Skris	conn_free,
12559191Skris	conn_callback_ctrl,
12655714Skris	};
12755714Skris
12855714Skrisstatic int conn_state(BIO *b, BIO_CONNECT *c)
12955714Skris	{
13055714Skris	int ret= -1,i;
13155714Skris	unsigned long l;
13255714Skris	char *p,*q;
133160814Ssimon	int (*cb)(const BIO *,int,int)=NULL;
13455714Skris
13555714Skris	if (c->info_callback != NULL)
13655714Skris		cb=c->info_callback;
13755714Skris
13855714Skris	for (;;)
13955714Skris		{
14055714Skris		switch (c->state)
14155714Skris			{
14255714Skris		case BIO_CONN_S_BEFORE:
14355714Skris			p=c->param_hostname;
14455714Skris			if (p == NULL)
14555714Skris				{
14655714Skris				BIOerr(BIO_F_CONN_STATE,BIO_R_NO_HOSTNAME_SPECIFIED);
14755714Skris				goto exit_loop;
14855714Skris				}
14955714Skris			for ( ; *p != '\0'; p++)
15055714Skris				{
15155714Skris				if ((*p == ':') || (*p == '/')) break;
15255714Skris				}
15355714Skris
15455714Skris			i= *p;
15555714Skris			if ((i == ':') || (i == '/'))
15655714Skris				{
15755714Skris
15855714Skris				*(p++)='\0';
15955714Skris				if (i == ':')
16055714Skris					{
16155714Skris					for (q=p; *q; q++)
16255714Skris						if (*q == '/')
16355714Skris							{
16455714Skris							*q='\0';
16555714Skris							break;
16655714Skris							}
16755714Skris					if (c->param_port != NULL)
16868651Skris						OPENSSL_free(c->param_port);
16955714Skris					c->param_port=BUF_strdup(p);
17055714Skris					}
17155714Skris				}
17255714Skris
17355714Skris			if (c->param_port == NULL)
17455714Skris				{
17555714Skris				BIOerr(BIO_F_CONN_STATE,BIO_R_NO_PORT_SPECIFIED);
17655714Skris				ERR_add_error_data(2,"host=",c->param_hostname);
17755714Skris				goto exit_loop;
17855714Skris				}
17955714Skris			c->state=BIO_CONN_S_GET_IP;
18055714Skris			break;
18155714Skris
18255714Skris		case BIO_CONN_S_GET_IP:
18355714Skris			if (BIO_get_host_ip(c->param_hostname,&(c->ip[0])) <= 0)
18455714Skris				goto exit_loop;
18555714Skris			c->state=BIO_CONN_S_GET_PORT;
18655714Skris			break;
18755714Skris
18855714Skris		case BIO_CONN_S_GET_PORT:
18955714Skris			if (c->param_port == NULL)
19055714Skris				{
19168651Skris				/* abort(); */
19255714Skris				goto exit_loop;
19355714Skris				}
19455714Skris			else if (BIO_get_port(c->param_port,&c->port) <= 0)
19555714Skris				goto exit_loop;
19655714Skris			c->state=BIO_CONN_S_CREATE_SOCKET;
19755714Skris			break;
19855714Skris
19955714Skris		case BIO_CONN_S_CREATE_SOCKET:
20055714Skris			/* now setup address */
20155714Skris			memset((char *)&c->them,0,sizeof(c->them));
20255714Skris			c->them.sin_family=AF_INET;
20355714Skris			c->them.sin_port=htons((unsigned short)c->port);
20455714Skris			l=(unsigned long)
20555714Skris				((unsigned long)c->ip[0]<<24L)|
20655714Skris				((unsigned long)c->ip[1]<<16L)|
20755714Skris				((unsigned long)c->ip[2]<< 8L)|
20855714Skris				((unsigned long)c->ip[3]);
20955714Skris			c->them.sin_addr.s_addr=htonl(l);
21055714Skris			c->state=BIO_CONN_S_CREATE_SOCKET;
21155714Skris
21255714Skris			ret=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
21355714Skris			if (ret == INVALID_SOCKET)
21455714Skris				{
21555714Skris				SYSerr(SYS_F_SOCKET,get_last_socket_error());
21655714Skris				ERR_add_error_data(4,"host=",c->param_hostname,
21755714Skris					":",c->param_port);
21855714Skris				BIOerr(BIO_F_CONN_STATE,BIO_R_UNABLE_TO_CREATE_SOCKET);
21955714Skris				goto exit_loop;
22055714Skris				}
22155714Skris			b->num=ret;
22255714Skris			c->state=BIO_CONN_S_NBIO;
22355714Skris			break;
22455714Skris
22555714Skris		case BIO_CONN_S_NBIO:
22655714Skris			if (c->nbio)
22755714Skris				{
22855714Skris				if (!BIO_socket_nbio(b->num,1))
22955714Skris					{
23055714Skris					BIOerr(BIO_F_CONN_STATE,BIO_R_ERROR_SETTING_NBIO);
23155714Skris					ERR_add_error_data(4,"host=",
23255714Skris						c->param_hostname,
23355714Skris						":",c->param_port);
23455714Skris					goto exit_loop;
23555714Skris					}
23655714Skris				}
23755714Skris			c->state=BIO_CONN_S_CONNECT;
23855714Skris
239109998Smarkm#if defined(SO_KEEPALIVE) && !defined(OPENSSL_SYS_MPE)
24055714Skris			i=1;
24155714Skris			i=setsockopt(b->num,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
24255714Skris			if (i < 0)
24355714Skris				{
24455714Skris				SYSerr(SYS_F_SOCKET,get_last_socket_error());
24555714Skris				ERR_add_error_data(4,"host=",c->param_hostname,
24655714Skris					":",c->param_port);
24755714Skris				BIOerr(BIO_F_CONN_STATE,BIO_R_KEEPALIVE);
24855714Skris				goto exit_loop;
24955714Skris				}
25055714Skris#endif
25155714Skris			break;
25255714Skris
25355714Skris		case BIO_CONN_S_CONNECT:
25455714Skris			BIO_clear_retry_flags(b);
25555714Skris			ret=connect(b->num,
25655714Skris				(struct sockaddr *)&c->them,
25755714Skris				sizeof(c->them));
25855714Skris			b->retry_reason=0;
25955714Skris			if (ret < 0)
26055714Skris				{
26155714Skris				if (BIO_sock_should_retry(ret))
26255714Skris					{
26355714Skris					BIO_set_retry_special(b);
26455714Skris					c->state=BIO_CONN_S_BLOCKED_CONNECT;
26555714Skris					b->retry_reason=BIO_RR_CONNECT;
26655714Skris					}
26755714Skris				else
26855714Skris					{
26955714Skris					SYSerr(SYS_F_CONNECT,get_last_socket_error());
27055714Skris					ERR_add_error_data(4,"host=",
27155714Skris						c->param_hostname,
27255714Skris						":",c->param_port);
27355714Skris					BIOerr(BIO_F_CONN_STATE,BIO_R_CONNECT_ERROR);
27455714Skris					}
27555714Skris				goto exit_loop;
27655714Skris				}
27755714Skris			else
27855714Skris				c->state=BIO_CONN_S_OK;
27955714Skris			break;
28055714Skris
28155714Skris		case BIO_CONN_S_BLOCKED_CONNECT:
28255714Skris			i=BIO_sock_error(b->num);
28355714Skris			if (i)
28455714Skris				{
28555714Skris				BIO_clear_retry_flags(b);
28655714Skris				SYSerr(SYS_F_CONNECT,i);
28755714Skris				ERR_add_error_data(4,"host=",
28855714Skris					c->param_hostname,
28955714Skris					":",c->param_port);
29055714Skris				BIOerr(BIO_F_CONN_STATE,BIO_R_NBIO_CONNECT_ERROR);
29155714Skris				ret=0;
29255714Skris				goto exit_loop;
29355714Skris				}
29455714Skris			else
29555714Skris				c->state=BIO_CONN_S_OK;
29655714Skris			break;
29755714Skris
29855714Skris		case BIO_CONN_S_OK:
29955714Skris			ret=1;
30055714Skris			goto exit_loop;
30155714Skris		default:
30268651Skris			/* abort(); */
30355714Skris			goto exit_loop;
30455714Skris			}
30555714Skris
30655714Skris		if (cb != NULL)
30755714Skris			{
30855714Skris			if (!(ret=cb((BIO *)b,c->state,ret)))
30955714Skris				goto end;
31055714Skris			}
31155714Skris		}
31255714Skris
31355714Skris	/* Loop does not exit */
31455714Skrisexit_loop:
31555714Skris	if (cb != NULL)
31655714Skris		ret=cb((BIO *)b,c->state,ret);
31755714Skrisend:
31855714Skris	return(ret);
31955714Skris	}
32055714Skris
32155714SkrisBIO_CONNECT *BIO_CONNECT_new(void)
32255714Skris	{
32355714Skris	BIO_CONNECT *ret;
32455714Skris
32568651Skris	if ((ret=(BIO_CONNECT *)OPENSSL_malloc(sizeof(BIO_CONNECT))) == NULL)
32655714Skris		return(NULL);
32755714Skris	ret->state=BIO_CONN_S_BEFORE;
32855714Skris	ret->param_hostname=NULL;
32955714Skris	ret->param_port=NULL;
33055714Skris	ret->info_callback=NULL;
33155714Skris	ret->nbio=0;
33255714Skris	ret->ip[0]=0;
33355714Skris	ret->ip[1]=0;
33455714Skris	ret->ip[2]=0;
33555714Skris	ret->ip[3]=0;
33655714Skris	ret->port=0;
33755714Skris	memset((char *)&ret->them,0,sizeof(ret->them));
33855714Skris	return(ret);
33955714Skris	}
34055714Skris
34155714Skrisvoid BIO_CONNECT_free(BIO_CONNECT *a)
34255714Skris	{
34355714Skris	if(a == NULL)
34455714Skris	    return;
34555714Skris
34655714Skris	if (a->param_hostname != NULL)
34768651Skris		OPENSSL_free(a->param_hostname);
34855714Skris	if (a->param_port != NULL)
34968651Skris		OPENSSL_free(a->param_port);
35068651Skris	OPENSSL_free(a);
35155714Skris	}
35255714Skris
35355714SkrisBIO_METHOD *BIO_s_connect(void)
35455714Skris	{
35555714Skris	return(&methods_connectp);
35655714Skris	}
35755714Skris
35855714Skrisstatic int conn_new(BIO *bi)
35955714Skris	{
36055714Skris	bi->init=0;
36155714Skris	bi->num=INVALID_SOCKET;
36255714Skris	bi->flags=0;
36355714Skris	if ((bi->ptr=(char *)BIO_CONNECT_new()) == NULL)
36455714Skris		return(0);
36555714Skris	else
36655714Skris		return(1);
36755714Skris	}
36855714Skris
36955714Skrisstatic void conn_close_socket(BIO *bio)
37055714Skris	{
37155714Skris	BIO_CONNECT *c;
37255714Skris
37355714Skris	c=(BIO_CONNECT *)bio->ptr;
37455714Skris	if (bio->num != INVALID_SOCKET)
37555714Skris		{
37655714Skris		/* Only do a shutdown if things were established */
37755714Skris		if (c->state == BIO_CONN_S_OK)
37855714Skris			shutdown(bio->num,2);
37955714Skris		closesocket(bio->num);
38055714Skris		bio->num=INVALID_SOCKET;
38155714Skris		}
38255714Skris	}
38355714Skris
38455714Skrisstatic int conn_free(BIO *a)
38555714Skris	{
38655714Skris	BIO_CONNECT *data;
38755714Skris
38855714Skris	if (a == NULL) return(0);
38955714Skris	data=(BIO_CONNECT *)a->ptr;
39055714Skris
39155714Skris	if (a->shutdown)
39255714Skris		{
39355714Skris		conn_close_socket(a);
39455714Skris		BIO_CONNECT_free(data);
39555714Skris		a->ptr=NULL;
39655714Skris		a->flags=0;
39755714Skris		a->init=0;
39855714Skris		}
39955714Skris	return(1);
40055714Skris	}
40155714Skris
40255714Skrisstatic int conn_read(BIO *b, char *out, int outl)
40355714Skris	{
40455714Skris	int ret=0;
40555714Skris	BIO_CONNECT *data;
40655714Skris
40755714Skris	data=(BIO_CONNECT *)b->ptr;
40855714Skris	if (data->state != BIO_CONN_S_OK)
40955714Skris		{
41055714Skris		ret=conn_state(b,data);
41155714Skris		if (ret <= 0)
41255714Skris				return(ret);
41355714Skris		}
41455714Skris
41555714Skris	if (out != NULL)
41655714Skris		{
41755714Skris		clear_socket_error();
41855714Skris		ret=readsocket(b->num,out,outl);
41955714Skris		BIO_clear_retry_flags(b);
42055714Skris		if (ret <= 0)
42155714Skris			{
42255714Skris			if (BIO_sock_should_retry(ret))
42355714Skris				BIO_set_retry_read(b);
42455714Skris			}
42555714Skris		}
42655714Skris	return(ret);
42755714Skris	}
42855714Skris
42968651Skrisstatic int conn_write(BIO *b, const char *in, int inl)
43055714Skris	{
43155714Skris	int ret;
43255714Skris	BIO_CONNECT *data;
43355714Skris
43455714Skris	data=(BIO_CONNECT *)b->ptr;
43555714Skris	if (data->state != BIO_CONN_S_OK)
43655714Skris		{
43755714Skris		ret=conn_state(b,data);
43855714Skris		if (ret <= 0) return(ret);
43955714Skris		}
44055714Skris
44155714Skris	clear_socket_error();
44255714Skris	ret=writesocket(b->num,in,inl);
44355714Skris	BIO_clear_retry_flags(b);
44455714Skris	if (ret <= 0)
44555714Skris		{
44655714Skris		if (BIO_sock_should_retry(ret))
44755714Skris			BIO_set_retry_write(b);
44855714Skris		}
44955714Skris	return(ret);
45055714Skris	}
45155714Skris
45268651Skrisstatic long conn_ctrl(BIO *b, int cmd, long num, void *ptr)
45355714Skris	{
45455714Skris	BIO *dbio;
45555714Skris	int *ip;
45655714Skris	const char **pptr;
45755714Skris	long ret=1;
45855714Skris	BIO_CONNECT *data;
45955714Skris
46055714Skris	data=(BIO_CONNECT *)b->ptr;
46155714Skris
46255714Skris	switch (cmd)
46355714Skris		{
46455714Skris	case BIO_CTRL_RESET:
46555714Skris		ret=0;
46655714Skris		data->state=BIO_CONN_S_BEFORE;
46755714Skris		conn_close_socket(b);
46855714Skris		b->flags=0;
46955714Skris		break;
47055714Skris	case BIO_C_DO_STATE_MACHINE:
47155714Skris		/* use this one to start the connection */
472160814Ssimon		if (data->state != BIO_CONN_S_OK)
47355714Skris			ret=(long)conn_state(b,data);
47455714Skris		else
47555714Skris			ret=1;
47655714Skris		break;
47755714Skris	case BIO_C_GET_CONNECT:
47855714Skris		if (ptr != NULL)
47955714Skris			{
48055714Skris			pptr=(const char **)ptr;
48155714Skris			if (num == 0)
48255714Skris				{
48355714Skris				*pptr=data->param_hostname;
48455714Skris
48555714Skris				}
48655714Skris			else if (num == 1)
48755714Skris				{
48855714Skris				*pptr=data->param_port;
48955714Skris				}
49055714Skris			else if (num == 2)
49155714Skris				{
49255714Skris				*pptr= (char *)&(data->ip[0]);
49355714Skris				}
49455714Skris			else if (num == 3)
49555714Skris				{
49655714Skris				*((int *)ptr)=data->port;
49755714Skris				}
49855714Skris			if ((!b->init) || (ptr == NULL))
49959191Skris				*pptr="not initialized";
50055714Skris			ret=1;
50155714Skris			}
50255714Skris		break;
50355714Skris	case BIO_C_SET_CONNECT:
50455714Skris		if (ptr != NULL)
50555714Skris			{
50655714Skris			b->init=1;
50755714Skris			if (num == 0)
50855714Skris				{
50955714Skris				if (data->param_hostname != NULL)
51068651Skris					OPENSSL_free(data->param_hostname);
51155714Skris				data->param_hostname=BUF_strdup(ptr);
51255714Skris				}
51355714Skris			else if (num == 1)
51455714Skris				{
51555714Skris				if (data->param_port != NULL)
51668651Skris					OPENSSL_free(data->param_port);
51755714Skris				data->param_port=BUF_strdup(ptr);
51855714Skris				}
51955714Skris			else if (num == 2)
52055714Skris				{
52155714Skris				char buf[16];
522109998Smarkm				unsigned char *p = ptr;
52355714Skris
524127128Snectar				BIO_snprintf(buf,sizeof buf,"%d.%d.%d.%d",
525127128Snectar					     p[0],p[1],p[2],p[3]);
52655714Skris				if (data->param_hostname != NULL)
52768651Skris					OPENSSL_free(data->param_hostname);
52855714Skris				data->param_hostname=BUF_strdup(buf);
52955714Skris				memcpy(&(data->ip[0]),ptr,4);
53055714Skris				}
53155714Skris			else if (num == 3)
53255714Skris				{
533109998Smarkm				char buf[DECIMAL_SIZE(int)+1];
53455714Skris
535127128Snectar				BIO_snprintf(buf,sizeof buf,"%d",*(int *)ptr);
53655714Skris				if (data->param_port != NULL)
53768651Skris					OPENSSL_free(data->param_port);
53855714Skris				data->param_port=BUF_strdup(buf);
53955714Skris				data->port= *(int *)ptr;
54055714Skris				}
54155714Skris			}
54255714Skris		break;
54355714Skris	case BIO_C_SET_NBIO:
54455714Skris		data->nbio=(int)num;
54555714Skris		break;
54655714Skris	case BIO_C_GET_FD:
54755714Skris		if (b->init)
54855714Skris			{
54955714Skris			ip=(int *)ptr;
55055714Skris			if (ip != NULL)
55155714Skris				*ip=b->num;
55255714Skris			ret=b->num;
55355714Skris			}
55455714Skris		else
55555714Skris			ret= -1;
55655714Skris		break;
55755714Skris	case BIO_CTRL_GET_CLOSE:
55855714Skris		ret=b->shutdown;
55955714Skris		break;
56055714Skris	case BIO_CTRL_SET_CLOSE:
56155714Skris		b->shutdown=(int)num;
56255714Skris		break;
56355714Skris	case BIO_CTRL_PENDING:
56455714Skris	case BIO_CTRL_WPENDING:
56555714Skris		ret=0;
56655714Skris		break;
56755714Skris	case BIO_CTRL_FLUSH:
56855714Skris		break;
56955714Skris	case BIO_CTRL_DUP:
57059191Skris		{
57155714Skris		dbio=(BIO *)ptr;
57255714Skris		if (data->param_port)
57355714Skris			BIO_set_conn_port(dbio,data->param_port);
57455714Skris		if (data->param_hostname)
57555714Skris			BIO_set_conn_hostname(dbio,data->param_hostname);
57655714Skris		BIO_set_nbio(dbio,data->nbio);
577109998Smarkm		/* FIXME: the cast of the function seems unlikely to be a good idea */
578109998Smarkm                (void)BIO_set_info_callback(dbio,(bio_info_cb *)data->info_callback);
57959191Skris		}
58055714Skris		break;
58155714Skris	case BIO_CTRL_SET_CALLBACK:
58259191Skris		{
58359191Skris#if 0 /* FIXME: Should this be used?  -- Richard Levitte */
58459191Skris		BIOerr(BIO_F_CONN_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
58559191Skris		ret = -1;
58659191Skris#else
58759191Skris		ret=0;
58859191Skris#endif
58959191Skris		}
59055714Skris		break;
59155714Skris	case BIO_CTRL_GET_CALLBACK:
59255714Skris		{
593160814Ssimon		int (**fptr)(const BIO *bio,int state,int xret);
59455714Skris
595160814Ssimon		fptr=(int (**)(const BIO *bio,int state,int xret))ptr;
59655714Skris		*fptr=data->info_callback;
59755714Skris		}
59855714Skris		break;
59955714Skris	default:
60055714Skris		ret=0;
60155714Skris		break;
60255714Skris		}
60355714Skris	return(ret);
60455714Skris	}
60555714Skris
60668651Skrisstatic long conn_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
60759191Skris	{
60859191Skris	long ret=1;
60959191Skris	BIO_CONNECT *data;
61059191Skris
61159191Skris	data=(BIO_CONNECT *)b->ptr;
61259191Skris
61359191Skris	switch (cmd)
61459191Skris		{
61559191Skris	case BIO_CTRL_SET_CALLBACK:
61659191Skris		{
617109998Smarkm		data->info_callback=(int (*)(const struct bio_st *, int, int))fp;
61859191Skris		}
61959191Skris		break;
62059191Skris	default:
62159191Skris		ret=0;
62259191Skris		break;
62359191Skris		}
62459191Skris	return(ret);
62559191Skris	}
62659191Skris
62768651Skrisstatic int conn_puts(BIO *bp, const char *str)
62855714Skris	{
62955714Skris	int n,ret;
63055714Skris
63155714Skris	n=strlen(str);
63255714Skris	ret=conn_write(bp,str,n);
63355714Skris	return(ret);
63455714Skris	}
63555714Skris
63655714SkrisBIO *BIO_new_connect(char *str)
63755714Skris	{
63855714Skris	BIO *ret;
63955714Skris
64055714Skris	ret=BIO_new(BIO_s_connect());
64155714Skris	if (ret == NULL) return(NULL);
64255714Skris	if (BIO_set_conn_hostname(ret,str))
64355714Skris		return(ret);
64455714Skris	else
64555714Skris		{
64655714Skris		BIO_free(ret);
64755714Skris		return(NULL);
64855714Skris		}
64955714Skris	}
65055714Skris
65155714Skris#endif
65255714Skris
653