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