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.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
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
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
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
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
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
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"
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
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>
310 #include <netinet/if_ether.h>
314 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
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>
326 int PX_NewHandle(const char *, int);
329 //////////////////////////////////////////////////////////////////////////////
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()
342 memset(set
, 0, (max_fd
+7)>>3);
346 //////////////////////////////////////////////////////////////////////////////
353 int PSocket::os_close()
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
);
367 int retval
= ::closesocket(os_handle
);
376 static int SetNonBlocking(int fd
)
378 #if defined __BEOS__ || defined(P_VXWORKS)
384 // Set non-blocking so we can use select calls to break I/O block on close
386 if (::ioctl(fd
, FIONBIO
, &cmd
) == 0 && ::fcntl(fd
, F_SETFD
, 1) == 0)
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
))
412 // A successful select() call does not necessarily mean the socket connected OK.
414 socklen_t optlen
= sizeof(optval
);
415 getsockopt(os_handle
, SOL_SOCKET
, SO_ERROR
, (char *)&optval
, &optlen
);
418 return ConvertOSError(-1);
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());
433 int new_fd
= ::accept(listener
.GetHandle(), addr
, (socklen_t
*)size
);
435 return ConvertOSError(os_handle
= SetNonBlocking(new_fd
));
438 return ConvertOSError(-1);
440 PTRACE(3, "PWLib\tAccept on " << sock
<< " failed with EPROTO - retrying");
443 return ConvertOSError(os_handle
= SetNonBlocking(::accept(listener
.GetHandle(), addr
, (socklen_t
*)size
)));
448 #if !defined(P_PTHREADS) && !defined(P_MAC_MPTHREADS)
450 int PSocket::os_select(int maxHandle
,
453 fd_set
* exceptionBits
,
454 const PIntArray
& osHandles
,
455 const PTimeInterval
& timeout
)
457 int stat
= PThread::Current()->PXBlockOnIO(maxHandle
,
467 return ::select(maxHandle
, readBits
, writeBits
, exceptionBits
, instant
);
472 int PSocket::os_select(int width
,
475 fd_set
* exceptionBits
,
477 const PTimeInterval
& timeout
)
479 int unblockPipe
= PThread::Current()->unblockPipe
[0];
480 FD_SET(unblockPipe
, readBits
);
481 width
= PMAX(width
, unblockPipe
+1);
484 P_timeval tval
= timeout
;
485 int result
= ::select(width
, readBits
, writeBits
, exceptionBits
, tval
);
487 if (FD_ISSET(unblockPipe
, readBits
)) {
488 FD_CLR(unblockPipe
, readBits
);
491 ::read(unblockPipe
, &ch
, 1);
492 FD_CLR(unblockPipe
, readBits
);
499 } while (errno
== EINTR
);
506 PIPSocket::Address::Address(DWORD dw
)
512 PIPSocket::Address
& PIPSocket::Address::operator=(DWORD dw
)
516 memset(&v
, 0, sizeof(v
));
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
)
555 BYTE
* p
= (BYTE
*)&v
.four
.s_addr
;
562 BOOL
PIPSocket::IsLocalHost(const PString
& hostname
)
564 if (hostname
.IsEmpty())
567 if (hostname
*= "localhost")
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
577 if (!GetHostAddress(hostname
, addr
))
583 // get number of interfaces
586 PAssert(::ioctl(sock
.GetHandle(), SIOCGIFNUM
, &ifNum
) >= 0, "could not do ioctl for ifNum");
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) {
598 ifNum
= ifConf
.ifc_len
/ sizeof(ifreq
);
602 for (num
= 0; num
< ifNum
; num
++) {
604 ifreq
* ifName
= ifConf
.ifc_req
+ num
;
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
)))
623 ////////////////////////////////////////////////////////////////
627 BOOL
PTCPSocket::Read(void * buf
, PINDEX maxLen
)
632 // wait until select indicates there is data to read, or until
634 if (!PXSetIOBlock(PXReadBlock
, readTimeout
))
638 // attempt to read out of band data
641 while ((ooblen
= ::recv(os_handle
, buffer
, sizeof(buffer
), MSG_OOB
)) > 0)
642 OnOutOfBand(buffer
, ooblen
);
645 // attempt to read non-out of band data
646 int r
= ::recv(os_handle
, (char *)buf
, maxLen
, 0);
647 if (!ConvertOSError(r
, LastReadError
))
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>.
659 sockaddr
* addr
, // Address from which the datagram was received.
664 if (!PXSetIOBlock(PXReadBlock
, readTimeout
))
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
))
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>.
681 sockaddr
* addr
, // Address to which the datagram is sent.
687 return SetErrorValues(NotOpen
, EBADF
, LastWriteError
);
689 // attempt to read data
693 result
= ::sendto(os_handle
, (char *)buf
, len
, flags
, (sockaddr
*)addr
, addrlen
);
695 result
= ::send(os_handle
, (char *)buf
, len
, flags
);
700 if (errno
!= EWOULDBLOCK
)
701 return ConvertOSError(-1, LastWriteError
);
703 if (!PXSetIOBlock(PXWriteBlock
, writeTimeout
))
707 #if !defined(P_PTHREADS) && !defined(P_MAC_MPTHREADS)
708 PThread::Yield(); // Starvation prevention
711 lastWriteCount
= result
;
712 return ConvertOSError(0, LastWriteError
);
716 BOOL
PSocket::Read(void * buf
, PINDEX len
)
719 return SetErrorValues(NotOpen
, EBADF
, LastReadError
);
721 if (!PXSetIOBlock(PXReadBlock
, readTimeout
))
724 if (ConvertOSError(lastReadCount
= ::recv(os_handle
, (char *)buf
, len
, 0)))
725 return lastReadCount
> 0;
733 //////////////////////////////////////////////////////////////////
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()
754 BOOL
PEthSocket::Connect(const PString
& interfaceName
)
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)
765 else if (strncmp("sl", interfaceName
, 2) == 0) {
767 fakeMacHeader
= TRUE
;
769 else if (strncmp("ppp", interfaceName
, 3) == 0) {
771 fakeMacHeader
= TRUE
;
773 else if (strncmp("ippp", interfaceName
, 4) == 0) {
775 ipppInterface
= TRUE
;
778 else if (strncmp(RTEMS_BSP_NETWORK_DRIVER_NAME
, interfaceName
, 3) == 0)
779 medium
= Medium802_3
;
782 return SetErrorValues(NotFound
, ENOENT
);
784 #if defined(SIO_Get_MAC_Address) && !defined(__BEOS__)
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
)))
792 memcpy(&macAddress
, ifr
.ifr_macaddr
, sizeof(macAddress
));
795 channelName
= interfaceName
;
800 BOOL
PEthSocket::OpenSocket()
803 if (!ConvertOSError(os_handle
= os_socket(AF_INET
, SOCK_PACKET
, htons(filterType
))))
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
)))) {
821 BOOL
PEthSocket::Close()
823 SetFilter(FilterDirected
, filterType
); // Turn off promiscuous mode
824 return PSocket::Close();
828 BOOL
PEthSocket::EnumInterfaces(PINDEX idx
, PString
& name
)
833 ifreq ifreqs
[20]; // Maximum of 20 interfaces
835 ifc
.ifc_len
= sizeof(ifreqs
);
836 ifc
.ifc_buf
= (caddr_t
)ifreqs
;
837 if (!ConvertOSError(ioctl(ifsock
.GetHandle(), SIOCGIFCONF
, &ifc
)))
840 int ifcount
= ifc
.ifc_len
/sizeof(ifreq
);
842 for (ifidx
= 0; ifidx
< ifcount
; ifidx
++) {
843 if (strchr(ifreqs
[ifidx
].ifr_name
, ':') == NULL
) {
845 strcpy(ifr
.ifr_name
, ifreqs
[ifidx
].ifr_name
);
846 if (ioctl(ifsock
.GetHandle(), SIOCGIFFLAGS
, &ifr
) == 0 &&
847 (ifr
.ifr_flags
& IFF_UP
) != 0 &&
849 name
= ifreqs
[ifidx
].ifr_name
;
860 BOOL
PEthSocket::GetAddress(Address
& addr
)
870 BOOL
PEthSocket::EnumIpAddress(PINDEX idx
,
871 PIPSocket::Address
& addr
,
872 PIPSocket::Address
& net_mask
)
880 ifr
.ifr_addr
.sa_family
= AF_INET
;
882 strcpy(ifr
.ifr_name
, channelName
);
884 sprintf(ifr
.ifr_name
, "%s:%u", (const char *)channelName
, (int)(idx
-1));
885 if (!ConvertOSError(ioctl(os_handle
, SIOCGIFADDR
, &ifr
)))
888 sockaddr_in
*sin
= (struct sockaddr_in
*)&ifr
.ifr_addr
;
889 addr
= sin
->sin_addr
;
891 if (!ConvertOSError(ioctl(os_handle
, SIOCGIFNETMASK
, &ifr
)))
894 net_mask
= sin
->sin_addr
;
902 BOOL
PEthSocket::GetFilter(unsigned & mask
, WORD
& type
)
909 memset(&ifr
, 0, sizeof(ifr
));
910 strcpy(ifr
.ifr_name
, channelName
);
911 if (!ConvertOSError(ioctl(os_handle
, SIOCGIFFLAGS
, &ifr
)))
914 if ((ifr
.ifr_flags
&IFF_PROMISC
) != 0)
915 filterMask
|= FilterPromiscuous
;
917 filterMask
&= ~FilterPromiscuous
;
928 BOOL
PEthSocket::SetFilter(unsigned filter
, WORD type
)
933 if (filterType
!= type
) {
942 memset(&ifr
, 0, sizeof(ifr
));
943 strcpy(ifr
.ifr_name
, channelName
);
944 if (!ConvertOSError(ioctl(os_handle
, SIOCGIFFLAGS
, &ifr
)))
947 if ((filter
&FilterPromiscuous
) != 0)
948 ifr
.ifr_flags
|= IFF_PROMISC
;
950 ifr
.ifr_flags
&= ~IFF_PROMISC
;
952 if (!ConvertOSError(ioctl(os_handle
, SIOCSIFFLAGS
, &ifr
)))
964 PEthSocket::MediumTypes
PEthSocket::GetMedium()
970 BOOL
PEthSocket::ResetAdaptor()
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
;
984 if (len
<= (PINDEX
)sizeof(macHeader
)) {
985 memcpy(bufptr
, macHeader
, len
);
990 memcpy(bufptr
, macHeader
, sizeof(macHeader
));
991 bufptr
+= sizeof(macHeader
);
992 len
-= sizeof(macHeader
);
997 PINDEX fromlen
= sizeof(from
);
998 if (!os_recvfrom(bufptr
, len
, 0, &from
, &fromlen
))
1001 if (channelName
!= from
.sa_data
)
1004 if (ipppInterface
) {
1005 if (lastReadCount
<= 10)
1007 if (memcmp(bufptr
+6, "\xff\x03\x00\x21", 4) != 0) {
1008 memmove(bufptr
+sizeof(macHeader
), bufptr
, lastReadCount
);
1009 lastReadCount
+= sizeof(macHeader
);
1012 memmove(bufptr
+sizeof(macHeader
), bufptr
+10, lastReadCount
);
1013 lastReadCount
+= sizeof(macHeader
)-10;
1015 memcpy(bufptr
, macHeader
, sizeof(macHeader
));
1019 if (fakeMacHeader
) {
1020 lastReadCount
+= sizeof(macHeader
);
1024 if ((filterMask
&FilterPromiscuous
) != 0)
1027 if ((filterMask
&FilterDirected
) != 0 && macAddress
== bufptr
)
1030 static const Address broadcast
;
1031 if ((filterMask
&FilterBroadcast
) != 0 && broadcast
== bufptr
)
1035 return lastReadCount
> 0;
1039 BOOL
PEthSocket::Write(const void * buf
, PINDEX len
)
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
)
1052 if (GetRouteTable(table
)) {
1053 for (PINDEX i
= 0; i
< table
.GetSize(); i
++) {
1054 if (table
[i
].GetNetwork() == 0) {
1055 addr
= table
[i
].GetDestination();
1065 PString
PIPSocket::GetGatewayInterface()
1068 if (GetRouteTable(table
)) {
1069 for (PINDEX i
= 0; i
< table
.GetSize(); i
++) {
1070 if (table
[i
].GetNetwork() == 0)
1071 return table
[i
].GetInterface();
1077 #if defined(P_LINUX) || defined (P_AIX)
1079 BOOL
PIPSocket::GetRouteTable(RouteTable
& table
)
1083 if (!procfile
.Open("/proc/net/route", PFile::ReadOnly
))
1087 // Ignore heading line or remainder of route line
1088 procfile
.ignore(1000, '\n');
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
;
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
)
1119 size_t space_needed
;
1120 char *limit
, *buf
, *ptr
;
1121 struct rt_msghdr
*rtm
;
1123 InterfaceTable if_table
;
1126 // Read the Routing Table
1131 mib
[4] = NET_RT_DUMP
;
1134 if (sysctl(mib
, 6, NULL
, &space_needed
, NULL
, 0) < 0) {
1135 printf("sysctl: net.route.0.0.dump estimate");
1139 if ((buf
= (char *)malloc(space_needed
)) == NULL
) {
1140 printf("malloc(%lu)", (unsigned long)space_needed
);
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");
1152 // Read the interface table
1153 if (!GetInterfaceTable(if_table
)) {
1154 printf("Interface Table Invalid\n");
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
;
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
);
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
;
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");
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
1210 // Open BSD does not have it at all!
1214 //strcpy(name, if_table[rtm->rtm_index].GetName);
1216 net_addr
=dest_addr
=net_mask
=metric
=0;
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
));
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
));
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;
1243 *p_net_addr
= net_addr
;
1244 *p_dest_addr
= dest_addr
;
1245 *p_net_mask
= net_mask
;
1255 BOOL
get_ifname(int index
, char *name
) {
1258 char *lim
, *buf
, *next
;
1259 struct if_msghdr
*ifm
;
1260 struct sockaddr_dl
*sdl
;
1266 mib
[4] = NET_RT_IFLIST
;
1269 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0) {
1270 printf("ERR route-sysctl-estimate");
1274 if ((buf
= (char *)malloc(needed
)) == NULL
) {
1275 printf("ERR malloc");
1279 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0) {
1280 printf("ERR actual retrieval of routing table");
1290 ifm
= (struct if_msghdr
*)next
;
1292 if (ifm
->ifm_type
== RTM_IFINFO
) {
1293 sdl
= (struct sockaddr_dl
*)(ifm
+ 1);
1295 printf("out of sync parsing NET_RT_IFLIST\n");
1298 next
+= ifm
->ifm_msglen
;
1300 strncpy(name
, sdl
->sdl_data
, sdl
->sdl_nlen
);
1301 name
[sdl
->sdl_nlen
] = '\0';
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>
1327 #define T_CURRENT MI_T_CURRENT
1330 BOOL
PIPSocket::GetRouteTable(RouteTable
& table
)
1332 #define task_pagesize 512
1333 char buf
[task_pagesize
]; /* = task_block_malloc(task_pagesize);*/
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
;
1343 sd
= open("/dev/ip", O_RDWR
);
1346 perror("can't open mib stream");
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 */
1362 strbuf
.len
= tor
->OPT_length
+ tor
->OPT_offset
;
1364 rc
= putmsg(sd
, &strbuf
, (struct strbuf
*) 0, flags
);
1367 perror("putmsg(ctl)");
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
;
1381 rc
= getmsg(sd
, &strbuf
, (struct strbuf
*) 0, &flags
);
1384 perror("getmsg(ctl)");
1389 && strbuf
.len
>= sizeof(struct T_optmgmt_ack
)
1390 && toa
->PRIM_type
== T_OPTMGMT_ACK
1391 && toa
->MGMT_flags
== T_SUCCESS
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
;
1401 perror("T_ERROR_ACK in mibget");
1407 || strbuf
.len
< sizeof(struct T_optmgmt_ack
)
1408 || toa
->PRIM_type
!= T_OPTMGMT_ACK
1409 || toa
->MGMT_flags
!= T_SUCCESS
) {
1414 if (req
->level
!= MIB2_IP
1416 || req
->name
!= MIB2_IP_ROUTE
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
;
1423 rc
= getmsg(sd
, (struct strbuf
*) 0, &strbuf
, &flags
);
1424 } while (rc
== MOREDATA
) ;
1428 strbuf
.maxlen
= (task_pagesize
/ sizeof (mib2_ipRouteEntry_t
)) * sizeof (mib2_ipRouteEntry_t
);
1432 rc
= getmsg(sd
, (struct strbuf
* ) 0, &strbuf
, &flags
);
1437 perror("mibget getmsg(data) failed.");
1443 fprintf(stderr
,"mibget getmsg(data) returned %d, strbuf.maxlen = %d, strbuf.len = %d",
1453 mib2_ipRouteEntry_t
*rp
= (mib2_ipRouteEntry_t
*) strbuf
.buf
;
1454 mib2_ipRouteEntry_t
*lp
= (mib2_ipRouteEntry_t
*) (strbuf
.buf
+ strbuf
.len
);
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
),
1468 rp
->ipRouteIfIndex
.o_length
,
1469 rp
->ipRouteIfIndex
.o_bytes
,
1471 rp
->ipRouteInfo
.re_ire_type
,
1472 rp
->ipRouteInfo
.re_flags
1475 if (rp
->ipRouteInfo
.re_ire_type
& (IRE_BROADCAST
|IRE_CACHE
|IRE_LOCAL
))
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
);
1485 entry
->interfaceName
= name
;
1486 entry
->metric
= rp
->ipRouteMetric1
;
1487 table
.Append(entry
);
1488 } while (++rp
< lp
) ;
1492 } while (rc
== MOREDATA
) ;
1499 /*task_block_reclaim(task_pagesize, buf);*/
1507 #elif defined(P_VXWORKS)
1509 BOOL
PIPSocket::GetRouteTable(RouteTable
& table
)
1511 PAssertAlways("PIPSocket::GetRouteTable()");
1514 unsigned long net_addr
, dest_addr
, net_mask
;
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
);
1526 #else // unsupported platform
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
;
1539 ret
= get_route_table(&reqtable
);
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
);
1572 BOOL
PIPSocket::GetRouteTable(RouteTable
& table
)
1574 #warning Platform requires implemetation of GetRouteTable()
1580 BOOL
PIPSocket::GetInterfaceTable(InterfaceTable
& list
)
1586 struct ifconf ifConf
;
1590 PAssert(::ioctl(sock
.GetHandle(), SIOCGIFNUM
, &ifNum
) >= 0, "could not do ioctl for ifNum");
1591 ifConf
.ifc_len
= ifNum
* sizeof(ifreq
);
1593 ifConf
.ifc_len
= 100 * sizeof(ifreq
); // That's a LOT of interfaces!
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
) {
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
);
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
;
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
;
1625 for (i
= 0; i
< list
.GetSize(); i
++) {
1627 if (list
[i
].GetName() == name
&&
1628 list
[i
].GetAddress() == addr
)
1629 if(list
[i
].GetNetMask() == mask
)
1631 if (list
[i
].GetName() == name
&&
1632 list
[i
].GetAddress() == addr
&&
1633 list
[i
].GetNetMask() == mask
)
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))
1653 // move the ifName pointer along to the next ifreq entry
1654 ifName
= (struct ifreq
*)((char *)ifName
+ _SIZEOF_ADDR_IFREQ(*ifName
));
1669 struct hostent
* Vx_gethostbyname(char *name
, struct hostent
*hp
)
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
;
1682 memcpy(staticgethostname
, &addr
, sizeof (addr
));
1683 hp
->h_addr_list
[0] = staticgethostname
;
1688 struct hostent
* Vx_gethostbyaddr(char *name
, struct hostent
*hp
)
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
;
1703 printf ("_gethostbyaddr: not able to get %s\n",name
);
1712 #include "../common/pethsock.cxx"
1715 ///////////////////////////////////////////////////////////////////////////////