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

📄 httcp.c

📁 用于linux和其他unix下面的
💻 C
📖 第 1 页 / 共 4 页
字号:
    for (res = res0; res; res = res->ai_next) {	*s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);	if (*s == -1) {	    char hostbuf[1024], portbuf[1024];	    getnameinfo(res->ai_addr, res->ai_addrlen,		    hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf),		    NI_NUMERICHOST|NI_NUMERICSERV);	    HTSprintf0 (&line, gettext("socket failed: family %d addr %s port %s."),		    res->ai_family, hostbuf, portbuf);	    _HTProgress (line);	    FREE(line);	    continue;	}#else    *s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    if (*s == -1) {	HTAlert(gettext("socket failed."));	return HT_NO_DATA;    }#endif /* INET6 */#ifndef DOSPATH#if !defined(NO_IOCTL) || defined(USE_FCNTL)    /*    **	Make the socket non-blocking, so the connect can be canceled.    **	This means that when we issue the connect we should NOT    **	have to wait for the accept on the other end.    */    {#ifdef USE_FCNTL	int ret = fcntl(*s, F_SETFL, O_NONBLOCK);#else	int val = 1;	int ret = IOCTL(*s, FIONBIO, &val);#endif /* USE_FCNTL */	if (ret == -1)	    _HTProgress(gettext("Could not make connection non-blocking."));    }#endif /* !NO_IOCTL || USE_FCNTL */#endif /* !DOSPATH */    /*    **	Issue the connect.  Since the server can't do an instantaneous    **	accept and we are non-blocking, this will almost certainly return    **	a negative status.    */#ifdef SOCKS    if (socks_flag) {#ifdef INET6	status = Rconnect(*s, res->ai_addr, res->ai_addrlen);#else	status = Rconnect(*s, (struct sockaddr*)&soc_address,			  sizeof(soc_address));#endif /* INET6 */	/*	**  For long Rbind.	*/	socks_bind_remoteAddr = soc_address.sin_addr.s_addr;    } else#endif /* SOCKS */#ifdef INET6    status = connect(*s, res->ai_addr, res->ai_addrlen);#else    status = connect(*s, (struct sockaddr*)&soc_address, sizeof(soc_address));#endif /* INET6 */#ifndef __DJGPP__    /*    **	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 ((status < 0) &&	(SOCKET_ERRNO == EINPROGRESS#ifdef EAGAIN	 || SOCKET_ERRNO == EAGAIN#endif	 )) {	struct timeval select_timeout;	int ret;	int tries=0;#ifdef SOCKET_DEBUG_TRACE	HTInetStatus("this socket's first connect");#endif /* SOCKET_DEBUG_TRACE */	ret = 0;	while (ret <= 0) {	    fd_set writefds;	    /*	    **	Protect against an infinite loop.	    */	    if ((tries++/10) >= connect_timeout) {		HTAlert(gettext("Connection failed (too many retries)."));#ifdef INET6		FREE(line);		freeaddrinfo(res0);#endif /* INET6 */		return HT_NO_DATA;	    }#ifdef _WINDOWS_NSL	    select_timeout.tv_sec = connect_timeout;	    select_timeout.tv_usec = 0;#else	    select_timeout.tv_sec = 0;	    select_timeout.tv_usec = 100000;#endif /* _WINDOWS_NSL */	    FD_ZERO(&writefds);	    FD_SET((unsigned) *s, &writefds);#ifdef SOCKS	    if (socks_flag)		ret = Rselect(FD_SETSIZE, NULL,			      (void *)&writefds, NULL, &select_timeout);	    else#endif /* SOCKS */	    ret = select(FD_SETSIZE, NULL, (void *)&writefds, NULL, &select_timeout);#ifdef SOCKET_DEBUG_TRACE	    if (tries == 1) {		HTInetStatus("this socket's first select");	    }#endif /* SOCKET_DEBUG_TRACE */	    /*	    **  If we suspend, then it is possible that select will be	    **  interrupted.  Allow for this possibility. - JED	    */	    if ((ret == -1) && (errno == EINTR))		continue;#ifdef SOCKET_DEBUG_TRACE	    if (ret < 0) {		HTInetStatus("failed select");	    }#endif /* SOCKET_DEBUG_TRACE */	    /*	    **	Again according to the Sun and Motorola man pages for connect:	    **	   EALREADY	       The socket is non-blocking and a  previ-	    **			       ous  connection attempt has not yet been	    **			       completed.	    **	Thus if the SOCKET_ERRNO is NOT EALREADY we have a real error,	    **	and should break out here and return that error.	    **	Otherwise if it is EALREADY keep on trying to complete the	    **	connection.	    */	    if ((ret < 0) && (SOCKET_ERRNO != EALREADY)) {		status = ret;		break;	    } else if (ret > 0) {		/*		**  Extra check here for connection success, if we try to		**  connect again, and get EISCONN, it means we have a		**  successful connection.  But don't check with SOCKS.		*/#ifdef SOCKS		if (socks_flag) {		    status = 0;		} else {#endif /* SOCKS */#ifdef INET6		status = connect(*s, res->ai_addr, res->ai_addrlen);#else		status = connect(*s, (struct sockaddr*)&soc_address,				 sizeof(soc_address));#endif /* INET6 */#ifdef UCX		/*		**  A UCX feature: Instead of returning EISCONN		**		 UCX returns EADDRINUSE.		**  Test for this status also.		*/		if ((status < 0) && ((SOCKET_ERRNO == EISCONN) ||				     (SOCKET_ERRNO == EADDRINUSE)))#else		if ((status < 0) && (SOCKET_ERRNO == EISCONN))#endif /* UCX */		{		    status = 0;		}		if (status && (SOCKET_ERRNO == EALREADY)) /* new stuff LJM */		    ret = 0; /* keep going */		else {#ifdef SOCKET_DEBUG_TRACE		    if (status < 0) {			HTInetStatus("confirm-ready connect");		    }#endif /* SOCKET_DEBUG_TRACE */		    break;		}#ifdef SOCKS		}#endif /* SOCKS */	    }#ifdef SOCKS	    else if (!socks_flag)#else	    else#endif /* SOCKS */	    {		/*		**  The select says we aren't ready yet.  Try to connect		**  again to make sure.  If we don't get EALREADY or EISCONN,		**  something has gone wrong.  Break out and report it.		**		**  For some reason, SVR4 returns EAGAIN here instead of		**  EALREADY, even though the man page says it should be		**  EALREADY.		**		**  For some reason, UCX pre 3 apparently returns		**  errno = 18242 instead the EALREADY or EISCONN.		*/#ifdef INET6		status = connect(*s, res->ai_addr, res->ai_addrlen);#else		status = connect(*s, (struct sockaddr*)&soc_address,				 sizeof(soc_address));#endif /* INET6 */		if ((status < 0) &&		    (SOCKET_ERRNO != EALREADY#ifdef EAGAIN		    && SOCKET_ERRNO != EAGAIN#endif		    ) &&#ifdef UCX		    (SOCKET_ERRNO != 18242) &&#endif /* UCX */		    (SOCKET_ERRNO != EISCONN)) {#ifdef SOCKET_DEBUG_TRACE		    HTInetStatus("confirm-not-ready connect");#endif /* SOCKET_DEBUG_TRACE */		    break;		}	    }	    if (HTCheckForInterrupt()) {		CTRACE((tfp, "*** INTERRUPTED in middle of connect.\n"));		status = HT_INTERRUPTED;#ifdef _WINDOWS		WSASetLastError(EINTR);#else		SOCKET_ERRNO = EINTR;#endif		break;	    }	}    }#ifdef SOCKET_DEBUG_TRACE    else if (status < 0) {	HTInetStatus("this socket's first and only connect");    }#endif /* SOCKET_DEBUG_TRACE */#ifdef INET6	if (status < 0) {		NETCLOSE(*s);		*s = -1;		continue;	}	break;    }#endif /* INET6 */#endif /* !__DJGPP__ */#ifdef INET6    if (*s < 0)#else    if (status < 0)#endif /* INET6 */    {	/*	**  The connect attempt failed or was interrupted,	**  so close up the socket.	*/	NETCLOSE(*s);    }#ifndef DOSPATH#if !defined(NO_IOCTL) || defined(USE_FCNTL)    else {	/*	**  Make the socket blocking again on good connect.	*/#ifdef USE_FCNTL	int ret = fcntl(*s, F_SETFL, 0);#else	int val = 0;	int ret = IOCTL(*s, FIONBIO, &val);#endif /* USE_FCNTL */	if (ret == -1)	    _HTProgress(gettext("Could not restore socket to blocking."));    }#endif /* !NO_IOCTL || USE_FCNTL */#endif /* !DOSPATH */#ifdef INET6    FREE(line);    freeaddrinfo(res0);#endif /* INET6 */    return status;}/***  This is so interruptible reads can be implemented cleanly.*/PUBLIC int HTDoRead ARGS3(	int,		fildes,	void *,		buf,	unsigned,	nbyte){    int ready, ret;    fd_set readfds;    struct timeval select_timeout;    int tries=0;#ifdef EXP_READPROGRESS    int otries = 0;    time_t otime = time((time_t *)0);#endif#if defined(UNIX) || defined(UCX)    int nb;#endif /* UCX, BSN */#ifdef UNIX    if (fildes == 0) {	/*	 *  0 can be a valid socket fd, but if it's a tty something must	 *  have gone wrong. - kw	 */	if (isatty(fildes)) {	    CTRACE((tfp, "HTDoRead - refusing to read fd 0 which is a tty!\n"));	    return -1;	}    } else#endif    if (fildes <= 0)	return -1;    if (HTCheckForInterrupt()) {#ifdef _WINDOWS	WSASetLastError(EINTR);#else	SOCKET_ERRNO = EINTR;#endif	return (HT_INTERRUPTED);    }#if !defined(NO_IOCTL)    ready = 0;#else    ready = 1;#endif /* bypass for NO_IOCTL */    while (!ready) {	/*	**  Protect against an infinite loop.	*/	if (tries++ >= 180000) {	    HTAlert(gettext("Socket read failed for 180,000 tries."));#ifdef _WINDOWS	    WSASetLastError(EINTR);#else	    SOCKET_ERRNO = EINTR;#endif	    return HT_INTERRUPTED;	}#ifdef EXP_READPROGRESS	if (tries - otries > 10) {	    time_t t = time((time_t *)0);	    otries = tries;	    if (t - otime >= 5) {		otime = t;		HTReadProgress(-1, 0);	/* Put "stalled" message */	    }	}#endif	/*	**  If we suspend, then it is possible that select will be	**  interrupted.  Allow for this possibility. - JED	*/	do {	    select_timeout.tv_sec = 0;	    select_timeout.tv_usec = 100000;	    FD_ZERO(&readfds);	    FD_SET((unsigned)fildes, &readfds);#ifdef SOCKS	    if (socks_flag)		ret = Rselect(FD_SETSIZE,			      (void *)&readfds, NULL, NULL, &select_timeout);	    else#endif /* SOCKS */		ret = select(FD_SETSIZE,			     (void *)&readfds, NULL, NULL, &select_timeout);	} while ((ret == -1) && (errno == EINTR));	if (ret < 0) {	    return -1;	} else if (ret > 0) {	    ready = 1;	} else if (HTCheckForInterrupt()) {#ifdef _WINDOWS	    WSASetLastError(EINTR);#else	    SOCKET_ERRNO = EINTR;#endif	    return HT_INTERRUPTED;	}    }#if !defined(UCX) || !defined(VAXC)#ifdef UNIX    while ((nb = SOCKET_READ (fildes, buf, nbyte)) == -1) {	if (errno == EINTR)	    continue;#ifdef ERESTARTSYS	if (errno == ERESTARTSYS)	    continue;#endif /* ERESTARTSYS */	HTInetStatus("read");	break;    }    return nb;#else  /* UNIX */    return SOCKET_READ (fildes, buf, nbyte);#endif /* !UNIX */#else  /* UCX && VAXC */    /*    **	VAXC and UCX problem only.    */    errno = vaxc$errno = 0;    nb = SOCKET_READ (fildes, buf, nbyte);    CTRACE((tfp,	   "Read - nb,errno,vaxc$errno: %d %d %d\n", nb,errno,vaxc$errno));    if ((nb <= 0) && TRACE)	perror ("HTTCP.C:HTDoRead:read");	   /* RJF */    /*    **	An errno value of EPIPE and nb < 0 indicates end-of-file on VAXC.    */    if ((nb <= 0) && (errno == EPIPE)) {	nb = 0;	set_errno(0);    }    return nb;#endif /* UCX, BSN */}#ifdef SVR4_BSDSELECT/***  This is a fix for the difference between BSD's select() and**  SVR4's select().  SVR4's select() can never return a value larger**  than the total number of file descriptors being checked.  So, if**  you select for read and write on one file descriptor, and both**  are true, SVR4 select() will only return 1.  BSD select in the**  same situation will return 2.****	Additionally, BSD select() on timing out, will zero the masks,**	while SVR4 does not.  This is fixed here as well.****	Set your tabstops to 4 characters to have this code nicely formatted.****	Jerry Whelan, guru@bradley.edu, June 12th, 1993*/#ifdef select#undef select#endif /* select */#ifdef SOCKS#ifdef Rselect#undef Rselect#endif /* Rselect */#endif /* SOCKS */#include <sys/types.h>#include <sys/time.h>#include <sys/select.h>PUBLIC int BSDselect ARGS5(	int,			nfds,	fd_set *,		readfds,	fd_set *,		writefds,	fd_set *,		exceptfds,	struct timeval *,	select_timeout){    int rval,    i;#ifdef SOCKS    if (socks_flag)	rval = Rselect(nfds, readfds, writefds, exceptfds, select_timeout);    else#endif /* SOCKS */    rval = select(nfds, readfds, writefds, exceptfds, select_timeout);    switch (rval) {	case -1:	    return(rval);	case 0:	    if (readfds != NULL)		FD_ZERO(readfds);	    if (writefds != NULL)		FD_ZERO(writefds);	    if (exceptfds != NULL)		FD_ZERO(exceptfds);	    return(rval);	default:	    for (i = 0, rval = 0; i < nfds; i++) {		if ((readfds != NULL) && FD_ISSET(i, readfds))		    rval++;		if ((writefds != NULL) && FD_ISSET(i, writefds))		    rval++;		if ((exceptfds != NULL) && FD_ISSET(i, exceptfds))		    rval++;	    }	    return(rval);    }/* Should never get here */}#endif /* SVR4_BSDSELECT */

⌨️ 快捷键说明

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