1//
2// NetworkInterface.cpp
3//
4// Library: Net
5// Package: NetCore
6// Module: NetworkInterface
7//
8// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/Net/NetworkInterface.h"
16
17
18#ifdef POCO_NET_HAS_INTERFACE
19
20
21#include "Poco/Net/DatagramSocket.h"
22#include "Poco/Net/NetException.h"
23#include "Poco/NumberFormatter.h"
24#include "Poco/NumberParser.h"
25#include "Poco/StringTokenizer.h"
26#include "Poco/RefCountedObject.h"
27#include "Poco/Format.h"
28#if defined(POCO_OS_FAMILY_WINDOWS)
29 #include "Poco/Platform_WIN32_OSVER.h"
30 #include "Poco/UnicodeConverter.h"
31 #include "Poco/Error.h"
32 #include <wincrypt.h>
33 #include <iphlpapi.h>
34 #include <ipifcons.h>
35#endif
36#include <cstring>
37#include <fstream>
38#include <iostream>
39#include <iomanip>
40
41
42using Poco::NumberFormatter;
43using Poco::FastMutex;
44using Poco::format;
45
46
47std::ostream& operator << (std::ostream& os, const Poco::Net::NetworkInterface::MACAddress& mac)
48{
49 std::ios state(0);
50 state.copyfmt(os);
51 for (unsigned i = 0; i < mac.size(); ++i)
52 {
53 if (i > 0) os << Poco::Net::NetworkInterface::MAC_SEPARATOR;
54 os << std::hex << std::setw(2) << std::setfill('0') << (unsigned) mac[i];
55 }
56 os.copyfmt(state);
57 return os;
58}
59
60
61namespace Poco {
62namespace Net {
63
64
65//
66// NetworkInterfaceImpl
67//
68
69class NetworkInterfaceImpl: public Poco::RefCountedObject
70{
71public:
72 typedef NetworkInterface::AddressTuple AddressTuple;
73 typedef NetworkInterface::AddressList AddressList;
74 typedef NetworkInterface::Type Type;
75
76 NetworkInterfaceImpl(unsigned index);
77 NetworkInterfaceImpl(const std::string& name, const std::string& displayName, const std::string& adapterName, const IPAddress& address, unsigned index, NetworkInterface::MACAddress* pMACAddress = 0);
78 NetworkInterfaceImpl(const std::string& name, const std::string& displayName, const std::string& adapterName, unsigned index = 0, NetworkInterface::MACAddress* pMACAddress = 0);
79 NetworkInterfaceImpl(const std::string& name,
80 const std::string& displayName,
81 const std::string& adapterName,
82 const IPAddress& address,
83 const IPAddress& subnetMask,
84 const IPAddress& broadcastAddress,
85 unsigned index,
86 NetworkInterface::MACAddress* pMACAddress = 0);
87
88 unsigned index() const;
89 const std::string& name() const;
90 const std::string& displayName() const;
91 const std::string& adapterName() const;
92 const IPAddress& firstAddress(IPAddress::Family family) const;
93 void addAddress(const AddressTuple& address);
94 const IPAddress& address(unsigned index) const;
95 const NetworkInterface::AddressList& addressList() const;
96 bool hasAddress(const IPAddress& address) const;
97 const IPAddress& subnetMask(unsigned index) const;
98 const IPAddress& broadcastAddress(unsigned index) const;
99 const IPAddress& destAddress(unsigned index) const;
100 const NetworkInterface::MACAddress& macAddress() const;
101 bool supportsIPv4() const;
102 bool supportsIPv6() const;
103
104 void setName(const std::string& name);
105 void setDisplayName(const std::string& name);
106 void setAdapterName(const std::string& name);
107 void addAddress(const IPAddress& addr);
108 void setMACAddress(const NetworkInterface::MACAddress& addr);
109 void setMACAddress(const void *addr, std::size_t len);
110
111 unsigned mtu() const;
112 unsigned ifindex() const;
113 Type type() const;
114
115 bool broadcast() const;
116 bool loopback() const;
117 bool multicast() const;
118 bool pointToPoint() const;
119 bool running() const;
120 bool up() const;
121
122#if defined(POCO_OS_FAMILY_WINDOWS)
123 void setFlags(DWORD flags, DWORD iftype);
124 void setRunning(bool running);
125#else
126 void setFlags(short flags);
127#endif
128
129 void setUp(bool up);
130 void setMTU(unsigned mtu);
131 void setType(Type type);
132 void setIndex(unsigned index);
133 void setPhyParams();
134
135protected:
136 ~NetworkInterfaceImpl();
137
138private:
139 std::string _name;
140 std::string _displayName;
141 std::string _adapterName;
142 AddressList _addressList;
143 unsigned _index;
144 bool _broadcast;
145 bool _loopback;
146 bool _multicast;
147 bool _pointToPoint;
148 bool _up;
149 bool _running;
150 unsigned _mtu;
151 Type _type;
152
153 NetworkInterface::MACAddress _macAddress;
154
155 friend class NetworkInterface;
156};
157
158
159NetworkInterfaceImpl::NetworkInterfaceImpl(unsigned index):
160 _index(index),
161 _broadcast(false),
162 _loopback(false),
163 _multicast(false),
164 _pointToPoint(false),
165 _up(false),
166 _running(false),
167 _mtu(0),
168 _type(NetworkInterface::NI_TYPE_OTHER)
169{
170}
171
172
173NetworkInterfaceImpl::NetworkInterfaceImpl(const std::string& name, const std::string& displayName, const std::string& adapterName, const IPAddress& address, unsigned index, NetworkInterface::MACAddress* pMACAddress):
174 _name(name),
175 _displayName(displayName),
176 _adapterName(adapterName),
177 _index(index),
178 _broadcast(false),
179 _loopback(false),
180 _multicast(false),
181 _pointToPoint(false),
182 _up(false),
183 _running(false),
184 _mtu(0),
185 _type(NetworkInterface::NI_TYPE_OTHER)
186{
187 _addressList.push_back(AddressTuple(address, IPAddress(), IPAddress()));
188 setPhyParams();
189 if (pMACAddress) setMACAddress(*pMACAddress);
190}
191
192
193NetworkInterfaceImpl::NetworkInterfaceImpl(const std::string& name, const std::string& displayName, const std::string& adapterName, unsigned index, NetworkInterface::MACAddress* pMACAddress):
194 _name(name),
195 _displayName(displayName),
196 _adapterName(adapterName),
197 _index(index),
198 _broadcast(false),
199 _loopback(false),
200 _multicast(false),
201 _pointToPoint(false),
202 _up(false),
203 _running(false),
204 _mtu(0),
205 _type(NetworkInterface::NI_TYPE_OTHER)
206{
207 setPhyParams();
208 if (pMACAddress) setMACAddress(*pMACAddress);
209}
210
211
212NetworkInterfaceImpl::NetworkInterfaceImpl(const std::string& name,
213 const std::string& displayName,
214 const std::string& adapterName,
215 const IPAddress& address,
216 const IPAddress& subnetMask,
217 const IPAddress& broadcastAddress,
218 unsigned index,
219 NetworkInterface::MACAddress* pMACAddress):
220 _name(name),
221 _displayName(displayName),
222 _adapterName(adapterName),
223 _index(index),
224 _broadcast(false),
225 _loopback(false),
226 _multicast(false),
227 _pointToPoint(false),
228 _up(false),
229 _running(false),
230 _mtu(0),
231 _type(NetworkInterface::NI_TYPE_OTHER)
232{
233 _addressList.push_back(AddressTuple(address, subnetMask, broadcastAddress));
234 setPhyParams();
235 if (pMACAddress) setMACAddress(*pMACAddress);
236}
237
238
239void NetworkInterfaceImpl::setPhyParams()
240{
241#if !defined(POCO_OS_FAMILY_WINDOWS) && !defined(POCO_VXWORKS)
242 struct ifreq ifr;
243 std::strncpy(ifr.ifr_name, _name.c_str(), IFNAMSIZ);
244 DatagramSocket ds(SocketAddress::IPv4);
245
246 ds.impl()->ioctl(SIOCGIFFLAGS, &ifr);
247 setFlags(ifr.ifr_flags);
248
249 ds.impl()->ioctl(SIOCGIFMTU, &ifr);
250 setMTU(ifr.ifr_mtu);
251#endif
252}
253
254
255NetworkInterfaceImpl::~NetworkInterfaceImpl()
256{
257}
258
259
260bool NetworkInterfaceImpl::supportsIPv4() const
261{
262 AddressList::const_iterator it = _addressList.begin();
263 AddressList::const_iterator end = _addressList.end();
264 for (; it != end; ++it)
265 {
266 if (IPAddress::IPv4 == it->get<NetworkInterface::IP_ADDRESS>().family())
267 return true;
268 }
269
270 return false;
271}
272
273
274bool NetworkInterfaceImpl::supportsIPv6() const
275{
276#ifdef POCO_HAVE_IPv6
277 AddressList::const_iterator it = _addressList.begin();
278 AddressList::const_iterator end = _addressList.end();
279 for (; it != end; ++it)
280 {
281 if (IPAddress::IPv6 == it->get<NetworkInterface::IP_ADDRESS>().family())
282 return true;
283 }
284#endif
285 return false;
286}
287
288
289inline unsigned NetworkInterfaceImpl::index() const
290{
291 return _index;
292}
293
294
295inline const std::string& NetworkInterfaceImpl::name() const
296{
297 return _name;
298}
299
300
301inline const std::string& NetworkInterfaceImpl::displayName() const
302{
303 return _displayName;
304}
305
306
307inline const std::string& NetworkInterfaceImpl::adapterName() const
308{
309 return _adapterName;
310}
311
312
313const IPAddress& NetworkInterfaceImpl::firstAddress(IPAddress::Family family) const
314{
315 AddressList::const_iterator it = _addressList.begin();
316 AddressList::const_iterator end = _addressList.end();
317 for (;it != end; ++it)
318 {
319 const IPAddress& addr = it->get<NetworkInterface::IP_ADDRESS>();
320 if (addr.family() == family) return addr;
321 }
322
323 throw NotFoundException(format("%s family address not found.", (family == IPAddress::IPv4) ? std::string("IPv4") : std::string("IPv6")));
324}
325
326
327inline void NetworkInterfaceImpl::addAddress(const AddressTuple& address)
328{
329 _addressList.push_back(address);
330}
331
332
333bool NetworkInterfaceImpl::hasAddress(const IPAddress& address) const
334{
335 NetworkInterface::ConstAddressIterator it = _addressList.begin();
336 NetworkInterface::ConstAddressIterator end = _addressList.end();
337 for (; it != end; ++it)
338 {
339 if (it->get<NetworkInterface::IP_ADDRESS>() == address)
340 return true;
341 }
342 return false;
343}
344
345
346inline const IPAddress& NetworkInterfaceImpl::address(unsigned index) const
347{
348 if (index < _addressList.size()) return _addressList[index].get<NetworkInterface::IP_ADDRESS>();
349 else throw NotFoundException(Poco::format("No address with index %u.", index));
350}
351
352
353inline const NetworkInterface::AddressList& NetworkInterfaceImpl::addressList() const
354{
355 return _addressList;
356}
357
358
359const IPAddress& NetworkInterfaceImpl::subnetMask(unsigned index) const
360{
361 if (index < _addressList.size())
362 return _addressList[index].get<NetworkInterface::SUBNET_MASK>();
363
364 throw NotFoundException(Poco::format("No subnet mask with index %u.", index));
365}
366
367
368const IPAddress& NetworkInterfaceImpl::broadcastAddress(unsigned index) const
369{
370 if (index < _addressList.size())
371 return _addressList[index].get<NetworkInterface::BROADCAST_ADDRESS>();
372
373 throw NotFoundException(Poco::format("No subnet mask with index %u.", index));
374}
375
376
377const IPAddress& NetworkInterfaceImpl::destAddress(unsigned index) const
378{
379 if (!pointToPoint())
380 throw InvalidAccessException("Only PPP addresses have destination address.");
381 else if (index < _addressList.size())
382 return _addressList[index].get<NetworkInterface::BROADCAST_ADDRESS>();
383
384 throw NotFoundException(Poco::format("No address with index %u.", index));
385}
386
387
388const NetworkInterface::MACAddress& NetworkInterfaceImpl::macAddress() const
389{
390 return _macAddress;
391}
392
393
394inline unsigned NetworkInterfaceImpl::mtu() const
395{
396 return _mtu;
397}
398
399
400inline NetworkInterface::Type NetworkInterfaceImpl::type() const
401{
402 return _type;
403}
404
405
406inline bool NetworkInterfaceImpl::broadcast() const
407{
408 return _broadcast;
409}
410
411
412inline bool NetworkInterfaceImpl::loopback() const
413{
414 return _loopback;
415}
416
417
418inline bool NetworkInterfaceImpl::multicast() const
419{
420 return _multicast;
421}
422
423
424inline bool NetworkInterfaceImpl::pointToPoint() const
425{
426 return _pointToPoint;
427}
428
429
430inline bool NetworkInterfaceImpl::running() const
431{
432 return _running;
433}
434
435
436inline bool NetworkInterfaceImpl::up() const
437{
438 return _up;
439}
440
441
442#if defined(POCO_OS_FAMILY_WINDOWS)
443
444
445void NetworkInterfaceImpl::setFlags(DWORD flags, DWORD iftype)
446{
447 _running = _up = false;
448 switch (iftype) {
449 case IF_TYPE_ETHERNET_CSMACD:
450 case IF_TYPE_ISO88025_TOKENRING:
451 case IF_TYPE_IEEE80211:
452 _multicast = _broadcast = true;
453 break;
454 case IF_TYPE_SOFTWARE_LOOPBACK:
455 _loopback = true;
456 break;
457 case IF_TYPE_PPP:
458 case IF_TYPE_ATM:
459 case IF_TYPE_TUNNEL:
460 case IF_TYPE_IEEE1394:
461 _pointToPoint = true;
462 break;
463 }
464 if (!(flags & IP_ADAPTER_NO_MULTICAST))
465 _multicast = true;
466}
467
468
469void NetworkInterfaceImpl::setRunning(bool running)
470{
471 _running = running;
472}
473
474
475#else
476
477
478void NetworkInterfaceImpl::setFlags(short flags)
479{
480#ifdef POCO_OS_FAMILY_UNIX
481 _broadcast = ((flags & IFF_BROADCAST) != 0);
482 _loopback = ((flags & IFF_LOOPBACK) != 0);
483 _multicast = ((flags & IFF_MULTICAST) != 0);
484 _pointToPoint = ((flags & IFF_POINTOPOINT) != 0);
485 _running = ((flags & IFF_RUNNING) != 0);
486 _up = ((flags & IFF_UP) != 0);
487#endif
488}
489
490
491#endif
492
493
494inline void NetworkInterfaceImpl::setUp(bool up)
495{
496 _up = up;
497}
498
499
500inline void NetworkInterfaceImpl::setMTU(unsigned mtu)
501{
502 _mtu = mtu;
503}
504
505
506inline void NetworkInterfaceImpl::setType(Type type)
507{
508 _type = type;
509}
510
511
512inline void NetworkInterfaceImpl::setIndex(unsigned index)
513{
514 _index = index;
515}
516
517
518inline void NetworkInterfaceImpl::setName(const std::string& name)
519{
520 _name = name;
521}
522
523
524inline void NetworkInterfaceImpl::setDisplayName(const std::string& name)
525{
526 _displayName = name;
527}
528
529
530inline void NetworkInterfaceImpl::setAdapterName(const std::string& name)
531{
532 _adapterName = name;
533}
534
535
536inline void NetworkInterfaceImpl::addAddress(const IPAddress& addr)
537{
538 _addressList.push_back(addr);
539}
540
541
542inline void NetworkInterfaceImpl::setMACAddress(const NetworkInterface::MACAddress& addr)
543{
544 _macAddress = addr;
545}
546
547
548inline void NetworkInterfaceImpl::setMACAddress(const void *addr, std::size_t len)
549{
550 _macAddress.clear();
551 _macAddress.insert(_macAddress.end(), static_cast<const unsigned char*>(addr), static_cast<const unsigned char*>(addr) + len);
552}
553
554
555//
556// NetworkInterface
557//
558
559
560FastMutex NetworkInterface::_mutex;
561
562
563NetworkInterface::NetworkInterface(unsigned index):
564 _pImpl(new NetworkInterfaceImpl(index))
565{
566}
567
568
569NetworkInterface::NetworkInterface(const NetworkInterface& interfc):
570 _pImpl(interfc._pImpl)
571{
572 _pImpl->duplicate();
573}
574
575
576NetworkInterface::NetworkInterface(const std::string& name, const std::string& displayName, const std::string& adapterName, const IPAddress& address, unsigned index, MACAddress* pMACAddress):
577 _pImpl(new NetworkInterfaceImpl(name, displayName, adapterName, address, index, pMACAddress))
578{
579}
580
581
582NetworkInterface::NetworkInterface(const std::string& name, const std::string& displayName, const std::string& adapterName, unsigned index, MACAddress* pMACAddress):
583 _pImpl(new NetworkInterfaceImpl(name, displayName, adapterName, index, pMACAddress))
584{
585}
586
587
588NetworkInterface::NetworkInterface(const std::string& name, const IPAddress& address, unsigned index, MACAddress* pMACAddress):
589 _pImpl(new NetworkInterfaceImpl(name, name, name, address, index, pMACAddress))
590{
591}
592
593
594NetworkInterface::NetworkInterface(const std::string& name,
595 const std::string& displayName,
596 const std::string& adapterName,
597 const IPAddress& address,
598 const IPAddress& subnetMask,
599 const IPAddress& broadcastAddress,
600 unsigned index,
601 MACAddress* pMACAddress):
602 _pImpl(new NetworkInterfaceImpl(name, displayName, adapterName, address, subnetMask, broadcastAddress, index, pMACAddress))
603{
604}
605
606
607NetworkInterface::NetworkInterface(const std::string& name,
608 const IPAddress& address,
609 const IPAddress& subnetMask,
610 const IPAddress& broadcastAddress,
611 unsigned index,
612 MACAddress* pMACAddress):
613 _pImpl(new NetworkInterfaceImpl(name, name, name, address, subnetMask, broadcastAddress, index, pMACAddress))
614{
615}
616
617
618NetworkInterface::~NetworkInterface()
619{
620 _pImpl->release();
621}
622
623
624NetworkInterface& NetworkInterface::operator = (const NetworkInterface& interfc)
625{
626 NetworkInterface tmp(interfc);
627 swap(tmp);
628 return *this;
629}
630
631
632void NetworkInterface::swap(NetworkInterface& other)
633{
634 using std::swap;
635 swap(_pImpl, other._pImpl);
636}
637
638
639unsigned NetworkInterface::index() const
640{
641 return _pImpl->index();
642}
643
644
645const std::string& NetworkInterface::name() const
646{
647 return _pImpl->name();
648}
649
650
651const std::string& NetworkInterface::displayName() const
652{
653 return _pImpl->displayName();
654}
655
656
657const std::string& NetworkInterface::adapterName() const
658{
659 return _pImpl->adapterName();
660}
661
662
663const IPAddress& NetworkInterface::firstAddress(IPAddress::Family family) const
664{
665 return _pImpl->firstAddress(family);
666}
667
668
669void NetworkInterface::firstAddress(IPAddress& addr, IPAddress::Family family) const
670{
671 try
672 {
673 addr = firstAddress(family);
674 }
675 catch (NotFoundException&)
676 {
677 addr = IPAddress(family);
678 }
679}
680
681
682void NetworkInterface::addAddress(const IPAddress& address)
683{
684 _pImpl->addAddress(AddressTuple(address, IPAddress(), IPAddress()));
685}
686
687
688void NetworkInterface::addAddress(const IPAddress& address, const IPAddress& subnetMask, const IPAddress& broadcastAddress)
689{
690 _pImpl->addAddress(AddressTuple(address, subnetMask, broadcastAddress));
691}
692
693
694const IPAddress& NetworkInterface::address(unsigned index) const
695{
696 return _pImpl->address(index);
697}
698
699
700const NetworkInterface::AddressList& NetworkInterface::addressList() const
701{
702 return _pImpl->addressList();
703}
704
705
706const IPAddress& NetworkInterface::subnetMask(unsigned index) const
707{
708 return _pImpl->subnetMask(index);
709}
710
711
712const IPAddress& NetworkInterface::broadcastAddress(unsigned index) const
713{
714 return _pImpl->broadcastAddress(index);
715}
716
717
718const NetworkInterface::MACAddress& NetworkInterface::macAddress() const
719{
720 return _pImpl->macAddress();
721}
722
723
724const IPAddress& NetworkInterface::destAddress(unsigned index) const
725{
726 return _pImpl->destAddress(index);
727}
728
729
730unsigned NetworkInterface::mtu() const
731{
732 return _pImpl->mtu();
733}
734
735
736NetworkInterface::Type NetworkInterface::type() const
737{
738 return _pImpl->type();
739}
740
741
742bool NetworkInterface::supportsIP() const
743{
744 return _pImpl->supportsIPv4() || _pImpl->supportsIPv6();
745}
746
747
748bool NetworkInterface::supportsIPv4() const
749{
750 return _pImpl->supportsIPv4();
751}
752
753
754bool NetworkInterface::supportsIPv6() const
755{
756 return _pImpl->supportsIPv6();
757}
758
759
760bool NetworkInterface::supportsBroadcast() const
761{
762 return _pImpl->broadcast();
763}
764
765
766bool NetworkInterface::supportsMulticast() const
767{
768 return _pImpl->multicast();
769}
770
771
772bool NetworkInterface::isLoopback() const
773{
774 return _pImpl->loopback();
775}
776
777
778bool NetworkInterface::isPointToPoint() const
779{
780 return _pImpl->pointToPoint();
781}
782
783
784bool NetworkInterface::isRunning() const
785{
786 return _pImpl->running();
787}
788
789
790bool NetworkInterface::isUp() const
791{
792 return _pImpl->up();
793}
794
795
796NetworkInterface NetworkInterface::forName(const std::string& name, bool requireIPv6)
797{
798 if (requireIPv6)
799 return forName(name, IPv6_ONLY);
800 else
801 return forName(name, IPv4_OR_IPv6);
802}
803
804
805NetworkInterface NetworkInterface::forName(const std::string& name, IPVersion ipVersion)
806{
807 Map map = NetworkInterface::map(false, false);
808 Map::const_iterator it = map.begin();
809 Map::const_iterator end = map.end();
810
811 for (; it != end; ++it)
812 {
813 if (it->second.name() == name)
814 {
815 if (ipVersion == IPv4_ONLY && it->second.supportsIPv4())
816 return it->second;
817 else if (ipVersion == IPv6_ONLY && it->second.supportsIPv6())
818 return it->second;
819 else if (ipVersion == IPv4_OR_IPv6)
820 return it->second;
821 }
822 }
823 throw InterfaceNotFoundException(name);
824}
825
826
827NetworkInterface NetworkInterface::forAddress(const IPAddress& addr)
828{
829 Map map = NetworkInterface::map(true, false);
830 Map::const_iterator it = map.begin();
831 Map::const_iterator end = map.end();
832
833 for (; it != end; ++it)
834 {
835 const std::size_t count = it->second.addressList().size();
836 for (int i = 0; i < count; ++i)
837 {
838 if (it->second.address(i) == addr)
839 return it->second;
840 }
841 }
842 throw InterfaceNotFoundException(addr.toString());
843}
844
845
846NetworkInterface NetworkInterface::forIndex(unsigned i)
847{
848 if (i != NetworkInterface::NO_INDEX)
849 {
850 Map map = NetworkInterface::map(false, false);
851 Map::const_iterator it = map.find(i);
852 if (it != map.end())
853 return it->second;
854 else
855 throw InterfaceNotFoundException("#" + NumberFormatter::format(i));
856 }
857 throw InterfaceNotFoundException("#" + NumberFormatter::format(i));
858}
859
860
861NetworkInterface::List NetworkInterface::list(bool ipOnly, bool upOnly)
862{
863 List list;
864 Map m = map(ipOnly, upOnly);
865 NetworkInterface::Map::const_iterator it = m.begin();
866 NetworkInterface::Map::const_iterator end = m.end();
867 for (; it != end; ++it)
868 {
869 int index = it->second.index();
870 std::string name = it->second.name();
871 std::string displayName = it->second.displayName();
872 std::string adapterName = it->second.adapterName();
873 NetworkInterface::MACAddress mac = it->second.macAddress();
874
875 typedef NetworkInterface::AddressList List;
876 const List& ipList = it->second.addressList();
877 List::const_iterator ipIt = ipList.begin();
878 List::const_iterator ipEnd = ipList.end();
879 for (; ipIt != ipEnd; ++ipIt)
880 {
881 IPAddress addr = ipIt->get<NetworkInterface::IP_ADDRESS>();
882 IPAddress mask = ipIt->get<NetworkInterface::SUBNET_MASK>();
883 NetworkInterface ni;
884 if (mask.isWildcard())
885 {
886 ni = NetworkInterface(name, displayName, adapterName, addr, index, &mac);
887 }
888 else
889 {
890 IPAddress broadcast = ipIt->get<NetworkInterface::BROADCAST_ADDRESS>();
891 ni = NetworkInterface(name, displayName, adapterName, addr, mask, broadcast, index, &mac);
892 }
893
894 ni._pImpl->_broadcast = it->second._pImpl->_broadcast;
895 ni._pImpl->_loopback = it->second._pImpl->_loopback;
896 ni._pImpl->_multicast = it->second._pImpl->_multicast;
897 ni._pImpl->_pointToPoint = it->second._pImpl->_pointToPoint;
898 ni._pImpl->_up = it->second._pImpl->_up;
899 ni._pImpl->_running = it->second._pImpl->_running;
900 ni._pImpl->_mtu = it->second._pImpl->_mtu;
901 ni._pImpl->_type = it->second._pImpl->_type;
902
903 list.push_back(ni);
904 }
905 }
906
907 return list;
908}
909
910
911} } // namespace Poco::Net
912
913
914//
915// platform-specific code below
916//
917
918
919#if defined(POCO_OS_FAMILY_WINDOWS)
920//
921// Windows
922//
923
924
925#include "Poco/Buffer.h"
926#include <iterator>
927
928
929namespace Poco {
930namespace Net {
931
932
933namespace {
934
935
936IPAddress getBroadcastAddress(PIP_ADAPTER_PREFIX pPrefix, const IPAddress& addr, ULONG* pprefix = 0)
937 /// This function relies on (1) subnet prefix being at the position
938 /// immediately preceding and (2) broadcast address being at the position
939 /// immediately succeeding the IPv4 unicast address.
940 ///
941 /// Since there is no explicit guarantee on order, to ensure correctness,
942 /// the above constraints are checked prior to returning the result.
943 /// Additionally, on pre-Vista versions on Windows, the main structure does
944 /// not contain prefix length; for those platforms, this function
945 /// returns prefix through pprefix argument.
946{
947 PIP_ADAPTER_PREFIX pPrev = 0;
948 for (int i = 0; pPrefix; pPrefix = pPrefix->Next, ++i)
949 {
950 ADDRESS_FAMILY family = pPrefix->Address.lpSockaddr->sa_family;
951 if ((family == AF_INET) && (addr == IPAddress(pPrefix->Address)))
952 break;
953 pPrev = pPrefix;
954 }
955
956 if (pPrefix && pPrefix->Next && pPrev)
957 {
958 IPAddress ipPrefix(pPrev->PrefixLength, IPAddress::IPv4);
959 IPAddress mask(pPrefix->Next->Address);
960 if ((ipPrefix & mask) == (ipPrefix & addr))
961 {
962 if (pprefix) *pprefix = pPrefix->PrefixLength;
963 return IPAddress(pPrefix->Next->Address);
964 }
965 }
966
967 return IPAddress(IPAddress::IPv4);
968}
969
970
971NetworkInterface::Type fromNative(DWORD type)
972{
973 switch (type)
974 {
975 case IF_TYPE_ETHERNET_CSMACD: return NetworkInterface::NI_TYPE_ETHERNET_CSMACD;
976 case IF_TYPE_ISO88025_TOKENRING: return NetworkInterface::NI_TYPE_ISO88025_TOKENRING;
977 case IF_TYPE_FRAMERELAY: return NetworkInterface::NI_TYPE_FRAMERELAY;
978 case IF_TYPE_PPP: return NetworkInterface::NI_TYPE_PPP;
979 case IF_TYPE_SOFTWARE_LOOPBACK: return NetworkInterface::NI_TYPE_SOFTWARE_LOOPBACK;
980 case IF_TYPE_ATM: return NetworkInterface::NI_TYPE_ATM;
981 case IF_TYPE_IEEE80211: return NetworkInterface::NI_TYPE_IEEE80211;
982 case IF_TYPE_TUNNEL: return NetworkInterface::NI_TYPE_TUNNEL;
983 case IF_TYPE_IEEE1394: return NetworkInterface::NI_TYPE_IEEE1394;
984 default: return NetworkInterface::NI_TYPE_OTHER;
985 }
986}
987
988
989IPAddress subnetMaskForInterface(const std::string& name, bool isLoopback)
990{
991 if (isLoopback)
992 {
993 return IPAddress::parse("255.0.0.0");
994 }
995 else
996 {
997#if !defined(_WIN32_WCE)
998 std::string subKey("SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces\\");
999 subKey += name;
1000 std::string netmask;
1001 HKEY hKey;
1002#if !defined(POCO_NO_WSTRING)
1003 std::wstring usubKey;
1004 Poco::UnicodeConverter::toUTF16(subKey, usubKey);
1005 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, usubKey.c_str(), 0, KEY_READ, &hKey) != ERROR_SUCCESS)
1006 return IPAddress();
1007 wchar_t unetmask[16];
1008 DWORD size = sizeof(unetmask);
1009 if (RegQueryValueExW(hKey, L"DhcpSubnetMask", NULL, NULL, (LPBYTE)&unetmask, &size) != ERROR_SUCCESS)
1010 {
1011 if (RegQueryValueExW(hKey, L"SubnetMask", NULL, NULL, (LPBYTE)&unetmask, &size) != ERROR_SUCCESS)
1012 {
1013 RegCloseKey(hKey);
1014 return IPAddress();
1015 }
1016 }
1017 Poco::UnicodeConverter::toUTF8(unetmask, netmask);
1018#endif
1019 RegCloseKey(hKey);
1020 return IPAddress::parse(netmask);
1021#else
1022 return IPAddress();
1023#endif // !defined(_WIN32_WCE)
1024 }
1025}
1026
1027
1028} /// namespace
1029
1030
1031NetworkInterface::Map NetworkInterface::map(bool ipOnly, bool upOnly)
1032{
1033 OSVERSIONINFO osvi;
1034 ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
1035 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1036 GetVersionEx(&osvi);
1037
1038 FastMutex::ScopedLock lock(_mutex);
1039 Map result;
1040 ULONG outBufLen = 16384;
1041 Poco::Buffer<UCHAR> memory(outBufLen);
1042 ULONG flags = (GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX);
1043#ifdef GAA_FLAG_INCLUDE_ALL_INTERFACES
1044 flags |= GAA_FLAG_INCLUDE_ALL_INTERFACES;
1045#endif
1046#if defined(POCO_HAVE_IPv6)
1047 const unsigned family = AF_UNSPEC; //IPv4 and IPv6
1048#else
1049 const unsigned family = AF_INET; //IPv4 only
1050#endif
1051 DWORD dwRetVal = 0;
1052 ULONG iterations = 0;
1053 PIP_ADAPTER_ADDRESSES pAddress = 0;
1054 do
1055 {
1056 pAddress = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(memory.begin()); // leave in the loop, begin may change after resize
1057 poco_assert (memory.capacity() >= outBufLen);
1058 if (ERROR_BUFFER_OVERFLOW == (dwRetVal = GetAdaptersAddresses(family, flags, 0, pAddress, &outBufLen)))
1059 memory.resize(outBufLen, false); // adjust size and try again
1060 else if (ERROR_NO_DATA == dwRetVal) // no network interfaces found
1061 return result;
1062 else if (NO_ERROR != dwRetVal) // error occurred
1063 throw SystemException(format("An error occurred while trying to obtain list of network interfaces: [%s]", Error::getMessage(dwRetVal)));
1064 else
1065 break;
1066 }
1067 while ((ERROR_BUFFER_OVERFLOW == dwRetVal) && (++iterations <= 2));
1068
1069 poco_assert (NO_ERROR == dwRetVal);
1070 for (; pAddress; pAddress = pAddress->Next)
1071 {
1072 IPAddress address;
1073 IPAddress subnetMask;
1074 IPAddress broadcastAddress;
1075 unsigned ifIndex = 0;
1076
1077#if defined(POCO_HAVE_IPv6)
1078 #if defined(_WIN32_WCE)
1079 ifIndex = pAddress->Ipv6IfIndex;
1080 #elif (_WIN32_WINNT >= 0x0501) && (NTDDI_VERSION >= 0x05010100) // Win XP SP1
1081 #if defined (IP_ADAPTER_IPV6_ENABLED) // Vista
1082 if(osvi.dwMajorVersion>=6)//vista
1083 {
1084 if ((pAddress->Flags & IP_ADAPTER_IPV6_ENABLED) &&
1085 (osvi.dwMajorVersion >= 5) &&
1086 (osvi.dwMinorVersion >= 1) &&
1087 (osvi.dwBuildNumber >=1))
1088 {
1089 ifIndex = pAddress->Ipv6IfIndex;
1090 }
1091 }
1092 else
1093 {
1094 if ((osvi.dwMajorVersion >= 5) &&
1095 (osvi.dwMinorVersion >= 1) &&
1096 (osvi.dwBuildNumber >= 1))
1097 {
1098 ifIndex = pAddress->Ipv6IfIndex;
1099 }
1100 }
1101 #else // !defined(IP_ADAPTER_IPV6_ENABLED)
1102 if ((osvi.dwMajorVersion >= 5) &&
1103 (osvi.dwMinorVersion >= 1) &&
1104 (osvi.dwBuildNumber >= 1))
1105 {
1106 ifIndex = pAddress->Ipv6IfIndex;
1107 }
1108 #endif // defined(IP_ADAPTER_IPV6_ENABLED)
1109 #endif // (_WIN32_WINNT >= 0x0501) && (NTDDI_VERSION >= 0x05010100)
1110#endif // POCO_HAVE_IPv6
1111
1112#if defined (IP_ADAPTER_IPV4_ENABLED)
1113 if(osvi.dwMajorVersion>=6)
1114 {//vista
1115 if (pAddress->Flags & IP_ADAPTER_IPV4_ENABLED)
1116 {
1117 ifIndex = pAddress->IfIndex;
1118 }
1119 }
1120 else
1121 {
1122 ifIndex = pAddress->IfIndex;
1123 }
1124#else // !IP_ADAPTER_IPV4_ENABLED
1125 ifIndex = pAddress->IfIndex;
1126#endif
1127 if (ifIndex == 0) continue;
1128
1129 std::string name;
1130 std::string displayName;
1131 std::string adapterName(pAddress->AdapterName);
1132 Poco::UnicodeConverter::toUTF8(pAddress->FriendlyName, name);
1133 Poco::UnicodeConverter::toUTF8(pAddress->Description, displayName);
1134
1135 bool isUp = (pAddress->OperStatus == IfOperStatusUp);
1136 bool isIP = (0 != pAddress->FirstUnicastAddress);
1137 if (((ipOnly && isIP) || !ipOnly) && ((upOnly && isUp) || !upOnly))
1138 {
1139 NetworkInterface ni(name, displayName, adapterName, ifIndex);
1140 // Create interface even if it has an empty list of addresses; also, set
1141 // physical attributes which are protocol independent (name, media type,
1142 // MAC address, MTU, operational status, etc).
1143 Map::iterator ifIt = result.find(ifIndex);
1144 if (ifIt == result.end())
1145 ifIt = result.insert(Map::value_type(ifIndex, ni)).first;
1146
1147 ifIt->second.impl().setFlags(pAddress->Flags, pAddress->IfType);
1148 ifIt->second.impl().setMTU(pAddress->Mtu);
1149 ifIt->second.impl().setUp(pAddress->OperStatus == IfOperStatusUp);
1150#if (_WIN32_WINNT >= 0x0600) // Vista and newer only
1151 if ((osvi.dwMajorVersion >= 6) &&
1152 (osvi.dwMinorVersion >= 0) &&
1153 (osvi.dwBuildNumber >= 0))
1154 {
1155 ifIt->second.impl().setRunning(pAddress->ReceiveLinkSpeed > 0 || pAddress->TransmitLinkSpeed > 0);
1156 }
1157#endif
1158 ifIt->second.impl().setType(fromNative(pAddress->IfType));
1159 if (pAddress->PhysicalAddressLength)
1160 ifIt->second.impl().setMACAddress(pAddress->PhysicalAddress, pAddress->PhysicalAddressLength);
1161
1162 for (PIP_ADAPTER_UNICAST_ADDRESS pUniAddr = pAddress->FirstUnicastAddress;
1163 pUniAddr;
1164 pUniAddr = pUniAddr->Next)
1165 {
1166 address = IPAddress(pUniAddr->Address);
1167 ADDRESS_FAMILY family = pUniAddr->Address.lpSockaddr->sa_family;
1168 switch (family)
1169 {
1170 case AF_INET:
1171 {
1172 // Windows lists broadcast address on localhost
1173 bool hasBroadcast = (pAddress->IfType == IF_TYPE_ETHERNET_CSMACD) || (pAddress->IfType == IF_TYPE_SOFTWARE_LOOPBACK) || (pAddress->IfType == IF_TYPE_IEEE80211);
1174 if (hasBroadcast)
1175 {
1176 // On Windows, a valid broadcast address will be all 1's (== address | ~subnetMask); additionally, on pre-Vista versions of
1177 // OS, master address structure does not contain member for prefix length; we go an extra mile here in order to make sure
1178 // we reflect the actual values held by system and protect against misconfiguration (e.g. bad DHCP config entry)
1179 ULONG prefixLength = 0;
1180#if defined(_WIN32_WCE)
1181 #if _WIN32_WCE >= 0x0800
1182 prefixLength = pUniAddr->OnLinkPrefixLength;
1183 broadcastAddress = getBroadcastAddress(pAddress->FirstPrefix, address);
1184 #else
1185 broadcastAddress = getBroadcastAddress(pAddress->FirstPrefix, address, &prefixLength);
1186 #endif
1187 // if previous call did not do it, make last-ditch attempt for prefix and broadcast
1188 if (prefixLength == 0 && pAddress->FirstPrefix)
1189 prefixLength = pAddress->FirstPrefix->PrefixLength;
1190 poco_assert (prefixLength <= 32);
1191 if (broadcastAddress.isWildcard())
1192 {
1193 IPAddress mask(static_cast<unsigned>(prefixLength), IPAddress::IPv4);
1194 IPAddress host(mask & address);
1195 broadcastAddress = host | ~mask;
1196 }
1197#elif (_WIN32_WINNT >= 0x0501) && (NTDDI_VERSION >= 0x05010100) // Win XP SP1
1198 #if (_WIN32_WINNT >= 0x0600) // Vista and newer
1199 if (osvi.dwMajorVersion >= 6)
1200 {
1201 prefixLength = pUniAddr->OnLinkPrefixLength;
1202 broadcastAddress = getBroadcastAddress(pAddress->FirstPrefix, address);
1203 }
1204 else
1205 {
1206 broadcastAddress = getBroadcastAddress(pAddress->FirstPrefix, address, &prefixLength);
1207 }
1208 #else
1209 broadcastAddress = getBroadcastAddress(pAddress->FirstPrefix, address, &prefixLength);
1210 #endif
1211 poco_assert (prefixLength <= 32);
1212 if (broadcastAddress.isWildcard())
1213 {
1214 IPAddress mask(static_cast<unsigned>(prefixLength), IPAddress::IPv4);
1215 IPAddress host(mask & address);
1216 broadcastAddress = host | ~mask;
1217 }
1218#endif // (_WIN32_WINNT >= 0x0501) && (NTDDI_VERSION >= 0x05010100)
1219 if (prefixLength)
1220 {
1221 subnetMask = IPAddress(static_cast<unsigned>(prefixLength), IPAddress::IPv4);
1222 }
1223 else // if all of the above fails, look up the subnet mask in the registry
1224 {
1225 address = IPAddress(&reinterpret_cast<struct sockaddr_in*>(pUniAddr->Address.lpSockaddr)->sin_addr, sizeof(in_addr));
1226 subnetMask = subnetMaskForInterface(name, address.isLoopback());
1227 if (!address.isLoopback())
1228 {
1229 broadcastAddress = address;
1230 broadcastAddress.mask(subnetMask, IPAddress::broadcast());
1231 }
1232 }
1233 ifIt->second.addAddress(address, subnetMask, broadcastAddress);
1234 }
1235 else
1236 {
1237 ifIt->second.addAddress(address);
1238 }
1239 }
1240 break;
1241#if defined(POCO_HAVE_IPv6)
1242 case AF_INET6:
1243 ifIt->second.addAddress(address);
1244 break;
1245#endif
1246 } // switch family
1247 } // for addresses
1248 } // if ipOnly/upOnly
1249 } // for adapters
1250 return result;
1251}
1252
1253
1254} } // namespace Poco::Net
1255
1256
1257#elif defined(POCO_VXWORKS)
1258//
1259// VxWorks
1260//
1261
1262#error TODO
1263
1264/*
1265namespace Poco {
1266namespace Net {
1267
1268
1269NetworkInterface::NetworkInterfaceList NetworkInterface::list()
1270{
1271 FastMutex::ScopedLock lock(_mutex);
1272 NetworkInterfaceList result;
1273
1274 int ifIndex = 1;
1275 char ifName[32];
1276 char ifAddr[INET_ADDR_LEN];
1277
1278 for (;;)
1279 {
1280 if (ifIndexToIfName(ifIndex, ifName) == OK)
1281 {
1282 std::string name(ifName);
1283 IPAddress addr;
1284 IPAddress mask;
1285 IPAddress bcst;
1286 if (ifAddrGet(ifName, ifAddr) == OK)
1287 {
1288 addr = IPAddress(std::string(ifAddr));
1289 }
1290 int ifMask;
1291 if (ifMaskGet(ifName, &ifMask) == OK)
1292 {
1293 mask = IPAddress(&ifMask, sizeof(ifMask));
1294 }
1295 if (ifBroadcastGet(ifName, ifAddr) == OK)
1296 {
1297 bcst = IPAddress(std::string(ifAddr));
1298 }
1299 result.push_back(NetworkInterface(name, name, name, addr, mask, bcst));
1300 ifIndex++;
1301 }
1302 else break;
1303 }
1304
1305 return result;
1306}
1307
1308
1309} } // namespace Poco::Net
1310*/
1311
1312#elif defined(POCO_OS_FAMILY_BSD) || (POCO_OS == POCO_OS_QNX) || (POCO_OS == POCO_OS_SOLARIS)
1313//
1314// BSD variants, QNX(?) and Solaris
1315//
1316#include <sys/types.h>
1317#include <sys/socket.h>
1318#include <ifaddrs.h>
1319#include <net/if.h>
1320#include <net/if_dl.h>
1321#ifndef POCO_NO_NET_IFTYPES
1322#include <net/if_types.h>
1323#endif
1324
1325
1326namespace Poco {
1327namespace Net {
1328
1329
1330namespace {
1331
1332
1333NetworkInterface::Type fromNative(u_char nativeType)
1334{
1335 switch (nativeType)
1336 {
1337#ifndef POCO_NO_NET_IFTYPES
1338 case IFT_ETHER: return NetworkInterface::NI_TYPE_ETHERNET_CSMACD;
1339 case IFT_ISO88025: return NetworkInterface::NI_TYPE_ISO88025_TOKENRING;
1340 case IFT_FRELAY: return NetworkInterface::NI_TYPE_FRAMERELAY;
1341 case IFT_PPP: return NetworkInterface::NI_TYPE_PPP;
1342 case IFT_LOOP: return NetworkInterface::NI_TYPE_SOFTWARE_LOOPBACK;
1343 case IFT_ATM: return NetworkInterface::NI_TYPE_ATM;
1344#if (POCO_OS != POCO_OS_SOLARIS)
1345 case IFT_IEEE1394: return NetworkInterface::NI_TYPE_IEEE1394;
1346#endif
1347#endif
1348 default: return NetworkInterface::NI_TYPE_OTHER;
1349
1350 }
1351}
1352
1353
1354void setInterfaceParams(struct ifaddrs* iface, NetworkInterfaceImpl& impl)
1355{
1356 struct sockaddr_dl* sdl = (struct sockaddr_dl*) iface->ifa_addr;
1357 impl.setName(iface->ifa_name);
1358 impl.setDisplayName(iface->ifa_name);
1359 impl.setAdapterName(iface->ifa_name);
1360 impl.setPhyParams();
1361
1362 impl.setMACAddress(LLADDR(sdl), sdl->sdl_alen);
1363 impl.setType(fromNative(sdl->sdl_type));
1364}
1365
1366
1367} // namespace
1368
1369
1370NetworkInterface::Map NetworkInterface::map(bool ipOnly, bool upOnly)
1371{
1372 FastMutex::ScopedLock lock(_mutex);
1373 Map result;
1374 unsigned ifIndex = 0;
1375 NetworkInterface intf;
1376 Map::iterator ifIt;
1377
1378 struct ifaddrs* ifaces = 0;
1379 struct ifaddrs* currIface = 0;
1380
1381 if (getifaddrs(&ifaces) < 0)
1382 throw NetException("cannot get network adapter list");
1383
1384 try
1385 {
1386 for (currIface = ifaces; currIface != 0; currIface = currIface->ifa_next)
1387 {
1388 if (!currIface->ifa_addr) continue;
1389
1390 IPAddress address, subnetMask, broadcastAddress;
1391 unsigned family = currIface->ifa_addr->sa_family;
1392 switch (family)
1393 {
1394#if defined(POCO_OS_FAMILY_BSD)
1395 case AF_LINK:
1396 {
1397 struct sockaddr_dl* sdl = (struct sockaddr_dl*) currIface->ifa_addr;
1398 ifIndex = sdl->sdl_index;
1399 intf = NetworkInterface(ifIndex);
1400 setInterfaceParams(currIface, intf.impl());
1401 if ((result.find(ifIndex) == result.end()) && ((upOnly && intf.isUp()) || !upOnly))
1402 ifIt = result.insert(Map::value_type(ifIndex, intf)).first;
1403 break;
1404 }
1405#endif
1406 case AF_INET:
1407 ifIndex = if_nametoindex(currIface->ifa_name);
1408 ifIt = result.find(ifIndex);
1409 intf = NetworkInterface(ifIndex);
1410 setInterfaceParams(currIface, intf.impl());
1411 if ((ifIt == result.end()) && ((upOnly && intf.isUp()) || !upOnly))
1412 ifIt = result.insert(Map::value_type(ifIndex, intf)).first;
1413
1414 address = IPAddress(*(currIface->ifa_addr));
1415
1416 if (( currIface->ifa_flags & IFF_LOOPBACK ) == 0 && currIface->ifa_netmask)
1417 subnetMask = IPAddress(*(currIface->ifa_netmask));
1418
1419 if (currIface->ifa_flags & IFF_BROADCAST && currIface->ifa_broadaddr)
1420 broadcastAddress = IPAddress(*(currIface->ifa_broadaddr));
1421 else if (currIface->ifa_flags & IFF_POINTOPOINT && currIface->ifa_dstaddr)
1422 broadcastAddress = IPAddress(*(currIface->ifa_dstaddr));
1423 else
1424 broadcastAddress = IPAddress();
1425 break;
1426#if defined(POCO_HAVE_IPv6)
1427 case AF_INET6:
1428 ifIndex = if_nametoindex(currIface->ifa_name);
1429 ifIt = result.find(ifIndex);
1430 intf = NetworkInterface(ifIndex);
1431 setInterfaceParams(currIface, intf.impl());
1432 if ((ifIt == result.end()) && ((upOnly && intf.isUp()) || !upOnly))
1433 ifIt = result.insert(Map::value_type(ifIndex, intf)).first;
1434
1435 address = IPAddress(&reinterpret_cast<const struct sockaddr_in6*>(currIface->ifa_addr)->sin6_addr,
1436 sizeof(struct in6_addr), ifIndex);
1437 subnetMask = IPAddress(*(currIface->ifa_netmask));
1438 broadcastAddress = IPAddress();
1439 break;
1440#endif
1441 default:
1442 continue;
1443 }
1444
1445 if (family == AF_INET
1446#ifdef POCO_HAVE_IPv6
1447 || family == AF_INET6
1448#endif
1449 )
1450 {
1451 if ((upOnly && intf.isUp()) || !upOnly)
1452 {
1453 if ((ifIt = result.find(ifIndex)) != result.end())
1454 ifIt->second.addAddress(address, subnetMask, broadcastAddress);
1455 }
1456 }
1457 }
1458 }
1459 catch (...)
1460 {
1461 }
1462 if (ifaces) freeifaddrs(ifaces);
1463
1464 if (ipOnly)
1465 {
1466 Map::iterator it = result.begin();
1467 Map::iterator end = result.end();
1468 for (; it != end;)
1469 {
1470 if (!it->second.supportsIPv4() && !it->second.supportsIPv6())
1471 result.erase(it++);
1472 else ++it;
1473 }
1474 }
1475
1476 return result;
1477}
1478
1479
1480} } // namespace Poco::Net
1481
1482
1483#elif POCO_OS == POCO_OS_LINUX
1484//
1485// Linux
1486//
1487
1488
1489#include <sys/types.h>
1490#ifndef POCO_ANDROID // Android doesn't have <ifaddrs.h>
1491#include <ifaddrs.h>
1492#endif
1493#include <net/if.h>
1494#ifndef POCO_NO_LINUX_IF_PACKET_H
1495#include <linux/if_packet.h>
1496#endif
1497#include <net/if_arp.h>
1498#include <iostream>
1499
1500namespace Poco {
1501namespace Net {
1502
1503
1504namespace {
1505
1506
1507static NetworkInterface::Type fromNative(unsigned arphrd)
1508{
1509 switch (arphrd)
1510 {
1511 case ARPHRD_ETHER: return NetworkInterface::NI_TYPE_ETHERNET_CSMACD;
1512 case ARPHRD_IEEE802: return NetworkInterface::NI_TYPE_ISO88025_TOKENRING;
1513 case ARPHRD_DLCI: return NetworkInterface::NI_TYPE_FRAMERELAY;
1514 case ARPHRD_PPP: return NetworkInterface::NI_TYPE_PPP;
1515 case ARPHRD_LOOPBACK: return NetworkInterface::NI_TYPE_SOFTWARE_LOOPBACK;
1516 case ARPHRD_ATM: return NetworkInterface::NI_TYPE_ATM;
1517 case ARPHRD_IEEE80211: return NetworkInterface::NI_TYPE_IEEE80211;
1518 case ARPHRD_TUNNEL:
1519 case ARPHRD_TUNNEL6: return NetworkInterface::NI_TYPE_TUNNEL;
1520 case ARPHRD_IEEE1394: return NetworkInterface::NI_TYPE_IEEE1394;
1521 default: return NetworkInterface::NI_TYPE_OTHER;
1522 }
1523}
1524
1525#ifndef POCO_ANDROID
1526
1527void setInterfaceParams(struct ifaddrs* iface, NetworkInterfaceImpl& impl)
1528{
1529 impl.setName(iface->ifa_name);
1530 impl.setDisplayName(iface->ifa_name);
1531 impl.setAdapterName(iface->ifa_name);
1532 impl.setPhyParams();
1533
1534#ifndef POCO_NO_LINUX_IF_PACKET_H
1535 struct sockaddr_ll* sdl = (struct sockaddr_ll*) iface->ifa_addr;
1536 impl.setMACAddress(sdl->sll_addr, sdl->sll_halen);
1537 impl.setType(fromNative(sdl->sll_hatype));
1538#else
1539 std::string ifPath("/sys/class/net/");
1540 ifPath += iface->ifa_name;
1541
1542 std::string addrPath(ifPath);
1543 addrPath += "/address";
1544
1545 std::ifstream addrStream(addrPath.c_str());
1546 if (addrStream.good())
1547 {
1548 std::string addr;
1549 std::getline(addrStream, addr);
1550 Poco::StringTokenizer tok(addr, ":");
1551 std::vector<unsigned char> mac;
1552 for (Poco::StringTokenizer::Iterator it = tok.begin(); it != tok.end(); ++it)
1553 {
1554 mac.push_back(static_cast<unsigned char>(Poco::NumberParser::parseHex(*it)));
1555 }
1556 impl.setMACAddress(&mac[0], mac.size());
1557 addrStream.close();
1558 }
1559
1560 std::string typePath(ifPath);
1561 typePath += "/type";
1562 std::ifstream typeStream(typePath.c_str());
1563 if (typeStream.good())
1564 {
1565 int type;
1566 typeStream >> type;
1567 impl.setType(fromNative(type));
1568 typeStream.close();
1569 }
1570#endif // POCO_NO_LINUX_IF_PACKET_H
1571}
1572
1573#endif
1574
1575
1576}
1577
1578
1579NetworkInterface::Map NetworkInterface::map(bool ipOnly, bool upOnly)
1580{
1581#ifndef POCO_ANDROID
1582 FastMutex::ScopedLock lock(_mutex);
1583 Map result;
1584 unsigned ifIndex = 0;
1585 NetworkInterface intf;
1586 Map::iterator ifIt;
1587
1588 struct ifaddrs* ifaces = 0;
1589 struct ifaddrs* iface = 0;
1590
1591 if (getifaddrs(&ifaces) < 0)
1592 throw NetException("cannot get network adapter list");
1593
1594 try
1595 {
1596 for (iface = ifaces; iface; iface = iface->ifa_next)
1597 {
1598 if (!iface->ifa_addr) continue;
1599
1600 IPAddress address, subnetMask, broadcastAddress;
1601 unsigned family = iface->ifa_addr->sa_family;
1602 switch (family)
1603 {
1604#ifndef POCO_NO_LINUX_IF_PACKET_H
1605 case AF_PACKET:
1606 {
1607 struct sockaddr_ll* sll = (struct sockaddr_ll*)iface->ifa_addr;
1608 ifIndex = sll->sll_ifindex;
1609 intf = NetworkInterface(ifIndex);
1610 setInterfaceParams(iface, intf.impl());
1611
1612 if ((result.find(ifIndex) == result.end()) && ((upOnly && intf.isUp()) || !upOnly))
1613 ifIt = result.insert(Map::value_type(ifIndex, intf)).first;
1614
1615 break;
1616 }
1617#endif // POCO_NO_LINUX_IF_PACKET_H
1618 case AF_INET:
1619 ifIndex = if_nametoindex(iface->ifa_name);
1620 ifIt = result.find(ifIndex);
1621 intf = NetworkInterface(ifIndex);
1622 setInterfaceParams(iface, intf.impl());
1623
1624 if ((ifIt == result.end()) && ((upOnly && intf.isUp()) || !upOnly))
1625 ifIt = result.insert(Map::value_type(ifIndex, intf)).first;
1626
1627 address = IPAddress(*(iface->ifa_addr));
1628 subnetMask = IPAddress(*(iface->ifa_netmask));
1629
1630 if (iface->ifa_flags & IFF_BROADCAST && iface->ifa_broadaddr)
1631 broadcastAddress = IPAddress(*(iface->ifa_broadaddr));
1632 else if (iface->ifa_flags & IFF_POINTOPOINT && iface->ifa_dstaddr)
1633 broadcastAddress = IPAddress(*(iface->ifa_dstaddr));
1634 else
1635 broadcastAddress = IPAddress();
1636
1637 break;
1638#if defined(POCO_HAVE_IPv6)
1639 case AF_INET6:
1640 ifIndex = if_nametoindex(iface->ifa_name);
1641 ifIt = result.find(ifIndex);
1642 intf = NetworkInterface(ifIndex);
1643 setInterfaceParams(iface, intf.impl());
1644
1645 if ((ifIt == result.end()) && ((upOnly && intf.isUp()) || !upOnly))
1646 result.insert(Map::value_type(ifIndex, intf));
1647
1648 address = IPAddress(&reinterpret_cast<const struct sockaddr_in6*>(iface->ifa_addr)->sin6_addr, sizeof(struct in6_addr), ifIndex);
1649 subnetMask = IPAddress(*(iface->ifa_netmask));
1650 broadcastAddress = IPAddress();
1651
1652 break;
1653#endif
1654 default:
1655 continue;
1656 }
1657
1658 if (family == AF_INET
1659#ifdef POCO_HAVE_IPv6
1660 || family == AF_INET6
1661#endif
1662 )
1663 {
1664 intf = NetworkInterface(std::string(iface->ifa_name), address, subnetMask, broadcastAddress, ifIndex);
1665 if ((upOnly && intf.isUp()) || !upOnly)
1666 {
1667 if ((ifIt = result.find(ifIndex)) != result.end())
1668 ifIt->second.addAddress(address, subnetMask, broadcastAddress);
1669 }
1670 }
1671 } // for interface
1672 }
1673 catch (...)
1674 {
1675 if (ifaces) freeifaddrs(ifaces);
1676 throw;
1677 }
1678
1679 if (ifaces) freeifaddrs(ifaces);
1680
1681 if (ipOnly)
1682 {
1683 Map::iterator it = result.begin();
1684 Map::iterator end = result.end();
1685 for (; it != end;)
1686 {
1687 if (!it->second.supportsIPv4() && !it->second.supportsIPv6())
1688 result.erase(it++);
1689 else ++it;
1690 }
1691 }
1692
1693 return result;
1694#else
1695 throw Poco::NotImplementedException("Not implemented in Android");
1696#endif
1697}
1698
1699
1700} } // namespace Poco::Net
1701
1702
1703#else
1704//
1705// Non-BSD Unix variants
1706//
1707#error TODO
1708/*
1709NetworkInterface::NetworkInterfaceList NetworkInterface::list()
1710{
1711 FastMutex::ScopedLock lock(_mutex);
1712 NetworkInterfaceList result;
1713 DatagramSocket socket;
1714 // the following code is loosely based
1715 // on W. Richard Stevens, UNIX Network Programming, pp 434ff.
1716 int lastlen = 0;
1717 int len = 100*sizeof(struct ifreq);
1718 char* buf = 0;
1719 try
1720 {
1721 struct ifconf ifc;
1722 for (;;)
1723 {
1724 buf = new char[len];
1725 ifc.ifc_len = len;
1726 ifc.ifc_buf = buf;
1727 if (::ioctl(socket.impl()->sockfd(), SIOCGIFCONF, &ifc) < 0)
1728 {
1729 if (errno != EINVAL || lastlen != 0)
1730 throw NetException("cannot get network adapter list");
1731 }
1732 else
1733 {
1734 if (ifc.ifc_len == lastlen)
1735 break;
1736 lastlen = ifc.ifc_len;
1737 }
1738 len += 10*sizeof(struct ifreq);
1739 delete [] buf;
1740 }
1741 for (const char* ptr = buf; ptr < buf + ifc.ifc_len;)
1742 {
1743 const struct ifreq* ifr = reinterpret_cast<const struct ifreq*>(ptr);
1744#if defined(POCO_HAVE_SALEN)
1745 len = ifr->ifr_addr.sa_len;
1746 if (sizeof(struct sockaddr) > len) len = sizeof(struct sockaddr);
1747#else
1748 len = sizeof(struct sockaddr);
1749#endif
1750 IPAddress addr;
1751 bool haveAddr = false;
1752 int ifIndex(-1);
1753 switch (ifr->ifr_addr.sa_family)
1754 {
1755#if defined(POCO_HAVE_IPv6)
1756 case AF_INET6:
1757 ifIndex = if_nametoindex(ifr->ifr_name);
1758 if (len < sizeof(struct sockaddr_in6)) len = sizeof(struct sockaddr_in6);
1759 addr = IPAddress(&reinterpret_cast<const struct sockaddr_in6*>(&ifr->ifr_addr)->sin6_addr, sizeof(struct in6_addr), ifIndex);
1760 haveAddr = true;
1761 break;
1762#endif
1763 case AF_INET:
1764 if (len < sizeof(struct sockaddr_in)) len = sizeof(struct sockaddr_in);
1765 addr = IPAddress(ifr->ifr_addr);
1766 haveAddr = true;
1767 break;
1768 default:
1769 break;
1770 }
1771 if (haveAddr)
1772 {
1773 std::string name(ifr->ifr_name);
1774 result.push_back(NetworkInterface(name, name, name, addr, ifIndex));
1775 }
1776 len += sizeof(ifr->ifr_name);
1777 ptr += len;
1778 }
1779 }
1780 catch (...)
1781 {
1782 delete [] buf;
1783 throw;
1784 }
1785 delete [] buf;
1786 return result;
1787}
1788*/
1789
1790} } // namespace Poco::Net
1791
1792
1793#endif
1794
1795
1796#endif // POCO_NET_HAS_INTERFACE
1797