2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
5 * Device-independent and device-specific hardware/protocol address
6 * classes that can store themselves efficiently as well as create a
7 * printable string version of themselves.
11 #include <sys/socket.h>
14 #include <sys/types.h>
16 #include <net/if_arp.h>
24 #define ARPHRD_IPSEC 31
27 // workaround for functions called sockaddr() -- oops.
28 typedef struct sockaddr sockaddr_bin
;
30 /* A list of Linux ARPHRD_* types, one for each element of CapType. */
31 int WvEncap::extypes
[] = {
33 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
35 // hardware encapsulation
46 // protocol encapsulation
48 AF_UNIX
// Unix domain socket
53 /* Printable strings corresponding to each element of CapType */
54 const char WvEncap::strings
[][20] = {
55 // hardware encapsulation
66 // protocol encapsulation
68 "Unix", // Unix domain socket
72 /* Figure out the CapType corresponding to a Linux ARPHRD_* type or
73 * sockaddr sa_family type.
75 WvEncap::WvEncap(int extype
)
77 for (int count
=0; count
< NUM_ENCAP_TYPES
; count
++)
79 if (extype
== extypes
[count
])
89 /* Find the hash value of a WvAddr, for use with WvHashTable */
90 unsigned WvHash(const WvAddr
&addr
)
96 /* Create an object of the appropriate WvAddr-derived class based on the
97 * address and type stored in 'addr'.
99 WvAddr
*WvAddr::gen(struct sockaddr
*addr
)
101 WvEncap
encap(addr
->sa_family
);
105 case WvEncap::Loopback
:
106 return new WvStringAddr("Loopback", WvEncap::Loopback
);
109 return new WvIPPortAddr((sockaddr_in
*)addr
);
111 case WvEncap::ARCnet
:
112 return new WvARCnetAddr(addr
);
114 case WvEncap::Ethertap
:
115 case WvEncap::Ethernet
:
116 return new WvEtherAddr(addr
);
119 return new WvStringAddr("IPsec", WvEncap::IPsec
);
122 return new WvStringAddr("Unknown", WvEncap::Unknown
);
127 bool WvAddr::isbroadcast() const
129 return false; // default is no support for broadcasts
133 const unsigned char *WvAddr::rawdata() const
139 size_t WvAddr::rawdata_len() const
145 unsigned WvAddr::WvHash() const
148 const unsigned char *cptr
, *raw
= rawdata();
149 int len
= rawdata_len(), width
;
151 if (!raw
|| !len
) return 0;
152 width
= (sizeof(hash
)*8 / len
) + 1;
154 for (cptr
= raw
; len
; len
--)
155 hash
= (hash
<< width
) ^ *(cptr
++);
160 bool WvAddr::comparator(const WvAddr
*a2
, bool first_pass
) const
162 if (type() != a2
->type()) return false;
164 const unsigned char *raw1
, *raw2
;
168 if (len
!= a2
->rawdata_len())
172 raw2
= a2
->rawdata();
174 if (!raw1
&& !raw2
) return true;
175 if (!raw1
|| !raw2
) return false;
177 return !memcmp(raw1
, raw2
, len
);
181 WvStringAddr::WvStringAddr(WvStringParm s
, const WvEncap
&_cap
)
187 WvStringAddr::WvStringAddr(const struct sockaddr
*_addr
)
188 : addr((char *)_addr
->sa_data
), cap(_addr
->sa_family
)
193 WvStringAddr::~WvStringAddr()
199 WvEncap
WvStringAddr::encap() const
205 const unsigned char *WvStringAddr::rawdata() const
207 return (const unsigned char *)(const char *)addr
;
211 size_t WvStringAddr::rawdata_len() const
217 sockaddr_bin
*WvStringAddr::sockaddr() const
219 sockaddr_bin
*sa
= new sockaddr_bin
;
220 memset(sa
, 0, sizeof(*sa
));
221 strncpy(sa
->sa_data
, addr
, sizeof(sa
->sa_data
));
226 size_t WvStringAddr::sockaddr_len() const
228 return sizeof(sockaddr_bin
);
232 WvString
WvStringAddr::printable() const
239 /* create a WvEtherAddr from a printable string in the format:
240 * AA:BB:CC:DD:EE:FF (six hex numbers, separated by colons)
242 void WvEtherAddr::string_init(char const string
[])
245 unsigned char *cptr
= binaddr
;
247 memset(binaddr
, 0, ETHER_ADDR_LEN
);
248 for (unsigned int count
=0; count
< ETHER_ADDR_LEN
; count
++)
250 *cptr
++ = strtoul(endptr
? endptr
: string
, &endptr
, 16);
251 if (!endptr
|| !*endptr
|| endptr
==string
) break;
257 WvEtherAddr::~WvEtherAddr()
263 /* Generate a printable version of an ethernet address. */
264 WvString
WvEtherAddr::printable() const
266 char s
[ETHER_ADDR_LEN
*3], *cptr
= s
;
268 for (unsigned int count
= 0; count
< ETHER_ADDR_LEN
; count
++)
272 sprintf(cptr
, "%02X", binaddr
[count
]);
277 return WvString("%s", s
); // create a dynamic WvString
281 WvEncap
WvEtherAddr::encap() const
283 return WvEncap(WvEncap::Ethernet
);
287 // FF:FF:FF:FF:FF:FF is the ethernet broadcast address.
288 bool WvEtherAddr::isbroadcast() const
290 for (unsigned int count
= 0; count
< ETHER_ADDR_LEN
; count
++)
291 if (binaddr
[count
] != 0xFF)
297 const unsigned char *WvEtherAddr::rawdata() const
303 size_t WvEtherAddr::rawdata_len() const
305 return ETHER_ADDR_LEN
;
309 sockaddr_bin
*WvEtherAddr::sockaddr() const
311 sockaddr_bin
*sa
= new sockaddr_bin
;
312 memset(sa
, 0, sizeof(*sa
));
313 sa
->sa_family
= ARPHRD_ETHER
;
314 memcpy(sa
->sa_data
, binaddr
, ETHER_ADDR_LEN
);
319 size_t WvEtherAddr::sockaddr_len() const
321 return sizeof(sockaddr_bin
);
325 WvARCnetAddr::~WvARCnetAddr()
331 WvString
WvARCnetAddr::printable() const
334 sprintf(s
.edit(), "%02X", binaddr
);
339 WvEncap
WvARCnetAddr::encap() const
341 return WvEncap(WvEncap::ARCnet
);
345 const unsigned char *WvARCnetAddr::rawdata() const
351 size_t WvARCnetAddr::rawdata_len() const
357 sockaddr_bin
*WvARCnetAddr::sockaddr() const
359 sockaddr_bin
*sa
= new sockaddr_bin
;
360 memset(sa
, 0, sizeof(*sa
));
361 sa
->sa_family
= ARPHRD_ARCNET
;
362 sa
->sa_data
[0] = binaddr
;
367 size_t WvARCnetAddr::sockaddr_len() const
369 return sizeof(sockaddr_bin
);
374 /* create an IP address from a dotted-quad string. We don't support
375 * gethostname()-style lookups here, because they happen only synchronously.
376 * Streams that need hostname lookups will have to do it themselves.
378 void WvIPAddr::string_init(const char string
[])
380 const char *iptr
, *nptr
;
381 unsigned char *cptr
= binaddr
;
383 memset(binaddr
, 0, 4);
385 for (int count
=0; count
< 4 && nptr
; count
++)
388 nptr
= strchr(iptr
, '.');
390 *cptr
++ = strtol(iptr
, NULL
, 10);
395 WvIPAddr::~WvIPAddr()
400 bool WvIPAddr::comparator(const WvAddr
*a2
, bool first_pass
) const
402 if (a2
->type() == WVIPADDR
)
403 return !memcmp(binaddr
, ((WvIPAddr
*)a2
)->binaddr
, sizeof(binaddr
));
405 return a2
->comparator(this, false);
408 const unsigned char *raw1
, *raw2
;
412 if (len
!= a2
->rawdata_len())
416 raw2
= a2
->rawdata();
418 if (!raw1
&& !raw2
) return true;
419 if (!raw1
|| !raw2
) return false;
421 return !memcmp(raw1
, raw2
, len
);
426 /* Generate a printable version of an IP address. */
427 WvString
WvIPAddr::printable() const
429 return WvString("%s.%s.%s.%s",
430 binaddr
[0], binaddr
[1], binaddr
[2], binaddr
[3]);
434 /* AND two IP addresses together (handle netmasks) */
435 WvIPAddr
WvIPAddr::operator& (const WvIPAddr
&a2
) const
437 unsigned char obin
[4];
439 for (int count
=0; count
<4; count
++)
440 obin
[count
] = binaddr
[count
] & a2
.binaddr
[count
];
441 return WvIPAddr(obin
);
445 /* OR two IP addresses together (for broadcasts, etc) */
446 WvIPAddr
WvIPAddr::operator| (const WvIPAddr
&a2
) const
448 unsigned char obin
[4];
450 for (int count
=0; count
<4; count
++)
451 obin
[count
] = binaddr
[count
] | a2
.binaddr
[count
];
452 return WvIPAddr(obin
);
456 /* XOR two IP addresses together (for binary operations) */
457 WvIPAddr
WvIPAddr::operator^ (const WvIPAddr
&a2
) const
459 unsigned char obin
[4];
461 for (int count
=0; count
<4; count
++)
462 obin
[count
] = binaddr
[count
] ^ a2
.binaddr
[count
];
463 return WvIPAddr(obin
);
467 /* invert all the bits of an IP address (for useful binary operations) */
468 WvIPAddr
WvIPAddr::operator~ () const
470 unsigned char obin
[4];
472 for (int count
=0; count
<4; count
++)
473 obin
[count
] = ~binaddr
[count
];
474 return WvIPAddr(obin
);
478 /* add an integer value to an IP address:
479 * eg. 192.168.42.255 + 1 == 192.168.43.0
481 WvIPAddr
WvIPAddr::operator+ (int n
) const
483 uint32_t newad
= htonl(ntohl(addr()) + n
);
484 return WvIPAddr((unsigned char *)&newad
);
488 WvIPAddr
WvIPAddr::operator- (int n
) const
490 uint32_t newad
= htonl(ntohl(addr()) - n
);
491 return WvIPAddr((unsigned char *)&newad
);
495 WvEncap
WvIPAddr::encap() const
497 return WvEncap(WvEncap::IPv4
);
501 const unsigned char *WvIPAddr::rawdata() const
507 size_t WvIPAddr::rawdata_len() const
513 /* Generate a struct sockaddr (suitable for sendto()) from this IP
514 * address. Don't forget to delete it after you're done!
516 sockaddr_bin
*WvIPAddr::sockaddr() const
518 sockaddr_in
*sin
= new sockaddr_in
;
520 memset(sin
, 0, sizeof(*sin
));
521 sin
->sin_family
= AF_INET
;
522 sin
->sin_addr
.s_addr
= addr();
524 return (sockaddr_bin
*)sin
;
528 size_t WvIPAddr::sockaddr_len() const
530 return sizeof(sockaddr_in
);
534 WvIPNet::WvIPNet() { }
537 WvIPNet::WvIPNet(const WvIPNet
&_net
)
538 : WvIPAddr(_net
), mask(_net
.netmask()) { }
541 // If the netmask is not specified, it will default to all 1's.
542 void WvIPNet::string_init(const char string
[])
548 maskptr
= strchr(string
, '/');
551 mask
= WvIPAddr("255.255.255.255");
557 if (strchr(maskptr
, '.'))
558 mask
= WvIPAddr(maskptr
);
561 bits
= atoi(maskptr
);
563 imask
= htonl(~(((uint32_t)1 << (32-bits
)) - 1)); // see below
566 mask
= WvIPAddr((unsigned char *)&imask
);
571 WvIPNet::WvIPNet(const WvIPAddr
&base
, const WvIPAddr
&_mask
)
572 : WvIPAddr(base
), mask(_mask
) { }
575 WvIPNet::WvIPNet(const WvIPAddr
&base
, int bits
)
579 if (bits
> 0) // <<32 is a bad idea!
580 imask
= htonl(~(((uint32_t)1 << (32-bits
)) - 1));
583 mask
= WvIPAddr((unsigned char *)&imask
);
592 WvString
WvIPNet::printable() const
595 return WvString("%s/%s", network(), bits());
597 return WvIPAddr::printable();
601 unsigned WvIPNet::WvHash() const
603 return WvIPAddr::WvHash() + mask
.WvHash();
607 bool WvIPNet::comparator(const WvAddr
*a2
, bool first_pass
) const
609 if (a2
->type() == WVIPNET
)
610 return WvIPAddr::comparator(a2
, false) && mask
== ((WvIPNet
*)a2
)->mask
;
612 return a2
->comparator(this, false);
614 return WvIPAddr::comparator(a2
, false);
619 void WvIPNet::include(const WvIPNet
&addr
)
621 mask
= mask
& addr
.mask
& ~(*this ^ addr
);
625 bool WvIPNet::includes(const WvIPNet
&addr
) const
627 return (addr
.base() & netmask()) == network() &&
628 (addr
.netmask() & netmask()) == netmask();
632 int WvIPNet::bits() const
635 uint32_t val
= ntohl(mask
.addr());
640 } while ((val
<<= 1) & (1 << 31));
646 void WvIPNet::normalize()
650 uint32_t val
= htonl(~(((uint32_t)1 << (32-bits())) - 1));
651 mask
= WvIPAddr((unsigned char *)&val
);
654 mask
= WvIPAddr(); // empty netmask
658 WvIPPortAddr::WvIPPortAddr()
664 WvIPPortAddr::WvIPPortAddr(const WvIPAddr
&_ipaddr
, uint16_t _port
)
671 static bool all_digits(const char *s
)
674 if (!isdigit((unsigned char)*s
))
680 // If no port is specified (after a ':' or a space or a tab) it defaults to 0.
681 void WvIPPortAddr::string_init(const char string
[])
683 // special case for an all-numeric string: it must be just a port,
684 // with default address 0.0.0.0.
685 if (all_digits(string
))
692 const char *cptr
= strchr(string
, ':');
694 cptr
= strchr(string
, ' ');
696 cptr
= strchr(string
, '\t');
698 // avoid calling getservbyname() if we can avoid it, since it's really
699 // slow and people like to create WvIPPortAddr objects really often.
700 if (cptr
&& strcmp(cptr
+1, "0"))
705 struct servent
*serv
= getservbyname(cptr
+1, NULL
);
707 port
= ntohs(serv
->s_port
);
715 WvIPPortAddr::WvIPPortAddr(uint16_t _port
)
716 : WvIPAddr("0.0.0.0")
722 WvIPPortAddr::WvIPPortAddr(const char string
[], uint16_t _port
)
729 WvIPPortAddr::~WvIPPortAddr()
735 /* Generate a printable version of an IP+Port Address. */
736 WvString
WvIPPortAddr::printable() const
738 return WvString("%s:%s", WvIPAddr::printable(), WvString(port
));
742 /* Generate a struct sockaddr (suitable for sendto()) from this IP+Port
743 * address. Don't forget to delete it after you're done!
745 sockaddr_bin
*WvIPPortAddr::sockaddr() const
747 sockaddr_in
*sin
= (sockaddr_in
*)WvIPAddr::sockaddr();
748 sin
->sin_port
= htons(port
);
749 return (sockaddr_bin
*)sin
;
753 unsigned WvIPPortAddr::WvHash() const
755 return WvIPAddr::WvHash() + port
;
758 bool WvIPPortAddr::comparator(const WvAddr
*a2
, bool first_pass
) const
760 if (a2
->type() == WVIPPORTADDR
)
761 return WvIPAddr::comparator(a2
, false)
762 && port
== ((WvIPPortAddr
*)a2
)->port
;
764 return a2
->comparator(this, false);
766 return WvIPAddr::comparator(a2
, false);
771 WvUnixAddr::WvUnixAddr(const char *_sockname
)
772 : sockname(_sockname
)
779 WvUnixAddr::WvUnixAddr(WvStringParm _sockname
)
780 : sockname(_sockname
)
787 WvUnixAddr::WvUnixAddr(const WvUnixAddr
&_addr
)
788 : sockname(_addr
.sockname
)
790 // nothing else needed
794 WvUnixAddr::~WvUnixAddr()
800 WvString
WvUnixAddr::printable() const
806 WvEncap
WvUnixAddr::encap() const
808 return WvEncap::Unix
;
812 /* don't forget to delete the returned object when you're done! */
813 sockaddr_bin
*WvUnixAddr::sockaddr() const
815 sockaddr_un
*addr
= new sockaddr_un
;
817 memset(addr
, 0, sizeof(*addr
));
818 addr
->sun_family
= AF_UNIX
;
819 size_t max
= strlen(sockname
);
820 if (max
> sizeof(addr
->sun_path
) - 2) // appease valgrind
821 max
= sizeof(addr
->sun_path
) - 2;
822 strncpy(addr
->sun_path
, sockname
, max
);
823 if (addr
->sun_path
[0] == '@') // user wants an "abstract" socket
824 addr
->sun_path
[0] = 0; // leading byte should be nul
825 return (sockaddr_bin
*)addr
;
829 size_t WvUnixAddr::sockaddr_len() const
832 size_t max
= sizeof(fake
->sun_path
);
833 size_t val
= strlen(sockname
);
836 return sizeof(fake
->sun_family
) + val
;
840 const unsigned char *WvUnixAddr::rawdata() const
842 return (const unsigned char *)(const char *)sockname
;
846 size_t WvUnixAddr::rawdata_len() const
848 return strlen(sockname
);