HTTCP.c
Upload User: zlh9724
Upload Date: 2007-01-04
Package Size: 1991k
Code Size: 30k
Category:

Browser Client

Development Platform:

Unix_Linux

  1. /* HTTCP.c
  2. ** GENERIC COMMUNICATION CODE
  3. **
  4. ** (c) COPYRIGHT MIT 1995.
  5. ** Please first read the full copyright statement in the file COPYRIGH.
  6. **
  7. ** This code is in common between client and server sides.
  8. **
  9. ** 16 Jan 92  TBL Fix strtol() undefined on CMU Mach.
  10. ** 25 Jun 92  JFG  Added DECNET option through TCP socket emulation.
  11. ** 13 Sep 93  MD   Added correct return of vmserrorno for HTInetStatus.
  12. ** Added decoding of vms error message for MULTINET.
  13. ** 31 May 94  HF Added cache on host id's; now use inet_ntoa() to
  14. ** HTInetString and some other fixes. Added HTDoConnect
  15. ** and HTDoAccept
  16. */
  17. /* Library include files */
  18. #include "tcp.h"
  19. #include "HTUtils.h"
  20. #include "HTString.h"
  21. #include "HTAtom.h"
  22. #include "HTList.h"
  23. #include "HTParse.h"
  24. #include "HTAlert.h"
  25. #include "HTError.h"
  26. #include "HTReqMan.h"
  27. #include "HTNetMan.h"
  28. #include "HTDNS.h"
  29. #include "HTTCP.h"  /* Implemented here */
  30. /* VMS stuff */
  31. #ifdef VMS
  32. #ifndef MULTINET
  33. #define FD_SETSIZE 32
  34. #else /* Multinet */
  35. #define FD_SETSIZE 256
  36. #endif /* Multinet */
  37. #endif /* VMS */
  38. /* Macros and other defines */
  39. /* x seconds penalty on a multi-homed host if IP-address is down */
  40. #define TCP_PENALTY 1200
  41. /* x seconds penalty on a multi-homed host if IP-address is timed out */
  42. #define TCP_DELAY 600
  43. #ifndef RESOLV_CONF
  44. #define RESOLV_CONF "/etc/resolv.conf"
  45. #endif
  46. PRIVATE char *hostname = NULL;     /* The name of this host */
  47. PRIVATE char *mailaddress = NULL;      /* Current mail address */
  48. /* ------------------------------------------------------------------------- */
  49. /*
  50. ** Returns the string equivalent to the errno passed in the argument.
  51. ** We can't use errno directly as we have both errno and socerrno. The
  52. ** result is a static buffer.
  53. */
  54. PUBLIC CONST char * HTErrnoString (int errornumber)
  55. {
  56. #ifdef HAVE_STRERROR
  57.     return strerror(errornumber);
  58. #else
  59. #ifdef VMS
  60.     static char buf[60];
  61.     sprintf(buf,"Unix errno = %ld dec, VMS error = %lx hex", errornumber,
  62.     vaxc$errno);
  63.     return buf;
  64. #else 
  65. #ifdef _WINSOCKAPI_ 
  66. static char buf[60];
  67. sprintf(buf, "Unix errno = %ld dec, WinSock erro = %ld", errornumber, WSAGetLastError());
  68. return buf;
  69. #else
  70.     return (errornumber < sys_nerr ? sys_errlist[errornumber]:"Unknown error");
  71. #endif  /* WINDOWS */
  72. #endif /* VMS */
  73. #endif /* HAVE_STRERROR */
  74. }
  75. /* Debug error message
  76. */
  77. PUBLIC int HTInetStatus (int errnum, char * where)
  78. {
  79. #if ! (defined(VMS) || defined(WINDOWS))
  80.     if (PROT_TRACE)
  81. TTYPrint(TDEST, "TCP errno... %d after call to %s() failed.n............ %sn", errno, where, HTErrnoString(errnum));
  82. #else /* VMS */
  83. #ifdef VMS 
  84.     if (PROT_TRACE) TTYPrint(TDEST, "         Unix error number          = %ld decn", errno);
  85.     if (PROT_TRACE) TTYPrint(TDEST, "         VMS error                  = %lx hexn", vaxc$errno);
  86. #endif
  87. #ifdef WINDOWS 
  88.     if (PROT_TRACE) TTYPrint(TDEST, "         Unix error number          = %ld decn", errno);
  89.     if (PROT_TRACE) TTYPrint(TDEST, "         NT error                  = %lx hexn", WSAGetLastError());
  90. #endif 
  91. #ifdef MULTINET
  92.     if (PROT_TRACE) TTYPrint(TDEST, "         Multinet error             = %lx hexn", socket_errno); 
  93.     if (PROT_TRACE) TTYPrint(TDEST, "         Error String               = %sn", vms_errno_string());
  94. #endif /* MULTINET */
  95. #endif /* VMS */
  96. #ifdef VMS
  97.     /* errno happen to be zero if vaxc$errno <> 0 */
  98.     return -vaxc$errno;
  99. #else
  100.     return -errno;
  101. #endif
  102. }
  103. /* Parse a cardinal value        parse_cardinal()
  104. ** ----------------------
  105. **
  106. ** On entry,
  107. ** *pp     points to first character to be interpreted, terminated by
  108. **     non 0:9 character.
  109. ** *pstatus    points to status already valid
  110. ** maxvalue    gives the largest allowable value.
  111. **
  112. ** On exit,
  113. ** *pp     points to first unread character
  114. ** *pstatus    points to status updated iff bad
  115. */
  116. PUBLIC unsigned int HTCardinal (int * pstatus,
  117. char ** pp,
  118. unsigned int max_value)
  119. {
  120.     unsigned int n=0;
  121.     if ( (**pp<'0') || (**pp>'9')) {     /* Null string is error */
  122. *pstatus = -3;  /* No number where one expeceted */
  123. return 0;
  124.     }
  125.     while ((**pp>='0') && (**pp<='9')) n = n*10 + *((*pp)++) - '0';
  126.     if (n>max_value) {
  127. *pstatus = -4;  /* Cardinal outside range */
  128. return 0;
  129.     }
  130.     return n;
  131. }
  132. /* ------------------------------------------------------------------------- */
  133. /*                 SIGNAL HANDLING       */
  134. /* ------------------------------------------------------------------------- */
  135. #ifdef WWWLIB_SIG
  136. /*     HTSetSignal
  137. **  This function sets up signal handlers. This might not be necessary to
  138. **  call if the application has its own handlers.
  139. */
  140. #include <signal.h>
  141. PUBLIC void HTSetSignal (void)
  142. {
  143.     /* On some systems (SYSV) it is necessary to catch the SIGPIPE signal
  144.     ** when attemting to connect to a remote host where you normally should
  145.     ** get `connection refused' back
  146.     */
  147.     if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
  148. if (PROT_TRACE) TTYPrint(TDEST, "HTSignal.... Can't catch SIGPIPEn");
  149.     } else {
  150. if (PROT_TRACE) TTYPrint(TDEST, "HTSignal.... Ignoring SIGPIPEn");
  151.     }
  152. }
  153. #else
  154. #ifdef WWW_WIN_DLL
  155. PUBLIC void HTSetSignal (void) {}
  156. #endif /* WWW_WIN_DLL */
  157. #endif /* WWWLIB_SIG */
  158. /* ------------------------------------------------------------------------- */
  159. /*              HOST NAME FUNCTIONS       */
  160. /* ------------------------------------------------------------------------- */
  161. /* Produce a string for an Internet address
  162. ** ----------------------------------------
  163. **
  164. ** On exit,
  165. ** returns a pointer to a static string which must be copied if
  166. ** it is to be kept.
  167. */
  168. PUBLIC CONST char * HTInetString (SockA * sin)
  169. {
  170. #ifndef DECNET  /* Function only used below for a trace message */
  171. #if 0
  172.     /* This dumps core on some Sun systems :-(. The problem is now, that 
  173.        the current implememtation only works for IP-addresses and not in
  174.        other address spaces. */
  175.     return inet_ntoa(sin->sin_addr);
  176. #endif
  177.     static char string[16];
  178.     sprintf(string, "%d.%d.%d.%d",
  179.     (int)*((unsigned char *)(&sin->sin_addr)+0),
  180.     (int)*((unsigned char *)(&sin->sin_addr)+1),
  181.     (int)*((unsigned char *)(&sin->sin_addr)+2),
  182.     (int)*((unsigned char *)(&sin->sin_addr)+3));
  183.     return string;
  184. #else
  185.     return "";
  186. #endif /* Decnet */
  187. }
  188. /* Parse a network node address and port
  189. ** -------------------------------------
  190. **  It is assumed that any portnumber and numeric host address
  191. ** is given in decimal notation. Separation character is '.'
  192. ** Any port number given in host name overrides all other values.
  193. ** 'host' might be modified.
  194. **      Returns:
  195. **         >0 Number of homes
  196. **  0 Wait for persistent socket
  197. ** -1 Error
  198. */
  199. PRIVATE int HTParseInet (HTNet * net, char * host)
  200. {
  201.     int status = 1;
  202.     SockA *sin = &net->sock_addr;
  203. #ifdef DECNET
  204.     /* read Decnet node name. @@ Should know about DECnet addresses, but it's
  205.        probably worth waiting until the Phase transition from IV to V. */
  206.     sin->sdn_nam.n_len = min(DN_MAXNAML, strlen(host));  /* <=6 in phase 4 */
  207.     strncpy (sin->sdn_nam.n_name, host, sin->sdn_nam.n_len + 1);
  208.     if (PROT_TRACE) TTYPrint(TDEST,  
  209. "DECnet: Parsed address as object number %d on host %.6s...n",
  210.       sin->sdn_objnum, host);
  211. #else /* Internet */
  212.     {
  213. char *strptr = host;
  214. while (*strptr) {
  215.     if (*strptr == ':') {
  216. *strptr = '';    /* Don't want port number in numeric host */
  217. break;
  218.     }
  219.     if (!isdigit(*strptr) && *strptr != '.')
  220. break;
  221.     strptr++;
  222. }
  223. if (!*strptr) {
  224. #ifdef GUSI
  225.     sin->sin_addr = inet_addr(host);   /* See netinet/in.h */
  226. #else
  227.     sin->sin_addr.s_addr = inet_addr(host);   /* See arpa/inet.h */
  228. #endif
  229. } else
  230.     status = HTGetHostByName(net, host);
  231. if (PROT_TRACE) {
  232.     if (status > 0)
  233. TTYPrint(TDEST, "ParseInet... as port %d on %s with %d homesn",
  234. (int) ntohs(sin->sin_port), HTInetString(sin), status);
  235. }
  236.     }
  237. #endif /* Internet vs. Decnet */
  238.     return status;
  239. }
  240. /* HTGetDomainName
  241. ** Returns the current domain name without the local host name.
  242. ** The response is pointing to a static area that might be changed
  243. ** using HTSetHostName().
  244. **
  245. ** Returns NULL on error, "" if domain name is not found
  246. */
  247. PUBLIC CONST char *HTGetDomainName (void)
  248. {
  249.     CONST char *host = HTGetHostName();
  250.     char *domain;
  251.     if (host && *host) {
  252. if ((domain = strchr(host, '.')) != NULL)
  253.     return ++domain;
  254. else
  255.     return "";
  256.     } else
  257. return NULL;
  258. }
  259. /* HTSetHostName
  260. ** Sets the current hostname inclusive domain name.
  261. ** If this is not set then the default approach is used using
  262. ** HTGetHostname().
  263. */
  264. PUBLIC void HTSetHostName (char * host)
  265. {
  266.     if (host && *host) {
  267. char *strptr;
  268. StrAllocCopy(hostname, host);
  269. strptr = hostname;
  270. while (*strptr) {
  271.     *strptr = TOLOWER(*strptr);
  272.     strptr++;
  273. }
  274. if (*(hostname+strlen(hostname)-1) == '.')    /* Remove trailing dot */
  275.     *(hostname+strlen(hostname)-1) = '';
  276.     } else {
  277. if (PROT_TRACE) TTYPrint(TDEST, "SetHostName. Bad argument ignoredn");
  278.     }
  279. }
  280. /* HTGetHostName
  281. ** Returns the name of this host. It uses the following algoritm:
  282. **
  283. ** 1) gethostname()
  284. ** 2) if the hostname doesn't contain any '.' try to read
  285. **    /etc/resolv.conf. If there is no domain line in this file then
  286. ** 3) Try getdomainname and do as the man pages say for resolv.conf (sun)
  287. **    If there is no domain line in this file, then it is derived
  288. **    from the domain name set by the domainname(1) command, usually
  289. **    by removing the first component. For example, if the domain-
  290. **    name is set to ``foo.podunk.edu'' then the default domain name
  291. **    used will be ``pudunk.edu''.
  292. **
  293. ** This is the same procedure as used by res_init() and sendmail.
  294. **
  295. ** Return: hostname on success else NULL
  296. */
  297. PUBLIC CONST char * HTGetHostName (void)
  298. {
  299.     BOOL got_it = NO;
  300.     FILE *fp;
  301.     char name[MAXHOSTNAMELEN+1];
  302.     if (hostname) {           /* If already done */
  303. if (*hostname)
  304.     return hostname;
  305. else
  306.     return NULL;     /* We couldn't get the last time */
  307.     }
  308.     *(name+MAXHOSTNAMELEN) = '';
  309. #ifndef NO_GETHOSTNAME
  310.     if (gethostname(name, MAXHOSTNAMELEN)) {       /* Maybe without domain */
  311. if (PROT_TRACE)
  312.     TTYPrint(TDEST, "HostName.... Can't get host namen");
  313. return NULL;
  314.     }
  315.     if (PROT_TRACE)
  316. TTYPrint(TDEST, "HostName.... Local host name is  `%s'n", name);
  317.     StrAllocCopy(hostname, name);
  318.     {
  319. char *strptr = strchr(hostname, '.');
  320. if (strptr != NULL)    /* We have it all */
  321.     got_it = YES;
  322.     }
  323. #ifndef NO_RESOLV_CONF
  324.     /* Now try the resolver config file */
  325.     if (!got_it && (fp = fopen(RESOLV_CONF, "r")) != NULL) {
  326. char buffer[80];
  327. *(buffer+79) = '';
  328. while (fgets(buffer, 79, fp)) {
  329.     if (!strncasecomp(buffer, "domain", 6)) {
  330. char *domainstr = buffer+6;
  331. char *end;
  332. while (*domainstr == ' ' || *domainstr == 't')
  333.     domainstr++;
  334. end = domainstr;
  335. while (*end && !isspace(*end))
  336.     end++;
  337. *end = '';
  338. if (*domainstr) {
  339.     StrAllocCat(hostname, ".");
  340.     StrAllocCat(hostname, domainstr);
  341.     got_it = YES;
  342.     break;
  343. }
  344.     }
  345. }
  346. fclose(fp);
  347.     }
  348. #endif /* NO_RESOLV_CONF */
  349. #ifndef NO_GETDOMAINNAME
  350.     /* If everything else has failed then try getdomainname */
  351.     if (!got_it) {
  352. if (getdomainname(name, MAXHOSTNAMELEN)) {
  353.     if (PROT_TRACE)
  354. TTYPrint(TDEST, "HostName.... Can't get domain namen");
  355.     StrAllocCopy(hostname, "");
  356.     return NULL;
  357. }
  358. /* If the host name and the first part of the domain name are different
  359.    then use the former as it is more exact (I guess) */
  360. if (strncmp(name, hostname, (int) strlen(hostname))) {
  361.     char *domain = strchr(name, '.');
  362.     if (!domain)
  363. domain = name;
  364.     StrAllocCat(hostname, domain);
  365. }
  366.     }
  367. #endif /* NO_GETDOMAINNAME */
  368.     {
  369. char *strptr = hostname;
  370. while (*strptr) {     
  371.     *strptr = TOLOWER(*strptr);
  372.     strptr++;
  373. }
  374. if (*(hostname+strlen(hostname)-1) == '.')    /* Remove trailing dot */
  375.     *(hostname+strlen(hostname)-1) = '';
  376.     }
  377. #endif /* NO_GETHOSTNAME */
  378.     if (PROT_TRACE)
  379. TTYPrint(TDEST, "HostName.... Full host name is `%s'n", hostname);
  380.     return hostname;
  381. }
  382. /*
  383. ** Free the host name. Called from HTLibTerminate
  384. */
  385. PUBLIC void HTFreeHostName (void)
  386. {
  387.     HT_FREE(hostname);
  388. }
  389. /*        HTSetMailAddress
  390. ** Sets the current mail address plus host name and domain name.
  391. ** If this is not set then the default approach is used using
  392. ** HTGetMailAddress(). If the argument is NULL or "" then HTGetMailAddress
  393. ** returns NULL on a succeding request.
  394. */
  395. PUBLIC void HTSetMailAddress (char * address)
  396. {
  397.     if (!address || !*address)
  398. StrAllocCopy(mailaddress, "");
  399.     else
  400. StrAllocCopy(mailaddress, address);
  401.     if (WWWTRACE)
  402. TTYPrint(TDEST, "SetMailAdr.. Set mail address to `%s'n",
  403. mailaddress);
  404. }
  405. /*        HTGetMailAddress
  406. **
  407. ** Get the mail address of the current user on the current host. The
  408. ** domain name used is the one initialized in HTSetHostName or
  409. ** HTGetHostName. The login name is determined using (ordered):
  410. **
  411. ** getlogin
  412. ** getpwuid(getuid())
  413. **
  414. ** The weakness about the last attempt is if the user has multiple
  415. ** login names each with the same user ID. If this fails as well then:
  416. **
  417. ** LOGNAME environment variable
  418. ** USER environment variable
  419. **
  420. ** Returns NULL if error else pointer to static string
  421. */
  422. PUBLIC CONST char * HTGetMailAddress (void)
  423. {
  424. #ifdef HT_REENTRANT
  425.     char name[LOGNAME_MAX+1];    /* For getlogin_r */
  426. #endif
  427.     char *login;
  428.     CONST char *domain;
  429.     struct passwd *pw_info;
  430.     if (mailaddress) {
  431. if (*mailaddress)
  432.     return mailaddress;
  433. else
  434.     return NULL;       /* No luck the last time so we wont try again */
  435.     }
  436. #ifdef VMS
  437.     if ((login = (char *) cuserid(NULL)) == NULL) {
  438.         if (PROT_TRACE) TTYPrint(TDEST, "MailAddress. cuserid returns NULLn");
  439.     }
  440. #else
  441. #ifdef WIN32 
  442.     login = getenv("USERNAME") ;
  443. #else 
  444. #ifdef WWW_MSWINDOWS
  445.     login = "PCUSER";   /* @@@ COULD BE BETTER @@@ */
  446. #else
  447. #ifdef GUSI
  448.     if ((login = getenv("LOGNAME")) == NULL) 
  449. login = "MACUSER";
  450. #else /* Unix like... */
  451. #ifdef HT_REENTRANT
  452.     if ((login = (char *) getlogin_r(name, LOGNAME_MAX)) == NULL) {
  453. #else
  454.     if ((login = (char *) getlogin()) == NULL) {
  455. #endif
  456. if (PROT_TRACE)
  457.     TTYPrint(TDEST, "MailAddress. getlogin returns NULLn");
  458. if ((pw_info = getpwuid(getuid())) == NULL) {
  459.     if (PROT_TRACE)
  460. TTYPrint(TDEST, "MailAddress. getpwid returns NULLn");
  461.     if ((login = getenv("LOGNAME")) == NULL) {
  462. if (PROT_TRACE)
  463.     TTYPrint(TDEST, "MailAddress. LOGNAME not foundn");
  464. if ((login = getenv("USER")) == NULL) {
  465.     if (PROT_TRACE)
  466. TTYPrint(TDEST,"MailAddress. USER not foundn");
  467.     return NULL; /* I GIVE UP */
  468. }
  469.     }
  470. } else
  471.     login = pw_info->pw_name;
  472.     }
  473. #endif /* GUSI */
  474. #endif /* WWW_MSWINDOWS */
  475. #endif /* WIN32 */
  476. #endif /* VMS */
  477.     if (login) {
  478. StrAllocCopy(mailaddress, login);
  479. StrAllocCat(mailaddress, "@");
  480. if ((domain = HTGetHostName()) != NULL)
  481.     StrAllocCat(mailaddress, domain);
  482. else {
  483.     *mailaddress = '';
  484.     return NULL; /* Domain name not available */
  485. }
  486. return mailaddress;
  487.     }
  488.     return NULL;
  489. }
  490. /*
  491. ** Free the mail address. Called from HTLibTerminate
  492. */
  493. PUBLIC void HTFreeMailAddress (void)
  494. {
  495.     HT_FREE(mailaddress);
  496. }
  497. /* ------------------------------------------------------------------------- */
  498. /*               CONNECTION ESTABLISHMENT MANAGEMENT       */
  499. /* ------------------------------------------------------------------------- */
  500. /* HTDoConnect()
  501. **
  502. ** Note: Any port indication in URL, e.g., as `host:port' overwrites
  503. ** the default port value.
  504. **
  505. ** returns HT_ERROR Error has occured or interrupted
  506. ** HT_OK if connected
  507. ** HT_WOULD_BLOCK  if operation would have blocked
  508. */
  509. PUBLIC int HTDoConnect (HTNet * net, char * url, u_short default_port)
  510. {
  511.     int status;
  512.     HTRequest * request = net->request;
  513.     char *fullhost = HTParse(url, "", PARSE_HOST);
  514.     char *at_sign;
  515.     char *host;
  516.     /* if there's an @ then use the stuff after it as a hostname */
  517.     if ((at_sign = strchr(fullhost, '@')) != NULL)
  518. host = at_sign+1;
  519.     else
  520. host = fullhost;
  521.     if (!*host) {
  522. HTRequest_addError(request, ERR_FATAL, NO, HTERR_NO_HOST,
  523.    NULL, 0, "HTDoConnect");
  524. HT_FREE(fullhost);
  525. return HT_ERROR;
  526.     }
  527.     /* Jump into the state machine */
  528.     while (1) {
  529. switch (net->tcpstate) {
  530.   case TCP_BEGIN:
  531.     {
  532. char *port = strchr(host, ':');
  533. SockA *sin = &net->sock_addr;
  534. memset((void *) sin, '', sizeof(SockA));
  535. if (port++ && isdigit(*port)) {
  536. #ifdef DECNET
  537.     sin->sdn_family = AF_DECnet;
  538.     sin->sdn_objnum=(unsigned char)(strtol(port,(char**)0,10));
  539. #else
  540.     sin->sin_family = AF_INET;
  541.     sin->sin_port = htons(atol(port));
  542. #endif
  543. } else {
  544. #ifdef DECNET
  545.     sin->sdn_family = AF_DECnet;
  546.     net->sock_addr.sdn_objnum = DNP_OBJ;
  547. #else  /* Internet */
  548.     sin->sin_family = AF_INET;
  549.     sin->sin_port = htons(default_port);
  550. #endif
  551. }
  552.     }
  553.     if (PROT_TRACE)
  554. TTYPrint(TDEST, "HTDoConnect. Looking up `%s'n", host);
  555.     net->tcpstate = TCP_DNS;
  556.     break;
  557.   case TCP_DNS:
  558.     if ((status = HTParseInet(net, host)) < 0) {
  559. if (PROT_TRACE)
  560.     TTYPrint(TDEST, "HTDoConnect. Can't locate `%s'n", host);
  561. HTRequest_addError(request, ERR_FATAL, NO,HTERR_NO_REMOTE_HOST,
  562.    (void *) host, strlen(host), "HTDoConnect");
  563. net->tcpstate = TCP_ERROR;
  564. break;
  565.     }
  566.     /*
  567.     ** Wait for a persistent connection. When we return, we check
  568.     ** that the socket hasn't been closed in the meantime
  569.     */
  570.     if (!status) {
  571. net->tcpstate = TCP_NEED_CONNECT;
  572. HT_FREE(fullhost);
  573. HTNet_wait(net);
  574. return HT_PERSISTENT;
  575.     }
  576.     if (!net->retry && status > 1) /* If multiple homes */
  577. net->retry = status;
  578.     if (net->sockfd != INVSOC) {    /* Reusing socket */
  579. if (PROT_TRACE)
  580.     TTYPrint(TDEST, "HTDoConnect. REUSING SOCKET %dn",
  581.     net->sockfd);
  582. net->tcpstate = TCP_CONNECTED;
  583.     } else
  584. net->tcpstate = TCP_NEED_SOCKET;
  585.     break;
  586.   case TCP_NEED_SOCKET:
  587. #ifdef DECNET
  588.     if ((net->sockfd=socket(AF_DECnet, SOCK_STREAM, 0))==INVSOC)
  589. #else
  590.     if ((net->sockfd=socket(AF_INET, SOCK_STREAM,IPPROTO_TCP))==INVSOC)
  591. #endif
  592.     {
  593. HTRequest_addSystemError(request, ERR_FATAL, socerrno, NO, "socket");
  594. net->tcpstate = TCP_ERROR;
  595. break;
  596.     }
  597.     if (PROT_TRACE)
  598. TTYPrint(TDEST, "HTDoConnect. Created socket %dn",net->sockfd);
  599.     /* If non-blocking protocol then change socket status
  600.     ** I use FCNTL so that I can ask the status before I set it.
  601.     ** See W. Richard Stevens (Advan. Prog. in UNIX environment, p.364)
  602.     ** Be CAREFULL with the old `O_NDELAY' - it will not work as read()
  603.     ** returns 0 when blocking and NOT -1. FNDELAY is ONLY for BSD and
  604.     ** does NOT work on SVR4 systems. O_NONBLOCK is POSIX.
  605.     */
  606.     if (!net->preemptive) {
  607. #ifdef _WINSOCKAPI_
  608. { /* begin windows scope  */
  609.     HTRequest * rq = request;
  610.     long levents = FD_READ | FD_WRITE | FD_ACCEPT | 
  611. FD_CONNECT | FD_CLOSE ;
  612.     int rv = 0 ;
  613.     
  614. #ifdef WWW_WIN_ASYNC
  615.     /* N.B WSAAsyncSelect() turns on non-blocking I/O */
  616.     rv = WSAAsyncSelect( net->sockfd, rq->hwnd, 
  617. rq->winMsg, levents);
  618.     if (rv == SOCKET_ERROR) {
  619. status = -1 ;
  620. if (PROT_TRACE) 
  621.     TTYPrint(TDEST, "HTDoConnect. WSAAsyncSelect() fails: %dn", 
  622.      WSAGetLastError());
  623.     } /* error returns */
  624. #else
  625.     int enable = 1;
  626.     status = IOCTL(net->sockfd, FIONBIO, &enable);
  627. #endif
  628. } /* end scope */
  629. #else 
  630. #if defined(VMS)
  631. {
  632.     int enable = 1;
  633.     status = IOCTL(net->sockfd, FIONBIO, &enable);
  634. }
  635. #else
  636. if((status = FCNTL(net->sockfd, F_GETFL, 0)) != -1) {
  637.     status |= O_NONBLOCK; /* POSIX */
  638.     status = FCNTL(net->sockfd, F_SETFL, status);
  639. }
  640. #endif /* VMS */
  641. #endif /* WINDOW */
  642. if (PROT_TRACE) {
  643.     if (status == -1)
  644. TTYPrint(TDEST, "HTDoConnect. Only blocking worksn");
  645.     else
  646. TTYPrint(TDEST, "HTDoConnect. Non-blocking socketn");
  647. }
  648.     } else if (PROT_TRACE)
  649. TTYPrint(TDEST, "HTDoConnect. Blocking socketn");
  650.     /* If multi-homed host then start timer on connection */
  651.     if (net->retry) net->connecttime = time(NULL);
  652.     /* Progress */
  653.     {
  654. HTAlertCallback *cbf = HTAlert_find(HT_PROG_CONNECT);
  655. if (cbf)
  656.   (*cbf)(request,HT_PROG_CONNECT,HT_MSG_NULL,NULL,host,NULL);
  657.     }
  658.     net->tcpstate = TCP_NEED_CONNECT;
  659.     break;
  660.   case TCP_NEED_CONNECT:
  661.     status = connect(net->sockfd, (struct sockaddr *) &net->sock_addr,
  662.      sizeof(net->sock_addr));
  663.     /*
  664.      * According to the Sun man page for connect:
  665.      *     EINPROGRESS         The socket is non-blocking and the  con-
  666.      *                         nection cannot be completed immediately.
  667.      *                         It is possible to select(2) for  comple-
  668.      *                         tion  by  selecting the socket for writ-
  669.      *                         ing.
  670.      * According to the Motorola SVR4 man page for connect:
  671.      *     EAGAIN              The socket is non-blocking and the  con-
  672.      *                         nection cannot be completed immediately.
  673.      *                         It is possible to select for  completion
  674.      *                         by  selecting  the  socket  for writing.
  675.      *                         However, this is only  possible  if  the
  676.      *                         socket  STREAMS  module  is  the topmost
  677.      *                         module on  the  protocol  stack  with  a
  678.      *                         write  service  procedure.  This will be
  679.      *                         the normal case.
  680.      */
  681. #ifdef _WINSOCKAPI_
  682.     if (status == SOCKET_ERROR)
  683. #else
  684.     if (status < 0) 
  685. #endif
  686.     {
  687. #ifdef EAGAIN
  688. if (socerrno==EINPROGRESS || socerrno==EAGAIN)
  689. #else 
  690. #ifdef _WINSOCKAPI_
  691. if (socerrno==WSAEWOULDBLOCK)
  692. #else
  693. if (socerrno==EINPROGRESS)
  694. #endif /* _WINSOCKAPI_ */
  695. #endif /* EAGAIN */
  696. {
  697.     if (PROT_TRACE)
  698. TTYPrint(TDEST,"HTDoConnect. WOULD BLOCK `%s'n",host);
  699.     HTEvent_Register(net->sockfd, request, (SockOps)FD_CONNECT,
  700.      net->cbf, net->priority);
  701.     HT_FREE(fullhost);
  702.     return HT_WOULD_BLOCK;
  703. }
  704. if (socerrno == EISCONN) {
  705.     net->tcpstate = TCP_CONNECTED;
  706.     break;
  707. }
  708. #ifdef _WINSOCKAPI_
  709. if (socerrno == WSAEBADF)          /* We lost the socket */
  710. #else
  711. if (socerrno == EBADF)          /* We lost the socket */
  712. #endif
  713. {
  714.     net->tcpstate = TCP_NEED_SOCKET;
  715.     break;
  716. }
  717. if (net->retry) {
  718.     net->connecttime -= time(NULL);
  719.     /* Added EINVAL `invalid argument' as this is what I 
  720.        get back from a non-blocking connect where I should 
  721.        get `connection refused' on BSD. SVR4 gives SIG_PIPE */
  722. #if defined(__srv4__) || defined (_WINSOCKAPI_)
  723.     if (socerrno==ECONNREFUSED || socerrno==ETIMEDOUT ||
  724. socerrno==ENETUNREACH || socerrno==EHOSTUNREACH ||
  725. socerrno==EHOSTDOWN)
  726. #else
  727.     if (socerrno==ECONNREFUSED || socerrno==ETIMEDOUT ||
  728. socerrno==ENETUNREACH || socerrno==EHOSTUNREACH ||
  729. socerrno==EHOSTDOWN || socerrno==EINVAL)
  730. #endif
  731.         net->connecttime += TCP_DELAY;
  732.     else
  733.         net->connecttime += TCP_PENALTY;
  734.     HTDNS_updateWeigths(net->dns, net->home, net->connecttime);
  735. }
  736. net->tcpstate = TCP_ERROR;
  737.     } else
  738. net->tcpstate = TCP_CONNECTED;
  739.     break;
  740.   case TCP_CONNECTED:
  741.     HTEvent_UnRegister(net->sockfd, (SockOps) FD_CONNECT);
  742.     if (net->retry) {
  743. net->connecttime -= time(NULL);
  744. HTDNS_updateWeigths(net->dns, net->home, net->connecttime);
  745.     }
  746.     net->retry = 0;
  747.     HT_FREE(fullhost);
  748.     net->tcpstate = TCP_BEGIN;
  749.     return HT_OK;
  750.     break;
  751.   case TCP_NEED_BIND:
  752.   case TCP_NEED_LISTEN:
  753.   case TCP_ERROR:
  754.     if (PROT_TRACE) TTYPrint(TDEST, "HTDoConnect. Connect failedn");
  755.     if (net->sockfd != INVSOC) {
  756.         HTEvent_UnRegister(net->sockfd, (SockOps) FD_ALL);
  757. NETCLOSE(net->sockfd);
  758. net->sockfd = INVSOC;
  759. if (HTDNS_socket(net->dns) != INVSOC) {  /* Inherited socket */
  760.     HTDNS_setSocket(net->dns, INVSOC);
  761.     net->tcpstate = TCP_NEED_SOCKET;
  762.     break;
  763. }
  764.     }
  765.     /* Do we have more homes to try? */
  766.     if (--net->retry > 0) {
  767.         HTRequest_addSystemError(request, ERR_NON_FATAL, socerrno, NO,
  768.       "connect");
  769. net->tcpstate = TCP_DNS;
  770. break;
  771.     }
  772.     HTRequest_addSystemError(request, ERR_FATAL,socerrno,NO,"connect");
  773.     HTDNS_delete(host);
  774.     net->retry = 0;
  775.     HT_FREE(fullhost);
  776.     net->tcpstate = TCP_BEGIN;
  777.     return HT_ERROR;
  778.     break;
  779. }
  780.     }
  781. }
  782. /* HTDoAccept()
  783. ** ------------
  784. ** This function makes a non-blocking accept which will turn up as ready
  785. ** read in the select.
  786. ** Returns
  787. ** HT_ERROR Error has occured or interrupted
  788. ** HT_OK if connected
  789. ** HT_WOULD_BLOCK  if operation would have blocked
  790. */
  791. PUBLIC int HTDoAccept (HTNet * net)
  792. {
  793.     int status;
  794.     int size = sizeof(net->sock_addr);
  795.     HTRequest *request = net->request;
  796.     if (net->sockfd==INVSOC) {
  797. if (PROT_TRACE) TTYPrint(TDEST, "HTDoAccept.. Invalid socketn");
  798. return HT_ERROR;
  799.     }
  800.     /* Progress report */
  801.     {
  802. HTAlertCallback *cbf = HTAlert_find(HT_PROG_ACCEPT);
  803. if (cbf) (*cbf)(request, HT_PROG_ACCEPT, HT_MSG_NULL,NULL, NULL, NULL);
  804.     }
  805.     status = accept(net->sockfd, (struct sockaddr *) &net->sock_addr, &size);
  806. #ifdef _WINSOCKAPI_
  807.     if (status == SOCKET_ERROR)
  808. #else
  809.     if (status < 0) 
  810. #endif
  811.     {
  812. #ifdef EAGAIN
  813. if (socerrno==EINPROGRESS || socerrno==EAGAIN)
  814. #else 
  815. #ifdef _WINSOCKAPI_
  816.         if (socerrno==WSAEWOULDBLOCK)
  817. #else
  818. if (socerrno==EINPROGRESS)
  819. #endif /* _WINSOCKAPI_ */
  820. #endif /* EAGAIN */
  821. {
  822.     if (PROT_TRACE)
  823. TTYPrint(TDEST,"HTDoAccept.. WOULD BLOCK %dn", net->sockfd);
  824.     HTEvent_Register(net->sockfd, request, (SockOps) FD_ACCEPT,
  825.      net->cbf, net->priority);
  826.     return HT_WOULD_BLOCK;
  827. }
  828. HTRequest_addSystemError(request, ERR_WARN, socerrno, YES, "accept");
  829. if (PROT_TRACE) TTYPrint(TDEST, "HTDoAccept.. Accept failedn");
  830. if (HTDNS_socket(net->dns) != INVSOC) {    /* Inherited socket */
  831.     HTDNS_setSocket(net->dns, INVSOC);
  832. }
  833. return HT_ERROR;
  834.     }
  835.     /* Swap to new socket */
  836.     HTEvent_UnRegister(net->sockfd, (SockOps) FD_ACCEPT);
  837.     net->sockfd = status;
  838.     if (PROT_TRACE) TTYPrint(TDEST, "Accepted.... socket %dn", status);
  839.     return HT_OK;
  840. }
  841. /* HTDoListen
  842. ** ----------
  843. ** Listens on the specified port. 0 means that we chose it here
  844. ** If master==INVSOC then we listen on all local interfaces (using a 
  845. ** wildcard). If !INVSOC then use this as the local interface
  846. ** returns HT_ERROR Error has occured or interrupted
  847. ** HT_OK if connected
  848. */
  849. PUBLIC int HTDoListen (HTNet * net, u_short port, SOCKET master, int backlog)
  850. {
  851.     int status;
  852.     /* Jump into the state machine */
  853.     while (1) {
  854. switch (net->tcpstate) {
  855.   case TCP_BEGIN:
  856.     {
  857. SockA *sin = &net->sock_addr;
  858. memset((void *) sin, '', sizeof(SockA));
  859. #ifdef DECNET
  860. sin->sdn_family = AF_DECnet;
  861. sin->sdn_objnum = port;
  862. #else
  863. sin->sin_family = AF_INET;
  864. if (master != INVSOC) {
  865.     int len = sizeof(SockA);
  866.     if (getsockname(master, (struct sockaddr *) sin, &len)<0) {
  867. HTRequest_addSystemError(net->request, ERR_FATAL,
  868.  socerrno, NO, "getsockname");
  869. net->tcpstate = TCP_ERROR;
  870. break;
  871.     }
  872. } else
  873.     sin->sin_addr.s_addr = INADDR_ANY;
  874. sin->sin_port = htons(port);
  875. #endif
  876.     }
  877.     if (PROT_TRACE)
  878. TTYPrint(TDEST, "HTDoListen.. Listen on port %dn", port);
  879.     net->tcpstate = TCP_NEED_SOCKET;
  880.     break;
  881.   case TCP_NEED_SOCKET:
  882. #ifdef DECNET
  883.     if ((net->sockfd=socket(AF_DECnet, SOCK_STREAM, 0))==INVSOC)
  884. #else
  885.     if ((net->sockfd=socket(AF_INET, SOCK_STREAM,IPPROTO_TCP))==INVSOC)
  886. #endif
  887.     {
  888. HTRequest_addSystemError(net->request, ERR_FATAL, socerrno,
  889.  NO, "socket");
  890. net->tcpstate = TCP_ERROR;
  891. break;
  892.     }
  893.     if (PROT_TRACE)
  894. TTYPrint(TDEST, "HTDoListen.. Created socket %dn",net->sockfd);
  895.     /* If non-blocking protocol then change socket status
  896.     ** I use FCNTL so that I can ask the status before I set it.
  897.     ** See W. Richard Stevens (Advan. Prog. in UNIX environment, p.364)
  898.     ** Be CAREFULL with the old `O_NDELAY' - it will not work as read()
  899.     ** returns 0 when blocking and NOT -1. FNDELAY is ONLY for BSD and
  900.     ** does NOT work on SVR4 systems. O_NONBLOCK is POSIX.
  901.     */
  902.     if (!net->preemptive) {
  903. #ifdef _WINSOCKAPI_ 
  904. { /* begin windows scope  */
  905.     long levents = FD_READ | FD_WRITE | FD_ACCEPT | 
  906. FD_CONNECT | FD_CLOSE ;
  907.     int rv = 0 ;
  908.     
  909. #ifdef WWW_WIN_ASYNC
  910.     /* N.B WSAAsyncSelect() turns on non-blocking I/O */
  911.     rv = WSAAsyncSelect(net->sockfd, net->request->hwnd, 
  912. net->request->winMsg, levents);
  913.     if (rv == SOCKET_ERROR) {
  914. status = -1 ;
  915. if (PROT_TRACE) 
  916.     TTYPrint(TDEST, "HTDoListen.. WSAAsyncSelect() fails: %dn", 
  917.      WSAGetLastError());
  918. } /* error returns */
  919. #else
  920.     int enable = 1 ;
  921.     status = IOCTL(net->sockfd, FIONBIO, &enable);
  922. #endif
  923. } /* end scope */
  924. #else 
  925. #if defined(VMS)
  926. {
  927.     int enable = 1;
  928.     status = IOCTL(net->sockfd, FIONBIO, &enable);
  929. }
  930. #else
  931. if((status = FCNTL(net->sockfd, F_GETFL, 0)) != -1) {
  932.     status |= O_NONBLOCK;     /* POSIX */
  933.     status = FCNTL(net->sockfd, F_SETFL, status);
  934. }
  935. #endif /* VMS */
  936. #endif /* WINDOW */
  937. if (PROT_TRACE) {
  938.     if (status == -1)
  939. TTYPrint(TDEST, "HTDoListen.. Blocking socketn");
  940.     else
  941. TTYPrint(TDEST, "HTDoListen.. Non-blocking socketn");
  942. }
  943.     }
  944.     net->tcpstate = TCP_NEED_BIND;
  945.     break;
  946.   case TCP_NEED_BIND:
  947.     status = bind(net->sockfd, (struct sockaddr *) &net->sock_addr,
  948.   sizeof(net->sock_addr));
  949. #ifdef _WINSOCKAPI_
  950.     if (status == SOCKET_ERROR)
  951. #else
  952.     if (status < 0) 
  953. #endif
  954.     {
  955. if (PROT_TRACE)
  956.     TTYPrint(TDEST, "Bind........ failed %dn", socerrno);
  957. net->tcpstate = TCP_ERROR;
  958.     } else
  959. net->tcpstate = TCP_NEED_LISTEN;
  960.     break;
  961.   case TCP_NEED_LISTEN:
  962.     status = listen(net->sockfd, backlog);
  963. #ifdef _WINSOCKAPI_
  964.     if (status == SOCKET_ERROR)
  965. #else
  966.     if (status < 0) 
  967. #endif
  968. net->tcpstate = TCP_ERROR;
  969.     else
  970. net->tcpstate = TCP_CONNECTED;
  971.     break;
  972.   case TCP_CONNECTED:
  973.     net->tcpstate = TCP_BEGIN;
  974.     if (PROT_TRACE)
  975. TTYPrint(TDEST,"HTDoListen.. Bind and listen on port %d %sn",
  976. (int) ntohs(net->sock_addr.sin_port),
  977. HTInetString(&net->sock_addr));
  978.     return HT_OK;
  979.     break;
  980.   case TCP_NEED_CONNECT:
  981.   case TCP_DNS:
  982.   case TCP_ERROR:
  983.     if (PROT_TRACE) TTYPrint(TDEST, "HTDoListen.. Listen failedn");
  984.     HTRequest_addSystemError(net->request, ERR_FATAL, socerrno, NO, "HTDoListen");
  985.     net->tcpstate = TCP_BEGIN;
  986.     return HT_ERROR;
  987.     break;
  988. }
  989.     }
  990. }