home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libnet / mkconect.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  43.0 KB  |  1,572 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /*
  19.  * generalized portable TCP routines
  20.  *
  21.  * Handles calls to async connect and dns routines.
  22.  *
  23.  * Designed and originally implemented by Lou Montulli '94
  24.  * Modified by Judson Valeski '97
  25.  */
  26.  
  27. #include "rosetta.h"
  28. #include "mkutils.h"
  29. #include "prefapi.h"
  30. #include "mkpadpac.h"
  31.  
  32. #if defined(XP_WIN)
  33. #define ASYNC_DNS
  34. #endif
  35.  
  36. #include "mktcp.h"
  37. #include "mkparse.h"
  38. #include "mkgeturl.h"  /* for error codes, and some util functions */
  39. #include "fe_proto.h" /* for externs */
  40. #ifdef MOZILLA_CLIENT
  41. #include "secnav.h"
  42. #endif /* MOZILLA_CLIENT */
  43. #include "merrors.h"
  44. #ifndef NSPR20
  45. #if defined(XP_UNIX) || defined(XP_WIN32)
  46. #include "prnetdb.h"
  47. #else
  48. #define PRHostEnt struct hostent
  49. #define PR_NETDB_BUF_SIZE 5
  50. #endif
  51. #else
  52. #include "prnetdb.h"
  53. #endif
  54.  
  55. #include "ssl.h"
  56.  
  57. #if defined(XP_OS2) /*DSR072196 - use os2sock.h*/
  58. #include "os2sock.h"
  59. #endif /* XP_OS2 */
  60.  
  61. #ifdef XP_UNIX
  62. /* #### WARNING, this is duplicated in mksockrw.c
  63.  */
  64. # include <sys/ioctl.h>
  65. /*
  66.  * mcom_db.h is only included here to set BYTE_ORDER !!!
  67.  * MAXDNAME is pilfered right out of arpa/nameser.h.
  68.  */
  69. # include "mcom_db.h"
  70.  
  71. # if defined(__hpux) || defined(_HPUX_SOURCE)
  72. #  define BYTE_ORDER BIG_ENDIAN
  73. #  define MAXDNAME        256             /* maximum domain name */
  74. # else
  75. #  include <arpa/nameser.h>
  76. # endif
  77.  
  78. #include <resolv.h>
  79.  
  80. #if !defined(__osf__) && !defined(AIXV3) && !defined(_HPUX_SOURCE) && !defined(__386BSD__) && !defined(__linux) && !defined(SCO_SV)
  81. #include <sys/filio.h>
  82. #endif
  83.  
  84. #endif /* XP_UNIX */
  85.  
  86. #include "xp_error.h"
  87.  
  88. /* for XP_GetString() */
  89. #include "xpgetstr.h"
  90. extern int MK_CONNECTION_REFUSED;
  91. extern int MK_CONNECTION_TIMED_OUT;
  92. extern int MK_OUT_OF_MEMORY;
  93. extern int MK_UNABLE_TO_CONNECT;
  94. extern int MK_UNABLE_TO_CREATE_SOCKET;
  95. extern int MK_UNABLE_TO_LOCATE_HOST;
  96. extern int MK_UNABLE_TO_LOCATE_SOCKS_HOST;
  97. extern int XP_ERRNO_EALREADY;
  98. extern int XP_ERRNO_ECONNREFUSED;
  99. extern int XP_ERRNO_EINPROGRESS;
  100. extern int XP_ERRNO_EISCONN;
  101. extern int XP_ERRNO_ETIMEDOUT;
  102. extern int XP_ERRNO_EWOULDBLOCK;
  103. extern int XP_PROGRESS_CONTACTHOST;
  104. extern int XP_PROGRESS_LOOKUPHOST;
  105. extern int XP_PROGRESS_NOCONNECTION;
  106. extern int XP_PROGRESS_UNABLELOCATE;
  107. extern int MK_PORT_ACCESS_NOT_ALLOWED;
  108.  
  109. /* An awful hack. setupSocks gets set to true after the first call to BeginConnect.
  110.  * We don't want to be setting up the socks host/port (a call to gethostbyname) 
  111.  * until we've gone all the way through the netscape initialization.
  112.  */
  113. static setupSocks=FALSE;
  114.  
  115. typedef enum {
  116.     NET_TCP_FINISH_DNS_LOOKUP,
  117.     NET_TCP_FINISH_CONNECT
  118. } TCPStatesEnum;
  119.  
  120. struct _TCP_ConData {
  121.     TCPStatesEnum       next_state;  /* states of the machine */
  122.     PRNetAddr           net_addr;
  123.     XP_Bool                use_security;
  124.     time_t              begin_time;
  125. };
  126.  
  127. /* MAX_DNS_LIST_SIZE controls the cache of resolved hosts.
  128.  * If it is undefined, the cache will grow without bound.
  129.  * If it is defined and >0, then the cache will be limited
  130.  * to that many entries.  If it is 0, there will be no cache.
  131.  *
  132.  * also needed for DNS failover...
  133.  */
  134. # define MAX_DNS_LIST_SIZE 10
  135.  
  136.  
  137. /* Global TCP connect variables
  138.  */
  139. PUBLIC u_long NET_SocksHost=0;
  140. PUBLIC short NET_SocksPort=0;
  141. PUBLIC char * NET_SocksHostName=0;
  142.  
  143. PUBLIC Bool socksFailure=FALSE;
  144.  
  145. PUBLIC int NET_InGetHostByName = FALSE; /* global semaphore */
  146.  
  147. /* The struct used to define a DNS cache entry */
  148. typedef struct _DNSEntry {
  149.     char      *hostname;
  150.     PRUint32  *ips;
  151.     int32      addressCount;
  152.     int        h_length;
  153.     time_t     expirationTime;
  154. } DNSEntry;
  155.    
  156. PRIVATE char   *  net_local_hostname=0;     /* The name of this host */
  157. PRIVATE XP_List * dns_list=0;
  158.  
  159. #define pref_dnsExpiration "network.dnsCacheExpiration"
  160. PRIVATE int32 dnsCacheExpiration=0;
  161.  
  162. #define DEFAULT_TCP_CONNECT_TIMEOUT 35  /* seconds */
  163. PRIVATE uint32 net_tcp_connect_timeout = DEFAULT_TCP_CONNECT_TIMEOUT;/*seconds*/
  164.  
  165. /* set the number of seconds for the tcp connect timeout
  166.  *
  167.  * this timeout is used to end connections that do not
  168.  * timeout on there own */
  169. PUBLIC void
  170. NET_SetTCPConnectTimeout(uint32 seconds) {
  171.     net_tcp_connect_timeout = seconds;
  172. }
  173.  
  174. /* socks support function
  175.  *
  176.  * if set to NULL socks is off.  If set to non null string the string will be
  177.  * used as the socks host and socks will be used for all connections.
  178.  *
  179.  * returns 0 if the numonic hostname given is invalid or gethostbyname
  180.  * returns host unknown
  181.  *
  182.  */
  183. int NET_SetSocksHost(char * host)
  184. {
  185.     XP_Bool is_numeric_ip;
  186.     char *host_cp;
  187.  
  188. #ifdef MOZ_OFFLINE
  189.     if (NET_IsOffline()
  190.         || !setupSocks) {
  191.         /* Either we're offline, or this is the very first call ot setsockshost. */
  192.         socksFailure=FALSE;
  193.         return 1;
  194.     }
  195. #endif /* MOZ_OFFLINE */
  196.  
  197.     if(host && *host)
  198.       {
  199.         char *cp;
  200.         XP_LTRACE(MKLib_trace_flag,1,("Trying to set Socks host: %s\n", host));
  201.  
  202.         /* If there's no port or it's zero, fail out so user gets
  203.          * an error and checks his configuration.
  204.          */
  205.         if ( ((cp = XP_STRRCHR(host, ':')) != NULL) 
  206.             && (*(cp+1) != '\0') 
  207.             && (*(cp+1) != '0') ) {
  208.             *cp = 0;
  209.             NET_SocksPort = atoi(cp+1);
  210.         } else {
  211.             NET_SocksHost = 0;
  212.             NET_SocksPort = 0;
  213.             XP_FREEIF(NET_SocksHostName);
  214.             NET_SocksHostName = 0;
  215.             XP_LTRACE(MKLib_trace_flag,1,("Couldn't find a socks port. :(\n"));
  216.             socksFailure=TRUE;
  217.             return 0;  /* Fail? */
  218.         }
  219.  
  220.         is_numeric_ip = TRUE; /* init positive */
  221.         for(host_cp = host; *host_cp; host_cp++)
  222.             if(!XP_IS_DIGIT(*host_cp) && *host_cp != '.')
  223.               {
  224.                 is_numeric_ip = FALSE;
  225.                 break;
  226.               }
  227.  
  228.         if (is_numeric_ip)  /* Numeric node address */
  229.           {
  230.             TRACEMSG(("Socks host is numeric"));
  231.  
  232.             /* some systems return a number instead of a struct
  233.              */
  234.             NET_SocksHost = inet_addr(host);
  235.             if (NET_SocksHostName) XP_FREE (NET_SocksHostName);
  236.             NET_SocksHostName = XP_STRDUP(host);
  237.           }
  238.         else      /* name not number */
  239.           {
  240.             PRHostEnt *hp;
  241.             PRHostEnt hpbuf;
  242.             char dbbuf[PR_NETDB_BUF_SIZE];
  243.             PRStatus rv;
  244.  
  245.             NET_InGetHostByName++; /* global semaphore */
  246.             rv = PR_GetHostByName(host, dbbuf, sizeof(dbbuf),  &hpbuf);
  247.             hp = (rv == PR_SUCCESS ? &hpbuf : NULL);
  248.             NET_InGetHostByName--; /* global semaphore */
  249.  
  250.             if (!hp)
  251.               {
  252.                 XP_LTRACE(MKLib_trace_flag,1,("mktcp.c: Can't find Socks host name `%s'\n", host));
  253.                 NET_SocksHost = 0;
  254.                 if (NET_SocksHostName) XP_FREE (NET_SocksHostName);
  255.                 NET_SocksHostName = 0;
  256.                 XP_LTRACE(MKLib_trace_flag,1,("Socks host is bad. :(\n"));
  257.                 if (cp) {
  258.                   *cp = ':';
  259.                 }
  260.                 socksFailure=TRUE;
  261.                 return 0;  /* Fail? */
  262.               }
  263.             XP_MEMCPY(&NET_SocksHost, hp->h_addr, hp->h_length);
  264.           }
  265.         if (cp) {
  266.             *cp = ':';
  267.         }
  268.       }
  269.     else
  270.       {
  271.         NET_SocksHost = 0;
  272.         if (NET_SocksHostName) XP_FREE (NET_SocksHostName);
  273.         NET_SocksHostName = NULL;
  274.         NET_SocksPort = 0;
  275.         XP_LTRACE(MKLib_trace_flag,1,("Clearing Socks Host\n"));
  276.       }
  277.     socksFailure=FALSE;
  278.     return(1);
  279. }
  280.  
  281. /* Used internally as a utility function. */
  282. PRIVATE void
  283. NET_FreeDNSStruct(DNSEntry * theVictim)
  284. {
  285.     if(theVictim)
  286.       {
  287.         FREE(theVictim->ips);
  288.         FREEIF(theVictim->hostname);
  289.         FREE(theVictim);
  290.       }
  291. }
  292.  
  293. /* Used when user turns the cache off (dnsCacheExpiration is set to 0). */
  294. PRIVATE void
  295. NET_DeleteDNSList(void)
  296. {
  297.     XP_List * list_obj = dns_list;
  298.     DNSEntry * dns_entry;
  299.  
  300.     if(!list_obj)
  301.         return;
  302.     while((dns_entry = (DNSEntry *)XP_ListNextObject(list_obj)) != 0)
  303.     {
  304.         XP_ListRemoveObject(dns_list, dns_entry);
  305.         NET_FreeDNSStruct(dns_entry);
  306.     }
  307.     XP_ListDestroy(dns_list);
  308.     return;
  309. }
  310.  
  311. PUBLIC void
  312. NET_SetDNSExpirationPref(int32 n)
  313. {
  314.     if((dnsCacheExpiration = n) <= 0)
  315.         NET_DeleteDNSList();
  316. }
  317.  
  318. MODULE_PRIVATE int PR_CALLBACK
  319. NET_DNSExpirationPrefChanged(const char * newpref, void * data)
  320. {
  321.     int32 n;
  322.     PREF_GetIntPref(pref_dnsExpiration, &n);
  323.     NET_SetDNSExpirationPref((int32)n);
  324.     return PREF_NOERROR;
  325. }
  326.  
  327. /* the dnsCacheExpiration units are seconds */
  328. PRIVATE int32
  329. net_GetDNSExpiration(void)
  330. {
  331.     return dnsCacheExpiration;
  332. }
  333.  
  334. /* net_CacheDNSEntry
  335.  *
  336.  * caches the results of a dns lookup for fast
  337.  * retrieval
  338.  */
  339. PRIVATE void
  340. net_CacheDNSEntry(char * hostname, 
  341.                   PRHostEnt * host_pointer,
  342.                   int32 addrCount)
  343. {
  344. #if defined(MAX_DNS_LIST_SIZE) && (MAX_DNS_LIST_SIZE == 0)
  345.  
  346.     /* If MAX_DNS_LIST_SIZE is defined, and 0, don't cache anything. */
  347.     return;
  348.  
  349. #else /* !defined(MAX_DNS_LIST_SIZE) || (MAX_DNS_LIST_SIZE > 0) */
  350.  
  351.     /* Otherwise, MAX_DNS_LIST_SIZE is either the number of entries to
  352.        cache, or is undefined, meaning "unlimited." */
  353.  
  354.     int32 i;
  355.     DNSEntry * new_entry;
  356.  
  357.     /* Make sure incomming data is valid. */
  358.     if(!hostname || !host_pointer)
  359.         return;
  360.     
  361.     /* Determine whether or not we've got a list going yet. If not, get one */
  362.     if(!dns_list)
  363.         dns_list = XP_ListNew();
  364.     if(!dns_list)
  365.         return;
  366.  
  367.     /* Create our DNSEntry object for caching. */
  368.     if(!(new_entry = XP_NEW(DNSEntry)))
  369.         return;
  370.  
  371.     /* Copy the host name. */
  372.     new_entry->hostname = 0;
  373.     StrAllocCopy(new_entry->hostname, hostname);
  374.  
  375.     if(!new_entry->hostname)
  376.     {
  377.         XP_FREE(new_entry);
  378.         return;
  379.     }
  380.  
  381.     /* Copy all the ip addresses. */
  382.     if( !(new_entry->ips = (PRUint32 *) XP_ALLOC(sizeof(PRUint32) * addrCount)) )
  383.     {
  384.         XP_FREE(new_entry->hostname);
  385.         XP_FREE(new_entry);
  386.         return;
  387.     }
  388.  
  389.     XP_ASSERT(host_pointer->h_length == 4);
  390.     for(i=0; i < addrCount; i++)
  391.     {
  392.         XP_MEMCPY(&new_entry->ips[i], host_pointer->h_addr_list[i], 4);
  393.     }
  394.  
  395.     /* Copy all the other data. */
  396.     new_entry->addressCount = addrCount;
  397.     new_entry->h_length = host_pointer->h_length;
  398.     new_entry->expirationTime = time(NULL) + (net_GetDNSExpiration()); /* Current time plus expiration */
  399.  
  400.     XP_ListAddObject(dns_list, new_entry);
  401.  
  402. # ifdef MAX_DNS_LIST_SIZE
  403.     /* check to make sure the list is not overflowing the maximum size. */
  404.     if(XP_ListCount(dns_list) > MAX_DNS_LIST_SIZE)
  405.       {
  406.         DNSEntry * first_entry = (DNSEntry *) XP_ListRemoveEndObject(dns_list);
  407.         NET_FreeDNSStruct(first_entry);
  408.       }
  409. # endif /* defined(MAX_DNS_LIST_SIZE) */
  410.  
  411. #endif  /* !defined(MAX_DNS_LIST_SIZE) || (MAX_DNS_LIST_SIZE > 0) */
  412.     return;
  413. }
  414.  
  415. /* net_CheckDNSCache
  416.  *
  417.  * checks the list of cached dns entries and returns
  418.  * the dns info in the form of struct hostent if a match is
  419.  * found for the passed in hostname
  420.  */
  421. PRIVATE DNSEntry *    
  422. net_CheckDNSCache(CONST char * hostname)    
  423. {
  424.     XP_List *list_obj = dns_list;
  425.     DNSEntry * dns_entry;
  426.  
  427.     if(!hostname || !dns_list)
  428.         return(0);
  429.  
  430.     while((dns_entry = (DNSEntry *)XP_ListNextObject(list_obj)) != 0)
  431.       {
  432.         TRACEMSG(("net_CheckDNSCache: comparing %s and %s", hostname, dns_entry->hostname));
  433.         if(dns_entry->hostname && !strcasecomp(hostname, dns_entry->hostname))
  434.           {
  435.             /* See if the dns entry has expired, if so, get rid of it */
  436.             if(dns_entry->expirationTime < time(NULL))
  437.             {
  438.                 XP_ListRemoveObject(dns_list, dns_entry);
  439.                 NET_FreeDNSStruct(dns_entry);
  440.                 return 0;
  441.             }
  442.                return(dns_entry);
  443.           }
  444.       }
  445.     return(0);
  446. }
  447.  
  448. /*  print an IP address from a sockaddr struct
  449.  *
  450.  *  This routine is only used for TRACE messages
  451.  */
  452. #if defined(XP_WIN) || defined(XP_OS2)
  453. MODULE_PRIVATE char *CONST
  454. NET_IpString (struct sockaddr_in *sin)
  455. #else
  456. MODULE_PRIVATE CONST char * 
  457. NET_IpString (struct sockaddr_in *sin)
  458. #endif
  459. {
  460.     static char buffer[32];
  461.     int a,b,c,d;
  462.     unsigned char *pc;
  463.  
  464.     pc = (unsigned char *) &sin->sin_addr;
  465.  
  466.     a = (int) *pc;
  467.     b = (int) *(++pc);
  468.     c = (int) *(++pc);
  469.     d = (int) *(++pc);
  470.     PR_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d", a,b,c,d);
  471.  
  472.     return buffer;
  473. }
  474.  
  475. /* a list of dis-allowed ports for gopher connections for security reasons */
  476. PRIVATE int net_bad_ports_table[] = {
  477. 1, 7, 9, 11, 13, 15, 17, 19, 20,
  478. 21, 23, 25, 37, 42, 43, 53, 77, 79, 87, 95, 101, 102,
  479. 103, 104, 109, 110, 111, 113, 115, 117, 119,
  480. 135, 143, 389, 512, 513, 514, 515, 526, 530, 531, 532,
  481. 540, 556, 601, 6000, 0 };
  482.  
  483. /* Lookup a host name. If ASYNC_DNS is defined a platform specific async
  484.  * lookup will occur.
  485.  * 
  486.  * return: 0 on sucess, -1 on failure. MK_WAITING_FOR_LOOKUP is always
  487.  *   returned after first call when ASYNC_DNS is defined (you have to call
  488.  *   it again).
  489.  * 
  490.  * On success hostEnt is not null. */
  491.  
  492. PRIVATE int
  493. #ifndef ASYNC_DNS
  494. net_dns_lookup(char *host,
  495.                PRHostEnt **hostEnt,
  496.                char *dbbuf,
  497.                PRHostEnt *hpbuf)
  498. #else
  499. net_dns_lookup(MWContext *windowID,
  500.                char *host,
  501.                PRHostEnt **hostEnt,
  502.                PRFileDesc *socket)
  503. #endif /* ASYNC_DNS */
  504.  
  505.  
  506. {
  507.     int status;
  508.     NET_InGetHostByName++;
  509.     XP_ASSERT(host);
  510.     XP_ASSERT(hostEnt);
  511. #ifndef ASYNC_DNS
  512.     XP_ASSERT(dbbuf);
  513.     XP_ASSERT(hpbuf);
  514.  
  515.     /* Not asyncronus, completes a full lookup before returing. */
  516.     status = PR_GetHostByName(host, dbbuf, PR_NETDB_BUF_SIZE, hpbuf);
  517.  
  518.     if(status == PR_SUCCESS) {
  519.         /* Success, hpbuf points to a valid hostent. */
  520.         NET_InGetHostByName--;
  521.         *hostEnt=hpbuf;
  522.         return status;
  523.     }
  524. #else  /* ASYNC_DNS */
  525.     XP_ASSERT(windowID);
  526.     XP_ASSERT(socket);
  527.     /* FE_StartAsyncDNSLookup  should fill in the hoststruct
  528.      * or leave zero the pointer if not found
  529.      * it can also return MK_WAITING_FOR_LOOKUP
  530.      * if it's not done yet.
  531.      *
  532.      * dbbuf and hpbuf are not needed in ASYNC_DNS case. */
  533.     status = FE_AsyncDNSLookup(windowID, host, hostEnt, socket);
  534.  
  535.     if(status == MK_WAITING_FOR_LOOKUP)    {
  536.         /* Always get here after first call to FE_Async.. for a
  537.          * particular host name. This ensures execution doesn't 
  538.          * block. */
  539.         NET_InGetHostByName--;
  540.         return status;
  541.     }
  542.     else if(status == 0) {
  543.         /* Success, hostEnt points to a valid hostent. */
  544.         NET_InGetHostByName--;
  545.         return status;
  546.     }
  547. #endif /* ASYNC_DNS */
  548.     /* FAIL */
  549.     NET_InGetHostByName--;
  550.     /* must set this pointer to NULL if we fail. FE_AsyncDNSLookup does
  551.      * this but PR_GetHostByName doesn't, so we cover our bases here. */
  552.     *hostEnt = NULL;
  553.     return -1;
  554. }
  555.  
  556. /*  find the ip address of a host and set sin->sin_addr to that address
  557.  * return 0 on success */
  558.  
  559. PRIVATE int 
  560. net_FindAddress (const char *host_ptr, 
  561.                  PRNetAddr  *net_addr,
  562.                  MWContext  *window_id, 
  563.                  PRFileDesc *sock) {
  564.     PRHostEnt *hoststruct_pointer; /* Pointer to host - See netdb.h */
  565.     DNSEntry * cache_pointer;
  566.     char *port, *host_port=0, *host_cp;
  567.  
  568.     /* acts as a flag to determine whether or not this is the first failure. If it is, we want to sanityCheckDNS
  569.        which determines whether or not we've got a good net connection, sort of */
  570.     static XP_Bool first_dns_failure=TRUE;
  571.     static int random_host_number = -1;
  572.     static time_t random_host_expiration = 0;
  573.     static XP_Bool tryPAD=TRUE;
  574.     XP_Bool is_numeric_ip;
  575.  
  576.     if(!host_ptr || !*host_ptr)
  577.         return -1;
  578.  
  579.     /* Proxy Auto-Discovery (PAD) */
  580.     if(tryPAD && MK_PadEnabled && MK_padPacURL && *MK_padPacURL) {
  581.         PRHostEnt *hostEnt=NULL;
  582.         static PRFileDesc *socket=NULL;
  583.         if(!strncasecomp(MK_padPacURL, "file:", 5)) {
  584.             /* Don't allow file urls because they're hard to figure out in an xp way. */
  585.             tryPAD=FALSE;
  586.             foundPADPAC=FALSE;
  587.         } else {
  588.             if(socket == NULL)
  589.                 socket=PR_NewTCPSocket();
  590.             if(socket != NULL) {
  591.                 char *padHost=NET_ParseURL(MK_padPacURL, GET_HOST_PART);
  592.                 if(padHost && *padHost) {
  593.                     char *colon=XP_STRCHR(padHost, ':');
  594.                     int status;
  595. #ifndef ASYNC_DNS
  596.                     char dbbuf[PR_NETDB_BUF_SIZE];
  597.                     PRHostEnt dpbuf;
  598. #endif
  599.                     if(colon)
  600.                         *colon='\0';
  601. #ifndef ASYNC_DNS
  602.                     status = net_dns_lookup(padHost, &hostEnt, dbbuf, &dpbuf);
  603. #else
  604.                     status = net_dns_lookup(window_id, padHost, &hostEnt, socket);
  605. #endif /* ASYNC_DNS */
  606.                     if(status != MK_WAITING_FOR_LOOKUP) {
  607.                         PR_Close(socket);
  608.                         socket=NULL;
  609.                         if(hostEnt != NULL)
  610.                             /* We found the padpac */
  611.                             foundPADPAC=TRUE;
  612.                         tryPAD=FALSE;
  613.                     }
  614.                     if(colon)
  615.                         *colon=':';
  616.                 } else {
  617.                     PR_Close(socket);
  618.                     socket=NULL;
  619.                     tryPAD=FALSE;
  620.                 }
  621.                 XP_FREEIF(padHost);
  622.             } /* End socket not null */
  623.         } 
  624.     } /* End tryPAD */
  625.  
  626.     StrAllocCopy(host_port, host_ptr);      /* Make a copy we can mess with */
  627.     if (!host_port)
  628.         return -1;
  629.  
  630.     /* Parse port number if present */  
  631.     port = XP_STRCHR(host_port, ':');  
  632.     if (port) {
  633.         *port++ = 0;       
  634.         if (XP_IS_DIGIT(*port)) {
  635.             unsigned short port_num = (unsigned short) atol(port);
  636.             int i;
  637.  
  638.             /* check for illegal ports */
  639.             /* if the explicit port number equals
  640.              * the default port number let it through
  641.              */
  642.             if(port_num != PR_ntohs(net_addr->inet.port)) {
  643.                 /* disallow well known ports */
  644.                 for(i=0; net_bad_ports_table[i]; i++)
  645.                     if(port_num == net_bad_ports_table[i]) {
  646.                         char *error_msg = XP_STRDUP(XP_GetString(MK_PORT_ACCESS_NOT_ALLOWED));
  647.                         if(error_msg) {
  648.                             FE_Alert(window_id, error_msg);
  649.                             XP_FREE(error_msg);
  650.                             }
  651.  
  652.                         /* return special error code
  653.                          * that NET_BeginConnect knows
  654.                          * about.
  655.                          */
  656.                         XP_FREE(host_port);
  657.                         return(MK_UNABLE_TO_CONNECT);
  658.                         }
  659.  
  660.                 net_addr->inet.port = PR_htons(port_num);
  661.               }
  662.  
  663.           }
  664.       }
  665.  
  666.     /* see if this host entry is already cached */
  667.     if( (cache_pointer = net_CheckDNSCache(host_port)) != NULL ) {
  668.         /* call FE_ClearDNSSelect to catch the case of a cache hit before 
  669.          * a successfull lookup response for this particular socket.
  670.          * This happens when a previous socket lookup for the same host
  671.          * succeeded and propagated the cache entry before this one
  672.          * finished.
  673.          */
  674.         NET_ClearDNSSelect(window_id, sock);
  675.         
  676.         net_addr->inet.ip = cache_pointer->ips[0];
  677.  
  678.         XP_FREE(host_port);
  679.         return(0);  /* FOUND OK */
  680.     }
  681.  
  682.     /* Determine whether or not we're dealing with an ip address as the host */
  683.     is_numeric_ip = TRUE; /* init positive */
  684.     for(host_cp = host_port; *host_cp; host_cp++)
  685.         if(!XP_IS_DIGIT(*host_cp) && *host_cp != '.') {
  686.             is_numeric_ip = FALSE;
  687.             break;
  688.           }
  689.  
  690.     /* Parse host number if present. */  
  691.     if (is_numeric_ip) {
  692.         PRUint16 port = net_addr->inet.port;  /* save a copy */
  693.         if(PR_SUCCESS != PR_StringToNetAddr(host_port, net_addr)) {
  694.             XP_ASSERT(0);
  695.             XP_FREE(host_port);
  696.             return(-1); /* fail */
  697.         }
  698.         net_addr->inet.port = port;  /* StringToNetAddr overites the port num */
  699.     /* name not number */
  700.     } else {
  701.         int32 addressCount=0;
  702.         char *remapped_host_port=0;
  703.  
  704.         /* randomly remap home.netscape.com to home1.netscape.com through
  705.          * home32.netscape.com
  706.          * cache the original name not the new one.
  707.          */
  708.         if((!strncasecomp(host_port, "home.", 5)
  709.             || !strncasecomp(host_port, "rl.", 3))
  710.             && (strcasestr(host_port+2, ".netscape.com")
  711.                 || strcasestr(host_port+2, ".mcom.com"))) {
  712.             time_t cur_time = time(NULL);
  713.             char temp_string[32];
  714.             XP_Bool is_rl_host;
  715.  
  716.             *temp_string = '\0';
  717.  
  718.             is_rl_host = !strncasecomp(host_port, "rl.", 3);
  719.  
  720.             if(random_host_number == -1 || random_host_expiration < cur_time) {
  721.                 /* pick a new random number */
  722.                 random_host_expiration = cur_time + (60 * 5); /* five min */
  723.                 random_host_number = (XP_RANDOM() & 31);
  724.               }
  725.                 
  726.             if(is_rl_host)
  727.                 PR_snprintf(temp_string, sizeof(temp_string), "rl%d%s",
  728.                                random_host_number+1, host_port+2);
  729.             else
  730.                 PR_snprintf(temp_string, sizeof(temp_string), "home%d%s",
  731.                                random_host_number+1, host_port+4);
  732.  
  733.             StrAllocCopy(remapped_host_port, temp_string);
  734.  
  735.             TRACEMSG(("Remapping %s to %s", host_port, remapped_host_port));
  736.           } 
  737.         
  738. #ifdef XP_UNIX
  739.           {
  740.             /* Implement a terrible hack just for unix. If the environment
  741.              * variable SOCKS_NS is defined, stomp on the host that the DNS
  742.              * code uses for host lookup to be a specific ip address. */
  743.             static char firstTime = 1;
  744.             if (firstTime) {
  745.                 char *ns = getenv("SOCKS_NS");
  746.                 firstTime = 0;
  747.                 if (ns && ns[0]) {
  748.                     /* Use a specific host for dns lookups */
  749.                     extern int res_init (void);
  750.                     res_init();
  751.                     _res.nsaddr_list[0].sin_addr.s_addr = inet_addr(ns);
  752.                     _res.nscount = 1;
  753.                   }
  754.               }
  755.           }
  756. #endif
  757.  
  758.         {
  759.             int status;
  760. #ifndef ASYNC_DNS
  761.             char dbbuf[PR_NETDB_BUF_SIZE];
  762.             PRHostEnt dpbuf;
  763. #endif
  764.             /* malloc the string to prevent overflow */
  765.             char *msg = PR_smprintf(XP_GetString(XP_PROGRESS_LOOKUPHOST), host_port);
  766.  
  767.             if(msg) {
  768.                 NET_Progress(window_id, msg);
  769.                 XP_FREE(msg);
  770.               }
  771.  
  772. #ifndef ASYNC_DNS
  773.             status = net_dns_lookup( 
  774.                            (remapped_host_port ?
  775.                             remapped_host_port :
  776.                             host_port),
  777.                             &hoststruct_pointer,
  778.                             dbbuf,
  779.                             &dpbuf);
  780. #else
  781.             status = net_dns_lookup(window_id, 
  782.                                (remapped_host_port ?
  783.                                 remapped_host_port :
  784.                                 host_port),
  785.                                 &hoststruct_pointer,
  786.                                 sock);
  787. #endif /* ASYNC_DNS */            
  788.             /* sucess if hoststruct_pointer is not null */
  789.             if(status == MK_WAITING_FOR_LOOKUP) {
  790.                 XP_FREE(host_port);
  791.                 return status;
  792.             }
  793.         }
  794.  
  795.         if (!hoststruct_pointer) {
  796.             if(first_dns_failure) {
  797.                 first_dns_failure = FALSE;
  798.                 /* On the proxy causes confusing messages.
  799.                  * This function is only implemented on for XP_UNIX. */
  800.                 NET_SanityCheckDNS(window_id);
  801.               }
  802.             XP_LTRACE(MKLib_trace_flag,1,("mktcp.c: Can't find host name `%s'.  Errno #%d\n",
  803.                                     host_port, PR_GetError()));
  804.             XP_FREE(host_port);
  805.             XP_LTRACE(MKLib_trace_flag,1,("gethostbyname failed with error: %d\n", PR_GetError()));
  806.             return -1;  /* Fail? */
  807.         }
  808.  
  809.         /* Count the number of addresses returned in the A record. */
  810.         for (addressCount=0; hoststruct_pointer->h_addr_list[addressCount]; addressCount++) {;}
  811.  
  812.         /* If the addressCount is zero we've got a problem */
  813.         if (addressCount == 0) {
  814.             XP_ASSERT(0);
  815.             XP_FREE(host_port);
  816.             return -1;
  817.         }
  818.  
  819.         /* Copy the first address in the list to the sin. char ** h_addr_list */
  820.         XP_ASSERT(hoststruct_pointer->h_length == 4);
  821.         XP_MEMCPY(&net_addr->inet.ip, hoststruct_pointer->h_addr_list[0], 4);
  822.     
  823.         /* if NET_GetDNSExpiration() returns 0 we are considering the cache disabled */
  824.         if(net_GetDNSExpiration() > 0)
  825.             net_CacheDNSEntry(host_port, hoststruct_pointer, addressCount);
  826.       } /* end name not number else*/
  827.  
  828. #ifdef DEBUG
  829.     {
  830.         char str[64];
  831.         PR_NetAddrToString(net_addr, str, sizeof(str));
  832.         TRACEMSG(("TCP.c: Found address %s and port %d", str, (int)PR_ntohs(net_addr->inet.port)));
  833.     }
  834. #endif
  835.  
  836.     XP_FREE(host_port);
  837.     return(0);   /* OK, we found an address */
  838. }
  839.  
  840. /*  Find out what host this is that we are running on
  841.  */
  842. #ifdef XP_WIN
  843. MODULE_PRIVATE char *CONST NET_HostName ()
  844. #else
  845. MODULE_PRIVATE const char * NET_HostName ()
  846. #endif
  847. {
  848.     if(!net_local_hostname)
  849.       {
  850.         char tmp_local_hostname[256];
  851.  
  852.         if (PR_GetSystemInfo(PR_SI_HOSTNAME, tmp_local_hostname, 254) == PR_FAILURE) /* Error, just get an empty string */
  853.             tmp_local_hostname[0] = 0;
  854.         StrAllocCopy(net_local_hostname, tmp_local_hostname);
  855.             
  856.         TRACEMSG(("TCP.c: Found local host name: %s", net_local_hostname));
  857.       }
  858.     return net_local_hostname;
  859. }
  860.  
  861. /* FREE left over tcp connection data if there is any
  862.  */
  863. MODULE_PRIVATE void 
  864. NET_FreeTCPConData(TCP_ConData * data)
  865. {
  866.     TRACEMSG(("Freeing TCPConData...Done with connect (i hope)"));
  867.     FREEIF(data)
  868. }
  869.  
  870. PRIVATE int
  871. net_start_first_connect(const char   *host, 
  872.                         PRFileDesc   *sock, 
  873.                         MWContext    *window_id, 
  874.                         TCP_ConData  *tcp_con_data,
  875.                         char        **error_msg)
  876. {
  877.  
  878.     /* malloc the string to prevent overflow
  879.      */
  880.     int32 len = XP_STRLEN(XP_GetString(XP_PROGRESS_CONTACTHOST));
  881.     char * buf;
  882.  
  883.     len += XP_STRLEN(host);
  884.  
  885.     buf = (char *)XP_ALLOC((len+10)*sizeof(char));
  886.     if(buf)
  887.       {
  888.         PR_snprintf(buf, (len+10)*sizeof(char),
  889.                 XP_GetString(XP_PROGRESS_CONTACTHOST), host);
  890.         NET_Progress(window_id, buf);
  891.         FREE(buf);
  892.       }
  893.  
  894.     /* set the begining time to be the current time.
  895.      * the timeout value will be  compared to this
  896.      * later
  897.      */
  898.     tcp_con_data->begin_time = time(NULL);
  899.  
  900. #define CONNECT_TIMEOUT  0
  901.  
  902.     /* if it's not equal to PR_SUCCESS something went wrong
  903.      *
  904.      * PRNetAddr is binary compatible with struct sockaddr
  905.      */
  906.     if(PR_SUCCESS != PR_Connect (sock,
  907.                                  &tcp_con_data->net_addr,
  908.                                  CONNECT_TIMEOUT))
  909.       {
  910.  
  911.         int rv = PR_GetError();
  912.  
  913. #if !defined(XP_MAC) && !defined(XP_WIN16)
  914.         XP_ASSERT(rv != PR_WOULD_BLOCK_ERROR); /* should never happen */
  915. #endif
  916.         if (rv == PR_IN_PROGRESS_ERROR || rv == PR_WOULD_BLOCK_ERROR)
  917.           {
  918.             tcp_con_data->next_state = NET_TCP_FINISH_CONNECT;
  919.             return(MK_WAITING_FOR_CONNECTION);  /* not connected yet */
  920.           }
  921.         else if (rv == PR_IS_CONNECTED_ERROR)
  922.           {
  923.             return(MK_CONNECTED);  /* already connected */
  924.           }
  925.         else
  926.           {
  927.             PR_Close(sock);
  928.             if(rv == PR_CONNECT_REFUSED_ERROR)
  929.               {
  930.                 *error_msg = NET_ExplainErrorDetails(MK_CONNECTION_REFUSED, host);
  931.  
  932.                 XP_LTRACE(MKLib_trace_flag,1,("connect: refused\n"));
  933.  
  934.                 return(MK_CONNECTION_REFUSED);
  935.               }
  936.             else if(rv == PR_CONNECT_TIMEOUT_ERROR)
  937.               {
  938.                 *error_msg = NET_ExplainErrorDetails(MK_CONNECTION_TIMED_OUT);
  939.  
  940.                 XP_LTRACE(MKLib_trace_flag,1,("connect: timed out\n"));
  941.  
  942.                 return(MK_CONNECTION_TIMED_OUT);
  943.               }
  944.             else 
  945.               {
  946.                 *error_msg = NET_ExplainErrorDetails(MK_UNABLE_TO_CONNECT, rv);
  947.  
  948.                 XP_LTRACE(MKLib_trace_flag,1,("connect: unable to connect %i\n", rv));
  949.  
  950.                 return (MK_UNABLE_TO_CONNECT);
  951.               }
  952.           }
  953.       }
  954.  
  955.     /* else  good connect */
  956.  
  957.     return(MK_CONNECTED);
  958. }
  959.  
  960. /* Finds the DNSEntry with hostname in it, removes it if it only has one address, otherwise
  961.    removes the first address and shifts the other(s) forward so they can be tried. */
  962. PRIVATE XP_Bool
  963. net_connection_failed(CONST char *hostname)
  964. {
  965.     DNSEntry *dns_entry = 0;
  966.     char *hostCopy=NULL, *port=NULL;
  967.  
  968.     if(!hostname)
  969.         return FALSE;
  970.  
  971.     StrAllocCopy(hostCopy, hostname);
  972.     if(!hostCopy)
  973.         return FALSE;
  974.  
  975.     /* Look for a port */
  976.     if( (port = XP_STRCHR(hostCopy, ':')) != NULL )
  977.         *port = '\0';
  978.  
  979.     dns_entry = net_CheckDNSCache(hostCopy);
  980.     FREE(hostCopy);
  981.     /* If we find the cached dns entry pull the address off the top because it is the one 
  982.         that failed. Then shift the others up to the front of the list. */
  983.     if (dns_entry)
  984.     {
  985.         /* If there is only one (most common case) ip address associated with this host,
  986.            blow the entire entry away */
  987.         if (dns_entry->addressCount == 1)          
  988.         {
  989.             XP_ListRemoveObject(dns_list, dns_entry);
  990.             NET_FreeDNSStruct(dns_entry);
  991.             return FALSE;
  992.         }
  993.         else /* Failover case */
  994.         {
  995.             dns_entry->addressCount--;
  996.             /* Shift addresses up one, overwriting the first one */
  997.             XP_MEMMOVE(dns_entry->ips,
  998.                         &dns_entry->ips[1],
  999.                         sizeof(PRUint32) * dns_entry->addressCount );
  1000.             /* Null terminate the array */
  1001.             dns_entry->ips[dns_entry->addressCount] = 0;
  1002.             return TRUE;
  1003.         }
  1004.     }
  1005.     /* If the host wasn't in the cache then caching is off or an ip address was sent in here
  1006.        and we don't want to keep trying this address so return false. */
  1007.     return FALSE;
  1008. }
  1009.  
  1010.  
  1011. /*
  1012.  * Non blocking connect begin function.  It will most likely
  1013.  * return negative. If it does, NET_ConnectFinish() will
  1014.  * need to be called repeatably until a connect is established.
  1015.  *
  1016.  * return's negative on error
  1017.  * return's MK_WAITING_FOR_CONNECTION when continue is neccessary
  1018.  * return's MK_CONNECTED on true connect
  1019.  */ 
  1020.  
  1021. MODULE_PRIVATE int 
  1022. NET_BeginConnect (CONST char   *url, 
  1023.                   char   *ip_address_string,
  1024.                     char         *prot_name, 
  1025.                     int           def_port, 
  1026.                     PRFileDesc     **sock, 
  1027.                   Bool       use_security,
  1028.                   TCP_ConData **tcp_con_data,
  1029.                     MWContext    *window_id,
  1030.                   char        **error_msg,
  1031.                   u_long        socks_host,
  1032.                   short            socks_port)
  1033. {
  1034.  
  1035.     char * proxy=NULL;
  1036.     int32 iPort=0;
  1037.     char text[MAXHOSTNAMELEN + 8];
  1038.     CONST char *host; 
  1039.     char *althost=0; 
  1040.        int status;
  1041.     PRFileDesc *fd;
  1042.     char *host_string=0;
  1043.     PRSocketOptionData opt;
  1044. #ifdef MOZ_OFFLINE
  1045.     if (NET_IsOffline())    /* if we're offline, ret error - dmb 11/25/96 */
  1046.         return MK_OFFLINE;    
  1047. #endif /* MOZ_OFFLINE */
  1048.     TRACEMSG(("NET_BeginConnect called for url: %s", url));
  1049.  
  1050.     /* One time startup flag. If this is the first time in BeginConnect,
  1051.      * make sure the socks is setup if it needs to be.
  1052.      */
  1053.     if(!setupSocks) {
  1054.         setupSocks=TRUE;
  1055.         if (NET_GetProxyStyle() == PROXY_STYLE_MANUAL) {
  1056.             PREF_CopyCharPref("network.hosts.socks_server",&proxy);
  1057.             if (proxy && *proxy) {
  1058.                 PREF_GetIntPref("network.hosts.socks_serverport",&iPort);
  1059.                 PR_snprintf(text, sizeof(text), "%s:%d", proxy, iPort);  
  1060.                 NET_SetSocksHost(text);
  1061.             }
  1062.             else {
  1063.                 NET_SetSocksHost(proxy); /* NULL is ok */
  1064.             }
  1065.         }
  1066.     }
  1067.  
  1068.     /* in case finish connect calls us 
  1069.      */
  1070.     if(*tcp_con_data)
  1071.         NET_FreeTCPConData(*tcp_con_data);
  1072.     
  1073.     /* construct state table data
  1074.      */    
  1075.     *tcp_con_data = XP_NEW(TCP_ConData);
  1076.     
  1077.     if(!*tcp_con_data)
  1078.       {
  1079.         *error_msg = NET_ExplainErrorDetails(MK_OUT_OF_MEMORY);
  1080.         return(MK_OUT_OF_MEMORY);
  1081.       }
  1082.  
  1083.     XP_MEMSET(*tcp_con_data, 0, sizeof(TCP_ConData));
  1084.  
  1085.     /* Set up Internet defaults and port*/
  1086.     PR_InitializeNetAddr(PR_IpAddrNull, (PRUint16) def_port, &(*tcp_con_data)->net_addr);
  1087.  
  1088.     if(NET_URL_Type(url)) 
  1089.       {
  1090.         host_string = NET_ParseURL(url, GET_HOST_PART);
  1091.         host = host_string;
  1092.       }
  1093.     else
  1094.       {
  1095.         /* assume that a hostname was passed directly 
  1096.          * instead of a URL
  1097.          */
  1098.         host = url;
  1099.       }
  1100.  
  1101.     /* build a socket
  1102.      */
  1103.     *sock = PR_NewTCPSocket();
  1104.  
  1105. HG59609
  1106.  
  1107.     if(*sock == NULL)
  1108.       {                                                
  1109.         int error = PR_GetError();
  1110.         TRACEMSG(("NETSOCKET call returned INVALID_SOCKET: %d", error));
  1111.         NET_FreeTCPConData(*tcp_con_data);
  1112.         *tcp_con_data = 0;
  1113.         *error_msg = NET_ExplainErrorDetails(MK_UNABLE_TO_CREATE_SOCKET, error);
  1114.         FREE_AND_CLEAR(host_string);
  1115.         return(MK_UNABLE_TO_CREATE_SOCKET);
  1116.       }
  1117.  
  1118. HG40252
  1119.  
  1120.     /* make the socket non-blocking */
  1121.     opt.option = PR_SockOpt_Nonblocking;
  1122.     opt.value.non_blocking = PR_TRUE;
  1123.     PR_SetSocketOption(*sock, &opt);
  1124.  
  1125. #if defined(XP_WIN16) || (defined(XP_OS2) && !defined(XP_OS2_DOUGSOCK))
  1126.     opt.option = PR_SockOpt_Linger;
  1127.     opt.value.linger.polarity = PR_TRUE;
  1128.     opt.value.linger.linger = PR_INTERVAL_NO_WAIT;
  1129.     PR_SetSocketOption(*sock, &opt);
  1130. #endif /* XP_WIN16 */
  1131.  
  1132.     /* copy the sock no
  1133.      */
  1134.     fd = *sock;
  1135.  
  1136. HG28879
  1137.     {
  1138.         /* if the socks host is invalid */
  1139.         if ( socksFailure && (NET_GetProxyStyle() == PROXY_STYLE_MANUAL) )
  1140.         {
  1141.             char * prefSocksHost = NULL;
  1142.             /* Tell the FE about the failure */
  1143.             int32 len = XP_STRLEN(XP_GetString(XP_PROGRESS_UNABLELOCATE));
  1144.             char * buf;
  1145.             PREF_CopyCharPref("network.hosts.socks_server",&prefSocksHost);
  1146.             if(prefSocksHost)
  1147.             {
  1148.                 len += XP_STRLEN(prefSocksHost);
  1149.  
  1150.                 buf = (char *)XP_ALLOC((len+10)*sizeof(char));
  1151.                 if(buf)
  1152.                   {
  1153.                     PR_snprintf(buf, (len+10)*sizeof(char),
  1154.                             XP_GetString(XP_PROGRESS_UNABLELOCATE), prefSocksHost);
  1155.                     NET_Progress(window_id, buf);
  1156.                     FREE(buf);
  1157.                   }
  1158.  
  1159.                 /* Tell the user about the failure */
  1160.                 *error_msg = NET_ExplainErrorDetails(MK_UNABLE_TO_LOCATE_SOCKS_HOST, prefSocksHost);
  1161.  
  1162.                 /* clean up prior to leaving */
  1163.                 NET_FreeTCPConData(*tcp_con_data);
  1164.                 *tcp_con_data = 0;
  1165.                 PR_Close(*sock);
  1166.                 *sock = NULL;
  1167.                 FREE_AND_CLEAR(host_string);
  1168.                 XP_FREEIF(prefSocksHost);
  1169.             }
  1170.             return MK_UNABLE_TO_LOCATE_HOST;
  1171.         }
  1172.     }
  1173.  
  1174. HG71089
  1175.  
  1176.     /* if an IP address string was passed in, then use it instead of the
  1177.      * hostname to do the DNS lookup.
  1178.      */
  1179.     if ( ip_address_string ) {
  1180.         char *port;
  1181.  
  1182.         StrAllocCopy(althost, ip_address_string);
  1183.  
  1184.         port = XP_STRCHR(host, ':');
  1185.         if ( port ) {
  1186.             StrAllocCat(althost, port);
  1187.         }
  1188.     }
  1189.     
  1190.     status = net_FindAddress(althost?althost:host, 
  1191.                  &((*tcp_con_data)->net_addr), 
  1192.                  window_id, 
  1193.                  *sock);
  1194.  
  1195.     if (althost) {
  1196.         XP_FREE(althost);
  1197.     }
  1198.     
  1199.     if(status == MK_WAITING_FOR_LOOKUP)
  1200.       {
  1201.         (*tcp_con_data)->next_state = NET_TCP_FINISH_DNS_LOOKUP;
  1202.         FREE_AND_CLEAR(host_string);
  1203.            return(MK_WAITING_FOR_CONNECTION);  /* not connected yet */
  1204.       }
  1205.     else if (status < 0)
  1206.       {
  1207.         {
  1208.             /* malloc the string to prevent overflow
  1209.              */
  1210.             int32 len = XP_STRLEN(XP_GetString(XP_PROGRESS_UNABLELOCATE));
  1211.             char * buf;
  1212.  
  1213.             len += XP_STRLEN(host);
  1214.  
  1215.             buf = (char *)XP_ALLOC((len+10)*sizeof(char));
  1216.             if(buf)
  1217.               {
  1218.                 PR_snprintf(buf, (len+10)*sizeof(char),
  1219.                         XP_GetString(XP_PROGRESS_UNABLELOCATE), host);
  1220.                 NET_Progress(window_id, buf);
  1221.                 FREE(buf);
  1222.               }
  1223.         }
  1224.  
  1225.         NET_FreeTCPConData(*tcp_con_data);
  1226.         *tcp_con_data = 0;
  1227.         PR_Close(*sock);
  1228.         *sock = NULL;
  1229.  
  1230.         /* @@@@@ HACK!  If we detect an illegal port in
  1231.          * net_FindAddress we put up an error message
  1232.          * and return MK_UNABLE_TO_CONNECT.  Don't
  1233.          * print another message
  1234.          */
  1235.         if(status != MK_UNABLE_TO_CONNECT)
  1236.             *error_msg = NET_ExplainErrorDetails(MK_UNABLE_TO_LOCATE_HOST, 
  1237.                                                 *host ? host : "(no name specified)");
  1238.         FREE_AND_CLEAR(host_string);
  1239.         return MK_UNABLE_TO_LOCATE_HOST;
  1240.       }
  1241.  
  1242.     status = net_start_first_connect(host, *sock, window_id, 
  1243.                                      *tcp_con_data, error_msg);
  1244.  
  1245.     if(status != MK_WAITING_FOR_CONNECTION)
  1246.       {
  1247.         NET_FreeTCPConData(*tcp_con_data);
  1248.         *tcp_con_data = 0;
  1249.       }
  1250.     else
  1251.       {
  1252.            (*tcp_con_data)->next_state = NET_TCP_FINISH_CONNECT;
  1253.         /* save in case we need it */
  1254.            (*tcp_con_data)->use_security = use_security; 
  1255.       }
  1256.  
  1257.     if(status < 0)
  1258.       {
  1259.         net_connection_failed(host);
  1260.         PR_Close(*sock);
  1261.         *sock = NULL;
  1262.       }
  1263.  
  1264.     FREE_AND_CLEAR(host_string);
  1265.     
  1266.     return(status);
  1267. }
  1268.  
  1269.  
  1270. /*
  1271.  * Non blocking connect finishing function.  This routine polls
  1272.  * the socket until a connection finally takes place or until
  1273.  * an error occurs. NET_ConnectFinish() will need to be called 
  1274.  * repeatably until a connect is established.
  1275.  *
  1276.  * return's negative on error
  1277.  * return's MK_WAITING_FOR_CONNECTION when continue is neccessary
  1278.  * return's MK_CONNECTED on true connect
  1279.  */
  1280. PUBLIC int 
  1281. NET_FinishConnect (CONST char   *url,
  1282.                    char         *prot_name,
  1283.                    int           def_port,
  1284.                    PRFileDesc   **sock, 
  1285.                    TCP_ConData **tcp_con_data,
  1286.                    MWContext    *window_id,
  1287.                    char        **error_msg)
  1288. {
  1289.     int status;
  1290.     char *host=NULL;
  1291.  
  1292.     TRACEMSG(("NET_FinishConnect called for url: %s", url));
  1293.  
  1294.     if(!*tcp_con_data)  /* safty valve */
  1295.       {
  1296.         *error_msg = NET_ExplainErrorDetails(MK_OUT_OF_MEMORY);
  1297.         return(MK_OUT_OF_MEMORY);
  1298.       }
  1299.  
  1300.     switch((*tcp_con_data)->next_state)
  1301.     {
  1302.     case NET_TCP_FINISH_DNS_LOOKUP:
  1303.       {
  1304.         char * host_string=NULL;    
  1305.         const char * host = NULL;
  1306.  
  1307.         if(NET_URL_Type(url))
  1308.           {
  1309.             host_string = NET_ParseURL(url, GET_HOST_PART);
  1310.             host = host_string;
  1311.           }
  1312.         else
  1313.           {
  1314.             /* assume that a hostname was passed directly
  1315.              * instead of a URL
  1316.              */
  1317.             host = url;
  1318.           }
  1319.  
  1320.         status = net_FindAddress(host, 
  1321.                     &((*tcp_con_data)->net_addr),
  1322.                     window_id, 
  1323.                     *sock);
  1324.  
  1325.         if(status == MK_WAITING_FOR_LOOKUP)
  1326.           {
  1327.             (*tcp_con_data)->next_state = NET_TCP_FINISH_DNS_LOOKUP;
  1328.             return(MK_WAITING_FOR_CONNECTION);  /* not connected yet */
  1329.           }
  1330.         else if (status < 0)
  1331.           {
  1332.             {
  1333.                 /* malloc the string to prevent overflow
  1334.                   */
  1335.                 int32 len = XP_STRLEN(XP_GetString(XP_PROGRESS_UNABLELOCATE));
  1336.                 char * buf;
  1337.     
  1338.                 len += XP_STRLEN(host);
  1339.     
  1340.                 buf = (char *)XP_ALLOC((len+10)*sizeof(char));
  1341.                 if(buf)
  1342.                     {
  1343.                     PR_snprintf(buf, (len+10)*sizeof(char),
  1344.                             XP_GetString(XP_PROGRESS_UNABLELOCATE), host);
  1345.                     NET_Progress(window_id, buf);
  1346.                     FREE(buf);
  1347.                     }
  1348.             }
  1349.  
  1350.             NET_FreeTCPConData(*tcp_con_data);
  1351.             *tcp_con_data = 0;
  1352.             *error_msg = NET_ExplainErrorDetails(MK_UNABLE_TO_LOCATE_HOST, host);
  1353.             FREE_AND_CLEAR(host_string);
  1354.             return MK_UNABLE_TO_LOCATE_HOST;
  1355.           }
  1356.  
  1357.         status = net_start_first_connect(host, *sock, window_id, 
  1358.                                          *tcp_con_data, error_msg);
  1359.  
  1360.         if(status != MK_WAITING_FOR_CONNECTION)
  1361.           {
  1362.             NET_FreeTCPConData(*tcp_con_data);
  1363.             *tcp_con_data = 0;
  1364.           }
  1365.         else
  1366.           {
  1367.             (*tcp_con_data)->next_state = NET_TCP_FINISH_CONNECT;
  1368.           }
  1369.  
  1370.         if(status < 0)
  1371.           {
  1372.             net_connection_failed(host);
  1373.             XP_LTRACE(MKLib_trace_flag,1,("mktcp.c: Error during connect %d\n", PR_GetError()));
  1374.             PR_Close(*sock);
  1375.             *sock = NULL;
  1376.           }  
  1377.  
  1378.         FREE_AND_CLEAR(host_string);
  1379.  
  1380.         return(status);
  1381.  
  1382.       } /* end of this part of the case */
  1383.     
  1384.     case NET_TCP_FINISH_CONNECT:
  1385.     {
  1386.         PRPollDesc pd;
  1387.  
  1388.         pd.fd = *sock;
  1389.         pd.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; 
  1390.  
  1391.         /* do another connect here to see if we are actually connected
  1392.          *
  1393.          * PRNetAddr is binary compatible with struct sockaddr
  1394.          */
  1395.         if(PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT) < 1)
  1396.         {
  1397.             XP_ASSERT(0);
  1398.             return MK_WAITING_FOR_CONNECTION;  /* perhaps we should error here */
  1399.         }
  1400.  
  1401. #if defined(XP_WIN16)
  1402.         if(PR_SUCCESS != PR_Connect (*sock,
  1403.                                  &(*tcp_con_data)->net_addr,
  1404.                                  CONNECT_TIMEOUT))
  1405. #else
  1406.         if(PR_SUCCESS != PR_GetConnectStatus(&pd))
  1407. #endif 
  1408.         {
  1409.             int error;
  1410.     
  1411.             error = PR_GetError();
  1412.         
  1413. #if !defined(XP_MAC) && !defined(XP_WIN16)
  1414.             XP_ASSERT(error != PR_WOULD_BLOCK_ERROR); /* should never happen */
  1415. #endif
  1416.             if (error == PR_IN_PROGRESS_ERROR || error == PR_WOULD_BLOCK_ERROR)
  1417.               {
  1418.  
  1419.                 /* check the begin time against the current time minus
  1420.                  * the timeout value.  Error out if past the timeout
  1421.                  */
  1422.                 if((time_t)(time(NULL)-net_tcp_connect_timeout) > (*tcp_con_data)->begin_time)
  1423.                   {
  1424.                     error = XP_ERRNO_ETIMEDOUT;
  1425.                     goto error_out;
  1426.                   }
  1427.  
  1428.                 /* still waiting
  1429.                  */
  1430.                 return MK_WAITING_FOR_CONNECTION;
  1431.               }
  1432.             else if(error !=  PR_IS_CONNECTED_ERROR)
  1433.               {
  1434. error_out:
  1435.             
  1436.                 /* if EISCONN then we actually are connected
  1437.                  * otherwise return an error
  1438.                  */
  1439.  
  1440.                 /* At this point we know there was a problem with the ip address we tried. */
  1441.                 XP_LTRACE(MKLib_trace_flag,1,("mktcp.c: Error during connect: %d\n", error));
  1442.  
  1443.                 host = NET_ParseURL(url, GET_HOST_PART);
  1444.                 if(!host)
  1445.                     return -1;
  1446.  
  1447.                 /* In the case when the url is a host, no protocol, NET_ParseURL returns null byte.
  1448.                    We run up against this case when a proxy was placed into the url instead of 
  1449.                    the url itself.*/
  1450.                 if(*host == '\0') {
  1451.                     FREE(host);
  1452.                     host = NULL;
  1453.                     StrAllocCopy(host, url);
  1454.                 }
  1455.  
  1456.                 /* If we should try other addresses with this tcpConnection, do it */
  1457.                 if (net_connection_failed(host))
  1458.                 {
  1459.                     int status;
  1460.  
  1461.                     if(*host == '\0')
  1462.                       {
  1463.                         /* the url is a hostname */
  1464.                         FREE(host);
  1465.                         if( !(host = XP_STRDUP(url)) )
  1466.                             return -1;
  1467.                       }
  1468.  
  1469.                     /* Go get another of the ip addresses */
  1470.                     status = net_FindAddress(host, 
  1471.                                  &((*tcp_con_data)->net_addr), 
  1472.                                  window_id, 
  1473.                                  *sock);
  1474.  
  1475.                     FREE(host);
  1476.                     if(status == 0)
  1477.                         return(NET_BeginConnect (url,
  1478.                                                 NULL,
  1479.                                                  prot_name,
  1480.                                                  def_port,
  1481.                                                  sock,
  1482.                                                  (*tcp_con_data)->use_security,
  1483.                                                  tcp_con_data,
  1484.                                                  window_id,
  1485.                                                  error_msg,
  1486.                                                 0,
  1487.                                                 0));
  1488.                     /* else fall through to the error */
  1489.                 }
  1490.                 else
  1491.                     FREE(host);
  1492.  
  1493.                 if (error == PR_CONNECT_REFUSED_ERROR)
  1494.                     {
  1495.                             char * host = NET_ParseURL(url, GET_HOST_PART);
  1496.                             *error_msg = NET_ExplainErrorDetails(
  1497.                                                 MK_CONNECTION_REFUSED,
  1498.                                                 host);
  1499.                             FREE(host);
  1500.                             NET_FreeTCPConData(*tcp_con_data);
  1501.                             *tcp_con_data = 0;
  1502.                             return MK_CONNECTION_REFUSED;
  1503.                     }
  1504.                 else if (error == PR_CONNECT_TIMEOUT_ERROR)
  1505.                     {
  1506.                         NET_FreeTCPConData(*tcp_con_data);
  1507.                         *tcp_con_data = 0;
  1508.                         *error_msg = NET_ExplainErrorDetails(MK_CONNECTION_TIMED_OUT);
  1509.                         return MK_CONNECTION_TIMED_OUT;
  1510.                     }
  1511.                 else
  1512.                     {
  1513.                         NET_FreeTCPConData(*tcp_con_data);
  1514.                         *tcp_con_data = 0;
  1515.                         *error_msg = NET_ExplainErrorDetails(MK_UNABLE_TO_CONNECT, error);
  1516.                         return MK_UNABLE_TO_CONNECT;
  1517.                     }
  1518.               }
  1519.         }
  1520.     
  1521.         TRACEMSG(("mktcp.c: Successful connection (message 1)"));
  1522.         NET_FreeTCPConData(*tcp_con_data);
  1523.         *tcp_con_data = 0;
  1524.         return MK_CONNECTED;
  1525.     }
  1526.  
  1527.     default:
  1528.         NET_FreeTCPConData(*tcp_con_data);
  1529.         *tcp_con_data = 0;
  1530.         TRACEMSG(("mktcp.c: bad state during connect"));
  1531.  
  1532.         assert(0);  /* should never happen */
  1533.  
  1534.         *error_msg = NET_ExplainErrorDetails(MK_UNABLE_TO_CONNECT, 0);
  1535.         return(MK_UNABLE_TO_CONNECT);
  1536.  
  1537.     } /* end switch on next_state */
  1538.  
  1539.     XP_ASSERT(0);  /* should never get here */
  1540.  
  1541.     *error_msg = NET_ExplainErrorDetails(MK_UNABLE_TO_CONNECT, 0);
  1542.     return(MK_UNABLE_TO_CONNECT);
  1543. }
  1544.  
  1545.  
  1546. /* Free any memory used up
  1547.  */
  1548. MODULE_PRIVATE void
  1549. NET_CleanupTCP(void)
  1550. {
  1551.     if(dns_list)
  1552.       {
  1553.         DNSEntry * tmp_entry;
  1554.  
  1555.         while((tmp_entry = (DNSEntry *)XP_ListRemoveTopObject(dns_list)) != NULL)
  1556.           {
  1557.              NET_FreeDNSStruct(tmp_entry);
  1558.           }
  1559.  
  1560.         XP_ListDestroy(dns_list);
  1561.         dns_list = 0;
  1562.       }
  1563.  
  1564.     /* we really should free the socket_buffer but
  1565.      * that is in the other module as a private :(
  1566.      */
  1567.  
  1568.     FREE_AND_CLEAR(net_local_hostname);
  1569.  
  1570.     return;
  1571. }
  1572.