Uncommented beaudio code
[pwlib.git] / src / ptlib / unix / socket.cxx
blobacdfbc229dc1b65b9fec0ccfd9308b4f189b4576
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.100 2003/10/27 04:06:14 csoutheren
31 * Added code to allow compilation of new QoS code on Unix
33 * Revision 1.99 2003/01/24 10:21:06 robertj
34 * Fixed issues in RTEMS support, thanks Vladimir Nesic
36 * Revision 1.98 2002/11/22 10:14:07 robertj
37 * QNX port, thanks Xiaodan Tang
39 * Revision 1.97 2002/11/02 00:32:21 robertj
40 * Further fixes to VxWorks (Tornado) port, thanks Andreas Sikkema.
42 * Revision 1.96 2002/10/22 10:25:07 rogerh
43 * Fix process_rtentry() following Thomas's patch.
45 * Revision 1.95 2002/10/22 07:42:52 robertj
46 * Added extra debugging for file handle and thread leak detection.
48 * Revision 1.94 2002/10/22 06:53:38 craigs
49 * Fixed signed/unsigned problem in GetRoutTable thanks to Thomas Jalsovsky
51 * Revision 1.93 2002/10/19 06:12:20 robertj
52 * Moved P_fd_set::Zero() from platform independent to platform dependent
53 * code as Win32 implementation is completely different from Unix.
55 * Revision 1.92 2002/10/17 13:44:27 robertj
56 * Port to RTEMS, thanks Vladimir Nesic.
58 * Revision 1.91 2002/10/17 12:57:24 robertj
59 * Added ability to increase maximum file handles on a process.
61 * Revision 1.90 2002/10/10 04:43:44 robertj
62 * VxWorks port, thanks Martijn Roest
64 * Revision 1.89 2002/10/08 14:31:43 robertj
65 * Changed for IPv6 support, thanks Sébastien Josset.
67 * Revision 1.88 2002/06/05 12:29:16 craigs
68 * Changes for gcc 3.1
70 * Revision 1.87 2002/04/18 06:16:06 robertj
71 * Fixed Net BSD problem with RTF_CLONED flag, thanks Motoyuki OHMORI
72 * Fixed operator precedence problem with bit mask tests in RTF_CLONE code.
74 * Revision 1.86 2002/04/12 07:57:41 robertj
75 * Fixed bug introduced into Accept() by previous change.
77 * Revision 1.85 2002/04/12 01:42:41 robertj
78 * Changed return value on os_connect() and os_accept() to make sure
79 * get the correct error codes propagated up under unix.
81 * Revision 1.84 2002/02/13 02:19:47 robertj
82 * Fixed mistake in previous patch, is if not ifdef!
84 * Revision 1.83 2002/02/13 00:50:32 robertj
85 * Fixed use of symbol in older versionsof Solaris, thanks Markus Storm
87 * Revision 1.82 2002/01/31 22:52:18 robertj
88 * Added fix for buffer too small in Solaris GetRouteTable(), thanks Markus Storm.
90 * Revision 1.81 2001/12/17 23:33:50 robertj
91 * Solaris 8 porting changes, thanks James Dugal
93 * Revision 1.80 2001/12/10 07:07:27 rogerh
94 * Take out some #includes which were already in pachdep.h. Fixes openBSD 2.9
96 * Revision 1.79 2001/11/22 12:29:57 rogerh
97 * Take out the cloned flag on OpenBSD so it compiles
99 * Revision 1.78 2001/11/14 10:37:32 rogerh
100 * Define _SIZEOF_ADDR_IFREQ as OpenBSD does not have it
102 * Revision 1.77 2001/10/28 23:00:10 robertj
103 * Fixed Solaris and IRIX compatibility issue, thanks Andre Schulze
105 * Revision 1.76 2001/10/11 02:20:54 robertj
106 * Added IRIX support (no audio/video), thanks Andre Schulze.
108 * Revision 1.75 2001/10/03 19:31:56 rogerh
109 * Add MAC OS X support to GetInterfaceTable
111 * Revision 1.74 2001/10/03 10:18:15 rogerh
112 * Make Mac OS X (Darwin) use the new GetRouteTable() function.
114 * Revision 1.73 2001/09/24 15:37:35 rogerh
115 * Add GetRouteTable() for BSD Unix. Based on FreeBSD's own networking code,
116 * and from an implementation by Martin Nilsson <martin@gneto.com>
118 * Revision 1.72 2001/09/19 00:41:20 robertj
119 * Fixed GetInterfaceTable so does not add duplicate interfaces into list.
120 * Changed the loop condition to allow for BSD variable length records.
122 * Revision 1.71 2001/09/18 05:56:03 robertj
123 * Fixed numerous problems with thread suspend/resume and signals handling.
125 * Revision 1.70 2001/09/10 03:03:36 robertj
126 * Major change to fix problem with error codes being corrupted in a
127 * PChannel when have simultaneous reads and writes in threads.
129 * Revision 1.69 2001/08/16 11:58:22 rogerh
130 * Add more Mac OS X changes from John Woods <jfw@jfwhome.funhouse.com>
132 * Revision 1.68 2001/08/12 07:12:40 rogerh
133 * More Mac OS Carbon changes from John Woods <jfw@jfwhome.funhouse.com>
135 * Revision 1.67 2001/08/12 06:34:33 rogerh
136 * Add Mac OS Carbon changes from John Woods <jfw@jfwhome.funhouse.com>
138 * Revision 1.66 2001/08/07 02:27:22 robertj
139 * Fixed some incorrect error values returned in Read() and Write() functions.
141 * Revision 1.65 2001/07/03 04:41:25 yurik
142 * Corrections to Jac's submission from 6/28
144 * Revision 1.64 2001/06/30 06:59:07 yurik
145 * Jac Goudsmit from Be submit these changes 6/28. Implemented by Yuri Kiryanov
147 * Revision 1.63 2001/06/19 12:09:13 rogerh
148 * Mac OS X change
150 * Revision 1.62 2001/04/16 22:46:22 craigs
151 * Fixed problem with os_connect not correctly reporting errors
153 * Revision 1.61 2001/03/26 03:31:53 robertj
154 * Fixed Solaris compile error.
156 * Revision 1.60 2001/03/20 06:44:25 robertj
157 * Lots of changes to fix the problems with terminating threads that are I/O
158 * blocked, especially when doing orderly shutdown of service via SIGTERM.
160 * Revision 1.59 2001/03/07 23:37:59 robertj
161 * Fixed slow down in UDP packet send, thanks Dmitriy Reka
163 * Revision 1.58 2001/03/07 06:56:36 yurik
164 * Made adjustment for BONE platforms as requested by Jac Goudsmit
166 * Revision 1.57 2001/03/06 00:16:59 robertj
167 * Fixed BSD compatibility problem.
169 * Revision 1.56 2001/03/05 04:28:56 robertj
170 * Added net mask to interface info returned by GetInterfaceTable()
172 * Revision 1.55 2001/02/02 23:31:30 robertj
173 * Fixed enumeration of interfaces, thanks Bertrand Croq.
175 * Revision 1.54 2001/01/17 03:48:25 rogerh
176 * Fix GetInterfaceTable so it actually works through all interfaces rather
177 * than falling over after the first entry.
179 * Revision 1.53 2001/01/16 12:56:01 rogerh
180 * On BeOS sa_data is 'unsigned char *'. Linux and BSD defines sa_data as 'char *'
181 * Add typecast, submitted by Jac Goudsmit <jac_goudsmit@yahoo.com>
183 * Revision 1.52 2000/06/21 01:01:22 robertj
184 * AIX port, thanks Wolfgang Platzer (wolfgang.platzer@infonova.at).
186 * Revision 1.51 2000/04/19 00:13:53 robertj
187 * BeOS port changes.
189 * Revision 1.50 2000/04/07 05:43:48 rogerh
190 * Fix a compilation error in a non-pthreaded function. Found by Kevin Packard
192 * Revision 1.49 2000/03/17 03:45:40 craigs
193 * Fixed problem with connect call hanging
195 * Revision 1.48 2000/02/17 23:47:40 robertj
196 * Fixed error in check for SIOCGHWADDR define, thanks Markus Storm.
198 * Revision 1.47 2000/01/20 08:20:57 robertj
199 * FreeBSD v3 compatibility changes, thanks Roger Hardiman & Motonori Shindo
201 * Revision 1.46 1999/11/18 13:45:21 craigs
202 * Removed obsolete declaration of iostream semaphore
204 * Revision 1.45 1999/10/30 13:43:01 craigs
205 * Added correct method of aborting socket operations asynchronously
207 * Revision 1.44 1999/09/27 01:04:42 robertj
208 * BeOS support changes.
210 * Revision 1.43 1999/09/12 07:06:23 craigs
211 * Added support for getting Solaris interface info
213 * Revision 1.42 1999/09/10 02:31:19 craigs
214 * Added interface table routines
216 * Revision 1.41 1999/09/03 02:26:25 robertj
217 * Changes to aid in breaking I/O locks on thread termination. Still needs more work esp in BSD!
219 * Revision 1.40 1999/05/01 03:52:20 robertj
220 * Fixed various egcs warnings.
222 * Revision 1.39 1999/03/02 05:41:59 robertj
223 * More BeOS changes
225 * Revision 1.38 1999/02/26 04:10:39 robertj
226 * More BeOS port changes
228 * Revision 1.37 1999/02/22 13:26:54 robertj
229 * BeOS port changes.
231 * Revision 1.36 1998/11/30 21:51:58 robertj
232 * New directory structure.
234 * Revision 1.35 1998/11/24 09:39:22 robertj
235 * FreeBSD port.
237 * Revision 1.34 1998/11/22 08:11:37 craigs
238 * *** empty log message ***
240 * Revision 1.33 1998/11/14 10:37:38 robertj
241 * Changed semantics of os_sendto to return TRUE if ANY bytes are sent.
243 * Revision 1.32 1998/10/16 01:16:55 craigs
244 * Added Yield to help with cooperative multithreading.
246 * Revision 1.31 1998/10/11 02:23:16 craigs
247 * Fixed problem with socket writes not correctly detecting EOF
249 * Revision 1.30 1998/09/24 08:21:11 robertj
250 * Fixed warning on GNU 6 library.
252 * Revision 1.29 1998/09/24 07:55:51 robertj
253 * Fixed warning on solaris build.
255 * Revision 1.28 1998/09/24 04:13:49 robertj
256 * Added open software license.
258 * Revision 1.27 1998/09/18 05:46:00 robertj
259 * Fixed incorrectly returning success on a connect() error other than a timeout.
261 * Revision 1.26 1998/09/08 11:31:51 robertj
262 * Fixed ippp bug on very full packets.
264 * Revision 1.25 1998/09/08 09:54:31 robertj
265 * Fixed ppp and ippp compatibility.
267 * Revision 1.24 1998/09/08 05:15:14 robertj
268 * Fixed problem in Windows requiring snmpapi.dll for PEthSocket class.
270 * Revision 1.23 1998/08/27 01:13:20 robertj
271 * Changes to resolve signedness in GNU C library v6
272 * Remove Linux EthSocket stuff from Sun build, still needs implementing.
274 * Revision 1.22 1998/08/21 05:30:59 robertj
275 * Ethernet socket implementation.
279 #pragma implementation "sockets.h"
280 #pragma implementation "socket.h"
281 #pragma implementation "ipsock.h"
282 #pragma implementation "udpsock.h"
283 #pragma implementation "tcpsock.h"
284 #pragma implementation "ipdsock.h"
285 #pragma implementation "ethsock.h"
286 #pragma implementation "qos.h"
289 #include <ptlib.h>
290 #include <ptlib/sockets.h>
293 #if defined(SIOCGENADDR)
294 #define SIO_Get_MAC_Address SIOCGENADDR
295 #define ifr_macaddr ifr_ifru.ifru_enaddr
296 #elif defined(SIOCGIFHWADDR)
297 #define SIO_Get_MAC_Address SIOCGIFHWADDR
298 #define ifr_macaddr ifr_hwaddr.sa_data
299 #endif
301 #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)
302 #define ifr_netmask ifr_addr
304 #include <net/if_dl.h>
305 #include <net/if_types.h>
306 #include <net/route.h>
308 #include <netinet/in.h>
309 #if !defined(P_QNX)
310 #include <netinet/if_ether.h>
311 #endif
313 #define ROUNDUP(a) \
314 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
316 #endif
318 #if defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_MACOS) || defined(P_QNX)
319 #include <sys/sysctl.h>
320 #endif
322 #ifdef P_RTEMS
323 #include <bsp.h>
324 #endif
326 int PX_NewHandle(const char *, int);
329 //////////////////////////////////////////////////////////////////////////////
330 // P_fd_set
332 void P_fd_set::Construct()
334 max_fd = PProcess::Current().GetMaxHandles();
335 set = (fd_set *)new char[(max_fd+7)>>3];
339 void P_fd_set::Zero()
341 PAssertNULL(set);
342 memset(set, 0, (max_fd+7)>>3);
346 //////////////////////////////////////////////////////////////////////////////
348 PSocket::~PSocket()
350 os_close();
353 int PSocket::os_close()
355 if (os_handle < 0)
356 return -1;
358 // send a shutdown to the other end
359 ::shutdown(os_handle, 2);
361 #if defined(__BEOS__) && !defined(BE_THREADS)
362 // abort any I/O block using this os_handle
363 PProcess::Current().PXAbortIOBlock(os_handle);
364 #endif
366 #ifdef BE_BONELESS
367 int retval = ::closesocket(os_handle);
368 os_handle = -1;
369 return retval;
370 #else
371 return PXClose();
372 #endif
376 static int SetNonBlocking(int fd)
378 #if defined __BEOS__ || defined(P_VXWORKS)
379 return fd;
380 #else
381 if (fd < 0)
382 return -1;
384 // Set non-blocking so we can use select calls to break I/O block on close
385 int cmd = 1;
386 if (::ioctl(fd, FIONBIO, &cmd) == 0 && ::fcntl(fd, F_SETFD, 1) == 0)
387 return fd;
389 ::close(fd);
390 return -1;
391 #endif // !__BEOS__ && !P_VXWORKS
395 int PSocket::os_socket(int af, int type, int protocol)
397 // attempt to create a socket
398 return SetNonBlocking(PX_NewHandle(GetClass(), ::socket(af, type, protocol)));
402 BOOL PSocket::os_connect(struct sockaddr * addr, PINDEX size)
404 int val = ::connect(os_handle, addr, size);
405 if (val == 0 || errno != EINPROGRESS)
406 return ConvertOSError(val);
408 if (!PXSetIOBlock(PXConnectBlock, readTimeout))
409 return FALSE;
411 #ifndef __BEOS__
412 // A successful select() call does not necessarily mean the socket connected OK.
413 int optval = -1;
414 socklen_t optlen = sizeof(optval);
415 getsockopt(os_handle, SOL_SOCKET, SO_ERROR, (char *)&optval, &optlen);
416 if (optval != 0) {
417 errno = optval;
418 return ConvertOSError(-1);
420 #endif //!__BEOS__
422 return TRUE;
426 BOOL PSocket::os_accept(PSocket & listener, struct sockaddr * addr, PINDEX * size)
428 if (!listener.PXSetIOBlock(PXAcceptBlock, listener.GetReadTimeout()))
429 return SetErrorValues(listener.GetErrorCode(), listener.GetErrorNumber());
431 #if defined(E_PROTO)
432 for (;;) {
433 int new_fd = ::accept(listener.GetHandle(), addr, (socklen_t *)size);
434 if (new_fd >= 0)
435 return ConvertOSError(os_handle = SetNonBlocking(new_fd));
437 if (errno != EPROTO)
438 return ConvertOSError(-1);
440 PTRACE(3, "PWLib\tAccept on " << sock << " failed with EPROTO - retrying");
442 #else
443 return ConvertOSError(os_handle = SetNonBlocking(::accept(listener.GetHandle(), addr, (socklen_t *)size)));
444 #endif
448 #if !defined(P_PTHREADS) && !defined(P_MAC_MPTHREADS)
450 int PSocket::os_select(int maxHandle,
451 fd_set * readBits,
452 fd_set * writeBits,
453 fd_set * exceptionBits,
454 const PIntArray & osHandles,
455 const PTimeInterval & timeout)
457 int stat = PThread::Current()->PXBlockOnIO(maxHandle,
458 readBits,
459 writeBits,
460 exceptionBits,
461 timeout,
462 osHandles);
463 if (stat <= 0)
464 return stat;
466 P_timeval instant;
467 return ::select(maxHandle, readBits, writeBits, exceptionBits, instant);
470 #else
472 int PSocket::os_select(int width,
473 fd_set * readBits,
474 fd_set * writeBits,
475 fd_set * exceptionBits,
476 const PIntArray & ,
477 const PTimeInterval & timeout)
479 int unblockPipe = PThread::Current()->unblockPipe[0];
480 FD_SET(unblockPipe, readBits);
481 width = PMAX(width, unblockPipe+1);
483 do {
484 P_timeval tval = timeout;
485 int result = ::select(width, readBits, writeBits, exceptionBits, tval);
486 if (result >= 0) {
487 if (FD_ISSET(unblockPipe, readBits)) {
488 FD_CLR(unblockPipe, readBits);
489 if (result == 1) {
490 BYTE ch;
491 ::read(unblockPipe, &ch, 1);
492 FD_CLR(unblockPipe, readBits);
493 errno = EINTR;
494 return -1;
497 return result;
499 } while (errno == EINTR);
500 return -1;
503 #endif
506 PIPSocket::Address::Address(DWORD dw)
508 operator=(dw);
512 PIPSocket::Address & PIPSocket::Address::operator=(DWORD dw)
514 if (dw == 0) {
515 version = 0;
516 memset(&v, 0, sizeof(v));
518 else {
519 version = 4;
520 v.four.s_addr = dw;
523 return *this;
527 PIPSocket::Address::operator DWORD() const
529 return version != 4 ? 0 : (DWORD)v.four.s_addr;
532 BYTE PIPSocket::Address::Byte1() const
534 return *(((BYTE *)&v.four.s_addr)+0);
537 BYTE PIPSocket::Address::Byte2() const
539 return *(((BYTE *)&v.four.s_addr)+1);
542 BYTE PIPSocket::Address::Byte3() const
544 return *(((BYTE *)&v.four.s_addr)+2);
547 BYTE PIPSocket::Address::Byte4() const
549 return *(((BYTE *)&v.four.s_addr)+3);
552 PIPSocket::Address::Address(BYTE b1, BYTE b2, BYTE b3, BYTE b4)
554 version = 4;
555 BYTE * p = (BYTE *)&v.four.s_addr;
556 p[0] = b1;
557 p[1] = b2;
558 p[2] = b3;
559 p[3] = b4;
562 BOOL PIPSocket::IsLocalHost(const PString & hostname)
564 if (hostname.IsEmpty())
565 return TRUE;
567 if (hostname *= "localhost")
568 return TRUE;
570 // lookup the host address using inet_addr, assuming it is a "." address
571 Address addr = hostname;
572 if (addr.IsLoopback()) // Is 127.0.0.1
573 return TRUE;
574 if (!addr.IsValid())
575 return FALSE;
577 if (!GetHostAddress(hostname, addr))
578 return FALSE;
580 PUDPSocket sock;
582 #ifndef __BEOS__
583 // get number of interfaces
584 int ifNum;
585 #ifdef SIOCGIFNUM
586 PAssert(::ioctl(sock.GetHandle(), SIOCGIFNUM, &ifNum) >= 0, "could not do ioctl for ifNum");
587 #else
588 ifNum = 100;
589 #endif
591 PBYTEArray buffer;
592 struct ifconf ifConf;
593 ifConf.ifc_len = ifNum * sizeof(ifreq);
594 ifConf.ifc_req = (struct ifreq *)buffer.GetPointer(ifConf.ifc_len);
596 if (ioctl(sock.GetHandle(), SIOCGIFCONF, &ifConf) >= 0) {
597 #ifndef SIOCGIFNUM
598 ifNum = ifConf.ifc_len / sizeof(ifreq);
599 #endif
601 int num = 0;
602 for (num = 0; num < ifNum; num++) {
604 ifreq * ifName = ifConf.ifc_req + num;
605 struct ifreq ifReq;
606 strcpy(ifReq.ifr_name, ifName->ifr_name);
608 if (ioctl(sock.GetHandle(), SIOCGIFFLAGS, &ifReq) >= 0) {
609 int flags = ifReq.ifr_flags;
610 if (ioctl(sock.GetHandle(), SIOCGIFADDR, &ifReq) >= 0) {
611 if ((flags & IFF_UP) && (addr == Address(((sockaddr_in *)&ifReq.ifr_addr)->sin_addr)))
612 return TRUE;
617 #endif //!__BEOS__
619 return FALSE;
623 ////////////////////////////////////////////////////////////////
625 // PTCPSocket
627 BOOL PTCPSocket::Read(void * buf, PINDEX maxLen)
630 lastReadCount = 0;
632 // wait until select indicates there is data to read, or until
633 // a timeout occurs
634 if (!PXSetIOBlock(PXReadBlock, readTimeout))
635 return FALSE;
637 #ifndef __BEOS__
638 // attempt to read out of band data
639 char buffer[32];
640 int ooblen;
641 while ((ooblen = ::recv(os_handle, buffer, sizeof(buffer), MSG_OOB)) > 0)
642 OnOutOfBand(buffer, ooblen);
643 #endif // !__BEOS__
645 // attempt to read non-out of band data
646 int r = ::recv(os_handle, (char *)buf, maxLen, 0);
647 if (!ConvertOSError(r, LastReadError))
648 return FALSE;
650 lastReadCount = r;
651 return lastReadCount > 0;
655 BOOL PSocket::os_recvfrom(
656 void * buf, // Data to be written as URGENT TCP data.
657 PINDEX len, // Number of bytes pointed to by <CODE>buf</CODE>.
658 int flags,
659 sockaddr * addr, // Address from which the datagram was received.
660 PINDEX * addrlen)
662 lastReadCount = 0;
664 if (!PXSetIOBlock(PXReadBlock, readTimeout))
665 return FALSE;
667 // attempt to read non-out of band data
668 int r = ::recvfrom(os_handle, (char *)buf, len, flags, (sockaddr *)addr, (socklen_t *)addrlen);
669 if (!ConvertOSError(r, LastReadError))
670 return FALSE;
672 lastReadCount = r;
673 return lastReadCount > 0;
677 BOOL PSocket::os_sendto(
678 const void * buf, // Data to be written as URGENT TCP data.
679 PINDEX len, // Number of bytes pointed to by <CODE>buf</CODE>.
680 int flags,
681 sockaddr * addr, // Address to which the datagram is sent.
682 PINDEX addrlen)
684 lastWriteCount = 0;
686 if (!IsOpen())
687 return SetErrorValues(NotOpen, EBADF, LastWriteError);
689 // attempt to read data
690 int result;
691 for (;;) {
692 if (addr != NULL)
693 result = ::sendto(os_handle, (char *)buf, len, flags, (sockaddr *)addr, addrlen);
694 else
695 result = ::send(os_handle, (char *)buf, len, flags);
697 if (result > 0)
698 break;
700 if (errno != EWOULDBLOCK)
701 return ConvertOSError(-1, LastWriteError);
703 if (!PXSetIOBlock(PXWriteBlock, writeTimeout))
704 return FALSE;
707 #if !defined(P_PTHREADS) && !defined(P_MAC_MPTHREADS)
708 PThread::Yield(); // Starvation prevention
709 #endif
711 lastWriteCount = result;
712 return ConvertOSError(0, LastWriteError);
716 BOOL PSocket::Read(void * buf, PINDEX len)
718 if (os_handle < 0)
719 return SetErrorValues(NotOpen, EBADF, LastReadError);
721 if (!PXSetIOBlock(PXReadBlock, readTimeout))
722 return FALSE;
724 if (ConvertOSError(lastReadCount = ::recv(os_handle, (char *)buf, len, 0)))
725 return lastReadCount > 0;
727 lastReadCount = 0;
728 return FALSE;
733 //////////////////////////////////////////////////////////////////
735 // PEthSocket
738 PEthSocket::PEthSocket(PINDEX, PINDEX, PINDEX)
740 medium = MediumUnknown;
741 filterMask = FilterDirected|FilterBroadcast;
742 filterType = TypeAll;
743 fakeMacHeader = FALSE;
744 ipppInterface = FALSE;
748 PEthSocket::~PEthSocket()
750 Close();
754 BOOL PEthSocket::Connect(const PString & interfaceName)
756 Close();
758 fakeMacHeader = FALSE;
759 ipppInterface = FALSE;
761 if (strncmp("eth", interfaceName, 3) == 0)
762 medium = Medium802_3;
763 else if (strncmp("lo", interfaceName, 2) == 0)
764 medium = MediumLoop;
765 else if (strncmp("sl", interfaceName, 2) == 0) {
766 medium = MediumWan;
767 fakeMacHeader = TRUE;
769 else if (strncmp("ppp", interfaceName, 3) == 0) {
770 medium = MediumWan;
771 fakeMacHeader = TRUE;
773 else if (strncmp("ippp", interfaceName, 4) == 0) {
774 medium = MediumWan;
775 ipppInterface = TRUE;
777 #ifdef P_RTEMS
778 else if (strncmp(RTEMS_BSP_NETWORK_DRIVER_NAME, interfaceName, 3) == 0)
779 medium = Medium802_3;
780 #endif
781 else
782 return SetErrorValues(NotFound, ENOENT);
784 #if defined(SIO_Get_MAC_Address) && !defined(__BEOS__)
785 PUDPSocket ifsock;
786 struct ifreq ifr;
787 ifr.ifr_addr.sa_family = AF_INET;
788 strcpy(ifr.ifr_name, interfaceName);
789 if (!ConvertOSError(ioctl(ifsock.GetHandle(), SIO_Get_MAC_Address, &ifr)))
790 return FALSE;
792 memcpy(&macAddress, ifr.ifr_macaddr, sizeof(macAddress));
793 #endif
795 channelName = interfaceName;
796 return OpenSocket();
800 BOOL PEthSocket::OpenSocket()
802 #ifdef SOCK_PACKET
803 if (!ConvertOSError(os_handle = os_socket(AF_INET, SOCK_PACKET, htons(filterType))))
804 return FALSE;
806 struct sockaddr addr;
807 memset(&addr, 0, sizeof(addr));
808 addr.sa_family = AF_INET;
809 strcpy(addr.sa_data, channelName);
810 if (!ConvertOSError(bind(os_handle, &addr, sizeof(addr)))) {
811 os_close();
812 os_handle = -1;
813 return FALSE;
815 #endif
817 return TRUE;
821 BOOL PEthSocket::Close()
823 SetFilter(FilterDirected, filterType); // Turn off promiscuous mode
824 return PSocket::Close();
828 BOOL PEthSocket::EnumInterfaces(PINDEX idx, PString & name)
830 #ifndef __BEOS__
831 PUDPSocket ifsock;
833 ifreq ifreqs[20]; // Maximum of 20 interfaces
834 struct ifconf ifc;
835 ifc.ifc_len = sizeof(ifreqs);
836 ifc.ifc_buf = (caddr_t)ifreqs;
837 if (!ConvertOSError(ioctl(ifsock.GetHandle(), SIOCGIFCONF, &ifc)))
838 return FALSE;
840 int ifcount = ifc.ifc_len/sizeof(ifreq);
841 int ifidx;
842 for (ifidx = 0; ifidx < ifcount; ifidx++) {
843 if (strchr(ifreqs[ifidx].ifr_name, ':') == NULL) {
844 ifreq ifr;
845 strcpy(ifr.ifr_name, ifreqs[ifidx].ifr_name);
846 if (ioctl(ifsock.GetHandle(), SIOCGIFFLAGS, &ifr) == 0 &&
847 (ifr.ifr_flags & IFF_UP) != 0 &&
848 idx-- == 0) {
849 name = ifreqs[ifidx].ifr_name;
850 return TRUE;
854 #endif //!__BEOS__
856 return FALSE;
860 BOOL PEthSocket::GetAddress(Address & addr)
862 if (!IsOpen())
863 return FALSE;
865 addr = macAddress;
866 return TRUE;
870 BOOL PEthSocket::EnumIpAddress(PINDEX idx,
871 PIPSocket::Address & addr,
872 PIPSocket::Address & net_mask)
874 if (!IsOpen())
875 return FALSE;
877 #ifndef __BEOS__
878 PUDPSocket ifsock;
879 struct ifreq ifr;
880 ifr.ifr_addr.sa_family = AF_INET;
881 if (idx == 0)
882 strcpy(ifr.ifr_name, channelName);
883 else
884 sprintf(ifr.ifr_name, "%s:%u", (const char *)channelName, (int)(idx-1));
885 if (!ConvertOSError(ioctl(os_handle, SIOCGIFADDR, &ifr)))
886 return FALSE;
888 sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
889 addr = sin->sin_addr;
891 if (!ConvertOSError(ioctl(os_handle, SIOCGIFNETMASK, &ifr)))
892 return FALSE;
894 net_mask = sin->sin_addr;
895 return TRUE;
896 #else
897 return FALSE;
898 #endif //!__BEOS__
902 BOOL PEthSocket::GetFilter(unsigned & mask, WORD & type)
904 if (!IsOpen())
905 return FALSE;
907 #ifndef __BEOS__
908 ifreq ifr;
909 memset(&ifr, 0, sizeof(ifr));
910 strcpy(ifr.ifr_name, channelName);
911 if (!ConvertOSError(ioctl(os_handle, SIOCGIFFLAGS, &ifr)))
912 return FALSE;
914 if ((ifr.ifr_flags&IFF_PROMISC) != 0)
915 filterMask |= FilterPromiscuous;
916 else
917 filterMask &= ~FilterPromiscuous;
919 mask = filterMask;
920 type = filterType;
921 return TRUE;
922 #else
923 return FALSE;
924 #endif //!__BEOS__
928 BOOL PEthSocket::SetFilter(unsigned filter, WORD type)
930 if (!IsOpen())
931 return FALSE;
933 if (filterType != type) {
934 os_close();
935 filterType = type;
936 if (!OpenSocket())
937 return FALSE;
940 #ifndef __BEOS__
941 ifreq ifr;
942 memset(&ifr, 0, sizeof(ifr));
943 strcpy(ifr.ifr_name, channelName);
944 if (!ConvertOSError(ioctl(os_handle, SIOCGIFFLAGS, &ifr)))
945 return FALSE;
947 if ((filter&FilterPromiscuous) != 0)
948 ifr.ifr_flags |= IFF_PROMISC;
949 else
950 ifr.ifr_flags &= ~IFF_PROMISC;
952 if (!ConvertOSError(ioctl(os_handle, SIOCSIFFLAGS, &ifr)))
953 return FALSE;
955 filterMask = filter;
957 return TRUE;
958 #else
959 return FALSE;
960 #endif //!__BEOS__
964 PEthSocket::MediumTypes PEthSocket::GetMedium()
966 return medium;
970 BOOL PEthSocket::ResetAdaptor()
972 // No implementation
973 return TRUE;
977 BOOL PEthSocket::Read(void * buf, PINDEX len)
979 static const BYTE macHeader[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 8, 0 };
981 BYTE * bufptr = (BYTE *)buf;
983 if (fakeMacHeader) {
984 if (len <= (PINDEX)sizeof(macHeader)) {
985 memcpy(bufptr, macHeader, len);
986 lastReadCount = len;
987 return TRUE;
990 memcpy(bufptr, macHeader, sizeof(macHeader));
991 bufptr += sizeof(macHeader);
992 len -= sizeof(macHeader);
995 for (;;) {
996 sockaddr from;
997 PINDEX fromlen = sizeof(from);
998 if (!os_recvfrom(bufptr, len, 0, &from, &fromlen))
999 return FALSE;
1001 if (channelName != from.sa_data)
1002 continue;
1004 if (ipppInterface) {
1005 if (lastReadCount <= 10)
1006 return FALSE;
1007 if (memcmp(bufptr+6, "\xff\x03\x00\x21", 4) != 0) {
1008 memmove(bufptr+sizeof(macHeader), bufptr, lastReadCount);
1009 lastReadCount += sizeof(macHeader);
1011 else {
1012 memmove(bufptr+sizeof(macHeader), bufptr+10, lastReadCount);
1013 lastReadCount += sizeof(macHeader)-10;
1015 memcpy(bufptr, macHeader, sizeof(macHeader));
1016 break;
1019 if (fakeMacHeader) {
1020 lastReadCount += sizeof(macHeader);
1021 break;
1024 if ((filterMask&FilterPromiscuous) != 0)
1025 break;
1027 if ((filterMask&FilterDirected) != 0 && macAddress == bufptr)
1028 break;
1030 static const Address broadcast;
1031 if ((filterMask&FilterBroadcast) != 0 && broadcast == bufptr)
1032 break;
1035 return lastReadCount > 0;
1039 BOOL PEthSocket::Write(const void * buf, PINDEX len)
1041 sockaddr to;
1042 strcpy((char *)to.sa_data, channelName);
1043 return os_sendto(buf, len, 0, &to, sizeof(to)) && lastWriteCount >= len;
1047 ///////////////////////////////////////////////////////////////////////////////
1049 BOOL PIPSocket::GetGatewayAddress(Address & addr)
1051 RouteTable table;
1052 if (GetRouteTable(table)) {
1053 for (PINDEX i = 0; i < table.GetSize(); i++) {
1054 if (table[i].GetNetwork() == 0) {
1055 addr = table[i].GetDestination();
1056 return TRUE;
1060 return FALSE;
1065 PString PIPSocket::GetGatewayInterface()
1067 RouteTable table;
1068 if (GetRouteTable(table)) {
1069 for (PINDEX i = 0; i < table.GetSize(); i++) {
1070 if (table[i].GetNetwork() == 0)
1071 return table[i].GetInterface();
1074 return PString();
1077 #if defined(P_LINUX) || defined (P_AIX)
1079 BOOL PIPSocket::GetRouteTable(RouteTable & table)
1082 PTextFile procfile;
1083 if (!procfile.Open("/proc/net/route", PFile::ReadOnly))
1084 return FALSE;
1086 for (;;) {
1087 // Ignore heading line or remainder of route line
1088 procfile.ignore(1000, '\n');
1089 if (procfile.eof())
1090 return TRUE;
1092 char iface[20];
1093 unsigned long net_addr, dest_addr, net_mask;
1094 int flags, refcnt, use, metric;
1095 procfile >> iface >> ::hex >> net_addr >> dest_addr >> flags
1096 >> ::dec >> refcnt >> use >> metric
1097 >> ::hex >> net_mask;
1098 if (procfile.bad())
1099 return FALSE;
1101 RouteEntry * entry = new RouteEntry(net_addr);
1102 entry->net_mask = net_mask;
1103 entry->destination = dest_addr;
1104 entry->interfaceName = iface;
1105 entry->metric = metric;
1106 table.Append(entry);
1110 #elif defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_QNX)
1112 BOOL process_rtentry(struct rt_msghdr *rtm, char *ptr, unsigned long *p_net_addr,
1113 unsigned long *p_net_mask, unsigned long *p_dest_addr, int *p_metric);
1114 BOOL get_ifname(int index, char *name);
1116 BOOL PIPSocket::GetRouteTable(RouteTable & table)
1118 int mib[6];
1119 size_t space_needed;
1120 char *limit, *buf, *ptr;
1121 struct rt_msghdr *rtm;
1123 InterfaceTable if_table;
1126 // Read the Routing Table
1127 mib[0] = CTL_NET;
1128 mib[1] = PF_ROUTE;
1129 mib[2] = 0;
1130 mib[3] = 0;
1131 mib[4] = NET_RT_DUMP;
1132 mib[5] = 0;
1134 if (sysctl(mib, 6, NULL, &space_needed, NULL, 0) < 0) {
1135 printf("sysctl: net.route.0.0.dump estimate");
1136 return FALSE;
1139 if ((buf = (char *)malloc(space_needed)) == NULL) {
1140 printf("malloc(%lu)", (unsigned long)space_needed);
1141 return FALSE;
1144 // read the routing table data
1145 if (sysctl(mib, 6, buf, &space_needed, NULL, 0) < 0) {
1146 printf("sysctl: net.route.0.0.dump");
1147 free(buf);
1148 return FALSE;
1152 // Read the interface table
1153 if (!GetInterfaceTable(if_table)) {
1154 printf("Interface Table Invalid\n");
1155 return FALSE;
1159 // Process the Routing Table data
1160 limit = buf + space_needed;
1161 for (ptr = buf; ptr < limit; ptr += rtm->rtm_msglen) {
1163 unsigned long net_addr, dest_addr, net_mask;
1164 int metric;
1165 char name[16];
1167 rtm = (struct rt_msghdr *)ptr;
1169 if ( process_rtentry(rtm,ptr, &net_addr, &net_mask, &dest_addr, &metric) ){
1171 RouteEntry * entry = new RouteEntry(net_addr);
1172 entry->net_mask = net_mask;
1173 entry->destination = dest_addr;
1174 if ( get_ifname(rtm->rtm_index,name) )
1175 entry->interfaceName = name;
1176 entry->metric = metric;
1177 table.Append(entry);
1179 } // end if
1181 } // end for loop
1183 free(buf);
1184 return TRUE;
1187 BOOL process_rtentry(struct rt_msghdr *rtm, char *ptr, unsigned long *p_net_addr,
1188 unsigned long *p_net_mask, unsigned long *p_dest_addr, int *p_metric) {
1190 struct sockaddr_in *sa_in;
1192 unsigned long net_addr, dest_addr, net_mask;
1193 int metric;
1195 sa_in = (struct sockaddr_in *)(rtm + 1);
1198 // Check for zero length entry
1199 if (rtm->rtm_msglen == 0) {
1200 printf("zero length message\n");
1201 return FALSE;
1204 if ((~rtm->rtm_flags&RTF_LLINFO)
1205 #if defined(P_NETBSD) || defined(P_QNX)
1206 && (~rtm->rtm_flags&RTF_CLONED) // Net BSD has flag one way
1207 #elif !defined(P_OPENBSD)
1208 && (~rtm->rtm_flags&RTF_WASCLONED) // Free BSD/MAC has it another
1209 #else
1210 // Open BSD does not have it at all!
1211 #endif
1214 //strcpy(name, if_table[rtm->rtm_index].GetName);
1216 net_addr=dest_addr=net_mask=metric=0;
1218 // NET_ADDR
1219 if(rtm->rtm_addrs&RTA_DST ) {
1220 if(sa_in->sin_family == AF_INET)
1221 net_addr = sa_in->sin_addr.s_addr;
1223 sa_in = (struct sockaddr_in *)((char *)sa_in + ROUNDUP(sa_in->sin_len));
1226 // DEST_ADDR
1227 if(rtm->rtm_addrs&RTA_GATEWAY) {
1228 if(sa_in->sin_family == AF_INET)
1229 dest_addr = sa_in->sin_addr.s_addr;
1231 sa_in = (struct sockaddr_in *)((char *)sa_in + ROUNDUP(sa_in->sin_len));
1234 // NETMASK
1235 if(rtm->rtm_addrs&RTA_NETMASK && sa_in->sin_len)
1236 net_mask = sa_in->sin_addr.s_addr;
1238 if( rtm->rtm_flags&RTF_HOST)
1239 net_mask = 0xffffffff;
1242 *p_metric = metric;
1243 *p_net_addr = net_addr;
1244 *p_dest_addr = dest_addr;
1245 *p_net_mask = net_mask;
1247 return TRUE;
1249 } else {
1250 return FALSE;
1255 BOOL get_ifname(int index, char *name) {
1256 int mib[6];
1257 size_t needed;
1258 char *lim, *buf, *next;
1259 struct if_msghdr *ifm;
1260 struct sockaddr_dl *sdl;
1262 mib[0] = CTL_NET;
1263 mib[1] = PF_ROUTE;
1264 mib[2] = 0;
1265 mib[3] = AF_INET;
1266 mib[4] = NET_RT_IFLIST;
1267 mib[5] = index;
1269 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
1270 printf("ERR route-sysctl-estimate");
1271 return FALSE;
1274 if ((buf = (char *)malloc(needed)) == NULL) {
1275 printf("ERR malloc");
1276 return FALSE;
1279 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
1280 printf("ERR actual retrieval of routing table");
1281 free(buf);
1282 return FALSE;
1285 lim = buf + needed;
1287 next = buf;
1288 if (next < lim) {
1290 ifm = (struct if_msghdr *)next;
1292 if (ifm->ifm_type == RTM_IFINFO) {
1293 sdl = (struct sockaddr_dl *)(ifm + 1);
1294 } else {
1295 printf("out of sync parsing NET_RT_IFLIST\n");
1296 return FALSE;
1298 next += ifm->ifm_msglen;
1300 strncpy(name, sdl->sdl_data, sdl->sdl_nlen);
1301 name[sdl->sdl_nlen] = '\0';
1303 free(buf);
1304 return TRUE;
1306 } else {
1307 free(buf);
1308 return FALSE;
1314 #elif defined(P_SOLARIS)
1316 /* jpd@louisiana.edu - influenced by Merit.edu's Gated 3.6 routine: krt_rtread_sunos5.c */
1318 #include <sys/stream.h>
1319 #include <stropts.h>
1320 #include <sys/tihdr.h>
1321 #include <sys/tiuser.h>
1322 #include <inet/common.h>
1323 #include <inet/mib2.h>
1324 #include <inet/ip.h>
1326 #ifndef T_CURRENT
1327 #define T_CURRENT MI_T_CURRENT
1328 #endif
1330 BOOL PIPSocket::GetRouteTable(RouteTable & table)
1332 #define task_pagesize 512
1333 char buf[task_pagesize]; /* = task_block_malloc(task_pagesize);*/
1334 int flags;
1335 int j = 0;
1336 int sd, i, rc;
1337 struct strbuf strbuf;
1338 struct T_optmgmt_req *tor = (struct T_optmgmt_req *) buf;
1339 struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *) buf;
1340 struct T_error_ack *tea = (struct T_error_ack *) buf;
1341 struct opthdr *req;
1343 sd = open("/dev/ip", O_RDWR);
1344 if (sd < 0) {
1345 #ifdef SOL_COMPLAIN
1346 perror("can't open mib stream");
1347 #endif
1348 goto Return;
1351 strbuf.buf = buf;
1353 tor->PRIM_type = T_OPTMGMT_REQ;
1354 tor->OPT_offset = sizeof(struct T_optmgmt_req);
1355 tor->OPT_length = sizeof(struct opthdr);
1356 tor->MGMT_flags = T_CURRENT;
1357 req = (struct opthdr *) (tor + 1);
1358 req->level = MIB2_IP; /* any MIB2_xxx value ok here */
1359 req->name = 0;
1360 req->len = 0;
1362 strbuf.len = tor->OPT_length + tor->OPT_offset;
1363 flags = 0;
1364 rc = putmsg(sd, &strbuf, (struct strbuf *) 0, flags);
1365 if (rc == -1) {
1366 #ifdef SOL_COMPLAIN
1367 perror("putmsg(ctl)");
1368 #endif
1369 goto Return;
1372 * each reply consists of a ctl part for one fixed structure
1373 * or table, as defined in mib2.h. The format is a T_OPTMGMT_ACK,
1374 * containing an opthdr structure. level/name identify the entry,
1375 * len is the size of the data part of the message.
1377 req = (struct opthdr *) (toa + 1);
1378 strbuf.maxlen = task_pagesize;
1379 while (++j) {
1380 flags = 0;
1381 rc = getmsg(sd, &strbuf, (struct strbuf *) 0, &flags);
1382 if (rc == -1) {
1383 #ifdef SOL_COMPLAIN
1384 perror("getmsg(ctl)");
1385 #endif
1386 goto Return;
1388 if (rc == 0
1389 && strbuf.len >= sizeof(struct T_optmgmt_ack)
1390 && toa->PRIM_type == T_OPTMGMT_ACK
1391 && toa->MGMT_flags == T_SUCCESS
1392 && req->len == 0) {
1393 errno = 0; /* just to be darned sure it's 0 */
1394 goto Return; /* this is EOD msg */
1397 if (strbuf.len >= sizeof(struct T_error_ack)
1398 && tea->PRIM_type == T_ERROR_ACK) {
1399 errno = (tea->TLI_error == TSYSERR) ? tea->UNIX_error : EPROTO;
1400 #ifdef SOL_COMPLAIN
1401 perror("T_ERROR_ACK in mibget");
1402 #endif
1403 goto Return;
1406 if (rc != MOREDATA
1407 || strbuf.len < sizeof(struct T_optmgmt_ack)
1408 || toa->PRIM_type != T_OPTMGMT_ACK
1409 || toa->MGMT_flags != T_SUCCESS) {
1410 errno = ENOMSG;
1411 goto Return;
1414 if (req->level != MIB2_IP
1415 #if P_SOLARIS > 7
1416 || req->name != MIB2_IP_ROUTE
1417 #endif
1418 ) { /* == 21 */
1419 /* If this is not the routing table, skip it */
1420 /* Note we don't bother with IPv6 (MIB2_IP6_ROUTE) ... */
1421 strbuf.maxlen = task_pagesize;
1422 do {
1423 rc = getmsg(sd, (struct strbuf *) 0, &strbuf, &flags);
1424 } while (rc == MOREDATA) ;
1425 continue;
1428 strbuf.maxlen = (task_pagesize / sizeof (mib2_ipRouteEntry_t)) * sizeof (mib2_ipRouteEntry_t);
1429 strbuf.len = 0;
1430 flags = 0;
1431 do {
1432 rc = getmsg(sd, (struct strbuf * ) 0, &strbuf, &flags);
1434 switch (rc) {
1435 case -1:
1436 #ifdef SOL_COMPLAIN
1437 perror("mibget getmsg(data) failed.");
1438 #endif
1439 goto Return;
1441 default:
1442 #ifdef SOL_COMPLAIN
1443 fprintf(stderr,"mibget getmsg(data) returned %d, strbuf.maxlen = %d, strbuf.len = %d",
1445 strbuf.maxlen,
1446 strbuf.len);
1447 #endif
1448 goto Return;
1450 case MOREDATA:
1451 case 0:
1453 mib2_ipRouteEntry_t *rp = (mib2_ipRouteEntry_t *) strbuf.buf;
1454 mib2_ipRouteEntry_t *lp = (mib2_ipRouteEntry_t *) (strbuf.buf + strbuf.len);
1456 do {
1457 char name[256];
1458 #ifdef SOL_DEBUG_RT
1459 printf("%s -> %s mask %s metric %d %d %d %d %d ifc %.*s type %d/%x/%x\n",
1460 inet_ntoa(rp->ipRouteDest),
1461 inet_ntoa(rp->ipRouteNextHop),
1462 inet_ntoa(rp->ipRouteMask),
1463 rp->ipRouteMetric1,
1464 rp->ipRouteMetric2,
1465 rp->ipRouteMetric3,
1466 rp->ipRouteMetric4,
1467 rp->ipRouteMetric5,
1468 rp->ipRouteIfIndex.o_length,
1469 rp->ipRouteIfIndex.o_bytes,
1470 rp->ipRouteType,
1471 rp->ipRouteInfo.re_ire_type,
1472 rp->ipRouteInfo.re_flags
1474 #endif
1475 if (rp->ipRouteInfo.re_ire_type & (IRE_BROADCAST|IRE_CACHE|IRE_LOCAL))
1476 continue;
1477 RouteEntry * entry = new RouteEntry(rp->ipRouteDest);
1478 entry->net_mask = rp->ipRouteMask;
1479 entry->destination = rp->ipRouteNextHop;
1480 unsigned len = rp->ipRouteIfIndex.o_length;
1481 if (len >= sizeof(name))
1482 len = sizeof(name)-1;
1483 strncpy(name, rp->ipRouteIfIndex.o_bytes, len);
1484 name[len] = '\0';
1485 entry->interfaceName = name;
1486 entry->metric = rp->ipRouteMetric1;
1487 table.Append(entry);
1488 } while (++rp < lp) ;
1490 break;
1492 } while (rc == MOREDATA) ;
1495 Return:
1496 i = errno;
1497 (void) close(sd);
1498 errno = i;
1499 /*task_block_reclaim(task_pagesize, buf);*/
1500 if (errno)
1501 return (FALSE);
1502 else
1503 return (TRUE);
1507 #elif defined(P_VXWORKS)
1509 BOOL PIPSocket::GetRouteTable(RouteTable & table)
1511 PAssertAlways("PIPSocket::GetRouteTable()");
1512 for(;;){
1513 char iface[20];
1514 unsigned long net_addr, dest_addr, net_mask;
1515 int metric;
1516 RouteEntry * entry = new RouteEntry(net_addr);
1517 entry->net_mask = net_mask;
1518 entry->destination = dest_addr;
1519 entry->interfaceName = iface;
1520 entry->metric = metric;
1521 table.Append(entry);
1522 return TRUE;
1526 #else // unsupported platform
1528 #if 0
1529 BOOL PIPSocket::GetRouteTable(RouteTable & table)
1531 // Most of this code came from the source code for the "route" command
1532 // so it should work on other platforms too.
1533 // However, it is not complete (the "address-for-interface" function doesn't exist) and not tested!
1535 route_table_req_t reqtable;
1536 route_req_t *rrtp;
1537 int i,ret;
1539 ret = get_route_table(&reqtable);
1540 if (ret < 0)
1542 return FALSE;
1545 for (i=reqtable.cnt, rrtp = reqtable.rrtp;i>0;i--, rrtp++)
1547 //the datalink doesn't save addresses/masks for host and default
1548 //routes, so the route_req_t may not be filled out completely
1549 if (rrtp->flags & RTF_DEFAULT) {
1550 //the IP default route is 0/0
1551 ((struct sockaddr_in *)&rrtp->dst)->sin_addr.s_addr = 0;
1552 ((struct sockaddr_in *)&rrtp->mask)->sin_addr.s_addr = 0;
1554 } else if (rrtp->flags & RTF_HOST) {
1555 //host routes are addr/32
1556 ((struct sockaddr_in *)&rrtp->mask)->sin_addr.s_addr = 0xffffffff;
1559 RouteEntry * entry = new RouteEntry(/* address_for_interface(rrtp->iface) */);
1560 entry->net_mask = rrtp->mask;
1561 entry->destination = rrtp->dst;
1562 entry->interfaceName = rrtp->iface;
1563 entry->metric = rrtp->refcnt;
1564 table.Append(entry);
1567 free(reqtable.rrtp);
1569 return TRUE;
1570 #endif // 0
1572 BOOL PIPSocket::GetRouteTable(RouteTable & table)
1574 #warning Platform requires implemetation of GetRouteTable()
1575 return FALSE;
1577 #endif
1580 BOOL PIPSocket::GetInterfaceTable(InterfaceTable & list)
1582 PUDPSocket sock;
1583 #ifndef __BEOS__
1585 PBYTEArray buffer;
1586 struct ifconf ifConf;
1588 #ifdef SIOCGIFNUM
1589 int ifNum;
1590 PAssert(::ioctl(sock.GetHandle(), SIOCGIFNUM, &ifNum) >= 0, "could not do ioctl for ifNum");
1591 ifConf.ifc_len = ifNum * sizeof(ifreq);
1592 #else
1593 ifConf.ifc_len = 100 * sizeof(ifreq); // That's a LOT of interfaces!
1594 #endif
1596 ifConf.ifc_req = (struct ifreq *)buffer.GetPointer(ifConf.ifc_len);
1598 if (ioctl(sock.GetHandle(), SIOCGIFCONF, &ifConf) >= 0) {
1599 void * ifEndList = (char *)ifConf.ifc_req + ifConf.ifc_len;
1600 ifreq * ifName = ifConf.ifc_req;
1601 while (ifName < ifEndList) {
1603 struct ifreq ifReq;
1604 strcpy(ifReq.ifr_name, ifName->ifr_name);
1606 if (ioctl(sock.GetHandle(), SIOCGIFFLAGS, &ifReq) >= 0) {
1607 int flags = ifReq.ifr_flags;
1608 if (flags & IFF_UP) {
1609 PString name(ifReq.ifr_name);
1611 PString macAddr;
1612 #if defined(SIO_Get_MAC_Address)
1613 if (ioctl(sock.GetHandle(), SIO_Get_MAC_Address, &ifReq) >= 0) {
1614 PEthSocket::Address a((BYTE *)ifReq.ifr_macaddr);
1615 macAddr = (PString)a;
1617 #endif
1619 if (ioctl(sock.GetHandle(), SIOCGIFADDR, &ifReq) >= 0) {
1620 PIPSocket::Address addr = ((sockaddr_in *)&ifReq.ifr_addr)->sin_addr;
1622 if (ioctl(sock.GetHandle(), SIOCGIFNETMASK, &ifReq) >= 0) {
1623 PIPSocket::Address mask = ((sockaddr_in *)&ifReq.ifr_netmask)->sin_addr;
1624 PINDEX i;
1625 for (i = 0; i < list.GetSize(); i++) {
1626 #ifdef P_TORNADO
1627 if (list[i].GetName() == name &&
1628 list[i].GetAddress() == addr)
1629 if(list[i].GetNetMask() == mask)
1630 #else
1631 if (list[i].GetName() == name &&
1632 list[i].GetAddress() == addr &&
1633 list[i].GetNetMask() == mask)
1634 #endif
1635 break;
1637 if (i >= list.GetSize())
1638 list.Append(PNEW InterfaceEntry(name, addr, mask, macAddr));
1644 #if defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_VXWORKS) || defined(P_RTEMS) || defined(P_QNX)
1645 // Define _SIZEOF_IFREQ for platforms (eg OpenBSD) which do not have it.
1646 #ifndef _SIZEOF_ADDR_IFREQ
1647 #define _SIZEOF_ADDR_IFREQ(ifr) \
1648 ((ifr).ifr_addr.sa_len > sizeof(struct sockaddr) ? \
1649 (sizeof(struct ifreq) - sizeof(struct sockaddr) + \
1650 (ifr).ifr_addr.sa_len) : sizeof(struct ifreq))
1651 #endif
1653 // move the ifName pointer along to the next ifreq entry
1654 ifName = (struct ifreq *)((char *)ifName + _SIZEOF_ADDR_IFREQ(*ifName));
1655 #else
1656 ifName++;
1657 #endif
1661 #endif //!__BEOS__
1662 return TRUE;
1665 #ifdef P_VXWORKS
1667 int h_errno;
1669 struct hostent * Vx_gethostbyname(char *name, struct hostent *hp)
1671 u_long addr;
1672 static char staticgethostname[100];
1674 hp->h_aliases = NULL;
1675 hp->h_addr_list[1] = NULL;
1676 if ((int)(addr = inet_addr(name)) != ERROR) {
1677 memcpy(staticgethostname, &addr, sizeof(addr));
1678 hp->h_addr_list[0] = staticgethostname;
1679 h_errno = SUCCESS;
1680 return hp;
1682 memcpy(staticgethostname, &addr, sizeof (addr));
1683 hp->h_addr_list[0] = staticgethostname;
1684 h_errno = SUCCESS;
1685 return hp;
1688 struct hostent * Vx_gethostbyaddr(char *name, struct hostent *hp)
1690 u_long addr;
1691 static char staticgethostaddr[100];
1693 hp->h_aliases = NULL;
1694 hp->h_addr_list = NULL;
1696 if ((int)(addr = inet_addr(name)) != ERROR) {
1697 sprintf(staticgethostaddr,"%s",inet_ntoa(addr));
1698 hp->h_name = staticgethostaddr;
1699 h_errno = SUCCESS;
1701 else
1703 printf ("_gethostbyaddr: not able to get %s\n",name);
1704 h_errno = NOTFOUND;
1706 return hp;
1709 #endif // P_VXWORKS
1712 #include "../common/pethsock.cxx"
1715 ///////////////////////////////////////////////////////////////////////////////