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
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.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
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
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
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
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
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
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"
356 #include <ptlib/sockets.h>
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
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>
378 #include <netinet/if_ether.h>
382 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
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>
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*
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))
410 int PX_NewHandle(const char *, int);
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
);
419 //////////////////////////////////////////////////////////////////////////////
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 //////////////////////////////////////////////////////////////////////////////
443 int PSocket::os_close()
448 // send a shutdown to the other end
449 ::shutdown(os_handle
, 2);
455 static int SetNonBlocking(int fd
)
460 // Set non-blocking so we can use select calls to break I/O block on close
462 #if defined(P_VXWORKS)
463 if (::ioctl(fd
, FIONBIO
, &cmd
) == 0)
465 if (::ioctl(fd
, FIONBIO
, &cmd
) == 0 && ::fcntl(fd
, F_SETFD
, 1) == 0)
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
)
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
))
493 // A successful select() call does not necessarily mean the socket connected OK.
495 socklen_t optlen
= sizeof(optval
);
496 getsockopt(os_handle
, SOL_SOCKET
, SO_ERROR
, (char *)&optval
, &optlen
);
499 return ConvertOSError(-1);
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());
513 int new_fd
= ::accept(listener
.GetHandle(), addr
, (socklen_t
*)size
);
515 return ConvertOSError(os_handle
= SetNonBlocking(new_fd
));
518 return ConvertOSError(-1);
520 PTRACE(3, "PWLib\tAccept on " << sock
<< " failed with EPROTO - retrying");
523 return ConvertOSError(os_handle
= SetNonBlocking(::accept(listener
.GetHandle(), addr
, (socklen_t
*)size
)));
528 #if !defined(P_PTHREADS) && !defined(P_MAC_MPTHREADS) && !defined(__BEOS__)
530 PChannel::Errors
PSocket::Select(SelectList
& read
,
533 const PTimeInterval
& timeout
)
538 Errors lastError
= NoError
;
539 PThread
* unblockThread
= PThread::Current();
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())
550 int h
= socket
.GetHandle();
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,
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();
580 lastError
= Interrupted
;
581 else if (!fds
[i
].IsPresent(h
))
582 list
[i
]->RemoveAt(j
--);
592 PChannel::Errors
PSocket::Select(SelectList
& read
,
595 const PTimeInterval
& timeout
)
599 Errors lastError
= NoError
;
600 PThread
* unblockThread
= PThread::Current();
601 int unblockPipe
= unblockThread
->unblockPipe
[0];
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())
612 int h
= socket
.GetHandle();
617 socket
.px_selectMutex
.Wait();
618 socket
.px_selectThread
= unblockThread
;
623 if (lastError
== NoError
) {
624 fds
[0] += unblockPipe
;
625 if (unblockPipe
> maxfds
)
626 maxfds
= unblockPipe
;
628 P_timeval tval
= timeout
;
630 result
= ::select(maxfds
+1, (fd_set
*)fds
[0], (fd_set
*)fds
[1], (fd_set
*)fds
[2], tval
);
631 } while (result
< 0 && errno
== EINTR
);
634 if (ConvertOSError(result
, lastError
, osError
)) {
635 if (fds
[0].IsPresent(unblockPipe
)) {
636 PTRACE(6, "PWLib\tSelect unblocked fd=" << unblockPipe
);
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();
652 lastError
= Interrupted
;
653 else if (!fds
[i
].IsPresent(h
))
654 list
[i
]->RemoveAt(j
--);
665 PIPSocket::Address::Address(DWORD dw
)
671 PIPSocket::Address
& PIPSocket::Address::operator=(DWORD dw
)
675 memset(&v
, 0, sizeof(v
));
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
)
714 BYTE
* p
= (BYTE
*)&v
.four
.s_addr
;
721 BOOL
PIPSocket::IsLocalHost(const PString
& hostname
)
723 if (hostname
.IsEmpty())
726 if (hostname
*= "localhost")
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
736 if (!GetHostAddress(hostname
, addr
))
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
)) {
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
);
770 // check IPV4 addresses
774 struct ifconf ifConf
;
778 PAssert(::ioctl(sock
.GetHandle(), SIOCGIFNUM
, &ifNum
) >= 0, "could not do ioctl for ifNum");
779 ifConf
.ifc_len
= ifNum
* sizeof(ifreq
);
781 ifConf
.ifc_len
= 100 * sizeof(ifreq
); // That's a LOT of interfaces!
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
) {
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
;
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
));
817 ////////////////////////////////////////////////////////////////
821 BOOL
PTCPSocket::Read(void * buf
, PINDEX maxLen
)
826 // wait until select indicates there is data to read, or until
828 if (!PXSetIOBlock(PXReadBlock
, readTimeout
))
831 // attempt to read out of band data
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
))
843 return lastReadCount
> 0;
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>.
853 sockaddr
* addr
, // Address from which the datagram was received.
858 if (!PXSetIOBlock(PXReadBlock
, readTimeout
))
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
))
868 return lastReadCount
> 0;
872 memset(&readData
, 0, sizeof(readData
));
874 readData
.msg_name
= addr
;
875 readData
.msg_namelen
= *addrlen
;
878 readVector
.iov_base
= buf
;
879 readVector
.iov_len
= len
;
880 readData
.msg_iov
= &readVector
;
881 readData
.msg_iovlen
= 1;
884 readData
.msg_control
= auxdata
;
885 readData
.msg_controllen
= sizeof(auxdata
);
888 int r
= ::recvmsg(os_handle
, &readData
, 0);
889 if (!ConvertOSError(r
, LastReadError
))
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
));
905 return lastReadCount
> 0;
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>.
914 sockaddr
* addr
, // Address from which the datagram was received.
919 if (!PXSetIOBlock(PXReadBlock
, readTimeout
))
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
))
928 return lastReadCount
> 0;
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>.
938 sockaddr
* addr
, // Address to which the datagram is sent.
944 return SetErrorValues(NotOpen
, EBADF
, LastWriteError
);
946 // attempt to read data
950 result
= ::sendto(os_handle
, (char *)buf
, len
, flags
, (sockaddr
*)addr
, addrlen
);
952 result
= ::send(os_handle
, (char *)buf
, len
, flags
);
957 if (errno
!= EWOULDBLOCK
)
958 return ConvertOSError(-1, LastWriteError
);
960 if (!PXSetIOBlock(PXWriteBlock
, writeTimeout
))
964 #if !defined(P_PTHREADS) && !defined(P_MAC_MPTHREADS)
965 PThread::Yield(); // Starvation prevention
968 lastWriteCount
= result
;
969 return ConvertOSError(0, LastWriteError
);
973 BOOL
PSocket::Read(void * buf
, PINDEX len
)
976 return SetErrorValues(NotOpen
, EBADF
, LastReadError
);
978 if (!PXSetIOBlock(PXReadBlock
, readTimeout
))
981 if (ConvertOSError(lastReadCount
= ::recv(os_handle
, (char *)buf
, len
, 0)))
982 return lastReadCount
> 0;
990 //////////////////////////////////////////////////////////////////
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()
1011 BOOL
PEthSocket::Connect(const PString
& interfaceName
)
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) {
1024 fakeMacHeader
= TRUE
;
1026 else if (strncmp("ppp", interfaceName
, 3) == 0) {
1028 fakeMacHeader
= TRUE
;
1030 else if (strncmp("ippp", interfaceName
, 4) == 0) {
1032 ipppInterface
= TRUE
;
1035 else if (strncmp(RTEMS_BSP_NETWORK_DRIVER_NAME
, interfaceName
, 3) == 0)
1036 medium
= Medium802_3
;
1039 return SetErrorValues(NotFound
, ENOENT
);
1041 #if defined(SIO_Get_MAC_Address)
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
)))
1049 memcpy(&macAddress
, ifr
.ifr_macaddr
, sizeof(macAddress
));
1052 channelName
= interfaceName
;
1053 return OpenSocket();
1057 BOOL
PEthSocket::OpenSocket()
1060 if (!ConvertOSError(os_handle
= os_socket(AF_INET
, SOCK_PACKET
, htons(filterType
))))
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
)))) {
1078 BOOL
PEthSocket::Close()
1080 SetFilter(FilterDirected
, filterType
); // Turn off promiscuous mode
1081 return PSocket::Close();
1085 BOOL
PEthSocket::EnumInterfaces(PINDEX idx
, PString
& name
)
1089 ifreq ifreqs
[20]; // Maximum of 20 interfaces
1091 ifc
.ifc_len
= sizeof(ifreqs
);
1092 ifc
.ifc_buf
= (caddr_t
)ifreqs
;
1093 if (!ConvertOSError(ioctl(ifsock
.GetHandle(), SIOCGIFCONF
, &ifc
)))
1096 int ifcount
= ifc
.ifc_len
/sizeof(ifreq
);
1098 for (ifidx
= 0; ifidx
< ifcount
; ifidx
++) {
1099 if (strchr(ifreqs
[ifidx
].ifr_name
, ':') == NULL
) {
1101 strcpy(ifr
.ifr_name
, ifreqs
[ifidx
].ifr_name
);
1102 if (ioctl(ifsock
.GetHandle(), SIOCGIFFLAGS
, &ifr
) == 0 &&
1103 (ifr
.ifr_flags
& IFF_UP
) != 0 &&
1105 name
= ifreqs
[ifidx
].ifr_name
;
1115 BOOL
PEthSocket::GetAddress(Address
& addr
)
1125 BOOL
PEthSocket::EnumIpAddress(PINDEX idx
,
1126 PIPSocket::Address
& addr
,
1127 PIPSocket::Address
& net_mask
)
1134 ifr
.ifr_addr
.sa_family
= AF_INET
;
1136 strcpy(ifr
.ifr_name
, channelName
);
1138 sprintf(ifr
.ifr_name
, "%s:%u", (const char *)channelName
, (int)(idx
-1));
1139 if (!ConvertOSError(ioctl(os_handle
, SIOCGIFADDR
, &ifr
)))
1142 sockaddr_in
*sin
= (struct sockaddr_in
*)&ifr
.ifr_addr
;
1143 addr
= sin
->sin_addr
;
1145 if (!ConvertOSError(ioctl(os_handle
, SIOCGIFNETMASK
, &ifr
)))
1148 net_mask
= sin
->sin_addr
;
1153 BOOL
PEthSocket::GetFilter(unsigned & mask
, WORD
& type
)
1159 memset(&ifr
, 0, sizeof(ifr
));
1160 strcpy(ifr
.ifr_name
, channelName
);
1161 if (!ConvertOSError(ioctl(os_handle
, SIOCGIFFLAGS
, &ifr
)))
1164 if ((ifr
.ifr_flags
&IFF_PROMISC
) != 0)
1165 filterMask
|= FilterPromiscuous
;
1167 filterMask
&= ~FilterPromiscuous
;
1175 BOOL
PEthSocket::SetFilter(unsigned filter
, WORD type
)
1180 if (filterType
!= type
) {
1188 memset(&ifr
, 0, sizeof(ifr
));
1189 strcpy(ifr
.ifr_name
, channelName
);
1190 if (!ConvertOSError(ioctl(os_handle
, SIOCGIFFLAGS
, &ifr
)))
1193 if ((filter
&FilterPromiscuous
) != 0)
1194 ifr
.ifr_flags
|= IFF_PROMISC
;
1196 ifr
.ifr_flags
&= ~IFF_PROMISC
;
1198 if (!ConvertOSError(ioctl(os_handle
, SIOCSIFFLAGS
, &ifr
)))
1201 filterMask
= filter
;
1207 PEthSocket::MediumTypes
PEthSocket::GetMedium()
1213 BOOL
PEthSocket::ResetAdaptor()
1215 // No implementation
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
;
1233 memcpy(bufptr
, macHeader
, sizeof(macHeader
));
1234 bufptr
+= sizeof(macHeader
);
1235 len
-= sizeof(macHeader
);
1240 PINDEX fromlen
= sizeof(from
);
1241 if (!os_recvfrom(bufptr
, len
, 0, &from
, &fromlen
))
1244 if (channelName
!= from
.sa_data
)
1247 if (ipppInterface
) {
1248 if (lastReadCount
<= 10)
1250 if (memcmp(bufptr
+6, "\xff\x03\x00\x21", 4) != 0) {
1251 memmove(bufptr
+sizeof(macHeader
), bufptr
, lastReadCount
);
1252 lastReadCount
+= sizeof(macHeader
);
1255 memmove(bufptr
+sizeof(macHeader
), bufptr
+10, lastReadCount
);
1256 lastReadCount
+= sizeof(macHeader
)-10;
1258 memcpy(bufptr
, macHeader
, sizeof(macHeader
));
1262 if (fakeMacHeader
) {
1263 lastReadCount
+= sizeof(macHeader
);
1267 if ((filterMask
&FilterPromiscuous
) != 0)
1270 if ((filterMask
&FilterDirected
) != 0 && macAddress
== bufptr
)
1273 static const Address broadcast
;
1274 if ((filterMask
&FilterBroadcast
) != 0 && broadcast
== bufptr
)
1278 return lastReadCount
> 0;
1282 BOOL
PEthSocket::Write(const void * buf
, PINDEX len
)
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
)
1295 if (GetRouteTable(table
)) {
1296 for (PINDEX i
= 0; i
< table
.GetSize(); i
++) {
1297 if (table
[i
].GetNetwork() == 0) {
1298 addr
= table
[i
].GetDestination();
1308 PString
PIPSocket::GetGatewayInterface()
1311 if (GetRouteTable(table
)) {
1312 for (PINDEX i
= 0; i
< table
.GetSize(); i
++) {
1313 if (table
[i
].GetNetwork() == 0)
1314 return table
[i
].GetInterface();
1320 #if defined(P_LINUX) || defined (P_AIX)
1322 BOOL
PIPSocket::GetRouteTable(RouteTable
& table
)
1325 if (!procfile
.Open("/proc/net/route", PFile::ReadOnly
))
1329 // Ignore heading line or remainder of route line
1330 procfile
.ignore(1000, '\n');
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
;
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
)
1361 size_t space_needed
;
1362 char *limit
, *buf
, *ptr
;
1363 struct rt_msghdr
*rtm
;
1365 InterfaceTable if_table
;
1368 // Read the Routing Table
1373 mib
[4] = NET_RT_DUMP
;
1376 if (sysctl(mib
, 6, NULL
, &space_needed
, NULL
, 0) < 0) {
1377 printf("sysctl: net.route.0.0.dump estimate");
1381 if ((buf
= (char *)malloc(space_needed
)) == NULL
) {
1382 printf("malloc(%lu)", (unsigned long)space_needed
);
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");
1394 // Read the interface table
1395 if (!GetInterfaceTable(if_table
)) {
1396 printf("Interface Table Invalid\n");
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
;
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
);
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
;
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");
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
1452 // Open BSD does not have it at all!
1456 //strcpy(name, if_table[rtm->rtm_index].GetName);
1458 net_addr
=dest_addr
=net_mask
=metric
=0;
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
));
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
));
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;
1485 *p_net_addr
= net_addr
;
1486 *p_dest_addr
= dest_addr
;
1487 *p_net_mask
= net_mask
;
1497 BOOL
get_ifname(int index
, char *name
) {
1500 char *lim
, *buf
, *next
;
1501 struct if_msghdr
*ifm
;
1502 struct sockaddr_dl
*sdl
;
1508 mib
[4] = NET_RT_IFLIST
;
1511 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0) {
1512 printf("ERR route-sysctl-estimate");
1516 if ((buf
= (char *)malloc(needed
)) == NULL
) {
1517 printf("ERR malloc");
1521 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0) {
1522 printf("ERR actual retrieval of routing table");
1532 ifm
= (struct if_msghdr
*)next
;
1534 if (ifm
->ifm_type
== RTM_IFINFO
) {
1535 sdl
= (struct sockaddr_dl
*)(ifm
+ 1);
1537 printf("out of sync parsing NET_RT_IFLIST\n");
1540 next
+= ifm
->ifm_msglen
;
1542 strncpy(name
, sdl
->sdl_data
, sdl
->sdl_nlen
);
1543 name
[sdl
->sdl_nlen
] = '\0';
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>
1569 #define T_CURRENT MI_T_CURRENT
1572 BOOL
PIPSocket::GetRouteTable(RouteTable
& table
)
1574 #define task_pagesize 512
1575 char buf
[task_pagesize
]; /* = task_block_malloc(task_pagesize);*/
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
;
1585 sd
= open("/dev/ip", O_RDWR
);
1588 perror("can't open mib stream");
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 */
1604 strbuf
.len
= tor
->OPT_length
+ tor
->OPT_offset
;
1606 rc
= putmsg(sd
, &strbuf
, (struct strbuf
*) 0, flags
);
1609 perror("putmsg(ctl)");
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
;
1623 rc
= getmsg(sd
, &strbuf
, (struct strbuf
*) 0, &flags
);
1626 perror("getmsg(ctl)");
1631 && strbuf
.len
>= (int)sizeof(struct T_optmgmt_ack
)
1632 && toa
->PRIM_type
== T_OPTMGMT_ACK
1633 && toa
->MGMT_flags
== T_SUCCESS
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
;
1643 perror("T_ERROR_ACK in mibget");
1649 || strbuf
.len
< (int)sizeof(struct T_optmgmt_ack
)
1650 || toa
->PRIM_type
!= T_OPTMGMT_ACK
1651 || toa
->MGMT_flags
!= T_SUCCESS
) {
1656 if (req
->level
!= MIB2_IP
1658 || req
->name
!= MIB2_IP_ROUTE
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
;
1665 rc
= getmsg(sd
, (struct strbuf
*) 0, &strbuf
, &flags
);
1666 } while (rc
== MOREDATA
) ;
1670 strbuf
.maxlen
= (task_pagesize
/ sizeof (mib2_ipRouteEntry_t
)) * sizeof (mib2_ipRouteEntry_t
);
1674 rc
= getmsg(sd
, (struct strbuf
* ) 0, &strbuf
, &flags
);
1679 perror("mibget getmsg(data) failed.");
1685 fprintf(stderr
,"mibget getmsg(data) returned %d, strbuf.maxlen = %d, strbuf.len = %d",
1695 mib2_ipRouteEntry_t
*rp
= (mib2_ipRouteEntry_t
*) strbuf
.buf
;
1696 mib2_ipRouteEntry_t
*lp
= (mib2_ipRouteEntry_t
*) (strbuf
.buf
+ strbuf
.len
);
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
),
1710 rp
->ipRouteIfIndex
.o_length
,
1711 rp
->ipRouteIfIndex
.o_bytes
,
1713 rp
->ipRouteInfo
.re_ire_type
,
1714 rp
->ipRouteInfo
.re_flags
1717 if (rp
->ipRouteInfo
.re_ire_type
& (IRE_BROADCAST
|IRE_CACHE
|IRE_LOCAL
))
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
);
1727 entry
->interfaceName
= name
;
1728 entry
->metric
= rp
->ipRouteMetric1
;
1729 table
.Append(entry
);
1730 } while (++rp
< lp
) ;
1734 } while (rc
== MOREDATA
) ;
1741 /*task_block_reclaim(task_pagesize, buf);*/
1749 #elif defined(P_VXWORKS)
1751 BOOL
PIPSocket::GetRouteTable(RouteTable
& table
)
1753 PAssertAlways("PIPSocket::GetRouteTable()");
1756 unsigned long net_addr
, dest_addr
, net_mask
;
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
);
1768 #else // unsupported platform
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
;
1781 ret
= get_route_table(&reqtable
);
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
);
1814 BOOL
PIPSocket::GetRouteTable(RouteTable
& table
)
1816 #warning Platform requires implemetation of GetRouteTable()
1822 // fe800000000000000202e3fffe1ee330 02 40 20 80 eth0
1823 // 00000000000000000000000000000001 01 80 10 80 lo
1825 BOOL
PIPSocket::GetInterfaceTable(InterfaceTable
& list
, BOOL includeDown
)
1828 // build a table of IPV6 interface addresses
1829 typedef std::map
<PString
, PString
> IP6ListType
;
1830 IP6ListType ip6Ifaces
;
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
) {
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
));
1862 struct ifconf ifConf
;
1866 #if defined(SIOCGIFNUM)
1868 PAssert(::ioctl(sock
.GetHandle(), SIOCGIFNUM
, &ifNum
) >= 0, "could not do ioctl for ifNum");
1869 ifConf
.ifc_len
= ifNum
* sizeof(ifreq
);
1871 ifConf
.ifc_len
= 100 * sizeof(ifreq
); // That's a LOT of interfaces!
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
) {
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
);
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
;
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
=
1908 ((sockaddr_in
*)&ifReq
.ifr_netmask
)->sin_addr
;
1910 ((sockaddr_in
*)&ifReq
.ifr_mask
)->sin_addr
;
1913 for (i
= 0; i
< list
.GetSize(); i
++) {
1915 if (list
[i
].GetName() == name
&&
1916 list
[i
].GetAddress() == addr
)
1917 if(list
[i
].GetNetMask() == mask
)
1919 if (list
[i
].GetName() == name
&&
1920 list
[i
].GetAddress() == addr
&&
1921 list
[i
].GetNetMask() == mask
)
1927 IP6ListType::const_iterator r
= ip6Ifaces
.find(name
);
1928 if (r
!= ip6Ifaces
.end())
1929 ip6Addr
= r
->second
;
1931 if (i
>= list
.GetSize())
1932 list
.Append(PNEW
InterfaceEntry(name
, addr
, mask
, macAddr
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
));
1958 struct hostent
* Vx_gethostbyname(char *name
, struct hostent
*hp
)
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
;
1971 memcpy(staticgethostname
, &addr
, sizeof (addr
));
1972 hp
->h_addr_list
[0] = staticgethostname
;
1977 struct hostent
* Vx_gethostbyaddr(char *name
, struct hostent
*hp
)
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
;
1994 printf ("_gethostbyaddr: not able to get %s\n",name
);
2003 #include "../common/pethsock.cxx"
2005 //////////////////////////////////////////////////////////////////////////////
2008 void PUDPSocket::EnableGQoS()
2012 BOOL
PUDPSocket::SupportQoS(const PIPSocket::Address
& )
2017 ///////////////////////////////////////////////////////////////////////////////