Make WvStreams compile with gcc 4.4.
[wvstreams.git] / ipstreams / wvaddr.cc
blobbb2d850674a08e9c905d7e6017ebb7db985347db
1 /*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4 *
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.
8 */
9 #ifndef _WIN32
10 #include <netdb.h>
11 #include <sys/socket.h>
12 #include <sys/un.h>
13 #ifdef MACOS
14 #include <sys/types.h>
15 #endif
16 #include <net/if_arp.h>
17 #endif
19 #include "wvaddr.h"
20 #include <assert.h>
22 #ifndef ARPHRD_IPSEC
23 // From ipsec_tunnel
24 #define ARPHRD_IPSEC 31
25 #endif
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[] = {
32 #ifdef _WIN32
33 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
34 #else
35 // hardware encapsulation
36 0, // Unknown
37 ARPHRD_LOOPBACK,
38 0, // Ethertap
39 ARPHRD_ETHER,
40 ARPHRD_ARCNET,
41 ARPHRD_SLIP,
42 ARPHRD_CSLIP,
43 ARPHRD_PPP,
44 ARPHRD_IPSEC,
46 // protocol encapsulation
47 AF_INET, // IPv4
48 AF_UNIX // Unix domain socket
49 #endif
53 /* Printable strings corresponding to each element of CapType */
54 const char WvEncap::strings[][20] = {
55 // hardware encapsulation
56 "Unknown",
57 "Loopback",
58 "Ethertap",
59 "Ethernet",
60 "ARCnet",
61 "SLIP",
62 "CSLIP",
63 "PPP",
64 "IPsec",
66 // protocol encapsulation
67 "IP", // IPv4
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])
81 cap = (CapType)count;
82 return;
85 cap = Unknown;
89 /* Find the hash value of a WvAddr, for use with WvHashTable */
90 unsigned WvHash(const WvAddr &addr)
92 return addr.WvHash();
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);
103 switch (encap.cap)
105 case WvEncap::Loopback:
106 return new WvStringAddr("Loopback", WvEncap::Loopback);
108 case WvEncap::IPv4:
109 return new WvIPPortAddr((sockaddr_in *)addr);
110 #ifndef _WIN32
111 case WvEncap::ARCnet:
112 return new WvARCnetAddr(addr);
114 case WvEncap::Ethertap:
115 case WvEncap::Ethernet:
116 return new WvEtherAddr(addr);
118 case WvEncap::IPsec:
119 return new WvStringAddr("IPsec", WvEncap::IPsec);
120 #endif
121 default:
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
135 return NULL;
139 size_t WvAddr::rawdata_len() const
141 return 0;
145 unsigned WvAddr::WvHash() const
147 unsigned hash = 0;
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++);
156 return hash;
160 bool WvAddr::comparator(const WvAddr *a2, bool first_pass) const
162 if (type() != a2->type()) return false;
164 const unsigned char *raw1, *raw2;
165 size_t len;
167 len = rawdata_len();
168 if (len != a2->rawdata_len())
169 return false;
171 raw1 = rawdata();
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)
182 : addr(s), cap(_cap)
187 WvStringAddr::WvStringAddr(const struct sockaddr *_addr)
188 : addr((char *)_addr->sa_data), cap(_addr->sa_family)
193 WvStringAddr::~WvStringAddr()
195 // nothing to do
199 WvEncap WvStringAddr::encap() const
201 return cap;
205 const unsigned char *WvStringAddr::rawdata() const
207 return (const unsigned char *)(const char *)addr;
211 size_t WvStringAddr::rawdata_len() const
213 return strlen(addr);
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));
222 return sa;
226 size_t WvStringAddr::sockaddr_len() const
228 return sizeof(sockaddr_bin);
232 WvString WvStringAddr::printable() const
234 return addr;
238 #ifndef _WIN32
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[])
244 char *endptr = NULL;
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;
252 endptr++;
257 WvEtherAddr::~WvEtherAddr()
259 // nothing to do
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++)
270 if (cptr > s)
271 *cptr++ = ':';
272 sprintf(cptr, "%02X", binaddr[count]);
273 cptr += 2;
275 *cptr = 0;
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)
292 return false;
293 return true;
297 const unsigned char *WvEtherAddr::rawdata() const
299 return binaddr;
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);
315 return sa;
319 size_t WvEtherAddr::sockaddr_len() const
321 return sizeof(sockaddr_bin);
325 WvARCnetAddr::~WvARCnetAddr()
327 // nothing to do
331 WvString WvARCnetAddr::printable() const
333 WvString s(" ");
334 sprintf(s.edit(), "%02X", binaddr);
335 return s;
339 WvEncap WvARCnetAddr::encap() const
341 return WvEncap(WvEncap::ARCnet);
345 const unsigned char *WvARCnetAddr::rawdata() const
347 return &binaddr;
351 size_t WvARCnetAddr::rawdata_len() const
353 return 1;
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;
363 return sa;
367 size_t WvARCnetAddr::sockaddr_len() const
369 return sizeof(sockaddr_bin);
372 #endif //_WIN32
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);
384 nptr = string;
385 for (int count=0; count < 4 && nptr; count++)
387 iptr = nptr;
388 nptr = strchr(iptr, '.');
389 if (nptr) nptr++;
390 *cptr++ = strtol(iptr, NULL, 10);
391 if (!nptr) break;
395 WvIPAddr::~WvIPAddr()
397 // nothing to do
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));
404 else if (first_pass)
405 return a2->comparator(this, false);
406 else
408 const unsigned char *raw1, *raw2;
409 size_t len;
411 len = rawdata_len();
412 if (len != a2->rawdata_len())
413 return false;
415 raw1 = rawdata();
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
503 return binaddr;
507 size_t WvIPAddr::rawdata_len() const
509 return 4;
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();
523 sin->sin_port = 0;
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[])
544 const char *maskptr;
545 int bits;
546 uint32_t imask;
548 maskptr = strchr(string, '/');
549 if (!maskptr)
551 mask = WvIPAddr("255.255.255.255");
552 return;
555 maskptr++;
557 if (strchr(maskptr, '.'))
558 mask = WvIPAddr(maskptr);
559 else
561 bits = atoi(maskptr);
562 if (bits > 0)
563 imask = htonl(~(((uint32_t)1 << (32-bits)) - 1)); // see below
564 else
565 imask = 0;
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)
576 : WvIPAddr(base)
578 uint32_t imask;
579 if (bits > 0) // <<32 is a bad idea!
580 imask = htonl(~(((uint32_t)1 << (32-bits)) - 1));
581 else
582 imask = 0;
583 mask = WvIPAddr((unsigned char *)&imask);
586 WvIPNet::~WvIPNet()
588 // nothing to do
592 WvString WvIPNet::printable() const
594 if (bits() < 32)
595 return WvString("%s/%s", network(), bits());
596 else
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;
611 else if (first_pass)
612 return a2->comparator(this, false);
613 else
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
634 int bits = 0;
635 uint32_t val = ntohl(mask.addr());
639 bits += val >> 31;
640 } while ((val <<= 1) & (1 << 31));
642 return bits;
646 void WvIPNet::normalize()
648 if (bits() > 0)
650 uint32_t val = htonl(~(((uint32_t)1 << (32-bits())) - 1));
651 mask = WvIPAddr((unsigned char *)&val);
653 else
654 mask = WvIPAddr(); // empty netmask
658 WvIPPortAddr::WvIPPortAddr()
660 port = 0;
664 WvIPPortAddr::WvIPPortAddr(const WvIPAddr &_ipaddr, uint16_t _port)
665 : WvIPAddr(_ipaddr)
667 port = _port;
671 static bool all_digits(const char *s)
673 for (; *s; s++)
674 if (!isdigit((unsigned char)*s))
675 return false;
676 return true;
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))
687 *this = WvIPAddr();
688 port = atoi(string);
689 return;
692 const char *cptr = strchr(string, ':');
693 if (!cptr)
694 cptr = strchr(string, ' ');
695 if (!cptr)
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"))
702 port = atoi(cptr+1);
703 if (!port)
705 struct servent *serv = getservbyname(cptr+1, NULL);
706 if (serv)
707 port = ntohs(serv->s_port);
710 else
711 port = 0;
715 WvIPPortAddr::WvIPPortAddr(uint16_t _port)
716 : WvIPAddr("0.0.0.0")
718 port = _port;
722 WvIPPortAddr::WvIPPortAddr(const char string[], uint16_t _port)
723 : WvIPAddr(string)
725 port = _port;
729 WvIPPortAddr::~WvIPPortAddr()
731 // nothing to do
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;
763 else if (first_pass)
764 return a2->comparator(this, false);
765 else
766 return WvIPAddr::comparator(a2, false);
770 #ifndef _WIN32
771 WvUnixAddr::WvUnixAddr(const char *_sockname)
772 : sockname(_sockname)
774 if (!sockname)
775 sockname = "/";
779 WvUnixAddr::WvUnixAddr(WvStringParm _sockname)
780 : sockname(_sockname)
782 if (!sockname)
783 sockname = "/";
787 WvUnixAddr::WvUnixAddr(const WvUnixAddr &_addr)
788 : sockname(_addr.sockname)
790 // nothing else needed
794 WvUnixAddr::~WvUnixAddr()
796 // nothing special
800 WvString WvUnixAddr::printable() const
802 return sockname;
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
831 sockaddr_un *fake;
832 size_t max = sizeof(fake->sun_path);
833 size_t val = strlen(sockname);
834 if (val > max)
835 val = max;
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);
850 #endif // _WIN32