⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httcp.c

📁 www工具包
💻 C
📖 第 1 页 / 共 2 页
字号:
/*									HTTCP.c**	TCP SPECIFIC CODE****	(c) COPYRIGHT MIT 1995.**	Please first read the full copyright statement in the file COPYRIGH.**	@(#) $Id: HTTCP.c,v 2.114 1999/02/22 22:10:12 frystyk Exp $****	This code is in common between client and server sides.****	16 Jan 92  TBL	Fix strtol() undefined on CMU Mach.**	25 Jun 92  JFG  Added DECNET option through TCP socket emulation.**	13 Sep 93  MD   Added correct return of vmserrorno for HTInetStatus.**			Added decoding of vms error message for MULTINET.**	31 May 94  HF	Added cache on host id's; now use inet_ntoa() to**			HTInetString and some other fixes. Added HTDoConnect**			and HTDoAccept*//* Library include files */#include "wwwsys.h"#include "WWWUtil.h"#include "WWWCore.h"#include "HTReqMan.h"#include "HTNetMan.h"#include "HTTCP.h"					 /* Implemented here */#include "HTHstMan.h"/* VMS stuff */#ifdef VMS#ifndef MULTINET#define FD_SETSIZE 32#else /* Multinet */#define FD_SETSIZE 256#endif /* Multinet */#endif /* VMS *//* Macros and other defines *//* x ms penalty on a multi-homed host if IP-address is unreachable */#define TCP_DELAY		30000/* x ms penalty on a multi-homed host if IP-address is down for unknown reason */#define TCP_PENALTY		60000/* imperical study in socket call error codes */#ifdef _WINSOCKAPI_					/* windows */#define NETCALL_ERROR(ret)	(ret == SOCKET_ERROR)#define NETCALL_DEADSOCKET(err)	(err == WSAEBADF)#define NETCALL_WOULDBLOCK(err)	(err == WSAEWOULDBLOCK)#else /* _WINSOCKAPI_ 					   unix    */#define NETCALL_ERROR(ret)	(ret < 0)#define NETCALL_DEADSOCKET(err)	(err == EBADF)#if defined(EAGAIN) && defined(EALREADY)#define NETCALL_WOULDBLOCK(err)	(err == EINPROGRESS || \				 err == EALREADY || \				 err == EAGAIN)#else /* (EAGAIN && EALREADY) */#ifdef EALREADY#define NETCALL_WOULDBLOCK(err)	(err == EINPROGRESS || err == EALREADY)#else /* EALREADY */#ifdef EAGAIN#define NETCALL_WOULDBLOCK(err)	(err == EINPROGRESS || err == EAGAIN)#else /* EAGAIN */#define NETCALL_WOULDBLOCK(err)	(err == EINPROGRESS)#endif /* !EAGAIN */#endif /* !EALREADY */#endif /* !(EAGAIN && EALREADY) */#endif /* !_WINSOCKAPI_ 				   done */#if defined(__svr4__) || defined (_WINSOCKAPI_)#define HT_HOSTUNREACHABLE(e)	((e)==ECONNREFUSED || (e)==ETIMEDOUT || \				 (e)==ENETUNREACH || (e)==EHOSTUNREACH || \				 (e)==EHOSTDOWN)#else#define HT_HOSTUNREACHABLE(e)	((e)==ECONNREFUSED || (e)==ETIMEDOUT || \				 (e)==ENETUNREACH || (e)==EHOSTUNREACH || \				 (e)==EHOSTDOWN || (e)==EINVAL)#endif/* ------------------------------------------------------------------------- *//*	       	      CONNECTION ESTABLISHMENT MANAGEMENT 		     *//* ------------------------------------------------------------------------- *//* _makeSocket - create a socket, if !preemptive, set FIONBIO * returns 1: blocking *	   0: non-blocking *	  -1: creation error */PRIVATE int _makeSocket(HTHost * host, HTRequest * request, int preemptive, HTTransport * transport){    int status = 1;    SOCKET sockfd;#ifdef DECNET    if ((sockfd=socket(AF_DECnet, SOCK_STREAM, 0))==INVSOC)#else    if ((sockfd=socket(AF_INET, SOCK_STREAM,IPPROTO_TCP))==INVSOC)#endif    {	HTRequest_addSystemError(request, ERR_FATAL, socerrno, NO, "socket");	return -1;    }    HTTRACE(PROT_TRACE, "Socket...... Created %d\n" _ sockfd);    /* Increase the number of sockets by one */    HTNet_increaseSocket();    /*    **  If we have compiled without Nagle's algorithm then try and turn    **  it off now    */#if defined(HT_NO_NAGLE) && defined(HAVE_SETSOCKOPT) && defined(TCP_NODELAY)    {	int disable = 1;	status = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY,			    (char *) &disable, sizeof(int));	if (status == -1) {	    HTTRACE(PROT_TRACE, "Socket...... Could not disable Nagle's algorithm - error %d\n" _ 			sockfd);	} else {	    HTTRACE(PROT_TRACE, "Socket...... Turned off Nagle's algorithm\n");	}    }#endif    /* If non-blocking protocol then change socket status    ** I use fcntl() so that I can ask the status before I set it.    ** See W. Richard Stevens (Advan. Prog. in UNIX environment, p.364)    ** Be CAREFULL with the old `O_NDELAY' - it will not work as read()    ** returns 0 when blocking and NOT -1. FNDELAY is ONLY for BSD and    ** does NOT work on SVR4 systems. O_NONBLOCK is POSIX.    */    if (!preemptive) {#ifdef _WINSOCKAPI_	{		/* begin windows scope  */	    long levents = FD_READ | FD_WRITE | FD_ACCEPT | 			   FD_CONNECT | FD_CLOSE ;	    int rv = 0 ;	    u_long one = 1;	    status = ioctlsocket(sockfd, FIONBIO, &one) == 		     SOCKET_ERROR ? -1 : 0;	} /* end scope */#else /* _WINSOCKAPI_ */#if defined(VMS)	{	    int enable = 1;	    status = IOCTL(sockfd, FIONBIO, &enable);	}#else /* VMS */	if((status = fcntl(sockfd, F_GETFL, 0)) != -1) {#ifdef O_NONBLOCK	    status |= O_NONBLOCK;			    /* POSIX */#else /* O_NONBLOCK */#ifdef F_NDELAY		    status |= F_NDELAY;				      /* BSD */#endif /* F_NDELAY */#endif /* !O_NONBLOCK */		    status = fcntl(sockfd, F_SETFL, status);	}#endif /* !VMS */#endif /* !_WINSOCKAPI_ */	HTTRACE(PROT_TRACE, "Socket...... %slocking socket\n" _ status == -1 ? "B" : "Non-b");    } else	HTTRACE(PROT_TRACE, "Socket...... Blocking socket\n");    /*    **  Associate the channel with the host and create an input and and output stream    **  for this host/channel    */    HTHost_setChannel(host, HTChannel_new(sockfd, NULL, YES));    HTHost_getInput(host, transport, NULL, 0);    HTHost_getOutput(host, transport, NULL, 0);    return status == -1 ? 1 : 0;}/*								HTDoConnect()****	Note: Any port indication in URL, e.g., as `host:port' overwrites**	the default port value.****	returns		HT_ERROR	Error has occured or interrupted**			HT_OK		if connected**			HT_WOULD_BLOCK  if operation would have blocked*/PUBLIC int HTDoConnect (HTNet * net, char * url, u_short default_port){    HTHost * me = HTNet_host(net);    HTRequest * request = HTNet_request(net);    int preemptive = net->preemptive;    int status = HT_OK;    char * hostname = HTHost_name(me);    /* Jump into the state machine */    while (1) {	switch (me->tcpstate) {	  case TCP_BEGIN:	  {	      /*	      ** Add the net object to the host object found above. If the	      ** host is idle then we can start the request right away,	      ** otherwise we must wait until it is free. 	      */	      if ((status = HTHost_addNet(net->host, net)) == HT_PENDING)		  HTTRACE(PROT_TRACE, "HTDoConnect. Pending...\n");	      /*	      ** If we are pending then return here, otherwise go to next state	      ** which is setting up a channel	      */	      me->tcpstate = TCP_CHANNEL;	      HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_CHANNEL.\n" _ me);	      if (status == HT_PENDING) return HT_PENDING;	  }	  break;	case TCP_CHANNEL:	    /*	    **  The next state depends on whether we have a connection	    **  or not - if so then we can jump directly to connect() to	    **  test it - otherwise we must around DNS to get the name	    **  Resolved	    */	    if (HTHost_channel(me) == NULL) {		me->tcpstate = TCP_DNS;		HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_DNS.\n" _ me);	    } else {		/*		**  There is now one more using the channel		*/		HTChannel_upSemaphore(me->channel);		/*		**  We are now all set and can jump to connected mode		*/		me->tcpstate = TCP_CONNECTED;		HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_CONNECTED.\n" _ me);	    }	    hostname = HTHost_name(me);	    break;	case TCP_DNS:	    if ((status = HTParseInet(me, hostname, request)) < 0) {		HTTRACE(PROT_TRACE, "HTDoConnect. Can't locate `%s\'\n" _ hostname);		HTRequest_addError(request, ERR_FATAL, NO,				   HTERR_NO_REMOTE_HOST,				   (void *) hostname, strlen(hostname),				   "HTDoConnect");		me->tcpstate = TCP_DNS_ERROR;		HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_ERROR.\n" _ me);		break;	    }	    if (!HTHost_retry(me) && status > 1)		/* If multiple homes */		HTHost_setRetry(me, status);	    me->tcpstate = TCP_NEED_SOCKET;	    HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_NEED_SOCKET.\n" _ me);	    break;	  case TCP_NEED_SOCKET:	      if (_makeSocket(me, request, preemptive, net->transport) == -1) {		  me->tcpstate = TCP_ERROR;		  break;	      }	    /* If multi-homed host then start timer on connection */	    if (HTHost_retry(me)) me->connecttime = HTGetTimeInMillis();	    /* Progress */	    {		HTAlertCallback *cbf = HTAlert_find(HT_PROG_CONNECT);		if (cbf) (*cbf)(request, HT_PROG_CONNECT, HT_MSG_NULL,				NULL, hostname, NULL);	    }	    me->tcpstate = TCP_NEED_CONNECT;	    HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_NEED_CONNECT.\n" _ me);	    break;	  case TCP_NEED_CONNECT:	    status = connect(HTChannel_socket(me->channel), (struct sockaddr *) &me->sock_addr,			     sizeof(me->sock_addr));	    /*	     * According to the Sun man page for connect:	     *     EINPROGRESS         The socket is non-blocking and the  con-	     *                         nection cannot be completed immediately.	     *                         It is possible to select(2) for  comple-	     *                         tion  by  selecting the socket for writ-	     *                         ing.	     * According to the Motorola SVR4 man page for connect:	     *     EAGAIN              The socket is non-blocking and the  con-	     *                         nection cannot be completed immediately.	     *                         It is possible to select for  completion	     *                         by  selecting  the  socket  for writing.	     *                         However, this is only  possible  if  the	     *                         socket  STREAMS  module  is  the topmost	     *                         module on  the  protocol  stack  with  a	     *                         write  service  procedure.  This will be	     *                         the normal case.	     */	    if (NETCALL_ERROR(status))	    {		if (NETCALL_WOULDBLOCK(socerrno))		{		    HTTRACE(PROT_TRACE, "HTDoConnect. WOULD BLOCK `%s'\n" _ hostname);		    HTHost_register(me, net, HTEvent_CONNECT);		    return HT_WOULD_BLOCK;		}		if (socerrno == EISCONN) {		    me->tcpstate = TCP_CONNECTED;		    HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_CONNECTED.\n" _ me);		    break;		}		if (NETCALL_DEADSOCKET(socerrno))     /* We lost the socket */		{		    me->tcpstate = TCP_NEED_SOCKET;		    HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_NEED_SOCKET.\n" _ me);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -