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  * $Revision: 28201 $
30  * $Author: rjongbloed $
31  * $Date: 2012-08-14 21:30:31 -0500 (Tue, 14 Aug 2012) $
32  */
33 
34 #include <ptlib.h>
35 #include <ptbuildopts.h>
36 #include <ptlib/sockets.h>
37 
38 #include <ctype.h>
39 
40 #ifdef P_VXWORKS
41 // VxWorks variant of inet_ntoa() allocates INET_ADDR_LEN bytes via malloc
42 // BUT DOES NOT FREE IT !!!  Use inet_ntoa_b() instead.
43 #define INET_ADDR_LEN      18
44 extern "C" void inet_ntoa_b(struct in_addr inetAddress, char *pString);
45 #endif // P_VXWORKS
46 
47 #ifdef __NUCLEUS_PLUS__
48 #include <ConfigurationClass.h>
49 #endif
50 
51 #if P_QOS
52 
53 #ifdef _WIN32
54 #include <winbase.h>
55 #include <winreg.h>
56 
57 #ifndef _WIN32_WCE
58 
59 void CALLBACK CompletionRoutine(DWORD dwError,
60                                 DWORD cbTransferred,
61                                 LPWSAOVERLAPPED lpOverlapped,
62                                 DWORD dwFlags);
63 
64 
65 #endif  // _WIN32_WCE
66 #endif  // _WIN32
67 #endif // P_QOS
68 
69 
70 #if !defined(P_MINGW) && !defined(P_CYGWIN)
71   #if P_HAS_IPV6 || defined(AI_NUMERICHOST)
72     #define HAS_GETADDRINFO 1
73   #endif
74 #else
75   #if WINVER > 0x500
76     #define HAS_GETADDRINFO 1
77   #endif
78 #endif
79 
80 
81 ///////////////////////////////////////////////////////////////////////////////
82 // PIPSocket::Address
83 
84 static int g_defaultIpAddressFamily = PF_INET;  // PF_UNSPEC;   // default to IPV4
85 static bool g_suppressCanonicalName = false;
86 
87 static PIPSocket::Address loopback4(127,0,0,1);
88 static PIPSocket::Address broadcast4(INADDR_BROADCAST);
89 static PIPSocket::Address any4(0,0,0,0);
90 static in_addr inaddr_empty;
91 #if P_HAS_IPV6
92 static int defaultIPv6ScopeId = 0;
93 
94 static PIPSocket::Address loopback6(16,(const BYTE *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\001");
95 static PIPSocket::Address broadcast6(16,(const BYTE *)"\377\002\0\0\0\0\0\0\0\0\0\0\0\0\0\001"); // IPV6 multicast address
96 static PIPSocket::Address any6(16,(const BYTE *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
97 
98 #define IPV6_PARAM(p) p
99 #else
100 #define IPV6_PARAM(p)
101 #endif
102 
103 
SetSuppressCanonicalName(bool suppress)104 void PIPSocket::SetSuppressCanonicalName(bool suppress)
105 {
106   g_suppressCanonicalName = suppress;
107 }
108 
109 
GetSuppressCanonicalName()110 bool PIPSocket::GetSuppressCanonicalName()
111 {
112   return g_suppressCanonicalName;
113 }
114 
115 
GetDefaultIpAddressFamily()116 int PIPSocket::GetDefaultIpAddressFamily()
117 {
118   return g_defaultIpAddressFamily;
119 }
120 
121 
SetDefaultIpAddressFamily(int ipAdressFamily)122 void PIPSocket::SetDefaultIpAddressFamily(int ipAdressFamily)
123 {
124   g_defaultIpAddressFamily = ipAdressFamily;
125 }
126 
127 
SetDefaultIpAddressFamilyV4()128 void PIPSocket::SetDefaultIpAddressFamilyV4()
129 {
130   SetDefaultIpAddressFamily(PF_INET);
131 }
132 
133 
134 #if P_HAS_IPV6
135 
SetDefaultIpAddressFamilyV6()136 void PIPSocket::SetDefaultIpAddressFamilyV6()
137 {
138   SetDefaultIpAddressFamily(PF_INET6);
139 }
140 
SetDefaultV6ScopeId(int scopeId)141 void PIPSocket::SetDefaultV6ScopeId(int scopeId)
142 {
143   defaultIPv6ScopeId = scopeId;
144 };
145 
GetDefaultV6ScopeId()146 int PIPSocket::GetDefaultV6ScopeId()
147 {
148   return defaultIPv6ScopeId;
149 }
150 
IsIpAddressFamilyV6Supported()151 PBoolean PIPSocket::IsIpAddressFamilyV6Supported()
152 {
153   int s = ::socket(PF_INET6, SOCK_DGRAM, 0);
154   if (s < 0)
155     return PFalse;
156 
157 #if _WIN32
158   closesocket(s);
159 #else
160   _close(s);
161 #endif
162   return PTrue;
163 }
164 
165 #endif
166 
167 
GetDefaultIpAny()168 PIPSocket::Address PIPSocket::GetDefaultIpAny()
169 {
170 #if P_HAS_IPV6
171   if (g_defaultIpAddressFamily != PF_INET)
172     return any6;
173 #endif
174 
175   return any4;
176 }
177 
178 
179 #if P_HAS_IPV6
180 
181 class Psockaddr
182 {
183   public:
Psockaddr()184     Psockaddr() : ptr(&storage) { memset(&storage, 0, sizeof(storage)); }
185     Psockaddr(const PIPSocket::Address & ip, WORD port);
operator ->() const186     sockaddr* operator->() const { return addr; }
operator sockaddr*() const187     operator sockaddr*()   const { return addr; }
188     socklen_t GetSize() const;
189     PIPSocket::Address GetIP() const;
190     WORD GetPort() const;
191   private:
192     sockaddr_storage storage;
193     union {
194       sockaddr_storage * ptr;
195       sockaddr         * addr;
196       sockaddr_in      * addr4;
197       sockaddr_in6     * addr6;
198     };
199 };
200 
201 
Psockaddr(const PIPSocket::Address & ip,WORD port)202 Psockaddr::Psockaddr(const PIPSocket::Address & ip, WORD port)
203  : ptr(&storage)
204 {
205   memset(&storage, 0, sizeof(storage));
206 
207   if (ip.GetVersion() == 6) {
208     addr6->sin6_family = AF_INET6;
209     addr6->sin6_addr = ip;
210     addr6->sin6_port = htons(port);
211     addr6->sin6_flowinfo = 0;
212     addr6->sin6_scope_id = PIPSocket::GetDefaultV6ScopeId(); // Should be set to the right interface....
213   }
214   else {
215     addr4->sin_family = AF_INET;
216     addr4->sin_addr = ip;
217     addr4->sin_port = htons(port);
218   }
219 }
220 
221 
GetSize() const222 socklen_t Psockaddr::GetSize() const
223 {
224   switch (addr->sa_family) {
225     case AF_INET :
226       return sizeof(sockaddr_in);
227     case AF_INET6 :
228       // RFC 2133 (Old IPv6 spec) size is 24
229       // RFC 2553 (New IPv6 spec) size is 28
230       return sizeof(sockaddr_in6);
231     default :
232       return sizeof(storage);
233   }
234 }
235 
236 
GetIP() const237 PIPSocket::Address Psockaddr::GetIP() const
238 {
239   switch (addr->sa_family) {
240     case AF_INET :
241       return addr4->sin_addr;
242     case AF_INET6 :
243       return addr6->sin6_addr;
244     default :
245       return 0;
246   }
247 }
248 
249 
GetPort() const250 WORD Psockaddr::GetPort() const
251 {
252   switch (addr->sa_family) {
253     case AF_INET :
254       return ntohs(addr4->sin_port);
255     case AF_INET6 :
256       return ntohs(addr6->sin6_port);
257     default :
258       return 0;
259   }
260 }
261 
262 #endif
263 
264 
265 #if (defined(_WIN32) || defined(WINDOWS)) && !defined(__NUCLEUS_MNT__)
266 static PWinSock dummyForWinSock; // Assure winsock is initialised
267 #endif
268 
269 #if (defined(P_PTHREADS) && !defined(P_THREAD_SAFE_CLIB)) || defined(__NUCLEUS_PLUS__)
270 #define REENTRANT_BUFFER_LEN 1024
271 #endif
272 
273 
274 class PIPCacheData : public PObject
275 {
276   PCLASSINFO(PIPCacheData, PObject)
277   public:
278     PIPCacheData(struct hostent * ent, const char * original);
279 #if HAS_GETADDRINFO
280     PIPCacheData(struct addrinfo  * addr_info, const char * original);
281     void AddEntry(struct addrinfo  * addr_info);
282 #endif
GetHostName() const283     const PString & GetHostName() const { return hostname; }
GetHostAddress() const284     const PIPSocket::Address & GetHostAddress() const { return address; }
GetHostAliases() const285     const PStringArray& GetHostAliases() const { return aliases; }
286     PBoolean HasAged() const;
287   private:
288     PString            hostname;
289     PIPSocket::Address address;
290     PStringArray       aliases;
291     PTime              birthDate;
292 };
293 
294 
295 
296 PDICTIONARY(PHostByName_private, PCaselessString, PIPCacheData);
297 
298 class PHostByName : PHostByName_private
299 {
300   public:
301     PBoolean GetHostName(const PString & name, PString & hostname);
302     PBoolean GetHostAddress(const PString & name, PIPSocket::Address & address);
303     PBoolean GetHostAliases(const PString & name, PStringArray & aliases);
304   private:
305     PIPCacheData * GetHost(const PString & name);
306     PMutex mutex;
307   friend void PIPSocket::ClearNameCache();
308 };
309 
310 static PMutex creationMutex;
pHostByName()311 static PHostByName & pHostByName()
312 {
313   PWaitAndSignal m(creationMutex);
314   static PHostByName t;
315   return t;
316 }
317 
318 class PIPCacheKey : public PObject
319 {
320   PCLASSINFO(PIPCacheKey, PObject)
321   public:
PIPCacheKey(const PIPSocket::Address & a)322     PIPCacheKey(const PIPSocket::Address & a)
323       { addr = a; }
324 
Clone() const325     PObject * Clone() const
326       { return new PIPCacheKey(*this); }
327 
HashFunction() const328     PINDEX HashFunction() const
329       { return (addr[1] + addr[2] + addr[3])%41; }
330 
331   private:
332     PIPSocket::Address addr;
333 };
334 
335 PDICTIONARY(PHostByAddr_private, PIPCacheKey, PIPCacheData);
336 
337 class PHostByAddr : PHostByAddr_private
338 {
339   public:
340     PBoolean GetHostName(const PIPSocket::Address & addr, PString & hostname);
341     PBoolean GetHostAddress(const PIPSocket::Address & addr, PIPSocket::Address & address);
342     PBoolean GetHostAliases(const PIPSocket::Address & addr, PStringArray & aliases);
343   private:
344     PIPCacheData * GetHost(const PIPSocket::Address & addr);
345     PMutex mutex;
346   friend void PIPSocket::ClearNameCache();
347 };
348 
pHostByAddr()349 static PHostByAddr & pHostByAddr()
350 {
351   PWaitAndSignal m(creationMutex);
352   static PHostByAddr t;
353   return t;
354 }
355 
356 #define new PNEW
357 
358 
359 //////////////////////////////////////////////////////////////////////////////
360 // IP Caching
361 
PIPCacheData(struct hostent * host_info,const char * original)362 PIPCacheData::PIPCacheData(struct hostent * host_info, const char * original)
363 {
364   if (host_info == NULL) {
365     address = 0;
366     return;
367   }
368 
369   hostname = host_info->h_name;
370   if (host_info->h_addr != NULL)
371 #ifndef _WIN32_WCE
372     address = *(DWORD *)host_info->h_addr;
373 #else
374     address = PIPSocket::Address(host_info->h_length, (const BYTE *)host_info->h_addr);
375 #endif
376   aliases.AppendString(host_info->h_name);
377 
378   PINDEX i;
379   for (i = 0; host_info->h_aliases[i] != NULL; i++)
380     aliases.AppendString(host_info->h_aliases[i]);
381 
382   for (i = 0; host_info->h_addr_list[i] != NULL; i++) {
383 #ifndef _WIN32_WCE
384     PIPSocket::Address ip(*(DWORD *)host_info->h_addr_list[i]);
385 #else
386     PIPSocket::Address ip(host_info->h_length, (const BYTE *)host_info->h_addr_list[i]);
387 #endif
388     aliases.AppendString(ip.AsString());
389   }
390 
391   for (i = 0; i < aliases.GetSize(); i++)
392     if (aliases[i] *= original)
393       return;
394 
395   aliases.AppendString(original);
396 }
397 
398 
399 #if HAS_GETADDRINFO
400 
PIPCacheData(struct addrinfo * addr_info,const char * original)401 PIPCacheData::PIPCacheData(struct addrinfo * addr_info, const char * original)
402 {
403   PINDEX i;
404   if (addr_info == NULL) {
405     address = 0;
406     return;
407   }
408 
409   // Fill Host primary informations
410   hostname = addr_info->ai_canonname; // Fully Qualified Domain Name (FQDN)
411   if (g_suppressCanonicalName || hostname.IsEmpty())
412     hostname = original;
413   if (addr_info->ai_addr != NULL)
414     address = PIPSocket::Address(addr_info->ai_family, addr_info->ai_addrlen, addr_info->ai_addr);
415 
416   // Next entries
417   while (addr_info != NULL) {
418     AddEntry(addr_info);
419     addr_info = addr_info->ai_next;
420   }
421 
422   // Add original as alias or allready added ?
423   for (i = 0; i < aliases.GetSize(); i++) {
424     if (aliases[i] *= original)
425       return;
426   }
427 
428   aliases.AppendString(original);
429 }
430 
431 
AddEntry(struct addrinfo * addr_info)432 void PIPCacheData::AddEntry(struct addrinfo * addr_info)
433 {
434   PINDEX i;
435 
436   if (addr_info == NULL)
437     return;
438 
439   // Add canonical name
440   PBoolean add_it = PTrue;
441   for (i = 0; i < aliases.GetSize(); i++) {
442     if (addr_info->ai_canonname != NULL && (aliases[i] *= addr_info->ai_canonname)) {
443       add_it = PFalse;
444       break;
445     }
446   }
447 
448   if (add_it && addr_info->ai_canonname != NULL)
449     aliases.AppendString(addr_info->ai_canonname);
450 
451   // Add IP address
452   PIPSocket::Address ip(addr_info->ai_family, addr_info->ai_addrlen, addr_info->ai_addr);
453   add_it = PTrue;
454   for (i = 0; i < aliases.GetSize(); i++) {
455     if (aliases[i] *= ip.AsString()) {
456       add_it = PFalse;
457       break;
458     }
459   }
460 
461   if (add_it)
462     aliases.AppendString(ip.AsString());
463 }
464 
465 #endif // HAS_GETADDRINFO
466 
467 
GetConfigTime(const char *,DWORD dflt)468 static PTimeInterval GetConfigTime(const char * /*key*/, DWORD dflt)
469 {
470   //PConfig cfg("DNS Cache");
471   //return cfg.GetInteger(key, dflt);
472   return dflt;
473 }
474 
475 
HasAged() const476 PBoolean PIPCacheData::HasAged() const
477 {
478   static PTimeInterval retirement = GetConfigTime("Age Limit", 300000); // 5 minutes
479   PTime now;
480   PTimeInterval age = now - birthDate;
481   return age > retirement;
482 }
483 
484 
GetHostName(const PString & name,PString & hostname)485 PBoolean PHostByName::GetHostName(const PString & name, PString & hostname)
486 {
487   PIPCacheData * host = GetHost(name);
488 
489   if (host != NULL) {
490     hostname = host->GetHostName();
491     hostname.MakeUnique();
492   }
493 
494   mutex.Signal();
495 
496   return host != NULL;
497 }
498 
499 
GetHostAddress(const PString & name,PIPSocket::Address & address)500 PBoolean PHostByName::GetHostAddress(const PString & name, PIPSocket::Address & address)
501 {
502   PIPCacheData * host = GetHost(name);
503 
504   if (host != NULL)
505     address = host->GetHostAddress();
506 
507   mutex.Signal();
508 
509   return host != NULL;
510 }
511 
512 
GetHostAliases(const PString & name,PStringArray & aliases)513 PBoolean PHostByName::GetHostAliases(const PString & name, PStringArray & aliases)
514 {
515   PIPCacheData * host = GetHost(name);
516 
517   if (host != NULL)
518     aliases = host->GetHostAliases();
519 
520   mutex.Signal();
521   return host != NULL;
522 }
523 
524 
GetHost(const PString & name)525 PIPCacheData * PHostByName::GetHost(const PString & name)
526 {
527   mutex.Wait();
528 
529   PString key = name;
530   PINDEX len = key.GetLength();
531 
532   // Check for a legal hostname as per RFC952
533   // but drop the requirement for leading alpha as per RFC 1123
534   if (key.IsEmpty() ||
535       key.FindSpan("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.") != P_MAX_INDEX ||
536       key[len-1] == '-') {
537     PTRACE(3, "Socket\tIllegal RFC952 characters in DNS name \"" << key << '"');
538     return NULL;
539   }
540 
541   // We lowercase this way rather than toupper() as that is locale dependent, and DNS names aren't.
542   for (PINDEX i = 0; i < len; i++) {
543     if (key[i] >= 'a')
544       key[i] &= 0x5f;
545   }
546 
547   PIPCacheData * host = GetAt(key);
548   int localErrNo = NO_DATA;
549 
550   if (host != NULL && host->HasAged()) {
551     SetAt(key, NULL);
552     host = NULL;
553   }
554 
555   if (host == NULL) {
556     mutex.Signal();
557 
558 #if HAS_GETADDRINFO
559 
560     struct addrinfo *res = NULL;
561     struct addrinfo hints;
562     memset(&hints, 0, sizeof(hints));
563     if (!g_suppressCanonicalName)
564       hints.ai_flags = AI_CANONNAME;
565     hints.ai_family = g_defaultIpAddressFamily;
566     localErrNo = getaddrinfo((const char *)name, NULL , &hints, &res);
567     if (localErrNo != 0 && g_defaultIpAddressFamily == AF_INET6) {
568       hints.ai_family = AF_INET;
569       localErrNo = getaddrinfo((const char *)name, NULL , &hints, &res);
570     }
571     host = new PIPCacheData(localErrNo != NETDB_SUCCESS ? NULL : res, name);
572     if (res != NULL)
573       freeaddrinfo(res);
574 
575 #else // HAS_GETADDRINFO
576 
577     int retry = 3;
578     struct hostent * host_info;
579 
580 #ifdef P_AIX
581 
582     struct hostent_data ht_data;
583     memset(&ht_data, 0, sizeof(ht_data));
584     struct hostent hostEnt;
585     do {
586       host_info = &hostEnt;
587       ::gethostbyname_r(name,
588                         host_info,
589                         &ht_data);
590       localErrNo = h_errno;
591     } while (localErrNo == TRY_AGAIN && --retry > 0);
592 
593 #elif defined(P_RTEMS) || defined(P_CYGWIN) || defined(P_MINGW)
594 
595     host_info = ::gethostbyname(name);
596     localErrNo = h_errno;
597 
598 #elif defined P_VXWORKS
599 
600     struct hostent hostEnt;
601     host_info = Vx_gethostbyname((char *)name, &hostEnt);
602     localErrNo = h_errno;
603 
604 #elif defined P_LINUX || defined(P_GNU_HURD)
605 
606     char buffer[REENTRANT_BUFFER_LEN];
607     struct hostent hostEnt;
608     do {
609       if (::gethostbyname_r(name,
610                             &hostEnt,
611                             buffer, REENTRANT_BUFFER_LEN,
612                             &host_info,
613                             &localErrNo) == 0)
614         localErrNo = NETDB_SUCCESS;
615     } while (localErrNo == TRY_AGAIN && --retry > 0);
616 
617 #elif (defined(P_PTHREADS) && !defined(P_THREAD_SAFE_CLIB)) || defined(__NUCLEUS_PLUS__)
618 
619     char buffer[REENTRANT_BUFFER_LEN];
620     struct hostent hostEnt;
621     do {
622       host_info = ::gethostbyname_r(name,
623                                     &hostEnt,
624                                     buffer, REENTRANT_BUFFER_LEN,
625                                     &localErrNo);
626     } while (localErrNo == TRY_AGAIN && --retry > 0);
627 
628 #else
629 
630     host_info = ::gethostbyname(name);
631     localErrNo = h_errno;
632 
633 #endif
634 
635     if (localErrNo != NETDB_SUCCESS || retry == 0)
636       host_info = NULL;
637     host = new PIPCacheData(host_info, name);
638 
639 #endif //HAS_GETADDRINFO
640 
641     mutex.Wait();
642 
643     SetAt(key, host);
644   }
645 
646   if (host->GetHostAddress().IsValid())
647     return host;
648 
649   PTRACE(4, "Socket\tName lookup of \"" << name << "\" failed: errno=" << localErrNo);
650   return NULL;
651 }
652 
653 
GetHostName(const PIPSocket::Address & addr,PString & hostname)654 PBoolean PHostByAddr::GetHostName(const PIPSocket::Address & addr, PString & hostname)
655 {
656   PIPCacheData * host = GetHost(addr);
657 
658   if (host != NULL) {
659     hostname = host->GetHostName();
660     hostname.MakeUnique();
661   }
662 
663   mutex.Signal();
664   return host != NULL;
665 }
666 
667 
GetHostAddress(const PIPSocket::Address & addr,PIPSocket::Address & address)668 PBoolean PHostByAddr::GetHostAddress(const PIPSocket::Address & addr, PIPSocket::Address & address)
669 {
670   PIPCacheData * host = GetHost(addr);
671 
672   if (host != NULL)
673     address = host->GetHostAddress();
674 
675   mutex.Signal();
676   return host != NULL;
677 }
678 
679 
GetHostAliases(const PIPSocket::Address & addr,PStringArray & aliases)680 PBoolean PHostByAddr::GetHostAliases(const PIPSocket::Address & addr, PStringArray & aliases)
681 {
682   PIPCacheData * host = GetHost(addr);
683 
684   if (host != NULL)
685     aliases = host->GetHostAliases();
686 
687   mutex.Signal();
688   return host != NULL;
689 }
690 
GetHost(const PIPSocket::Address & addr)691 PIPCacheData * PHostByAddr::GetHost(const PIPSocket::Address & addr)
692 {
693   mutex.Wait();
694 
695   PIPCacheKey key = addr;
696   PIPCacheData * host = GetAt(key);
697 
698   if (host != NULL && host->HasAged()) {
699     SetAt(key, NULL);
700     host = NULL;
701   }
702 
703   if (host == NULL) {
704     mutex.Signal();
705 
706     int retry = 3;
707     int localErrNo = NETDB_SUCCESS;
708     struct hostent * host_info;
709 
710 #ifdef P_AIX
711 
712     struct hostent_data ht_data;
713     struct hostent hostEnt;
714     do {
715       host_info = &hostEnt;
716       ::gethostbyaddr_r((char *)addr.GetPointer(), addr.GetSize(),
717                         PF_INET,
718                         host_info,
719                         &ht_data);
720       localErrNo = h_errno;
721     } while (localErrNo == TRY_AGAIN && --retry > 0);
722 
723 #elif defined P_RTEMS || defined P_CYGWIN || defined P_MINGW
724 
725     host_info = ::gethostbyaddr(addr.GetPointer(), addr.GetSize(), PF_INET);
726     localErrNo = h_errno;
727 
728 #elif defined P_VXWORKS
729 
730     struct hostent hostEnt;
731     host_info = Vx_gethostbyaddr(addr.GetPointer(), &hostEnt);
732 
733 #elif defined P_LINUX || defined(P_GNU_HURD)
734 
735     char buffer[REENTRANT_BUFFER_LEN];
736     struct hostent hostEnt;
737     do {
738       ::gethostbyaddr_r(addr.GetPointer(), addr.GetSize(),
739                         PF_INET,
740                         &hostEnt,
741                         buffer, REENTRANT_BUFFER_LEN,
742                         &host_info,
743                         &localErrNo);
744     } while (localErrNo == TRY_AGAIN && --retry > 0);
745 
746 #elif (defined(P_PTHREADS) && !defined(P_THREAD_SAFE_CLIB)) || defined(__NUCLEUS_PLUS__)
747 
748     char buffer[REENTRANT_BUFFER_LEN];
749     struct hostent hostEnt;
750     do {
751       host_info = ::gethostbyaddr_r(addr.GetPointer(), addr.GetSize(),
752                                     PF_INET,
753                                     &hostEnt,
754                                     buffer, REENTRANT_BUFFER_LEN,
755                                     &localErrNo);
756     } while (localErrNo == TRY_AGAIN && --retry > 0);
757 
758 #else
759 
760     host_info = ::gethostbyaddr(addr.GetPointer(), addr.GetSize(), PF_INET);
761     localErrNo = h_errno;
762 
763 #if defined(_WIN32) || defined(WINDOWS)  // Kludge to avoid strange 95 bug
764     extern PBoolean P_IsOldWin95();
765     if (P_IsOldWin95() && host_info != NULL && host_info->h_addr_list[0] != NULL)
766       host_info->h_addr_list[1] = NULL;
767 #endif
768 
769 #endif
770 
771     mutex.Wait();
772 
773     if (localErrNo != NETDB_SUCCESS || retry == 0)
774       return NULL;
775 
776     host = new PIPCacheData(host_info, addr.AsString());
777 
778     SetAt(key, host);
779   }
780 
781   return host->GetHostAddress().IsValid() ? host : NULL;
782 }
783 
784 
785 //////////////////////////////////////////////////////////////////////////////
786 // P_fd_set
787 
788 #ifdef _MSC_VER
789 #pragma warning(push)
790 #pragma warning(disable:4127)
791 #endif
792 
P_fd_set()793 P_fd_set::P_fd_set()
794 {
795   Construct();
796   Zero();
797 }
798 
799 
P_fd_set(SOCKET fd)800 P_fd_set::P_fd_set(SOCKET fd)
801 {
802   Construct();
803   Zero();
804   FD_SET(fd, set);
805 }
806 
807 
operator =(SOCKET fd)808 P_fd_set & P_fd_set::operator=(SOCKET fd)
809 {
810   PAssert(fd < max_fd, PInvalidParameter);
811   Zero();
812   FD_SET(fd, set);
813   return *this;
814 }
815 
816 
operator +=(SOCKET fd)817 P_fd_set & P_fd_set::operator+=(SOCKET fd)
818 {
819   PAssert(fd < max_fd, PInvalidParameter);
820   FD_SET(fd, set);
821   return *this;
822 }
823 
824 
operator -=(SOCKET fd)825 P_fd_set & P_fd_set::operator-=(SOCKET fd)
826 {
827   PAssert(fd < max_fd, PInvalidParameter);
828   FD_CLR(fd, set);
829   return *this;
830 }
831 
832 #ifdef _MSC_VER
833 #pragma warning(pop)
834 #endif
835 
836 
837 //////////////////////////////////////////////////////////////////////////////
838 // P_timeval
839 
P_timeval()840 P_timeval::P_timeval()
841 {
842   tval.tv_usec = 0;
843   tval.tv_sec = 0;
844   infinite = PFalse;
845 }
846 
847 
operator =(const PTimeInterval & time)848 P_timeval & P_timeval::operator=(const PTimeInterval & time)
849 {
850   infinite = time == PMaxTimeInterval;
851   tval.tv_usec = (long)(time.GetMilliSeconds()%1000)*1000;
852   tval.tv_sec = time.GetSeconds();
853   return *this;
854 }
855 
856 
857 //////////////////////////////////////////////////////////////////////////////
858 // PSocket
859 
PSocket()860 PSocket::PSocket()
861 {
862   port = 0;
863 #if P_HAS_RECVMSG
864   catchReceiveToAddr = PFalse;
865 #endif
866 }
867 
868 
Connect(const PString &)869 PBoolean PSocket::Connect(const PString &)
870 {
871   PAssertAlways("Illegal operation.");
872   return PFalse;
873 }
874 
875 
Listen(unsigned,WORD,Reusability)876 PBoolean PSocket::Listen(unsigned, WORD, Reusability)
877 {
878   PAssertAlways("Illegal operation.");
879   return PFalse;
880 }
881 
882 
Accept(PSocket &)883 PBoolean PSocket::Accept(PSocket &)
884 {
885   PAssertAlways("Illegal operation.");
886   return PFalse;
887 }
888 
889 
SetOption(int option,int value,int level)890 PBoolean PSocket::SetOption(int option, int value, int level)
891 {
892 #ifdef _WIN32_WCE
893   if(option == SO_RCVBUF || option == SO_SNDBUF || option == IP_TOS)
894     return PTrue;
895 #endif
896 
897   return ConvertOSError(::setsockopt(os_handle, level, option,
898                                      (char *)&value, sizeof(value)));
899 }
900 
901 
SetOption(int option,const void * valuePtr,PINDEX valueSize,int level)902 PBoolean PSocket::SetOption(int option, const void * valuePtr, PINDEX valueSize, int level)
903 {
904   return ConvertOSError(::setsockopt(os_handle, level, option,
905                                      (char *)valuePtr, valueSize));
906 }
907 
908 
GetOption(int option,int & value,int level)909 PBoolean PSocket::GetOption(int option, int & value, int level)
910 {
911   socklen_t valSize = sizeof(value);
912   return ConvertOSError(::getsockopt(os_handle, level, option,
913                                      (char *)&value, &valSize));
914 }
915 
916 
GetOption(int option,void * valuePtr,PINDEX valueSize,int level)917 PBoolean PSocket::GetOption(int option, void * valuePtr, PINDEX valueSize, int level)
918 {
919   return ConvertOSError(::getsockopt(os_handle, level, option,
920                                      (char *)valuePtr, (socklen_t *)&valueSize));
921 }
922 
923 
Shutdown(ShutdownValue value)924 PBoolean PSocket::Shutdown(ShutdownValue value)
925 {
926   return ConvertOSError(::shutdown(os_handle, value));
927 }
928 
929 
GetProtocolByName(const PString & name)930 WORD PSocket::GetProtocolByName(const PString & name)
931 {
932 #if !defined(__NUCLEUS_PLUS__) && !defined(P_VXWORKS)
933   struct protoent * ent = getprotobyname(name);
934   if (ent != NULL)
935     return ent->p_proto;
936 #endif
937 
938   return 0;
939 }
940 
941 
GetNameByProtocol(WORD proto)942 PString PSocket::GetNameByProtocol(WORD proto)
943 {
944 #if !defined(__NUCLEUS_PLUS__) && !defined(P_VXWORKS)
945   struct protoent * ent = getprotobynumber(proto);
946   if (ent != NULL)
947     return ent->p_name;
948 #endif
949 
950   return psprintf("%u", proto);
951 }
952 
953 
GetPortByService(const PString & serviceName) const954 WORD PSocket::GetPortByService(const PString & serviceName) const
955 {
956   return GetPortByService(GetProtocolName(), serviceName);
957 }
958 
959 
GetPortByService(const char * protocol,const PString & service)960 WORD PSocket::GetPortByService(const char * protocol, const PString & service)
961 {
962   // if the string is a valid integer, then use integer value
963   // this avoids stupid problems like operating systems that match service
964   // names to substrings (like "2000" to "taskmaster2000")
965   if (service.FindSpan("0123456789") == P_MAX_INDEX)
966     return (WORD)service.AsUnsigned();
967 
968 #if defined( __NUCLEUS_PLUS__ )
969   PAssertAlways("PSocket::GetPortByService: problem as no ::getservbyname in Nucleus NET");
970   return 0;
971 #elif defined(P_VXWORKS)
972   PAssertAlways("PSocket::GetPortByService: problem as no ::getservbyname in VxWorks");
973   return 0;
974 #else
975   PINDEX space = service.FindOneOf(" \t\r\n");
976   struct servent * serv = ::getservbyname(service(0, space-1), protocol);
977   if (serv != NULL)
978     return ntohs(serv->s_port);
979 
980   long portNum;
981   if (space != P_MAX_INDEX)
982     portNum = atol(service(space+1, P_MAX_INDEX));
983   else if (isdigit(service[0]))
984     portNum = atoi(service);
985   else
986     portNum = -1;
987 
988   if (portNum < 0 || portNum > 65535)
989     return 0;
990 
991   return (WORD)portNum;
992 #endif
993 }
994 
995 
GetServiceByPort(WORD port) const996 PString PSocket::GetServiceByPort(WORD port) const
997 {
998   return GetServiceByPort(GetProtocolName(), port);
999 }
1000 
1001 
GetServiceByPort(const char * protocol,WORD port)1002 PString PSocket::GetServiceByPort(const char * protocol, WORD port)
1003 {
1004 #if !defined(__NUCLEUS_PLUS__) && !defined(P_VXWORKS)
1005   struct servent * serv = ::getservbyport(htons(port), protocol);
1006   if (serv != NULL)
1007     return PString(serv->s_name);
1008   else
1009 #endif
1010     return PString(PString::Unsigned, port);
1011 }
1012 
1013 
SetPort(WORD newPort)1014 void PSocket::SetPort(WORD newPort)
1015 {
1016   PAssert(!IsOpen(), "Cannot change port number of opened socket");
1017   port = newPort;
1018 }
1019 
1020 
SetPort(const PString & service)1021 void PSocket::SetPort(const PString & service)
1022 {
1023   PAssert(!IsOpen(), "Cannot change port number of opened socket");
1024   port = GetPortByService(service);
1025 }
1026 
1027 
GetPort() const1028 WORD PSocket::GetPort() const
1029 {
1030   return port;
1031 }
1032 
1033 
GetService() const1034 PString PSocket::GetService() const
1035 {
1036   return GetServiceByPort(port);
1037 }
1038 
1039 
Select(PSocket & sock1,PSocket & sock2)1040 int PSocket::Select(PSocket & sock1, PSocket & sock2)
1041 {
1042   return Select(sock1, sock2, PMaxTimeInterval);
1043 }
1044 
1045 
Select(PSocket & sock1,PSocket & sock2,const PTimeInterval & timeout)1046 int PSocket::Select(PSocket & sock1,
1047                     PSocket & sock2,
1048                     const PTimeInterval & timeout)
1049 {
1050   SelectList read, dummy1, dummy2;
1051   read += sock1;
1052   read += sock2;
1053 
1054   Errors lastError;
1055   int osError;
1056   if (!ConvertOSError(Select(read, dummy1, dummy2, timeout), lastError, osError))
1057     return lastError;
1058 
1059   switch (read.GetSize()) {
1060     case 0 :
1061       return 0;
1062     case 2 :
1063       return -3;
1064     default :
1065       return &read.front() == &sock1 ? -1 : -2;
1066   }
1067 }
1068 
1069 
Select(SelectList & read)1070 PChannel::Errors PSocket::Select(SelectList & read)
1071 {
1072   SelectList dummy1, dummy2;
1073   return Select(read, dummy1, dummy2, PMaxTimeInterval);
1074 }
1075 
1076 
Select(SelectList & read,const PTimeInterval & timeout)1077 PChannel::Errors PSocket::Select(SelectList & read, const PTimeInterval & timeout)
1078 {
1079   SelectList dummy1, dummy2;
1080   return Select(read, dummy1, dummy2, timeout);
1081 }
1082 
1083 
Select(SelectList & read,SelectList & write)1084 PChannel::Errors PSocket::Select(SelectList & read, SelectList & write)
1085 {
1086   SelectList dummy1;
1087   return Select(read, write, dummy1, PMaxTimeInterval);
1088 }
1089 
1090 
Select(SelectList & read,SelectList & write,const PTimeInterval & timeout)1091 PChannel::Errors PSocket::Select(SelectList & read,
1092                                  SelectList & write,
1093                                  const PTimeInterval & timeout)
1094 {
1095   SelectList dummy1;
1096   return Select(read, write, dummy1, timeout);
1097 }
1098 
1099 
Select(SelectList & read,SelectList & write,SelectList & except)1100 PChannel::Errors PSocket::Select(SelectList & read,
1101                                  SelectList & write,
1102                                  SelectList & except)
1103 {
1104   return Select(read, write, except, PMaxTimeInterval);
1105 }
1106 
1107 
1108 //////////////////////////////////////////////////////////////////////////////
1109 // PIPSocket
1110 
PIPSocket()1111 PIPSocket::PIPSocket()
1112 {
1113 }
1114 
1115 
ClearNameCache()1116 void PIPSocket::ClearNameCache()
1117 {
1118   pHostByName().mutex.Wait();
1119   pHostByName().RemoveAll();
1120   pHostByName().mutex.Signal();
1121 
1122   pHostByAddr().mutex.Wait();
1123   pHostByAddr().RemoveAll();
1124   pHostByAddr().mutex.Signal();
1125 
1126 #if (defined(_WIN32) || defined(WINDOWS)) && !defined(__NUCLEUS_MNT__) // Kludge to avoid strange NT bug
1127   static PTimeInterval delay = GetConfigTime("NT Bug Delay", 0);
1128   if (delay != 0) {
1129     ::Sleep(delay.GetInterval());
1130     ::gethostbyname("www.microsoft.com");
1131   }
1132 #endif
1133   PTRACE(4, "Socket\tCleared DNS cache.");
1134 }
1135 
1136 
GetName() const1137 PString PIPSocket::GetName() const
1138 {
1139 #if P_HAS_IPV6
1140 
1141   Psockaddr sa;
1142   socklen_t size = sa.GetSize();
1143   if (getpeername(os_handle, sa, &size) == 0)
1144     return GetHostName(sa.GetIP()) + psprintf(":%u", sa.GetPort());
1145 
1146 #else
1147 
1148   sockaddr_in address;
1149   socklen_t size = sizeof(address);
1150   if (getpeername(os_handle, (struct sockaddr *)&address, &size) == 0)
1151     return GetHostName(address.sin_addr) + psprintf(":%u", ntohs(address.sin_port));
1152 
1153 #endif
1154 
1155   return PString::Empty();
1156 }
1157 
1158 
GetHostName()1159 PString PIPSocket::GetHostName()
1160 {
1161   char name[100];
1162   if (gethostname(name, sizeof(name)-1) != 0)
1163     return "localhost";
1164   name[sizeof(name)-1] = '\0';
1165   return name;
1166 }
1167 
1168 
GetHostName(const PString & hostname)1169 PString PIPSocket::GetHostName(const PString & hostname)
1170 {
1171   // lookup the host address using inet_addr, assuming it is a "." address
1172   Address temp = hostname;
1173   if (temp.IsValid())
1174     return GetHostName(temp);
1175 
1176   PString canonicalname;
1177   if (pHostByName().GetHostName(hostname, canonicalname))
1178     return canonicalname;
1179 
1180   return hostname;
1181 }
1182 
1183 
GetHostName(const Address & addr)1184 PString PIPSocket::GetHostName(const Address & addr)
1185 {
1186   if (!addr.IsValid())
1187     return addr.AsString();
1188 
1189   PString hostname;
1190   if (pHostByAddr().GetHostName(addr, hostname))
1191     return hostname;
1192 
1193 #if P_HAS_IPV6
1194   if (addr.GetVersion() == 6)
1195     return '[' + addr.AsString() + ']';
1196 #endif
1197 
1198   return addr.AsString();
1199 }
1200 
1201 
GetHostAddress(Address & addr)1202 PBoolean PIPSocket::GetHostAddress(Address & addr)
1203 {
1204   return pHostByName().GetHostAddress(GetHostName(), addr);
1205 }
1206 
1207 
GetHostAddress(const PString & hostname,Address & addr)1208 PBoolean PIPSocket::GetHostAddress(const PString & hostname, Address & addr)
1209 {
1210   if (hostname.IsEmpty())
1211     return PFalse;
1212 
1213   // Check for special case of "[ipaddr]"
1214   if (hostname[0] == '[') {
1215     PINDEX end = hostname.Find(']');
1216     if (end != P_MAX_INDEX) {
1217       if (addr.FromString(hostname(1, end-1)))
1218         return PTrue;
1219     }
1220   }
1221 
1222   // Assuming it is a "." address and return if so
1223   if (addr.FromString(hostname))
1224     return PTrue;
1225 
1226   // otherwise lookup the name as a host name
1227   return pHostByName().GetHostAddress(hostname, addr);
1228 }
1229 
1230 
GetHostAliases(const PString & hostname)1231 PStringArray PIPSocket::GetHostAliases(const PString & hostname)
1232 {
1233   PStringArray aliases;
1234 
1235   // lookup the host address using inet_addr, assuming it is a "." address
1236   Address addr = hostname;
1237   if (addr.IsValid())
1238     pHostByAddr().GetHostAliases(addr, aliases);
1239   else
1240     pHostByName().GetHostAliases(hostname, aliases);
1241 
1242   return aliases;
1243 }
1244 
1245 
GetHostAliases(const Address & addr)1246 PStringArray PIPSocket::GetHostAliases(const Address & addr)
1247 {
1248   PStringArray aliases;
1249 
1250   pHostByAddr().GetHostAliases(addr, aliases);
1251 
1252   return aliases;
1253 }
1254 
1255 
GetLocalAddress()1256 PString PIPSocket::GetLocalAddress()
1257 {
1258   PStringStream str;
1259   Address addr;
1260   WORD port;
1261   if (GetLocalAddress(addr, port))
1262     str << addr << ':' << port;
1263   return str;
1264 }
1265 
1266 
GetLocalAddress(Address & addr)1267 PBoolean PIPSocket::GetLocalAddress(Address & addr)
1268 {
1269   WORD dummy;
1270   return GetLocalAddress(addr, dummy);
1271 }
1272 
1273 
GetLocalAddress(PIPSocketAddressAndPort & addr)1274 PBoolean PIPSocket::GetLocalAddress(PIPSocketAddressAndPort & addr)
1275 {
1276   Address ip;
1277   WORD port;
1278   if (!GetLocalAddress(ip, port))
1279     return false;
1280 
1281   addr.SetAddress(ip, port);
1282   return true;
1283 }
1284 
1285 
GetLocalAddress(Address & addr,WORD & portNum)1286 PBoolean PIPSocket::GetLocalAddress(Address & addr, WORD & portNum)
1287 {
1288 #if P_HAS_IPV6
1289   Address   addrv4;
1290   Address   peerv4;
1291   Psockaddr sa;
1292   socklen_t size = sa.GetSize();
1293   if (!ConvertOSError(::getsockname(os_handle, sa, &size)))
1294     return PFalse;
1295 
1296   addr = sa.GetIP();
1297   portNum = sa.GetPort();
1298 
1299   // If the remote host is an IPv4 only host and our interface if an IPv4/IPv6 mapped
1300   // Then return an IPv4 address instead of an IPv6
1301   if (GetPeerAddress(peerv4)) {
1302     if ((peerv4.GetVersion()==4)||(peerv4.IsV4Mapped())) {
1303       if (addr.IsV4Mapped()) {
1304         addr = Address(addr[12], addr[13], addr[14], addr[15]);
1305       }
1306     }
1307   }
1308 
1309 #else
1310 
1311   sockaddr_in address;
1312   socklen_t size = sizeof(address);
1313   if (!ConvertOSError(::getsockname(os_handle,(struct sockaddr*)&address,&size)))
1314     return PFalse;
1315 
1316   addr = address.sin_addr;
1317   portNum = ntohs(address.sin_port);
1318 
1319 #endif
1320 
1321   return PTrue;
1322 }
1323 
1324 
GetPeerAddress()1325 PString PIPSocket::GetPeerAddress()
1326 {
1327   PStringStream str;
1328   Address addr;
1329   WORD port;
1330   if (GetPeerAddress(addr, port))
1331     str << addr << ':' << port;
1332   return str;
1333 }
1334 
1335 
GetPeerAddress(Address & addr)1336 PBoolean PIPSocket::GetPeerAddress(Address & addr)
1337 {
1338   WORD portNum;
1339   return GetPeerAddress(addr, portNum);
1340 }
1341 
1342 
GetPeerAddress(PIPSocketAddressAndPort & addr)1343 PBoolean PIPSocket::GetPeerAddress(PIPSocketAddressAndPort & addr)
1344 {
1345   Address ip;
1346   WORD port;
1347   if (!GetPeerAddress(ip, port))
1348     return false;
1349 
1350   addr.SetAddress(ip, port);
1351   return true;
1352 }
1353 
1354 
GetPeerAddress(Address & addr,WORD & portNum)1355 PBoolean PIPSocket::GetPeerAddress(Address & addr, WORD & portNum)
1356 {
1357 #if P_HAS_IPV6
1358 
1359   Psockaddr sa;
1360   socklen_t size = sa.GetSize();
1361   if (!ConvertOSError(::getpeername(os_handle, sa, &size)))
1362     return PFalse;
1363 
1364   addr = sa.GetIP();
1365   portNum = sa.GetPort();
1366 
1367 #else
1368 
1369   sockaddr_in address;
1370   socklen_t size = sizeof(address);
1371   if (!ConvertOSError(::getpeername(os_handle,(struct sockaddr*)&address,&size)))
1372     return PFalse;
1373 
1374   addr = address.sin_addr;
1375   portNum = ntohs(address.sin_port);
1376 
1377 #endif
1378 
1379   return PTrue;
1380 }
1381 
1382 
GetLocalHostName()1383 PString PIPSocket::GetLocalHostName()
1384 {
1385   Address addr;
1386 
1387   if (GetLocalAddress(addr))
1388     return GetHostName(addr);
1389 
1390   return PString::Empty();
1391 }
1392 
1393 
GetPeerHostName()1394 PString PIPSocket::GetPeerHostName()
1395 {
1396   Address addr;
1397 
1398   if (GetPeerAddress(addr))
1399     return GetHostName(addr);
1400 
1401   return PString::Empty();
1402 }
1403 
1404 
Connect(const PString & host)1405 PBoolean PIPSocket::Connect(const PString & host)
1406 {
1407   Address ipnum(host);
1408 #if P_HAS_IPV6
1409   if (ipnum.IsValid() || GetHostAddress(host, ipnum))
1410     return Connect(GetDefaultIpAny(), 0, ipnum);
1411 #else
1412   if (ipnum.IsValid() || GetHostAddress(host, ipnum))
1413     return Connect(INADDR_ANY, 0, ipnum);
1414 #endif
1415   return PFalse;
1416 }
1417 
1418 
Connect(const Address & addr)1419 PBoolean PIPSocket::Connect(const Address & addr)
1420 {
1421 #if P_HAS_IPV6
1422   return Connect(GetDefaultIpAny(), 0, addr);
1423 #else
1424   return Connect(INADDR_ANY, 0, addr);
1425 #endif
1426 }
1427 
1428 
Connect(WORD localPort,const Address & addr)1429 PBoolean PIPSocket::Connect(WORD localPort, const Address & addr)
1430 {
1431 #if P_HAS_IPV6
1432   return Connect(GetDefaultIpAny(), localPort, addr);
1433 #else
1434   return Connect(INADDR_ANY, localPort, addr);
1435 #endif
1436 }
1437 
1438 
Connect(const Address & iface,const Address & addr)1439 PBoolean PIPSocket::Connect(const Address & iface, const Address & addr)
1440 {
1441   return Connect(iface, 0, addr);
1442 }
1443 
1444 
Connect(const Address & iface,WORD localPort,const Address & addr)1445 PBoolean PIPSocket::Connect(const Address & iface, WORD localPort, const Address & addr)
1446 {
1447   // close the port if it is already open
1448   if (IsOpen())
1449     Close();
1450 
1451   // make sure we have a port
1452   PAssert(port != 0, "Cannot connect socket without setting port");
1453 
1454 #if P_HAS_IPV6
1455 
1456   Psockaddr sa(addr, port);
1457 
1458   // attempt to create a socket with the right family
1459   if (!OpenSocket(sa->sa_family))
1460     return PFalse;
1461 
1462   if (localPort != 0 || iface.IsValid()) {
1463     Psockaddr bind_sa(iface, localPort);
1464 
1465     if (!SetOption(SO_REUSEADDR, 0)) {
1466       os_close();
1467       return PFalse;
1468     }
1469 
1470     if (!ConvertOSError(::bind(os_handle, bind_sa, bind_sa.GetSize()))) {
1471       os_close();
1472       return PFalse;
1473     }
1474   }
1475 
1476   // attempt to connect
1477   if (os_connect(sa, sa.GetSize()))
1478     return PTrue;
1479 
1480 #else
1481 
1482   // attempt to create a socket
1483   if (!OpenSocket())
1484     return PFalse;
1485 
1486   // attempt to connect
1487   sockaddr_in sin;
1488   if (localPort != 0 || iface.IsValid()) {
1489     if (!SetOption(SO_REUSEADDR, 0)) {
1490       os_close();
1491       return PFalse;
1492     }
1493     memset(&sin, 0, sizeof(sin));
1494     sin.sin_family = AF_INET;
1495     sin.sin_addr.s_addr = iface;
1496     sin.sin_port        = htons(localPort);       // set the port
1497     if (!ConvertOSError(::bind(os_handle, (struct sockaddr*)&sin, sizeof(sin)))) {
1498       os_close();
1499       return PFalse;
1500     }
1501   }
1502 
1503   memset(&sin, 0, sizeof(sin));
1504   sin.sin_family = AF_INET;
1505   sin.sin_port   = htons(port);  // set the port
1506   sin.sin_addr   = addr;
1507   if (os_connect((struct sockaddr *)&sin, sizeof(sin)))
1508     return PTrue;
1509 
1510 #endif
1511 
1512   os_close();
1513   return PFalse;
1514 }
1515 
1516 
Listen(unsigned queueSize,WORD newPort,Reusability reuse)1517 PBoolean PIPSocket::Listen(unsigned queueSize, WORD newPort, Reusability reuse)
1518 {
1519 #if P_HAS_IPV6
1520   return Listen(GetDefaultIpAny(), queueSize, newPort, reuse);
1521 #else
1522   return Listen(INADDR_ANY, queueSize, newPort, reuse);
1523 #endif
1524 }
1525 
1526 
Listen(const Address & bindAddr,unsigned,WORD newPort,Reusability reuse)1527 PBoolean PIPSocket::Listen(const Address & bindAddr,
1528                        unsigned,
1529                        WORD newPort,
1530                        Reusability reuse)
1531 {
1532   // make sure we have a port
1533   if (newPort != 0)
1534     port = newPort;
1535 
1536 #if P_HAS_IPV6
1537   Psockaddr bind_sa(bindAddr, port);
1538 #endif
1539 
1540 #if P_HAS_IPV6
1541   // Always close and re-open as the bindAddr address family might change.
1542   Close();
1543 
1544   // attempt to create a socket
1545   if (!OpenSocket(bind_sa->sa_family))
1546     return PFalse;
1547 #else
1548   if (!IsOpen()) {
1549     if (!OpenSocket())
1550       return PFalse;
1551   }
1552 #endif
1553 
1554 #ifndef P_BEOS
1555 #if P_HAS_IPV6
1556   if(bind_sa->sa_family != AF_INET6)
1557 #endif
1558   {
1559    // attempt to listen
1560    if (!SetOption(SO_REUSEADDR, reuse == CanReuseAddress ? 1 : 0)) {
1561      os_close();
1562      return PFalse;
1563    }
1564   }
1565 #endif // BEOS
1566 
1567 #if P_HAS_IPV6
1568 
1569   if (ConvertOSError(::bind(os_handle, bind_sa, bind_sa.GetSize()))) {
1570     Psockaddr sa;
1571     socklen_t size = sa.GetSize();
1572     if (!ConvertOSError(::getsockname(os_handle, sa, &size)))
1573       return PFalse;
1574 
1575     port = sa.GetPort();
1576 
1577     if (!bindAddr.IsMulticast())
1578       return true;
1579 
1580     // Probably move this stuff into a separate method
1581     if (bindAddr.GetVersion() == 4) {
1582       struct ip_mreq  mreq;
1583       mreq.imr_multiaddr = in_addr(bindAddr);
1584       mreq.imr_interface.s_addr = htonl(INADDR_ANY);
1585       if (SetOption(IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq), IPPROTO_IP)) {
1586         PTRACE(4, "Socket\tJoined multicast group");
1587         return true;
1588       }
1589       PTRACE(1, "Socket\tFailed to join multicast group");
1590     }
1591     else {
1592       PTRACE(1, "Socket\tIPV6 Multicast join not implemented yet");
1593     }
1594 
1595     return false;
1596   }
1597 
1598 #else
1599 
1600   // attempt to listen
1601   sockaddr_in sin;
1602   memset(&sin, 0, sizeof(sin));
1603   sin.sin_family      = AF_INET;
1604   sin.sin_addr.s_addr = bindAddr;
1605   sin.sin_port        = htons(port);       // set the port
1606 
1607 #ifdef __NUCLEUS_NET__
1608   int bind_result;
1609   if (port == 0)
1610     bind_result = ::bindzero(os_handle, (struct sockaddr*)&sin, sizeof(sin));
1611   else
1612     bind_result = ::bind(os_handle, (struct sockaddr*)&sin, sizeof(sin));
1613   if (ConvertOSError(bind_result))
1614 #else
1615   if (ConvertOSError(::bind(os_handle, (struct sockaddr*)&sin, sizeof(sin))))
1616 #endif
1617   {
1618     socklen_t size = sizeof(sin);
1619     if (ConvertOSError(::getsockname(os_handle, (struct sockaddr*)&sin, &size))) {
1620       port = ntohs(sin.sin_port);
1621 
1622     if (!IN_MULTICAST(ntohl(sin.sin_addr.s_addr)))
1623         return true;
1624 
1625       struct ip_mreq  mreq;
1626       mreq.imr_multiaddr.s_addr = sin.sin_addr.s_addr;
1627       mreq.imr_interface.s_addr = htonl(INADDR_ANY);
1628       if (SetOption(IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) {
1629         PTRACE(4, "Socket\tJoined multicast group");
1630         return true;
1631       }
1632       PTRACE(1, "Socket\tFailed to join multicast group");
1633     }
1634   }
1635 
1636 #endif
1637 
1638   os_close();
1639   return PFalse;
1640 }
1641 
1642 
1643 #if P_HAS_IPV6
1644 
1645 /// Check for v4 mapped in v6 address ::ffff:a.b.c.d
IsV4Mapped() const1646 PBoolean PIPSocket::Address::IsV4Mapped() const
1647 {
1648   if (version != 6)
1649     return PFalse;
1650   return IN6_IS_ADDR_V4MAPPED(&v.six) || IN6_IS_ADDR_V4COMPAT(&v.six);
1651 }
1652 
1653 /// Check for link-local address fe80::/10
IsLinkLocal() const1654 PBoolean PIPSocket::Address::IsLinkLocal() const
1655 {
1656   if (version != 6)
1657     return PFalse;
1658   return IN6_IS_ADDR_LINKLOCAL(&v.six);
1659 }
1660 
1661 #endif
1662 
GetLoopback(int IPV6_PARAM (version))1663 const PIPSocket::Address & PIPSocket::Address::GetLoopback(int IPV6_PARAM(version))
1664 {
1665 #if P_HAS_IPV6
1666   if (version == 6)
1667     return loopback6;
1668 #endif
1669   return loopback4;
1670 }
1671 
GetAny(int IPV6_PARAM (version))1672 const PIPSocket::Address & PIPSocket::Address::GetAny(int IPV6_PARAM(version))
1673 {
1674 #if P_HAS_IPV6
1675   if (version == 6)
1676     return any6;
1677 #endif
1678   return any4;
1679 }
1680 
GetBroadcast(int IPV6_PARAM (version))1681 const PIPSocket::Address PIPSocket::Address::GetBroadcast(int IPV6_PARAM(version))
1682 {
1683 #if P_HAS_IPV6
1684   if (version == 6)
1685     return broadcast6;
1686 #endif
1687   return broadcast4;
1688 }
1689 
1690 
IsAny() const1691 PBoolean PIPSocket::Address::IsAny() const
1692 {
1693   return (!IsValid());
1694 }
1695 
1696 
Address()1697 PIPSocket::Address::Address()
1698 {
1699 #if P_HAS_IPV6
1700   if (g_defaultIpAddressFamily == AF_INET6)
1701     *this = loopback6;
1702   else
1703 #endif
1704     *this = loopback4;
1705 }
1706 
1707 
Address(const PString & dotNotation)1708 PIPSocket::Address::Address(const PString & dotNotation)
1709 {
1710   operator=(dotNotation);
1711 }
1712 
1713 
Address(PINDEX len,const BYTE * bytes)1714 PIPSocket::Address::Address(PINDEX len, const BYTE * bytes)
1715 {
1716   switch (len) {
1717 #if P_HAS_IPV6
1718     case 16 :
1719       version = 6;
1720       memcpy(&v.six, bytes, len);
1721       break;
1722 #endif
1723     case 4 :
1724       version = 4;
1725       memcpy(&v.four, bytes, len);
1726       break;
1727 
1728     default :
1729       version = 0;
1730   }
1731 }
1732 
1733 
Address(const in_addr & addr)1734 PIPSocket::Address::Address(const in_addr & addr)
1735 {
1736   version = 4;
1737   v.four = addr;
1738 }
1739 
1740 
1741 #if P_HAS_IPV6
Address(const in6_addr & addr)1742 PIPSocket::Address::Address(const in6_addr & addr)
1743 {
1744   version = 6;
1745   v.six = addr;
1746 }
1747 
1748 #endif
1749 
1750 
1751 // Create an IP (v4 or v6) address from a sockaddr (sockaddr_in, sockaddr_in6 or sockaddr_in6_old) structure
Address(const int ai_family,const int ai_addrlen,struct sockaddr * ai_addr)1752 PIPSocket::Address::Address(const int ai_family, const int ai_addrlen, struct sockaddr *ai_addr)
1753 {
1754   switch (ai_family) {
1755 #if P_HAS_IPV6
1756     case AF_INET6:
1757       if (ai_addrlen < (int)sizeof(sockaddr_in6)) {
1758         PTRACE(1, "Socket\tsockaddr size too small (" << ai_addrlen << ")  for family " << ai_family);
1759         break;
1760       }
1761 
1762       version = 6;
1763       v.six = ((struct sockaddr_in6 *)ai_addr)->sin6_addr;
1764       //sin6_scope_id, should be taken into account for link local addresses
1765       return;
1766 #endif
1767     case AF_INET:
1768       if (ai_addrlen < (int)sizeof(sockaddr_in)) {
1769         PTRACE(1, "Socket\tsockaddr size too small (" << ai_addrlen << ")  for family " << ai_family);
1770         break;
1771       }
1772 
1773       version = 4;
1774       v.four = ((struct sockaddr_in  *)ai_addr)->sin_addr;
1775       return;
1776 
1777     default :
1778       PTRACE(1, "Socket\tIllegal family (" << ai_family << ") specified.");
1779   }
1780 
1781   version = 0;
1782 }
1783 
1784 
1785 #ifdef __NUCLEUS_NET__
Address(const struct id_struct & addr)1786 PIPSocket::Address::Address(const struct id_struct & addr)
1787 {
1788   operator=(addr);
1789 }
1790 
1791 
operator =(const struct id_struct & addr)1792 PIPSocket::Address & PIPSocket::Address::operator=(const struct id_struct & addr)
1793 {
1794   s_addr = (((unsigned long)addr.is_ip_addrs[0])<<24) +
1795            (((unsigned long)addr.is_ip_addrs[1])<<16) +
1796            (((unsigned long)addr.is_ip_addrs[2])<<8) +
1797            (((unsigned long)addr.is_ip_addrs[3]));
1798   return *this;
1799 }
1800 #endif
1801 
1802 
operator =(const in_addr & addr)1803 PIPSocket::Address & PIPSocket::Address::operator=(const in_addr & addr)
1804 {
1805   version = 4;
1806   v.four = addr;
1807   return *this;
1808 }
1809 
1810 #if P_HAS_IPV6
operator =(const in6_addr & addr)1811 PIPSocket::Address & PIPSocket::Address::operator=(const in6_addr & addr)
1812 {
1813   version = 6;
1814   v.six = addr;
1815   return *this;
1816 }
1817 #endif
1818 
1819 
Compare(const PObject & obj) const1820 PObject::Comparison PIPSocket::Address::Compare(const PObject & obj) const
1821 {
1822   const PIPSocket::Address & other = (const PIPSocket::Address &)obj;
1823 
1824   if (version < other.version)
1825     return LessThan;
1826   if (version > other.version)
1827     return GreaterThan;
1828 
1829 #if P_HAS_IPV6
1830   if (version == 6) {
1831     int result = memcmp(&v.six, &other.v.six, sizeof(v.six));
1832     if (result < 0)
1833       return LessThan;
1834     if (result > 0)
1835       return GreaterThan;
1836     return EqualTo;
1837   }
1838 #endif
1839 
1840   if ((DWORD)*this < other)
1841     return LessThan;
1842   if ((DWORD)*this > other)
1843     return GreaterThan;
1844   return EqualTo;
1845 }
1846 
1847 #if P_HAS_IPV6
operator *=(const PIPSocket::Address & addr) const1848 bool PIPSocket::Address::operator*=(const PIPSocket::Address & addr) const
1849 {
1850   if (version == addr.version)
1851     return operator==(addr);
1852 
1853   if (this->GetVersion() == 6 && this->IsV4Mapped())
1854     return PIPSocket::Address((*this)[12], (*this)[13], (*this)[14], (*this)[15]) == addr;
1855   else if (addr.GetVersion() == 6 && addr.IsV4Mapped())
1856     return *this == PIPSocket::Address(addr[12], addr[13], addr[14], addr[15]);
1857   return PFalse;
1858 }
1859 
operator ==(in6_addr & addr) const1860 bool PIPSocket::Address::operator==(in6_addr & addr) const
1861 {
1862   PIPSocket::Address a(addr);
1863   return Compare(a) == EqualTo;
1864 }
1865 #endif
1866 
1867 
operator ==(in_addr & addr) const1868 bool PIPSocket::Address::operator==(in_addr & addr) const
1869 {
1870   PIPSocket::Address a(addr);
1871   return Compare(a) == EqualTo;
1872 }
1873 
1874 
operator ==(DWORD dw) const1875 bool PIPSocket::Address::operator==(DWORD dw) const
1876 {
1877   if (dw == 0)
1878     return !IsValid();
1879 
1880   if (version == 4)
1881     return (DWORD)*this == dw;
1882 
1883   return *this == Address(dw);
1884 }
1885 
1886 
operator =(const PString & dotNotation)1887 PIPSocket::Address & PIPSocket::Address::operator=(const PString & dotNotation)
1888 {
1889   FromString(dotNotation);
1890   return *this;
1891 }
1892 
1893 
AsString(bool IPV6_PARAM (bracketIPv6)) const1894 PString PIPSocket::Address::AsString(bool IPV6_PARAM(bracketIPv6)) const
1895 {
1896 #if defined(P_VXWORKS)
1897   char ipStorage[INET_ADDR_LEN];
1898   inet_ntoa_b(v.four, ipStorage);
1899   return ipStorage;
1900 #else
1901 # if defined(P_HAS_IPV6)
1902   if (version == 6) {
1903     PString str;
1904     Psockaddr sa(*this, 0);
1905     PAssertOS(getnameinfo(sa, sa.GetSize(), str.GetPointer(1024), 1024, NULL, 0, NI_NUMERICHOST) == 0);
1906     PINDEX percent = str.Find('%'); // used for scoped address e.g. fe80::1%ne0, (ne0=network interface 0)
1907     if (percent != P_MAX_INDEX)
1908       str[percent] = '\0';
1909     str.MakeMinimumSize();
1910     if (bracketIPv6)
1911       return '[' + str + ']';
1912     return str;
1913   }
1914 #endif // P_HAS_IPV6
1915 # if defined(P_HAS_INET_NTOP)
1916   PString str;
1917   if (inet_ntop(AF_INET, (const void *)&v.four, str.GetPointer(INET_ADDRSTRLEN), INET_ADDRSTRLEN) == NULL)
1918     return PString::Empty();
1919   str.MakeMinimumSize();
1920   return str;
1921 # else
1922   static PCriticalSection x;
1923   PWaitAndSignal m(x);
1924   return inet_ntoa(v.four);
1925 #endif // P_HAS_INET_NTOP
1926 #endif // P_VXWORKS
1927 }
1928 
1929 
FromString(const PString & ipAndInterface)1930 PBoolean PIPSocket::Address::FromString(const PString & ipAndInterface)
1931 {
1932   version = 0;
1933   memset(&v, 0, sizeof(v));
1934 
1935   PINDEX percent = ipAndInterface.Find('%');
1936   PString dotNotation = ipAndInterface.Left(percent);
1937   if (!dotNotation.IsEmpty()) {
1938 #if P_HAS_IPV6
1939 
1940     // Find out if string is in brackets [], as in ipv6 address
1941     PINDEX lbracket = dotNotation.Find('[');
1942     PINDEX rbracket = dotNotation.Find(']', lbracket);
1943     if (lbracket != P_MAX_INDEX && rbracket != P_MAX_INDEX)
1944       dotNotation = dotNotation(lbracket+1, rbracket-1);
1945 
1946     struct addrinfo *res = NULL;
1947     struct addrinfo hints = { AI_NUMERICHOST, PF_UNSPEC }; // Could be IPv4: x.x.x.x or IPv6: x:x:x:x::x
1948 
1949     if (getaddrinfo((const char *)dotNotation, NULL , &hints, &res) == 0) {
1950       if (res->ai_family == PF_INET6) {
1951         // IPv6 addr
1952         version = 6;
1953         struct sockaddr_in6 * addr_in6 = (struct sockaddr_in6 *)res->ai_addr;
1954         v.six = addr_in6->sin6_addr;
1955       } else {
1956         // IPv4 addr
1957         version = 4;
1958         struct sockaddr_in * addr_in = (struct sockaddr_in *)res->ai_addr;
1959         v.four = addr_in->sin_addr;
1960       }
1961       if (res != NULL)
1962         freeaddrinfo(res);
1963       return IsValid();
1964     }
1965 
1966 #else //P_HAS_IPV6
1967 
1968     DWORD iaddr;
1969     if (dotNotation.FindSpan("0123456789.") == P_MAX_INDEX &&
1970                       (iaddr = ::inet_addr((const char *)dotNotation)) != (DWORD)INADDR_NONE) {
1971       version = 4;
1972       v.four.s_addr = iaddr;
1973       return true;
1974     }
1975 
1976 #endif
1977   }
1978 
1979   if (percent == P_MAX_INDEX)
1980     return false;
1981 
1982   PString iface = ipAndInterface.Mid(percent+1);
1983   if (iface.IsEmpty())
1984     return false;
1985 
1986   PIPSocket::InterfaceTable interfaceTable;
1987   if (!PIPSocket::GetInterfaceTable(interfaceTable))
1988     return false;
1989 
1990   for (PINDEX i = 0; i < interfaceTable.GetSize(); i++) {
1991     if (interfaceTable[i].GetName().NumCompare(iface) == EqualTo) {
1992       *this = interfaceTable[i].GetAddress();
1993       return true;
1994     }
1995   }
1996 
1997   return false;
1998 
1999 }
2000 
2001 
operator PString() const2002 PIPSocket::Address::operator PString() const
2003 {
2004   return AsString();
2005 }
2006 
2007 
operator in_addr() const2008 PIPSocket::Address::operator in_addr() const
2009 {
2010   if (version != 4)
2011     return inaddr_empty;
2012 
2013   return v.four;
2014 }
2015 
2016 
2017 #if P_HAS_IPV6
operator in6_addr() const2018 PIPSocket::Address::operator in6_addr() const
2019 {
2020   if (version != 6)
2021     return any6.v.six;
2022 
2023   return v.six;
2024 }
2025 #endif
2026 
2027 
operator [](PINDEX idx) const2028 BYTE PIPSocket::Address::operator[](PINDEX idx) const
2029 {
2030   PASSERTINDEX(idx);
2031 #if P_HAS_IPV6
2032   if (version == 6) {
2033     PAssert(idx <= 15, PInvalidParameter);
2034     return v.six.s6_addr[idx];
2035   }
2036 #endif
2037 
2038   PAssert(idx <= 3, PInvalidParameter);
2039   return ((BYTE *)&v.four)[idx];
2040 }
2041 
2042 
operator <<(ostream & s,const PIPSocket::Address & a)2043 ostream & operator<<(ostream & s, const PIPSocket::Address & a)
2044 {
2045   return s << a.AsString();
2046 }
2047 
operator >>(istream & s,PIPSocket::Address & a)2048 istream & operator>>(istream & s, PIPSocket::Address & a)
2049 {
2050 /// Not IPv6 ready !!!!!!!!!!!!!
2051   char dot1, dot2, dot3;
2052   unsigned b1, b2, b3, b4;
2053   s >> b1;
2054   if (!s.fail()) {
2055     if (s.peek() != '.')
2056       a = htonl(b1);
2057     else {
2058       s >> dot1 >> b2 >> dot2 >> b3 >> dot3 >> b4;
2059       if (!s.fail() && dot1 == '.' && dot2 == '.' && dot3 == '.')
2060         a = PIPSocket::Address((BYTE)b1, (BYTE)b2, (BYTE)b3, (BYTE)b4);
2061     }
2062   }
2063   return s;
2064 }
2065 
2066 
GetSize() const2067 PINDEX PIPSocket::Address::GetSize() const
2068 {
2069   switch (version) {
2070 #if P_HAS_IPV6
2071     case 6 :
2072       return 16;
2073 #endif
2074 
2075     case 4 :
2076       return 4;
2077   }
2078 
2079   return 0;
2080 }
2081 
2082 
IsValid() const2083 PBoolean PIPSocket::Address::IsValid() const
2084 {
2085   switch (version) {
2086 #if P_HAS_IPV6
2087     case 6 :
2088       return memcmp(&v.six, &any6.v.six, sizeof(v.six)) != 0;
2089 #endif
2090 
2091     case 4 :
2092       return (DWORD)*this != INADDR_ANY;
2093   }
2094   return PFalse;
2095 }
2096 
2097 
IsLoopback() const2098 PBoolean PIPSocket::Address::IsLoopback() const
2099 {
2100 #if P_HAS_IPV6
2101   if (version == 6)
2102     return IN6_IS_ADDR_LOOPBACK(&v.six);
2103 #endif
2104   return Byte1() == 127;
2105 }
2106 
2107 
IsBroadcast() const2108 PBoolean PIPSocket::Address::IsBroadcast() const
2109 {
2110 #if P_HAS_IPV6
2111   if (version == 6) // In IPv6, no broadcast exist. Only multicast
2112     return *this == broadcast6; // multicast address as as substitute
2113 #endif
2114 
2115   return *this == broadcast4;
2116 }
2117 
2118 
IsMulticast() const2119 PBoolean PIPSocket::Address::IsMulticast() const
2120 {
2121 #if P_HAS_IPV6
2122   if (version == 6)
2123     return IN6_IS_ADDR_MULTICAST(&v.six);
2124 #endif
2125 
2126   return IN_MULTICAST(ntohl(v.four.s_addr));
2127 }
2128 
2129 
IsRFC1918() const2130 PBoolean PIPSocket::Address::IsRFC1918() const
2131 {
2132 #if P_HAS_IPV6
2133   if (version == 6) {
2134     if (IN6_IS_ADDR_LINKLOCAL(&v.six) || IN6_IS_ADDR_SITELOCAL(&v.six))
2135       return PTrue;
2136     if (IsV4Mapped())
2137       return PIPSocket::Address((*this)[12], (*this)[13], (*this)[14], (*this)[15]).IsRFC1918();
2138   }
2139 #endif
2140   return (Byte1() == 10)
2141           ||
2142           (
2143             (Byte1() == 172)
2144             &&
2145             (Byte2() >= 16) && (Byte2() <= 31)
2146           )
2147           ||
2148           (
2149             (Byte1() == 192)
2150             &&
2151             (Byte2() == 168)
2152           );
2153 }
2154 
InterfaceEntry()2155 PIPSocket::InterfaceEntry::InterfaceEntry()
2156   : m_ipAddress(0, NULL)
2157   , m_netMask(0, NULL)
2158 {
2159 }
2160 
InterfaceEntry(const PString & name,const Address & address,const Address & mask,const PString & macAddress)2161 PIPSocket::InterfaceEntry::InterfaceEntry(const PString & name,
2162                                           const Address & address,
2163                                           const Address & mask,
2164                                           const PString & macAddress)
2165   : m_name(name.Trim())
2166   , m_ipAddress(address)
2167   , m_netMask(mask)
2168   , m_macAddress(macAddress)
2169 {
2170   SanitiseName(m_name);
2171 }
2172 
2173 
SanitiseName(PString & name)2174 void PIPSocket::InterfaceEntry::SanitiseName(PString & name)
2175 {
2176   /* HACK!!
2177      At various points in PTLib (and OPAL) the interface name is used in
2178      situations where there can be confusion in parsing. For example a URL can
2179      be http:://[::%interface]:2345 and a ] in interface name blows it to
2180      pieces. Similarly, "ip:port" style description which can be used a LOT,
2181      will also fail. At this late stage it is too hard to change all the other
2182      places, so we hack the fairly rare cases by translating those special
2183      characters.
2184    */
2185   name.Replace('[', '{', true);
2186   name.Replace(']', '}', true);
2187   name.Replace(':', ';', true);
2188 }
2189 
2190 
PrintOn(ostream & strm) const2191 void PIPSocket::InterfaceEntry::PrintOn(ostream & strm) const
2192 {
2193   strm << m_ipAddress;
2194   if (!m_macAddress)
2195     strm << " <" << m_macAddress << '>';
2196   if (!m_name)
2197     strm << " (" << m_name << ')';
2198 }
2199 
2200 
2201 #ifdef __NUCLEUS_NET__
GetInterfaceTable(InterfaceTable & table)2202 PBoolean PIPSocket::GetInterfaceTable(InterfaceTable & table)
2203 {
2204     InterfaceEntry *IE;
2205     list<IPInterface>::iterator i;
2206     for(i=Route4Configuration->Getm_IPInterfaceList().begin();
2207             i!=Route4Configuration->Getm_IPInterfaceList().end();
2208             i++)
2209     {
2210         char ma[6];
2211         for(int j=0; j<6; j++) ma[j]=(*i).Getm_macaddr(j);
2212         IE = new InterfaceEntry((*i).Getm_name().c_str(), (*i).Getm_ipaddr(), ma );
2213         if(!IE) return false;
2214         table.Append(IE);
2215     }
2216     return true;
2217 }
2218 #endif
2219 
GetNetworkInterface(PIPSocket::Address & addr)2220 PBoolean PIPSocket::GetNetworkInterface(PIPSocket::Address & addr)
2221 {
2222   PIPSocket::InterfaceTable interfaceTable;
2223   if (PIPSocket::GetInterfaceTable(interfaceTable)) {
2224     PINDEX i;
2225     for (i = 0; i < interfaceTable.GetSize(); ++i) {
2226       PIPSocket::Address localAddr = interfaceTable[i].GetAddress();
2227       if (!localAddr.IsLoopback() && (!localAddr.IsRFC1918() || !addr.IsRFC1918()))
2228         addr = localAddr;
2229     }
2230   }
2231   return addr.IsValid();
2232 }
2233 
2234 
GetRouteInterfaceAddress(PIPSocket::Address remoteAddress)2235 PIPSocket::Address PIPSocket::GetRouteInterfaceAddress(PIPSocket::Address remoteAddress)
2236 {
2237   PIPSocket::InterfaceTable hostInterfaceTable;
2238   PIPSocket::GetInterfaceTable(hostInterfaceTable);
2239 
2240   PIPSocket::RouteTable hostRouteTable;
2241   PIPSocket::GetRouteTable(hostRouteTable);
2242 
2243   if (hostInterfaceTable.IsEmpty())
2244     return PIPSocket::GetDefaultIpAny();
2245 
2246   for (PINDEX IfaceIdx = 0; IfaceIdx < hostInterfaceTable.GetSize(); IfaceIdx++) {
2247     if (remoteAddress == hostInterfaceTable[IfaceIdx].GetAddress()) {
2248       PTRACE(5, "Socket\tRoute packet for " << remoteAddress
2249              << " over interface " << hostInterfaceTable[IfaceIdx].GetName()
2250              << "[" << hostInterfaceTable[IfaceIdx].GetAddress() << "]");
2251       return hostInterfaceTable[IfaceIdx].GetAddress();
2252     }
2253   }
2254 
2255   PIPSocket::RouteEntry * route = NULL;
2256   for (PINDEX routeIdx = 0; routeIdx < hostRouteTable.GetSize(); routeIdx++) {
2257     PIPSocket::RouteEntry & routeEntry = hostRouteTable[routeIdx];
2258 
2259     DWORD network = (DWORD) routeEntry.GetNetwork();
2260     DWORD mask = (DWORD) routeEntry.GetNetMask();
2261 
2262     if (((DWORD)remoteAddress & mask) == network) {
2263       if (route == NULL)
2264         route = &routeEntry;
2265       else if ((DWORD)routeEntry.GetNetMask() > (DWORD)route->GetNetMask())
2266         route = &routeEntry;
2267     }
2268   }
2269 
2270   if (route != NULL) {
2271     for (PINDEX IfaceIdx = 0; IfaceIdx < hostInterfaceTable.GetSize(); IfaceIdx++) {
2272       if (route->GetInterface() == hostInterfaceTable[IfaceIdx].GetName()) {
2273         PTRACE(5, "Socket\tRoute packet for " << remoteAddress
2274                << " over interface " << hostInterfaceTable[IfaceIdx].GetName()
2275                << "[" << hostInterfaceTable[IfaceIdx].GetAddress() << "]");
2276         return hostInterfaceTable[IfaceIdx].GetAddress();
2277       }
2278     }
2279   }
2280 
2281   return PIPSocket::GetDefaultIpAny();
2282 }
2283 
2284 //////////////////////////////////////////////////////////////////////////////
2285 // PTCPSocket
2286 
PTCPSocket(WORD newPort)2287 PTCPSocket::PTCPSocket(WORD newPort)
2288 {
2289   SetPort(newPort);
2290 }
2291 
2292 
PTCPSocket(const PString & service)2293 PTCPSocket::PTCPSocket(const PString & service)
2294 {
2295   SetPort(service);
2296 }
2297 
2298 
PTCPSocket(const PString & address,WORD newPort)2299 PTCPSocket::PTCPSocket(const PString & address, WORD newPort)
2300 {
2301   SetPort(newPort);
2302   Connect(address);
2303 }
2304 
2305 
PTCPSocket(const PString & address,const PString & service)2306 PTCPSocket::PTCPSocket(const PString & address, const PString & service)
2307 {
2308   SetPort(service);
2309   Connect(address);
2310 }
2311 
2312 
PTCPSocket(PSocket & socket)2313 PTCPSocket::PTCPSocket(PSocket & socket)
2314 {
2315   Accept(socket);
2316 }
2317 
2318 
PTCPSocket(PTCPSocket & tcpSocket)2319 PTCPSocket::PTCPSocket(PTCPSocket & tcpSocket)
2320 {
2321   Accept(tcpSocket);
2322 }
2323 
2324 
Clone() const2325 PObject * PTCPSocket::Clone() const
2326 {
2327   return new PTCPSocket(port);
2328 }
2329 
2330 
2331 // By default IPv4 only adresses
OpenSocket()2332 PBoolean PTCPSocket::OpenSocket()
2333 {
2334   return ConvertOSError(os_handle = os_socket(AF_INET, SOCK_STREAM, 0));
2335 }
2336 
2337 
2338 // ipAdressFamily should be AF_INET or AF_INET6
OpenSocket(int ipAdressFamily)2339 PBoolean PTCPSocket::OpenSocket(int ipAdressFamily)
2340 {
2341   return ConvertOSError(os_handle = os_socket(ipAdressFamily, SOCK_STREAM, 0));
2342 }
2343 
2344 
GetProtocolName() const2345 const char * PTCPSocket::GetProtocolName() const
2346 {
2347   return "tcp";
2348 }
2349 
2350 
Write(const void * buf,PINDEX len)2351 PBoolean PTCPSocket::Write(const void * buf, PINDEX len)
2352 {
2353   flush();
2354   PINDEX writeCount = 0;
2355 
2356   while (len > 0) {
2357     if (!os_sendto(((char *)buf)+writeCount, len, 0, NULL, 0))
2358       return PFalse;
2359     writeCount += lastWriteCount;
2360     len -= lastWriteCount;
2361   }
2362 
2363   lastWriteCount = writeCount;
2364   return PTrue;
2365 }
2366 
2367 
Listen(unsigned queueSize,WORD newPort,Reusability reuse)2368 PBoolean PTCPSocket::Listen(unsigned queueSize, WORD newPort, Reusability reuse)
2369 {
2370 #if P_HAS_IPV6
2371   return Listen(GetDefaultIpAny(), queueSize, newPort, reuse);
2372 #else
2373   return Listen(INADDR_ANY, queueSize, newPort, reuse);
2374 #endif
2375 }
2376 
2377 
Listen(const Address & bindAddr,unsigned queueSize,WORD newPort,Reusability reuse)2378 PBoolean PTCPSocket::Listen(const Address & bindAddr,
2379                         unsigned queueSize,
2380                         WORD newPort,
2381                         Reusability reuse)
2382 {
2383   if (PIPSocket::Listen(bindAddr, queueSize, newPort, reuse) &&
2384       ConvertOSError(::listen(os_handle, queueSize)))
2385     return PTrue;
2386 
2387   os_close();
2388   return PFalse;
2389 }
2390 
2391 
Accept(PSocket & socket)2392 PBoolean PTCPSocket::Accept(PSocket & socket)
2393 {
2394   PAssert(PIsDescendant(&socket, PIPSocket), "Invalid listener socket");
2395 
2396 #if P_HAS_IPV6
2397 
2398   Psockaddr sa;
2399   PINDEX size = sa.GetSize();
2400   if (!os_accept(socket, sa, &size))
2401     return PFalse;
2402 
2403 #else
2404 
2405   sockaddr_in address;
2406   address.sin_family = AF_INET;
2407   PINDEX size = sizeof(address);
2408   if (!os_accept(socket, (struct sockaddr *)&address, &size))
2409     return PFalse;
2410 
2411 #endif
2412 
2413   port = ((PIPSocket &)socket).GetPort();
2414 
2415   return PTrue;
2416 }
2417 
2418 
WriteOutOfBand(void const * buf,PINDEX len)2419 PBoolean PTCPSocket::WriteOutOfBand(void const * buf, PINDEX len)
2420 {
2421 #ifdef __NUCLEUS_NET__
2422   PAssertAlways("WriteOutOfBand unavailable on Nucleus Plus");
2423   //int count = NU_Send(os_handle, (char *)buf, len, 0);
2424   int count = ::send(os_handle, (const char *)buf, len, 0);
2425 #elif defined(P_VXWORKS)
2426   int count = ::send(os_handle, (char *)buf, len, MSG_OOB);
2427 #else
2428   int count = ::send(os_handle, (const char *)buf, len, MSG_OOB);
2429 #endif
2430   if (count < 0) {
2431     lastWriteCount = 0;
2432     return ConvertOSError(count, LastWriteError);
2433   }
2434   else {
2435     lastWriteCount = count;
2436     return PTrue;
2437   }
2438 }
2439 
2440 
OnOutOfBand(const void *,PINDEX)2441 void PTCPSocket::OnOutOfBand(const void *, PINDEX)
2442 {
2443 }
2444 
2445 
2446 //////////////////////////////////////////////////////////////////////////////
2447 // PIPDatagramSocket
2448 
PIPDatagramSocket()2449 PIPDatagramSocket::PIPDatagramSocket()
2450 {
2451 }
2452 
2453 
ReadFrom(void * buf,PINDEX len,Address & addr,WORD & port)2454 PBoolean PIPDatagramSocket::ReadFrom(void * buf, PINDEX len,
2455                                  Address & addr, WORD & port)
2456 {
2457   lastReadCount = 0;
2458 
2459 #if P_HAS_IPV6
2460 
2461   Psockaddr sa;
2462   PINDEX size = sa.GetSize();
2463   bool ok = os_recvfrom(buf, len, 0, sa, &size);
2464   addr = sa.GetIP();
2465   port = sa.GetPort();
2466 
2467 #else
2468 
2469   sockaddr_in sockAddr;
2470   PINDEX addrLen = sizeof(sockAddr);
2471   bool ok = os_recvfrom(buf, len, 0, (struct sockaddr *)&sockAddr, &addrLen);
2472   addr = sockAddr.sin_addr;
2473   port = ntohs(sockAddr.sin_port);
2474 
2475 #endif
2476 
2477   return ok;
2478 }
2479 
2480 
WriteTo(const void * buf,PINDEX len,const Address & addr,WORD port)2481 PBoolean PIPDatagramSocket::WriteTo(const void * buf, PINDEX len,
2482                                 const Address & addr, WORD port)
2483 {
2484   lastWriteCount = 0;
2485 
2486   PBoolean broadcast = addr.IsAny() || addr.IsBroadcast();
2487   if (broadcast) {
2488 #ifdef P_BEOS
2489     PAssertAlways("Broadcast option under BeOS is not implemented yet");
2490     return PFalse;
2491 #else
2492     if (!SetOption(SO_BROADCAST, 1))
2493       return PFalse;
2494 #endif
2495   }
2496 
2497 #ifdef P_MACOSX
2498   // Mac OS X does not treat 255.255.255.255 as a broadcast address (multihoming / ambiguity issues)
2499   // and such packets aren't sent to the layer 2 - broadcast address (i.e. ethernet ff:ff:ff:ff:ff:ff)
2500   // instead: send subnet broadcasts on all interfaces
2501 
2502   // TODO: Add IPv6 support
2503 
2504   PBoolean ok = PFalse;
2505   if (broadcast) {
2506     sockaddr_in sockAddr;
2507     sockAddr.sin_family = AF_INET;
2508     sockAddr.sin_port = htons(port);
2509 
2510     InterfaceTable interfaces;
2511     if (GetInterfaceTable(interfaces)) {
2512       for (int i = 0; i < interfaces.GetSize(); i++) {
2513         InterfaceEntry & iface = interfaces[i];
2514         if (iface.GetAddress().IsLoopback()) {
2515           continue;
2516         }
2517         // create network address from address / netmask
2518         DWORD ifAddr = iface.GetAddress();
2519         DWORD netmask = iface.GetNetMask();
2520         DWORD bcastAddr = (ifAddr & netmask) + ~netmask;
2521 
2522         sockAddr.sin_addr.s_addr = bcastAddr;
2523 
2524         PBoolean result = os_sendto(buf, len, 0, (struct sockaddr *)&sockAddr, sizeof(sockAddr)) != 0;
2525 
2526         ok = ok || result;
2527       }
2528     }
2529 
2530   } else {
2531     sockaddr_in sockAddr;
2532     sockAddr.sin_family = AF_INET;
2533     sockAddr.sin_addr = addr;
2534     sockAddr.sin_port = htons(port);
2535     ok = os_sendto(buf, len, 0, (struct sockaddr *)&sockAddr, sizeof(sockAddr)) != 0;
2536   }
2537 
2538 #else
2539 
2540 #if P_HAS_IPV6
2541 
2542   Psockaddr sa(broadcast ? Address::GetBroadcast(addr.GetVersion()) : addr, port);
2543   PBoolean ok = os_sendto(buf, len, 0, sa, sa.GetSize()) != 0;
2544 
2545 #else
2546 
2547   sockaddr_in sockAddr;
2548   sockAddr.sin_family = AF_INET;
2549   sockAddr.sin_addr = (broadcast ? Address::GetBroadcast() : addr);
2550   sockAddr.sin_port = htons(port);
2551   PBoolean ok = os_sendto(buf, len, 0, (struct sockaddr *)&sockAddr, sizeof(sockAddr)) != 0;
2552 
2553 #endif // P_HAS_IPV6
2554 
2555 #endif // P_MACOSX
2556 
2557 #ifndef P_BEOS
2558   if (broadcast)
2559     SetOption(SO_BROADCAST, 0);
2560 #endif
2561 
2562   return ok && lastWriteCount >= len;
2563 }
2564 
2565 
2566 //////////////////////////////////////////////////////////////////////////////
2567 // PUDPSocket
2568 
PUDPSocket(WORD newPort,int iAddressFamily)2569 PUDPSocket::PUDPSocket(WORD newPort, int iAddressFamily)
2570 {
2571   sendPort = 0;
2572   SetPort(newPort);
2573   OpenSocket(iAddressFamily);
2574 }
2575 
PUDPSocket(PQoS * qos,WORD newPort,int iAddressFamily)2576 PUDPSocket::PUDPSocket(PQoS * qos, WORD newPort, int iAddressFamily)
2577 #if P_HAS_IPV6
2578   : sendAddress(iAddressFamily == AF_INET ? loopback4 : loopback6),
2579     lastReceiveAddress(iAddressFamily == AF_INET ? loopback4 : loopback6)
2580 #else
2581   : sendAddress(loopback4),
2582     lastReceiveAddress(loopback4)
2583 #endif
2584 {
2585   if (qos != NULL)
2586       qosSpec = *qos;
2587   sendPort = 0;
2588   SetPort(newPort);
2589   OpenSocket(iAddressFamily);
2590 }
2591 
2592 
PUDPSocket(const PString & service,PQoS * qos,int iAddressFamily)2593 PUDPSocket::PUDPSocket(const PString & service, PQoS * qos, int iAddressFamily)
2594 #if P_HAS_IPV6
2595   : sendAddress(iAddressFamily == AF_INET ? loopback4 : loopback6),
2596     lastReceiveAddress(iAddressFamily == AF_INET ? loopback4 : loopback6)
2597 #else
2598   : sendAddress(loopback4),
2599     lastReceiveAddress(loopback4)
2600 #endif
2601 {
2602   if (qos != NULL)
2603       qosSpec = *qos;
2604   sendPort = 0;
2605   SetPort(service);
2606   OpenSocket(iAddressFamily);
2607 }
2608 
2609 
PUDPSocket(const PString & address,WORD newPort)2610 PUDPSocket::PUDPSocket(const PString & address, WORD newPort)
2611 {
2612   sendPort = 0;
2613   SetPort(newPort);
2614   Connect(address);
2615 }
2616 
2617 
PUDPSocket(const PString & address,const PString & service)2618 PUDPSocket::PUDPSocket(const PString & address, const PString & service)
2619 {
2620   sendPort = 0;
2621   SetPort(service);
2622   Connect(address);
2623 }
2624 
2625 
ModifyQoSSpec(PQoS * qos)2626 PBoolean PUDPSocket::ModifyQoSSpec(PQoS * qos)
2627 {
2628   if (qos==NULL)
2629     return PFalse;
2630 
2631   qosSpec = *qos;
2632   return PTrue;
2633 }
2634 
2635 #if P_QOS
GetQoSSpec()2636 PQoS & PUDPSocket::GetQoSSpec()
2637 {
2638   return qosSpec;
2639 }
2640 #endif //P_QOS
2641 
ApplyQoS()2642 PBoolean PUDPSocket::ApplyQoS()
2643 {
2644   char DSCPval = 0;
2645 #ifndef _WIN32_WCE
2646   if (qosSpec.GetDSCP() < 0 ||
2647       qosSpec.GetDSCP() > 63) {
2648     if (qosSpec.GetServiceType() == SERVICETYPE_PNOTDEFINED)
2649       return PTrue;
2650     else {
2651       switch (qosSpec.GetServiceType()) {
2652         case SERVICETYPE_GUARANTEED:
2653           DSCPval = PQoS::guaranteedDSCP;
2654           break;
2655         case SERVICETYPE_CONTROLLEDLOAD:
2656           DSCPval = PQoS::controlledLoadDSCP;
2657           break;
2658         case SERVICETYPE_BESTEFFORT:
2659         default:
2660           DSCPval = PQoS::bestEffortDSCP;
2661           break;
2662       }
2663     }
2664   }
2665   else
2666     DSCPval = (char)qosSpec.GetDSCP();
2667 #else
2668   DSCPval = 0x38;
2669   disableGQoS = PFalse;
2670 #endif
2671 
2672 #ifdef _WIN32
2673 #if P_QOS
2674   if (disableGQoS)
2675     return PFalse;
2676 
2677 #ifndef _WIN32_WCE
2678   PBoolean usesetsockopt = PFalse;
2679 
2680   OSVERSIONINFO versInfo;
2681   ZeroMemory(&versInfo,sizeof(OSVERSIONINFO));
2682   versInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
2683   if (!(GetVersionEx(&versInfo)))
2684     usesetsockopt = PTrue;
2685   else {
2686     if (versInfo.dwMajorVersion < 5)
2687       usesetsockopt = PTrue;
2688 
2689     if (disableGQoS)
2690           return PFalse;
2691 
2692     PBoolean usesetsockopt = PFalse;
2693 
2694     if (versInfo.dwMajorVersion == 5 &&
2695         versInfo.dwMinorVersion == 0)
2696       usesetsockopt = PTrue;         //Windows 2000 does not always support QOS_DESTADDR
2697   }
2698 #else
2699   PBoolean usesetsockopt = PTrue;
2700 #endif
2701 
2702   PBoolean retval = PFalse;
2703   if (!usesetsockopt && sendAddress.IsValid() && sendPort != 0) {
2704     sockaddr_in sa;
2705     sa.sin_family = AF_INET;
2706     sa.sin_port = htons(sendPort);
2707     sa.sin_addr = sendAddress;
2708     memset(sa.sin_zero,0,8);
2709 
2710     char * inBuf = new char[2048];
2711     memset(inBuf,0,2048);
2712     DWORD bufLen = 0;
2713     PWinQoS wqos(qosSpec, (struct sockaddr *)(&sa), inBuf, bufLen);
2714 
2715     DWORD dummy = 0;
2716     int irval = WSAIoctl(os_handle, SIO_SET_QOS, inBuf, bufLen, NULL, 0, &dummy, NULL, NULL);
2717 
2718     delete[] inBuf;
2719 
2720     return irval == 0;
2721   }
2722 
2723   if (!usesetsockopt)
2724     return retval;
2725 
2726 #endif  // P_QOS
2727 #endif  // _WIN32
2728 
2729   unsigned int setDSCP = DSCPval<<2;
2730 
2731   int rv = 0;
2732   unsigned int curval = 0;
2733   socklen_t cursize = sizeof(curval);
2734   rv = ::getsockopt(os_handle,IPPROTO_IP, IP_TOS, (char *)(&curval), &cursize);
2735   if (curval == setDSCP)
2736     return PTrue;    //Required DSCP already set
2737 
2738 
2739   rv = ::setsockopt(os_handle, IPPROTO_IP, IP_TOS, (char *)&setDSCP, sizeof(setDSCP));
2740 
2741   if (rv != 0) {
2742     int err;
2743 #ifdef _WIN32
2744     err = WSAGetLastError();
2745 #else
2746     err = errno;
2747 #endif
2748     PTRACE(1,"QOS\tsetsockopt failed with code " << err);
2749     return PFalse;
2750   }
2751 
2752   return PTrue;
2753 }
2754 
OpenSocketGQOS(int af,int type,int proto)2755 PBoolean PUDPSocket::OpenSocketGQOS(int af, int type, int proto)
2756 {
2757 #if defined(_WIN32) && defined(P_QOS)
2758 
2759   //Try to find a QOS-enabled protocol
2760   DWORD bufferSize = 0;
2761   DWORD numProtocols = WSAEnumProtocols(proto != 0 ? &proto : NULL, NULL, &bufferSize);
2762   if (!ConvertOSError(numProtocols) && WSAGetLastError() != WSAENOBUFS)
2763     return false;
2764 
2765   LPWSAPROTOCOL_INFO installedProtocols = (LPWSAPROTOCOL_INFO)(new BYTE[bufferSize]);
2766   numProtocols = WSAEnumProtocols(proto != 0 ? &proto : NULL, installedProtocols, &bufferSize);
2767   if (!ConvertOSError(numProtocols)) {
2768     delete[] installedProtocols;
2769     return false;
2770   }
2771 
2772   LPWSAPROTOCOL_INFO qosProtocol = installedProtocols;
2773   for (DWORD i = 0; i < numProtocols; qosProtocol++, i++) {
2774     if ((qosProtocol->dwServiceFlags1 & XP1_QOS_SUPPORTED) &&
2775         (qosProtocol->iSocketType == type) &&
2776         (qosProtocol->iAddressFamily == af)) {
2777       os_handle = WSASocket(af, type, proto, qosProtocol, 0, WSA_FLAG_OVERLAPPED);
2778       break;
2779     }
2780   }
2781 
2782   delete[] installedProtocols;
2783 
2784   if (!IsOpen())
2785     os_handle = WSASocket(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED);
2786 
2787   return ConvertOSError(os_handle);
2788 
2789 #else
2790   return ConvertOSError(os_handle = os_socket(af, type, proto));
2791 #endif
2792 }
2793 
2794 #ifdef _WIN32
2795 #if P_QOS
2796 
2797 #define COULD_HAVE_QOS
2798 
CheckOSVersionFor(DWORD major,DWORD minor)2799 static PBoolean CheckOSVersionFor(DWORD major, DWORD minor)
2800 {
2801   OSVERSIONINFO versInfo;
2802   ZeroMemory(&versInfo,sizeof(OSVERSIONINFO));
2803   versInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
2804   if (GetVersionEx(&versInfo)) {
2805     if (versInfo.dwMajorVersion > major ||
2806        (versInfo.dwMajorVersion == major && versInfo.dwMinorVersion >= minor))
2807       return PTrue;
2808   }
2809   return PFalse;
2810 }
2811 
2812 #endif // P_QOS
2813 #endif // _WIN32
2814 
OpenSocket()2815 PBoolean PUDPSocket::OpenSocket()
2816 {
2817 #ifdef COULD_HAVE_QOS
2818   if (CheckOSVersionFor(5,1))
2819     return OpenSocketGQOS(AF_INET, SOCK_DGRAM, 0);
2820 #endif
2821 
2822   return ConvertOSError(os_handle = os_socket(AF_INET,SOCK_DGRAM, 0));
2823 }
2824 
OpenSocket(int ipAdressFamily)2825 PBoolean PUDPSocket::OpenSocket(int ipAdressFamily)
2826 {
2827 #ifdef COULD_HAVE_QOS
2828   if (CheckOSVersionFor(5,1))
2829     return OpenSocketGQOS(ipAdressFamily, SOCK_DGRAM, 0);
2830 #endif
2831 
2832   return ConvertOSError(os_handle = os_socket(ipAdressFamily,SOCK_DGRAM, 0));
2833 }
2834 
GetProtocolName() const2835 const char * PUDPSocket::GetProtocolName() const
2836 {
2837   return "udp";
2838 }
2839 
2840 
Connect(const PString & address)2841 PBoolean PUDPSocket::Connect(const PString & address)
2842 {
2843   sendPort = 0;
2844   return PIPDatagramSocket::Connect(address);
2845 }
2846 
2847 
Read(void * buf,PINDEX len)2848 PBoolean PUDPSocket::Read(void * buf, PINDEX len)
2849 {
2850   return PIPDatagramSocket::ReadFrom(buf, len, lastReceiveAddress, lastReceivePort);
2851 }
2852 
2853 
Write(const void * buf,PINDEX len)2854 PBoolean PUDPSocket::Write(const void * buf, PINDEX len)
2855 {
2856   if (sendPort == 0)
2857     return PIPDatagramSocket::Write(buf, len);
2858   else
2859     return PIPDatagramSocket::WriteTo(buf, len, sendAddress, sendPort);
2860 }
2861 
2862 
SetSendAddress(const Address & newAddress,WORD newPort)2863 void PUDPSocket::SetSendAddress(const Address & newAddress, WORD newPort)
2864 {
2865   sendAddress = newAddress;
2866   sendPort    = newPort;
2867   ApplyQoS();
2868 }
2869 
2870 
GetSendAddress(Address & address,WORD & port) const2871 void PUDPSocket::GetSendAddress(Address & address, WORD & port) const
2872 {
2873   address = sendAddress;
2874   port    = sendPort;
2875 }
2876 
2877 
GetSendAddress() const2878 PString PUDPSocket::GetSendAddress() const
2879 {
2880   return sendAddress.AsString(true) + psprintf(":%u", sendPort);
2881 }
2882 
2883 
GetLastReceiveAddress(Address & address,WORD & port) const2884 void PUDPSocket::GetLastReceiveAddress(Address & address, WORD & port) const
2885 {
2886   address = lastReceiveAddress;
2887   port    = lastReceivePort;
2888 }
2889 
2890 
GetLastReceiveAddress() const2891 PString PUDPSocket::GetLastReceiveAddress() const
2892 {
2893   return lastReceiveAddress.AsString(true) + psprintf(":%u", lastReceivePort);
2894 }
2895 
2896 
IsAlternateAddress(const Address &,WORD)2897 PBoolean PUDPSocket::IsAlternateAddress(const Address &, WORD)
2898 {
2899   return false;
2900 }
2901 
DoPseudoRead(int &)2902 PBoolean PUDPSocket::DoPseudoRead(int & /*selectStatus*/)
2903 {
2904    return false;
2905 }
2906 
2907 //////////////////////////////////////////////////////////////////////////////
2908 
OpenSocket(int)2909 PBoolean PICMPSocket::OpenSocket(int)
2910 {
2911   return PFalse;
2912 }
2913 
2914 //////////////////////////////////////////////////////////////////////////////
2915 
Parse(const PString & str,WORD port,char separator)2916 PBoolean PIPSocketAddressAndPort::Parse(const PString & str, WORD port, char separator)
2917 {
2918   if (separator != '\0')
2919     m_separator = separator;
2920 
2921   PINDEX pos = str.Find(m_separator);
2922   if (pos != P_MAX_INDEX)
2923     port = (WORD)str.Mid(pos+1).AsUnsigned();
2924 
2925   if (port != 0)
2926     m_port = port;
2927 
2928   return PIPSocket::GetHostAddress(str.Left(pos), m_address) && m_port != 0;
2929 }
2930 
2931 
SetAddress(const PIPSocket::Address & addr,WORD port)2932 void PIPSocketAddressAndPort::SetAddress(const PIPSocket::Address & addr, WORD port)
2933 {
2934   m_address = addr;
2935   if (port != 0)
2936     m_port = port;
2937 }
2938 
2939 
2940 // End Of File ///////////////////////////////////////////////////////////////
2941