home *** CD-ROM | disk | FTP | other *** search
/ Collection of Internet / Collection of Internet.iso / msdos / lynx / source / www / library / implemen / httcp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-25  |  10.4 KB  |  415 lines

  1. /*            Generic Communication Code        HTTCP.c
  2. **            ==========================
  3. **
  4. **    This code is in common between client and server sides.
  5. **
  6. **    16 Jan 92  TBL    Fix strtol() undefined on CMU Mach.
  7. **    25 Jun 92  JFG  Added DECNET option through TCP socket emulation.
  8. **    13 Sep 93  MD   Added correct return of vmserrorno for HTInetStatus.
  9. **            Added decoding of vms error message for MULTINET.
  10. */
  11.  
  12. #include"capalloc.h"
  13. #include"capstdio.h"
  14. #include "HTUtils.h"
  15. #include "tcp.h"        /* Defines SHORT_NAMES if necessary */
  16. #ifdef SHORT_NAMES
  17. #define HTInetStatus        HTInStat
  18. #define HTInetString         HTInStri
  19. #define HTParseInet        HTPaInet
  20. #endif
  21.  
  22. /*    Module-Wide variables
  23. */
  24.  
  25. PRIVATE char *hostname=0;        /* The name of this host */
  26.  
  27.  
  28. /*    PUBLIC VARIABLES
  29. */
  30.  
  31. /* PUBLIC SockA HTHostAddress; */    /* The internet address of the host */
  32.                     /* Valid after call to HTHostName() */
  33.  
  34. /*    Encode INET status (as in sys/errno.h)              inet_status()
  35. **    ------------------
  36. **
  37. ** On entry,
  38. **    where        gives a description of what caused the error
  39. **    global errno    gives the error number in the unix way.
  40. **
  41. ** On return,
  42. **    returns        a negative status in the unix way.
  43. */
  44. #ifndef PCNFS
  45. #ifndef MSDOS
  46. #ifdef VMS
  47. extern int uerrno;    /* Deposit of error info (as per errno.h) */
  48. extern volatile noshare int socket_errno; /* socket VMS error info
  49.                          (used for translation of vmserrno) */
  50. extern volatile noshare int vmserrno;    /* Deposit of VMS error info */
  51. extern volatile noshare int errno;  /* noshare to avoid PSECT conflict */
  52. #else /* VMS */
  53. #ifndef errno
  54. extern int errno;
  55. #endif /* errno */
  56. #endif /* VMS */
  57.  
  58. #ifndef VM
  59. #ifndef VMS
  60. #ifndef NeXT
  61. #ifndef THINK_C
  62. extern char *sys_errlist[];        /* see man perror on cernvax */
  63. extern int sys_nerr;
  64. #endif  /* think c */
  65. #endif    /* NeXT */
  66. #endif  /* VMS */
  67. #endif    /* VM */
  68. #endif  /* MSDOS */
  69. #endif    /* PCNFS */
  70.  
  71. /*    Report Internet Error
  72. **    ---------------------
  73. */
  74. #ifdef __STDC__
  75. PUBLIC int HTInetStatus(char *where)
  76. #else
  77. PUBLIC int HTInetStatus(where)
  78.     char    *where;
  79. #endif
  80. {
  81. #ifdef VMS
  82. #ifdef MULTINET
  83.             socket_errno = vmserrno;
  84. #endif
  85. #endif 
  86.  
  87. #ifndef RELEASE
  88.     CTRACE(tfp, "TCP: Error %d in `errno' after call to %s() failed.\n\t%s\n",
  89.         errno,  where,
  90.  
  91. #ifdef VM
  92.         "(Error number not translated)");    /* What Is the VM equiv? */
  93. #define ER_NO_TRANS_DONE
  94. #endif
  95. #ifdef VMS
  96. #ifdef MULTINET
  97.         vms_errno_string());
  98. #else
  99.         "(Error number not translated)");
  100. #endif
  101. #define ER_NO_TRANS_DONE
  102. #endif
  103. #ifdef NeXT
  104.         strerror(errno));
  105. #define ER_NO_TRANS_DONE
  106. #endif
  107. #ifdef THINK_C
  108.         strerror(errno));
  109. #define ER_NO_TRANS_DONE
  110. #endif
  111.  
  112. #ifndef ER_NO_TRANS_DONE
  113.         errno < sys_nerr ? sys_errlist[errno] : "Unknown error" );
  114. #endif
  115.  
  116. #endif /* RELEASE */
  117.  
  118. #ifdef VMS
  119. #ifndef MULTINET
  120. #ifndef RELEASE
  121.     CTRACE(tfp, "         Unix error number (uerrno) = %ld dec\n", uerrno);
  122.     CTRACE(tfp, "         VMS error (vmserrno)       = %lx hex\n", vmserrno);
  123. #endif /* RELEASE */
  124. #endif
  125. #endif
  126.  
  127. #ifdef VMS
  128.     /* uerrno and errno happen to be zero if vmserrno <> 0 */
  129.     return -vmserrno;
  130. #else
  131.     return -errno;
  132. #endif
  133. }
  134.  
  135.  
  136. /*    Parse a cardinal value                       parse_cardinal()
  137. **    ----------------------
  138. **
  139. ** On entry,
  140. **    *pp        points to first character to be interpreted, terminated by
  141. **            non 0:9 character.
  142. **    *pstatus    points to status already valid
  143. **    maxvalue    gives the largest allowable value.
  144. **
  145. ** On exit,
  146. **    *pp        points to first unread character
  147. **    *pstatus    points to status updated iff bad
  148. */
  149.  
  150. PUBLIC unsigned int HTCardinal ARGS3
  151.     (int *,        pstatus,
  152.     char **,    pp,
  153.     unsigned int,    max_value)
  154. {
  155.     int   n;
  156.     if ( (**pp<'0') || (**pp>'9')) {        /* Null string is error */
  157.     *pstatus = -3;  /* No number where one expeceted */
  158.     return 0;
  159.     }
  160.  
  161.     n=0;
  162.     while ((**pp>='0') && (**pp<='9')) n = n*10 + *((*pp)++) - '0';
  163.  
  164.     if (n>max_value) {
  165.     *pstatus = -4;  /* Cardinal outside range */
  166.     return 0;
  167.     }
  168.  
  169.     return n;
  170. }
  171.  
  172.  
  173. #ifndef DECNET  /* Function only used below for a trace message */
  174.  
  175. /*    Produce a string for an Internet address
  176. **    ----------------------------------------
  177. **
  178. ** On exit,
  179. **    returns    a pointer to a static string which must be copied if
  180. **        it is to be kept.
  181. */
  182.  
  183. PUBLIC CONST char * HTInetString ARGS1(SockA*,sin)
  184. {
  185.     static char string[16];
  186.     sprintf(string, "%d.%d.%d.%d",
  187.         (int)*((unsigned char *)(&sin->sin_addr)+0),
  188.         (int)*((unsigned char *)(&sin->sin_addr)+1),
  189.         (int)*((unsigned char *)(&sin->sin_addr)+2),
  190.         (int)*((unsigned char *)(&sin->sin_addr)+3));
  191.     return string;
  192. }
  193. #endif /* Decnet */
  194.  
  195.  
  196. /*    Parse a network node address and port
  197. **    -------------------------------------
  198. **
  199. ** On entry,
  200. **    str    points to a string with a node name or number,
  201. **        with optional trailing colon and port number.
  202. **    sin    points to the binary internet or decnet address field.
  203. **
  204. ** On exit,
  205. **    *sin    is filled in. If no port is specified in str, that
  206. **        field is left unchanged in *sin.
  207. */
  208. PUBLIC int HTParseInet ARGS2(SockA *,sin, CONST char *,str)
  209. {
  210.     char *port;
  211.     char host[256];
  212.     struct hostent  *phost;    /* Pointer to host - See netdb.h */
  213.     strcpy(host, str);        /* Take a copy we can mutilate */
  214.  
  215.  
  216.  
  217. /*    Parse port number if present
  218. */    
  219.     if (port=strchr(host, ':')) {
  220.         *port++ = 0;        /* Chop off port */
  221.         if (port[0]>='0' && port[0]<='9') {
  222.  
  223. #ifdef unix
  224.         sin->sin_port = htons(atol(port));
  225. #else /* VMS */
  226. #ifdef DECNET
  227.         sin->sdn_objnum = (unsigned char) (strtol(port, (char**)0 , 10));
  228. #else
  229.         sin->sin_port = htons(strtol(port, (char**)0 , 10));
  230. #endif /* Decnet */
  231. #endif /* Unix vs. VMS */
  232.  
  233.     } else {
  234.  
  235. #ifdef SUPPRESS        /* 1. crashes!?!.  2. Not recommended */
  236.         struct servent * serv = getservbyname(port, (char*)0);
  237.         if (serv) sin->sin_port = serv->s_port;
  238. #ifndef RELEASE
  239.         else if (TRACE) fprintf(stderr, "TCP: Unknown service %s\n", port);
  240. #endif /* RELEASE */
  241. #endif
  242.     }
  243.       }
  244.  
  245. #ifdef DECNET
  246.     /* read Decnet node name. @@ Should know about DECnet addresses, but it's
  247.        probably worth waiting until the Phase transition from IV to V. */
  248.  
  249.     sin->sdn_nam.n_len = min(DN_MAXNAML, strlen(host));  /* <=6 in phase 4 */
  250.     strncpy (sin->sdn_nam.n_name, host, sin->sdn_nam.n_len + 1);
  251.  
  252. #ifndef RELEASE
  253.     if (TRACE) fprintf(stderr,
  254.     "DECnet: Parsed address as object number %d on host %.6s...\n",
  255.               sin->sdn_objnum, host);
  256. #endif /* RELEASE */
  257.  
  258. #else  /* parse Internet host */
  259.  
  260. /*    Parse host number if present.
  261. */  
  262.     if (*host>='0' && *host<='9') {   /* Numeric node address: */
  263.     sin->sin_addr.s_addr = inet_addr(host); /* See arpa/inet.h */
  264.  
  265.     } else {            /* Alphanumeric node name: */
  266. #ifdef MVS    /* Oustanding problem with crash in MVS gethostbyname */
  267. #ifndef RELEASE
  268.     if(TRACE)fprintf(stderr, "HTTCP: Calling gethostbyname(%s)\n", host);
  269. #endif /* RELEASE */
  270. #endif
  271.     phost=gethostbyname(host);    /* See netdb.h */
  272. #ifdef MVS
  273. #ifndef RELEASE
  274.     if(TRACE)fprintf(stderr, "HTTCP: gethostbyname() returned %d\n", phost);
  275. #endif /* RELEASE */
  276. #endif
  277.     if (!phost) {
  278. #ifndef RELEASE
  279.         if (TRACE) fprintf(stderr,
  280.             "HTTPAccess: Can't find internet node name `%s'.\n",host);
  281. #endif /* RELEASE */
  282.         return -1;  /* Fail? */
  283.     }
  284.     memcpy(&sin->sin_addr, phost->h_addr, phost->h_length);
  285.     }
  286.  
  287. #ifndef RELEASE
  288.     if (TRACE) fprintf(stderr,
  289.     "TCP: Parsed address as port %d, IP address %d.%d.%d.%d\n",
  290.         (int)ntohs(sin->sin_port),
  291.         (int)*((unsigned char *)(&sin->sin_addr)+0),
  292.         (int)*((unsigned char *)(&sin->sin_addr)+1),
  293.         (int)*((unsigned char *)(&sin->sin_addr)+2),
  294.         (int)*((unsigned char *)(&sin->sin_addr)+3));
  295. #endif /* RELEASE */
  296. #endif  /* Internet vs. Decnet */
  297.  
  298.     return 0;    /* OK */
  299. }
  300.  
  301.  
  302. /*    Derive the name of the host on which we are
  303. **    -------------------------------------------
  304. **
  305. */
  306. #ifdef __STDC__
  307. PRIVATE void get_host_details(void)
  308. #else
  309. PRIVATE void get_host_details()
  310. #endif
  311.  
  312. #ifndef MAXHOSTNAMELEN
  313. #define MAXHOSTNAMELEN 64        /* Arbitrary limit */
  314. #endif
  315.  
  316. {
  317.     char name[MAXHOSTNAMELEN+1];    /* The name of this host */
  318. #ifdef NEED_HOST_ADDRESS        /* no -- needs name server! */
  319.     struct hostent * phost;        /* Pointer to host -- See netdb.h */
  320. #endif
  321.     int namelength = sizeof(name);
  322.     
  323.     if (hostname) return;        /* Already done */
  324.     gethostname(name, namelength);    /* Without domain */
  325. #ifndef RELEASE
  326.     CTRACE(tfp, "TCP: Local host name is %s\n", name);
  327. #endif /* RELEASE */
  328.     StrAllocCopy(hostname, name);
  329.  
  330. #ifndef DECNET  /* Decnet ain't got no damn name server 8#OO */
  331. #ifdef NEED_HOST_ADDRESS        /* no -- needs name server! */
  332.     phost=gethostbyname(name);        /* See netdb.h */
  333.     if (!phost) {
  334. #ifndef RELEASE
  335.     if (TRACE) fprintf(stderr,
  336.         "TCP: Can't find my own internet node address for `%s'!!\n",
  337.         name);
  338. #endif /* RELEASE */
  339.     return;  /* Fail! */
  340.     }
  341.     StrAllocCopy(hostname, phost->h_name);
  342.     memcpy(&HTHostAddress, &phost->h_addr, phost->h_length);
  343. #ifndef RELEASE
  344.     if (TRACE) fprintf(stderr, "     Name server says that I am `%s' = %s\n",
  345.         hostname, HTInetString(&HTHostAddress));
  346. #endif /* RELEASE */
  347. #endif
  348.  
  349. #endif /* not Decnet */
  350. }
  351.  
  352. #ifdef __STDC__
  353. PUBLIC const char * HTHostName(void)
  354. #else
  355. PUBLIC char * HTHostName()
  356. #endif
  357. {
  358.     get_host_details();
  359.     return hostname;
  360. }
  361.  
  362.  
  363. #include"htparse.h"
  364.  
  365. PUBLIC int HTDoConnect ARGS4(char *,url, char *,protocol, int,default_port,
  366.                                      int *,s)
  367. {
  368.   struct sockaddr_in soc_address;
  369.   struct sockaddr_in *sin = &soc_address;
  370.   int status;
  371.  
  372.   /* Set up defaults: */
  373.   sin->sin_family = AF_INET;
  374.   sin->sin_port = htons(default_port);
  375.  
  376.   /* Get node name and optional port number: */
  377.   {
  378.     char line[256];
  379.     char *p1 = HTParse(url, "", PARSE_HOST);
  380.     char *at_sign, *host;
  381.     int status;
  382.  
  383.     /* if theres an @ then use the stuff after it as a hostname */
  384.     if((at_sign = strchr(p1,'@')) != NULL)
  385.     host = at_sign+1;
  386.     else
  387.     host = p1;
  388.  
  389.     status = HTParseInet(sin, host);
  390.     if (status)
  391.       {
  392.     free (p1);
  393.     return -1;
  394.       }
  395.  
  396.     free (p1);
  397.   }
  398.  
  399.   /* Now, let's get a socket set up from the server for the data: */
  400.   *s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  401.  
  402.   /*
  403.    * Issue the connect.  Since the server can't do an instantaneous accept
  404.    * and we are non-blocking, this will almost certainly return a negative
  405.    * status.
  406.    */
  407.   status = connect(*s, (struct sockaddr*)&soc_address, sizeof(soc_address));
  408.  
  409.   if(status < 0)    {
  410.     close(*s);
  411.   }
  412.  
  413.   return status;
  414. }
  415.