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

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * winsock.cxx
  3.  *
  4.  * WINSOCK implementation of Berkley sockets.
  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: winsock.cxx,v $
  30.  * Revision 1.41  1998/11/30 04:50:19  robertj
  31.  * New directory structure
  32.  *
  33.  * Revision 1.40  1998/11/14 06:31:15  robertj
  34.  * Changed semantics of os_sendto to return TRUE if ANY bytes are sent.
  35.  *
  36.  * Revision 1.39  1998/09/24 03:31:02  robertj
  37.  * Added open software license.
  38.  *
  39.  * Revision 1.38  1998/08/28 14:09:45  robertj
  40.  * Fixed bug in Write() that caused endlesss loops, introduced in previous version.
  41.  *
  42.  * Revision 1.37  1998/08/21 05:27:31  robertj
  43.  * Fixed bug where write streams out to non-stream socket.
  44.  *
  45.  * Revision 1.36  1998/08/06 00:55:21  robertj
  46.  * Fixed conversion of text to IPX address, was swapping nibbles.
  47.  *
  48.  * Revision 1.35  1998/05/08 11:52:03  robertj
  49.  * Added workaround for winsock bug where getpeername() doesn't work immediately after connect().
  50.  *
  51.  * Revision 1.34  1998/05/07 05:21:04  robertj
  52.  * Fixed DNS lookup so only works around bug in old Win95 and not OSR2
  53.  *
  54.  * Revision 1.33  1998/01/26 01:00:06  robertj
  55.  * Added timeout to os_connect().
  56.  * Fixed problems with NT version of IsLocalHost().
  57.  *
  58.  * Revision 1.32  1997/12/18 05:05:27  robertj
  59.  * Moved IsLocalHost() to platform dependent code.
  60.  *
  61.  * Revision 1.31  1997/12/11 10:41:55  robertj
  62.  * Added DWORD operator for IP addresses.
  63.  *
  64.  * Revision 1.30  1997/01/03 04:37:11  robertj
  65.  * Fixed '95 problem with send timeouts.
  66.  *
  67.  * Revision 1.29  1996/12/05 11:51:50  craigs
  68.  * Fixed Win95 recvfrom timeout problem
  69.  *
  70.  * Revision 1.28  1996/11/10 21:04:56  robertj
  71.  * Fixed bug in not flushing stream on close of socket.
  72.  *
  73.  * Revision 1.27  1996/10/31 12:39:30  robertj
  74.  * Fixed bug in byte order of port numbers in IPX protocol.
  75.  *
  76.  * Revision 1.26  1996/10/26 01:43:18  robertj
  77.  * Removed translation of IP address to host order DWORD. Is ALWAYS net order.
  78.  *
  79.  * Revision 1.25  1996/10/08 13:03:09  robertj
  80.  * More IPX support.
  81.  *
  82.  * Revision 1.24  1996/09/14 13:09:47  robertj
  83.  * Major upgrade:
  84.  *   rearranged sockets to help support IPX.
  85.  *   added indirect channel class and moved all protocols to descend from it,
  86.  *   separating the protocol from the low level byte transport.
  87.  *
  88.  * Revision 1.23  1996/08/08 10:06:07  robertj
  89.  * Fixed incorrect value in write, causes incorrect output if send is split.
  90.  *
  91.  * Revision 1.22  1996/07/27 04:03:29  robertj
  92.  * Created static version of ConvertOSError().
  93.  *
  94.  * Revision 1.21  1996/06/01 04:19:34  robertj
  95.  * Added flush to PSocket destructor as needs to use Write() at that level.
  96.  *
  97.  * Revision 1.20  1996/05/15 10:23:08  robertj
  98.  * Changed millisecond access functions to get 64 bit integer.
  99.  * Added timeout to accept function.
  100.  * Added ICMP protocol socket, getting common ancestor to UDP.
  101.  *
  102.  * Revision 1.19  1996/04/29 12:22:26  robertj
  103.  * Fixed detection of infinite timeout.
  104.  *
  105.  * Revision 1.18  1996/04/17 12:09:52  robertj
  106.  * Fixed bug in detecting infinte timeout.
  107.  *
  108.  * Revision 1.17  1996/04/12 09:45:06  robertj
  109.  * Rewrite of PSocket::Read() to avoid "Connection Reset" errors caused by SO_RCVTIMEO
  110.  *
  111.  * Revision 1.17  1996/04/10 12:15:11  robertj
  112.  * Rewrite of PSocket::Read() to avoid "Connection Reset" errors caused by SO_RCVTIMEO.
  113.  *
  114.  * Revision 1.16  1996/04/05 01:42:28  robertj
  115.  * Assured PSocket::Write always writes the number of bytes specified.
  116.  *
  117.  * Revision 1.15  1996/03/31 09:11:06  robertj
  118.  * Fixed major performance problem in timeout read/write to sockets.
  119.  *
  120.  * Revision 1.14  1996/03/10 13:16:25  robertj
  121.  * Fixed ioctl of closed socket.
  122.  *
  123.  * Revision 1.13  1996/03/04 12:41:02  robertj
  124.  * Fixed bug in leaving socket in non-blocking mode.
  125.  * Changed _Close to os_close to be consistent.
  126.  *
  127.  * Revision 1.12  1996/02/25 11:23:40  robertj
  128.  * Fixed bug in Read for when a timeout occurs on select, not returning error code.
  129.  *
  130.  * Revision 1.11  1996/02/25 03:13:12  robertj
  131.  * Moved some socket functions to platform dependent code.
  132.  *
  133.  * Revision 1.10  1996/02/19 13:52:39  robertj
  134.  * Added SO_LINGER option to socket to stop data loss on close.
  135.  * Fixed error reporting for winsock classes.
  136.  *
  137.  * Revision 1.9  1996/02/15 14:53:36  robertj
  138.  * Added Select() function to PSocket.
  139.  *
  140.  * Revision 1.8  1996/01/23 13:25:48  robertj
  141.  * Moved Accept from platform independent code.
  142.  *
  143.  * Revision 1.7  1996/01/02 12:57:17  robertj
  144.  * Unix compatibility.
  145.  *
  146.  * Revision 1.6  1995/12/10 12:06:00  robertj
  147.  * Numerous fixes for sockets.
  148.  *
  149.  * Revision 1.5  1995/06/17 00:59:49  robertj
  150.  * Fixed bug with stream being flushed on read/write.
  151.  *
  152.  * Revision 1.4  1995/06/04 12:49:51  robertj
  153.  * Fixed bugs in socket read and write function return status.
  154.  * Fixed bug in socket close setting object state to "closed".
  155.  *
  156.  * Revision 1.3  1995/03/12 05:00:10  robertj
  157.  * Re-organisation of DOS/WIN16 and WIN32 platforms to maximise common code.
  158.  * Used built-in equate for WIN32 API (_WIN32).
  159.  *
  160.  * Revision 1.2  1995/01/03  09:43:27  robertj
  161.  * Moved out of band stuff to common.
  162.  *
  163.  * Revision 1.1  1994/10/30  12:06:56  robertj
  164.  * Initial revision
  165.  */
  166. #include <ptlib.h>
  167. #include <ptlib/sockets.h>
  168. #include <nspapi.h>
  169. #include <svcguid.h>
  170. //////////////////////////////////////////////////////////////////////////////
  171. // PWinSock
  172. PWinSock::PWinSock()
  173. {
  174.   WSADATA winsock;
  175.   PAssert(WSAStartup(0x101, &winsock) == 0, POperatingSystemError);
  176.   PAssert(LOBYTE(winsock.wVersion) == 1 &&
  177.           HIBYTE(winsock.wVersion) == 1, POperatingSystemError);
  178. }
  179. PWinSock::~PWinSock()
  180. {
  181.   WSACleanup();
  182. }
  183. BOOL PWinSock::OpenSocket()
  184. {
  185.   return FALSE;
  186. }
  187. const char * PWinSock::GetProtocolName() const
  188. {
  189.   return NULL;
  190. }
  191. //////////////////////////////////////////////////////////////////////////////
  192. // PSocket
  193. PSocket::~PSocket()
  194. {
  195.   Close();
  196. }
  197. BOOL PSocket::Read(void * buf, PINDEX len)
  198. {
  199.   flush();
  200.   lastReadCount = 0;
  201.   if (len == 0) {
  202.     lastError = BadParameter;
  203.     osError = EINVAL;
  204.     return FALSE;
  205.   }
  206.   os_recvfrom((char *)buf, len, 0, NULL, NULL);
  207.   return lastReadCount > 0;
  208. }
  209. BOOL PSocket::Write(const void * buf, PINDEX len)
  210. {
  211.   flush();
  212.   return os_sendto(buf, len, 0, NULL, 0) && lastWriteCount >= len;
  213. }
  214. BOOL PSocket::Close()
  215. {
  216.   if (!IsOpen())
  217.     return FALSE;
  218.   flush();
  219.   return ConvertOSError(os_close());
  220. }
  221. int PSocket::os_close()
  222. {
  223.   int err = closesocket(os_handle);
  224.   os_handle = -1;
  225.   return err;
  226. }
  227. int PSocket::os_socket(int af, int type, int proto)
  228. {
  229.   return ::socket(af, type, proto);
  230. }
  231. class fd_set_class : public fd_set {
  232.   public:
  233.     fd_set_class(SOCKET fd)
  234.       {
  235. #ifdef _MSC_VER
  236. #pragma warning(disable:4127)
  237. #endif
  238.         FD_ZERO(this);
  239.         FD_SET(fd, this);
  240. #ifdef _MSC_VER
  241. #pragma warning(default:4127)
  242. #endif
  243.       }
  244.     BOOL IsPresent(int h) const
  245.       { return FD_ISSET(h, this); }
  246. };
  247. class timeval_class : public timeval {
  248.   public:
  249.     timeval_class(const PTimeInterval & time)
  250.       {
  251.         tv_usec = (long)(time.GetMilliSeconds()%1000)*1000;
  252.         tv_sec = time.GetSeconds();
  253.       }
  254. };
  255. int PSocket::os_connect(struct sockaddr * addr, int size)
  256. {
  257.   if (readTimeout == PMaxTimeInterval)
  258.     return ::connect(os_handle, addr, size);
  259.   DWORD fionbio = 1;
  260.   if (::ioctlsocket(os_handle, FIONBIO, &fionbio) == SOCKET_ERROR)
  261.     return SOCKET_ERROR;
  262.   fionbio = 0;
  263.   if (::connect(os_handle, addr, size) != SOCKET_ERROR)
  264.     return ::ioctlsocket(os_handle, FIONBIO, &fionbio);
  265.   DWORD err = GetLastError();
  266.   if (err != WSAEWOULDBLOCK) {
  267.     ::ioctlsocket(os_handle, FIONBIO, &fionbio);
  268.     SetLastError(err);
  269.     return SOCKET_ERROR;
  270.   }
  271.   fd_set_class writefds = os_handle;
  272.   timeval_class tv = readTimeout;
  273.   switch (select(0, NULL, &writefds, NULL, &tv)) {
  274.     case 1 :
  275.       err = 0;
  276.       break;
  277.     case 0 :
  278.       err = WSAETIMEDOUT;
  279.       break;
  280.     default :
  281.       err = GetLastError();
  282.   }
  283.   if (::ioctlsocket(os_handle, FIONBIO, &fionbio) == SOCKET_ERROR) {
  284.     if (err == 0)
  285.       err = GetLastError();
  286.   }
  287.   // The following is to avoid a bug in Win32 sockets. The getpeername() function doesn't
  288.   // work for some period of time after a connect, saying it is not connected yet!
  289.   for (PINDEX failsafe = 0; failsafe < 1000; failsafe++) {
  290.     sockaddr_in address;
  291.     int sz = sizeof(address);
  292.     if (::getpeername(os_handle, (struct sockaddr *)&address, &sz) == 0)
  293.       break;
  294.     ::Sleep(0);
  295.   }
  296.   SetLastError(err);
  297.   return err == 0 ? 0 : SOCKET_ERROR;
  298. }
  299. int PSocket::os_accept(int sock, struct sockaddr * addr, int * size,
  300.                        const PTimeInterval & timeout)
  301. {
  302.   if (timeout != PMaxTimeInterval) {
  303.     fd_set_class readfds = sock;
  304.     timeval_class tv = timeout;
  305.     switch (select(0, &readfds, NULL, NULL, &tv)) {
  306.       case 1 :
  307.         break;
  308.       case 0 :
  309.         SetLastError(WSAETIMEDOUT);
  310.         // Then return -1
  311.       default :
  312.         return -1;
  313.     }
  314.   }
  315.   return ::accept(sock, addr, size);
  316. }
  317. BOOL PSocket::os_recvfrom(void * buf,
  318.                           PINDEX len,
  319.                           int flags,
  320.                           struct sockaddr * from,
  321.                           int * fromlen)
  322. {
  323.   lastReadCount = 0;
  324.   if (readTimeout != PMaxTimeInterval) {
  325.     DWORD available;
  326.     if (!ConvertOSError(ioctlsocket(os_handle, FIONREAD, &available)))
  327.       return FALSE;
  328.     if (available == 0) {
  329.       fd_set_class readfds = os_handle;
  330.       timeval_class tv = readTimeout;
  331.       int selval = ::select(0, &readfds, NULL, NULL, &tv);
  332.       if (!ConvertOSError(selval))
  333.         return FALSE;
  334.       if (selval == 0) {
  335.         lastError = Timeout;
  336.         osError = EAGAIN;
  337.         return FALSE;
  338.       }
  339.       if (!ConvertOSError(ioctlsocket(os_handle, FIONREAD, &available)))
  340.         return FALSE;
  341.     }
  342.     if (available > 0 && len > (PINDEX)available)
  343.       len = available;
  344.   }
  345.   int recvResult = ::recvfrom(os_handle, (char *)buf, len, flags, from, fromlen);
  346.   if (!ConvertOSError(recvResult))
  347.     return FALSE;
  348.   lastReadCount = recvResult;
  349.   return TRUE;
  350. }
  351. BOOL PSocket::os_sendto(const void * buf,
  352.                         PINDEX len,
  353.                         int flags,
  354.                         struct sockaddr * to,
  355.                         int tolen)
  356. {
  357.   lastWriteCount = 0;
  358.   if (writeTimeout != PMaxTimeInterval) {
  359.     fd_set_class writefds = os_handle;
  360.     timeval_class tv = writeTimeout;
  361.     int selval = ::select(0, NULL, &writefds, NULL, &tv);
  362.     if (selval < 0)
  363.       return FALSE;
  364.     if (selval == 0) {
  365.       errno = EAGAIN;
  366.       return FALSE;
  367.     }
  368.   }
  369.   int sendResult = ::sendto(os_handle, (const char *)buf, len, flags, to, tolen);
  370.   if (!ConvertOSError(sendResult))
  371.     return FALSE;
  372.   if (sendResult == 0)
  373.     return FALSE;
  374.   lastWriteCount = sendResult;
  375.   return TRUE;
  376. }
  377. int PSocket::os_select(int maxfds,
  378.                        fd_set & readfds,
  379.                        fd_set & writefds,
  380.                        fd_set & exceptfds,
  381.                        const PIntArray &,
  382.                        const PTimeInterval & timeout)
  383. {
  384.   struct timeval tv_buf;
  385.   struct timeval * tv = NULL;
  386.   if (timeout != PMaxTimeInterval) {
  387.     tv = &tv_buf;
  388.     tv->tv_usec = (long)(timeout.GetMilliSeconds()%1000)*1000;
  389.     tv->tv_sec = timeout.GetSeconds();
  390.   }
  391.   return select(maxfds, &readfds, &writefds, &exceptfds, tv);
  392. }
  393. BOOL PSocket::ConvertOSError(int error)
  394. {
  395.   return ConvertOSError(error, lastError, osError);
  396. }
  397. BOOL PSocket::ConvertOSError(int error, Errors & lastError, int & osError)
  398. {
  399.   if (error >= 0) {
  400.     lastError = NoError;
  401.     osError = 0;
  402.     return TRUE;
  403.   }
  404. #ifdef _WIN32
  405.   SetLastError(WSAGetLastError());
  406.   return PChannel::ConvertOSError(-2, lastError, osError);
  407. #else
  408.   osError = WSAGetLastError();
  409.   switch (osError) {
  410.     case 0 :
  411.       lastError = NoError;
  412.       return TRUE;
  413.     case WSAEWOULDBLOCK :
  414.       lastError = Timeout;
  415.       break;
  416.     default :
  417.       osError |= 0x40000000;
  418.       lastError = Miscellaneous;
  419.   }
  420.   return FALSE;
  421. #endif
  422. }
  423. //////////////////////////////////////////////////////////////////////////////
  424. // PIPSocket
  425. PIPSocket::Address::Address(BYTE b1, BYTE b2, BYTE b3, BYTE b4)
  426. {
  427.   S_un.S_un_b.s_b1 = b1;
  428.   S_un.S_un_b.s_b2 = b2;
  429.   S_un.S_un_b.s_b3 = b3;
  430.   S_un.S_un_b.s_b4 = b4;
  431. }
  432. PIPSocket::Address::Address(DWORD dw)
  433. {
  434.   S_un.S_addr = dw;
  435. }
  436. PIPSocket::Address & PIPSocket::Address::operator=(DWORD dw)
  437. {
  438.   S_un.S_addr = dw;
  439.   return *this;
  440. }
  441. PIPSocket::Address::operator DWORD() const
  442. {
  443.   return S_un.S_addr;
  444. }
  445. BYTE PIPSocket::Address::Byte1() const
  446. {
  447.   return S_un.S_un_b.s_b1;
  448. }
  449. BYTE PIPSocket::Address::Byte2() const
  450. {
  451.   return S_un.S_un_b.s_b2;
  452. }
  453. BYTE PIPSocket::Address::Byte3() const
  454. {
  455.   return S_un.S_un_b.s_b3;
  456. }
  457. BYTE PIPSocket::Address::Byte4() const
  458. {
  459.   return S_un.S_un_b.s_b4;
  460. }
  461. BOOL P_IsOldWin95()
  462. {
  463.   static int state = -1;
  464.   if (state < 0) {
  465.     state = 1;
  466.     OSVERSIONINFO info;
  467.     info.dwOSVersionInfoSize = sizeof(info);
  468.     if (GetVersionEx(&info)) {
  469.       state = 0;
  470.       if (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && info.dwBuildNumber < 1000)
  471.         state = 1;
  472.     }
  473.   }
  474.   return state != 0;
  475. }
  476. BOOL PIPSocket::IsLocalHost(const PString & hostname)
  477. {
  478.   if (hostname.IsEmpty())
  479.     return TRUE;
  480.   if (hostname *= "localhost")
  481.     return TRUE;
  482.   // lookup the host address using inet_addr, assuming it is a "." address
  483.   Address addr = hostname;
  484.   if (addr == 16777343)  // Is 127.0.0.1
  485.     return TRUE;
  486.   if (addr == 0) {
  487.     if (!GetHostAddress(hostname, addr))
  488.       return FALSE;
  489.   }
  490.   struct hostent * host_info = ::gethostbyname(GetHostName());
  491.   if (P_IsOldWin95())
  492.     return addr == Address(*(struct in_addr *)host_info->h_addr_list[0]);
  493.   for (PINDEX i = 0; host_info->h_addr_list[i] != NULL; i++) {
  494.     if (addr == Address(*(struct in_addr *)host_info->h_addr_list[i]))
  495.       return TRUE;
  496.   }
  497.   return FALSE;
  498. }
  499. //////////////////////////////////////////////////////////////////////////////
  500. // PIPXSocket
  501. PIPXSocket::Address::Address()
  502. {
  503.   memset(this, 0, sizeof(*this));
  504. }
  505. PIPXSocket::Address::Address(const Address & addr)
  506. {
  507.   memcpy(this, &addr, sizeof(*this));
  508. }
  509. PIPXSocket::Address::Address(const PString & str)
  510. {
  511.   PINDEX colon = str.Find(':');
  512.   if (colon == P_MAX_INDEX)
  513.     colon = 0;
  514.   else {
  515.     DWORD netnum = 0;
  516.     for (PINDEX i = 0; i < colon; i++) {
  517.       int c = str[i];
  518.       if (isdigit(c))
  519.         netnum = (netnum << 4) + c - '0';
  520.       else if (isxdigit(c))
  521.         netnum = (netnum << 4) + toupper(c) - 'A' + 10;
  522.       else {
  523.         memset(this, 0, sizeof(*this));
  524.         return;
  525.       }
  526.     }
  527.     network.dw = ntohl(netnum);
  528.   }
  529.   memset(node, 0, sizeof(node));
  530.   int shift = 0;
  531.   PINDEX byte = 5;
  532.   PINDEX pos = str.GetLength();
  533.   while (--pos > colon) {
  534.     int c = str[pos];
  535.     if (c != '-') {
  536.       if (isdigit(c))
  537.         node[byte] |= (c - '0') << shift;
  538.       else if (isxdigit(c))
  539.         node[byte] |= (toupper(c) - 'A' + 10) << shift;
  540.       else {
  541.         memset(this, 0, sizeof(*this));
  542.         return;
  543.       }
  544.       if (shift == 0)
  545.         shift = 4;
  546.       else {
  547.         shift = 0;
  548.         byte--;
  549.       }
  550.     }
  551.   }
  552. }
  553. PIPXSocket::Address::Address(DWORD netNum, const char * nodeNum)
  554. {
  555.   network.dw = netNum;
  556.   memcpy(node, nodeNum, sizeof(node));
  557. }
  558. PIPXSocket::Address & PIPXSocket::Address::operator=(const Address & addr)
  559. {
  560.   memcpy(this, &addr, sizeof(*this));
  561.   return *this;
  562. }
  563. PIPXSocket::Address::operator PString() const
  564. {
  565.   return psprintf("%02X%02X%02X%02X:%02X%02X%02X%02X%02X%02X",
  566.                   network.b.b1, network.b.b2, network.b.b3, network.b.b4,
  567.                   node[0], node[1], node[2], node[3], node[4], node[5]);
  568. }
  569. BOOL PIPXSocket::Address::IsValid() const
  570. {
  571.   static Address empty;
  572.   return memcmp(this, &empty, sizeof(empty)) != 0;
  573. }
  574. PIPXSocket::PIPXSocket(WORD newPort)
  575. {
  576.   SetPort(newPort);
  577. }
  578. PString PIPXSocket::GetName() const
  579. {
  580.   Address addr;
  581.   if (((PIPXSocket*)this)->GetPeerAddress(addr))
  582.     return addr;
  583.   else
  584.     return PString();
  585. }
  586. BOOL PIPXSocket::OpenSocket()
  587. {
  588.   return ConvertOSError(os_handle = os_socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX));
  589. }
  590. const char * PIPXSocket::GetProtocolName() const
  591. {
  592.   return "ipx";
  593. }
  594. BOOL PIPXSocket::SetPacketType(int type)
  595. {
  596.   return ConvertOSError(::setsockopt(os_handle,
  597.                            NSPROTO_IPX, IPX_PTYPE, (char *)&type, sizeof(type)));
  598. }
  599. int PIPXSocket::GetPacketType()
  600. {
  601.   int value;
  602.   int valSize = sizeof(value);
  603.   if (ConvertOSError(::getsockopt(os_handle,
  604.                                 NSPROTO_IPX, IPX_PTYPE, (char *)&value, &valSize)))
  605.     return value;
  606.   return -1;
  607. }
  608. PString PIPXSocket::GetHostName(const Address & addr)
  609. {
  610.   return addr;
  611. }
  612. BOOL PIPXSocket::GetHostAddress(Address &)
  613. {
  614.   return FALSE;
  615. }
  616. static void AssignAddress(sockaddr_ipx & sip, const PIPXSocket::Address & addr)
  617. {
  618.   memcpy(sip.sa_netnum, &addr.network, sizeof(sip.sa_netnum));
  619.   memcpy(sip.sa_nodenum, addr.node, sizeof(sip.sa_nodenum));
  620. }
  621. static void AssignAddress(PIPXSocket::Address & addr, const sockaddr_ipx & sip)
  622. {
  623.   memcpy(&addr.network, sip.sa_netnum, sizeof(addr.network));
  624.   memcpy(addr.node, sip.sa_nodenum, sizeof(addr.node));
  625. }
  626. BOOL PIPXSocket::GetHostAddress(const PString & hostname, Address & addr)
  627. {
  628.   addr = hostname;
  629.   if (addr.IsValid())
  630.     return TRUE;
  631.   static GUID netware_file_server = SVCID_FILE_SERVER;
  632.   CSADDR_INFO addr_info[10];
  633.   DWORD buffer_length = sizeof(addr_info);
  634. int num = GetAddressByName(NS_DEFAULT,
  635.                              &netware_file_server,
  636.                              (LPTSTR)(const char *)hostname,
  637.                              NULL,
  638.                              0,
  639.                              NULL,
  640.                              addr_info,
  641.                              &buffer_length,
  642.                              NULL,
  643.                              NULL
  644.                             );
  645.   if (num <= 0)
  646.     return FALSE;
  647.   AssignAddress(addr, *(sockaddr_ipx *)addr_info[0].RemoteAddr.lpSockaddr);
  648.   return TRUE;
  649. }
  650. BOOL PIPXSocket::GetLocalAddress(Address & addr)
  651. {
  652.   sockaddr_ipx sip;
  653.   int size = sizeof(sip);
  654.   if (!ConvertOSError(::getsockname(os_handle, (struct sockaddr *)&sip, &size)))
  655.     return FALSE;
  656.   AssignAddress(addr, sip);
  657.   return TRUE;
  658. }
  659. BOOL PIPXSocket::GetLocalAddress(Address & addr, WORD & portNum)
  660. {
  661.   sockaddr_ipx sip;
  662.   int size = sizeof(sip);
  663.   if (!ConvertOSError(::getsockname(os_handle, (struct sockaddr *)&sip, &size)))
  664.     return FALSE;
  665.   AssignAddress(addr, sip);
  666.   portNum = Net2Host(sip.sa_socket);
  667.   return TRUE;
  668. }
  669. BOOL PIPXSocket::GetPeerAddress(Address & addr)
  670. {
  671.   sockaddr_ipx sip;
  672.   int size = sizeof(sip);
  673.   if (!ConvertOSError(::getpeername(os_handle, (struct sockaddr *)&sip, &size)))
  674.     return FALSE;
  675.   AssignAddress(addr, sip);
  676.   return TRUE;
  677. }
  678. BOOL PIPXSocket::GetPeerAddress(Address & addr, WORD & portNum)
  679. {
  680.   sockaddr_ipx sip;
  681.   int size = sizeof(sip);
  682.   if (!ConvertOSError(::getpeername(os_handle, (struct sockaddr *)&sip, &size)))
  683.     return FALSE;
  684.   AssignAddress(addr, sip);
  685.   portNum = Net2Host(sip.sa_socket);
  686.   return TRUE;
  687. }
  688. BOOL PIPXSocket::Connect(const PString & host)
  689. {
  690.   Address addr;
  691.   if (GetHostAddress(host, addr))
  692.     return Connect(addr);
  693.   return FALSE;
  694. }
  695. BOOL PIPXSocket::Connect(const Address & addr)
  696. {
  697.   // close the port if it is already open
  698.   if (IsOpen())
  699.     Close();
  700.   // make sure we have a port
  701.   PAssert(port != 0, "Cannot connect socket without setting port");
  702.   // attempt to create a socket
  703.   if (!OpenSocket())
  704.     return FALSE;
  705.   // attempt to lookup the host name
  706.   sockaddr_ipx sip;
  707.   memset(&sip, 0, sizeof(sip));
  708.   sip.sa_family = AF_IPX;
  709.   AssignAddress(sip, addr);
  710.   sip.sa_socket  = Host2Net(port);  // set the port
  711.   if (ConvertOSError(os_connect((struct sockaddr *)&sip, sizeof(sip))))
  712.     return TRUE;
  713.   os_close();
  714.   return FALSE;
  715. }
  716. BOOL PIPXSocket::Listen(unsigned, WORD newPort, Reusability reuse)
  717. {
  718.   // make sure we have a port
  719.   if (newPort != 0)
  720.     port = newPort;
  721.   // close the port if it is already open
  722.   if (!IsOpen()) {
  723.     // attempt to create a socket
  724.     if (!OpenSocket())
  725.       return FALSE;
  726.   }
  727.   // attempt to listen
  728.   if (SetOption(SO_REUSEADDR, reuse == CanReuseAddress ? 1 : 0)) {
  729.     // attempt to listen
  730.     sockaddr_ipx sip;
  731.     memset(&sip, 0, sizeof(sip));
  732.     sip.sa_family = AF_IPX;
  733.     sip.sa_socket = Host2Net(port);       // set the port
  734.     if (ConvertOSError(::bind(os_handle, (struct sockaddr*)&sip, sizeof(sip)))) {
  735.       int size = sizeof(sip);
  736.       if (ConvertOSError(::getsockname(os_handle, (struct sockaddr*)&sip, &size))) {
  737.         port = Net2Host(sip.sa_socket);
  738.         return TRUE;
  739.       }
  740.     }
  741.   }
  742.   os_close();
  743.   return FALSE;
  744. }
  745. BOOL PIPXSocket::ReadFrom(void * buf, PINDEX len, Address & addr, WORD & port)
  746. {
  747.   lastReadCount = 0;
  748.   sockaddr_ipx sip;
  749.   int addrLen = sizeof(sip);
  750.   if (os_recvfrom(buf, len, 0, (struct sockaddr *)&sip, &addrLen)) {
  751.     AssignAddress(addr, sip);
  752.     port = Net2Host(sip.sa_socket);
  753.   }
  754.   return lastReadCount > 0;
  755. }
  756. BOOL PIPXSocket::WriteTo(const void * buf, PINDEX len, const Address & addr, WORD port)
  757. {
  758.   lastWriteCount = 0;
  759.   sockaddr_ipx sip;
  760.   sip.sa_family = AF_IPX;
  761.   AssignAddress(sip, addr);
  762.   sip.sa_socket = Host2Net(port);
  763.   int sendResult = os_sendto(buf, len, 0, (struct sockaddr *)&sip, sizeof(sip));
  764.   if (ConvertOSError(sendResult))
  765.     lastWriteCount = sendResult;
  766.   return lastWriteCount >= len;
  767. }
  768. //////////////////////////////////////////////////////////////////////////////
  769. // PSPXSocket
  770. PSPXSocket::PSPXSocket(WORD port)
  771.   : PIPXSocket(port)
  772. {
  773. }
  774. BOOL PSPXSocket::OpenSocket()
  775. {
  776.   return ConvertOSError(os_handle = os_socket(AF_IPX, SOCK_STREAM, NSPROTO_SPX));
  777. }
  778. const char * PSPXSocket::GetProtocolName() const
  779. {
  780.   return "spx";
  781. }
  782. BOOL PSPXSocket::Listen(unsigned queueSize, WORD newPort, Reusability reuse)
  783. {
  784.   if (PIPXSocket::Listen(queueSize, newPort, reuse) &&
  785.       ConvertOSError(::listen(os_handle, queueSize)))
  786.     return TRUE;
  787.   os_close();
  788.   return FALSE;
  789. }
  790. BOOL PSPXSocket::Accept(PSocket & socket)
  791. {
  792.   PAssert(socket.IsDescendant(PIPXSocket::Class()), "Invalid listener socket");
  793.   sockaddr_ipx sip;
  794.   sip.sa_family = AF_IPX;
  795.   int size = sizeof(sip);
  796.   if (!ConvertOSError(os_handle = os_accept(socket.GetHandle(),
  797.                                           (struct sockaddr *)&sip, &size,
  798.                                            socket.GetReadTimeout())))
  799.     return FALSE;
  800.   port = ((PIPXSocket &)socket).GetPort();
  801.   return TRUE;
  802. }
  803. // End Of File ///////////////////////////////////////////////////////////////