Fixed DevStudio 2003 build with memory check code.
[pwlib.git] / src / ptlib / unix / socket.cxx
blobd12b74fa07a4f52f65c32e0e5462d0eee61dccdc
1 /*
2 * socket.cxx
4 * Berkley sockets classes implementation
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.120 2007/06/27 03:15:21 rjongbloed
31 * Added ability to select filtering of down network interfaces.
33 * Revision 1.119 2007/02/17 18:57:58 hfriederich
34 * Use similar code in IsLocalHost() as in GetInterfaceTable() to fix
35 * incorrect IsLocalHost() on Mac OS X. Untested on other platforms!
37 * Revision 1.118 2006/06/21 03:28:44 csoutheren
38 * Various cleanups thanks for Frederic Heem
40 * Revision 1.117 2006/02/21 13:57:31 csoutheren
41 * Second attempt at fixing problem with interfaces having multiple addresses
43 * Revision 1.116 2006/02/18 15:57:45 dsandras
44 * Applied patch from Richard van der Hoff and Stephane Epardaud <stef lunatech
45 * com> to fix infinite loop with IPv6 interfaces. Thanks!
47 * Revision 1.115 2005/11/30 12:47:42 csoutheren
48 * Removed tabs, reformatted some code, and changed tags for Doxygen
50 * Revision 1.114 2005/11/23 11:47:03 shorne
51 * Changed EnableQoS to EnableGQoS
53 * Revision 1.113 2005/07/15 12:45:13 rogerhardiman
54 * Fix bug 1237508 (M Zygmuntowicz). Make IPV6 code use #if instead of #ifdef.
56 * Revision 1.112 2005/07/13 11:48:55 csoutheren
57 * Backported QOS changes from isvo branch
59 * Revision 1.111 2005/02/07 12:12:31 csoutheren
60 * Expanded interface list routines to include IPV6 addresses
61 * Added IPV6 to GetLocalAddress
63 * Revision 1.110 2004/08/24 07:08:11 csoutheren
64 * Added use of recvmsg to determine which interface UDP packets arrive on
66 * Revision 1.109 2004/07/11 07:56:36 csoutheren
67 * Applied jumbo VxWorks patch, thanks to Eize Slange
69 * Revision 1.108 2004/07/08 00:57:29 csoutheren
70 * Added check for EINTR on connect
71 * Thanks to Alex Vishnev
73 * Revision 1.107 2004/07/03 23:50:42 csoutheren
74 * Removed warnings under Solaris
76 * Revision 1.106 2004/05/06 11:28:30 rjongbloed
77 * Changed P_fd_set to use malloc/free isntead of new/delete due to pedantry about [].
79 * Revision 1.105 2004/05/05 06:52:37 ykiryanov
80 * Made BeOS changes
82 * Revision 1.104 2004/04/27 04:37:51 rjongbloed
83 * Fixed ability to break of a PSocket::Select call under linux when a socket
84 * is closed by another thread.
86 * Revision 1.103 2004/04/24 06:28:12 rjongbloed
87 * Fixed GCC 3.4.0 warnings about PAssertNULL and improved recoverability on
88 * NULL pointer usage in various bits of code.
90 * Revision 1.102 2004/04/18 07:46:32 rjongbloed
91 * Fixed other unix builds after Yuri's BeOS changes.
93 * Revision 1.101 2004/04/18 00:21:35 ykiryanov
94 * Cleaned up BeOS related code. Less ifdefs, more functionality
96 * Revision 1.100 2003/10/27 04:06:14 csoutheren
97 * Added code to allow compilation of new QoS code on Unix
99 * Revision 1.99 2003/01/24 10:21:06 robertj
100 * Fixed issues in RTEMS support, thanks Vladimir Nesic
102 * Revision 1.98 2002/11/22 10:14:07 robertj
103 * QNX port, thanks Xiaodan Tang
105 * Revision 1.97 2002/11/02 00:32:21 robertj
106 * Further fixes to VxWorks (Tornado) port, thanks Andreas Sikkema.
108 * Revision 1.96 2002/10/22 10:25:07 rogerh
109 * Fix process_rtentry() following Thomas's patch.
111 * Revision 1.95 2002/10/22 07:42:52 robertj
112 * Added extra debugging for file handle and thread leak detection.
114 * Revision 1.94 2002/10/22 06:53:38 craigs
115 * Fixed signed/unsigned problem in GetRoutTable thanks to Thomas Jalsovsky
117 * Revision 1.93 2002/10/19 06:12:20 robertj
118 * Moved P_fd_set::Zero() from platform independent to platform dependent
119 * code as Win32 implementation is completely different from Unix.
121 * Revision 1.92 2002/10/17 13:44:27 robertj
122 * Port to RTEMS, thanks Vladimir Nesic.
124 * Revision 1.91 2002/10/17 12:57:24 robertj
125 * Added ability to increase maximum file handles on a process.
127 * Revision 1.90 2002/10/10 04:43:44 robertj
128 * VxWorks port, thanks Martijn Roest
130 * Revision 1.89 2002/10/08 14:31:43 robertj
131 * Changed for IPv6 support, thanks Sébastien Josset.
133 * Revision 1.88 2002/06/05 12:29:16 craigs
134 * Changes for gcc 3.1
136 * Revision 1.87 2002/04/18 06:16:06 robertj
137 * Fixed Net BSD problem with RTF_CLONED flag, thanks Motoyuki OHMORI
138 * Fixed operator precedence problem with bit mask tests in RTF_CLONE code.
140 * Revision 1.86 2002/04/12 07:57:41 robertj
141 * Fixed bug introduced into Accept() by previous change.
143 * Revision 1.85 2002/04/12 01:42:41 robertj
144 * Changed return value on os_connect() and os_accept() to make sure
145 * get the correct error codes propagated up under unix.
147 * Revision 1.84 2002/02/13 02:19:47 robertj
148 * Fixed mistake in previous patch, is if not ifdef!
150 * Revision 1.83 2002/02/13 00:50:32 robertj
151 * Fixed use of symbol in older versionsof Solaris, thanks Markus Storm
153 * Revision 1.82 2002/01/31 22:52:18 robertj
154 * Added fix for buffer too small in Solaris GetRouteTable(), thanks Markus Storm.
156 * Revision 1.81 2001/12/17 23:33:50 robertj
157 * Solaris 8 porting changes, thanks James Dugal
159 * Revision 1.80 2001/12/10 07:07:27 rogerh
160 * Take out some #includes which were already in pachdep.h. Fixes openBSD 2.9
162 * Revision 1.79 2001/11/22 12:29:57 rogerh
163 * Take out the cloned flag on OpenBSD so it compiles
165 * Revision 1.78 2001/11/14 10:37:32 rogerh
166 * Define _SIZEOF_ADDR_IFREQ as OpenBSD does not have it
168 * Revision 1.77 2001/10/28 23:00:10 robertj
169 * Fixed Solaris and IRIX compatibility issue, thanks Andre Schulze
171 * Revision 1.76 2001/10/11 02:20:54 robertj
172 * Added IRIX support (no audio/video), thanks Andre Schulze.
174 * Revision 1.75 2001/10/03 19:31:56 rogerh
175 * Add MAC OS X support to GetInterfaceTable
177 * Revision 1.74 2001/10/03 10:18:15 rogerh
178 * Make Mac OS X (Darwin) use the new GetRouteTable() function.
180 * Revision 1.73 2001/09/24 15:37:35 rogerh
181 * Add GetRouteTable() for BSD Unix. Based on FreeBSD's own networking code,
182 * and from an implementation by Martin Nilsson <martin@gneto.com>
184 * Revision 1.72 2001/09/19 00:41:20 robertj
185 * Fixed GetInterfaceTable so does not add duplicate interfaces into list.
186 * Changed the loop condition to allow for BSD variable length records.
188 * Revision 1.71 2001/09/18 05:56:03 robertj
189 * Fixed numerous problems with thread suspend/resume and signals handling.
191 * Revision 1.70 2001/09/10 03:03:36 robertj
192 * Major change to fix problem with error codes being corrupted in a
193 * PChannel when have simultaneous reads and writes in threads.
195 * Revision 1.69 2001/08/16 11:58:22 rogerh
196 * Add more Mac OS X changes from John Woods <jfw@jfwhome.funhouse.com>
198 * Revision 1.68 2001/08/12 07:12:40 rogerh
199 * More Mac OS Carbon changes from John Woods <jfw@jfwhome.funhouse.com>
201 * Revision 1.67 2001/08/12 06:34:33 rogerh
202 * Add Mac OS Carbon changes from John Woods <jfw@jfwhome.funhouse.com>
204 * Revision 1.66 2001/08/07 02:27:22 robertj
205 * Fixed some incorrect error values returned in Read() and Write() functions.
207 * Revision 1.65 2001/07/03 04:41:25 yurik
208 * Corrections to Jac's submission from 6/28
210 * Revision 1.64 2001/06/30 06:59:07 yurik
211 * Jac Goudsmit from Be submit these changes 6/28. Implemented by Yuri Kiryanov
213 * Revision 1.63 2001/06/19 12:09:13 rogerh
214 * Mac OS X change
216 * Revision 1.62 2001/04/16 22:46:22 craigs
217 * Fixed problem with os_connect not correctly reporting errors
219 * Revision 1.61 2001/03/26 03:31:53 robertj
220 * Fixed Solaris compile error.
222 * Revision 1.60 2001/03/20 06:44:25 robertj
223 * Lots of changes to fix the problems with terminating threads that are I/O
224 * blocked, especially when doing orderly shutdown of service via SIGTERM.
226 * Revision 1.59 2001/03/07 23:37:59 robertj
227 * Fixed slow down in UDP packet send, thanks Dmitriy Reka
229 * Revision 1.58 2001/03/07 06:56:36 yurik
230 * Made adjustment for BONE platforms as requested by Jac Goudsmit
232 * Revision 1.57 2001/03/06 00:16:59 robertj
233 * Fixed BSD compatibility problem.
235 * Revision 1.56 2001/03/05 04:28:56 robertj
236 * Added net mask to interface info returned by GetInterfaceTable()
238 * Revision 1.55 2001/02/02 23:31:30 robertj
239 * Fixed enumeration of interfaces, thanks Bertrand Croq.
241 * Revision 1.54 2001/01/17 03:48:25 rogerh
242 * Fix GetInterfaceTable so it actually works through all interfaces rather
243 * than falling over after the first entry.
245 * Revision 1.53 2001/01/16 12:56:01 rogerh
246 * On BeOS sa_data is 'unsigned char *'. Linux and BSD defines sa_data as 'char *'
247 * Add typecast, submitted by Jac Goudsmit <jac_goudsmit@yahoo.com>
249 * Revision 1.52 2000/06/21 01:01:22 robertj
250 * AIX port, thanks Wolfgang Platzer (wolfgang.platzer@infonova.at).
252 * Revision 1.51 2000/04/19 00:13:53 robertj
253 * BeOS port changes.
255 * Revision 1.50 2000/04/07 05:43:48 rogerh
256 * Fix a compilation error in a non-pthreaded function. Found by Kevin Packard
258 * Revision 1.49 2000/03/17 03:45:40 craigs
259 * Fixed problem with connect call hanging
261 * Revision 1.48 2000/02/17 23:47:40 robertj
262 * Fixed error in check for SIOCGHWADDR define, thanks Markus Storm.
264 * Revision 1.47 2000/01/20 08:20:57 robertj
265 * FreeBSD v3 compatibility changes, thanks Roger Hardiman & Motonori Shindo
267 * Revision 1.46 1999/11/18 13:45:21 craigs
268 * Removed obsolete declaration of iostream semaphore
270 * Revision 1.45 1999/10/30 13:43:01 craigs
271 * Added correct method of aborting socket operations asynchronously
273 * Revision 1.44 1999/09/27 01:04:42 robertj
274 * BeOS support changes.
276 * Revision 1.43 1999/09/12 07:06:23 craigs
277 * Added support for getting Solaris interface info
279 * Revision 1.42 1999/09/10 02:31:19 craigs
280 * Added interface table routines
282 * Revision 1.41 1999/09/03 02:26:25 robertj
283 * Changes to aid in breaking I/O locks on thread termination. Still needs more work esp in BSD!
285 * Revision 1.40 1999/05/01 03:52:20 robertj
286 * Fixed various egcs warnings.
288 * Revision 1.39 1999/03/02 05:41:59 robertj
289 * More BeOS changes
291 * Revision 1.38 1999/02/26 04:10:39 robertj
292 * More BeOS port changes
294 * Revision 1.37 1999/02/22 13:26:54 robertj
295 * BeOS port changes.
297 * Revision 1.36 1998/11/30 21:51:58 robertj
298 * New directory structure.
300 * Revision 1.35 1998/11/24 09:39:22 robertj
301 * FreeBSD port.
303 * Revision 1.34 1998/11/22 08:11:37 craigs
304 * *** empty log message ***
306 * Revision 1.33 1998/11/14 10:37:38 robertj
307 * Changed semantics of os_sendto to return TRUE if ANY bytes are sent.
309 * Revision 1.32 1998/10/16 01:16:55 craigs
310 * Added Yield to help with cooperative multithreading.
312 * Revision 1.31 1998/10/11 02:23:16 craigs
313 * Fixed problem with socket writes not correctly detecting EOF
315 * Revision 1.30 1998/09/24 08:21:11 robertj
316 * Fixed warning on GNU 6 library.
318 * Revision 1.29 1998/09/24 07:55:51 robertj
319 * Fixed warning on solaris build.
321 * Revision 1.28 1998/09/24 04:13:49 robertj
322 * Added open software license.
324 * Revision 1.27 1998/09/18 05:46:00 robertj
325 * Fixed incorrectly returning success on a connect() error other than a timeout.
327 * Revision 1.26 1998/09/08 11:31:51 robertj
328 * Fixed ippp bug on very full packets.
330 * Revision 1.25 1998/09/08 09:54:31 robertj
331 * Fixed ppp and ippp compatibility.
333 * Revision 1.24 1998/09/08 05:15:14 robertj
334 * Fixed problem in Windows requiring snmpapi.dll for PEthSocket class.
336 * Revision 1.23 1998/08/27 01:13:20 robertj
337 * Changes to resolve signedness in GNU C library v6
338 * Remove Linux EthSocket stuff from Sun build, still needs implementing.
340 * Revision 1.22 1998/08/21 05:30:59 robertj
341 * Ethernet socket implementation.
345 #pragma implementation "sockets.h"
346 #pragma implementation "socket.h"
347 #pragma implementation "ipsock.h"
348 #pragma implementation "udpsock.h"
349 #pragma implementation "tcpsock.h"
350 #pragma implementation "ipdsock.h"
351 #pragma implementation "ethsock.h"
352 #pragma implementation "qos.h"
355 #include <ptlib.h>
356 #include <ptlib/sockets.h>
358 #include <map>
359 #include <ptlib/pstring.h>
361 #if defined(SIOCGENADDR)
362 #define SIO_Get_MAC_Address SIOCGENADDR
363 #define ifr_macaddr ifr_ifru.ifru_enaddr
364 #elif defined(SIOCGIFHWADDR)
365 #define SIO_Get_MAC_Address SIOCGIFHWADDR
366 #define ifr_macaddr ifr_hwaddr.sa_data
367 #endif
369 #if defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_SOLARIS) || defined(P_MACOSX) || defined(P_MACOS) || defined(P_IRIX) || defined(P_VXWORKS) || defined(P_RTEMS) || defined(P_QNX)
370 #define ifr_netmask ifr_addr
372 #include <net/if_dl.h>
373 #include <net/if_types.h>
374 #include <net/route.h>
376 #include <netinet/in.h>
377 #if !defined(P_QNX)
378 #include <netinet/if_ether.h>
379 #endif
381 #define ROUNDUP(a) \
382 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
384 #endif
386 #if defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_MACOS) || defined(P_QNX)
387 #include <sys/sysctl.h>
388 #endif
390 #ifdef P_RTEMS
391 #include <bsp.h>
392 #endif
394 #ifdef __BEOS__
395 #include <posix/sys/ioctl.h> // for FIONBIO
396 #include <be/bone/net/if.h> // for ifconf
397 #include <be/bone/sys/sockio.h> // for SIOCGI*
398 #endif
400 #if defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_VXWORKS) || defined(P_RTEMS) || defined(P_QNX)
401 // Define _SIZEOF_IFREQ for platforms (eg OpenBSD) which do not have it.
402 #ifndef _SIZEOF_ADDR_IFREQ
403 #define _SIZEOF_ADDR_IFREQ(ifr) \
404 ((ifr).ifr_addr.sa_len > sizeof(struct sockaddr) ? \
405 (sizeof(struct ifreq) - sizeof(struct sockaddr) + \
406 (ifr).ifr_addr.sa_len) : sizeof(struct ifreq))
407 #endif
408 #endif
410 int PX_NewHandle(const char *, int);
412 #ifdef P_VXWORKS
413 // VxWorks variant of inet_ntoa() allocates INET_ADDR_LEN bytes via malloc
414 // BUT DOES NOT FREE IT !!! Use inet_ntoa_b() instead.
415 #define INET_ADDR_LEN 18
416 extern "C" void inet_ntoa_b(struct in_addr inetAddress, char *pString);
417 #endif // P_VXWORKS
419 //////////////////////////////////////////////////////////////////////////////
420 // P_fd_set
422 void P_fd_set::Construct()
424 max_fd = PProcess::Current().GetMaxHandles();
425 set = (fd_set *)malloc((max_fd+7)>>3);
429 void P_fd_set::Zero()
431 if (PAssertNULL(set) != NULL)
432 memset(set, 0, (max_fd+7)>>3);
436 //////////////////////////////////////////////////////////////////////////////
438 PSocket::~PSocket()
440 os_close();
443 int PSocket::os_close()
445 if (os_handle < 0)
446 return -1;
448 // send a shutdown to the other end
449 ::shutdown(os_handle, 2);
451 return PXClose();
455 static int SetNonBlocking(int fd)
457 if (fd < 0)
458 return -1;
460 // Set non-blocking so we can use select calls to break I/O block on close
461 int cmd = 1;
462 #if defined(P_VXWORKS)
463 if (::ioctl(fd, FIONBIO, &cmd) == 0)
464 #else
465 if (::ioctl(fd, FIONBIO, &cmd) == 0 && ::fcntl(fd, F_SETFD, 1) == 0)
466 #endif
467 return fd;
469 ::close(fd);
470 return -1;
474 int PSocket::os_socket(int af, int type, int protocol)
476 // attempt to create a socket
477 return SetNonBlocking(PX_NewHandle(GetClass(), ::socket(af, type, protocol)));
481 BOOL PSocket::os_connect(struct sockaddr * addr, PINDEX size)
483 int val;
484 do {
485 val = ::connect(os_handle, addr, size);
486 } while (val != 0 && errno == EINTR);
487 if (val == 0 || errno != EINPROGRESS)
488 return ConvertOSError(val);
490 if (!PXSetIOBlock(PXConnectBlock, readTimeout))
491 return FALSE;
493 // A successful select() call does not necessarily mean the socket connected OK.
494 int optval = -1;
495 socklen_t optlen = sizeof(optval);
496 getsockopt(os_handle, SOL_SOCKET, SO_ERROR, (char *)&optval, &optlen);
497 if (optval != 0) {
498 errno = optval;
499 return ConvertOSError(-1);
502 return TRUE;
506 BOOL PSocket::os_accept(PSocket & listener, struct sockaddr * addr, PINDEX * size)
508 if (!listener.PXSetIOBlock(PXAcceptBlock, listener.GetReadTimeout()))
509 return SetErrorValues(listener.GetErrorCode(), listener.GetErrorNumber());
511 #if defined(E_PROTO)
512 for (;;) {
513 int new_fd = ::accept(listener.GetHandle(), addr, (socklen_t *)size);
514 if (new_fd >= 0)
515 return ConvertOSError(os_handle = SetNonBlocking(new_fd));
517 if (errno != EPROTO)
518 return ConvertOSError(-1);
520 PTRACE(3, "PWLib\tAccept on " << sock << " failed with EPROTO - retrying");
522 #else
523 return ConvertOSError(os_handle = SetNonBlocking(::accept(listener.GetHandle(), addr, (socklen_t *)size)));
524 #endif
528 #if !defined(P_PTHREADS) && !defined(P_MAC_MPTHREADS) && !defined(__BEOS__)
530 PChannel::Errors PSocket::Select(SelectList & read,
531 SelectList & write,
532 SelectList & except,
533 const PTimeInterval & timeout)
535 PINDEX i, j;
536 PINDEX nextfd = 0;
537 int maxfds = 0;
538 Errors lastError = NoError;
539 PThread * unblockThread = PThread::Current();
541 P_fd_set fds[3];
542 SelectList * list[3] = { &read, &write, &except };
544 for (i = 0; i < 3; i++) {
545 for (j = 0; j < list[i]->GetSize(); j++) {
546 PSocket & socket = (*list[i])[j];
547 if (!socket.IsOpen())
548 lastError = NotOpen;
549 else {
550 int h = socket.GetHandle();
551 fds[i] += h;
552 if (h > maxfds)
553 maxfds = h;
555 socket.px_selectMutex.Wait();
556 socket.px_selectThread = unblockThread;
560 if (lastError == NoError) {
561 P_timeval tval = timeout;
562 int result = ::select(maxfds+1,
563 (fd_set *)fds[0],
564 (fd_set *)fds[1],
565 (fd_set *)fds[2],
566 tval);
568 int osError;
569 (void)ConvertOSError(result, lastError, osError);
572 for (i = 0; i < 3; i++) {
573 for (j = 0; j < list[i]->GetSize(); j++) {
574 PSocket & socket = (*list[i])[j];
575 socket.px_selectThread = NULL;
576 socket.px_selectMutex.Signal();
577 if (lastError == NoError) {
578 int h = socket.GetHandle();
579 if (h < 0)
580 lastError = Interrupted;
581 else if (!fds[i].IsPresent(h))
582 list[i]->RemoveAt(j--);
587 return lastError;
590 #else
592 PChannel::Errors PSocket::Select(SelectList & read,
593 SelectList & write,
594 SelectList & except,
595 const PTimeInterval & timeout)
597 PINDEX i, j;
598 int maxfds = 0;
599 Errors lastError = NoError;
600 PThread * unblockThread = PThread::Current();
601 int unblockPipe = unblockThread->unblockPipe[0];
603 P_fd_set fds[3];
604 SelectList * list[3] = { &read, &write, &except };
606 for (i = 0; i < 3; i++) {
607 for (j = 0; j < list[i]->GetSize(); j++) {
608 PSocket & socket = (*list[i])[j];
609 if (!socket.IsOpen())
610 lastError = NotOpen;
611 else {
612 int h = socket.GetHandle();
613 fds[i] += h;
614 if (h > maxfds)
615 maxfds = h;
617 socket.px_selectMutex.Wait();
618 socket.px_selectThread = unblockThread;
622 int result = -1;
623 if (lastError == NoError) {
624 fds[0] += unblockPipe;
625 if (unblockPipe > maxfds)
626 maxfds = unblockPipe;
628 P_timeval tval = timeout;
629 do {
630 result = ::select(maxfds+1, (fd_set *)fds[0], (fd_set *)fds[1], (fd_set *)fds[2], tval);
631 } while (result < 0 && errno == EINTR);
633 int osError;
634 if (ConvertOSError(result, lastError, osError)) {
635 if (fds[0].IsPresent(unblockPipe)) {
636 PTRACE(6, "PWLib\tSelect unblocked fd=" << unblockPipe);
637 BYTE ch;
638 ::read(unblockPipe, &ch, 1);
639 lastError = Interrupted;
644 for (i = 0; i < 3; i++) {
645 for (j = 0; j < list[i]->GetSize(); j++) {
646 PSocket & socket = (*list[i])[j];
647 socket.px_selectThread = NULL;
648 socket.px_selectMutex.Signal();
649 if (lastError == NoError) {
650 int h = socket.GetHandle();
651 if (h < 0)
652 lastError = Interrupted;
653 else if (!fds[i].IsPresent(h))
654 list[i]->RemoveAt(j--);
659 return lastError;
662 #endif
665 PIPSocket::Address::Address(DWORD dw)
667 operator=(dw);
671 PIPSocket::Address & PIPSocket::Address::operator=(DWORD dw)
673 if (dw == 0) {
674 version = 0;
675 memset(&v, 0, sizeof(v));
677 else {
678 version = 4;
679 v.four.s_addr = dw;
682 return *this;
686 PIPSocket::Address::operator DWORD() const
688 return version != 4 ? 0 : (DWORD)v.four.s_addr;
691 BYTE PIPSocket::Address::Byte1() const
693 return *(((BYTE *)&v.four.s_addr)+0);
696 BYTE PIPSocket::Address::Byte2() const
698 return *(((BYTE *)&v.four.s_addr)+1);
701 BYTE PIPSocket::Address::Byte3() const
703 return *(((BYTE *)&v.four.s_addr)+2);
706 BYTE PIPSocket::Address::Byte4() const
708 return *(((BYTE *)&v.four.s_addr)+3);
711 PIPSocket::Address::Address(BYTE b1, BYTE b2, BYTE b3, BYTE b4)
713 version = 4;
714 BYTE * p = (BYTE *)&v.four.s_addr;
715 p[0] = b1;
716 p[1] = b2;
717 p[2] = b3;
718 p[3] = b4;
721 BOOL PIPSocket::IsLocalHost(const PString & hostname)
723 if (hostname.IsEmpty())
724 return TRUE;
726 if (hostname *= "localhost")
727 return TRUE;
729 // lookup the host address using inet_addr, assuming it is a "." address
730 Address addr = hostname;
731 if (addr.IsLoopback()) // Is 127.0.0.1
732 return TRUE;
733 if (!addr.IsValid())
734 return FALSE;
736 if (!GetHostAddress(hostname, addr))
737 return FALSE;
739 #if P_HAS_IPV6
741 FILE * file;
742 int dummy;
743 int addr6[16];
744 char ifaceName[255];
745 BOOL found = FALSE;
746 if ((file = fopen("/proc/net/if_inet6", "r")) != NULL) {
747 while (!found && (fscanf(file, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x %x %x %x %x %255s\n",
748 &addr6[0], &addr6[1], &addr6[2], &addr6[3],
749 &addr6[4], &addr6[5], &addr6[6], &addr6[7],
750 &addr6[8], &addr6[9], &addr6[10], &addr6[11],
751 &addr6[12], &addr6[13], &addr6[14], &addr6[15],
752 &dummy, &dummy, &dummy, &dummy, ifaceName) != EOF)) {
753 Address ip6addr(
754 psprintf("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
755 addr6[0], addr6[1], addr6[2], addr6[3],
756 addr6[4], addr6[5], addr6[6], addr6[7],
757 addr6[8], addr6[9], addr6[10], addr6[11],
758 addr6[12], addr6[13], addr6[14], addr6[15]
761 found = (ip6addr *= addr);
763 fclose(file);
765 if (found)
766 return TRUE;
768 #endif
770 // check IPV4 addresses
771 PUDPSocket sock;
773 PBYTEArray buffer;
774 struct ifconf ifConf;
776 #ifdef SIOCGIFNUM
777 int ifNum;
778 PAssert(::ioctl(sock.GetHandle(), SIOCGIFNUM, &ifNum) >= 0, "could not do ioctl for ifNum");
779 ifConf.ifc_len = ifNum * sizeof(ifreq);
780 #else
781 ifConf.ifc_len = 100 * sizeof(ifreq); // That's a LOT of interfaces!
782 #endif
784 ifConf.ifc_req = (struct ifreq *)buffer.GetPointer(ifConf.ifc_len);
786 if (ioctl(sock.GetHandle(), SIOCGIFCONF, &ifConf) >= 0) {
787 void * ifEndList = (char *)ifConf.ifc_req + ifConf.ifc_len;
788 ifreq * ifName = ifConf.ifc_req;
790 while (ifName < ifEndList) {
791 struct ifreq ifReq;
792 memcpy(&ifReq, ifName, sizeof(ifreq));
794 if (ioctl(sock.GetHandle(), SIOCGIFFLAGS, &ifReq) >= 0) {
795 int flags = ifReq.ifr_flags;
796 if ((flags & IFF_UP) && ioctl(sock.GetHandle(), SIOCGIFADDR, &ifReq) >= 0) {
797 sockaddr_in * sin = (sockaddr_in *)&ifReq.ifr_addr;
798 PIPSocket::Address address = sin->sin_addr;
799 if (addr *= address)
800 return TRUE;
804 #if defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_VXWORKS) || defined(P_RTEMS) || defined(P_QNX)
805 // move the ifName pointer along to the next ifreq entry
806 ifName = (struct ifreq *)((char *)ifName + _SIZEOF_ADDR_IFREQ(*ifName));
807 #else
808 ifName++;
809 #endif
813 return FALSE;
817 ////////////////////////////////////////////////////////////////
819 // PTCPSocket
821 BOOL PTCPSocket::Read(void * buf, PINDEX maxLen)
824 lastReadCount = 0;
826 // wait until select indicates there is data to read, or until
827 // a timeout occurs
828 if (!PXSetIOBlock(PXReadBlock, readTimeout))
829 return FALSE;
831 // attempt to read out of band data
832 char buffer[32];
833 int ooblen;
834 while ((ooblen = ::recv(os_handle, buffer, sizeof(buffer), MSG_OOB)) > 0)
835 OnOutOfBand(buffer, ooblen);
837 // attempt to read non-out of band data
838 int r = ::recv(os_handle, (char *)buf, maxLen, 0);
839 if (!ConvertOSError(r, LastReadError))
840 return FALSE;
842 lastReadCount = r;
843 return lastReadCount > 0;
847 #if P_HAS_RECVMSG
849 int PSocket::os_recvfrom(
850 void * buf, // Data to be written as URGENT TCP data.
851 PINDEX len, // Number of bytes pointed to by <CODE>buf</CODE>.
852 int flags,
853 sockaddr * addr, // Address from which the datagram was received.
854 PINDEX * addrlen)
856 lastReadCount = 0;
858 if (!PXSetIOBlock(PXReadBlock, readTimeout))
859 return FALSE;
861 // if we don't care what interface the packet arrives on, then don't bother getting the information
862 if (!catchReceiveToAddr) {
863 int r = ::recvfrom(os_handle, (char *)buf, len, flags, (sockaddr *)addr, (socklen_t *)addrlen);
864 if (!ConvertOSError(r, LastReadError))
865 return FALSE;
867 lastReadCount = r;
868 return lastReadCount > 0;
871 msghdr readData;
872 memset(&readData, 0, sizeof(readData));
874 readData.msg_name = addr;
875 readData.msg_namelen = *addrlen;
877 iovec readVector;
878 readVector.iov_base = buf;
879 readVector.iov_len = len;
880 readData.msg_iov = &readVector;
881 readData.msg_iovlen = 1;
883 char auxdata[50];
884 readData.msg_control = auxdata;
885 readData.msg_controllen = sizeof(auxdata);
887 // read a packet
888 int r = ::recvmsg(os_handle, &readData, 0);
889 if (!ConvertOSError(r, LastReadError))
890 return FALSE;
892 lastReadCount = r;
894 if (r >= 0) {
895 struct cmsghdr * cmsg;
896 for (cmsg = CMSG_FIRSTHDR(&readData); cmsg != NULL; cmsg = CMSG_NXTHDR(&readData,cmsg)) {
897 if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
898 in_pktinfo * info = (in_pktinfo *)CMSG_DATA(cmsg);
899 SetLastReceiveAddr(&info->ipi_spec_dst, sizeof(in_addr));
900 break;
905 return lastReadCount > 0;
908 #else
910 BOOL PSocket::os_recvfrom(
911 void * buf, // Data to be written as URGENT TCP data.
912 PINDEX len, // Number of bytes pointed to by <CODE>buf</CODE>.
913 int flags,
914 sockaddr * addr, // Address from which the datagram was received.
915 PINDEX * addrlen)
917 lastReadCount = 0;
919 if (!PXSetIOBlock(PXReadBlock, readTimeout))
920 return FALSE;
922 // attempt to read non-out of band data
923 int r = ::recvfrom(os_handle, (char *)buf, len, flags, (sockaddr *)addr, (socklen_t *)addrlen);
924 if (!ConvertOSError(r, LastReadError))
925 return FALSE;
927 lastReadCount = r;
928 return lastReadCount > 0;
931 #endif
934 BOOL PSocket::os_sendto(
935 const void * buf, // Data to be written as URGENT TCP data.
936 PINDEX len, // Number of bytes pointed to by <CODE>buf</CODE>.
937 int flags,
938 sockaddr * addr, // Address to which the datagram is sent.
939 PINDEX addrlen)
941 lastWriteCount = 0;
943 if (!IsOpen())
944 return SetErrorValues(NotOpen, EBADF, LastWriteError);
946 // attempt to read data
947 int result;
948 for (;;) {
949 if (addr != NULL)
950 result = ::sendto(os_handle, (char *)buf, len, flags, (sockaddr *)addr, addrlen);
951 else
952 result = ::send(os_handle, (char *)buf, len, flags);
954 if (result > 0)
955 break;
957 if (errno != EWOULDBLOCK)
958 return ConvertOSError(-1, LastWriteError);
960 if (!PXSetIOBlock(PXWriteBlock, writeTimeout))
961 return FALSE;
964 #if !defined(P_PTHREADS) && !defined(P_MAC_MPTHREADS)
965 PThread::Yield(); // Starvation prevention
966 #endif
968 lastWriteCount = result;
969 return ConvertOSError(0, LastWriteError);
973 BOOL PSocket::Read(void * buf, PINDEX len)
975 if (os_handle < 0)
976 return SetErrorValues(NotOpen, EBADF, LastReadError);
978 if (!PXSetIOBlock(PXReadBlock, readTimeout))
979 return FALSE;
981 if (ConvertOSError(lastReadCount = ::recv(os_handle, (char *)buf, len, 0)))
982 return lastReadCount > 0;
984 lastReadCount = 0;
985 return FALSE;
990 //////////////////////////////////////////////////////////////////
992 // PEthSocket
995 PEthSocket::PEthSocket(PINDEX, PINDEX, PINDEX)
997 medium = MediumUnknown;
998 filterMask = FilterDirected|FilterBroadcast;
999 filterType = TypeAll;
1000 fakeMacHeader = FALSE;
1001 ipppInterface = FALSE;
1005 PEthSocket::~PEthSocket()
1007 Close();
1011 BOOL PEthSocket::Connect(const PString & interfaceName)
1013 Close();
1015 fakeMacHeader = FALSE;
1016 ipppInterface = FALSE;
1018 if (strncmp("eth", interfaceName, 3) == 0)
1019 medium = Medium802_3;
1020 else if (strncmp("lo", interfaceName, 2) == 0)
1021 medium = MediumLoop;
1022 else if (strncmp("sl", interfaceName, 2) == 0) {
1023 medium = MediumWan;
1024 fakeMacHeader = TRUE;
1026 else if (strncmp("ppp", interfaceName, 3) == 0) {
1027 medium = MediumWan;
1028 fakeMacHeader = TRUE;
1030 else if (strncmp("ippp", interfaceName, 4) == 0) {
1031 medium = MediumWan;
1032 ipppInterface = TRUE;
1034 #ifdef P_RTEMS
1035 else if (strncmp(RTEMS_BSP_NETWORK_DRIVER_NAME, interfaceName, 3) == 0)
1036 medium = Medium802_3;
1037 #endif
1038 else
1039 return SetErrorValues(NotFound, ENOENT);
1041 #if defined(SIO_Get_MAC_Address)
1042 PUDPSocket ifsock;
1043 struct ifreq ifr;
1044 ifr.ifr_addr.sa_family = AF_INET;
1045 strcpy(ifr.ifr_name, interfaceName);
1046 if (!ConvertOSError(ioctl(ifsock.GetHandle(), SIO_Get_MAC_Address, &ifr)))
1047 return FALSE;
1049 memcpy(&macAddress, ifr.ifr_macaddr, sizeof(macAddress));
1050 #endif
1052 channelName = interfaceName;
1053 return OpenSocket();
1057 BOOL PEthSocket::OpenSocket()
1059 #ifdef SOCK_PACKET
1060 if (!ConvertOSError(os_handle = os_socket(AF_INET, SOCK_PACKET, htons(filterType))))
1061 return FALSE;
1063 struct sockaddr addr;
1064 memset(&addr, 0, sizeof(addr));
1065 addr.sa_family = AF_INET;
1066 strcpy(addr.sa_data, channelName);
1067 if (!ConvertOSError(bind(os_handle, &addr, sizeof(addr)))) {
1068 os_close();
1069 os_handle = -1;
1070 return FALSE;
1072 #endif
1074 return TRUE;
1078 BOOL PEthSocket::Close()
1080 SetFilter(FilterDirected, filterType); // Turn off promiscuous mode
1081 return PSocket::Close();
1085 BOOL PEthSocket::EnumInterfaces(PINDEX idx, PString & name)
1087 PUDPSocket ifsock;
1089 ifreq ifreqs[20]; // Maximum of 20 interfaces
1090 struct ifconf ifc;
1091 ifc.ifc_len = sizeof(ifreqs);
1092 ifc.ifc_buf = (caddr_t)ifreqs;
1093 if (!ConvertOSError(ioctl(ifsock.GetHandle(), SIOCGIFCONF, &ifc)))
1094 return FALSE;
1096 int ifcount = ifc.ifc_len/sizeof(ifreq);
1097 int ifidx;
1098 for (ifidx = 0; ifidx < ifcount; ifidx++) {
1099 if (strchr(ifreqs[ifidx].ifr_name, ':') == NULL) {
1100 ifreq ifr;
1101 strcpy(ifr.ifr_name, ifreqs[ifidx].ifr_name);
1102 if (ioctl(ifsock.GetHandle(), SIOCGIFFLAGS, &ifr) == 0 &&
1103 (ifr.ifr_flags & IFF_UP) != 0 &&
1104 idx-- == 0) {
1105 name = ifreqs[ifidx].ifr_name;
1106 return TRUE;
1111 return FALSE;
1115 BOOL PEthSocket::GetAddress(Address & addr)
1117 if (!IsOpen())
1118 return FALSE;
1120 addr = macAddress;
1121 return TRUE;
1125 BOOL PEthSocket::EnumIpAddress(PINDEX idx,
1126 PIPSocket::Address & addr,
1127 PIPSocket::Address & net_mask)
1129 if (!IsOpen())
1130 return FALSE;
1132 PUDPSocket ifsock;
1133 struct ifreq ifr;
1134 ifr.ifr_addr.sa_family = AF_INET;
1135 if (idx == 0)
1136 strcpy(ifr.ifr_name, channelName);
1137 else
1138 sprintf(ifr.ifr_name, "%s:%u", (const char *)channelName, (int)(idx-1));
1139 if (!ConvertOSError(ioctl(os_handle, SIOCGIFADDR, &ifr)))
1140 return FALSE;
1142 sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
1143 addr = sin->sin_addr;
1145 if (!ConvertOSError(ioctl(os_handle, SIOCGIFNETMASK, &ifr)))
1146 return FALSE;
1148 net_mask = sin->sin_addr;
1149 return TRUE;
1153 BOOL PEthSocket::GetFilter(unsigned & mask, WORD & type)
1155 if (!IsOpen())
1156 return FALSE;
1158 ifreq ifr;
1159 memset(&ifr, 0, sizeof(ifr));
1160 strcpy(ifr.ifr_name, channelName);
1161 if (!ConvertOSError(ioctl(os_handle, SIOCGIFFLAGS, &ifr)))
1162 return FALSE;
1164 if ((ifr.ifr_flags&IFF_PROMISC) != 0)
1165 filterMask |= FilterPromiscuous;
1166 else
1167 filterMask &= ~FilterPromiscuous;
1169 mask = filterMask;
1170 type = filterType;
1171 return TRUE;
1175 BOOL PEthSocket::SetFilter(unsigned filter, WORD type)
1177 if (!IsOpen())
1178 return FALSE;
1180 if (filterType != type) {
1181 os_close();
1182 filterType = type;
1183 if (!OpenSocket())
1184 return FALSE;
1187 ifreq ifr;
1188 memset(&ifr, 0, sizeof(ifr));
1189 strcpy(ifr.ifr_name, channelName);
1190 if (!ConvertOSError(ioctl(os_handle, SIOCGIFFLAGS, &ifr)))
1191 return FALSE;
1193 if ((filter&FilterPromiscuous) != 0)
1194 ifr.ifr_flags |= IFF_PROMISC;
1195 else
1196 ifr.ifr_flags &= ~IFF_PROMISC;
1198 if (!ConvertOSError(ioctl(os_handle, SIOCSIFFLAGS, &ifr)))
1199 return FALSE;
1201 filterMask = filter;
1203 return TRUE;
1207 PEthSocket::MediumTypes PEthSocket::GetMedium()
1209 return medium;
1213 BOOL PEthSocket::ResetAdaptor()
1215 // No implementation
1216 return TRUE;
1220 BOOL PEthSocket::Read(void * buf, PINDEX len)
1222 static const BYTE macHeader[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 8, 0 };
1224 BYTE * bufptr = (BYTE *)buf;
1226 if (fakeMacHeader) {
1227 if (len <= (PINDEX)sizeof(macHeader)) {
1228 memcpy(bufptr, macHeader, len);
1229 lastReadCount = len;
1230 return TRUE;
1233 memcpy(bufptr, macHeader, sizeof(macHeader));
1234 bufptr += sizeof(macHeader);
1235 len -= sizeof(macHeader);
1238 for (;;) {
1239 sockaddr from;
1240 PINDEX fromlen = sizeof(from);
1241 if (!os_recvfrom(bufptr, len, 0, &from, &fromlen))
1242 return FALSE;
1244 if (channelName != from.sa_data)
1245 continue;
1247 if (ipppInterface) {
1248 if (lastReadCount <= 10)
1249 return FALSE;
1250 if (memcmp(bufptr+6, "\xff\x03\x00\x21", 4) != 0) {
1251 memmove(bufptr+sizeof(macHeader), bufptr, lastReadCount);
1252 lastReadCount += sizeof(macHeader);
1254 else {
1255 memmove(bufptr+sizeof(macHeader), bufptr+10, lastReadCount);
1256 lastReadCount += sizeof(macHeader)-10;
1258 memcpy(bufptr, macHeader, sizeof(macHeader));
1259 break;
1262 if (fakeMacHeader) {
1263 lastReadCount += sizeof(macHeader);
1264 break;
1267 if ((filterMask&FilterPromiscuous) != 0)
1268 break;
1270 if ((filterMask&FilterDirected) != 0 && macAddress == bufptr)
1271 break;
1273 static const Address broadcast;
1274 if ((filterMask&FilterBroadcast) != 0 && broadcast == bufptr)
1275 break;
1278 return lastReadCount > 0;
1282 BOOL PEthSocket::Write(const void * buf, PINDEX len)
1284 sockaddr to;
1285 strcpy((char *)to.sa_data, channelName);
1286 return os_sendto(buf, len, 0, &to, sizeof(to)) && lastWriteCount >= len;
1290 ///////////////////////////////////////////////////////////////////////////////
1292 BOOL PIPSocket::GetGatewayAddress(Address & addr)
1294 RouteTable table;
1295 if (GetRouteTable(table)) {
1296 for (PINDEX i = 0; i < table.GetSize(); i++) {
1297 if (table[i].GetNetwork() == 0) {
1298 addr = table[i].GetDestination();
1299 return TRUE;
1303 return FALSE;
1308 PString PIPSocket::GetGatewayInterface()
1310 RouteTable table;
1311 if (GetRouteTable(table)) {
1312 for (PINDEX i = 0; i < table.GetSize(); i++) {
1313 if (table[i].GetNetwork() == 0)
1314 return table[i].GetInterface();
1317 return PString();
1320 #if defined(P_LINUX) || defined (P_AIX)
1322 BOOL PIPSocket::GetRouteTable(RouteTable & table)
1324 PTextFile procfile;
1325 if (!procfile.Open("/proc/net/route", PFile::ReadOnly))
1326 return FALSE;
1328 for (;;) {
1329 // Ignore heading line or remainder of route line
1330 procfile.ignore(1000, '\n');
1331 if (procfile.eof())
1332 return TRUE;
1334 char iface[20];
1335 unsigned long net_addr, dest_addr, net_mask;
1336 int flags, refcnt, use, metric;
1337 procfile >> iface >> ::hex >> net_addr >> dest_addr >> flags
1338 >> ::dec >> refcnt >> use >> metric
1339 >> ::hex >> net_mask;
1340 if (procfile.bad())
1341 return FALSE;
1343 RouteEntry * entry = new RouteEntry(net_addr);
1344 entry->net_mask = net_mask;
1345 entry->destination = dest_addr;
1346 entry->interfaceName = iface;
1347 entry->metric = metric;
1348 table.Append(entry);
1352 #elif defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_QNX)
1354 BOOL process_rtentry(struct rt_msghdr *rtm, char *ptr, unsigned long *p_net_addr,
1355 unsigned long *p_net_mask, unsigned long *p_dest_addr, int *p_metric);
1356 BOOL get_ifname(int index, char *name);
1358 BOOL PIPSocket::GetRouteTable(RouteTable & table)
1360 int mib[6];
1361 size_t space_needed;
1362 char *limit, *buf, *ptr;
1363 struct rt_msghdr *rtm;
1365 InterfaceTable if_table;
1368 // Read the Routing Table
1369 mib[0] = CTL_NET;
1370 mib[1] = PF_ROUTE;
1371 mib[2] = 0;
1372 mib[3] = 0;
1373 mib[4] = NET_RT_DUMP;
1374 mib[5] = 0;
1376 if (sysctl(mib, 6, NULL, &space_needed, NULL, 0) < 0) {
1377 printf("sysctl: net.route.0.0.dump estimate");
1378 return FALSE;
1381 if ((buf = (char *)malloc(space_needed)) == NULL) {
1382 printf("malloc(%lu)", (unsigned long)space_needed);
1383 return FALSE;
1386 // read the routing table data
1387 if (sysctl(mib, 6, buf, &space_needed, NULL, 0) < 0) {
1388 printf("sysctl: net.route.0.0.dump");
1389 free(buf);
1390 return FALSE;
1394 // Read the interface table
1395 if (!GetInterfaceTable(if_table)) {
1396 printf("Interface Table Invalid\n");
1397 return FALSE;
1401 // Process the Routing Table data
1402 limit = buf + space_needed;
1403 for (ptr = buf; ptr < limit; ptr += rtm->rtm_msglen) {
1405 unsigned long net_addr, dest_addr, net_mask;
1406 int metric;
1407 char name[16];
1409 rtm = (struct rt_msghdr *)ptr;
1411 if ( process_rtentry(rtm,ptr, &net_addr, &net_mask, &dest_addr, &metric) ){
1413 RouteEntry * entry = new RouteEntry(net_addr);
1414 entry->net_mask = net_mask;
1415 entry->destination = dest_addr;
1416 if ( get_ifname(rtm->rtm_index,name) )
1417 entry->interfaceName = name;
1418 entry->metric = metric;
1419 table.Append(entry);
1421 } // end if
1423 } // end for loop
1425 free(buf);
1426 return TRUE;
1429 BOOL process_rtentry(struct rt_msghdr *rtm, char *ptr, unsigned long *p_net_addr,
1430 unsigned long *p_net_mask, unsigned long *p_dest_addr, int *p_metric) {
1432 struct sockaddr_in *sa_in;
1434 unsigned long net_addr, dest_addr, net_mask;
1435 int metric;
1437 sa_in = (struct sockaddr_in *)(rtm + 1);
1440 // Check for zero length entry
1441 if (rtm->rtm_msglen == 0) {
1442 printf("zero length message\n");
1443 return FALSE;
1446 if ((~rtm->rtm_flags&RTF_LLINFO)
1447 #if defined(P_NETBSD) || defined(P_QNX)
1448 && (~rtm->rtm_flags&RTF_CLONED) // Net BSD has flag one way
1449 #elif !defined(P_OPENBSD)
1450 && (~rtm->rtm_flags&RTF_WASCLONED) // Free BSD/MAC has it another
1451 #else
1452 // Open BSD does not have it at all!
1453 #endif
1456 //strcpy(name, if_table[rtm->rtm_index].GetName);
1458 net_addr=dest_addr=net_mask=metric=0;
1460 // NET_ADDR
1461 if(rtm->rtm_addrs&RTA_DST ) {
1462 if(sa_in->sin_family == AF_INET)
1463 net_addr = sa_in->sin_addr.s_addr;
1465 sa_in = (struct sockaddr_in *)((char *)sa_in + ROUNDUP(sa_in->sin_len));
1468 // DEST_ADDR
1469 if(rtm->rtm_addrs&RTA_GATEWAY) {
1470 if(sa_in->sin_family == AF_INET)
1471 dest_addr = sa_in->sin_addr.s_addr;
1473 sa_in = (struct sockaddr_in *)((char *)sa_in + ROUNDUP(sa_in->sin_len));
1476 // NETMASK
1477 if(rtm->rtm_addrs&RTA_NETMASK && sa_in->sin_len)
1478 net_mask = sa_in->sin_addr.s_addr;
1480 if( rtm->rtm_flags&RTF_HOST)
1481 net_mask = 0xffffffff;
1484 *p_metric = metric;
1485 *p_net_addr = net_addr;
1486 *p_dest_addr = dest_addr;
1487 *p_net_mask = net_mask;
1489 return TRUE;
1491 } else {
1492 return FALSE;
1497 BOOL get_ifname(int index, char *name) {
1498 int mib[6];
1499 size_t needed;
1500 char *lim, *buf, *next;
1501 struct if_msghdr *ifm;
1502 struct sockaddr_dl *sdl;
1504 mib[0] = CTL_NET;
1505 mib[1] = PF_ROUTE;
1506 mib[2] = 0;
1507 mib[3] = AF_INET;
1508 mib[4] = NET_RT_IFLIST;
1509 mib[5] = index;
1511 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
1512 printf("ERR route-sysctl-estimate");
1513 return FALSE;
1516 if ((buf = (char *)malloc(needed)) == NULL) {
1517 printf("ERR malloc");
1518 return FALSE;
1521 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
1522 printf("ERR actual retrieval of routing table");
1523 free(buf);
1524 return FALSE;
1527 lim = buf + needed;
1529 next = buf;
1530 if (next < lim) {
1532 ifm = (struct if_msghdr *)next;
1534 if (ifm->ifm_type == RTM_IFINFO) {
1535 sdl = (struct sockaddr_dl *)(ifm + 1);
1536 } else {
1537 printf("out of sync parsing NET_RT_IFLIST\n");
1538 return FALSE;
1540 next += ifm->ifm_msglen;
1542 strncpy(name, sdl->sdl_data, sdl->sdl_nlen);
1543 name[sdl->sdl_nlen] = '\0';
1545 free(buf);
1546 return TRUE;
1548 } else {
1549 free(buf);
1550 return FALSE;
1556 #elif defined(P_SOLARIS)
1558 /* jpd@louisiana.edu - influenced by Merit.edu's Gated 3.6 routine: krt_rtread_sunos5.c */
1560 #include <sys/stream.h>
1561 #include <stropts.h>
1562 #include <sys/tihdr.h>
1563 #include <sys/tiuser.h>
1564 #include <inet/common.h>
1565 #include <inet/mib2.h>
1566 #include <inet/ip.h>
1568 #ifndef T_CURRENT
1569 #define T_CURRENT MI_T_CURRENT
1570 #endif
1572 BOOL PIPSocket::GetRouteTable(RouteTable & table)
1574 #define task_pagesize 512
1575 char buf[task_pagesize]; /* = task_block_malloc(task_pagesize);*/
1576 int flags;
1577 int j = 0;
1578 int sd, i, rc;
1579 struct strbuf strbuf;
1580 struct T_optmgmt_req *tor = (struct T_optmgmt_req *) buf;
1581 struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *) buf;
1582 struct T_error_ack *tea = (struct T_error_ack *) buf;
1583 struct opthdr *req;
1585 sd = open("/dev/ip", O_RDWR);
1586 if (sd < 0) {
1587 #ifdef SOL_COMPLAIN
1588 perror("can't open mib stream");
1589 #endif
1590 goto Return;
1593 strbuf.buf = buf;
1595 tor->PRIM_type = T_OPTMGMT_REQ;
1596 tor->OPT_offset = sizeof(struct T_optmgmt_req);
1597 tor->OPT_length = sizeof(struct opthdr);
1598 tor->MGMT_flags = T_CURRENT;
1599 req = (struct opthdr *) (tor + 1);
1600 req->level = MIB2_IP; /* any MIB2_xxx value ok here */
1601 req->name = 0;
1602 req->len = 0;
1604 strbuf.len = tor->OPT_length + tor->OPT_offset;
1605 flags = 0;
1606 rc = putmsg(sd, &strbuf, (struct strbuf *) 0, flags);
1607 if (rc == -1) {
1608 #ifdef SOL_COMPLAIN
1609 perror("putmsg(ctl)");
1610 #endif
1611 goto Return;
1614 * each reply consists of a ctl part for one fixed structure
1615 * or table, as defined in mib2.h. The format is a T_OPTMGMT_ACK,
1616 * containing an opthdr structure. level/name identify the entry,
1617 * len is the size of the data part of the message.
1619 req = (struct opthdr *) (toa + 1);
1620 strbuf.maxlen = task_pagesize;
1621 while (++j) {
1622 flags = 0;
1623 rc = getmsg(sd, &strbuf, (struct strbuf *) 0, &flags);
1624 if (rc == -1) {
1625 #ifdef SOL_COMPLAIN
1626 perror("getmsg(ctl)");
1627 #endif
1628 goto Return;
1630 if (rc == 0
1631 && strbuf.len >= (int)sizeof(struct T_optmgmt_ack)
1632 && toa->PRIM_type == T_OPTMGMT_ACK
1633 && toa->MGMT_flags == T_SUCCESS
1634 && req->len == 0) {
1635 errno = 0; /* just to be darned sure it's 0 */
1636 goto Return; /* this is EOD msg */
1639 if (strbuf.len >= (int)sizeof(struct T_error_ack)
1640 && tea->PRIM_type == T_ERROR_ACK) {
1641 errno = (tea->TLI_error == TSYSERR) ? tea->UNIX_error : EPROTO;
1642 #ifdef SOL_COMPLAIN
1643 perror("T_ERROR_ACK in mibget");
1644 #endif
1645 goto Return;
1648 if (rc != MOREDATA
1649 || strbuf.len < (int)sizeof(struct T_optmgmt_ack)
1650 || toa->PRIM_type != T_OPTMGMT_ACK
1651 || toa->MGMT_flags != T_SUCCESS) {
1652 errno = ENOMSG;
1653 goto Return;
1656 if (req->level != MIB2_IP
1657 #if P_SOLARIS > 7
1658 || req->name != MIB2_IP_ROUTE
1659 #endif
1660 ) { /* == 21 */
1661 /* If this is not the routing table, skip it */
1662 /* Note we don't bother with IPv6 (MIB2_IP6_ROUTE) ... */
1663 strbuf.maxlen = task_pagesize;
1664 do {
1665 rc = getmsg(sd, (struct strbuf *) 0, &strbuf, &flags);
1666 } while (rc == MOREDATA) ;
1667 continue;
1670 strbuf.maxlen = (task_pagesize / sizeof (mib2_ipRouteEntry_t)) * sizeof (mib2_ipRouteEntry_t);
1671 strbuf.len = 0;
1672 flags = 0;
1673 do {
1674 rc = getmsg(sd, (struct strbuf * ) 0, &strbuf, &flags);
1676 switch (rc) {
1677 case -1:
1678 #ifdef SOL_COMPLAIN
1679 perror("mibget getmsg(data) failed.");
1680 #endif
1681 goto Return;
1683 default:
1684 #ifdef SOL_COMPLAIN
1685 fprintf(stderr,"mibget getmsg(data) returned %d, strbuf.maxlen = %d, strbuf.len = %d",
1687 strbuf.maxlen,
1688 strbuf.len);
1689 #endif
1690 goto Return;
1692 case MOREDATA:
1693 case 0:
1695 mib2_ipRouteEntry_t *rp = (mib2_ipRouteEntry_t *) strbuf.buf;
1696 mib2_ipRouteEntry_t *lp = (mib2_ipRouteEntry_t *) (strbuf.buf + strbuf.len);
1698 do {
1699 char name[256];
1700 #ifdef SOL_DEBUG_RT
1701 printf("%s -> %s mask %s metric %d %d %d %d %d ifc %.*s type %d/%x/%x\n",
1702 inet_ntoa(rp->ipRouteDest),
1703 inet_ntoa(rp->ipRouteNextHop),
1704 inet_ntoa(rp->ipRouteMask),
1705 rp->ipRouteMetric1,
1706 rp->ipRouteMetric2,
1707 rp->ipRouteMetric3,
1708 rp->ipRouteMetric4,
1709 rp->ipRouteMetric5,
1710 rp->ipRouteIfIndex.o_length,
1711 rp->ipRouteIfIndex.o_bytes,
1712 rp->ipRouteType,
1713 rp->ipRouteInfo.re_ire_type,
1714 rp->ipRouteInfo.re_flags
1716 #endif
1717 if (rp->ipRouteInfo.re_ire_type & (IRE_BROADCAST|IRE_CACHE|IRE_LOCAL))
1718 continue;
1719 RouteEntry * entry = new RouteEntry(rp->ipRouteDest);
1720 entry->net_mask = rp->ipRouteMask;
1721 entry->destination = rp->ipRouteNextHop;
1722 unsigned len = rp->ipRouteIfIndex.o_length;
1723 if (len >= sizeof(name))
1724 len = sizeof(name)-1;
1725 strncpy(name, rp->ipRouteIfIndex.o_bytes, len);
1726 name[len] = '\0';
1727 entry->interfaceName = name;
1728 entry->metric = rp->ipRouteMetric1;
1729 table.Append(entry);
1730 } while (++rp < lp) ;
1732 break;
1734 } while (rc == MOREDATA) ;
1737 Return:
1738 i = errno;
1739 (void) close(sd);
1740 errno = i;
1741 /*task_block_reclaim(task_pagesize, buf);*/
1742 if (errno)
1743 return (FALSE);
1744 else
1745 return (TRUE);
1749 #elif defined(P_VXWORKS)
1751 BOOL PIPSocket::GetRouteTable(RouteTable & table)
1753 PAssertAlways("PIPSocket::GetRouteTable()");
1754 for(;;){
1755 char iface[20];
1756 unsigned long net_addr, dest_addr, net_mask;
1757 int metric;
1758 RouteEntry * entry = new RouteEntry(net_addr);
1759 entry->net_mask = net_mask;
1760 entry->destination = dest_addr;
1761 entry->interfaceName = iface;
1762 entry->metric = metric;
1763 table.Append(entry);
1764 return TRUE;
1768 #else // unsupported platform
1770 #if 0
1771 BOOL PIPSocket::GetRouteTable(RouteTable & table)
1773 // Most of this code came from the source code for the "route" command
1774 // so it should work on other platforms too.
1775 // However, it is not complete (the "address-for-interface" function doesn't exist) and not tested!
1777 route_table_req_t reqtable;
1778 route_req_t *rrtp;
1779 int i,ret;
1781 ret = get_route_table(&reqtable);
1782 if (ret < 0)
1784 return FALSE;
1787 for (i=reqtable.cnt, rrtp = reqtable.rrtp;i>0;i--, rrtp++)
1789 //the datalink doesn't save addresses/masks for host and default
1790 //routes, so the route_req_t may not be filled out completely
1791 if (rrtp->flags & RTF_DEFAULT) {
1792 //the IP default route is 0/0
1793 ((struct sockaddr_in *)&rrtp->dst)->sin_addr.s_addr = 0;
1794 ((struct sockaddr_in *)&rrtp->mask)->sin_addr.s_addr = 0;
1796 } else if (rrtp->flags & RTF_HOST) {
1797 //host routes are addr/32
1798 ((struct sockaddr_in *)&rrtp->mask)->sin_addr.s_addr = 0xffffffff;
1801 RouteEntry * entry = new RouteEntry(/* address_for_interface(rrtp->iface) */);
1802 entry->net_mask = rrtp->mask;
1803 entry->destination = rrtp->dst;
1804 entry->interfaceName = rrtp->iface;
1805 entry->metric = rrtp->refcnt;
1806 table.Append(entry);
1809 free(reqtable.rrtp);
1811 return TRUE;
1812 #endif // 0
1814 BOOL PIPSocket::GetRouteTable(RouteTable & table)
1816 #warning Platform requires implemetation of GetRouteTable()
1817 return FALSE;
1819 #endif
1822 // fe800000000000000202e3fffe1ee330 02 40 20 80 eth0
1823 // 00000000000000000000000000000001 01 80 10 80 lo
1825 BOOL PIPSocket::GetInterfaceTable(InterfaceTable & list, BOOL includeDown)
1827 #if P_HAS_IPV6
1828 // build a table of IPV6 interface addresses
1829 typedef std::map<PString, PString> IP6ListType;
1830 IP6ListType ip6Ifaces;
1832 FILE * file;
1833 int dummy;
1834 int addr[16];
1835 char ifaceName[255];
1836 if ((file = fopen("/proc/net/if_inet6", "r")) != NULL) {
1837 while (fscanf(file, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x %x %x %x %x %255s\n",
1838 &addr[0], &addr[1], &addr[2], &addr[3],
1839 &addr[4], &addr[5], &addr[6], &addr[7],
1840 &addr[8], &addr[9], &addr[10], &addr[11],
1841 &addr[12], &addr[13], &addr[14], &addr[15],
1842 &dummy, &dummy, &dummy, &dummy, ifaceName) != EOF) {
1843 PString addrStr(
1844 psprintf("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
1845 addr[0], addr[1], addr[2], addr[3],
1846 addr[4], addr[5], addr[6], addr[7],
1847 addr[8], addr[9], addr[10], addr[11],
1848 addr[12], addr[13], addr[14], addr[15]
1851 PString iface(ifaceName);
1852 ip6Ifaces.insert(IP6ListType::value_type(ifaceName, addrStr));
1854 fclose(file);
1857 #endif
1859 PUDPSocket sock;
1861 PBYTEArray buffer;
1862 struct ifconf ifConf;
1865 // HERE
1866 #if defined(SIOCGIFNUM)
1867 int ifNum;
1868 PAssert(::ioctl(sock.GetHandle(), SIOCGIFNUM, &ifNum) >= 0, "could not do ioctl for ifNum");
1869 ifConf.ifc_len = ifNum * sizeof(ifreq);
1870 #else
1871 ifConf.ifc_len = 100 * sizeof(ifreq); // That's a LOT of interfaces!
1872 #endif
1874 ifConf.ifc_req = (struct ifreq *)buffer.GetPointer(ifConf.ifc_len);
1876 if (ioctl(sock.GetHandle(), SIOCGIFCONF, &ifConf) >= 0) {
1877 void * ifEndList = (char *)ifConf.ifc_req + ifConf.ifc_len;
1878 ifreq * ifName = ifConf.ifc_req;
1879 while (ifName < ifEndList) {
1881 struct ifreq ifReq;
1882 memcpy(&ifReq, ifName, sizeof(ifreq));
1884 if (ioctl(sock.GetHandle(), SIOCGIFFLAGS, &ifReq) >= 0) {
1885 int flags = ifReq.ifr_flags;
1886 if (includeDown || (flags & IFF_UP) != 0) {
1887 PString name(ifReq.ifr_name);
1889 PString macAddr;
1890 #if defined(SIO_Get_MAC_Address)
1891 memcpy(&ifReq, ifName, sizeof(ifreq));
1892 if (ioctl(sock.GetHandle(), SIO_Get_MAC_Address, &ifReq) >= 0) {
1893 PEthSocket::Address a((BYTE *)ifReq.ifr_macaddr);
1894 macAddr = (PString)a;
1896 #endif
1898 memcpy(&ifReq, ifName, sizeof(ifreq));
1899 if (ioctl(sock.GetHandle(), SIOCGIFADDR, &ifReq) >= 0) {
1901 sockaddr_in * sin = (sockaddr_in *)&ifReq.ifr_addr;
1902 PIPSocket::Address addr = sin->sin_addr;
1904 memcpy(&ifReq, ifName, sizeof(ifreq));
1905 if (ioctl(sock.GetHandle(), SIOCGIFNETMASK, &ifReq) >= 0) {
1906 PIPSocket::Address mask =
1907 #ifndef __BEOS__
1908 ((sockaddr_in *)&ifReq.ifr_netmask)->sin_addr;
1909 #else
1910 ((sockaddr_in *)&ifReq.ifr_mask)->sin_addr;
1911 #endif // !__BEOS__
1912 PINDEX i;
1913 for (i = 0; i < list.GetSize(); i++) {
1914 #ifdef P_TORNADO
1915 if (list[i].GetName() == name &&
1916 list[i].GetAddress() == addr)
1917 if(list[i].GetNetMask() == mask)
1918 #else
1919 if (list[i].GetName() == name &&
1920 list[i].GetAddress() == addr &&
1921 list[i].GetNetMask() == mask)
1922 #endif
1923 break;
1925 #if P_HAS_IPV6
1926 PString ip6Addr;
1927 IP6ListType::const_iterator r = ip6Ifaces.find(name);
1928 if (r != ip6Ifaces.end())
1929 ip6Addr = r->second;
1930 #endif
1931 if (i >= list.GetSize())
1932 list.Append(PNEW InterfaceEntry(name, addr, mask, macAddr
1933 #if P_HAS_IPV6
1934 , ip6Addr
1935 #endif
1942 #if defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_VXWORKS) || defined(P_RTEMS) || defined(P_QNX)
1943 // move the ifName pointer along to the next ifreq entry
1944 ifName = (struct ifreq *)((char *)ifName + _SIZEOF_ADDR_IFREQ(*ifName));
1945 #else
1946 ifName++;
1947 #endif
1951 return TRUE;
1954 #ifdef P_VXWORKS
1956 int h_errno;
1958 struct hostent * Vx_gethostbyname(char *name, struct hostent *hp)
1960 u_long addr;
1961 static char staticgethostname[100];
1963 hp->h_aliases = NULL;
1964 hp->h_addr_list[1] = NULL;
1965 if ((int)(addr = inet_addr(name)) != ERROR) {
1966 memcpy(staticgethostname, &addr, sizeof(addr));
1967 hp->h_addr_list[0] = staticgethostname;
1968 h_errno = SUCCESS;
1969 return hp;
1971 memcpy(staticgethostname, &addr, sizeof (addr));
1972 hp->h_addr_list[0] = staticgethostname;
1973 h_errno = SUCCESS;
1974 return hp;
1977 struct hostent * Vx_gethostbyaddr(char *name, struct hostent *hp)
1979 u_long addr;
1980 static char staticgethostaddr[100];
1982 hp->h_aliases = NULL;
1983 hp->h_addr_list = NULL;
1985 if ((int)(addr = inet_addr(name)) != ERROR) {
1986 char ipStorage[INET_ADDR_LEN];
1987 inet_ntoa_b(*(struct in_addr*)&addr, ipStorage);
1988 sprintf(staticgethostaddr,"%s",ipStorage);
1989 hp->h_name = staticgethostaddr;
1990 h_errno = SUCCESS;
1992 else
1994 printf ("_gethostbyaddr: not able to get %s\n",name);
1995 h_errno = NOTFOUND;
1997 return hp;
2000 #endif // P_VXWORKS
2003 #include "../common/pethsock.cxx"
2005 //////////////////////////////////////////////////////////////////////////////
2006 // PUDPSocket
2008 void PUDPSocket::EnableGQoS()
2012 BOOL PUDPSocket::SupportQoS(const PIPSocket::Address & )
2014 return FALSE;
2017 ///////////////////////////////////////////////////////////////////////////////