home *** CD-ROM | disk | FTP | other *** search
/ ftp.uv.es / 2014.11.ftp.uv.es.tar / ftp.uv.es / pub / unix / pine4.10.tar.gz / pine4.10.tar / pine4.10 / imap / src / osdep / nt / tcp_nt.c < prev    next >
C/C++ Source or Header  |  1999-01-12  |  19KB  |  632 lines

  1. /*
  2.  * Program:    Winsock TCP/IP routines
  3.  *
  4.  * Author:    Mark Crispin from Mike Seibel's Winsock code
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date:    11 April 1989
  13.  * Last Edited:    12 January 1999
  14.  *
  15.  * Copyright 1999 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made
  24.  * available "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  */
  35.  
  36.  
  37. /* Private functions */
  38.  
  39. long tcp_abort (SOCKET *sock);
  40.  
  41.  
  42. /* Private data */
  43.  
  44. int wsa_initted = 0;        /* init ? */
  45. static int wsa_sock_open = 0;    /* keep track of open sockets */
  46. static tcptimeout_t tmoh = NIL;    /* TCP timeout handler routine */
  47. static long ttmo_read = 0;    /* TCP timeouts, in seconds */
  48. static long ttmo_write = 0;
  49.  
  50. /* TCP/IP manipulate parameters
  51.  * Accepts: function code
  52.  *        function-dependent value
  53.  * Returns: function-dependent return value
  54.  */
  55.  
  56. void *tcp_parameters (long function,void *value)
  57. {
  58.   switch ((int) function) {
  59.   case SET_TIMEOUT:
  60.     tmoh = (tcptimeout_t) value;
  61.     break;
  62.   case GET_TIMEOUT:
  63.     value = (void *) tmoh;
  64.     break;
  65.   case SET_READTIMEOUT:
  66.     ttmo_read = (long) value;
  67.     break;
  68.   case GET_READTIMEOUT:
  69.     value = (void *) ttmo_read;
  70.     break;
  71.   case SET_WRITETIMEOUT:
  72.     ttmo_write = (long) value;
  73.     break;
  74.   case GET_WRITETIMEOUT:
  75.     value = (void *) ttmo_write;
  76.     break;
  77.   default:
  78.     value = NIL;        /* error case */
  79.     break;
  80.   }
  81.   return value;
  82. }
  83.  
  84. /* TCP/IP open
  85.  * Accepts: host name
  86.  *        contact service name
  87.  *        contact port number
  88.  * Returns: TCP/IP stream if success else NIL
  89.  */
  90.  
  91. TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
  92. {
  93.   TCPSTREAM *stream = NIL;
  94.   SOCKET sock;
  95.   char *s;
  96.   struct sockaddr_in sin;
  97.   struct hostent *he;
  98.   char tmp[MAILTMPLEN];
  99.   char *hostname = NIL;
  100.   if (!wsa_initted++) {        /* init Windows Sockets */
  101.     WSADATA wsock;
  102.     int i = (int) WSAStartup (WSA_VERSION,&wsock);
  103.     if (i) {            /* failed */
  104.       wsa_initted = 0;        /* in case we try again */
  105.       sprintf (tmp,"Unable to start Windows Sockets (%d)",i);
  106.       mm_log (tmp,ERROR);
  107.       return NIL;
  108.     }
  109.   }
  110.   /* The domain literal form is used (rather than simply the dotted decimal
  111.      as with other Unix programs) because it has to be a valid "host name"
  112.      in mailsystem terminology. */
  113.   sin.sin_family = AF_INET;    /* family is always Internet */
  114.                 /* look like domain literal? */
  115.   if (host[0] == '[' && host[(strlen (host))-1] == ']') {
  116.     strcpy (tmp,host+1);    /* yes, copy number part */
  117.     tmp[strlen (tmp)-1] = '\0';
  118.     if ((sin.sin_addr.s_addr = inet_addr (tmp)) == INADDR_NONE) {
  119.       sprintf (tmp,"Bad format domain-literal: %.80s",host);
  120.       mm_log (tmp,ERROR);
  121.       return NIL;
  122.     }
  123.     else hostname = cpystr (host);
  124.   }
  125.   else {            /* lookup host name */
  126.     if ((he = gethostbyname (lcase (strcpy (tmp,host))))) {
  127.                 /* copy host name */
  128.       hostname = cpystr (he->h_name);
  129.                 /* copy host addresses */
  130.       memcpy (&sin.sin_addr,he->h_addr,he->h_length);
  131.     }
  132.     else {
  133.       sprintf (tmp,"Host not found (#%d): %s",WSAGetLastError(),host);
  134.       mm_log (tmp,ERROR);
  135.       return NIL;
  136.     }
  137.   }
  138.  
  139.                 /* copy port number in network format */
  140.   if (!(sin.sin_port = htons ((u_short)port)))
  141.     fatal ("Bad port argument to tcp_open");
  142.                 /* get a TCP stream */
  143.   if ((sock = socket (sin.sin_family,SOCK_STREAM,0)) == INVALID_SOCKET) {
  144.     sprintf (tmp,"Unable to create TCP socket (%d)",WSAGetLastError());
  145.     mm_log (tmp,ERROR);
  146.     fs_give ((void **) &hostname);
  147.     return NIL;
  148.   }
  149.                 /* open connection */
  150.   if (connect (sock,(struct sockaddr *) &sin,sizeof (sin)) == SOCKET_ERROR) {
  151.     switch (WSAGetLastError ()) {    /* analyze error */
  152.     case WSAECONNREFUSED:
  153.       s = "Refused";
  154.       break;
  155.     case WSAENOBUFS:
  156.       s = "Insufficient system resources";
  157.       break;
  158.     case WSAETIMEDOUT:
  159.       s = "Timed out";
  160.       break;
  161.     default:
  162.       s = "Unknown error";
  163.       break;
  164.     }
  165.     sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",hostname,port,s,
  166.          WSAGetLastError ());
  167.     mm_log (tmp,ERROR);
  168.     fs_give ((void **) &hostname);
  169.     return (TCPSTREAM *) tcp_abort (&sock);
  170.   }
  171.   wsa_sock_open++;        /* create TCP/IP stream */
  172.   stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0,
  173.                  sizeof (TCPSTREAM));
  174.   stream->host = hostname;    /* official host name */
  175.   stream->port = port;        /* port number */
  176.   stream->tcps = sock;        /* init socket */
  177.   stream->ictr = 0;        /* init input counter */
  178.   return stream;        /* return success */
  179. }
  180.   
  181. /* TCP/IP authenticated open
  182.  * Accepts: NETMBX specifier
  183.  *        service name
  184.  *        returned user name buffer
  185.  * Returns: TCP/IP stream if success else NIL
  186.  */
  187.  
  188. TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
  189. {
  190.   return NIL;            /* always NIL on Windows */
  191. }
  192.  
  193. /* TCP/IP receive line
  194.  * Accepts: TCP/IP stream
  195.  * Returns: text line string or NIL if failure
  196.  */
  197.  
  198. char *tcp_getline (TCPSTREAM *stream)
  199. {
  200.   int n,m;
  201.   char *st,*ret,*stp;
  202.   char c = '\0';
  203.   char d;
  204.                 /* make sure have data */
  205.   if (!tcp_getdata (stream)) return NIL;
  206.   st = stream->iptr;        /* save start of string */
  207.   n = 0;            /* init string count */
  208.   while (stream->ictr--) {    /* look for end of line */
  209.     d = *stream->iptr++;    /* slurp another character */
  210.     if ((c == '\015') && (d == '\012')) {
  211.       ret = (char *) fs_get (n--);
  212.       memcpy (ret,st,n);    /* copy into a free storage string */
  213.       ret[n] = '\0';        /* tie off string with null */
  214.       return ret;
  215.     }
  216.     n++;            /* count another character searched */
  217.     c = d;            /* remember previous character */
  218.   }
  219.                 /* copy partial string from buffer */
  220.   memcpy ((ret = stp = (char *) fs_get (n)),st,n);
  221.                 /* get more data from the net */
  222.   if (!tcp_getdata (stream)) fs_give ((void **) &ret);
  223.                 /* special case of newline broken by buffer */
  224.   else if ((c == '\015') && (*stream->iptr == '\012')) {
  225.     stream->iptr++;        /* eat the line feed */
  226.     stream->ictr--;
  227.     ret[n - 1] = '\0';        /* tie off string with null */
  228.   }
  229.                 /* else recurse to get remainder */
  230.   else if (st = tcp_getline (stream)) {
  231.     ret = (char *) fs_get (n + 1 + (m = strlen (st)));
  232.     memcpy (ret,stp,n);        /* copy first part */
  233.     memcpy (ret + n,st,m);    /* and second part */
  234.     fs_give ((void **) &stp);    /* flush first part */
  235.     fs_give ((void **) &st);    /* flush second part */
  236.     ret[n + m] = '\0';        /* tie off string with null */
  237.   }
  238.   return ret;
  239. }
  240.  
  241. /* TCP/IP receive buffer
  242.  * Accepts: TCP/IP stream
  243.  *        size in bytes
  244.  *        buffer to read into
  245.  * Returns: T if success, NIL otherwise
  246.  */
  247.  
  248. long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
  249. {
  250.   unsigned long n;
  251.   char *bufptr = buffer;
  252.   while (size > 0) {        /* until request satisfied */
  253.     if (!tcp_getdata (stream)) return NIL;
  254.     n = min (size,stream->ictr);/* number of bytes to transfer */
  255.                 /* do the copy */
  256.     memcpy (bufptr,stream->iptr,(size_t)n);
  257.     bufptr += n;        /* update pointer */
  258.     stream->iptr +=n;
  259.     size -= n;            /* update # of bytes to do */
  260.     stream->ictr -=n;
  261.   }
  262.   bufptr[0] = '\0';        /* tie off string */
  263.   return T;
  264. }
  265.  
  266.  
  267. /* TCP/IP receive data
  268.  * Accepts: TCP/IP stream
  269.  * Returns: T if success, NIL otherwise
  270.  */
  271.  
  272. long tcp_getdata (TCPSTREAM *stream)
  273. {
  274.   struct timeval tmo;
  275.   int i;
  276.   fd_set fds;
  277.   time_t tc,t = time (0);
  278.   FD_ZERO (&fds);        /* initialize selection vector */
  279.   if (stream->tcps == INVALID_SOCKET) return NIL;
  280.   tmo.tv_sec = ttmo_read;
  281.   tmo.tv_usec = 0;
  282.   while (stream->ictr < 1) {    /* if nothing in the buffer */
  283.     time_t tl = time (0);
  284.     FD_SET (stream->tcps,&fds);    /* set bit in selection vector */
  285.                 /* block and read */
  286.     switch (select (stream->tcps+1,&fds,0,0,
  287.             ttmo_read ? &tmo : (struct timeval *) 0)) {
  288.     case SOCKET_ERROR:        /* error */
  289.       if (WSAGetLastError () != WSAEINTR) return tcp_abort (&stream->tcps);
  290.       break;
  291.     case 0:            /* timeout */
  292.       tc = time (0);
  293.       if (tmoh && ((*tmoh) (tc - t,tc - tl))) break;
  294.       return tcp_abort (&stream->tcps);
  295.     default:
  296.       while (((i = recv (stream->tcps,stream->ibuf,BUFLEN,0)) == SOCKET_ERROR)
  297.          && (WSAGetLastError() == WSAEINTR));
  298.       switch (i) {
  299.       case SOCKET_ERROR:    /* error */
  300.       case 0:            /* no data read */
  301.     return tcp_abort(&stream->tcps);
  302.       default:
  303.     stream->ictr = i;    /* set new byte count */
  304.     stream->iptr = stream->ibuf;/* point at TCP buffer */
  305.       }
  306.     }
  307.   }
  308.   return T;
  309. }
  310.  
  311. /* TCP/IP send string as record
  312.  * Accepts: TCP/IP stream
  313.  *        string pointer
  314.  * Returns: T if success else NIL
  315.  */
  316.  
  317. long tcp_soutr (TCPSTREAM *stream,char *string)
  318. {
  319.   return tcp_sout (stream,string,(unsigned long) strlen (string));
  320. }
  321.  
  322.  
  323. /* TCP/IP send string
  324.  * Accepts: TCP/IP stream
  325.  *        string pointer
  326.  *        byte count
  327.  * Returns: T if success else NIL
  328.  */
  329.  
  330. long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
  331. {
  332.   int i;
  333.   struct timeval tmo;
  334.   fd_set fds;
  335.   time_t tc,t = time (0);
  336.   tmo.tv_sec = ttmo_write;
  337.   tmo.tv_usec = 0;
  338.   FD_ZERO (&fds);        /* initialize selection vector */
  339.   if (stream->tcps == INVALID_SOCKET) return NIL;
  340.   while (size > 0) {        /* until request satisfied */
  341.     time_t tl = time (0);
  342.     FD_SET (stream->tcps,&fds);    /* set bit in selection vector */
  343.                 /* block and write */
  344.     switch (select (stream->tcps+1,NULL,&fds,NULL,
  345.             tmo.tv_sec ? &tmo : (struct timeval *) 0)) {
  346.     case SOCKET_ERROR:        /* error */
  347.       if (WSAGetLastError () != WSAEINTR) return tcp_abort (&stream->tcps);
  348.       break;
  349.     case 0:            /* timeout */
  350.       tc = time (0);
  351.       if (tmoh && ((*tmoh) (tc - t,tc - tl))) break;
  352.       return tcp_abort (&stream->tcps);
  353.     default:
  354.       while (((i = send (stream->tcps,string,(int) size,0)) == SOCKET_ERROR) &&
  355.          (WSAGetLastError () == WSAEINTR));
  356.       if (i == SOCKET_ERROR) return tcp_abort (&stream->tcps);
  357.       size -= i;        /* count this size */
  358.       string += i;
  359.     }
  360.   }
  361.   return T;            /* all done */
  362. }
  363.  
  364.  
  365. /* TCP/IP close
  366.  * Accepts: TCP/IP stream
  367.  */
  368.  
  369. void tcp_close (TCPSTREAM *stream)
  370. {
  371.   tcp_abort (&stream->tcps);    /* nuke the socket */
  372.                 /* flush host names */
  373.   if (stream->host) fs_give ((void **) &stream->host);
  374.   if (stream->localhost) fs_give ((void **) &stream->localhost);
  375.   fs_give ((void **) &stream);    /* flush the stream */
  376. }
  377.  
  378.  
  379. /* TCP/IP abort stream
  380.  * Accepts: WinSock SOCKET
  381.  */
  382.  
  383. long tcp_abort (SOCKET *sock)
  384. {
  385.                 /* something to close? */
  386.   if (sock && *sock != INVALID_SOCKET) {
  387.     closesocket (*sock);    /* WinSock socket close */
  388.     *sock = INVALID_SOCKET;
  389.                 /* no more open streams? */
  390.     if (wsa_initted && !--wsa_sock_open) {
  391.       wsa_initted = 0;        /* no more sockets, so... */
  392.       WSACleanup ();        /* free up resources until needed */
  393.     }
  394.   }
  395.   return NIL;
  396. }
  397.  
  398. /* TCP/IP get host name
  399.  * Accepts: TCP/IP stream
  400.  * Returns: host name for this stream
  401.  */
  402.  
  403. char *tcp_host (TCPSTREAM *stream)
  404. {
  405.   return stream->host;        /* use tcp_remotehost() if want guarantees */
  406. }
  407.  
  408.  
  409. /* TCP/IP get remote host name
  410.  * Accepts: TCP/IP stream
  411.  * Returns: host name for this stream
  412.  */
  413.  
  414. char *tcp_remotehost (TCPSTREAM *stream)
  415. {
  416.   if (!stream->remotehost) {
  417.     char *s,tmp[MAILTMPLEN];
  418.     struct hostent *he;
  419.     struct sockaddr_in sin;
  420.     int sinlen = sizeof (struct sockaddr_in);
  421.     if ((getpeername (stream->tcps,(struct sockaddr *) &sin,&sinlen) ==
  422.      SOCKET_ERROR) || (sinlen <= 0)) s = stream->host;
  423. #ifndef DISABLE_REVERSE_DNS_LOOKUP
  424.     /* Guarantees that the client will have the same string as the server does
  425.      * from calling tcp_serverhost ().
  426.      */
  427.     else if (he = gethostbyaddr ((char *) &sin.sin_addr,
  428.                  sizeof (struct in_addr),sin.sin_family))
  429.       s = he->h_name;
  430. #else
  431.   /* Not recommended.  In any mechanism (e.g. Kerberos) in which both client
  432.    * and server must agree on the name of the server system, this may cause
  433.    * the client to have a different idea of the server's name from the server.
  434.    * This is particularly important in those cases where a server has multiple
  435.    * CNAMEs; the gethostbyaddr() will canonicalize the name to the proper IP
  436.    * address.
  437.    */
  438. #endif
  439.     else sprintf (s = tmp,"[%s]",inet_ntoa (sin.sin_addr));
  440.     stream->remotehost = cpystr (s);
  441.   }
  442.   return stream->remotehost;
  443. }
  444.  
  445. /* TCP/IP return port for this stream
  446.  * Accepts: TCP/IP stream
  447.  * Returns: port number for this stream
  448.  */
  449.  
  450. unsigned long tcp_port (TCPSTREAM *stream)
  451. {
  452.   return stream->port;        /* return port number */
  453. }
  454.  
  455.  
  456. /* TCP/IP get local host name
  457.  * Accepts: TCP/IP stream
  458.  * Returns: local host name
  459.  */
  460.  
  461. char *tcp_localhost (TCPSTREAM *stream)
  462. {
  463.   if (!stream->localhost) {
  464.     char *s,tmp[MAILTMPLEN];
  465.     struct hostent *he;
  466.     struct sockaddr_in sin;
  467.     int sinlen = sizeof (struct sockaddr_in);
  468.     if ((getsockname (stream->tcps,(struct sockaddr *) &sin,&sinlen) ==
  469.      SOCKET_ERROR) || (sinlen <= 0)) s = mylocalhost ();
  470. #ifndef DISABLE_REVERSE_DNS_LOOKUP
  471.     /* Guarantees that the client will have the same string as the server will
  472.      * get in doing a reverse DNS lookup on the client's IP address.
  473.      */
  474.                 /* translate socket address to name */
  475.     else if (he = gethostbyaddr ((char *) &sin.sin_addr,
  476.                  sizeof (struct in_addr),sin.sin_family)) 
  477.       s = he->h_name;
  478. #else
  479.     /* Not recommended.  In any mechanism (e.g. SMTP or NNTP) in which both
  480.      * client and server must agree on the name of the client system, this may
  481.      * cause the client to use the wrong name.
  482.      */
  483. #endif
  484.     else sprintf (s = tmp,"[%s]",inet_ntoa (sin.sin_addr));
  485.     stream->localhost = cpystr (s);
  486.   }
  487.   return stream->localhost;    /* return local host name */
  488. }
  489.  
  490. /* Return my local host name
  491.  * Returns: my local host name
  492.  */
  493.  
  494. char *mylocalhost (void)
  495. {
  496.   if (!myLocalHost) {
  497.     char *s,tmp[MAILTMPLEN];
  498.     struct hostent *he;
  499.     struct sockaddr_in sin, stmp;
  500.     int sinlen = sizeof (struct sockaddr_in);
  501.     SOCKET sock;
  502.     if (!wsa_initted++) {    /* init Windows Sockets */
  503.       WSADATA wsock;
  504.       if (WSAStartup (WSA_VERSION,&wsock)) {
  505.     wsa_initted = 0;
  506.     return "random-pc";    /* try again later? */
  507.       }
  508.     }
  509.     sin.sin_family = AF_INET;    /* family is always Internet */
  510.     sin.sin_addr.s_addr = inet_addr ("127.0.0.1");
  511.     sin.sin_port = htons ((u_short) 7);
  512.     if (((sock = socket (sin.sin_family,SOCK_DGRAM,0)) != INVALID_SOCKET) &&
  513.     (getsockname (sock,(struct sockaddr *) &stmp,&sinlen)!= SOCKET_ERROR)&&
  514.     (sinlen > 0) &&
  515.     (he = gethostbyaddr ((char *) &stmp.sin_addr,
  516.                  sizeof (struct in_addr),stmp.sin_family)))
  517.       s = he->h_name;
  518.     else if (gethostname (tmp,MAILTMPLEN-1) == SOCKET_ERROR) s = "random-pc";
  519.     else s = (he = gethostbyname (tmp)) ? he->h_name : tmp;
  520.     myLocalHost = cpystr (s);    /* canonicalize it */
  521.                 /* leave wsa_initted to save work later */
  522.     if (sock != INVALID_SOCKET) closesocket (sock);
  523.   }
  524.   return myLocalHost;
  525. }
  526.  
  527. /* TCP/IP get client host name (server calls only)
  528.  * Returns: client host name
  529.  */
  530.  
  531. char *tcp_clienthost ()
  532. {
  533.   if (!myClientHost) {
  534.     char *s,tmp[MAILTMPLEN];
  535.     struct hostent *he;
  536.     struct sockaddr_in sin;
  537.     int sinlen = sizeof (struct sockaddr_in);
  538.                 /* get socket address */
  539.     if ((getpeername (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
  540.     (sinlen <= 0)) s = "UNKNOWN";
  541. #ifndef DISABLE_REVERSE_DNS_LOOKUP
  542.     /* Includes both client name and IP address in syslog() output. */
  543.     else if (he = gethostbyaddr ((char *) &sin.sin_addr,
  544.                  sizeof (struct in_addr),sin.sin_family)) 
  545.       sprintf (s = tmp,"%s [%s]",he->h_name,inet_ntoa (sin.sin_addr));
  546. #else
  547.     /* Not recommended.  Syslog output will only have the client IP address. */
  548. #endif
  549.     else sprintf (s = tmp,"[%s]",inet_ntoa (sin.sin_addr));
  550.     myClientHost = cpystr (s);
  551.   }
  552.   return myClientHost;
  553. }
  554.  
  555. /* TCP/IP get server host name (server calls only)
  556.  * Returns: server host name
  557.  */
  558.  
  559. static long myServerPort = -1;
  560.  
  561. char *tcp_serverhost ()
  562. {
  563.   if (!myServerHost) {
  564.     char *s,tmp[MAILTMPLEN];
  565.     struct hostent *he;
  566.     struct sockaddr_in sin;
  567.     int sinlen = sizeof (struct sockaddr_in);
  568.     if (!wsa_initted++) {    /* init Windows Sockets */
  569.       WSADATA wsock;
  570.       if (WSAStartup (WSA_VERSION,&wsock)) {
  571.     wsa_initted = 0;
  572.     return "random-pc";    /* try again later? */
  573.       }
  574.     }
  575.                 /* get socket address */
  576.     if ((getsockname (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
  577.     (sinlen <= 0)) s = mylocalhost ();
  578.     else {
  579.       myServerPort = ntohs (sin.sin_port);
  580. #ifndef DISABLE_REVERSE_DNS_LOOKUP
  581.       /* Guarantees that the server will have the same string as the client
  582.        * does from calling tcp_remotehost ().
  583.        */
  584.       if (he = gethostbyaddr ((char *) &sin.sin_addr,
  585.                   sizeof (struct in_addr),sin.sin_family))
  586.     s = he->h_name;
  587.       else
  588. #else
  589.       /* Not recommended.  In any mechanism (e.g. Kerberos) in which both
  590.        * client and server must agree on the name of the server system, this
  591.        * may cause a spurious mismatch.  This is particularly important when
  592.        * multiple server systems are co-located on the same CPU with different
  593.        * IP addresses; the gethostbyaddr() call will return the name of the
  594.        * proper server system name and avoid canonicalizing it to a default
  595.        * name.
  596.        */
  597. #endif
  598.       sprintf (s = tmp,"[%s]",inet_ntoa (sin.sin_addr));
  599.     }
  600.     myServerHost = cpystr (s);
  601.     if (!myLocalHost) myLocalHost = cpystr (s);
  602.   }
  603.   return myServerHost;
  604. }
  605.  
  606. /* TCP/IP get server port number (server calls only)
  607.  * Returns: server port number
  608.  */
  609.  
  610. long tcp_serverport ()
  611. {
  612.   if (!myServerHost) tcp_serverhost ();
  613.   return myServerPort;
  614. }
  615.  
  616.  
  617. /* TCP/IP return canonical form of host name
  618.  * Accepts: host name
  619.  * Returns: canonical form of host name
  620.  */
  621.  
  622. char *tcp_canonical (char *name)
  623. {
  624.   char host[MAILTMPLEN];
  625.   struct hostent *he;
  626.                 /* look like domain literal? */
  627.   if (name[0] == '[' && name[strlen (name) - 1] == ']') return name;
  628.                 /* note that Unix requires lowercase! */
  629.   else return (he = gethostbyname (lcase (strcpy (host,name)))) ?
  630.     he->h_name : name;
  631. }
  632.