bss_conn.c revision 59191
11556Srgrimes/* crypto/bio/bss_conn.c */
217987Speter/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
31556Srgrimes * All rights reserved.
41556Srgrimes *
51556Srgrimes * This package is an SSL implementation written
61556Srgrimes * by Eric Young (eay@cryptsoft.com).
71556Srgrimes * The implementation was written so as to conform with Netscapes SSL.
81556Srgrimes *
91556Srgrimes * This library is free for commercial and non-commercial use as long as
101556Srgrimes * the following conditions are aheared to.  The following conditions
111556Srgrimes * apply to all code found in this distribution, be it the RC4, RSA,
121556Srgrimes * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
131556Srgrimes * included with this distribution is covered by the same copyright terms
141556Srgrimes * except that the holder is Tim Hudson (tjh@cryptsoft.com).
151556Srgrimes *
161556Srgrimes * Copyright remains Eric Young's, and as such any Copyright notices in
171556Srgrimes * the code are not to be removed.
181556Srgrimes * If this package is used in a product, Eric Young should be given attribution
191556Srgrimes * as the author of the parts of the library used.
201556Srgrimes * This can be in the form of a textual message at program startup or
211556Srgrimes * in documentation (online or textual) provided with the package.
221556Srgrimes *
231556Srgrimes * Redistribution and use in source and binary forms, with or without
241556Srgrimes * modification, are permitted provided that the following conditions
251556Srgrimes * are met:
261556Srgrimes * 1. Redistributions of source code must retain the copyright
271556Srgrimes *    notice, this list of conditions and the following disclaimer.
281556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
291556Srgrimes *    notice, this list of conditions and the following disclaimer in the
301556Srgrimes *    documentation and/or other materials provided with the distribution.
311556Srgrimes * 3. All advertising materials mentioning features or use of this software
3217987Speter *    must display the following acknowledgement:
331556Srgrimes *    "This product includes cryptographic software written by
341556Srgrimes *     Eric Young (eay@cryptsoft.com)"
351556Srgrimes *    The word 'cryptographic' can be left out if the rouines from the library
361556Srgrimes *    being used are not cryptographic related :-).
371556Srgrimes * 4. If you include any Windows specific code (or a derivative thereof) from
381556Srgrimes *    the apps directory (application code) you must include an acknowledgement:
391556Srgrimes *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
401556Srgrimes *
411556Srgrimes * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
421556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
431556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
441556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
451556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
461556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
471556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
481556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
491556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
501556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
511556Srgrimes * SUCH DAMAGE.
521556Srgrimes *
531556Srgrimes * The licence and distribution terms for any publically available version or
541556Srgrimes * derivative of this code cannot be changed.  i.e. this code cannot simply be
551556Srgrimes * copied and put under another distribution licence
561556Srgrimes * [including the GNU Public Licence.]
571556Srgrimes */
581556Srgrimes
591556Srgrimes#ifndef NO_SOCK
601556Srgrimes
611556Srgrimes#include <stdio.h>
621556Srgrimes#include <errno.h>
631556Srgrimes#define USE_SOCKETS
641556Srgrimes#include "cryptlib.h"
651556Srgrimes#include <openssl/bio.h>
661556Srgrimes
671556Srgrimes#ifdef WIN16
681556Srgrimes#define SOCKET_PROTOCOL 0 /* more microsoft stupidity */
691556Srgrimes#else
701556Srgrimes#define SOCKET_PROTOCOL IPPROTO_TCP
711556Srgrimes#endif
721556Srgrimes
731556Srgrimes#if (defined(VMS) && __VMS_VER < 70000000)
741556Srgrimes/* FIONBIO used as a switch to enable ioctl, and that isn't in VMS < 7.0 */
751556Srgrimes#undef FIONBIO
761556Srgrimes#endif
771556Srgrimes
781556Srgrimes
791556Srgrimestypedef struct bio_connect_st
801556Srgrimes	{
811556Srgrimes	int state;
821556Srgrimes
831556Srgrimes	char *param_hostname;
841556Srgrimes	char *param_port;
851556Srgrimes	int nbio;
861556Srgrimes
871556Srgrimes	unsigned char ip[4];
881556Srgrimes	unsigned short port;
891556Srgrimes
901556Srgrimes	struct sockaddr_in them;
911556Srgrimes
921556Srgrimes	/* int socket; this will be kept in bio->num so that it is
931556Srgrimes	 * compatible with the bss_sock bio */
941556Srgrimes
951556Srgrimes	/* called when the connection is initially made
961556Srgrimes	 *  callback(BIO,state,ret);  The callback should return
971556Srgrimes	 * 'ret'.  state is for compatibility with the ssl info_callback */
981556Srgrimes	int (*info_callback)();
991556Srgrimes	} BIO_CONNECT;
1001556Srgrimes
1011556Srgrimesstatic int conn_write(BIO *h,char *buf,int num);
1021556Srgrimesstatic int conn_read(BIO *h,char *buf,int size);
1031556Srgrimesstatic int conn_puts(BIO *h,char *str);
1041556Srgrimesstatic long conn_ctrl(BIO *h,int cmd,long arg1,char *arg2);
1051556Srgrimesstatic int conn_new(BIO *h);
1061556Srgrimesstatic int conn_free(BIO *data);
1071556Srgrimesstatic long conn_callback_ctrl(BIO *h,int cmd,void *(*fp)());
1081556Srgrimes
1091556Srgrimesstatic int conn_state(BIO *b, BIO_CONNECT *c);
1101556Srgrimesstatic void conn_close_socket(BIO *data);
1111556SrgrimesBIO_CONNECT *BIO_CONNECT_new(void );
1121556Srgrimesvoid BIO_CONNECT_free(BIO_CONNECT *a);
1131556Srgrimes
1141556Srgrimesstatic BIO_METHOD methods_connectp=
1151556Srgrimes	{
1161556Srgrimes	BIO_TYPE_CONNECT,
1171556Srgrimes	"socket connect",
1181556Srgrimes	conn_write,
1191556Srgrimes	conn_read,
1201556Srgrimes	conn_puts,
1211556Srgrimes	NULL, /* connect_gets, */
1221556Srgrimes	conn_ctrl,
1231556Srgrimes	conn_new,
1241556Srgrimes	conn_free,
1251556Srgrimes	conn_callback_ctrl,
1261556Srgrimes	};
1271556Srgrimes
1281556Srgrimesstatic int conn_state(BIO *b, BIO_CONNECT *c)
1291556Srgrimes	{
1301556Srgrimes	int ret= -1,i;
1311556Srgrimes	unsigned long l;
1321556Srgrimes	char *p,*q;
1331556Srgrimes	int (*cb)()=NULL;
1341556Srgrimes
1351556Srgrimes	if (c->info_callback != NULL)
1361556Srgrimes		cb=c->info_callback;
1371556Srgrimes
1381556Srgrimes	for (;;)
1391556Srgrimes		{
1401556Srgrimes		switch (c->state)
1411556Srgrimes			{
1421556Srgrimes		case BIO_CONN_S_BEFORE:
1431556Srgrimes			p=c->param_hostname;
1441556Srgrimes			if (p == NULL)
1451556Srgrimes				{
1461556Srgrimes				BIOerr(BIO_F_CONN_STATE,BIO_R_NO_HOSTNAME_SPECIFIED);
1471556Srgrimes				goto exit_loop;
1481556Srgrimes				}
1491556Srgrimes			for ( ; *p != '\0'; p++)
1501556Srgrimes				{
1511556Srgrimes				if ((*p == ':') || (*p == '/')) break;
1521556Srgrimes				}
1531556Srgrimes
1541556Srgrimes			i= *p;
1551556Srgrimes			if ((i == ':') || (i == '/'))
1561556Srgrimes				{
1571556Srgrimes
1581556Srgrimes				*(p++)='\0';
1591556Srgrimes				if (i == ':')
1601556Srgrimes					{
1611556Srgrimes					for (q=p; *q; q++)
1621556Srgrimes						if (*q == '/')
1631556Srgrimes							{
1641556Srgrimes							*q='\0';
1651556Srgrimes							break;
1661556Srgrimes							}
1671556Srgrimes					if (c->param_port != NULL)
1681556Srgrimes						Free(c->param_port);
1691556Srgrimes					c->param_port=BUF_strdup(p);
1701556Srgrimes					}
1711556Srgrimes				}
1721556Srgrimes
1731556Srgrimes			if (c->param_port == NULL)
1741556Srgrimes				{
1751556Srgrimes				BIOerr(BIO_F_CONN_STATE,BIO_R_NO_PORT_SPECIFIED);
1761556Srgrimes				ERR_add_error_data(2,"host=",c->param_hostname);
1771556Srgrimes				goto exit_loop;
1781556Srgrimes				}
1791556Srgrimes			c->state=BIO_CONN_S_GET_IP;
1801556Srgrimes			break;
1811556Srgrimes
1821556Srgrimes		case BIO_CONN_S_GET_IP:
1831556Srgrimes			if (BIO_get_host_ip(c->param_hostname,&(c->ip[0])) <= 0)
1841556Srgrimes				goto exit_loop;
1851556Srgrimes			c->state=BIO_CONN_S_GET_PORT;
1861556Srgrimes			break;
1871556Srgrimes
1881556Srgrimes		case BIO_CONN_S_GET_PORT:
1891556Srgrimes			if (c->param_port == NULL)
1901556Srgrimes				{
1911556Srgrimes				abort();
1921556Srgrimes				goto exit_loop;
1931556Srgrimes				}
1941556Srgrimes			else if (BIO_get_port(c->param_port,&c->port) <= 0)
1951556Srgrimes				goto exit_loop;
1961556Srgrimes			c->state=BIO_CONN_S_CREATE_SOCKET;
1971556Srgrimes			break;
1981556Srgrimes
1991556Srgrimes		case BIO_CONN_S_CREATE_SOCKET:
2001556Srgrimes			/* now setup address */
2011556Srgrimes			memset((char *)&c->them,0,sizeof(c->them));
2021556Srgrimes			c->them.sin_family=AF_INET;
2031556Srgrimes			c->them.sin_port=htons((unsigned short)c->port);
2041556Srgrimes			l=(unsigned long)
2051556Srgrimes				((unsigned long)c->ip[0]<<24L)|
2061556Srgrimes				((unsigned long)c->ip[1]<<16L)|
2071556Srgrimes				((unsigned long)c->ip[2]<< 8L)|
2081556Srgrimes				((unsigned long)c->ip[3]);
2091556Srgrimes			c->them.sin_addr.s_addr=htonl(l);
2101556Srgrimes			c->state=BIO_CONN_S_CREATE_SOCKET;
2111556Srgrimes
2121556Srgrimes			ret=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
2131556Srgrimes			if (ret == INVALID_SOCKET)
2141556Srgrimes				{
2151556Srgrimes				SYSerr(SYS_F_SOCKET,get_last_socket_error());
2161556Srgrimes				ERR_add_error_data(4,"host=",c->param_hostname,
2171556Srgrimes					":",c->param_port);
2181556Srgrimes				BIOerr(BIO_F_CONN_STATE,BIO_R_UNABLE_TO_CREATE_SOCKET);
2191556Srgrimes				goto exit_loop;
2201556Srgrimes				}
2211556Srgrimes			b->num=ret;
2221556Srgrimes			c->state=BIO_CONN_S_NBIO;
2231556Srgrimes			break;
2241556Srgrimes
2251556Srgrimes		case BIO_CONN_S_NBIO:
2261556Srgrimes			if (c->nbio)
2271556Srgrimes				{
2281556Srgrimes				if (!BIO_socket_nbio(b->num,1))
2291556Srgrimes					{
2301556Srgrimes					BIOerr(BIO_F_CONN_STATE,BIO_R_ERROR_SETTING_NBIO);
2311556Srgrimes					ERR_add_error_data(4,"host=",
2321556Srgrimes						c->param_hostname,
2331556Srgrimes						":",c->param_port);
2341556Srgrimes					goto exit_loop;
2351556Srgrimes					}
2361556Srgrimes				}
2371556Srgrimes			c->state=BIO_CONN_S_CONNECT;
2381556Srgrimes
2391556Srgrimes#ifdef SO_KEEPALIVE
2401556Srgrimes			i=1;
2411556Srgrimes			i=setsockopt(b->num,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
2421556Srgrimes			if (i < 0)
2431556Srgrimes				{
2441556Srgrimes				SYSerr(SYS_F_SOCKET,get_last_socket_error());
2451556Srgrimes				ERR_add_error_data(4,"host=",c->param_hostname,
2461556Srgrimes					":",c->param_port);
2471556Srgrimes				BIOerr(BIO_F_CONN_STATE,BIO_R_KEEPALIVE);
2481556Srgrimes				goto exit_loop;
2491556Srgrimes				}
2501556Srgrimes#endif
2511556Srgrimes			break;
2521556Srgrimes
2531556Srgrimes		case BIO_CONN_S_CONNECT:
2541556Srgrimes			BIO_clear_retry_flags(b);
2551556Srgrimes			ret=connect(b->num,
2561556Srgrimes				(struct sockaddr *)&c->them,
2571556Srgrimes				sizeof(c->them));
2581556Srgrimes			b->retry_reason=0;
2591556Srgrimes			if (ret < 0)
2601556Srgrimes				{
2611556Srgrimes				if (BIO_sock_should_retry(ret))
2621556Srgrimes					{
2631556Srgrimes					BIO_set_retry_special(b);
2641556Srgrimes					c->state=BIO_CONN_S_BLOCKED_CONNECT;
2651556Srgrimes					b->retry_reason=BIO_RR_CONNECT;
2661556Srgrimes					}
2671556Srgrimes				else
2681556Srgrimes					{
2691556Srgrimes					SYSerr(SYS_F_CONNECT,get_last_socket_error());
2701556Srgrimes					ERR_add_error_data(4,"host=",
2711556Srgrimes						c->param_hostname,
2721556Srgrimes						":",c->param_port);
2731556Srgrimes					BIOerr(BIO_F_CONN_STATE,BIO_R_CONNECT_ERROR);
2741556Srgrimes					}
2751556Srgrimes				goto exit_loop;
2761556Srgrimes				}
2771556Srgrimes			else
2781556Srgrimes				c->state=BIO_CONN_S_OK;
2791556Srgrimes			break;
2801556Srgrimes
2811556Srgrimes		case BIO_CONN_S_BLOCKED_CONNECT:
2821556Srgrimes			i=BIO_sock_error(b->num);
2831556Srgrimes			if (i)
2841556Srgrimes				{
2851556Srgrimes				BIO_clear_retry_flags(b);
2861556Srgrimes				SYSerr(SYS_F_CONNECT,i);
2871556Srgrimes				ERR_add_error_data(4,"host=",
2881556Srgrimes					c->param_hostname,
2891556Srgrimes					":",c->param_port);
2901556Srgrimes				BIOerr(BIO_F_CONN_STATE,BIO_R_NBIO_CONNECT_ERROR);
2911556Srgrimes				ret=0;
2921556Srgrimes				goto exit_loop;
2931556Srgrimes				}
2941556Srgrimes			else
2951556Srgrimes				c->state=BIO_CONN_S_OK;
2961556Srgrimes			break;
2971556Srgrimes
2981556Srgrimes		case BIO_CONN_S_OK:
2991556Srgrimes			ret=1;
3001556Srgrimes			goto exit_loop;
3011556Srgrimes		default:
3021556Srgrimes			abort();
3031556Srgrimes			goto exit_loop;
3041556Srgrimes			}
3051556Srgrimes
3061556Srgrimes		if (cb != NULL)
3071556Srgrimes			{
3081556Srgrimes			if (!(ret=cb((BIO *)b,c->state,ret)))
3091556Srgrimes				goto end;
3101556Srgrimes			}
3111556Srgrimes		}
3121556Srgrimes
3131556Srgrimes	/* Loop does not exit */
3141556Srgrimesexit_loop:
3151556Srgrimes	if (cb != NULL)
3161556Srgrimes		ret=cb((BIO *)b,c->state,ret);
3171556Srgrimesend:
3181556Srgrimes	return(ret);
3191556Srgrimes	}
3201556Srgrimes
3211556SrgrimesBIO_CONNECT *BIO_CONNECT_new(void)
3221556Srgrimes	{
3231556Srgrimes	BIO_CONNECT *ret;
3241556Srgrimes
3251556Srgrimes	if ((ret=(BIO_CONNECT *)Malloc(sizeof(BIO_CONNECT))) == NULL)
3261556Srgrimes		return(NULL);
3271556Srgrimes	ret->state=BIO_CONN_S_BEFORE;
3281556Srgrimes	ret->param_hostname=NULL;
3291556Srgrimes	ret->param_port=NULL;
3301556Srgrimes	ret->info_callback=NULL;
3311556Srgrimes	ret->nbio=0;
3321556Srgrimes	ret->ip[0]=0;
3331556Srgrimes	ret->ip[1]=0;
3341556Srgrimes	ret->ip[2]=0;
3351556Srgrimes	ret->ip[3]=0;
3361556Srgrimes	ret->port=0;
3371556Srgrimes	memset((char *)&ret->them,0,sizeof(ret->them));
3381556Srgrimes	return(ret);
3391556Srgrimes	}
3401556Srgrimes
3411556Srgrimesvoid BIO_CONNECT_free(BIO_CONNECT *a)
3421556Srgrimes	{
3431556Srgrimes	if(a == NULL)
3441556Srgrimes	    return;
3451556Srgrimes
3461556Srgrimes	if (a->param_hostname != NULL)
3471556Srgrimes		Free(a->param_hostname);
3481556Srgrimes	if (a->param_port != NULL)
3491556Srgrimes		Free(a->param_port);
3501556Srgrimes	Free(a);
3511556Srgrimes	}
3521556Srgrimes
3531556SrgrimesBIO_METHOD *BIO_s_connect(void)
3541556Srgrimes	{
3551556Srgrimes	return(&methods_connectp);
3561556Srgrimes	}
3571556Srgrimes
358static int conn_new(BIO *bi)
359	{
360	bi->init=0;
361	bi->num=INVALID_SOCKET;
362	bi->flags=0;
363	if ((bi->ptr=(char *)BIO_CONNECT_new()) == NULL)
364		return(0);
365	else
366		return(1);
367	}
368
369static void conn_close_socket(BIO *bio)
370	{
371	BIO_CONNECT *c;
372
373	c=(BIO_CONNECT *)bio->ptr;
374	if (bio->num != INVALID_SOCKET)
375		{
376		/* Only do a shutdown if things were established */
377		if (c->state == BIO_CONN_S_OK)
378			shutdown(bio->num,2);
379		closesocket(bio->num);
380		bio->num=INVALID_SOCKET;
381		}
382	}
383
384static int conn_free(BIO *a)
385	{
386	BIO_CONNECT *data;
387
388	if (a == NULL) return(0);
389	data=(BIO_CONNECT *)a->ptr;
390
391	if (a->shutdown)
392		{
393		conn_close_socket(a);
394		BIO_CONNECT_free(data);
395		a->ptr=NULL;
396		a->flags=0;
397		a->init=0;
398		}
399	return(1);
400	}
401
402static int conn_read(BIO *b, char *out, int outl)
403	{
404	int ret=0;
405	BIO_CONNECT *data;
406
407	data=(BIO_CONNECT *)b->ptr;
408	if (data->state != BIO_CONN_S_OK)
409		{
410		ret=conn_state(b,data);
411		if (ret <= 0)
412				return(ret);
413		}
414
415	if (out != NULL)
416		{
417		clear_socket_error();
418		ret=readsocket(b->num,out,outl);
419		BIO_clear_retry_flags(b);
420		if (ret <= 0)
421			{
422			if (BIO_sock_should_retry(ret))
423				BIO_set_retry_read(b);
424			}
425		}
426	return(ret);
427	}
428
429static int conn_write(BIO *b, char *in, int inl)
430	{
431	int ret;
432	BIO_CONNECT *data;
433
434	data=(BIO_CONNECT *)b->ptr;
435	if (data->state != BIO_CONN_S_OK)
436		{
437		ret=conn_state(b,data);
438		if (ret <= 0) return(ret);
439		}
440
441	clear_socket_error();
442	ret=writesocket(b->num,in,inl);
443	BIO_clear_retry_flags(b);
444	if (ret <= 0)
445		{
446		if (BIO_sock_should_retry(ret))
447			BIO_set_retry_write(b);
448		}
449	return(ret);
450	}
451
452static long conn_ctrl(BIO *b, int cmd, long num, char *ptr)
453	{
454	BIO *dbio;
455	int *ip;
456	const char **pptr;
457	long ret=1;
458	BIO_CONNECT *data;
459
460	data=(BIO_CONNECT *)b->ptr;
461
462	switch (cmd)
463		{
464	case BIO_CTRL_RESET:
465		ret=0;
466		data->state=BIO_CONN_S_BEFORE;
467		conn_close_socket(b);
468		b->flags=0;
469		break;
470	case BIO_C_DO_STATE_MACHINE:
471		/* use this one to start the connection */
472		if (!data->state != BIO_CONN_S_OK)
473			ret=(long)conn_state(b,data);
474		else
475			ret=1;
476		break;
477	case BIO_C_GET_CONNECT:
478		if (ptr != NULL)
479			{
480			pptr=(const char **)ptr;
481			if (num == 0)
482				{
483				*pptr=data->param_hostname;
484
485				}
486			else if (num == 1)
487				{
488				*pptr=data->param_port;
489				}
490			else if (num == 2)
491				{
492				*pptr= (char *)&(data->ip[0]);
493				}
494			else if (num == 3)
495				{
496				*((int *)ptr)=data->port;
497				}
498			if ((!b->init) || (ptr == NULL))
499				*pptr="not initialized";
500			ret=1;
501			}
502		break;
503	case BIO_C_SET_CONNECT:
504		if (ptr != NULL)
505			{
506			b->init=1;
507			if (num == 0)
508				{
509				if (data->param_hostname != NULL)
510					Free(data->param_hostname);
511				data->param_hostname=BUF_strdup(ptr);
512				}
513			else if (num == 1)
514				{
515				if (data->param_port != NULL)
516					Free(data->param_port);
517				data->param_port=BUF_strdup(ptr);
518				}
519			else if (num == 2)
520				{
521				char buf[16];
522
523				sprintf(buf,"%d.%d.%d.%d",
524					ptr[0],ptr[1],ptr[2],ptr[3]);
525				if (data->param_hostname != NULL)
526					Free(data->param_hostname);
527				data->param_hostname=BUF_strdup(buf);
528				memcpy(&(data->ip[0]),ptr,4);
529				}
530			else if (num == 3)
531				{
532				char buf[16];
533
534				sprintf(buf,"%d",*(int *)ptr);
535				if (data->param_port != NULL)
536					Free(data->param_port);
537				data->param_port=BUF_strdup(buf);
538				data->port= *(int *)ptr;
539				}
540			}
541		break;
542	case BIO_C_SET_NBIO:
543		data->nbio=(int)num;
544		break;
545	case BIO_C_GET_FD:
546		if (b->init)
547			{
548			ip=(int *)ptr;
549			if (ip != NULL)
550				*ip=b->num;
551			ret=b->num;
552			}
553		else
554			ret= -1;
555		break;
556	case BIO_CTRL_GET_CLOSE:
557		ret=b->shutdown;
558		break;
559	case BIO_CTRL_SET_CLOSE:
560		b->shutdown=(int)num;
561		break;
562	case BIO_CTRL_PENDING:
563	case BIO_CTRL_WPENDING:
564		ret=0;
565		break;
566	case BIO_CTRL_FLUSH:
567		break;
568	case BIO_CTRL_DUP:
569		{
570		dbio=(BIO *)ptr;
571		if (data->param_port)
572			BIO_set_conn_port(dbio,data->param_port);
573		if (data->param_hostname)
574			BIO_set_conn_hostname(dbio,data->param_hostname);
575		BIO_set_nbio(dbio,data->nbio);
576		(void)BIO_set_info_callback(dbio,(void *(*)())(data->info_callback));
577		}
578		break;
579	case BIO_CTRL_SET_CALLBACK:
580		{
581#if 0 /* FIXME: Should this be used?  -- Richard Levitte */
582		BIOerr(BIO_F_CONN_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
583		ret = -1;
584#else
585		ret=0;
586#endif
587		}
588		break;
589	case BIO_CTRL_GET_CALLBACK:
590		{
591		int (**fptr)();
592
593		fptr=(int (**)())ptr;
594		*fptr=data->info_callback;
595		}
596		break;
597	default:
598		ret=0;
599		break;
600		}
601	return(ret);
602	}
603
604static long conn_callback_ctrl(BIO *b, int cmd, void *(*fp)())
605	{
606	long ret=1;
607	BIO_CONNECT *data;
608
609	data=(BIO_CONNECT *)b->ptr;
610
611	switch (cmd)
612		{
613	case BIO_CTRL_SET_CALLBACK:
614		{
615		data->info_callback=(int (*)())fp;
616		}
617		break;
618	default:
619		ret=0;
620		break;
621		}
622	return(ret);
623	}
624
625static int conn_puts(BIO *bp, char *str)
626	{
627	int n,ret;
628
629	n=strlen(str);
630	ret=conn_write(bp,str,n);
631	return(ret);
632	}
633
634BIO *BIO_new_connect(char *str)
635	{
636	BIO *ret;
637
638	ret=BIO_new(BIO_s_connect());
639	if (ret == NULL) return(NULL);
640	if (BIO_set_conn_hostname(ret,str))
641		return(ret);
642	else
643		{
644		BIO_free(ret);
645		return(NULL);
646		}
647	}
648
649#endif
650
651