xref: /haiku/src/kits/network/libnetapi/NetworkAddress.cpp (revision bddcee2a27042b4d8d6b0142b466f30abc886648)
1 /*
2  * Copyright 2010-2015, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <NetworkAddress.h>
8 
9 #include <NetworkInterface.h>
10 #include <NetworkRoster.h>
11 
12 #include <arpa/inet.h>
13 #include <ctype.h>
14 #include <errno.h>
15 #include <netinet/in.h>
16 #include <stdio.h>
17 #include <sys/sockio.h>
18 
19 
20 /* The GCC builtin below only exists in > GCC 3.4
21  * Benefits include faster execution time as the builtin
22  * uses a bitcounting cpu instruction if it exists
23  */
24 #if __GNUC__ > 3
25 #	define addr_bitcount(bitfield) __builtin_popcount(bitfield)
26 #else
27 static ssize_t
28 addr_bitcount(uint32 bitfield)
29 {
30 	ssize_t result = 0;
31 	for (uint8 i = 32; i > 0; i--) {
32 		if ((bitfield & (1 << (i - 1))) == 0)
33 			break;
34 		result++;
35 	}
36 	return result;
37 }
38 #endif
39 
40 
41 static uint8
42 from_hex(char hex)
43 {
44 	if (isdigit(hex))
45 		return hex - '0';
46 
47 	return tolower(hex) - 'a' + 10;
48 }
49 
50 
51 // #pragma mark -
52 
53 
54 BNetworkAddress::BNetworkAddress()
55 {
56 	Unset();
57 }
58 
59 
60 BNetworkAddress::BNetworkAddress(const char* host, uint16 port, uint32 flags)
61 {
62 	fStatus = SetTo(host, port, flags);
63 }
64 
65 
66 BNetworkAddress::BNetworkAddress(const char* host, const char* service,
67 	uint32 flags)
68 {
69 	fStatus = SetTo(host, service, flags);
70 }
71 
72 
73 BNetworkAddress::BNetworkAddress(int family, const char* host, uint16 port,
74 	uint32 flags)
75 {
76 	fStatus = SetTo(family, host, port, flags);
77 }
78 
79 
80 BNetworkAddress::BNetworkAddress(int family, const char* host,
81 	const char* service, uint32 flags)
82 {
83 	fStatus = SetTo(family, host, service, flags);
84 }
85 
86 
87 BNetworkAddress::BNetworkAddress(const sockaddr& address)
88 {
89 	SetTo(address);
90 }
91 
92 
93 BNetworkAddress::BNetworkAddress(const sockaddr_storage& address)
94 {
95 	SetTo(address);
96 }
97 
98 
99 BNetworkAddress::BNetworkAddress(const sockaddr_in& address)
100 {
101 	SetTo(address);
102 }
103 
104 
105 BNetworkAddress::BNetworkAddress(const sockaddr_in6& address)
106 {
107 	SetTo(address);
108 }
109 
110 
111 BNetworkAddress::BNetworkAddress(const sockaddr_dl& address)
112 {
113 	SetTo(address);
114 }
115 
116 
117 BNetworkAddress::BNetworkAddress(in_addr_t address, uint16 port)
118 {
119 	SetTo(address, port);
120 }
121 
122 
123 BNetworkAddress::BNetworkAddress(const in6_addr& address, uint16 port)
124 {
125 	SetTo(address, port);
126 }
127 
128 
129 BNetworkAddress::BNetworkAddress(const BNetworkAddress& other)
130 	:
131 	fAddress(other.fAddress),
132 	fStatus(other.fStatus),
133 	fHostName(other.fHostName)
134 {
135 }
136 
137 
138 BNetworkAddress::~BNetworkAddress()
139 {
140 }
141 
142 
143 status_t
144 BNetworkAddress::InitCheck() const
145 {
146 	return fStatus;
147 }
148 
149 
150 void
151 BNetworkAddress::Unset()
152 {
153 	fAddress.ss_family = AF_UNSPEC;
154 	fAddress.ss_len = 2;
155 	fHostName = "";
156 	fStatus = B_OK;
157 }
158 
159 
160 status_t
161 BNetworkAddress::SetTo(const char* host, uint16 port, uint32 flags)
162 {
163 	BReference<const BNetworkAddressResolver> resolver
164 		= BNetworkAddressResolver::Resolve(host, port, flags);
165 	if (resolver.Get() == NULL)
166 		return B_NO_MEMORY;
167 	status_t status = resolver->InitCheck();
168 	if (status != B_OK)
169 		return status;
170 
171 	// Prefer IPv6 addresses
172 
173 	uint32 cookie = 0;
174 	status = resolver->GetNextAddress(AF_INET6, &cookie, *this);
175 	if (status != B_OK) {
176 		cookie = 0;
177 		status = resolver->GetNextAddress(&cookie, *this);
178 		if (status != B_OK)
179 			Unset();
180 	}
181 	fHostName = host;
182 	fStatus = status;
183 	return status;
184 }
185 
186 
187 status_t
188 BNetworkAddress::SetTo(const char* host, const char* service, uint32 flags)
189 {
190 	BReference<const BNetworkAddressResolver> resolver
191 		= BNetworkAddressResolver::Resolve(host, service, flags);
192 	if (resolver.Get() == NULL)
193 		return B_NO_MEMORY;
194 	status_t status = resolver->InitCheck();
195 	if (status != B_OK)
196 		return status;
197 
198 	// Prefer IPv6 addresses
199 
200 	uint32 cookie = 0;
201 	status = resolver->GetNextAddress(AF_INET6, &cookie, *this);
202 	if (status != B_OK) {
203 		cookie = 0;
204 		status = resolver->GetNextAddress(&cookie, *this);
205 		if (status != B_OK)
206 			Unset();
207 	}
208 	fHostName = host;
209 	fStatus = status;
210 	return status;
211 }
212 
213 
214 status_t
215 BNetworkAddress::SetTo(int family, const char* host, uint16 port, uint32 flags)
216 {
217 	if (family == AF_LINK) {
218 		if (port != 0)
219 			return B_BAD_VALUE;
220 		return _ParseLinkAddress(host);
221 			// SetToLinkAddress takes care of setting fStatus
222 	}
223 
224 	BReference<const BNetworkAddressResolver> resolver
225 		= BNetworkAddressResolver::Resolve(family, host, port, flags);
226 	if (resolver.Get() == NULL)
227 		return B_NO_MEMORY;
228 	status_t status = resolver->InitCheck();
229 	if (status != B_OK)
230 		return status;
231 
232 	uint32 cookie = 0;
233 	status = resolver->GetNextAddress(&cookie, *this);
234 	if (status != B_OK)
235 		Unset();
236 	fHostName = host;
237 	fStatus = status;
238 	return status;
239 }
240 
241 
242 status_t
243 BNetworkAddress::SetTo(int family, const char* host, const char* service,
244 	uint32 flags)
245 {
246 	if (family == AF_LINK) {
247 		if (service != NULL)
248 			return B_BAD_VALUE;
249 		return _ParseLinkAddress(host);
250 			// SetToLinkAddress takes care of setting fStatus
251 	}
252 
253 	BReference<const BNetworkAddressResolver> resolver
254 		= BNetworkAddressResolver::Resolve(family, host, service, flags);
255 	if (resolver.Get() == NULL)
256 		return B_NO_MEMORY;
257 	status_t status = resolver->InitCheck();
258 	if (status != B_OK)
259 		return status;
260 
261 	uint32 cookie = 0;
262 	status = resolver->GetNextAddress(&cookie, *this);
263 	if (status != B_OK)
264 		Unset();
265 	fHostName = host;
266 	fStatus = status;
267 	return status;
268 }
269 
270 
271 void
272 BNetworkAddress::SetTo(const sockaddr& address)
273 {
274 	if (address.sa_family == AF_UNSPEC) {
275 		Unset();
276 		return;
277 	}
278 
279 	size_t length = min_c(sizeof(sockaddr_storage), address.sa_len);
280 	switch (address.sa_family) {
281 		case AF_INET:
282 			length = sizeof(sockaddr_in);
283 			break;
284 		case AF_INET6:
285 			length = sizeof(sockaddr_in6);
286 			break;
287 		case AF_LINK:
288 		{
289 			sockaddr_dl& link = (sockaddr_dl&)address;
290 			length = sizeof(sockaddr_dl) - sizeof(link.sdl_data) + link.sdl_alen
291 				+ link.sdl_nlen + link.sdl_slen;
292 			break;
293 		}
294 	}
295 
296 	SetTo(address, length);
297 }
298 
299 
300 void
301 BNetworkAddress::SetTo(const sockaddr& address, size_t length)
302 {
303 	if (address.sa_family == AF_UNSPEC || length == 0) {
304 		Unset();
305 		return;
306 	}
307 
308 	memcpy(&fAddress, &address, length);
309 	fAddress.ss_len = length;
310 	fStatus = B_OK;
311 }
312 
313 
314 void
315 BNetworkAddress::SetTo(const sockaddr_storage& address)
316 {
317 	SetTo((sockaddr&)address);
318 }
319 
320 
321 void
322 BNetworkAddress::SetTo(const sockaddr_in& address)
323 {
324 	SetTo((sockaddr&)address);
325 }
326 
327 
328 void
329 BNetworkAddress::SetTo(const sockaddr_in6& address)
330 {
331 	SetTo((sockaddr&)address);
332 }
333 
334 
335 void
336 BNetworkAddress::SetTo(const sockaddr_dl& address)
337 {
338 	SetTo((sockaddr&)address);
339 }
340 
341 
342 void
343 BNetworkAddress::SetTo(in_addr_t inetAddress, uint16 port)
344 {
345 	memset(&fAddress, 0, sizeof(sockaddr_storage));
346 
347 	fAddress.ss_family = AF_INET;
348 	fAddress.ss_len = sizeof(sockaddr_in);
349 	SetAddress(inetAddress);
350 	SetPort(port);
351 
352 	fStatus = B_OK;
353 }
354 
355 
356 void
357 BNetworkAddress::SetTo(const in6_addr& inet6Address, uint16 port)
358 {
359 	memset(&fAddress, 0, sizeof(sockaddr_storage));
360 
361 	fAddress.ss_family = AF_INET6;
362 	fAddress.ss_len = sizeof(sockaddr_in6);
363 	SetAddress(inet6Address);
364 	SetPort(port);
365 
366 	fStatus = B_OK;
367 }
368 
369 
370 void
371 BNetworkAddress::SetTo(const BNetworkAddress& other)
372 {
373 	fAddress = other.fAddress;
374 	fStatus = other.fStatus;
375 	fHostName = other.fHostName;
376 }
377 
378 
379 status_t
380 BNetworkAddress::SetToBroadcast(int family, uint16 port)
381 {
382 	if (family != AF_INET)
383 		return fStatus = B_NOT_SUPPORTED;
384 
385 	SetTo(INADDR_BROADCAST, port);
386 	return fStatus;
387 }
388 
389 
390 status_t
391 BNetworkAddress::SetToLocal(int family, uint16 port)
392 {
393 	// TODO: choose a local address from the network interfaces
394 	return fStatus = B_NOT_SUPPORTED;
395 }
396 
397 
398 status_t
399 BNetworkAddress::SetToLoopback(int family, uint16 port)
400 {
401 	switch (family) {
402 		// TODO: choose family depending on availability of IPv6
403 		case AF_UNSPEC:
404 		case AF_INET:
405 			SetTo(htonl(INADDR_LOOPBACK), port);
406 			break;
407 
408 		case AF_INET6:
409 			SetTo(in6addr_loopback, port);
410 			break;
411 
412 		default:
413 			return fStatus = B_NOT_SUPPORTED;
414 	}
415 
416 	return fStatus;
417 }
418 
419 
420 status_t
421 BNetworkAddress::SetToMask(int family, uint32 prefixLength)
422 {
423 	switch (family) {
424 		case AF_INET:
425 		{
426 			if (prefixLength > 32)
427 				return B_BAD_VALUE;
428 
429 			sockaddr_in& mask = (sockaddr_in&)fAddress;
430 			memset(&fAddress, 0, sizeof(sockaddr_storage));
431 			mask.sin_family = AF_INET;
432 			mask.sin_len = sizeof(sockaddr_in);
433 
434 			uint32 hostMask = 0;
435 			for (uint8 i = 32; i > 32 - prefixLength; i--)
436 				hostMask |= 1 << (i - 1);
437 
438 			mask.sin_addr.s_addr = htonl(hostMask);
439 			break;
440 		}
441 
442 		case AF_INET6:
443 		{
444 			if (prefixLength > 128)
445 				return B_BAD_VALUE;
446 
447 			sockaddr_in6& mask = (sockaddr_in6&)fAddress;
448 			memset(&fAddress, 0, sizeof(sockaddr_storage));
449 			mask.sin6_family = AF_INET6;
450 			mask.sin6_len = sizeof(sockaddr_in6);
451 
452 			for (uint8 i = 0; i < sizeof(in6_addr); i++, prefixLength -= 8) {
453 				if (prefixLength < 8) {
454 					mask.sin6_addr.s6_addr[i]
455 						= (uint8)(0xff << (8 - prefixLength));
456 					break;
457 				}
458 
459 				mask.sin6_addr.s6_addr[i] = 0xff;
460 			}
461 			break;
462 		}
463 
464 		default:
465 			return B_NOT_SUPPORTED;
466 	}
467 
468 	return fStatus = B_OK;
469 }
470 
471 
472 status_t
473 BNetworkAddress::SetToWildcard(int family, uint16 port)
474 {
475 	switch (family) {
476 		case AF_INET:
477 			SetTo(INADDR_ANY, port);
478 			break;
479 
480 		case AF_INET6:
481 			SetTo(in6addr_any, port);
482 			break;
483 
484 		default:
485 			return B_NOT_SUPPORTED;
486 	}
487 
488 	return fStatus;
489 }
490 
491 
492 status_t
493 BNetworkAddress::SetAddress(in_addr_t inetAddress)
494 {
495 	if (Family() != AF_INET)
496 		return B_BAD_VALUE;
497 
498 	sockaddr_in& address = (sockaddr_in&)fAddress;
499 	address.sin_addr.s_addr = inetAddress;
500 	return B_OK;
501 }
502 
503 
504 status_t
505 BNetworkAddress::SetAddress(const in6_addr& inet6Address)
506 {
507 	if (Family() != AF_INET6)
508 		return B_BAD_VALUE;
509 
510 	sockaddr_in6& address = (sockaddr_in6&)fAddress;
511 	memcpy(address.sin6_addr.s6_addr, &inet6Address,
512 		sizeof(address.sin6_addr.s6_addr));
513 	return B_OK;
514 }
515 
516 
517 void
518 BNetworkAddress::SetPort(uint16 port)
519 {
520 	switch (fAddress.ss_family) {
521 		case AF_INET:
522 			((sockaddr_in&)fAddress).sin_port = htons(port);
523 			break;
524 
525 		case AF_INET6:
526 			((sockaddr_in6&)fAddress).sin6_port = htons(port);
527 			break;
528 
529 		default:
530 			break;
531 	}
532 }
533 
534 
535 void
536 BNetworkAddress::SetToLinkLevel(uint8* address, size_t length)
537 {
538 	sockaddr_dl& link = (sockaddr_dl&)fAddress;
539 	memset(&link, 0, sizeof(sockaddr_dl));
540 
541 	link.sdl_family = AF_LINK;
542 	link.sdl_alen = length;
543 	memcpy(LLADDR(&link), address, length);
544 
545 	link.sdl_len = sizeof(sockaddr_dl);
546 	if (length > sizeof(link.sdl_data))
547 		link.sdl_len += length - sizeof(link.sdl_data);
548 
549 	fStatus = B_OK;
550 }
551 
552 
553 void
554 BNetworkAddress::SetToLinkLevel(const char* name)
555 {
556 	sockaddr_dl& link = (sockaddr_dl&)fAddress;
557 	memset(&link, 0, sizeof(sockaddr_dl));
558 
559 	size_t length = strlen(name);
560 	if (length > sizeof(fAddress) - sizeof(sockaddr_dl) + sizeof(link.sdl_data))
561 		length = sizeof(fAddress) - sizeof(sockaddr_dl) + sizeof(link.sdl_data);
562 
563 	link.sdl_family = AF_LINK;
564 	link.sdl_nlen = length;
565 
566 	memcpy(link.sdl_data, name, link.sdl_nlen);
567 
568 	link.sdl_len = sizeof(sockaddr_dl);
569 	if (link.sdl_nlen > sizeof(link.sdl_data))
570 		link.sdl_len += link.sdl_nlen - sizeof(link.sdl_data);
571 
572 	fStatus = B_OK;
573 }
574 
575 
576 void
577 BNetworkAddress::SetToLinkLevel(uint32 index)
578 {
579 	sockaddr_dl& link = (sockaddr_dl&)fAddress;
580 	memset(&link, 0, sizeof(sockaddr_dl));
581 
582 	link.sdl_family = AF_LINK;
583 	link.sdl_len = sizeof(sockaddr_dl);
584 	link.sdl_index = index;
585 
586 	fStatus = B_OK;
587 }
588 
589 
590 void
591 BNetworkAddress::SetLinkLevelIndex(uint32 index)
592 {
593 	sockaddr_dl& link = (sockaddr_dl&)fAddress;
594 	link.sdl_index = index;
595 }
596 
597 
598 void
599 BNetworkAddress::SetLinkLevelType(uint8 type)
600 {
601 	sockaddr_dl& link = (sockaddr_dl&)fAddress;
602 	link.sdl_type = type;
603 }
604 
605 
606 void
607 BNetworkAddress::SetLinkLevelFrameType(uint16 frameType)
608 {
609 	sockaddr_dl& link = (sockaddr_dl&)fAddress;
610 	link.sdl_e_type = htons(frameType);
611 }
612 
613 
614 int
615 BNetworkAddress::Family() const
616 {
617 	return fAddress.ss_family;
618 }
619 
620 
621 uint16
622 BNetworkAddress::Port() const
623 {
624 	switch (fAddress.ss_family) {
625 		case AF_INET:
626 			return ntohs(((sockaddr_in&)fAddress).sin_port);
627 
628 		case AF_INET6:
629 			return ntohs(((sockaddr_in6&)fAddress).sin6_port);
630 
631 		default:
632 			return 0;
633 	}
634 }
635 
636 
637 size_t
638 BNetworkAddress::Length() const
639 {
640 	return fAddress.ss_len;
641 }
642 
643 
644 const sockaddr&
645 BNetworkAddress::SockAddr() const
646 {
647 	return (const sockaddr&)fAddress;
648 }
649 
650 
651 sockaddr&
652 BNetworkAddress::SockAddr()
653 {
654 	return (sockaddr&)fAddress;
655 }
656 
657 
658 bool
659 BNetworkAddress::IsEmpty() const
660 {
661 	if (fAddress.ss_len == 0)
662 		return true;
663 
664 	switch (fAddress.ss_family) {
665 		case AF_UNSPEC:
666 			return true;
667 		case AF_INET:
668 		{
669 			sockaddr_in& sin = (sockaddr_in&)fAddress;
670 			return sin.sin_addr.s_addr == INADDR_ANY && sin.sin_port == 0;
671 		}
672 		case AF_INET6:
673 		{
674 			sockaddr_in6& sin6 = (sockaddr_in6&)fAddress;
675 			return IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)
676 				&& sin6.sin6_port == 0;
677 		}
678 
679 		default:
680 			return false;
681 	}
682 }
683 
684 
685 bool
686 BNetworkAddress::IsWildcard() const
687 {
688 	switch (fAddress.ss_family) {
689 		case AF_INET:
690 			return ((sockaddr_in&)fAddress).sin_addr.s_addr == INADDR_ANY;
691 
692 		case AF_INET6:
693 			return !memcmp(&((sockaddr_in6&)fAddress).sin6_addr, &in6addr_any,
694 				sizeof(in6_addr));
695 
696 		default:
697 			return false;
698 	}
699 }
700 
701 
702 bool
703 BNetworkAddress::IsBroadcast() const
704 {
705 	switch (fAddress.ss_family) {
706 		case AF_INET:
707 			return ((sockaddr_in&)fAddress).sin_addr.s_addr == INADDR_BROADCAST;
708 
709 		case AF_INET6:
710 			// There is no broadcast in IPv6, only multicast/anycast
711 			return IN6_IS_ADDR_MULTICAST(&((sockaddr_in6&)fAddress).sin6_addr);
712 
713 		default:
714 			return false;
715 	}
716 }
717 
718 
719 bool
720 BNetworkAddress::IsMulticast() const
721 {
722 	switch (fAddress.ss_family) {
723 		case AF_INET:
724 			return IN_MULTICAST(((sockaddr_in&)fAddress).sin_addr.s_addr);
725 
726 		case AF_INET6:
727 			return IN6_IS_ADDR_MULTICAST(&((sockaddr_in6&)fAddress).sin6_addr);
728 
729 		default:
730 			return false;
731 	}
732 }
733 
734 
735 bool
736 BNetworkAddress::IsMulticastGlobal() const
737 {
738 	switch (fAddress.ss_family) {
739 		case AF_INET6:
740 			return IN6_IS_ADDR_MC_GLOBAL(&((sockaddr_in6&)fAddress).sin6_addr);
741 
742 		default:
743 			return false;
744 	}
745 }
746 
747 
748 bool
749 BNetworkAddress::IsMulticastNodeLocal() const
750 {
751 	switch (fAddress.ss_family) {
752 		case AF_INET6:
753 			return IN6_IS_ADDR_MC_NODELOCAL(
754 				&((sockaddr_in6&)fAddress).sin6_addr);
755 
756 		default:
757 			return false;
758 	}
759 }
760 
761 
762 bool
763 BNetworkAddress::IsMulticastLinkLocal() const
764 {
765 	switch (fAddress.ss_family) {
766 		case AF_INET6:
767 			return IN6_IS_ADDR_MC_LINKLOCAL(
768 				&((sockaddr_in6&)fAddress).sin6_addr);
769 
770 		default:
771 			return false;
772 	}
773 }
774 
775 
776 bool
777 BNetworkAddress::IsMulticastSiteLocal() const
778 {
779 	switch (fAddress.ss_family) {
780 		case AF_INET6:
781 			return IN6_IS_ADDR_MC_SITELOCAL(
782 				&((sockaddr_in6&)fAddress).sin6_addr);
783 
784 		default:
785 			return false;
786 	}
787 }
788 
789 
790 bool
791 BNetworkAddress::IsMulticastOrgLocal() const
792 {
793 	switch (fAddress.ss_family) {
794 		case AF_INET6:
795 			return IN6_IS_ADDR_MC_ORGLOCAL(
796 				&((sockaddr_in6&)fAddress).sin6_addr);
797 
798 		default:
799 			return false;
800 	}
801 }
802 
803 
804 bool
805 BNetworkAddress::IsLinkLocal() const
806 {
807 	// TODO: ipv4
808 	switch (fAddress.ss_family) {
809 		case AF_INET6:
810 			return IN6_IS_ADDR_LINKLOCAL(&((sockaddr_in6&)fAddress).sin6_addr);
811 
812 		default:
813 			return false;
814 	}
815 }
816 
817 
818 bool
819 BNetworkAddress::IsSiteLocal() const
820 {
821 	switch (fAddress.ss_family) {
822 		case AF_INET6:
823 			return IN6_IS_ADDR_SITELOCAL(&((sockaddr_in6&)fAddress).sin6_addr);
824 
825 		default:
826 			return false;
827 	}
828 }
829 
830 
831 bool
832 BNetworkAddress::IsLocal() const
833 {
834 	BNetworkRoster& roster = BNetworkRoster::Default();
835 
836 	BNetworkInterface interface;
837 	uint32 cookie = 0;
838 
839 	while (roster.GetNextInterface(&cookie, interface) == B_OK) {
840 		int32 count = interface.CountAddresses();
841 		for (int32 j = 0; j < count; j++) {
842 			BNetworkInterfaceAddress address;
843 			if (interface.GetAddressAt(j, address) != B_OK)
844 				break;
845 
846 			if (Equals(address.Address(), false))
847 				return true;
848 		}
849 	}
850 
851 	return false;
852 }
853 
854 
855 ssize_t
856 BNetworkAddress::PrefixLength() const
857 {
858 	switch (fAddress.ss_family) {
859 		case AF_INET:
860 		{
861 			sockaddr_in& mask = (sockaddr_in&)fAddress;
862 
863 			uint32 hostMask = ntohl(mask.sin_addr.s_addr);
864 			return addr_bitcount(hostMask);
865 		}
866 
867 		case AF_INET6:
868 		{
869 			sockaddr_in6& mask = (sockaddr_in6&)fAddress;
870 
871 			// TODO : see if we can use the optimized addr_bitcount for this
872 			ssize_t result = 0;
873 			for (uint8 i = 0; i < sizeof(in6_addr); i++) {
874 				for (uint8 j = 0; j < 8; j++) {
875 					if (!(mask.sin6_addr.s6_addr[i] & (1 << j)))
876 						return result;
877 					result++;
878 				}
879 			}
880 
881 			return 128;
882 		}
883 
884 		default:
885 			return B_NOT_SUPPORTED;
886 	}
887 }
888 
889 
890 uint32
891 BNetworkAddress::LinkLevelIndex() const
892 {
893 	return ((sockaddr_dl&)fAddress).sdl_index;
894 }
895 
896 
897 BString
898 BNetworkAddress::LinkLevelInterface() const
899 {
900 	sockaddr_dl& address = (sockaddr_dl&)fAddress;
901 	if (address.sdl_nlen == 0)
902 		return "";
903 
904 	BString name;
905 	name.SetTo((const char*)address.sdl_data, address.sdl_nlen);
906 
907 	return name;
908 }
909 
910 
911 uint8
912 BNetworkAddress::LinkLevelType() const
913 {
914 	return ((sockaddr_dl&)fAddress).sdl_type;
915 }
916 
917 
918 uint16
919 BNetworkAddress::LinkLevelFrameType() const
920 {
921 	return ntohs(((sockaddr_dl&)fAddress).sdl_e_type);
922 }
923 
924 
925 uint8*
926 BNetworkAddress::LinkLevelAddress() const
927 {
928 	return LLADDR(&(sockaddr_dl&)fAddress);
929 }
930 
931 
932 size_t
933 BNetworkAddress::LinkLevelAddressLength() const
934 {
935 	return ((sockaddr_dl&)fAddress).sdl_alen;
936 }
937 
938 
939 status_t
940 BNetworkAddress::ResolveForDestination(const BNetworkAddress& destination)
941 {
942 	if (!IsWildcard())
943 		return B_OK;
944 	if (destination.fAddress.ss_family != fAddress.ss_family)
945 		return B_BAD_VALUE;
946 
947 	char buffer[2048];
948 	memset(buffer, 0, sizeof(buffer));
949 
950 	route_entry* route = (route_entry*)buffer;
951 	route->destination = (sockaddr*)&destination.fAddress;
952 
953 	int socket = ::socket(fAddress.ss_family, SOCK_DGRAM, 0);
954 	if (socket < 0)
955 		return errno;
956 
957 	if (ioctl(socket, SIOCGETRT, route, sizeof(buffer)) != 0) {
958 		close(socket);
959 		return errno;
960 	}
961 
962 	uint16 port = Port();
963 	memcpy(&fAddress, route->source, sizeof(sockaddr_storage));
964 	SetPort(port);
965 
966 	close(socket);
967 	return B_OK;
968 }
969 
970 
971 status_t
972 BNetworkAddress::ResolveTo(const BNetworkAddress& address)
973 {
974 	if (!IsWildcard())
975 		return B_OK;
976 	if (address.fAddress.ss_family != fAddress.ss_family)
977 		return B_BAD_VALUE;
978 
979 	uint16 port = Port();
980 	*this = address;
981 	SetPort(port);
982 
983 	return B_OK;
984 }
985 
986 
987 BString
988 BNetworkAddress::ToString(bool includePort) const
989 {
990 	char buffer[512];
991 
992 	switch (fAddress.ss_family) {
993 		case AF_INET:
994 			inet_ntop(AF_INET, &((sockaddr_in&)fAddress).sin_addr, buffer,
995 				sizeof(buffer));
996 			break;
997 
998 		case AF_INET6:
999 			inet_ntop(AF_INET6, &((sockaddr_in6&)fAddress).sin6_addr,
1000 				buffer, sizeof(buffer));
1001 			break;
1002 
1003 		case AF_LINK:
1004 		{
1005 			uint8 *byte = LinkLevelAddress();
1006 			char* target = buffer;
1007 			int bytesLeft = sizeof(buffer);
1008 			target[0] = '\0';
1009 
1010 			for (size_t i = 0; i < LinkLevelAddressLength(); i++) {
1011 				if (i != 0 && bytesLeft > 1) {
1012 					target[0] = ':';
1013 					target[1] = '\0';
1014 					target++;
1015 					bytesLeft--;
1016 				}
1017 
1018 				int bytesWritten = snprintf(target, bytesLeft, "%02x", byte[i]);
1019 				if (bytesWritten >= bytesLeft)
1020 					break;
1021 
1022 				target += bytesWritten;
1023 				bytesLeft -= bytesWritten;
1024 			}
1025 			break;
1026 		}
1027 
1028 		default:
1029 			return "";
1030 	}
1031 
1032 	BString address = buffer;
1033 	if (includePort && Port() != 0) {
1034 		if (fAddress.ss_family == AF_INET6) {
1035 			address = "[";
1036 			address += buffer;
1037 			address += "]";
1038 		}
1039 
1040 		snprintf(buffer, sizeof(buffer), ":%u", Port());
1041 		address += buffer;
1042 	}
1043 
1044 	return address;
1045 }
1046 
1047 
1048 BString
1049 BNetworkAddress::HostName() const
1050 {
1051 	// TODO: implement host name lookup
1052 	return fHostName;
1053 }
1054 
1055 
1056 BString
1057 BNetworkAddress::ServiceName() const
1058 {
1059 	// TODO: implement service lookup
1060 	BString portName;
1061 	portName << Port();
1062 	return portName;
1063 }
1064 
1065 
1066 bool
1067 BNetworkAddress::Equals(const BNetworkAddress& other, bool includePort) const
1068 {
1069 	if (IsEmpty() && other.IsEmpty())
1070 		return true;
1071 
1072 	if (Family() != other.Family()
1073 			|| (includePort && Port() != other.Port())) {
1074 		return false;
1075 	}
1076 
1077 	switch (fAddress.ss_family) {
1078 		case AF_INET:
1079 		{
1080 			sockaddr_in& address = (sockaddr_in&)fAddress;
1081 			sockaddr_in& otherAddress = (sockaddr_in&)other.fAddress;
1082 			return memcmp(&address.sin_addr, &otherAddress.sin_addr,
1083 				sizeof(address.sin_addr)) == 0;
1084 		}
1085 
1086 		case AF_INET6:
1087 		{
1088 			sockaddr_in6& address = (sockaddr_in6&)fAddress;
1089 			sockaddr_in6& otherAddress = (sockaddr_in6&)other.fAddress;
1090 			return memcmp(&address.sin6_addr, &otherAddress.sin6_addr,
1091 				sizeof(address.sin6_addr)) == 0;
1092 		}
1093 
1094 		default:
1095 			if (fAddress.ss_len != other.fAddress.ss_len)
1096 				return false;
1097 
1098 			return memcmp(&fAddress, &other.fAddress, fAddress.ss_len);
1099 	}
1100 }
1101 
1102 
1103 // #pragma mark - BFlattenable implementation
1104 
1105 
1106 bool
1107 BNetworkAddress::IsFixedSize() const
1108 {
1109 	return false;
1110 }
1111 
1112 
1113 type_code
1114 BNetworkAddress::TypeCode() const
1115 {
1116 	return B_NETWORK_ADDRESS_TYPE;
1117 }
1118 
1119 
1120 ssize_t
1121 BNetworkAddress::FlattenedSize() const
1122 {
1123 	return Length();
1124 }
1125 
1126 
1127 status_t
1128 BNetworkAddress::Flatten(void* buffer, ssize_t size) const
1129 {
1130 	if (buffer == NULL || size < FlattenedSize())
1131 		return B_BAD_VALUE;
1132 
1133 	memcpy(buffer, &fAddress, Length());
1134 	return B_OK;
1135 }
1136 
1137 
1138 status_t
1139 BNetworkAddress::Unflatten(type_code code, const void* buffer, ssize_t size)
1140 {
1141 	// 2 bytes minimum for family, and length
1142 	if (buffer == NULL || size < 2)
1143 		return fStatus = B_BAD_VALUE;
1144 	if (!AllowsTypeCode(code))
1145 		return fStatus = B_BAD_TYPE;
1146 
1147 	memcpy(&fAddress, buffer, min_c(size, (ssize_t)sizeof(fAddress)));
1148 
1149 	// check if this can contain a valid address
1150 	if (fAddress.ss_family != AF_UNSPEC && size < (ssize_t)sizeof(sockaddr))
1151 		return fStatus = B_BAD_VALUE;
1152 
1153 	return fStatus = B_OK;
1154 }
1155 
1156 
1157 // #pragma mark - operators
1158 
1159 
1160 BNetworkAddress&
1161 BNetworkAddress::operator=(const BNetworkAddress& other)
1162 {
1163 	memcpy(&fAddress, &other.fAddress, other.fAddress.ss_len);
1164 	fHostName = other.fHostName;
1165 	fStatus = other.fStatus;
1166 
1167 	return *this;
1168 }
1169 
1170 
1171 bool
1172 BNetworkAddress::operator==(const BNetworkAddress& other) const
1173 {
1174 	return Equals(other);
1175 }
1176 
1177 
1178 bool
1179 BNetworkAddress::operator!=(const BNetworkAddress& other) const
1180 {
1181 	return !Equals(other);
1182 }
1183 
1184 
1185 bool
1186 BNetworkAddress::operator<(const BNetworkAddress& other) const
1187 {
1188 	if (Family() < other.Family())
1189 		return true;
1190 	if (Family() > other.Family())
1191 		return false;
1192 
1193 	int compare;
1194 
1195 	switch (fAddress.ss_family) {
1196 		default:
1197 		case AF_INET:
1198 		{
1199 			sockaddr_in& address = (sockaddr_in&)fAddress;
1200 			sockaddr_in& otherAddress = (sockaddr_in&)other.fAddress;
1201 			compare = memcmp(&address.sin_addr, &otherAddress.sin_addr,
1202 				sizeof(address.sin_addr));
1203 			break;
1204 		}
1205 
1206 		case AF_INET6:
1207 		{
1208 			sockaddr_in6& address = (sockaddr_in6&)fAddress;
1209 			sockaddr_in6& otherAddress = (sockaddr_in6&)other.fAddress;
1210 			compare = memcmp(&address.sin6_addr, &otherAddress.sin6_addr,
1211 				sizeof(address.sin6_addr));
1212 			break;
1213 		}
1214 
1215 		case AF_LINK:
1216 			if (LinkLevelAddressLength() < other.LinkLevelAddressLength())
1217 				return true;
1218 			if (LinkLevelAddressLength() > other.LinkLevelAddressLength())
1219 				return true;
1220 
1221 			// TODO: could compare index, and name, too
1222 			compare = memcmp(LinkLevelAddress(), other.LinkLevelAddress(),
1223 				LinkLevelAddressLength());
1224 			break;
1225 	}
1226 
1227 	if (compare < 0)
1228 		return true;
1229 	if (compare > 0)
1230 		return false;
1231 
1232 	return Port() < other.Port();
1233 }
1234 
1235 
1236 BNetworkAddress::operator const sockaddr*() const
1237 {
1238 	return (const sockaddr*)&fAddress;
1239 }
1240 
1241 
1242 BNetworkAddress::operator const sockaddr&() const
1243 {
1244 	return (const sockaddr&)fAddress;
1245 }
1246 
1247 
1248 BNetworkAddress::operator sockaddr*()
1249 {
1250 	return (sockaddr*)&fAddress;
1251 }
1252 
1253 
1254 BNetworkAddress::operator const sockaddr*()
1255 {
1256 	return (sockaddr*)&fAddress;
1257 }
1258 
1259 
1260 BNetworkAddress::operator sockaddr&()
1261 {
1262 	return (sockaddr&)fAddress;
1263 }
1264 
1265 
1266 BNetworkAddress::operator const sockaddr&()
1267 {
1268 	return (sockaddr&)fAddress;
1269 }
1270 
1271 
1272 // #pragma mark - private
1273 
1274 
1275 status_t
1276 BNetworkAddress::_ParseLinkAddress(const char* address)
1277 {
1278 	if (address == NULL)
1279 		return B_BAD_VALUE;
1280 
1281 	uint8 linkAddress[128];
1282 	uint32 length = 0;
1283 	while (length < sizeof(linkAddress)) {
1284 		if (!isxdigit(address[0]) || !isxdigit(address[1]))
1285 			return B_BAD_VALUE;
1286 
1287 		linkAddress[length++] = (from_hex(address[0]) << 4)
1288 			| from_hex(address[1]);
1289 
1290 		if (address[2] == '\0')
1291 			break;
1292 		if (address[2] != ':')
1293 			return B_BAD_VALUE;
1294 
1295 		address += 3;
1296 	}
1297 
1298 	fHostName = address;
1299 
1300 	SetToLinkLevel(linkAddress, length);
1301 	return B_OK;
1302 }
1303