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

📄 httcp.c

📁 firtext搜索引擎源码
💻 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.119 2000/08/02 10:48:12 kahan 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/* empirical study in socket call error codes   yovavm@contact.com : added handling for WSAEINVAL error code (Windows)   "When calling connect() in the second time, after the first call to    connect() returned WSAEWOULDBLOCK, an error of WSAEINVAL is returned.    It happens often on WinNT & Win95, and rarely on Win2K & Win98, where in    most cases the second call to connect() returns WSAEISCON (10056).   jose@w3.org : didn't add that test for Unix, as the connect() doc (Linux   and Solaris) says it's not needed. */#ifdef _WINSOCKAPI_					/* windows */#define NETCALL_ERROR(ret)	(ret == SOCKET_ERROR)#define NETCALL_DEADSOCKET(err)	(err == WSAEBADF)#define NETCALL_WOULDBLOCK(err)	(err == WSAEWOULDBLOCK)#define NETCALL_INVAL(err)      (err == WSAEINVAL)#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 sockfd or INVSOC if error*/PRIVATE int _makeSocket (HTHost * host, HTRequest * request, int preemptive){    int status = 1;    SOCKET sockfd = INVSOC;#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 INVSOC;    }    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");    return sockfd;}/***  Associate the channel with the host and create an input and and output stream**  for this host/channel*/PRIVATE BOOL createChannelAndTransportStreams (HTHost * host, SOCKET sockfd, HTTransport * trans){    if (host && sockfd!=INVSOC && trans) {	HTHost_setChannel(host, HTChannel_new(sockfd, NULL, YES));	HTHost_getInput(host, trans, NULL, 0);	HTHost_getOutput(host, trans, NULL, 0);	return YES;    }    return NO;}/*								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){    HTHost * host = HTNet_host(net);    HTRequest * request = HTNet_request(net);    char * hostname = HTHost_name(host);    int preemptive = net->preemptive;    int status = HT_OK;    /* Jump into the state machine */    while (1) {	switch (host->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(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	      */	      host->tcpstate = TCP_CHANNEL;	      HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_CHANNEL.\n" _ host);	      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(host) == NULL) {		host->tcpstate = TCP_DNS;		HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_DNS.\n" _ host);	    } else {		/*		**  There is now one more using the channel		*/		HTChannel_upSemaphore(host->channel);		/*		**  We are now all set and can jump to connected mode		*/		host->tcpstate = TCP_CONNECTED;		HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_CONNECTED.\n" _ host);	    }	    hostname = HTHost_name(host);	    break;	case TCP_DNS:	    if ((status = HTParseInet(host, 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");		host->tcpstate = TCP_DNS_ERROR;		HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_ERROR.\n" _ host);		break;	    }	    if (!HTHost_retry(host) && status > 1)		/* If multiple homes */		HTHost_setRetry(host, status);	    host->tcpstate = TCP_NEED_SOCKET;	    HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_NEED_SOCKET.\n" _ host);	    break;	case TCP_NEED_SOCKET:	{	    SOCKET sockfd;	    /* Create a new socket */	    if ((sockfd = _makeSocket(host, request, preemptive)) == INVSOC) {		host->tcpstate = TCP_ERROR;		break;	    }	    /* Create channnel and streams */	    createChannelAndTransportStreams (host, sockfd, net->transport);	    /* If multi-homed host then start timer on connection */	    if (HTHost_retry(host)) host->connecttime = HTGetTimeInMillis();	    /* Progress notification */	    {		HTAlertCallback *cbf = HTAlert_find(HT_PROG_CONNECT);		if (cbf) (*cbf)(request, HT_PROG_CONNECT, HT_MSG_NULL,				NULL, hostname, NULL);	    }	    host->tcpstate = TCP_NEED_CONNECT;	    HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_NEED_CONNECT.\n" _ host);	    break;	}	case TCP_NEED_CONNECT:#ifdef _WINSOCKAPI_	    /* 2000/08/02 Jens Meggers (jens@meggers.com):            ** In HTDoConnect(), the connect command is done before the            ** WSAAsyncSelect() that is called when             ** HTHost_register(host, net, HTEvent_CONNECT); is executed.             ** Although that is in line with the WinSock2 and Microsoft             ** documentation, it does _not_ work all the time. I have done             ** extensive tests on Win2000 and Win 4.0 SP5. In very rare cases,            ** the connect is finished between the connect() command itself and             ** the WSAAsyncSelect(). In this unlikely case, WinSock does not             ** (always) send the FD_CONNECT message. As a result, when using             ** the Async mode, the event loop hangs because there is no             ** timeout procedure registered for FD_CONNECT.	    ** JK: what happens if status returns an error? Do we have to	    ** unregister the HTEvent_CONNECT event then?                                   */	    HTHost_register(host, net, HTEvent_CONNECT);#endif /* _WINSOCKAPI_ */	    status = connect(HTChannel_socket(host->channel), (struct sockaddr *) &host->sock_addr,			     sizeof(host->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))		{

⌨️ 快捷键说明

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