sockets.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:44k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * sockets.cxx
  3.  *
  4.  * Berkley sockets classes.
  5.  *
  6.  * Portable Windows Library
  7.  *
  8.  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
  9.  *
  10.  * The contents of this file are subject to the Mozilla Public License
  11.  * Version 1.0 (the "License"); you may not use this file except in
  12.  * compliance with the License. You may obtain a copy of the License at
  13.  * http://www.mozilla.org/MPL/
  14.  *
  15.  * Software distributed under the License is distributed on an "AS IS"
  16.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  17.  * the License for the specific language governing rights and limitations
  18.  * under the License.
  19.  *
  20.  * The Original Code is Portable Windows Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  25.  * All Rights Reserved.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: sockets.cxx,v $
  30.  * Revision 1.103  2000/06/26 11:17:21  robertj
  31.  * Nucleus++ port (incomplete).
  32.  *
  33.  * Revision 1.102  2000/06/21 01:01:22  robertj
  34.  * AIX port, thanks Wolfgang Platzer (wolfgang.platzer@infonova.at).
  35.  *
  36.  * Revision 1.101  2000/05/02 08:14:40  craigs
  37.  * Fixed problem with "memory leak" reporting under Unix
  38.  *
  39.  * Revision 1.100  2000/04/27 02:43:45  robertj
  40.  * Fixed warning about signedness mismatch.
  41.  *
  42.  * Revision 1.99  2000/04/19 00:13:52  robertj
  43.  * BeOS port changes.
  44.  *
  45.  * Revision 1.98  2000/02/18 09:55:21  robertj
  46.  * Added parameter so get/setsockopt can have other levels to SOL_SOCKET.
  47.  *
  48.  * Revision 1.97  1999/10/27 01:21:44  robertj
  49.  * Improved portability of copy from host_info struct to IP address.
  50.  *
  51.  * Revision 1.96  1999/08/30 02:21:03  robertj
  52.  * Added ability to listen to specific interfaces for IP sockets.
  53.  *
  54.  * Revision 1.95  1999/08/27 08:18:52  robertj
  55.  * Added ability to get the host/port of the the last packet read/written to UDP socket.
  56.  *
  57.  * Revision 1.94  1999/08/08 09:04:01  robertj
  58.  * Added operator>> for PIPSocket::Address class.
  59.  *
  60.  * Revision 1.93  1999/07/11 13:42:13  craigs
  61.  * pthreads support for Linux
  62.  *
  63.  * Revision 1.92  1999/06/01 08:04:35  robertj
  64.  * Fixed mistake from previous fix.
  65.  *
  66.  * Revision 1.91  1999/06/01 07:39:23  robertj
  67.  * Added retries to DNS lookup if get temporary error.
  68.  *
  69.  * Revision 1.90  1999/03/09 08:13:52  robertj
  70.  * Fixed race condition in doing Select() on closed sockets. Could go into infinite wait.
  71.  *
  72.  * Revision 1.89  1999/03/02 05:41:58  robertj
  73.  * More BeOS changes
  74.  *
  75.  * Revision 1.88  1999/02/26 04:10:39  robertj
  76.  * More BeOS port changes
  77.  *
  78.  * Revision 1.87  1999/02/25 03:43:35  robertj
  79.  * Fixed warning when PINDEX is unsigned.
  80.  *
  81.  * Revision 1.86  1999/02/23 07:19:22  robertj
  82.  * Added [] operator PIPSocket::Address to get the bytes out of an IP address.
  83.  *
  84.  * Revision 1.85  1999/02/16 08:08:06  robertj
  85.  * MSVC 6.0 compatibility changes.
  86.  *
  87.  * Revision 1.84  1999/01/08 01:29:47  robertj
  88.  * Support for pthreads under FreeBSD
  89.  *
  90.  * Revision 1.83  1999/01/06 10:58:01  robertj
  91.  * Fixed subtle mutex bug in returning string hostname from DNS cache.
  92.  *
  93.  * Revision 1.82  1998/12/22 10:25:01  robertj
  94.  * Added clone() function to support SOCKS in FTP style protocols.
  95.  * Fixed internal use of new operator in IP cache.
  96.  *
  97.  * Revision 1.81  1998/12/18 04:34:37  robertj
  98.  * PPC Linux GNU C compatibility.
  99.  *
  100.  * Revision 1.80  1998/11/30 04:47:52  robertj
  101.  * New directory structure
  102.  *
  103.  * Revision 1.79  1998/11/14 06:28:36  robertj
  104.  * Changed senatics of os_sendto to return TRUE if ANY bytes are sent.
  105.  *
  106.  * Revision 1.78  1998/11/08 12:05:04  robertj
  107.  * Fixed multiple thread access problem with DNS aliases array.
  108.  *
  109.  * Revision 1.77  1998/10/01 09:05:35  robertj
  110.  * Added check that port number is between 1 and 65535.
  111.  *
  112.  * Revision 1.76  1998/09/23 06:22:44  robertj
  113.  * Added open source copyright license.
  114.  *
  115.  * Revision 1.75  1998/08/31 13:00:34  robertj
  116.  * Prevented dependency on snmpapi.dll for all ptlib apps.
  117.  *
  118.  * Revision 1.74  1998/08/27 00:58:42  robertj
  119.  * Resolved signedness problems with various GNU libraries.
  120.  *
  121.  * Revision 1.73  1998/08/25 14:07:43  robertj
  122.  * Added getprotobyxxx wrapper functions.
  123.  *
  124.  * Revision 1.72  1998/08/25 11:09:20  robertj
  125.  * Fixed parsing of 802.x header on ethernet frames.
  126.  * Changed DNS cache to not cache temporary lookup failures, only an authoratative 'no such host'.
  127.  *
  128.  * Revision 1.71  1998/08/21 05:26:10  robertj
  129.  * Fixed bug where write streams out to non-stream socket.
  130.  * Added ethernet socket.
  131.  *
  132.  * Revision 1.70  1998/05/07 05:20:25  robertj
  133.  * Fixed DNS lookup so only works around bug in old Win95 and not OSR2
  134.  *
  135.  * Revision 1.69  1998/03/20 03:18:21  robertj
  136.  * Added special classes for specific sepahores, PMutex and PSyncPoint.
  137.  *
  138.  * Revision 1.68  1998/03/05 12:45:48  robertj
  139.  * DNS cache and NT bug fix attempts.
  140.  *
  141.  * Revision 1.67  1998/01/26 02:49:22  robertj
  142.  * GNU support.
  143.  *
  144.  * Revision 1.66  1998/01/26 00:49:28  robertj
  145.  * Fixed bug in detecting local host on NT, 95 bug kludge was interfering with it.
  146.  *
  147.  * Revision 1.65  1998/01/06 12:43:23  craigs
  148.  * Added definition of REENTRANT_BUFFER_LEN
  149.  *
  150.  * Revision 1.64  1998/01/04 07:25:09  robertj
  151.  * Added pthreads compatible calls for gethostbyx functions.
  152.  *
  153.  * Revision 1.63  1997/12/18 05:06:13  robertj
  154.  * Moved IsLocalHost() to platform dependent code.
  155.  *
  156.  * Revision 1.62  1997/12/11 10:30:35  robertj
  157.  * Added operators for IP address to DWORD conversions.
  158.  *
  159.  * Revision 1.61  1997/10/03 13:33:22  robertj
  160.  * Added workaround for NT winsock bug with RAS and DNS lookups.
  161.  *
  162.  * Revision 1.60  1997/09/27 00:58:39  robertj
  163.  * Fixed race condition on socket close in Select() function.
  164.  *
  165.  * Revision 1.59  1997/06/06 10:56:36  craigs
  166.  * Added new functions for connectionless UDP writes
  167.  *
  168.  * Revision 1.58  1997/01/04 07:42:18  robertj
  169.  * Fixed GCC Warnings.
  170.  *
  171.  * Revision 1.57  1997/01/04 06:54:38  robertj
  172.  * Added missing canonical name to alias list.
  173.  *
  174.  * Revision 1.56  1996/12/17 11:07:05  robertj
  175.  * Added clear of name cache.
  176.  *
  177.  * Revision 1.55  1996/12/12 09:23:27  robertj
  178.  * Fixed name cache to cache missing names as well.
  179.  * Fixed new connect with specific local port so can be re-used (simultaneous FTP session bug)
  180.  *
  181.  * Revision 1.54  1996/12/05 11:46:39  craigs
  182.  * Fixed problem with Win95 recvfrom not having timeouts
  183.  *
  184.  * Revision 1.53  1996/11/30 12:08:17  robertj
  185.  * Added Connect() variant so can set the local port number on link.
  186.  *
  187.  * Revision 1.52  1996/11/16 10:49:03  robertj
  188.  * Fixed missing const in PIPSocket::Address stream output operator..
  189.  *
  190.  * Revision 1.51  1996/11/16 01:43:49  craigs
  191.  * Fixed problem with ambiguous DNS cache keys
  192.  *
  193.  * Revision 1.50  1996/11/10 21:08:31  robertj
  194.  * Added host name caching.
  195.  *
  196.  * Revision 1.49  1996/11/04 03:40:22  robertj
  197.  * Moved address printer from inline to source.
  198.  *
  199.  * Revision 1.48  1996/10/26 01:41:09  robertj
  200.  * Compensated for Win'95 gethostbyaddr bug.
  201.  *
  202.  * Revision 1.47  1996/09/14 13:09:40  robertj
  203.  * Major upgrade:
  204.  *   rearranged sockets to help support IPX.
  205.  *   added indirect channel class and moved all protocols to descend from it,
  206.  *   separating the protocol from the low level byte transport.
  207.  *
  208.  * Revision 1.46  1996/08/25 09:33:32  robertj
  209.  * Added function to detect "local" host name.
  210.  *
  211.  * Revision 1.45  1996/07/30 12:24:53  robertj
  212.  * Fixed incorrect conditional stopping Select() from working.
  213.  *
  214.  * Revision 1.44  1996/07/27 04:10:35  robertj
  215.  * Changed Select() calls to return error codes.
  216.  *
  217.  * Revision 1.43  1996/06/10 09:58:21  robertj
  218.  * Fixed win95 compatibility with looking up zero address (got a response and shouldn't).
  219.  *
  220.  * Revision 1.42  1996/05/26 03:47:03  robertj
  221.  * Compatibility to GNU 2.7.x
  222.  *
  223.  * Revision 1.39  1996/04/29 12:20:01  robertj
  224.  * Fixed GetHostAliases() so doesn't overwrite names with IP numbers.
  225.  *
  226.  * Revision 1.38  1996/04/15 10:59:41  robertj
  227.  * Opened socket on UDP sockets so ReadFrom/WriteTo work when no Connect/Listen.
  228.  *
  229.  * Revision 1.37  1996/03/31 09:06:41  robertj
  230.  * Added socket shutdown function.
  231.  *
  232.  * Revision 1.35  1996/03/18 13:33:18  robertj
  233.  * Fixed incompatibilities to GNU compiler where PINDEX != int.
  234.  *
  235.  * Revision 1.34  1996/03/17 05:51:18  robertj
  236.  * Fixed strange bug in accept cant have NULL address.
  237.  *
  238.  * Revision 1.33  1996/03/16 04:52:20  robertj
  239.  * Changed all the get host name and get host address functions to be more consistent.
  240.  *
  241.  * Revision 1.32  1996/03/04 12:21:00  robertj
  242.  * Split file into telnet.cxx
  243.  *
  244.  * Revision 1.31  1996/03/03 07:38:45  robertj
  245.  * Added Reusability clause to the Listen() function on sockets.
  246.  *
  247.  * Revision 1.30  1996/03/02 03:25:13  robertj
  248.  * Added Capability to get and set Berkeley socket options.
  249.  *
  250.  * Revision 1.29  1996/02/25 11:30:08  robertj
  251.  * Changed Listen so can do a listen on a socket that is connected.
  252.  *
  253.  * Revision 1.28  1996/02/25 03:10:55  robertj
  254.  * Moved some socket functions to platform dependent code.
  255.  *
  256.  * Revision 1.27  1996/02/19 13:30:15  robertj
  257.  * Fixed bug in getting port by service name when specifying service by string number.
  258.  * Added SO_LINGER option to socket to stop data loss on close.
  259.  *
  260.  * Revision 1.26  1996/02/15 14:46:44  robertj
  261.  * Added Select() function to PSocket.
  262.  *
  263.  * Revision 1.25  1996/02/13 13:08:09  robertj
  264.  * Fixed usage of sock_addr structure, not being cleared correctly.
  265.  *
  266.  * Revision 1.24  1996/02/08 12:27:22  robertj
  267.  * Added function to get peer port as well as IP number..
  268.  *
  269.  * Revision 1.23  1996/02/03 11:07:37  robertj
  270.  * Fixed buf in assuring error when converting string to IP number and string is empty.
  271.  *
  272.  * Revision 1.22  1996/01/28 14:08:13  robertj
  273.  * Changed service parameter to PString for ease of use in GetPortByService function
  274.  * Fixed up comments.
  275.  * Added default value in string for service name.
  276.  *
  277.  * Revision 1.21  1996/01/23 13:19:13  robertj
  278.  * Moved Accept() function to platform dependent code.
  279.  *
  280.  * Revision 1.20  1995/12/23 03:42:53  robertj
  281.  * Unix portability issues.
  282.  *
  283.  * Revision 1.19  1995/12/10 11:42:23  robertj
  284.  * Numerous fixes for sockets.
  285.  *
  286.  * Revision 1.18  1995/10/14 15:11:31  robertj
  287.  * Added internet address to string conversion functionality.
  288.  *
  289.  * Revision 1.17  1995/07/02 01:21:23  robertj
  290.  * Added static functions to get the current host name/address.
  291.  *
  292.  * Revision 1.16  1995/06/17 00:47:01  robertj
  293.  * Changed overloaded Open() calls to 3 separate function names.
  294.  * More logical design of port numbers and service names.
  295.  *
  296.  * Revision 1.15  1995/06/04 12:45:33  robertj
  297.  * Added application layer protocol sockets.
  298.  * Slight redesign of port numbers on sockets.
  299.  *
  300.  * Revision 1.14  1995/04/25 11:12:44  robertj
  301.  * Fixed functions hiding ancestor virtuals.
  302.  *
  303.  * Revision 1.13  1995/04/01 08:31:54  robertj
  304.  * Finally got a working TELNET.
  305.  *
  306.  * Revision 1.12  1995/03/18 06:27:49  robertj
  307.  * Rewrite of telnet socket protocol according to RFC1143.
  308.  *
  309.  * Revision 1.11  1995/03/12  04:46:29  robertj
  310.  * Added more functionality.
  311.  *
  312.  * Revision 1.10  1995/02/21  11:25:29  robertj
  313.  * Further implementation of telnet socket, feature complete now.
  314.  *
  315.  * Revision 1.9  1995/01/27  11:16:16  robertj
  316.  * Fixed missing cast in function, required by some platforms.
  317.  *
  318.  * Revision 1.8  1995/01/15  04:55:47  robertj
  319.  * Moved all Berkley socket functions inside #ifdef.
  320.  *
  321.  * Revision 1.7  1995/01/04  10:57:08  robertj
  322.  * Changed for HPUX and GNU2.6.x
  323.  *
  324.  * Revision 1.6  1995/01/03  09:37:52  robertj
  325.  * Added constructor to open TCP socket.
  326.  *
  327.  * Revision 1.5  1995/01/02  12:28:25  robertj
  328.  * Documentation.
  329.  * Added more socket functions.
  330.  *
  331.  * Revision 1.4  1995/01/01  01:06:58  robertj
  332.  * More implementation.
  333.  *
  334.  * Revision 1.3  1994/11/28  12:38:49  robertj
  335.  * Added DONT and WONT states.
  336.  *
  337.  * Revision 1.2  1994/08/21  23:43:02  robertj
  338.  * Some implementation.
  339.  *
  340.  * Revision 1.1  1994/08/01  03:39:05  robertj
  341.  * Initial revision
  342.  *
  343.  */
  344. #ifdef __NUCLEUS_PLUS__
  345. #include <ConfigurationClass.h>
  346. #endif
  347. #include <ptlib.h>
  348. #include <ptlib/sockets.h>
  349. #include <ctype.h>
  350. #if (defined(_WIN32) || defined(WINDOWS)) && !defined(__NUCLEUS_MNT__)
  351. static PWinSock dummyForWinSock; // Assure winsock is initialised
  352. #endif
  353. #if (defined(P_PTHREADS) && !defined(P_THREAD_SAFE_CLIB)) || defined(__NUCLEUS_PLUS__)
  354. #define REENTRANT_BUFFER_LEN 1024
  355. #endif
  356. class PIPCacheData : public PObject
  357. {
  358.   PCLASSINFO(PIPCacheData, PObject)
  359.   public:
  360.     PIPCacheData(struct hostent * ent, const char * original);
  361.     const PString & GetHostName() const { return hostname; }
  362.     const PIPSocket::Address & GetHostAddress() const { return address; }
  363.     const PStringList & GetHostAliases() const { return aliases; }
  364.     BOOL HasAged() const;
  365.   private:
  366.     PString            hostname;
  367.     PIPSocket::Address address;
  368.     PStringList        aliases;
  369.     PTime              birthDate;
  370. };
  371. PDICTIONARY(PHostByName_private, PCaselessString, PIPCacheData);
  372. class PHostByName : PHostByName_private
  373. {
  374.   public:
  375.     BOOL GetHostName(const PString & name, PString & hostname);
  376.     BOOL GetHostAddress(const PString & name, PIPSocket::Address & address);
  377.     BOOL GetHostAliases(const PString & name, PStringArray & aliases);
  378.   private:
  379.     PIPCacheData * GetHost(const PString & name);
  380.     PMutex mutex;
  381.   friend void PIPSocket::ClearNameCache();
  382. };
  383. static PHostByName & pHostByName()
  384. {
  385.   static PHostByName t;
  386.   return t;
  387. }
  388. class PIPCacheKey : public PObject
  389. {
  390.   PCLASSINFO(PIPCacheKey, PObject)
  391.   public:
  392.     PIPCacheKey(const PIPSocket::Address & a)
  393.       { addr = a; }
  394.     PObject * Clone() const
  395.       { return new PIPCacheKey(*this); }
  396.     PINDEX HashFunction() const
  397.       { return (addr.Byte2() + addr.Byte3() + addr.Byte4())%41; }
  398.   private:
  399.     PIPSocket::Address addr;
  400. };
  401. PDICTIONARY(PHostByAddr_private, PIPCacheKey, PIPCacheData);
  402. class PHostByAddr : PHostByAddr_private
  403. {
  404.   public:
  405.     BOOL GetHostName(const PIPSocket::Address & addr, PString & hostname);
  406.     BOOL GetHostAddress(const PIPSocket::Address & addr, PIPSocket::Address & address);
  407.     BOOL GetHostAliases(const PIPSocket::Address & addr, PStringArray & aliases);
  408.   private:
  409.     PIPCacheData * GetHost(const PIPSocket::Address & addr);
  410.     PMutex mutex;
  411.   friend void PIPSocket::ClearNameCache();
  412. };
  413. static PHostByAddr & pHostByAddr()
  414. {
  415.   static PHostByAddr t;
  416.   return t;
  417. }
  418. #define new PNEW
  419. //////////////////////////////////////////////////////////////////////////////
  420. // IP Caching
  421. PIPCacheData::PIPCacheData(struct hostent * host_info, const char * original)
  422. {
  423.   if (host_info == NULL) {
  424.     address.s_addr = 0;
  425.     return;
  426.   }
  427.   hostname = host_info->h_name;
  428.   address = *(DWORD *)host_info->h_addr;
  429.   aliases.AppendString(host_info->h_name);
  430.   PINDEX i;
  431.   for (i = 0; host_info->h_aliases[i] != NULL; i++)
  432.     aliases.AppendString(host_info->h_aliases[i]);
  433.   for (i = 0; host_info->h_addr_list[i] != NULL; i++)
  434.     aliases.AppendString(inet_ntoa(*(struct in_addr *)host_info->h_addr_list[i]));
  435.   for (i = 0; i < aliases.GetSize(); i++)
  436.     if (aliases[i] *= original)
  437.       return;
  438.   aliases.AppendString(original);
  439. }
  440. static PTimeInterval GetConfigTime(const char * key, DWORD dflt)
  441. {
  442.   PConfig cfg("DNS Cache");
  443.   return cfg.GetInteger(key, dflt);
  444. }
  445. BOOL PIPCacheData::HasAged() const
  446. {
  447.   static PTimeInterval retirement = GetConfigTime("Age Limit", 300000); // 5 minutes
  448.   PTime now;
  449.   PTimeInterval age = now - birthDate;
  450.   return age > retirement;
  451. }
  452. BOOL PHostByName::GetHostName(const PString & name, PString & hostname)
  453. {
  454.   PIPCacheData * host = GetHost(name);
  455.   if (host != NULL) {
  456.     hostname = host->GetHostName();
  457.     hostname.MakeUnique();
  458.   }
  459.   mutex.Signal();
  460.   return host != NULL;
  461. }
  462. BOOL PHostByName::GetHostAddress(const PString & name, PIPSocket::Address & address)
  463. {
  464.   PIPCacheData * host = GetHost(name);
  465.   if (host != NULL)
  466.     address = host->GetHostAddress();
  467.   mutex.Signal();
  468.   return host != NULL;
  469. }
  470. BOOL PHostByName::GetHostAliases(const PString & name, PStringArray & aliases)
  471. {
  472.   PIPCacheData * host = GetHost(name);
  473.   if (host != NULL) {
  474.     const PStringList & a = host->GetHostAliases();
  475.     aliases.SetSize(a.GetSize());
  476.     for (PINDEX i = 0; i < a.GetSize(); i++)
  477.       aliases[i] = a[i];
  478.   }
  479.   mutex.Signal();
  480.   return host != NULL;
  481. }
  482. PIPCacheData * PHostByName::GetHost(const PString & name)
  483. {
  484.   mutex.Wait();
  485.   PCaselessString key = name;
  486.   PIPCacheData * host = GetAt(key);
  487.   if (host != NULL && host->HasAged()) {
  488.     SetAt(key, NULL);
  489.     host = NULL;
  490.   }
  491.   if (host == NULL) {
  492.     mutex.Signal();
  493. #ifdef P_AIX
  494.     struct hostent_data ht_data;
  495.     memset(&ht_data, 0, sizeof(ht_data)); 
  496.     struct hostent host_info;
  497. #else
  498.     struct hostent * host_info;
  499. #endif
  500.     int retry = 3;
  501.     do {
  502. #if ( ( defined(P_PTHREADS) && !defined(P_THREAD_SAFE_CLIB) ) || (defined(__NUCLEUS_PLUS__) ) )
  503.       // this function should really be a static on PIPSocket, but this would
  504.       // require allocating thread-local storage for the data and that's too much
  505.       // of a pain!
  506. #ifndef P_AIX // that I get no warnings
  507.       int localErrNo;
  508.       char buffer[REENTRANT_BUFFER_LEN];
  509.       struct hostent hostEnt;
  510. #endif
  511. #ifdef P_LINUX
  512.       ::gethostbyname_r(name,
  513.                         &hostEnt,
  514.                         buffer, REENTRANT_BUFFER_LEN,
  515.                         &host_info,
  516.                &localErrNo);
  517.                       
  518.                
  519. #elif defined P_AIX
  520.       ::gethostbyname_r(name,
  521.                         &host_info,
  522.                         &ht_data);     
  523. #else
  524.       host_info = ::gethostbyname_r(name,
  525.  &hostEnt, buffer, REENTRANT_BUFFER_LEN,
  526.  &localErrNo);
  527. #endif
  528. #else
  529.       host_info = ::gethostbyname(name);
  530. #endif
  531.     } while (h_errno == TRY_AGAIN && --retry > 0);
  532.     mutex.Wait();
  533.     if (retry == 0)
  534.       return NULL;
  535. #ifdef P_AIX
  536.     host = new PIPCacheData (&host_info, (const char*) name);
  537. #else
  538.     host = new PIPCacheData(host_info, name);
  539. #endif
  540.     SetAt(key, host);
  541.   }
  542.   if (host->GetHostAddress() == 0)
  543.     return NULL;
  544.   return host;
  545. }
  546. BOOL PHostByAddr::GetHostName(const PIPSocket::Address & addr, PString & hostname)
  547. {
  548.   PIPCacheData * host = GetHost(addr);
  549.   if (host != NULL) {
  550.     hostname = host->GetHostName();
  551.     hostname.MakeUnique();
  552.   }
  553.   mutex.Signal();
  554.   return host != NULL;
  555. }
  556. BOOL PHostByAddr::GetHostAddress(const PIPSocket::Address & addr, PIPSocket::Address & address)
  557. {
  558.   PIPCacheData * host = GetHost(addr);
  559.   if (host != NULL)
  560.     address = host->GetHostAddress();
  561.   mutex.Signal();
  562.   return host != NULL;
  563. }
  564. BOOL PHostByAddr::GetHostAliases(const PIPSocket::Address & addr, PStringArray & aliases)
  565. {
  566.   PIPCacheData * host = GetHost(addr);
  567.   if (host != NULL) {
  568.     const PStringList & a = host->GetHostAliases();
  569.     aliases.SetSize(a.GetSize());
  570.     for (PINDEX i = 0; i < a.GetSize(); i++)
  571.       aliases[i] = a[i];
  572.   }
  573.   mutex.Signal();
  574.   return host != NULL;
  575. }
  576. PIPCacheData * PHostByAddr::GetHost(const PIPSocket::Address & addr)
  577. {
  578.   mutex.Wait();
  579.   PIPCacheKey key = addr;
  580.   PIPCacheData * host = GetAt(key);
  581.   if (host != NULL && host->HasAged()) {
  582.     SetAt(key, NULL);
  583.     host = NULL;
  584.   }
  585.   if (host == NULL) {
  586.     mutex.Signal();
  587. #ifdef P_AIX
  588.     struct hostent_data ht_data;
  589.     struct hostent host_info;
  590. #else    
  591.     struct hostent * host_info;
  592. #endif
  593.     int retry = 3;
  594.     do {
  595. #if ( ( defined(P_PTHREADS) && !defined(P_THREAD_SAFE_CLIB) ) || ( defined(__NUCLEUS_PLUS__) ) )
  596.       // this function should really be a static on PIPSocket, but this would
  597.       // require allocating thread-local storage for the data and that's too much
  598.       // of a pain!
  599.       
  600. #ifndef P_AIX // that I get no warnings
  601.       int localErrNo;
  602.       char buffer[REENTRANT_BUFFER_LEN];
  603.       struct hostent hostEnt;
  604. #endif
  605. #ifdef P_LINUX
  606.       ::gethostbyaddr_r((const char *)&addr, sizeof(addr),
  607.                         PF_INET, 
  608.                         &hostEnt,
  609.                         buffer, REENTRANT_BUFFER_LEN,
  610.                         &host_info,
  611.                         &localErrNo);
  612. #elif P_AIX
  613.       ::gethostbyaddr_r((char *)&addr, sizeof(addr),
  614.                         PF_INET, 
  615.                         &host_info,
  616.                         &ht_data );
  617. #else
  618.       host_info = ::gethostbyaddr_r((const char *)&addr, sizeof(addr), PF_INET, 
  619.                                     &hostEnt, buffer, REENTRANT_BUFFER_LEN, &localErrNo);
  620. #endif
  621. #else
  622.       host_info = ::gethostbyaddr((const char *)&addr, sizeof(addr), PF_INET);
  623. #if defined(_WIN32) || defined(WINDOWS)  // Kludge to avoid strange 95 bug
  624.       extern P_IsOldWin95();
  625.       if (P_IsOldWin95() && host_info != NULL && host_info->h_addr_list[0] != NULL)
  626.         host_info->h_addr_list[1] = NULL;
  627. #endif
  628. #endif
  629.     } while (h_errno == TRY_AGAIN && --retry > 0);
  630.     mutex.Wait();
  631.     if (retry == 0)
  632.       return FALSE;
  633. #ifdef P_AIX
  634.     host = new PIPCacheData(&host_info, inet_ntoa(addr));
  635. #else
  636.     host = new PIPCacheData(host_info, inet_ntoa(addr));
  637. #endif
  638.     SetAt(key, host);
  639.   }
  640.   if (host->GetHostAddress() == 0)
  641.     return NULL;
  642.   return host;
  643. }
  644. //////////////////////////////////////////////////////////////////////////////
  645. // PSocket
  646. PSocket::PSocket()
  647. {
  648.   port = 0;
  649. }
  650. BOOL PSocket::Connect(const PString &)
  651. {
  652.   PAssertAlways("Illegal operation.");
  653.   return FALSE;
  654. }
  655. BOOL PSocket::Listen(unsigned, WORD, Reusability)
  656. {
  657.   PAssertAlways("Illegal operation.");
  658.   return FALSE;
  659. }
  660. BOOL PSocket::Accept(PSocket &)
  661. {
  662.   PAssertAlways("Illegal operation.");
  663.   return FALSE;
  664. }
  665. BOOL PSocket::SetOption(int option, int value, int level)
  666. {
  667.   return ConvertOSError(::setsockopt(os_handle, level, option,
  668.                                      (char *)&value, sizeof(value)));
  669. }
  670. BOOL PSocket::SetOption(int option, const void * valuePtr, PINDEX valueSize, int level)
  671. {
  672.   return ConvertOSError(::setsockopt(os_handle, level, option,
  673.                                      (char *)valuePtr, valueSize));
  674. }
  675. BOOL PSocket::GetOption(int option, int & value, int level)
  676. {
  677. #ifdef __BEOS__
  678.   return FALSE;
  679. #else
  680.   socklen_t valSize = sizeof(value);
  681.   return ConvertOSError(::getsockopt(os_handle, level, option,
  682.                                      (char *)&value, &valSize));
  683. #endif
  684. }
  685. BOOL PSocket::GetOption(int option, void * valuePtr, PINDEX valueSize, int level)
  686. {
  687. #ifdef __BEOS__
  688.   return FALSE;
  689. #else
  690.   return ConvertOSError(::getsockopt(os_handle, level, option,
  691.                                      (char *)valuePtr, (socklen_t *)&valueSize));
  692. #endif
  693. }
  694. BOOL PSocket::Shutdown(ShutdownValue value)
  695. {
  696.   return ConvertOSError(::shutdown(os_handle, value));
  697. }
  698. WORD PSocket::GetProtocolByName(const PString & name)
  699. {
  700. #if !defined(__BEOS__) && !defined(__NUCLEUS_PLUS__)
  701.   struct protoent * ent = getprotobyname(name);
  702.   if (ent != NULL)
  703.     return ent->p_proto;
  704. #endif
  705.   return 0;
  706. }
  707. PString PSocket::GetNameByProtocol(WORD proto)
  708. {
  709. #if !defined(__BEOS__) && !defined(__NUCLEUS_PLUS__)
  710.   struct protoent * ent = getprotobynumber(proto);
  711.   if (ent != NULL)
  712.     return ent->p_name;
  713. #endif
  714.   return psprintf("%u", proto);
  715. }
  716. WORD PSocket::GetPortByService(const PString & serviceName) const
  717. {
  718.   return GetPortByService(GetProtocolName(), serviceName);
  719. }
  720. WORD PSocket::GetPortByService(const char * protocol, const PString & service)
  721. {
  722. #ifdef __NUCLEUS_PLUS__
  723.   if(!strcmp(protocol,"tcp") && service.AsInteger()>0) return service.AsInteger();
  724.   PAssertAlways
  725.   ("PSocket::GetPortByService: problem as no ::getservbyname in Nucleus NET");
  726.   return 0;
  727. #else
  728.   PINDEX space = service.FindOneOf(" trn");
  729.   struct servent * serv = ::getservbyname(service(0, space-1), protocol);
  730.   if (serv != NULL)
  731.     return ntohs(serv->s_port);
  732.   long portNum;
  733.   if (space != P_MAX_INDEX)
  734.     portNum = atol(service(space+1, P_MAX_INDEX));
  735.   else if (isdigit(service[0]))
  736.     portNum = atoi(service);
  737.   else
  738.     portNum = -1;
  739.   if (portNum < 0 || portNum > 65535)
  740.     return 0;
  741.   return (WORD)portNum;
  742. #endif
  743. }
  744. PString PSocket::GetServiceByPort(WORD port) const
  745. {
  746.   return GetServiceByPort(GetProtocolName(), port);
  747. }
  748. PString PSocket::GetServiceByPort(const char * protocol, WORD port)
  749. {
  750. #if !defined(__BEOS__) && !defined(__NUCLEUS_PLUS__)
  751.   struct servent * serv = ::getservbyport(htons(port), protocol);
  752.   if (serv != NULL)
  753.     return PString(serv->s_name);
  754.   else
  755. #endif
  756.     return PString(PString::Unsigned, port);
  757. }
  758. void PSocket::SetPort(WORD newPort)
  759. {
  760.   PAssert(!IsOpen(), "Cannot change port number of opened socket");
  761.   port = newPort;
  762. }
  763. void PSocket::SetPort(const PString & service)
  764. {
  765.   PAssert(!IsOpen(), "Cannot change port number of opened socket");
  766.   port = GetPortByService(service);
  767. }
  768. WORD PSocket::GetPort() const
  769. {
  770.   return port;
  771. }
  772. PString PSocket::GetService() const
  773. {
  774.   return GetServiceByPort(port);
  775. }
  776. int PSocket::Select(PSocket & sock1, PSocket & sock2)
  777. {
  778.   return Select(sock1, sock2, PMaxTimeInterval);
  779. }
  780. int PSocket::Select(PSocket & sock1,
  781.                     PSocket & sock2,
  782.                     const PTimeInterval & timeout)
  783. {
  784.   if (!sock1.IsOpen() || !sock2.IsOpen())
  785.     return NotOpen;
  786.   int h1 = sock1.GetHandle();
  787.   int h2 = sock2.GetHandle();
  788. #ifdef _MSC_VER
  789. #pragma warning(disable:4127)
  790. #endif
  791.   fd_set readfds;
  792.   FD_ZERO(&readfds);
  793.   FD_SET(h1, &readfds);
  794.   FD_SET(h2, &readfds);
  795.   fd_set writefds;
  796.   FD_ZERO(&writefds);
  797.   fd_set exceptfds;
  798.   FD_ZERO(&exceptfds);
  799. #ifdef _MSC_VER
  800. #pragma warning(default:4127)
  801. #endif
  802.   PIntArray allfds(4);
  803.   allfds[0] = h1;
  804.   allfds[1] = 1;
  805.   allfds[2] = h2;
  806.   allfds[3] = 1;
  807.   int rval = os_select(PMAX(h1, h2)+1,
  808.                                 readfds, writefds, exceptfds, allfds, timeout);
  809.   Errors lastError;
  810.   int osError;
  811.   if (!ConvertOSError(rval, lastError, osError))
  812.     return lastError;
  813.   rval = 0;
  814.   if (FD_ISSET(h1, &readfds))
  815.     rval -= 1;
  816.   if (FD_ISSET(h2, &readfds))
  817.     rval -= 2;
  818.   return rval;
  819. }
  820. PChannel::Errors PSocket::Select(SelectList & read)
  821. {
  822.   SelectList dummy1, dummy2;
  823.   return Select(read, dummy1, dummy2, PMaxTimeInterval);
  824. }
  825. PChannel::Errors PSocket::Select(SelectList & read, const PTimeInterval & timeout)
  826. {
  827.   SelectList dummy1, dummy2;
  828.   return Select(read, dummy1, dummy2, timeout);
  829. }
  830. PChannel::Errors PSocket::Select(SelectList & read, SelectList & write)
  831. {
  832.   SelectList dummy1;
  833.   return Select(read, write, dummy1, PMaxTimeInterval);
  834. }
  835. PChannel::Errors PSocket::Select(SelectList & read,
  836.                                  SelectList & write,
  837.                                  const PTimeInterval & timeout)
  838. {
  839.   SelectList dummy1;
  840.   return Select(read, write, dummy1, timeout);
  841. }
  842. PChannel::Errors PSocket::Select(SelectList & read,
  843.                                  SelectList & write,
  844.                                  SelectList & except)
  845. {
  846.   return Select(read, write, except, PMaxTimeInterval);
  847. }
  848. PChannel::Errors PSocket::Select(SelectList & read,
  849.                                  SelectList & write,
  850.                                  SelectList & except,
  851.                                  const PTimeInterval & timeout)
  852. {
  853.   int maxfds = 0;
  854.   PINDEX nextfd = 0;
  855.   PIntArray allfds(2*(read.GetSize()+write.GetSize()+except.GetSize()));
  856. #ifdef _MSC_VER
  857. #pragma warning(disable:4127)
  858. #endif
  859.   fd_set readfds;
  860.   FD_ZERO(&readfds);
  861.   PINDEX i;
  862.   for (i = 0; i < read.GetSize(); i++) {
  863.     if (!read[i].IsOpen())
  864.       return NotOpen;
  865.     int h = read[i].GetHandle();
  866.     FD_SET(h, &readfds);
  867.     if (h > maxfds)
  868.       maxfds = h;
  869.     allfds[nextfd++] = h;
  870.     allfds[nextfd++] = 1;
  871.   }
  872.   fd_set writefds;
  873.   FD_ZERO(&writefds);
  874.   for (i = 0; i < write.GetSize(); i++) {
  875.     if (!write[i].IsOpen())
  876.       return NotOpen;
  877.     int h = write[i].GetHandle();
  878.     FD_SET(h, &writefds);
  879.     if (h > maxfds)
  880.       maxfds = h;
  881.     allfds[nextfd++] = h;
  882.     allfds[nextfd++] = 2;
  883.   }
  884.   fd_set exceptfds;
  885.   FD_ZERO(&exceptfds);
  886.   for (i = 0; i < except.GetSize(); i++) {
  887.     if (!except[i].IsOpen())
  888.       return NotOpen;
  889.     int h = except[i].GetHandle();
  890.     FD_SET(h, &exceptfds);
  891.     if (h > maxfds)
  892.       maxfds = h;
  893.     allfds[nextfd++] = h;
  894.     allfds[nextfd++] = 4;
  895.   }
  896. #ifdef _MSC_VER
  897. #pragma warning(default:4127)
  898. #endif
  899.   int retval = os_select(maxfds+1,readfds,writefds,exceptfds,allfds,timeout);
  900.   Errors lastError;
  901.   int osError;
  902.   if (!ConvertOSError(retval, lastError, osError))
  903.     return lastError;
  904.   if (retval > 0) {
  905.     for (i = 0; i < read.GetSize(); i++) {
  906.       int h = read[i].GetHandle();
  907.       if (h < 0)
  908.         return Interrupted;
  909.       if (!FD_ISSET(h, &readfds))
  910.         read.RemoveAt(i--);
  911.     }
  912.     for (i = 0; i < write.GetSize(); i++) {
  913.       int h = write[i].GetHandle();
  914.       if (h < 0)
  915.         return Interrupted;
  916.       if (!FD_ISSET(h, &writefds))
  917.         write.RemoveAt(i--);
  918.     }
  919.     for (i = 0; i < except.GetSize(); i++) {
  920.       int h = except[i].GetHandle();
  921.       if (h < 0)
  922.         return Interrupted;
  923.       if (!FD_ISSET(h, &exceptfds))
  924.         except.RemoveAt(i--);
  925.     }
  926.   }
  927.   else {
  928.     read.RemoveAll();
  929.     write.RemoveAll();
  930.     except.RemoveAll();
  931.   }
  932.   return NoError;
  933. }
  934. //////////////////////////////////////////////////////////////////////////////
  935. // PIPSocket
  936. PIPSocket::PIPSocket()
  937. {
  938. }
  939. void PIPSocket::ClearNameCache()
  940. {
  941.   pHostByName().mutex.Wait();
  942.   pHostByAddr().mutex.Wait();
  943.   pHostByName().RemoveAll();
  944.   pHostByAddr().RemoveAll();
  945. #if (defined(_WIN32) || defined(WINDOWS)) && !defined(__NUCLEUS_MNT__) // Kludge to avoid strange NT bug
  946.   static PTimeInterval delay = GetConfigTime("NT Bug Delay", 0);
  947.   if (delay != 0) {
  948.     ::Sleep(delay.GetInterval());
  949.     ::gethostbyname("www.microsoft.com");
  950.   }
  951. #endif
  952.   pHostByName().mutex.Signal();
  953.   pHostByAddr().mutex.Signal();
  954. }
  955. PString PIPSocket::GetName() const
  956. {
  957.   PString name;
  958.   sockaddr_in address;
  959.   socklen_t size = sizeof(address);
  960.   if (getpeername(os_handle, (struct sockaddr *)&address, &size) == 0)
  961.     name = GetHostName(address.sin_addr) + psprintf(":%u", ntohs(address.sin_port));
  962.   return name;
  963. }
  964. PString PIPSocket::GetHostName()
  965. {
  966.   char name[100];
  967.   if (gethostname(name, sizeof(name)-1) != 0)
  968.     return "localhost";
  969.   name[sizeof(name)-1] = '';
  970.   return name;
  971. }
  972. PString PIPSocket::GetHostName(const PString & hostname)
  973. {
  974.   // lookup the host address using inet_addr, assuming it is a "." address
  975.   Address temp = hostname;
  976.   if (temp != 0)
  977.     return GetHostName(temp);
  978.   PString canonicalname;
  979.   if (pHostByName().GetHostName(hostname, canonicalname))
  980.     return canonicalname;
  981.   return hostname;
  982. }
  983. PString PIPSocket::GetHostName(const Address & addr)
  984. {
  985.   if (addr == 0)
  986.     return addr;
  987.   PString hostname;
  988.   if (pHostByAddr().GetHostName(addr, hostname))
  989.     return hostname;
  990.   return addr;
  991. }
  992. BOOL PIPSocket::GetHostAddress(Address & addr)
  993. {
  994.   return pHostByName().GetHostAddress(GetHostName(), addr);
  995. }
  996. BOOL PIPSocket::GetHostAddress(const PString & hostname, Address & addr)
  997. {
  998.   if (hostname.IsEmpty())
  999.     return FALSE;
  1000.   // lookup the host address using inet_addr, assuming it is a "." address
  1001.   addr = hostname;
  1002.   if (addr != 0)
  1003.     return TRUE;
  1004.   // otherwise lookup the name as a host name
  1005.   return pHostByName().GetHostAddress(hostname, addr);
  1006. }
  1007. PStringArray PIPSocket::GetHostAliases(const PString & hostname)
  1008. {
  1009.   PStringArray aliases;
  1010.   // lookup the host address using inet_addr, assuming it is a "." address
  1011.   Address addr = hostname;
  1012.   if (addr != 0)
  1013.     pHostByAddr().GetHostAliases(addr, aliases);
  1014.   else
  1015.     pHostByName().GetHostAliases(hostname, aliases);
  1016.   return aliases;
  1017. }
  1018. PStringArray PIPSocket::GetHostAliases(const Address & addr)
  1019. {
  1020.   PStringArray aliases;
  1021.   pHostByAddr().GetHostAliases(addr, aliases);
  1022.   return aliases;
  1023. }
  1024. BOOL PIPSocket::GetLocalAddress(Address & addr)
  1025. {
  1026.   sockaddr_in address;
  1027.   socklen_t size = sizeof(address);
  1028.   if (!ConvertOSError(::getsockname(os_handle,(struct sockaddr*)&address,&size)))
  1029.     return FALSE;
  1030.   addr = address.sin_addr;
  1031.   return TRUE;
  1032. }
  1033. BOOL PIPSocket::GetLocalAddress(Address & addr, WORD & portNum)
  1034. {
  1035.   sockaddr_in address;
  1036.   socklen_t size = sizeof(address);
  1037.   if (!ConvertOSError(::getsockname(os_handle,(struct sockaddr*)&address,&size)))
  1038.     return FALSE;
  1039.   addr = address.sin_addr;
  1040.   portNum = ntohs(address.sin_port);
  1041.   return TRUE;
  1042. }
  1043.  
  1044. BOOL PIPSocket::GetPeerAddress(Address & addr)
  1045. {
  1046.   sockaddr_in address;
  1047.   socklen_t size = sizeof(address);
  1048.   if (!ConvertOSError(::getpeername(os_handle,(struct sockaddr*)&address,&size)))
  1049.     return FALSE;
  1050.   addr = address.sin_addr;
  1051.   return TRUE;
  1052. }
  1053. BOOL PIPSocket::GetPeerAddress(Address & addr, WORD & portNum)
  1054. {
  1055.   sockaddr_in address;
  1056.   socklen_t size = sizeof(address);
  1057.   if (!ConvertOSError(::getpeername(os_handle,(struct sockaddr*)&address,&size)))
  1058.     return FALSE;
  1059.   addr = address.sin_addr;
  1060.   portNum = ntohs(address.sin_port);
  1061.   return TRUE;
  1062. }
  1063. PString PIPSocket::GetLocalHostName()
  1064. {
  1065.   PString name;
  1066.   sockaddr_in address;
  1067.   socklen_t size = sizeof(address);
  1068.   if (ConvertOSError(::getsockname(os_handle, (struct sockaddr *)&address, &size)))
  1069.     name = GetHostName(address.sin_addr);
  1070.   return name;
  1071. }
  1072. PString PIPSocket::GetPeerHostName()
  1073. {
  1074.   PString name;
  1075.   sockaddr_in address;
  1076.   socklen_t size = sizeof(address);
  1077.   if (ConvertOSError(::getpeername(os_handle, (struct sockaddr *)&address, &size)))
  1078.     name = GetHostName(address.sin_addr);
  1079.   return name;
  1080. }
  1081. BOOL PIPSocket::Connect(const PString & host)
  1082. {
  1083.   Address ipnum;
  1084.   if (GetHostAddress(host, ipnum))
  1085.     return Connect(ipnum);
  1086.   return FALSE;
  1087. }
  1088. BOOL PIPSocket::Connect(const Address & addr)
  1089. {
  1090.   return Connect(0, addr);
  1091. }
  1092. BOOL PIPSocket::Connect(WORD localPort, const Address & addr)
  1093. {
  1094.   // close the port if it is already open
  1095.   if (IsOpen())
  1096.     Close();
  1097.   // make sure we have a port
  1098.   PAssert(port != 0, "Cannot connect socket without setting port");
  1099.   // attempt to create a socket
  1100.   if (!OpenSocket())
  1101.     return FALSE;
  1102.   // attempt to connect
  1103.   sockaddr_in sin;
  1104.   if (localPort != 0) {
  1105.     if (!SetOption(SO_REUSEADDR, 1)) {
  1106.       os_close();
  1107.       return FALSE;
  1108.     }
  1109.     memset(&sin, 0, sizeof(sin));
  1110.     sin.sin_family = AF_INET;
  1111.     sin.sin_addr.s_addr = htonl(INADDR_ANY);
  1112.     sin.sin_port        = htons(localPort);       // set the port
  1113.     if (!ConvertOSError(::bind(os_handle, (struct sockaddr*)&sin, sizeof(sin)))) {
  1114.       os_close();
  1115.       return FALSE;
  1116.     }
  1117.   }
  1118.   memset(&sin, 0, sizeof(sin));
  1119.   sin.sin_family = AF_INET;
  1120.   sin.sin_port   = htons(port);  // set the port
  1121.   sin.sin_addr   = addr;
  1122.   if (ConvertOSError(os_connect((struct sockaddr *)&sin, sizeof(sin))))
  1123.     return TRUE;
  1124.   os_close();
  1125.   return FALSE;
  1126. }
  1127. BOOL PIPSocket::Listen(unsigned queueSize, WORD newPort, Reusability reuse)
  1128. {
  1129.   return Listen(INADDR_ANY, queueSize, newPort, reuse);
  1130. }
  1131. BOOL PIPSocket::Listen(const Address & bindAddr,
  1132.                        unsigned,
  1133.                        WORD newPort,
  1134.                        Reusability reuse)
  1135. {
  1136.   // make sure we have a port
  1137.   if (newPort != 0)
  1138.     port = newPort;
  1139.   // close the port if it is already open
  1140.   if (!IsOpen()) {
  1141.     // attempt to create a socket
  1142.     if (!OpenSocket())
  1143.       return FALSE;
  1144.   }
  1145.   // attempt to listen
  1146.   if (SetOption(SO_REUSEADDR, reuse == CanReuseAddress ? 1 : 0)) {
  1147.     // attempt to listen
  1148.     sockaddr_in sin;
  1149.     memset(&sin, 0, sizeof(sin));
  1150.     sin.sin_family      = AF_INET;
  1151.     sin.sin_addr.s_addr = bindAddr;
  1152.     sin.sin_port        = htons(port);       // set the port
  1153. #ifdef __NUCLEUS_NET__
  1154.     int bind_result;
  1155.     if (port == 0)
  1156.       bind_result = ::bindzero(os_handle, (struct sockaddr*)&sin, sizeof(sin));
  1157.     else
  1158.       bind_result = ::bind(os_handle, (struct sockaddr*)&sin, sizeof(sin));
  1159.     if (ConvertOSError(bind_result)) {
  1160. #else
  1161.     if (ConvertOSError(::bind(os_handle, (struct sockaddr*)&sin, sizeof(sin)))) {
  1162. #endif
  1163.       socklen_t size = sizeof(sin);
  1164.       if (ConvertOSError(::getsockname(os_handle, (struct sockaddr*)&sin, &size))) {
  1165.         port = ntohs(sin.sin_port);
  1166.         return TRUE;
  1167.       }
  1168.     }
  1169.   }
  1170.   os_close();
  1171.   return FALSE;
  1172. }
  1173. PIPSocket::Address::Address()
  1174. {
  1175.   s_addr = inet_addr("127.0.0.1");
  1176. }
  1177. PIPSocket::Address::Address(const in_addr & addr)
  1178. {
  1179.   s_addr = addr.s_addr;
  1180. }
  1181. PIPSocket::Address::Address(const Address & addr)
  1182. {
  1183.   s_addr = addr.s_addr;
  1184. }
  1185. PIPSocket::Address::Address(const PString & dotNotation)
  1186. {
  1187.   operator=(dotNotation);
  1188. }
  1189. #ifdef __NUCLEUS_NET__
  1190. PIPSocket::Address::Address(const struct id_struct & addr)
  1191. {
  1192.   operator=(addr);
  1193. }
  1194. PIPSocket::Address & PIPSocket::Address::operator=(const struct id_struct & addr)
  1195. {
  1196.   s_addr = (((unsigned long)addr.is_ip_addrs[0])<<24) +
  1197.            (((unsigned long)addr.is_ip_addrs[1])<<16) +
  1198.            (((unsigned long)addr.is_ip_addrs[2])<<8) +
  1199.            (((unsigned long)addr.is_ip_addrs[3]));
  1200.   return *this;
  1201. }
  1202. #endif
  1203. PIPSocket::Address & PIPSocket::Address::operator=(const in_addr & addr)
  1204. {
  1205.   s_addr = addr.s_addr;
  1206.   return *this;
  1207. }
  1208. PIPSocket::Address & PIPSocket::Address::operator=(const Address & addr)
  1209. {
  1210.   s_addr = addr.s_addr;
  1211.   return *this;
  1212. }
  1213. PIPSocket::Address & PIPSocket::Address::operator=(const PString & dotNotation)
  1214. {
  1215.   if (::strspn(dotNotation, "0123456789.") < ::strlen(dotNotation))
  1216.     s_addr = 0;
  1217.   else {
  1218.     s_addr = inet_addr((const char *)dotNotation);
  1219.     if (s_addr == (DWORD)INADDR_NONE)
  1220.       s_addr = 0;
  1221.   }
  1222.   return *this;
  1223. }
  1224. PString PIPSocket::Address::AsString() const
  1225. {
  1226.   return inet_ntoa(*this);
  1227. }
  1228. PIPSocket::Address::operator PString() const
  1229. {
  1230.   return inet_ntoa(*this);
  1231. }
  1232. BYTE PIPSocket::Address::operator[](PINDEX idx) const
  1233. {
  1234.   PASSERTINDEX(idx);
  1235.   PAssert(idx <= 3, PInvalidParameter);
  1236.   return ((BYTE *)this)[idx];
  1237. }
  1238. ostream & operator<<(ostream & s, const PIPSocket::Address & a)
  1239. {
  1240.   return s << inet_ntoa(a);
  1241. }
  1242. istream & operator>>(istream & s, PIPSocket::Address & a)
  1243. {
  1244.   char dot1, dot2, dot3;
  1245.   unsigned b1, b2, b3, b4;
  1246.   s >> b1 >> dot1 >> b2 >> dot2 >> b3 >> dot3 >> b4;
  1247.   if (!s && (dot1 != '.' || dot2 != '.' || dot3 != '.'))
  1248.     s.clear(ios::failbit);
  1249.   a = PIPSocket::Address((BYTE)b1, (BYTE)b2, (BYTE)b3, (BYTE)b4);
  1250.   return s;
  1251. }
  1252. #ifdef __NUCLEUS_NET__
  1253. BOOL PIPSocket::GetInterfaceTable(InterfaceTable & table)
  1254. {
  1255.     InterfaceEntry *IE;
  1256.     list<IPInterface>::iterator i;
  1257.     for(i=Route4Configuration->Getm_IPInterfaceList().begin();
  1258.             i!=Route4Configuration->Getm_IPInterfaceList().end();
  1259.             i++)
  1260.     {
  1261.         char ma[6];
  1262.         for(int j=0; j<6; j++) ma[j]=(*i).Getm_macaddr(j);
  1263.         IE = new InterfaceEntry((*i).Getm_name().c_str(), (*i).Getm_ipaddr(), ma );
  1264.         if(!IE) return false;
  1265.         table.Append(IE);
  1266.     }
  1267.     return true;
  1268. }
  1269. #endif
  1270. //////////////////////////////////////////////////////////////////////////////
  1271. // PTCPSocket
  1272. PTCPSocket::PTCPSocket(WORD newPort)
  1273. {
  1274.   SetPort(newPort);
  1275. }
  1276. PTCPSocket::PTCPSocket(const PString & service)
  1277. {
  1278.   SetPort(service);
  1279. }
  1280. PTCPSocket::PTCPSocket(const PString & address, WORD newPort)
  1281. {
  1282.   SetPort(newPort);
  1283.   Connect(address);
  1284. }
  1285. PTCPSocket::PTCPSocket(const PString & address, const PString & service)
  1286. {
  1287.   SetPort(service);
  1288.   Connect(address);
  1289. }
  1290. PTCPSocket::PTCPSocket(PSocket & socket)
  1291. {
  1292.   Accept(socket);
  1293. }
  1294. PTCPSocket::PTCPSocket(PTCPSocket & tcpSocket)
  1295. {
  1296.   Accept(tcpSocket);
  1297. }
  1298. PObject * PTCPSocket::Clone() const
  1299. {
  1300.   return new PTCPSocket(port);
  1301. }
  1302. BOOL PTCPSocket::OpenSocket()
  1303. {
  1304.   return ConvertOSError(os_handle = os_socket(AF_INET, SOCK_STREAM, 0));
  1305. }
  1306. const char * PTCPSocket::GetProtocolName() const
  1307. {
  1308.   return "tcp";
  1309. }
  1310. BOOL PTCPSocket::Write(const void * buf, PINDEX len)
  1311. {
  1312.   flush();
  1313.   PINDEX writeCount = 0;
  1314.   while (len > 0) {
  1315.     if (!os_sendto(((char *)buf)+writeCount, len, 0, NULL, 0))
  1316.       return FALSE;
  1317.     writeCount += lastWriteCount;
  1318.     len -= lastWriteCount;
  1319.   }
  1320.   lastWriteCount = writeCount;
  1321.   return TRUE;
  1322. }
  1323. BOOL PTCPSocket::Listen(unsigned queueSize, WORD newPort, Reusability reuse)
  1324. {
  1325.   return Listen(INADDR_ANY, queueSize, newPort, reuse);
  1326. }
  1327. BOOL PTCPSocket::Listen(const Address & bindAddr,
  1328.                         unsigned queueSize,
  1329.                         WORD newPort,
  1330.                         Reusability reuse)
  1331. {
  1332.   if (PIPSocket::Listen(bindAddr, queueSize, newPort, reuse) &&
  1333.       ConvertOSError(::listen(os_handle, queueSize)))
  1334.     return TRUE;
  1335.   os_close();
  1336.   return FALSE;
  1337. }
  1338. BOOL PTCPSocket::Accept(PSocket & socket)
  1339. {
  1340.   PAssert(socket.IsDescendant(PIPSocket::Class()), "Invalid listener socket");
  1341.   sockaddr_in address;
  1342.   address.sin_family = AF_INET;
  1343.   PINDEX size = sizeof(address);
  1344.   if (!ConvertOSError(os_handle = os_accept(socket.GetHandle(),
  1345.                                           (struct sockaddr *)&address, &size,
  1346.                                            socket.GetReadTimeout())))
  1347.     return FALSE;
  1348.   port = ((PIPSocket &)socket).GetPort();
  1349.   return TRUE;
  1350. }
  1351. BOOL PTCPSocket::WriteOutOfBand(void const * buf, PINDEX len)
  1352. {
  1353. #ifdef __NUCLEUS_NET__
  1354.   PAssertAlways("WriteOutOfBand unavailable on Nucleus Plus");
  1355.   //int count = NU_Send(os_handle, (char *)buf, len, 0);
  1356.   int count = ::send(os_handle, (const char *)buf, len, 0);
  1357. #else
  1358.   int count = ::send(os_handle, (const char *)buf, len, MSG_OOB);
  1359. #endif
  1360.   if (count < 0) {
  1361.     lastWriteCount = 0;
  1362.     return ConvertOSError(count);
  1363.   }
  1364.   else {
  1365.     lastWriteCount = count;
  1366.     return TRUE;
  1367.   }
  1368. }
  1369. void PTCPSocket::OnOutOfBand(const void *, PINDEX)
  1370. {
  1371. }
  1372. //////////////////////////////////////////////////////////////////////////////
  1373. // PIPDatagramSocket
  1374. PIPDatagramSocket::PIPDatagramSocket()
  1375. {
  1376. }
  1377. BOOL PIPDatagramSocket::ReadFrom(void * buf, PINDEX len,
  1378.                                  Address & addr, WORD & port)
  1379. {
  1380.   lastReadCount = 0;
  1381.   sockaddr_in sockAddr;
  1382.   PINDEX addrLen = sizeof(sockAddr);
  1383.   if (os_recvfrom(buf, len, 0, (struct sockaddr *)&sockAddr, &addrLen)) {
  1384.     addr = sockAddr.sin_addr;
  1385.     port = ntohs(sockAddr.sin_port);
  1386.   }
  1387.   return lastReadCount > 0;
  1388. }
  1389. BOOL PIPDatagramSocket::WriteTo(const void * buf, PINDEX len,
  1390.                                 const Address & addr, WORD port)
  1391. {
  1392.   lastWriteCount = 0;
  1393.   sockaddr_in sockAddr;
  1394.   sockAddr.sin_family = AF_INET;
  1395.   sockAddr.sin_addr = addr;
  1396.   sockAddr.sin_port = htons(port);
  1397.   return os_sendto(buf, len, 0, (struct sockaddr *)&sockAddr, sizeof(sockAddr))
  1398.          && lastWriteCount >= len;
  1399. }
  1400. //////////////////////////////////////////////////////////////////////////////
  1401. // PUDPSocket
  1402. PUDPSocket::PUDPSocket(WORD newPort)
  1403. {
  1404.   sendPort = 0;
  1405.   SetPort(newPort);
  1406.   OpenSocket();
  1407. }
  1408. PUDPSocket::PUDPSocket(const PString & service)
  1409. {
  1410.   sendPort = 0;
  1411.   SetPort(service);
  1412.   OpenSocket();
  1413. }
  1414. PUDPSocket::PUDPSocket(const PString & address, WORD newPort)
  1415. {
  1416.   sendPort = 0;
  1417.   SetPort(newPort);
  1418.   Connect(address);
  1419. }
  1420. PUDPSocket::PUDPSocket(const PString & address, const PString & service)
  1421. {
  1422.   sendPort = 0;
  1423.   SetPort(service);
  1424.   Connect(address);
  1425. }
  1426. BOOL PUDPSocket::OpenSocket()
  1427. {
  1428.   return ConvertOSError(os_handle = os_socket(AF_INET, SOCK_DGRAM, 0));
  1429. }
  1430. const char * PUDPSocket::GetProtocolName() const
  1431. {
  1432.   return "udp";
  1433. }
  1434. BOOL PUDPSocket::Connect(const PString & address)
  1435. {
  1436.   sendPort = 0;
  1437.   return PIPDatagramSocket::Connect(address);
  1438. }
  1439. BOOL PUDPSocket::Read(void * buf, PINDEX len)
  1440. {
  1441.   return PIPDatagramSocket::ReadFrom(buf, len, lastReceiveAddress, lastReceivePort);
  1442. }
  1443. BOOL PUDPSocket::Write(const void * buf, PINDEX len)
  1444. {
  1445.   if (sendPort == 0)
  1446.     return PIPDatagramSocket::Write(buf, len);
  1447.   else
  1448.     return PIPDatagramSocket::WriteTo(buf, len, sendAddress, sendPort);
  1449. }
  1450. void PUDPSocket::SetSendAddress(const Address & newAddress, WORD newPort)
  1451. {
  1452.   sendAddress = newAddress;
  1453.   sendPort    = newPort;
  1454. }
  1455. void PUDPSocket::GetSendAddress(Address & address, WORD & port)
  1456. {
  1457.   address = sendAddress;
  1458.   port    = sendPort;
  1459. }
  1460. void PUDPSocket::GetLastReceiveAddress(Address & address, WORD & port)
  1461. {
  1462.   address = lastReceiveAddress;
  1463.   port    = lastReceivePort;
  1464. }
  1465. // End Of File ///////////////////////////////////////////////////////////////