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
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): ______________________________________.
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
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
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
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
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
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
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
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
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
484 #ifdef __NUCLEUS_PLUS__
485 #include <ConfigurationClass.h>
491 #include <ptlib/sockets.h>
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;
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....
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
) {
539 return sizeof(sockaddr_in
);
541 // RFC 2133 (Old IPv6 spec) size is 24
542 // RFC 2553 (New IPv6 spec) size is 28
543 return sizeof(sockaddr_in6
);
545 return sizeof(storage
);
550 PIPSocket::Address
Psockaddr::GetIP() const
552 switch (((sockaddr
*)&storage
)->sa_family
) {
554 return ((sockaddr_in
*)&storage
)->sin_addr
;
556 return ((sockaddr_in6
*)&storage
)->sin6_addr
;
563 WORD
Psockaddr::GetPort() const
565 switch (((sockaddr
*)&storage
)->sa_family
) {
567 return ntohs(((sockaddr_in
*)&storage
)->sin_port
);
569 return ntohs(((sockaddr_in6
*)&storage
)->sin6_port
);
578 #if (defined(_WIN32) || defined(WINDOWS)) && !defined(__NUCLEUS_MNT__)
579 static PWinSock dummyForWinSock
; // Assure winsock is initialised
582 #if (defined(P_PTHREADS) && !defined(P_THREAD_SAFE_CLIB)) || defined(__NUCLEUS_PLUS__)
583 #define REENTRANT_BUFFER_LEN 1024
587 class PIPCacheData
: public PObject
589 PCLASSINFO(PIPCacheData
, PObject
)
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;
598 PIPSocket::Address address
;
604 PDICTIONARY(PHostByName_private
, PCaselessString
, PIPCacheData
);
606 class PHostByName
: PHostByName_private
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
);
613 PIPCacheData
* GetHost(const PString
& name
);
615 friend void PIPSocket::ClearNameCache();
618 static PHostByName
& pHostByName()
620 static PHostByName t
;
624 class PIPCacheKey
: public PObject
626 PCLASSINFO(PIPCacheKey
, PObject
)
628 PIPCacheKey(const PIPSocket::Address
& a
)
631 PObject
* Clone() const
632 { return new PIPCacheKey(*this); }
634 PINDEX
HashFunction() const
635 { return (addr
[1] + addr
[2] + addr
[3])%41; }
638 PIPSocket::Address addr
;
641 PDICTIONARY(PHostByAddr_private
, PIPCacheKey
, PIPCacheData
);
643 class PHostByAddr
: PHostByAddr_private
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
);
650 PIPCacheData
* GetHost(const PIPSocket::Address
& addr
);
652 friend void PIPSocket::ClearNameCache();
655 static PHostByAddr
& pHostByAddr()
657 static PHostByAddr t
;
664 //////////////////////////////////////////////////////////////////////////////
667 PIPCacheData::PIPCacheData(struct hostent
* host_info
, const char * original
)
669 if (host_info
== NULL
) {
674 hostname
= host_info
->h_name
;
675 if (host_info
->h_addr
!= NULL
)
677 address
= *(DWORD
*)host_info
->h_addr
;
679 address
= PIPSocket::Address(h_length
, host_info
->h_addr
);
681 aliases
.AppendString(host_info
->h_name
);
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
)
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
709 PTimeInterval age
= now
- birthDate
;
710 return age
> retirement
;
714 BOOL
PHostByName::GetHostName(const PString
& name
, PString
& hostname
)
716 PIPCacheData
* host
= GetHost(name
);
719 hostname
= host
->GetHostName();
720 hostname
.MakeUnique();
729 BOOL
PHostByName::GetHostAddress(const PString
& name
, PIPSocket::Address
& address
)
731 PIPCacheData
* host
= GetHost(name
);
734 address
= host
->GetHostAddress();
742 BOOL
PHostByName::GetHostAliases(const PString
& name
, PStringArray
& aliases
)
744 PIPCacheData
* host
= GetHost(name
);
747 const PStringList
& a
= host
->GetHostAliases();
748 aliases
.SetSize(a
.GetSize());
749 for (PINDEX i
= 0; i
< a
.GetSize(); i
++)
758 PIPCacheData
* PHostByName::GetHost(const PString
& name
)
762 PCaselessString key
= name
;
763 PIPCacheData
* host
= GetAt(key
);
765 if (host
!= NULL
&& host
->HasAged()) {
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
;
780 struct hostent
* host_info
;
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
793 #if !defined(P_AIX) && !defined(P_RTEMS) // that I get no warnings
794 char buffer
[REENTRANT_BUFFER_LEN
];
795 struct hostent hostEnt
;
799 ::gethostbyname_r(name
,
801 buffer
, REENTRANT_BUFFER_LEN
,
806 ::gethostbyname_r(name
,
809 localErrNo
= h_errno
;
811 #elif defined P_RTEMS
812 host_info
= *::gethostbyname(name
);
814 host_info
= ::gethostbyname_r(name
,
815 &hostEnt
, buffer
, REENTRANT_BUFFER_LEN
,
819 #elif defined P_VXWORKS
820 struct hostent hostEnt
;
821 host_info
= Vx_gethostbyname((char *)name
, &hostEnt
);
822 localErrNo
= h_errno
;
824 host_info
= ::gethostbyname(name
);
825 localErrNo
= h_errno
;
827 } while (localErrNo
== TRY_AGAIN
&& --retry
> 0);
831 if (localErrNo
!= NETDB_SUCCESS
|| retry
== 0)
834 #if defined(P_AIX) || defined(P_RTEMS)
835 host
= new PIPCacheData (&host_info
, (const char*) name
);
837 host
= new PIPCacheData(host_info
, name
);
843 if (host
->GetHostAddress() == 0)
850 BOOL
PHostByAddr::GetHostName(const PIPSocket::Address
& addr
, PString
& hostname
)
852 PIPCacheData
* host
= GetHost(addr
);
855 hostname
= host
->GetHostName();
856 hostname
.MakeUnique();
864 BOOL
PHostByAddr::GetHostAddress(const PIPSocket::Address
& addr
, PIPSocket::Address
& address
)
866 PIPCacheData
* host
= GetHost(addr
);
869 address
= host
->GetHostAddress();
876 BOOL
PHostByAddr::GetHostAliases(const PIPSocket::Address
& addr
, PStringArray
& aliases
)
878 PIPCacheData
* host
= GetHost(addr
);
881 const PStringList
& a
= host
->GetHostAliases();
882 aliases
.SetSize(a
.GetSize());
883 for (PINDEX i
= 0; i
< a
.GetSize(); i
++)
891 PIPCacheData
* PHostByAddr::GetHost(const PIPSocket::Address
& addr
)
895 PIPCacheKey key
= addr
;
896 PIPCacheData
* host
= GetAt(key
);
898 if (host
!= NULL
&& host
->HasAged()) {
907 struct hostent_data ht_data
;
908 struct hostent host_info
;
910 struct hostent host_info
;
912 struct hostent
* host_info
;
916 int localErrNo
= NETDB_SUCCESS
;
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
923 #if !defined(P_AIX) && !defined(P_RTEMS) // that I get no warnings
925 char buffer
[REENTRANT_BUFFER_LEN
];
926 struct hostent hostEnt
;
930 ::gethostbyaddr_r((const char *)&addr
, sizeof(addr
),
933 buffer
, REENTRANT_BUFFER_LEN
,
937 ::gethostbyaddr_r((char *)&addr
, sizeof(addr
),
941 localErrNo
= h_errno
;
942 #elif defined P_RTEMS
943 host_info
= *::gethostbyaddr((const char *)&addr
, sizeof(addr
), PF_INET
);
944 localErrNo
= h_errno
;
946 host_info
= ::gethostbyaddr_r((const char *)&addr
, sizeof(addr
), PF_INET
,
947 &hostEnt
, buffer
, REENTRANT_BUFFER_LEN
, &localErrNo
);
950 #elif defined P_VXWORKS
951 struct hostent hostEnt
;
952 host_info
= Vx_gethostbyaddr((char *)&addr
, &hostEnt
);
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
;
962 } while (localErrNo
== TRY_AGAIN
&& --retry
> 0);
966 if (localErrNo
!= NETDB_SUCCESS
|| retry
== 0)
969 #if defined(P_AIX) || defined(P_RTEMS)
970 host
= new PIPCacheData(&host_info
, addr
.AsString());
972 host
= new PIPCacheData(host_info
, addr
.AsString());
978 if (host
->GetHostAddress() == 0)
985 //////////////////////////////////////////////////////////////////////////////
989 #pragma warning(push)
990 #pragma warning(disable:4127)
1000 P_fd_set::P_fd_set(SOCKET fd
)
1008 P_fd_set
& P_fd_set::operator=(SOCKET fd
)
1010 PAssert(fd
< max_fd
, PInvalidParameter
);
1017 P_fd_set
& P_fd_set::operator+=(SOCKET fd
)
1019 PAssert(fd
< max_fd
, PInvalidParameter
);
1025 P_fd_set
& P_fd_set::operator-=(SOCKET fd
)
1027 PAssert(fd
< max_fd
, PInvalidParameter
);
1033 #pragma warning(pop)
1037 //////////////////////////////////////////////////////////////////////////////
1040 P_timeval::P_timeval()
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();
1057 //////////////////////////////////////////////////////////////////////////////
1066 BOOL
PSocket::Connect(const PString
&)
1068 PAssertAlways("Illegal operation.");
1073 BOOL
PSocket::Listen(unsigned, WORD
, Reusability
)
1075 PAssertAlways("Illegal operation.");
1080 BOOL
PSocket::Accept(PSocket
&)
1082 PAssertAlways("Illegal operation.");
1087 BOOL
PSocket::SetOption(int option
, int value
, int level
)
1090 if(option
== SO_RCVBUF
|| option
== SO_SNDBUF
|| option
== IP_TOS
)
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
)
1110 socklen_t valSize
= sizeof(value
);
1111 return ConvertOSError(::getsockopt(os_handle
, level
, option
,
1112 (char *)&value
, &valSize
));
1117 BOOL
PSocket::GetOption(int option
, void * valuePtr
, PINDEX valueSize
, int level
)
1122 return ConvertOSError(::getsockopt(os_handle
, level
, option
,
1123 (char *)valuePtr
, (socklen_t
*)&valueSize
));
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
);
1139 return ent
->p_proto
;
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
);
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");
1175 #elif defined(_WIN32_WCE)
1176 PAssertAlways("PSocket::GetPortByService: problem for WindowsCE as no port given.");
1178 #elif defined(P_VXWORKS)
1179 PAssertAlways("PSocket::GetPortByService: problem as no ::getservbyname in VxWorks");
1182 PINDEX space
= service
.FindOneOf(" \t\r\n");
1183 struct servent
* serv
= ::getservbyname(service(0, space
-1), protocol
);
1185 return ntohs(serv
->s_port
);
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
);
1195 if (portNum
< 0 || portNum
> 65535)
1198 return (WORD
)portNum
;
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
);
1214 return PString(serv
->s_name
);
1217 return PString(PString::Unsigned
, port
);
1221 void PSocket::SetPort(WORD newPort
)
1223 PAssert(!IsOpen(), "Cannot change port number of opened socket");
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
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
,
1255 const PTimeInterval
& timeout
)
1257 if (!sock1
.IsOpen() || !sock2
.IsOpen())
1260 int h1
= sock1
.GetHandle();
1261 int h2
= sock2
.GetHandle();
1267 PIntArray
allfds(4);
1272 int rval
= os_select(PMAX(h1
, h2
)+1, (fd_set
*)readfds
, NULL
, NULL
, allfds
, timeout
);
1276 if (!ConvertOSError(rval
, lastError
, osError
))
1280 if (readfds
.IsPresent(h1
))
1282 if (readfds
.IsPresent(h2
))
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
)
1306 return Select(read
, write
, dummy1
, PMaxTimeInterval
);
1310 PChannel::Errors
PSocket::Select(SelectList
& read
,
1312 const PTimeInterval
& timeout
)
1315 return Select(read
, write
, dummy1
, timeout
);
1319 PChannel::Errors
PSocket::Select(SelectList
& read
,
1321 SelectList
& except
)
1323 return Select(read
, write
, except
, PMaxTimeInterval
);
1327 PChannel::Errors
PSocket::Select(SelectList
& read
,
1329 SelectList
& except
,
1330 const PTimeInterval
& timeout
)
1334 PIntArray
allfds(2*(read
.GetSize()+write
.GetSize()+except
.GetSize()));
1338 for (i
= 0; i
< read
.GetSize(); i
++) {
1339 if (!read
[i
].IsOpen())
1341 int h
= read
[i
].GetHandle();
1345 allfds
[nextfd
++] = h
;
1346 allfds
[nextfd
++] = 1;
1350 for (i
= 0; i
< write
.GetSize(); i
++) {
1351 if (!write
[i
].IsOpen())
1353 int h
= write
[i
].GetHandle();
1357 allfds
[nextfd
++] = h
;
1358 allfds
[nextfd
++] = 2;
1362 for (i
= 0; i
< except
.GetSize(); i
++) {
1363 if (!except
[i
].IsOpen())
1365 int h
= except
[i
].GetHandle();
1369 allfds
[nextfd
++] = h
;
1370 allfds
[nextfd
++] = 4;
1373 #pragma warning(default:4018 4127)
1376 int retval
= os_select(maxfds
+1,(fd_set
*)readfds
,(fd_set
*)writefds
,(fd_set
*)exceptfds
,allfds
,timeout
);
1380 if (!ConvertOSError(retval
, lastError
, osError
))
1384 for (i
= 0; i
< read
.GetSize(); i
++) {
1385 int h
= read
[i
].GetHandle();
1388 if (!readfds
.IsPresent(h
))
1391 for (i
= 0; i
< write
.GetSize(); i
++) {
1392 int h
= write
[i
].GetHandle();
1395 if (!writefds
.IsPresent(h
))
1396 write
.RemoveAt(i
--);
1398 for (i
= 0; i
< except
.GetSize(); i
++) {
1399 int h
= except
[i
].GetHandle();
1402 if (!exceptfds
.IsPresent(h
))
1403 except
.RemoveAt(i
--);
1417 //////////////////////////////////////////////////////////////////////////////
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);
1434 ::Sleep(delay
.GetInterval());
1435 ::gethostbyname("www.microsoft.com");
1438 pHostByName().mutex
.Signal();
1439 pHostByAddr().mutex
.Signal();
1443 PString
PIPSocket::GetName() const
1448 socklen_t size
= sa
.GetSize();
1449 if (getpeername(os_handle
, sa
, &size
) == 0)
1450 return GetHostName(sa
.GetIP()) + psprintf(":%u", sa
.GetPort());
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
));
1461 return PString::Empty();
1465 PString
PIPSocket::GetHostName()
1468 if (gethostname(name
, sizeof(name
)-1) != 0)
1470 name
[sizeof(name
)-1] = '\0';
1475 PString
PIPSocket::GetHostName(const PString
& hostname
)
1477 // lookup the host address using inet_addr, assuming it is a "." address
1478 Address temp
= hostname
;
1480 return GetHostName(temp
);
1482 PString canonicalname
;
1483 if (pHostByName().GetHostName(hostname
, canonicalname
))
1484 return canonicalname
;
1490 PString
PIPSocket::GetHostName(const Address
& addr
)
1493 return addr
.AsString();
1496 if (pHostByAddr().GetHostName(addr
, 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())
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)))
1523 // Assuming it is a "." address and return if so
1524 if (addr
.FromString(hostname
))
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
;
1539 pHostByAddr().GetHostAliases(addr
, aliases
);
1541 pHostByName().GetHostAliases(hostname
, aliases
);
1547 PStringArray
PIPSocket::GetHostAliases(const Address
& addr
)
1549 PStringArray aliases
;
1551 pHostByAddr().GetHostAliases(addr
, aliases
);
1557 BOOL
PIPSocket::GetLocalAddress(Address
& addr
)
1560 return GetLocalAddress(addr
, dummy
);
1563 BOOL
PIPSocket::GetLocalAddress(Address
& addr
, WORD
& portNum
)
1568 socklen_t size
= sa
.GetSize();
1569 if (!ConvertOSError(::getsockname(os_handle
, sa
, &size
)))
1573 portNum
= sa
.GetPort();
1577 sockaddr_in address
;
1578 socklen_t size
= sizeof(address
);
1579 if (!ConvertOSError(::getsockname(os_handle
,(struct sockaddr
*)&address
,&size
)))
1582 addr
= address
.sin_addr
;
1583 portNum
= ntohs(address
.sin_port
);
1591 BOOL
PIPSocket::GetPeerAddress(Address
& addr
)
1594 return GetPeerAddress(addr
, portNum
);
1597 BOOL
PIPSocket::GetPeerAddress(Address
& addr
, WORD
& portNum
)
1602 socklen_t size
= sa
.GetSize();
1603 if (!ConvertOSError(::getpeername(os_handle
, sa
, &size
)))
1607 portNum
= sa
.GetPort();
1611 sockaddr_in address
;
1612 socklen_t size
= sizeof(address
);
1613 if (!ConvertOSError(::getpeername(os_handle
,(struct sockaddr
*)&address
,&size
)))
1616 addr
= address
.sin_addr
;
1617 portNum
= ntohs(address
.sin_port
);
1625 PString
PIPSocket::GetLocalHostName()
1629 if (GetLocalAddress(addr
))
1630 return GetHostName(addr
);
1632 return PString::Empty();
1636 PString
PIPSocket::GetPeerHostName()
1640 if (GetPeerAddress(addr
))
1641 return GetHostName(addr
);
1643 return PString::Empty();
1647 BOOL
PIPSocket::Connect(const PString
& host
)
1650 if (GetHostAddress(host
, ipnum
))
1651 return Connect(INADDR_ANY
, 0, ipnum
);
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
1680 // make sure we have a port
1681 PAssert(port
!= 0, "Cannot connect socket without setting port");
1685 Psockaddr
sa(addr
, port
);
1687 // attempt to create a socket with the right family
1688 if (!OpenSocket(sa
->sa_family
))
1691 if (localPort
!= 0 || iface
.IsValid()) {
1692 Psockaddr
bind_sa(iface
, localPort
);
1694 if (sa
->sa_family
!= bind_sa
->sa_family
) {
1699 if (!SetOption(SO_REUSEADDR
, 0)) {
1704 if (!ConvertOSError(::bind(os_handle
, bind_sa
, bind_sa
.GetSize()))) {
1710 // attempt to connect
1711 if (os_connect(sa
, sa
.GetSize()))
1716 // attempt to create a socket
1720 // attempt to connect
1722 if (localPort
!= 0 || iface
.IsValid()) {
1723 if (!SetOption(SO_REUSEADDR
, 0)) {
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
)))) {
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
)))
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
,
1762 // make sure we have a port
1767 Psockaddr
bind_sa(bindAddr
, port
);
1771 if (!GetOption(SO_TYPE
, socketType
, SOL_SOCKET
) || bind_sa
->sa_family
!= socketType
)
1777 // attempt to create a socket
1779 if (!OpenSocket(bind_sa
->sa_family
))
1787 // attempt to listen
1788 if (!SetOption(SO_REUSEADDR
, reuse
== CanReuseAddress
? 1 : 0)) {
1795 if (ConvertOSError(::bind(os_handle
, bind_sa
, bind_sa
.GetSize()))) {
1797 socklen_t size
= sa
.GetSize();
1798 if (!ConvertOSError(::getsockname(os_handle
, sa
, &size
)))
1801 port
= sa
.GetPort();
1807 // attempt to listen
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__
1817 bind_result
= ::bindzero(os_handle
, (struct sockaddr
*)&sin
, sizeof(sin
));
1819 bind_result
= ::bind(os_handle
, (struct sockaddr
*)&sin
, sizeof(sin
));
1820 if (ConvertOSError(bind_result
))
1822 if (ConvertOSError(::bind(os_handle
, (struct sockaddr
*)&sin
, sizeof(sin
))))
1825 socklen_t size
= sizeof(sin
);
1826 if (ConvertOSError(::getsockname(os_handle
, (struct sockaddr
*)&sin
, &size
))) {
1827 port
= ntohs(sin
.sin_port
);
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
;
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
;
1851 const PIPSocket::Address
& PIPSocket::Address::GetLoopback()
1858 const PIPSocket::Address
& PIPSocket::Address::GetLoopback6()
1865 const PIPSocket::Address
& PIPSocket::Address::GetBroadcast()
1871 PIPSocket::Address::Address()
1877 PIPSocket::Address::Address(const PString
& dotNotation
)
1879 operator=(dotNotation
);
1883 PIPSocket::Address::Address(PINDEX len
, const BYTE
* bytes
)
1889 memcpy(&v
.six
, bytes
, len
);
1894 memcpy(&v
.four
, bytes
, len
);
1903 PIPSocket::Address::Address(const in_addr
& addr
)
1911 PIPSocket::Address::Address(const in6_addr
& addr
)
1919 #ifdef __NUCLEUS_NET__
1920 PIPSocket::Address::Address(const struct id_struct
& 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]));
1937 PIPSocket::Address
& PIPSocket::Address::operator=(const in_addr
& addr
)
1945 PIPSocket::Address
& PIPSocket::Address::operator=(const in6_addr
& addr
)
1954 PObject::Comparison
PIPSocket::Address::Compare(const PObject
& obj
) const
1956 const PIPSocket::Address
& other
= (const PIPSocket::Address
&)obj
;
1958 if (version
< other
.version
)
1960 if (version
> other
.version
)
1965 int result
= memcmp(&v
.six
, &other
.v
.six
, sizeof(v
.six
));
1974 if ((DWORD
)*this < other
)
1976 if ((DWORD
)*this > other
)
1983 BOOL
PIPSocket::Address::operator==(in6_addr
& addr
) const
1985 PIPSocket::Address
a(addr
);
1986 return Compare(a
) == EqualTo
;
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
2001 return (DWORD
)*this == dw
;
2007 PIPSocket::Address
& PIPSocket::Address::operator=(const PString
& dotNotation
)
2011 struct addrinfo
*res
;
2012 struct addrinfo hints
= {AI_PASSIVE
, 0, SOCK_STREAM
, 0, 0, NULL
, NULL
, NULL
};
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
) {
2023 struct sockaddr_in6
* addr_in6
= (struct sockaddr_in6
*)res
->ai_addr
;
2024 v
.six
= addr_in6
->sin6_addr
;
2028 struct sockaddr_in
* addr_in
= (struct sockaddr_in
*)res
->ai_addr
;
2029 v
.four
= addr_in
->sin_addr
;
2036 if (::strspn(dotNotation
, "0123456789.") < ::strlen(dotNotation
))
2040 v
.four
.s_addr
= inet_addr((const char *)dotNotation
);
2041 if (v
.four
.s_addr
== (DWORD
)INADDR_NONE
)
2051 PString
PIPSocket::Address::AsString() const
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();
2066 return inet_ntoa(v
.four
);
2070 BOOL
PIPSocket::Address::FromString(const PString
& dotNotation
)
2072 (*this) = dotNotation
;
2078 PIPSocket::Address::operator PString() const
2084 PIPSocket::Address::operator in_addr() const
2087 return inaddr_empty
;
2094 PIPSocket::Address::operator in6_addr() const
2097 return inaddr6_empty
;
2104 BYTE
PIPSocket::Address::operator[](PINDEX idx
) const
2109 PAssert(idx
<= 15, PInvalidParameter
);
2110 return v
.six
.s6_addr
[idx
];
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
);
2139 PINDEX
PIPSocket::Address::GetSize() const
2155 BOOL
PIPSocket::Address::IsValid() const
2160 return memcmp(&v
.six
, &inaddr6_empty
, sizeof(v
.six
)) != 0;
2164 return (DWORD
)*this != INADDR_ANY
;
2170 BOOL
PIPSocket::Address::IsLoopback() const
2174 return *this == loopback6
;
2176 return *this == loopback4
;
2180 BOOL
PIPSocket::Address::IsBroadcast() const
2183 if (version
== 6) // In IPv6, no broadcast exist. Only multicast
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()),
2203 void PIPSocket::InterfaceEntry::PrintOn(ostream
& strm
) const
2207 strm
<< " <" << macAddr
<< '>';
2209 strm
<< " (" << name
<< ')';
2213 #ifdef __NUCLEUS_NET__
2214 BOOL
PIPSocket::GetInterfaceTable(InterfaceTable
& table
)
2217 list
<IPInterface
>::iterator i
;
2218 for(i
=Route4Configuration
->Getm_IPInterfaceList().begin();
2219 i
!=Route4Configuration
->Getm_IPInterfaceList().end();
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;
2233 //////////////////////////////////////////////////////////////////////////////
2236 PTCPSocket::PTCPSocket(WORD newPort
)
2242 PTCPSocket::PTCPSocket(const PString
& service
)
2248 PTCPSocket::PTCPSocket(const PString
& address
, WORD newPort
)
2255 PTCPSocket::PTCPSocket(const PString
& address
, const PString
& service
)
2262 PTCPSocket::PTCPSocket(PSocket
& socket
)
2268 PTCPSocket::PTCPSocket(PTCPSocket
& 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
2300 BOOL
PTCPSocket::Write(const void * buf
, PINDEX len
)
2303 PINDEX writeCount
= 0;
2306 if (!os_sendto(((char *)buf
)+writeCount
, len
, 0, NULL
, 0))
2308 writeCount
+= lastWriteCount
;
2309 len
-= lastWriteCount
;
2312 lastWriteCount
= writeCount
;
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
,
2328 if (PIPSocket::Listen(bindAddr
, queueSize
, newPort
, reuse
) &&
2329 ConvertOSError(::listen(os_handle
, queueSize
)))
2337 BOOL
PTCPSocket::Accept(PSocket
& socket
)
2339 PAssert(socket
.IsDescendant(PIPSocket::Class()), "Invalid listener socket");
2344 PINDEX size
= sa
.GetSize();
2345 if (!os_accept(socket
, sa
, &size
))
2350 sockaddr_in address
;
2351 address
.sin_family
= AF_INET
;
2352 PINDEX size
= sizeof(address
);
2353 if (!os_accept(socket
, (struct sockaddr
*)&address
, &size
))
2358 port
= ((PIPSocket
&)socket
).GetPort();
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
);
2372 int count
= ::send(os_handle
, (const char *)buf
, len
, MSG_OOB
);
2376 return ConvertOSError(count
, LastWriteError
);
2379 lastWriteCount
= count
;
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
)
2406 PINDEX size
= sa
.GetSize();
2407 if (os_recvfrom(buf
, len
, 0, sa
, &size
)) {
2409 port
= sa
.GetPort();
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
);
2423 return lastReadCount
> 0;
2427 BOOL
PIPDatagramSocket::WriteTo(const void * buf
, PINDEX len
,
2428 const Address
& addr
, WORD port
)
2434 Psockaddr
sa(addr
, port
);
2435 return os_sendto(buf
, len
, 0, sa
, sa
.GetSize()) && lastWriteCount
>= len
;
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
;
2450 //////////////////////////////////////////////////////////////////////////////
2453 PUDPSocket::PUDPSocket(WORD newPort
)
2461 PUDPSocket::PUDPSocket(const PString
& service
)
2469 PUDPSocket::PUDPSocket(const PString
& address
, WORD newPort
)
2477 PUDPSocket::PUDPSocket(const PString
& address
, const PString
& service
)
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
2501 BOOL
PUDPSocket::Connect(const PString
& address
)
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
)
2517 return PIPDatagramSocket::Write(buf
, len
);
2519 return PIPDatagramSocket::WriteTo(buf
, len
, sendAddress
, sendPort
);
2523 void PUDPSocket::SetSendAddress(const Address
& newAddress
, WORD newPort
)
2525 sendAddress
= newAddress
;
2530 void PUDPSocket::GetSendAddress(Address
& address
, WORD
& port
)
2532 address
= sendAddress
;
2537 void PUDPSocket::GetLastReceiveAddress(Address
& address
, WORD
& port
)
2539 address
= lastReceiveAddress
;
2540 port
= lastReceivePort
;
2544 // End Of File ///////////////////////////////////////////////////////////////