Initialised error code in gethostbyname usage.
[pwlib.git] / src / ptlib / common / sockets.cxx
blob312914b66277ca1ea3dd0235f78ae3209b647b57
1 /*
2 * sockets.cxx
4 * Berkley sockets classes.
6 * Portable Windows Library
8 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
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/
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.
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
25 * All Rights Reserved.
27 * Contributor(s): ______________________________________.
29 * $Log$
30 * Revision 1.144 2002/12/13 04:01:46 robertj
31 * Initialised error code in gethostbyname usage.
33 * Revision 1.143 2002/12/04 00:52:59 robertj
34 * Fixed GNU warning
36 * Revision 1.142 2002/12/02 12:25:08 craigs
37 * Fixed problem with error code from gethostbyname_r not being checked correctly
39 * Revision 1.141 2002/11/24 23:47:01 robertj
40 * Fixed MSVC v5 compatibility
42 * Revision 1.140 2002/11/13 02:15:25 craigs
43 * Fixed problem with GetLocalHostName
45 * Revision 1.139 2002/11/12 11:47:53 rogerh
46 * Add a missing memset in the Psockaddr constructor
48 * Revision 1.138 2002/11/02 00:32:21 robertj
49 * Further fixes to VxWorks (Tornado) port, thanks Andreas Sikkema.
51 * Revision 1.137 2002/11/01 23:56:11 robertj
52 * Fixed GNu compatibility isse with IPv6
54 * Revision 1.136 2002/11/01 03:32:08 robertj
55 * More IPv6 fixes, thanks Sébastien Josset.
57 * Revision 1.135 2002/10/31 07:55:33 robertj
58 * Put sizeof ipv6 structure back as magic number 28 is explained by
59 * mismatched header file and running implementation.
61 * Revision 1.134 2002/10/29 08:04:44 robertj
62 * Changed in_addr6 to more universally used in6_addr.
63 * Changed size of ipv6 address to be 28 under win32, Why? I don't know!
65 * Revision 1.133 2002/10/19 06:12:20 robertj
66 * Moved P_fd_set::Zero() from platform independent to platform dependent
67 * code as Win32 implementation is completely different from Unix.
69 * Revision 1.132 2002/10/18 08:07:41 robertj
70 * Fixed use of FD_ZERO as (strangely) crashes on some paltforms and would
71 * not have cleared enough of an enlarges fd_set anyway.
73 * Revision 1.131 2002/10/17 13:44:27 robertj
74 * Port to RTEMS, thanks Vladimir Nesic.
76 * Revision 1.130 2002/10/17 08:17:28 robertj
77 * Fixed incomplete changes for expandable fd_set
79 * Revision 1.129 2002/10/17 07:17:43 robertj
80 * Added ability to increase maximum file handles on a process.
82 * Revision 1.128 2002/10/17 01:24:11 robertj
83 * Fixed so internal sockaddr classes GetSize() returns correct size for
84 * particular sockaddr it represents, thanks Sébastien Josset.
86 * Revision 1.127 2002/10/16 06:19:36 robertj
87 * Rewrite of IPv6 sockaddr code to use intelligent class to automatically
88 * know if it is sockaddr_in or aockaddr_in6.
89 * Fixed Connect() function to work correctly on unopened socket.
91 * Revision 1.126 2002/10/10 11:38:56 robertj
92 * Added close of socket if not open in correct ip version, thanks Sébastien Josset
94 * Revision 1.125 2002/10/10 04:43:44 robertj
95 * VxWorks port, thanks Martijn Roest
97 * Revision 1.124 2002/10/09 05:37:52 robertj
98 * Fixed IPv6 version of ReadFrom() and WriteTo().
100 * Revision 1.123 2002/10/08 23:31:44 robertj
101 * Added missing GetSize() implementation in ip address.
103 * Revision 1.122 2002/10/08 12:41:52 robertj
104 * Changed for IPv6 support, thanks Sébastien Josset.
106 * Revision 1.121 2002/09/23 07:17:24 robertj
107 * Changes to allow winsock2 to be included.
109 * Revision 1.120 2002/05/22 07:18:46 robertj
110 * Fixed bug where SO_RESUSEADDR wsa being turned ON instead of OFF when
111 * making an outgoing connection, should only be ON for listener sockets.
113 * Revision 1.119 2002/04/12 01:42:41 robertj
114 * Changed return value on os_connect() and os_accept() to make sure
115 * get the correct error codes propagated up under unix.
117 * Revision 1.118 2002/01/28 01:27:03 robertj
118 * Removed previous change that actually has nothing to do with GCC 3 compatibility,
119 * setting default timeout for all sockets to 10 seconds is NOT a sensible thing to do!
121 * Revision 1.117 2002/01/26 23:57:45 craigs
122 * Changed for GCC 3.0 compatibility, thanks to manty@manty.net
124 * Revision 1.116 2002/01/07 05:37:32 robertj
125 * Changed to allow for a service name that starts with a number.
127 * Revision 1.115 2002/01/02 04:55:31 craigs
128 * Fixed problem when PSocket::GetPortByService called with a number
129 * that is a substring of a valid service name
131 * Revision 1.114 2001/12/13 09:18:07 robertj
132 * Added function to convert PString to IP address with error checking that can
133 * distinguish between 0.0.0.0 or 255.255.255.255 and illegal address.
134 * Added ability to decode bracketed IP addresss [10.1.2.3] as host name.
136 * Revision 1.113 2001/09/14 08:00:38 robertj
137 * Added new versions of Conenct() to allow binding to a specific local interface.
139 * Revision 1.112 2001/09/10 02:51:23 robertj
140 * Major change to fix problem with error codes being corrupted in a
141 * PChannel when have simultaneous reads and writes in threads.
143 * Revision 1.111 2001/06/30 06:59:07 yurik
144 * Jac Goudsmit from Be submit these changes 6/28. Implemented by Yuri Kiryanov
146 * Revision 1.110 2001/05/24 02:07:31 yurik
147 * ::setsockopt on WinCE is now not called if option is not supported
149 * Revision 1.109 2001/05/23 19:48:55 yurik
150 * Fix submitted by Dave Cassel, dcassel@cyberfone.com,
151 * allowing a connection between a client and a gatekeeper.
153 * Revision 1.108 2001/03/20 06:44:25 robertj
154 * Lots of changes to fix the problems with terminating threads that are I/O
155 * blocked, especially when doing orderly shutdown of service via SIGTERM.
157 * Revision 1.107 2001/03/05 04:18:27 robertj
158 * Added net mask to interface info returned by GetInterfaceTable()
160 * Revision 1.106 2001/01/29 06:41:32 robertj
161 * Added printing of entry of interface table.
163 * Revision 1.105 2001/01/28 01:15:01 yurik
164 * WinCE port-related
166 * Revision 1.104 2001/01/24 06:32:17 yurik
167 * Windows CE port-related changes
169 * Revision 1.103 2000/06/26 11:17:21 robertj
170 * Nucleus++ port (incomplete).
172 * Revision 1.102 2000/06/21 01:01:22 robertj
173 * AIX port, thanks Wolfgang Platzer (wolfgang.platzer@infonova.at).
175 * Revision 1.101 2000/05/02 08:14:40 craigs
176 * Fixed problem with "memory leak" reporting under Unix
178 * Revision 1.100 2000/04/27 02:43:45 robertj
179 * Fixed warning about signedness mismatch.
181 * Revision 1.99 2000/04/19 00:13:52 robertj
182 * BeOS port changes.
184 * Revision 1.98 2000/02/18 09:55:21 robertj
185 * Added parameter so get/setsockopt can have other levels to SOL_SOCKET.
187 * Revision 1.97 1999/10/27 01:21:44 robertj
188 * Improved portability of copy from host_info struct to IP address.
190 * Revision 1.96 1999/08/30 02:21:03 robertj
191 * Added ability to listen to specific interfaces for IP sockets.
193 * Revision 1.95 1999/08/27 08:18:52 robertj
194 * Added ability to get the host/port of the the last packet read/written to UDP socket.
196 * Revision 1.94 1999/08/08 09:04:01 robertj
197 * Added operator>> for PIPSocket::Address class.
199 * Revision 1.93 1999/07/11 13:42:13 craigs
200 * pthreads support for Linux
202 * Revision 1.92 1999/06/01 08:04:35 robertj
203 * Fixed mistake from previous fix.
205 * Revision 1.91 1999/06/01 07:39:23 robertj
206 * Added retries to DNS lookup if get temporary error.
208 * Revision 1.90 1999/03/09 08:13:52 robertj
209 * Fixed race condition in doing Select() on closed sockets. Could go into infinite wait.
211 * Revision 1.89 1999/03/02 05:41:58 robertj
212 * More BeOS changes
214 * Revision 1.88 1999/02/26 04:10:39 robertj
215 * More BeOS port changes
217 * Revision 1.87 1999/02/25 03:43:35 robertj
218 * Fixed warning when PINDEX is unsigned.
220 * Revision 1.86 1999/02/23 07:19:22 robertj
221 * Added [] operator PIPSocket::Address to get the bytes out of an IP address.
223 * Revision 1.85 1999/02/16 08:08:06 robertj
224 * MSVC 6.0 compatibility changes.
226 * Revision 1.84 1999/01/08 01:29:47 robertj
227 * Support for pthreads under FreeBSD
229 * Revision 1.83 1999/01/06 10:58:01 robertj
230 * Fixed subtle mutex bug in returning string hostname from DNS cache.
232 * Revision 1.82 1998/12/22 10:25:01 robertj
233 * Added clone() function to support SOCKS in FTP style protocols.
234 * Fixed internal use of new operator in IP cache.
236 * Revision 1.81 1998/12/18 04:34:37 robertj
237 * PPC Linux GNU C compatibility.
239 * Revision 1.80 1998/11/30 04:47:52 robertj
240 * New directory structure
242 * Revision 1.79 1998/11/14 06:28:36 robertj
243 * Changed senatics of os_sendto to return TRUE if ANY bytes are sent.
245 * Revision 1.78 1998/11/08 12:05:04 robertj
246 * Fixed multiple thread access problem with DNS aliases array.
248 * Revision 1.77 1998/10/01 09:05:35 robertj
249 * Added check that port number is between 1 and 65535.
251 * Revision 1.76 1998/09/23 06:22:44 robertj
252 * Added open source copyright license.
254 * Revision 1.75 1998/08/31 13:00:34 robertj
255 * Prevented dependency on snmpapi.dll for all ptlib apps.
257 * Revision 1.74 1998/08/27 00:58:42 robertj
258 * Resolved signedness problems with various GNU libraries.
260 * Revision 1.73 1998/08/25 14:07:43 robertj
261 * Added getprotobyxxx wrapper functions.
263 * Revision 1.72 1998/08/25 11:09:20 robertj
264 * Fixed parsing of 802.x header on ethernet frames.
265 * Changed DNS cache to not cache temporary lookup failures, only an authoratative 'no such host'.
267 * Revision 1.71 1998/08/21 05:26:10 robertj
268 * Fixed bug where write streams out to non-stream socket.
269 * Added ethernet socket.
271 * Revision 1.70 1998/05/07 05:20:25 robertj
272 * Fixed DNS lookup so only works around bug in old Win95 and not OSR2
274 * Revision 1.69 1998/03/20 03:18:21 robertj
275 * Added special classes for specific sepahores, PMutex and PSyncPoint.
277 * Revision 1.68 1998/03/05 12:45:48 robertj
278 * DNS cache and NT bug fix attempts.
280 * Revision 1.67 1998/01/26 02:49:22 robertj
281 * GNU support.
283 * Revision 1.66 1998/01/26 00:49:28 robertj
284 * Fixed bug in detecting local host on NT, 95 bug kludge was interfering with it.
286 * Revision 1.65 1998/01/06 12:43:23 craigs
287 * Added definition of REENTRANT_BUFFER_LEN
289 * Revision 1.64 1998/01/04 07:25:09 robertj
290 * Added pthreads compatible calls for gethostbyx functions.
292 * Revision 1.63 1997/12/18 05:06:13 robertj
293 * Moved IsLocalHost() to platform dependent code.
295 * Revision 1.62 1997/12/11 10:30:35 robertj
296 * Added operators for IP address to DWORD conversions.
298 * Revision 1.61 1997/10/03 13:33:22 robertj
299 * Added workaround for NT winsock bug with RAS and DNS lookups.
301 * Revision 1.60 1997/09/27 00:58:39 robertj
302 * Fixed race condition on socket close in Select() function.
304 * Revision 1.59 1997/06/06 10:56:36 craigs
305 * Added new functions for connectionless UDP writes
307 * Revision 1.58 1997/01/04 07:42:18 robertj
308 * Fixed GCC Warnings.
310 * Revision 1.57 1997/01/04 06:54:38 robertj
311 * Added missing canonical name to alias list.
313 * Revision 1.56 1996/12/17 11:07:05 robertj
314 * Added clear of name cache.
316 * Revision 1.55 1996/12/12 09:23:27 robertj
317 * Fixed name cache to cache missing names as well.
318 * Fixed new connect with specific local port so can be re-used (simultaneous FTP session bug)
320 * Revision 1.54 1996/12/05 11:46:39 craigs
321 * Fixed problem with Win95 recvfrom not having timeouts
323 * Revision 1.53 1996/11/30 12:08:17 robertj
324 * Added Connect() variant so can set the local port number on link.
326 * Revision 1.52 1996/11/16 10:49:03 robertj
327 * Fixed missing const in PIPSocket::Address stream output operator..
329 * Revision 1.51 1996/11/16 01:43:49 craigs
330 * Fixed problem with ambiguous DNS cache keys
332 * Revision 1.50 1996/11/10 21:08:31 robertj
333 * Added host name caching.
335 * Revision 1.49 1996/11/04 03:40:22 robertj
336 * Moved address printer from inline to source.
338 * Revision 1.48 1996/10/26 01:41:09 robertj
339 * Compensated for Win'95 gethostbyaddr bug.
341 * Revision 1.47 1996/09/14 13:09:40 robertj
342 * Major upgrade:
343 * rearranged sockets to help support IPX.
344 * added indirect channel class and moved all protocols to descend from it,
345 * separating the protocol from the low level byte transport.
347 * Revision 1.46 1996/08/25 09:33:32 robertj
348 * Added function to detect "local" host name.
350 * Revision 1.45 1996/07/30 12:24:53 robertj
351 * Fixed incorrect conditional stopping Select() from working.
353 * Revision 1.44 1996/07/27 04:10:35 robertj
354 * Changed Select() calls to return error codes.
356 * Revision 1.43 1996/06/10 09:58:21 robertj
357 * Fixed win95 compatibility with looking up zero address (got a response and shouldn't).
359 * Revision 1.42 1996/05/26 03:47:03 robertj
360 * Compatibility to GNU 2.7.x
362 * Revision 1.39 1996/04/29 12:20:01 robertj
363 * Fixed GetHostAliases() so doesn't overwrite names with IP numbers.
365 * Revision 1.38 1996/04/15 10:59:41 robertj
366 * Opened socket on UDP sockets so ReadFrom/WriteTo work when no Connect/Listen.
368 * Revision 1.37 1996/03/31 09:06:41 robertj
369 * Added socket shutdown function.
371 * Revision 1.35 1996/03/18 13:33:18 robertj
372 * Fixed incompatibilities to GNU compiler where PINDEX != int.
374 * Revision 1.34 1996/03/17 05:51:18 robertj
375 * Fixed strange bug in accept cant have NULL address.
377 * Revision 1.33 1996/03/16 04:52:20 robertj
378 * Changed all the get host name and get host address functions to be more consistent.
380 * Revision 1.32 1996/03/04 12:21:00 robertj
381 * Split file into telnet.cxx
383 * Revision 1.31 1996/03/03 07:38:45 robertj
384 * Added Reusability clause to the Listen() function on sockets.
386 * Revision 1.30 1996/03/02 03:25:13 robertj
387 * Added Capability to get and set Berkeley socket options.
389 * Revision 1.29 1996/02/25 11:30:08 robertj
390 * Changed Listen so can do a listen on a socket that is connected.
392 * Revision 1.28 1996/02/25 03:10:55 robertj
393 * Moved some socket functions to platform dependent code.
395 * Revision 1.27 1996/02/19 13:30:15 robertj
396 * Fixed bug in getting port by service name when specifying service by string number.
397 * Added SO_LINGER option to socket to stop data loss on close.
399 * Revision 1.26 1996/02/15 14:46:44 robertj
400 * Added Select() function to PSocket.
402 * Revision 1.25 1996/02/13 13:08:09 robertj
403 * Fixed usage of sock_addr structure, not being cleared correctly.
405 * Revision 1.24 1996/02/08 12:27:22 robertj
406 * Added function to get peer port as well as IP number..
408 * Revision 1.23 1996/02/03 11:07:37 robertj
409 * Fixed buf in assuring error when converting string to IP number and string is empty.
411 * Revision 1.22 1996/01/28 14:08:13 robertj
412 * Changed service parameter to PString for ease of use in GetPortByService function
413 * Fixed up comments.
414 * Added default value in string for service name.
416 * Revision 1.21 1996/01/23 13:19:13 robertj
417 * Moved Accept() function to platform dependent code.
419 * Revision 1.20 1995/12/23 03:42:53 robertj
420 * Unix portability issues.
422 * Revision 1.19 1995/12/10 11:42:23 robertj
423 * Numerous fixes for sockets.
425 * Revision 1.18 1995/10/14 15:11:31 robertj
426 * Added internet address to string conversion functionality.
428 * Revision 1.17 1995/07/02 01:21:23 robertj
429 * Added static functions to get the current host name/address.
431 * Revision 1.16 1995/06/17 00:47:01 robertj
432 * Changed overloaded Open() calls to 3 separate function names.
433 * More logical design of port numbers and service names.
435 * Revision 1.15 1995/06/04 12:45:33 robertj
436 * Added application layer protocol sockets.
437 * Slight redesign of port numbers on sockets.
439 * Revision 1.14 1995/04/25 11:12:44 robertj
440 * Fixed functions hiding ancestor virtuals.
442 * Revision 1.13 1995/04/01 08:31:54 robertj
443 * Finally got a working TELNET.
445 * Revision 1.12 1995/03/18 06:27:49 robertj
446 * Rewrite of telnet socket protocol according to RFC1143.
448 * Revision 1.11 1995/03/12 04:46:29 robertj
449 * Added more functionality.
451 * Revision 1.10 1995/02/21 11:25:29 robertj
452 * Further implementation of telnet socket, feature complete now.
454 * Revision 1.9 1995/01/27 11:16:16 robertj
455 * Fixed missing cast in function, required by some platforms.
457 * Revision 1.8 1995/01/15 04:55:47 robertj
458 * Moved all Berkley socket functions inside #ifdef.
460 * Revision 1.7 1995/01/04 10:57:08 robertj
461 * Changed for HPUX and GNU2.6.x
463 * Revision 1.6 1995/01/03 09:37:52 robertj
464 * Added constructor to open TCP socket.
466 * Revision 1.5 1995/01/02 12:28:25 robertj
467 * Documentation.
468 * Added more socket functions.
470 * Revision 1.4 1995/01/01 01:06:58 robertj
471 * More implementation.
473 * Revision 1.3 1994/11/28 12:38:49 robertj
474 * Added DONT and WONT states.
476 * Revision 1.2 1994/08/21 23:43:02 robertj
477 * Some implementation.
479 * Revision 1.1 1994/08/01 03:39:05 robertj
480 * Initial revision
484 #ifdef __NUCLEUS_PLUS__
485 #include <ConfigurationClass.h>
486 #endif
489 #include <ptlib.h>
491 #include <ptlib/sockets.h>
493 #include <ctype.h>
497 #if P_HAS_IPV6
499 class Psockaddr
501 public:
502 Psockaddr() { memset(&storage, 0, sizeof(storage)); }
503 Psockaddr(const PIPSocket::Address & ip, WORD port);
504 sockaddr* operator->() const { return (sockaddr *)&storage; }
505 operator sockaddr*() const { return (sockaddr *)&storage; }
506 socklen_t GetSize() const;
507 PIPSocket::Address GetIP() const;
508 WORD GetPort() const;
509 private:
510 sockaddr_storage storage;
514 Psockaddr::Psockaddr(const PIPSocket::Address & ip, WORD port)
516 memset(&storage, 0, sizeof(storage));
518 if (ip.GetVersion() == 6) {
519 sockaddr_in6 * addr6 = (sockaddr_in6 *)&storage;
520 addr6->sin6_family = AF_INET6;
521 addr6->sin6_addr = ip;
522 addr6->sin6_port = htons(port);
523 addr6->sin6_flowinfo = 0;
524 addr6->sin6_scope_id = 0; // Should be set to the right interface....
526 else {
527 sockaddr_in * addr4 = (sockaddr_in *)&storage;
528 addr4->sin_family = AF_INET;
529 addr4->sin_addr = ip;
530 addr4->sin_port = htons(port);
535 socklen_t Psockaddr::GetSize() const
537 switch (((sockaddr *)&storage)->sa_family) {
538 case AF_INET :
539 return sizeof(sockaddr_in);
540 case AF_INET6 :
541 // RFC 2133 (Old IPv6 spec) size is 24
542 // RFC 2553 (New IPv6 spec) size is 28
543 return sizeof(sockaddr_in6);
544 default :
545 return sizeof(storage);
550 PIPSocket::Address Psockaddr::GetIP() const
552 switch (((sockaddr *)&storage)->sa_family) {
553 case AF_INET :
554 return ((sockaddr_in *)&storage)->sin_addr;
555 case AF_INET6 :
556 return ((sockaddr_in6 *)&storage)->sin6_addr;
557 default :
558 return 0;
563 WORD Psockaddr::GetPort() const
565 switch (((sockaddr *)&storage)->sa_family) {
566 case AF_INET :
567 return ntohs(((sockaddr_in *)&storage)->sin_port);
568 case AF_INET6 :
569 return ntohs(((sockaddr_in6 *)&storage)->sin6_port);
570 default :
571 return 0;
575 #endif
578 #if (defined(_WIN32) || defined(WINDOWS)) && !defined(__NUCLEUS_MNT__)
579 static PWinSock dummyForWinSock; // Assure winsock is initialised
580 #endif
582 #if (defined(P_PTHREADS) && !defined(P_THREAD_SAFE_CLIB)) || defined(__NUCLEUS_PLUS__)
583 #define REENTRANT_BUFFER_LEN 1024
584 #endif
587 class PIPCacheData : public PObject
589 PCLASSINFO(PIPCacheData, PObject)
590 public:
591 PIPCacheData(struct hostent * ent, const char * original);
592 const PString & GetHostName() const { return hostname; }
593 const PIPSocket::Address & GetHostAddress() const { return address; }
594 const PStringList & GetHostAliases() const { return aliases; }
595 BOOL HasAged() const;
596 private:
597 PString hostname;
598 PIPSocket::Address address;
599 PStringList aliases;
600 PTime birthDate;
604 PDICTIONARY(PHostByName_private, PCaselessString, PIPCacheData);
606 class PHostByName : PHostByName_private
608 public:
609 BOOL GetHostName(const PString & name, PString & hostname);
610 BOOL GetHostAddress(const PString & name, PIPSocket::Address & address);
611 BOOL GetHostAliases(const PString & name, PStringArray & aliases);
612 private:
613 PIPCacheData * GetHost(const PString & name);
614 PMutex mutex;
615 friend void PIPSocket::ClearNameCache();
618 static PHostByName & pHostByName()
620 static PHostByName t;
621 return t;
624 class PIPCacheKey : public PObject
626 PCLASSINFO(PIPCacheKey, PObject)
627 public:
628 PIPCacheKey(const PIPSocket::Address & a)
629 { addr = a; }
631 PObject * Clone() const
632 { return new PIPCacheKey(*this); }
634 PINDEX HashFunction() const
635 { return (addr[1] + addr[2] + addr[3])%41; }
637 private:
638 PIPSocket::Address addr;
641 PDICTIONARY(PHostByAddr_private, PIPCacheKey, PIPCacheData);
643 class PHostByAddr : PHostByAddr_private
645 public:
646 BOOL GetHostName(const PIPSocket::Address & addr, PString & hostname);
647 BOOL GetHostAddress(const PIPSocket::Address & addr, PIPSocket::Address & address);
648 BOOL GetHostAliases(const PIPSocket::Address & addr, PStringArray & aliases);
649 private:
650 PIPCacheData * GetHost(const PIPSocket::Address & addr);
651 PMutex mutex;
652 friend void PIPSocket::ClearNameCache();
655 static PHostByAddr & pHostByAddr()
657 static PHostByAddr t;
658 return t;
661 #define new PNEW
664 //////////////////////////////////////////////////////////////////////////////
665 // IP Caching
667 PIPCacheData::PIPCacheData(struct hostent * host_info, const char * original)
669 if (host_info == NULL) {
670 address = 0;
671 return;
674 hostname = host_info->h_name;
675 if (host_info->h_addr != NULL)
676 #ifndef _WIN32_WCE
677 address = *(DWORD *)host_info->h_addr;
678 #else
679 address = PIPSocket::Address(h_length, host_info->h_addr);
680 #endif
681 aliases.AppendString(host_info->h_name);
683 PINDEX i;
684 for (i = 0; host_info->h_aliases[i] != NULL; i++)
685 aliases.AppendString(host_info->h_aliases[i]);
687 for (i = 0; host_info->h_addr_list[i] != NULL; i++)
688 aliases.AppendString(inet_ntoa(*(struct in_addr *)host_info->h_addr_list[i]));
690 for (i = 0; i < aliases.GetSize(); i++)
691 if (aliases[i] *= original)
692 return;
694 aliases.AppendString(original);
698 static PTimeInterval GetConfigTime(const char * key, DWORD dflt)
700 PConfig cfg("DNS Cache");
701 return cfg.GetInteger(key, dflt);
705 BOOL PIPCacheData::HasAged() const
707 static PTimeInterval retirement = GetConfigTime("Age Limit", 300000); // 5 minutes
708 PTime now;
709 PTimeInterval age = now - birthDate;
710 return age > retirement;
714 BOOL PHostByName::GetHostName(const PString & name, PString & hostname)
716 PIPCacheData * host = GetHost(name);
718 if (host != NULL) {
719 hostname = host->GetHostName();
720 hostname.MakeUnique();
723 mutex.Signal();
725 return host != NULL;
729 BOOL PHostByName::GetHostAddress(const PString & name, PIPSocket::Address & address)
731 PIPCacheData * host = GetHost(name);
733 if (host != NULL)
734 address = host->GetHostAddress();
736 mutex.Signal();
738 return host != NULL;
742 BOOL PHostByName::GetHostAliases(const PString & name, PStringArray & aliases)
744 PIPCacheData * host = GetHost(name);
746 if (host != NULL) {
747 const PStringList & a = host->GetHostAliases();
748 aliases.SetSize(a.GetSize());
749 for (PINDEX i = 0; i < a.GetSize(); i++)
750 aliases[i] = a[i];
753 mutex.Signal();
754 return host != NULL;
758 PIPCacheData * PHostByName::GetHost(const PString & name)
760 mutex.Wait();
762 PCaselessString key = name;
763 PIPCacheData * host = GetAt(key);
765 if (host != NULL && host->HasAged()) {
766 SetAt(key, NULL);
767 host = NULL;
770 if (host == NULL) {
771 mutex.Signal();
773 #ifdef P_AIX
774 struct hostent_data ht_data;
775 memset(&ht_data, 0, sizeof(ht_data));
776 struct hostent host_info;
777 #elif defined(P_RTEMS)
778 struct hostent host_info;
779 #else
780 struct hostent * host_info;
781 #endif
783 int retry = 3;
784 int localErrNo = 0;
786 do {
787 #if ( ( defined(P_PTHREADS) && !defined(P_THREAD_SAFE_CLIB) ) || (defined(__NUCLEUS_PLUS__) ) )
788 // this function should really be a static on PIPSocket, but this would
789 // require allocating thread-local storage for the data and that's too much
790 // of a pain!
793 #if !defined(P_AIX) && !defined(P_RTEMS) // that I get no warnings
794 char buffer[REENTRANT_BUFFER_LEN];
795 struct hostent hostEnt;
796 #endif
798 #ifdef P_LINUX
799 ::gethostbyname_r(name,
800 &hostEnt,
801 buffer, REENTRANT_BUFFER_LEN,
802 &host_info,
803 &localErrNo);
805 #elif defined P_AIX
806 ::gethostbyname_r(name,
807 &host_info,
808 &ht_data);
809 localErrNo = h_errno;
811 #elif defined P_RTEMS
812 host_info = *::gethostbyname(name);
813 #else
814 host_info = ::gethostbyname_r(name,
815 &hostEnt, buffer, REENTRANT_BUFFER_LEN,
816 &localErrNo);
817 #endif
819 #elif defined P_VXWORKS
820 struct hostent hostEnt;
821 host_info = Vx_gethostbyname((char *)name, &hostEnt);
822 localErrNo = h_errno;
823 #else
824 host_info = ::gethostbyname(name);
825 localErrNo = h_errno;
826 #endif
827 } while (localErrNo == TRY_AGAIN && --retry > 0);
829 mutex.Wait();
831 if (localErrNo != NETDB_SUCCESS || retry == 0)
832 return NULL;
834 #if defined(P_AIX) || defined(P_RTEMS)
835 host = new PIPCacheData (&host_info, (const char*) name);
836 #else
837 host = new PIPCacheData(host_info, name);
838 #endif
840 SetAt(key, host);
843 if (host->GetHostAddress() == 0)
844 return NULL;
846 return host;
850 BOOL PHostByAddr::GetHostName(const PIPSocket::Address & addr, PString & hostname)
852 PIPCacheData * host = GetHost(addr);
854 if (host != NULL) {
855 hostname = host->GetHostName();
856 hostname.MakeUnique();
859 mutex.Signal();
860 return host != NULL;
864 BOOL PHostByAddr::GetHostAddress(const PIPSocket::Address & addr, PIPSocket::Address & address)
866 PIPCacheData * host = GetHost(addr);
868 if (host != NULL)
869 address = host->GetHostAddress();
871 mutex.Signal();
872 return host != NULL;
876 BOOL PHostByAddr::GetHostAliases(const PIPSocket::Address & addr, PStringArray & aliases)
878 PIPCacheData * host = GetHost(addr);
880 if (host != NULL) {
881 const PStringList & a = host->GetHostAliases();
882 aliases.SetSize(a.GetSize());
883 for (PINDEX i = 0; i < a.GetSize(); i++)
884 aliases[i] = a[i];
887 mutex.Signal();
888 return host != NULL;
891 PIPCacheData * PHostByAddr::GetHost(const PIPSocket::Address & addr)
893 mutex.Wait();
895 PIPCacheKey key = addr;
896 PIPCacheData * host = GetAt(key);
898 if (host != NULL && host->HasAged()) {
899 SetAt(key, NULL);
900 host = NULL;
903 if (host == NULL) {
904 mutex.Signal();
906 #ifdef P_AIX
907 struct hostent_data ht_data;
908 struct hostent host_info;
909 #elif P_RTEMS
910 struct hostent host_info;
911 #else
912 struct hostent * host_info;
913 #endif
915 int retry = 3;
916 int localErrNo = NETDB_SUCCESS;
917 do {
918 #if ( ( defined(P_PTHREADS) && !defined(P_THREAD_SAFE_CLIB) ) || ( defined(__NUCLEUS_PLUS__) ) )
919 // this function should really be a static on PIPSocket, but this would
920 // require allocating thread-local storage for the data and that's too much
921 // of a pain!
923 #if !defined(P_AIX) && !defined(P_RTEMS) // that I get no warnings
924 int localErrNo;
925 char buffer[REENTRANT_BUFFER_LEN];
926 struct hostent hostEnt;
927 #endif
929 #ifdef P_LINUX
930 ::gethostbyaddr_r((const char *)&addr, sizeof(addr),
931 PF_INET,
932 &hostEnt,
933 buffer, REENTRANT_BUFFER_LEN,
934 &host_info,
935 &localErrNo);
936 #elif defined P_AIX
937 ::gethostbyaddr_r((char *)&addr, sizeof(addr),
938 PF_INET,
939 &host_info,
940 &ht_data );
941 localErrNo = h_errno;
942 #elif defined P_RTEMS
943 host_info = *::gethostbyaddr((const char *)&addr, sizeof(addr), PF_INET);
944 localErrNo = h_errno;
945 #else
946 host_info = ::gethostbyaddr_r((const char *)&addr, sizeof(addr), PF_INET,
947 &hostEnt, buffer, REENTRANT_BUFFER_LEN, &localErrNo);
948 #endif
950 #elif defined P_VXWORKS
951 struct hostent hostEnt;
952 host_info = Vx_gethostbyaddr((char *)&addr, &hostEnt);
953 #else
954 host_info = ::gethostbyaddr((const char *)&addr, sizeof(addr), PF_INET);
955 localErrNo = h_errno;
956 #if defined(_WIN32) || defined(WINDOWS) // Kludge to avoid strange 95 bug
957 extern P_IsOldWin95();
958 if (P_IsOldWin95() && host_info != NULL && host_info->h_addr_list[0] != NULL)
959 host_info->h_addr_list[1] = NULL;
960 #endif
961 #endif
962 } while (localErrNo == TRY_AGAIN && --retry > 0);
964 mutex.Wait();
966 if (localErrNo != NETDB_SUCCESS || retry == 0)
967 return NULL;
969 #if defined(P_AIX) || defined(P_RTEMS)
970 host = new PIPCacheData(&host_info, addr.AsString());
971 #else
972 host = new PIPCacheData(host_info, addr.AsString());
973 #endif
975 SetAt(key, host);
978 if (host->GetHostAddress() == 0)
979 return NULL;
981 return host;
985 //////////////////////////////////////////////////////////////////////////////
986 // P_fd_set
988 #ifdef _MSC_VER
989 #pragma warning(push)
990 #pragma warning(disable:4127)
991 #endif
993 P_fd_set::P_fd_set()
995 Construct();
996 Zero();
1000 P_fd_set::P_fd_set(SOCKET fd)
1002 Construct();
1003 Zero();
1004 FD_SET(fd, set);
1008 P_fd_set & P_fd_set::operator=(SOCKET fd)
1010 PAssert(fd < max_fd, PInvalidParameter);
1011 Zero();
1012 FD_SET(fd, set);
1013 return *this;
1017 P_fd_set & P_fd_set::operator+=(SOCKET fd)
1019 PAssert(fd < max_fd, PInvalidParameter);
1020 FD_SET(fd, set);
1021 return *this;
1025 P_fd_set & P_fd_set::operator-=(SOCKET fd)
1027 PAssert(fd < max_fd, PInvalidParameter);
1028 FD_CLR(fd, set);
1029 return *this;
1032 #ifdef _MSC_VER
1033 #pragma warning(pop)
1034 #endif
1037 //////////////////////////////////////////////////////////////////////////////
1038 // P_timeval
1040 P_timeval::P_timeval()
1042 tval.tv_usec = 0;
1043 tval.tv_sec = 0;
1044 infinite = FALSE;
1048 P_timeval & P_timeval::operator=(const PTimeInterval & time)
1050 infinite = time == PMaxTimeInterval;
1051 tval.tv_usec = (long)(time.GetMilliSeconds()%1000)*1000;
1052 tval.tv_sec = time.GetSeconds();
1053 return *this;
1057 //////////////////////////////////////////////////////////////////////////////
1058 // PSocket
1060 PSocket::PSocket()
1062 port = 0;
1066 BOOL PSocket::Connect(const PString &)
1068 PAssertAlways("Illegal operation.");
1069 return FALSE;
1073 BOOL PSocket::Listen(unsigned, WORD, Reusability)
1075 PAssertAlways("Illegal operation.");
1076 return FALSE;
1080 BOOL PSocket::Accept(PSocket &)
1082 PAssertAlways("Illegal operation.");
1083 return FALSE;
1087 BOOL PSocket::SetOption(int option, int value, int level)
1089 #ifdef _WIN32_WCE
1090 if(option == SO_RCVBUF || option == SO_SNDBUF || option == IP_TOS)
1091 return TRUE;
1092 #endif
1093 return ConvertOSError(::setsockopt(os_handle, level, option,
1094 (char *)&value, sizeof(value)));
1098 BOOL PSocket::SetOption(int option, const void * valuePtr, PINDEX valueSize, int level)
1100 return ConvertOSError(::setsockopt(os_handle, level, option,
1101 (char *)valuePtr, valueSize));
1105 BOOL PSocket::GetOption(int option, int & value, int level)
1107 #ifdef BE_BONELESS
1108 return FALSE;
1109 #else
1110 socklen_t valSize = sizeof(value);
1111 return ConvertOSError(::getsockopt(os_handle, level, option,
1112 (char *)&value, &valSize));
1113 #endif
1117 BOOL PSocket::GetOption(int option, void * valuePtr, PINDEX valueSize, int level)
1119 #ifdef BE_BONELESS
1120 return FALSE;
1121 #else
1122 return ConvertOSError(::getsockopt(os_handle, level, option,
1123 (char *)valuePtr, (socklen_t *)&valueSize));
1124 #endif
1128 BOOL PSocket::Shutdown(ShutdownValue value)
1130 return ConvertOSError(::shutdown(os_handle, value));
1134 WORD PSocket::GetProtocolByName(const PString & name)
1136 #if !defined(BE_BONELESS) && !defined(__NUCLEUS_PLUS__) && !defined(_WIN32_WCE) && !defined(P_VXWORKS)
1137 struct protoent * ent = getprotobyname(name);
1138 if (ent != NULL)
1139 return ent->p_proto;
1140 #endif
1142 return 0;
1146 PString PSocket::GetNameByProtocol(WORD proto)
1148 #if !defined(BE_BONELESS) && !defined(__NUCLEUS_PLUS__) && !defined(_WIN32_WCE) && !defined(P_VXWORKS)
1149 struct protoent * ent = getprotobynumber(proto);
1150 if (ent != NULL)
1151 return ent->p_name;
1152 #endif
1154 return psprintf("%u", proto);
1158 WORD PSocket::GetPortByService(const PString & serviceName) const
1160 return GetPortByService(GetProtocolName(), serviceName);
1164 WORD PSocket::GetPortByService(const char * protocol, const PString & service)
1166 // if the string is a valid integer, then use integer value
1167 // this avoids stupid problems like operating systems that match service
1168 // names to substrings (like "2000" to "taskmaster2000")
1169 if (strspn(service, "0123456789") == strlen(service))
1170 return (WORD)service.AsUnsigned();
1172 #if defined( __NUCLEUS_PLUS__ )
1173 PAssertAlways("PSocket::GetPortByService: problem as no ::getservbyname in Nucleus NET");
1174 return 0;
1175 #elif defined(_WIN32_WCE)
1176 PAssertAlways("PSocket::GetPortByService: problem for WindowsCE as no port given.");
1177 return 0;
1178 #elif defined(P_VXWORKS)
1179 PAssertAlways("PSocket::GetPortByService: problem as no ::getservbyname in VxWorks");
1180 return 0;
1181 #else
1182 PINDEX space = service.FindOneOf(" \t\r\n");
1183 struct servent * serv = ::getservbyname(service(0, space-1), protocol);
1184 if (serv != NULL)
1185 return ntohs(serv->s_port);
1187 long portNum;
1188 if (space != P_MAX_INDEX)
1189 portNum = atol(service(space+1, P_MAX_INDEX));
1190 else if (isdigit(service[0]))
1191 portNum = atoi(service);
1192 else
1193 portNum = -1;
1195 if (portNum < 0 || portNum > 65535)
1196 return 0;
1198 return (WORD)portNum;
1199 #endif
1203 PString PSocket::GetServiceByPort(WORD port) const
1205 return GetServiceByPort(GetProtocolName(), port);
1209 PString PSocket::GetServiceByPort(const char * protocol, WORD port)
1211 #if !defined(BE_BONELESS) && !defined(__NUCLEUS_PLUS__) && !defined(_WIN32_WCE) && !defined(P_VXWORKS)
1212 struct servent * serv = ::getservbyport(htons(port), protocol);
1213 if (serv != NULL)
1214 return PString(serv->s_name);
1215 else
1216 #endif
1217 return PString(PString::Unsigned, port);
1221 void PSocket::SetPort(WORD newPort)
1223 PAssert(!IsOpen(), "Cannot change port number of opened socket");
1224 port = newPort;
1228 void PSocket::SetPort(const PString & service)
1230 PAssert(!IsOpen(), "Cannot change port number of opened socket");
1231 port = GetPortByService(service);
1235 WORD PSocket::GetPort() const
1237 return port;
1241 PString PSocket::GetService() const
1243 return GetServiceByPort(port);
1247 int PSocket::Select(PSocket & sock1, PSocket & sock2)
1249 return Select(sock1, sock2, PMaxTimeInterval);
1253 int PSocket::Select(PSocket & sock1,
1254 PSocket & sock2,
1255 const PTimeInterval & timeout)
1257 if (!sock1.IsOpen() || !sock2.IsOpen())
1258 return NotOpen;
1260 int h1 = sock1.GetHandle();
1261 int h2 = sock2.GetHandle();
1263 P_fd_set readfds;
1264 readfds += h1;
1265 readfds += h2;
1267 PIntArray allfds(4);
1268 allfds[0] = h1;
1269 allfds[1] = 1;
1270 allfds[2] = h2;
1271 allfds[3] = 1;
1272 int rval = os_select(PMAX(h1, h2)+1, (fd_set*)readfds, NULL, NULL, allfds, timeout);
1274 Errors lastError;
1275 int osError;
1276 if (!ConvertOSError(rval, lastError, osError))
1277 return lastError;
1279 rval = 0;
1280 if (readfds.IsPresent(h1))
1281 rval -= 1;
1282 if (readfds.IsPresent(h2))
1283 rval -= 2;
1285 return rval;
1289 PChannel::Errors PSocket::Select(SelectList & read)
1291 SelectList dummy1, dummy2;
1292 return Select(read, dummy1, dummy2, PMaxTimeInterval);
1296 PChannel::Errors PSocket::Select(SelectList & read, const PTimeInterval & timeout)
1298 SelectList dummy1, dummy2;
1299 return Select(read, dummy1, dummy2, timeout);
1303 PChannel::Errors PSocket::Select(SelectList & read, SelectList & write)
1305 SelectList dummy1;
1306 return Select(read, write, dummy1, PMaxTimeInterval);
1310 PChannel::Errors PSocket::Select(SelectList & read,
1311 SelectList & write,
1312 const PTimeInterval & timeout)
1314 SelectList dummy1;
1315 return Select(read, write, dummy1, timeout);
1319 PChannel::Errors PSocket::Select(SelectList & read,
1320 SelectList & write,
1321 SelectList & except)
1323 return Select(read, write, except, PMaxTimeInterval);
1327 PChannel::Errors PSocket::Select(SelectList & read,
1328 SelectList & write,
1329 SelectList & except,
1330 const PTimeInterval & timeout)
1332 int maxfds = 0;
1333 PINDEX nextfd = 0;
1334 PIntArray allfds(2*(read.GetSize()+write.GetSize()+except.GetSize()));
1336 P_fd_set readfds;
1337 PINDEX i;
1338 for (i = 0; i < read.GetSize(); i++) {
1339 if (!read[i].IsOpen())
1340 return NotOpen;
1341 int h = read[i].GetHandle();
1342 readfds += h;
1343 if (h > maxfds)
1344 maxfds = h;
1345 allfds[nextfd++] = h;
1346 allfds[nextfd++] = 1;
1349 P_fd_set writefds;
1350 for (i = 0; i < write.GetSize(); i++) {
1351 if (!write[i].IsOpen())
1352 return NotOpen;
1353 int h = write[i].GetHandle();
1354 writefds += h;
1355 if (h > maxfds)
1356 maxfds = h;
1357 allfds[nextfd++] = h;
1358 allfds[nextfd++] = 2;
1361 P_fd_set exceptfds;
1362 for (i = 0; i < except.GetSize(); i++) {
1363 if (!except[i].IsOpen())
1364 return NotOpen;
1365 int h = except[i].GetHandle();
1366 exceptfds += h;
1367 if (h > maxfds)
1368 maxfds = h;
1369 allfds[nextfd++] = h;
1370 allfds[nextfd++] = 4;
1372 #ifdef _MSC_VER
1373 #pragma warning(default:4018 4127)
1374 #endif
1376 int retval = os_select(maxfds+1,(fd_set*)readfds,(fd_set*)writefds,(fd_set*)exceptfds,allfds,timeout);
1378 Errors lastError;
1379 int osError;
1380 if (!ConvertOSError(retval, lastError, osError))
1381 return lastError;
1383 if (retval > 0) {
1384 for (i = 0; i < read.GetSize(); i++) {
1385 int h = read[i].GetHandle();
1386 if (h < 0)
1387 return Interrupted;
1388 if (!readfds.IsPresent(h))
1389 read.RemoveAt(i--);
1391 for (i = 0; i < write.GetSize(); i++) {
1392 int h = write[i].GetHandle();
1393 if (h < 0)
1394 return Interrupted;
1395 if (!writefds.IsPresent(h))
1396 write.RemoveAt(i--);
1398 for (i = 0; i < except.GetSize(); i++) {
1399 int h = except[i].GetHandle();
1400 if (h < 0)
1401 return Interrupted;
1402 if (!exceptfds.IsPresent(h))
1403 except.RemoveAt(i--);
1406 else {
1407 read.RemoveAll();
1408 write.RemoveAll();
1409 except.RemoveAll();
1412 return NoError;
1417 //////////////////////////////////////////////////////////////////////////////
1418 // PIPSocket
1420 PIPSocket::PIPSocket()
1425 void PIPSocket::ClearNameCache()
1427 pHostByName().mutex.Wait();
1428 pHostByAddr().mutex.Wait();
1429 pHostByName().RemoveAll();
1430 pHostByAddr().RemoveAll();
1431 #if (defined(_WIN32) || defined(WINDOWS)) && !defined(__NUCLEUS_MNT__) // Kludge to avoid strange NT bug
1432 static PTimeInterval delay = GetConfigTime("NT Bug Delay", 0);
1433 if (delay != 0) {
1434 ::Sleep(delay.GetInterval());
1435 ::gethostbyname("www.microsoft.com");
1437 #endif
1438 pHostByName().mutex.Signal();
1439 pHostByAddr().mutex.Signal();
1443 PString PIPSocket::GetName() const
1445 #if P_HAS_IPV6
1447 Psockaddr sa;
1448 socklen_t size = sa.GetSize();
1449 if (getpeername(os_handle, sa, &size) == 0)
1450 return GetHostName(sa.GetIP()) + psprintf(":%u", sa.GetPort());
1452 #else
1454 sockaddr_in address;
1455 socklen_t size = sizeof(address);
1456 if (getpeername(os_handle, (struct sockaddr *)&address, &size) == 0)
1457 return GetHostName(address.sin_addr) + psprintf(":%u", ntohs(address.sin_port));
1459 #endif
1461 return PString::Empty();
1465 PString PIPSocket::GetHostName()
1467 char name[100];
1468 if (gethostname(name, sizeof(name)-1) != 0)
1469 return "localhost";
1470 name[sizeof(name)-1] = '\0';
1471 return name;
1475 PString PIPSocket::GetHostName(const PString & hostname)
1477 // lookup the host address using inet_addr, assuming it is a "." address
1478 Address temp = hostname;
1479 if (temp != 0)
1480 return GetHostName(temp);
1482 PString canonicalname;
1483 if (pHostByName().GetHostName(hostname, canonicalname))
1484 return canonicalname;
1486 return hostname;
1490 PString PIPSocket::GetHostName(const Address & addr)
1492 if (addr == 0)
1493 return addr.AsString();
1495 PString hostname;
1496 if (pHostByAddr().GetHostName(addr, hostname))
1497 return hostname;
1499 return addr.AsString();
1503 BOOL PIPSocket::GetHostAddress(Address & addr)
1505 return pHostByName().GetHostAddress(GetHostName(), addr);
1509 BOOL PIPSocket::GetHostAddress(const PString & hostname, Address & addr)
1511 if (hostname.IsEmpty())
1512 return FALSE;
1514 // Check for special case of "[ipaddr]"
1515 if (hostname[0] == '[') {
1516 PINDEX end = hostname.Find(']');
1517 if (end != P_MAX_INDEX) {
1518 if (addr.FromString(hostname(1, end-1)))
1519 return TRUE;
1523 // Assuming it is a "." address and return if so
1524 if (addr.FromString(hostname))
1525 return TRUE;
1527 // otherwise lookup the name as a host name
1528 return pHostByName().GetHostAddress(hostname, addr);
1532 PStringArray PIPSocket::GetHostAliases(const PString & hostname)
1534 PStringArray aliases;
1536 // lookup the host address using inet_addr, assuming it is a "." address
1537 Address addr = hostname;
1538 if (addr != 0)
1539 pHostByAddr().GetHostAliases(addr, aliases);
1540 else
1541 pHostByName().GetHostAliases(hostname, aliases);
1543 return aliases;
1547 PStringArray PIPSocket::GetHostAliases(const Address & addr)
1549 PStringArray aliases;
1551 pHostByAddr().GetHostAliases(addr, aliases);
1553 return aliases;
1557 BOOL PIPSocket::GetLocalAddress(Address & addr)
1559 WORD dummy;
1560 return GetLocalAddress(addr, dummy);
1563 BOOL PIPSocket::GetLocalAddress(Address & addr, WORD & portNum)
1565 #if P_HAS_IPV6
1567 Psockaddr sa;
1568 socklen_t size = sa.GetSize();
1569 if (!ConvertOSError(::getsockname(os_handle, sa, &size)))
1570 return FALSE;
1572 addr = sa.GetIP();
1573 portNum = sa.GetPort();
1575 #else
1577 sockaddr_in address;
1578 socklen_t size = sizeof(address);
1579 if (!ConvertOSError(::getsockname(os_handle,(struct sockaddr*)&address,&size)))
1580 return FALSE;
1582 addr = address.sin_addr;
1583 portNum = ntohs(address.sin_port);
1585 #endif
1587 return TRUE;
1591 BOOL PIPSocket::GetPeerAddress(Address & addr)
1593 WORD portNum;
1594 return GetPeerAddress(addr, portNum);
1597 BOOL PIPSocket::GetPeerAddress(Address & addr, WORD & portNum)
1599 #if P_HAS_IPV6
1601 Psockaddr sa;
1602 socklen_t size = sa.GetSize();
1603 if (!ConvertOSError(::getpeername(os_handle, sa, &size)))
1604 return FALSE;
1606 addr = sa.GetIP();
1607 portNum = sa.GetPort();
1609 #else
1611 sockaddr_in address;
1612 socklen_t size = sizeof(address);
1613 if (!ConvertOSError(::getpeername(os_handle,(struct sockaddr*)&address,&size)))
1614 return FALSE;
1616 addr = address.sin_addr;
1617 portNum = ntohs(address.sin_port);
1619 #endif
1621 return TRUE;
1625 PString PIPSocket::GetLocalHostName()
1627 Address addr;
1629 if (GetLocalAddress(addr))
1630 return GetHostName(addr);
1632 return PString::Empty();
1636 PString PIPSocket::GetPeerHostName()
1638 Address addr;
1640 if (GetPeerAddress(addr))
1641 return GetHostName(addr);
1643 return PString::Empty();
1647 BOOL PIPSocket::Connect(const PString & host)
1649 Address ipnum;
1650 if (GetHostAddress(host, ipnum))
1651 return Connect(INADDR_ANY, 0, ipnum);
1652 return FALSE;
1656 BOOL PIPSocket::Connect(const Address & addr)
1658 return Connect(INADDR_ANY, 0, addr);
1662 BOOL PIPSocket::Connect(WORD localPort, const Address & addr)
1664 return Connect(INADDR_ANY, localPort, addr);
1668 BOOL PIPSocket::Connect(const Address & iface, const Address & addr)
1670 return Connect(iface, 0, addr);
1674 BOOL PIPSocket::Connect(const Address & iface, WORD localPort, const Address & addr)
1676 // close the port if it is already open
1677 if (IsOpen())
1678 Close();
1680 // make sure we have a port
1681 PAssert(port != 0, "Cannot connect socket without setting port");
1683 #if P_HAS_IPV6
1685 Psockaddr sa(addr, port);
1687 // attempt to create a socket with the right family
1688 if (!OpenSocket(sa->sa_family))
1689 return FALSE;
1691 if (localPort != 0 || iface.IsValid()) {
1692 Psockaddr bind_sa(iface, localPort);
1694 if (sa->sa_family != bind_sa->sa_family) {
1695 os_close();
1696 return FALSE;
1699 if (!SetOption(SO_REUSEADDR, 0)) {
1700 os_close();
1701 return FALSE;
1704 if (!ConvertOSError(::bind(os_handle, bind_sa, bind_sa.GetSize()))) {
1705 os_close();
1706 return FALSE;
1710 // attempt to connect
1711 if (os_connect(sa, sa.GetSize()))
1712 return TRUE;
1714 #else
1716 // attempt to create a socket
1717 if (!OpenSocket())
1718 return FALSE;
1720 // attempt to connect
1721 sockaddr_in sin;
1722 if (localPort != 0 || iface.IsValid()) {
1723 if (!SetOption(SO_REUSEADDR, 0)) {
1724 os_close();
1725 return FALSE;
1727 memset(&sin, 0, sizeof(sin));
1728 sin.sin_family = AF_INET;
1729 sin.sin_addr.s_addr = iface;
1730 sin.sin_port = htons(localPort); // set the port
1731 if (!ConvertOSError(::bind(os_handle, (struct sockaddr*)&sin, sizeof(sin)))) {
1732 os_close();
1733 return FALSE;
1737 memset(&sin, 0, sizeof(sin));
1738 sin.sin_family = AF_INET;
1739 sin.sin_port = htons(port); // set the port
1740 sin.sin_addr = addr;
1741 if (os_connect((struct sockaddr *)&sin, sizeof(sin)))
1742 return TRUE;
1744 #endif
1746 os_close();
1747 return FALSE;
1751 BOOL PIPSocket::Listen(unsigned queueSize, WORD newPort, Reusability reuse)
1753 return Listen(INADDR_ANY, queueSize, newPort, reuse);
1757 BOOL PIPSocket::Listen(const Address & bindAddr,
1758 unsigned,
1759 WORD newPort,
1760 Reusability reuse)
1762 // make sure we have a port
1763 if (newPort != 0)
1764 port = newPort;
1766 #if P_HAS_IPV6
1767 Psockaddr bind_sa(bindAddr, port);
1769 if (IsOpen()) {
1770 int socketType;
1771 if (!GetOption(SO_TYPE, socketType, SOL_SOCKET) || bind_sa->sa_family != socketType)
1772 Close();
1774 #endif
1776 if (!IsOpen()) {
1777 // attempt to create a socket
1778 #if P_HAS_IPV6
1779 if (!OpenSocket(bind_sa->sa_family))
1780 return FALSE;
1781 #else
1782 if (!OpenSocket())
1783 return FALSE;
1784 #endif
1787 // attempt to listen
1788 if (!SetOption(SO_REUSEADDR, reuse == CanReuseAddress ? 1 : 0)) {
1789 os_close();
1790 return FALSE;
1793 #if P_HAS_IPV6
1795 if (ConvertOSError(::bind(os_handle, bind_sa, bind_sa.GetSize()))) {
1796 Psockaddr sa;
1797 socklen_t size = sa.GetSize();
1798 if (!ConvertOSError(::getsockname(os_handle, sa, &size)))
1799 return FALSE;
1801 port = sa.GetPort();
1802 return TRUE;
1805 #else
1807 // attempt to listen
1808 sockaddr_in sin;
1809 memset(&sin, 0, sizeof(sin));
1810 sin.sin_family = AF_INET;
1811 sin.sin_addr.s_addr = bindAddr;
1812 sin.sin_port = htons(port); // set the port
1814 #ifdef __NUCLEUS_NET__
1815 int bind_result;
1816 if (port == 0)
1817 bind_result = ::bindzero(os_handle, (struct sockaddr*)&sin, sizeof(sin));
1818 else
1819 bind_result = ::bind(os_handle, (struct sockaddr*)&sin, sizeof(sin));
1820 if (ConvertOSError(bind_result))
1821 #else
1822 if (ConvertOSError(::bind(os_handle, (struct sockaddr*)&sin, sizeof(sin))))
1823 #endif
1825 socklen_t size = sizeof(sin);
1826 if (ConvertOSError(::getsockname(os_handle, (struct sockaddr*)&sin, &size))) {
1827 port = ntohs(sin.sin_port);
1828 return TRUE;
1832 #endif
1834 os_close();
1835 return FALSE;
1839 ///////////////////////////////////////////////////////////////////////////////
1840 // PIPSocket::Address
1842 static PIPSocket::Address loopback4(127,0,0,1);
1843 static PIPSocket::Address broadcast4(INADDR_BROADCAST);
1844 static in_addr inaddr_empty;
1845 #if P_HAS_IPV6
1846 static PIPSocket::Address loopback6(16,(const BYTE *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\001");
1847 static in6_addr inaddr6_empty;
1848 #endif
1851 const PIPSocket::Address & PIPSocket::Address::GetLoopback()
1853 return loopback4;
1857 #if P_HAS_IPV6
1858 const PIPSocket::Address & PIPSocket::Address::GetLoopback6()
1860 return loopback6;
1862 #endif
1865 const PIPSocket::Address & PIPSocket::Address::GetBroadcast()
1867 return broadcast4;
1871 PIPSocket::Address::Address()
1873 *this = loopback4;
1877 PIPSocket::Address::Address(const PString & dotNotation)
1879 operator=(dotNotation);
1883 PIPSocket::Address::Address(PINDEX len, const BYTE * bytes)
1885 switch (len) {
1886 #if P_HAS_IPV6
1887 case 16 :
1888 version = 6;
1889 memcpy(&v.six, bytes, len);
1890 break;
1891 #endif
1892 case 4 :
1893 version = 4;
1894 memcpy(&v.four, bytes, len);
1895 break;
1897 case 0 :
1898 version = 0;
1903 PIPSocket::Address::Address(const in_addr & addr)
1905 version = 4;
1906 v.four = addr;
1910 #if P_HAS_IPV6
1911 PIPSocket::Address::Address(const in6_addr & addr)
1913 version = 6;
1914 v.six = addr;
1916 #endif
1919 #ifdef __NUCLEUS_NET__
1920 PIPSocket::Address::Address(const struct id_struct & addr)
1922 operator=(addr);
1926 PIPSocket::Address & PIPSocket::Address::operator=(const struct id_struct & addr)
1928 s_addr = (((unsigned long)addr.is_ip_addrs[0])<<24) +
1929 (((unsigned long)addr.is_ip_addrs[1])<<16) +
1930 (((unsigned long)addr.is_ip_addrs[2])<<8) +
1931 (((unsigned long)addr.is_ip_addrs[3]));
1932 return *this;
1934 #endif
1937 PIPSocket::Address & PIPSocket::Address::operator=(const in_addr & addr)
1939 version = 4;
1940 v.four = addr;
1941 return *this;
1944 #if P_HAS_IPV6
1945 PIPSocket::Address & PIPSocket::Address::operator=(const in6_addr & addr)
1947 version = 6;
1948 v.six = addr;
1949 return *this;
1951 #endif
1954 PObject::Comparison PIPSocket::Address::Compare(const PObject & obj) const
1956 const PIPSocket::Address & other = (const PIPSocket::Address &)obj;
1958 if (version < other.version)
1959 return LessThan;
1960 if (version > other.version)
1961 return GreaterThan;
1963 #if P_HAS_IPV6
1964 if (version == 6) {
1965 int result = memcmp(&v.six, &other.v.six, sizeof(v.six));
1966 if (result < 0)
1967 return LessThan;
1968 if (result > 0)
1969 return GreaterThan;
1970 return EqualTo;
1972 #endif
1974 if ((DWORD)*this < other)
1975 return LessThan;
1976 if ((DWORD)*this > other)
1977 return GreaterThan;
1978 return EqualTo;
1982 #if P_HAS_IPV6
1983 BOOL PIPSocket::Address::operator==(in6_addr & addr) const
1985 PIPSocket::Address a(addr);
1986 return Compare(a) == EqualTo;
1988 #endif
1991 BOOL PIPSocket::Address::operator==(in_addr & addr) const
1993 PIPSocket::Address a(addr);
1994 return Compare(a) == EqualTo;
1998 BOOL PIPSocket::Address::operator==(DWORD dw) const
2000 if (dw != 0)
2001 return (DWORD)*this == dw;
2003 return !IsValid();
2007 PIPSocket::Address & PIPSocket::Address::operator=(const PString & dotNotation)
2009 #if P_HAS_IPV6
2011 struct addrinfo *res;
2012 struct addrinfo hints= {AI_PASSIVE, 0, SOCK_STREAM, 0, 0, NULL, NULL, NULL };
2014 version = 0;
2016 hints.ai_family = PF_UNSPEC;//PF_INET6; Could be IPv4: x.x.x.x or IPv6: x:x:x:x::x
2017 hints.ai_socktype = 0;//SOCK_STREAM;
2019 if (getaddrinfo((const char *)dotNotation, NULL , &hints, &res) == 0) {
2020 if (res->ai_family == PF_INET6) {
2021 // IPv6 addr
2022 version = 6;
2023 struct sockaddr_in6 * addr_in6 = (struct sockaddr_in6 *)res->ai_addr;
2024 v.six = addr_in6->sin6_addr;
2025 } else {
2026 // IPv4 addr
2027 version = 4;
2028 struct sockaddr_in * addr_in = (struct sockaddr_in *)res->ai_addr;
2029 v.four = addr_in->sin_addr;
2031 freeaddrinfo(res);
2034 #else //P_HAS_IPV6
2036 if (::strspn(dotNotation, "0123456789.") < ::strlen(dotNotation))
2037 *this = 0;
2038 else {
2039 version = 4;
2040 v.four.s_addr = inet_addr((const char *)dotNotation);
2041 if (v.four.s_addr == (DWORD)INADDR_NONE)
2042 v.four.s_addr = 0;
2045 #endif
2047 return *this;
2051 PString PIPSocket::Address::AsString() const
2053 #if P_HAS_IPV6
2054 if (version == 6) {
2055 PString str;
2056 Psockaddr sa(*this, 0);
2057 PAssertOS(getnameinfo(sa, sa.GetSize(), str.GetPointer(1024), 1024, NULL, 0, NI_NUMERICHOST) == 0);
2058 PINDEX percent = str.Find('%'); // used for scoped address e.g. fe80::1%ne0, (ne0=network interface 0)
2059 if (percent != P_MAX_INDEX)
2060 str[percent] = '\0';
2061 str.MakeMinimumSize();
2062 return str;
2064 #endif
2066 return inet_ntoa(v.four);
2070 BOOL PIPSocket::Address::FromString(const PString & dotNotation)
2072 (*this) = dotNotation;
2073 return IsValid();
2078 PIPSocket::Address::operator PString() const
2080 return AsString();
2084 PIPSocket::Address::operator in_addr() const
2086 if (version != 4)
2087 return inaddr_empty;
2089 return v.four;
2093 #if P_HAS_IPV6
2094 PIPSocket::Address::operator in6_addr() const
2096 if (version != 6)
2097 return inaddr6_empty;
2099 return v.six;
2101 #endif
2104 BYTE PIPSocket::Address::operator[](PINDEX idx) const
2106 PASSERTINDEX(idx);
2107 #if P_HAS_IPV6
2108 if (version == 6) {
2109 PAssert(idx <= 15, PInvalidParameter);
2110 return v.six.s6_addr[idx];
2112 #endif
2114 PAssert(idx <= 3, PInvalidParameter);
2115 return ((BYTE *)&v.four)[idx];
2119 ostream & operator<<(ostream & s, const PIPSocket::Address & a)
2121 return s << a.AsString();
2125 istream & operator>>(istream & s, PIPSocket::Address & a)
2127 /// Not IPv6 ready !!!!!!!!!!!!!
2128 char dot1, dot2, dot3;
2129 unsigned b1, b2, b3, b4;
2130 s >> b1 >> dot1 >> b2 >> dot2 >> b3 >> dot3 >> b4;
2131 if (!s && (dot1 != '.' || dot2 != '.' || dot3 != '.'))
2132 s.clear(ios::failbit);
2134 a = PIPSocket::Address((BYTE)b1, (BYTE)b2, (BYTE)b3, (BYTE)b4);
2135 return s;
2139 PINDEX PIPSocket::Address::GetSize() const
2141 switch (version) {
2142 #if P_HAS_IPV6
2143 case 6 :
2144 return 16;
2145 #endif
2147 case 4 :
2148 return 4;
2151 return 0;
2155 BOOL PIPSocket::Address::IsValid() const
2157 switch (version) {
2158 #if P_HAS_IPV6
2159 case 6 :
2160 return memcmp(&v.six, &inaddr6_empty, sizeof(v.six)) != 0;
2161 #endif
2163 case 4 :
2164 return (DWORD)*this != INADDR_ANY;
2166 return FALSE;
2170 BOOL PIPSocket::Address::IsLoopback() const
2172 #if P_HAS_IPV6
2173 if (version == 6)
2174 return *this == loopback6;
2175 #endif
2176 return *this == loopback4;
2180 BOOL PIPSocket::Address::IsBroadcast() const
2182 #if P_HAS_IPV6
2183 if (version == 6) // In IPv6, no broadcast exist. Only multicast
2184 return FALSE;
2185 #endif
2187 return *this == broadcast4;
2191 PIPSocket::InterfaceEntry::InterfaceEntry(const PString & _name,
2192 const Address & _addr,
2193 const Address & _mask,
2194 const PString & _macAddr)
2195 : name(_name.Trim()),
2196 ipAddr(_addr),
2197 netMask(_mask),
2198 macAddr(_macAddr)
2203 void PIPSocket::InterfaceEntry::PrintOn(ostream & strm) const
2205 strm << ipAddr;
2206 if (!macAddr)
2207 strm << " <" << macAddr << '>';
2208 if (!name)
2209 strm << " (" << name << ')';
2213 #ifdef __NUCLEUS_NET__
2214 BOOL PIPSocket::GetInterfaceTable(InterfaceTable & table)
2216 InterfaceEntry *IE;
2217 list<IPInterface>::iterator i;
2218 for(i=Route4Configuration->Getm_IPInterfaceList().begin();
2219 i!=Route4Configuration->Getm_IPInterfaceList().end();
2220 i++)
2222 char ma[6];
2223 for(int j=0; j<6; j++) ma[j]=(*i).Getm_macaddr(j);
2224 IE = new InterfaceEntry((*i).Getm_name().c_str(), (*i).Getm_ipaddr(), ma );
2225 if(!IE) return false;
2226 table.Append(IE);
2228 return true;
2230 #endif
2233 //////////////////////////////////////////////////////////////////////////////
2234 // PTCPSocket
2236 PTCPSocket::PTCPSocket(WORD newPort)
2238 SetPort(newPort);
2242 PTCPSocket::PTCPSocket(const PString & service)
2244 SetPort(service);
2248 PTCPSocket::PTCPSocket(const PString & address, WORD newPort)
2250 SetPort(newPort);
2251 Connect(address);
2255 PTCPSocket::PTCPSocket(const PString & address, const PString & service)
2257 SetPort(service);
2258 Connect(address);
2262 PTCPSocket::PTCPSocket(PSocket & socket)
2264 Accept(socket);
2268 PTCPSocket::PTCPSocket(PTCPSocket & tcpSocket)
2270 Accept(tcpSocket);
2274 PObject * PTCPSocket::Clone() const
2276 return new PTCPSocket(port);
2280 // By default IPv4 only adresses
2281 BOOL PTCPSocket::OpenSocket()
2283 return ConvertOSError(os_handle = os_socket(AF_INET, SOCK_STREAM, 0));
2287 // ipAdressFamily should be AF_INET or AF_INET6
2288 BOOL PTCPSocket::OpenSocket(int ipAdressFamily)
2290 return ConvertOSError(os_handle = os_socket(ipAdressFamily, SOCK_STREAM, 0));
2294 const char * PTCPSocket::GetProtocolName() const
2296 return "tcp";
2300 BOOL PTCPSocket::Write(const void * buf, PINDEX len)
2302 flush();
2303 PINDEX writeCount = 0;
2305 while (len > 0) {
2306 if (!os_sendto(((char *)buf)+writeCount, len, 0, NULL, 0))
2307 return FALSE;
2308 writeCount += lastWriteCount;
2309 len -= lastWriteCount;
2312 lastWriteCount = writeCount;
2313 return TRUE;
2317 BOOL PTCPSocket::Listen(unsigned queueSize, WORD newPort, Reusability reuse)
2319 return Listen(INADDR_ANY, queueSize, newPort, reuse);
2323 BOOL PTCPSocket::Listen(const Address & bindAddr,
2324 unsigned queueSize,
2325 WORD newPort,
2326 Reusability reuse)
2328 if (PIPSocket::Listen(bindAddr, queueSize, newPort, reuse) &&
2329 ConvertOSError(::listen(os_handle, queueSize)))
2330 return TRUE;
2332 os_close();
2333 return FALSE;
2337 BOOL PTCPSocket::Accept(PSocket & socket)
2339 PAssert(socket.IsDescendant(PIPSocket::Class()), "Invalid listener socket");
2341 #if P_HAS_IPV6
2343 Psockaddr sa;
2344 PINDEX size = sa.GetSize();
2345 if (!os_accept(socket, sa, &size))
2346 return FALSE;
2348 #else
2350 sockaddr_in address;
2351 address.sin_family = AF_INET;
2352 PINDEX size = sizeof(address);
2353 if (!os_accept(socket, (struct sockaddr *)&address, &size))
2354 return FALSE;
2356 #endif
2358 port = ((PIPSocket &)socket).GetPort();
2359 return TRUE;
2363 BOOL PTCPSocket::WriteOutOfBand(void const * buf, PINDEX len)
2365 #ifdef __NUCLEUS_NET__
2366 PAssertAlways("WriteOutOfBand unavailable on Nucleus Plus");
2367 //int count = NU_Send(os_handle, (char *)buf, len, 0);
2368 int count = ::send(os_handle, (const char *)buf, len, 0);
2369 #elif defined(P_VXWORKS)
2370 int count = ::send(os_handle, (char *)buf, len, MSG_OOB);
2371 #else
2372 int count = ::send(os_handle, (const char *)buf, len, MSG_OOB);
2373 #endif
2374 if (count < 0) {
2375 lastWriteCount = 0;
2376 return ConvertOSError(count, LastWriteError);
2378 else {
2379 lastWriteCount = count;
2380 return TRUE;
2385 void PTCPSocket::OnOutOfBand(const void *, PINDEX)
2390 //////////////////////////////////////////////////////////////////////////////
2391 // PIPDatagramSocket
2393 PIPDatagramSocket::PIPDatagramSocket()
2398 BOOL PIPDatagramSocket::ReadFrom(void * buf, PINDEX len,
2399 Address & addr, WORD & port)
2401 lastReadCount = 0;
2403 #if P_HAS_IPV6
2405 Psockaddr sa;
2406 PINDEX size = sa.GetSize();
2407 if (os_recvfrom(buf, len, 0, sa, &size)) {
2408 addr = sa.GetIP();
2409 port = sa.GetPort();
2412 #else
2414 sockaddr_in sockAddr;
2415 PINDEX addrLen = sizeof(sockAddr);
2416 if (os_recvfrom(buf, len, 0, (struct sockaddr *)&sockAddr, &addrLen)) {
2417 addr = sockAddr.sin_addr;
2418 port = ntohs(sockAddr.sin_port);
2421 #endif
2423 return lastReadCount > 0;
2427 BOOL PIPDatagramSocket::WriteTo(const void * buf, PINDEX len,
2428 const Address & addr, WORD port)
2430 lastWriteCount = 0;
2432 #if P_HAS_IPV6
2434 Psockaddr sa(addr, port);
2435 return os_sendto(buf, len, 0, sa, sa.GetSize()) && lastWriteCount >= len;
2437 #else
2439 sockaddr_in sockAddr;
2440 sockAddr.sin_family = AF_INET;
2441 sockAddr.sin_addr = addr;
2442 sockAddr.sin_port = htons(port);
2443 return os_sendto(buf, len, 0, (struct sockaddr *)&sockAddr, sizeof(sockAddr))
2444 && lastWriteCount >= len;
2446 #endif
2450 //////////////////////////////////////////////////////////////////////////////
2451 // PUDPSocket
2453 PUDPSocket::PUDPSocket(WORD newPort)
2455 sendPort = 0;
2456 SetPort(newPort);
2457 OpenSocket();
2461 PUDPSocket::PUDPSocket(const PString & service)
2463 sendPort = 0;
2464 SetPort(service);
2465 OpenSocket();
2469 PUDPSocket::PUDPSocket(const PString & address, WORD newPort)
2471 sendPort = 0;
2472 SetPort(newPort);
2473 Connect(address);
2477 PUDPSocket::PUDPSocket(const PString & address, const PString & service)
2479 sendPort = 0;
2480 SetPort(service);
2481 Connect(address);
2485 BOOL PUDPSocket::OpenSocket()
2487 return ConvertOSError(os_handle = os_socket(AF_INET, SOCK_DGRAM, 0));
2490 BOOL PUDPSocket::OpenSocket(int ipAdressFamily)
2492 return ConvertOSError(os_handle = os_socket(ipAdressFamily, SOCK_DGRAM, 0));
2495 const char * PUDPSocket::GetProtocolName() const
2497 return "udp";
2501 BOOL PUDPSocket::Connect(const PString & address)
2503 sendPort = 0;
2504 return PIPDatagramSocket::Connect(address);
2508 BOOL PUDPSocket::Read(void * buf, PINDEX len)
2510 return PIPDatagramSocket::ReadFrom(buf, len, lastReceiveAddress, lastReceivePort);
2514 BOOL PUDPSocket::Write(const void * buf, PINDEX len)
2516 if (sendPort == 0)
2517 return PIPDatagramSocket::Write(buf, len);
2518 else
2519 return PIPDatagramSocket::WriteTo(buf, len, sendAddress, sendPort);
2523 void PUDPSocket::SetSendAddress(const Address & newAddress, WORD newPort)
2525 sendAddress = newAddress;
2526 sendPort = newPort;
2530 void PUDPSocket::GetSendAddress(Address & address, WORD & port)
2532 address = sendAddress;
2533 port = sendPort;
2537 void PUDPSocket::GetLastReceiveAddress(Address & address, WORD & port)
2539 address = lastReceiveAddress;
2540 port = lastReceivePort;
2544 // End Of File ///////////////////////////////////////////////////////////////