1 /*****************************************************************
5 | Copyright (c) 2004-2010, Plutinosoft, LLC.
7 | http://www.plutinosoft.com
9 | This program is free software; you can redistribute it and/or
10 | modify it under the terms of the GNU General Public License
11 | as published by the Free Software Foundation; either version 2
12 | of the License, or (at your option) any later version.
14 | OEMs, ISVs, VARs and other distributors that combine and
15 | distribute commercially licensed software with Platinum software
16 | and do not wish to distribute the source code for the commercially
17 | licensed software under version 2, or (at your option) any later
18 | version, of the GNU General Public License (the "GPL") must enter
19 | into a commercial license agreement with Plutinosoft, LLC.
20 | licensing@plutinosoft.com
22 | This program is distributed in the hope that it will be useful,
23 | but WITHOUT ANY WARRANTY; without even the implied warranty of
24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 | GNU General Public License for more details.
27 | You should have received a copy of the GNU General Public License
28 | along with this program; see the file LICENSE.txt. If not, write to
29 | the Free Software Foundation, Inc.,
30 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
31 | http://www.gnu.org/licenses/gpl-2.0.html
33 ****************************************************************/
35 #ifndef _PLT_UTILITIES_H_
36 #define _PLT_UTILITIES_H_
38 /*----------------------------------------------------------------------
40 +---------------------------------------------------------------------*/
43 /*----------------------------------------------------------------------
44 | PLT_XmlAttributeFinder
45 +---------------------------------------------------------------------*/
47 The PLT_XmlAttributeFinder class is used to determine if an attribute
48 exists given an xml element node, an attribute name and namespace.
50 class PLT_XmlAttributeFinder
53 // if 'namespc' is NULL, we're looking for ANY namespace
54 // if 'namespc' is '\0', we're looking for NO namespace
55 // if 'namespc' is non-empty, look for that SPECIFIC namespace
56 PLT_XmlAttributeFinder(const NPT_XmlElementNode
& element
,
58 const char* namespc
) :
59 m_Element(element
), m_Name(name
), m_Namespace(namespc
) {}
61 bool operator()(const NPT_XmlAttribute
* const & attribute
) const {
62 if (attribute
->GetName() == m_Name
) {
64 const NPT_String
& prefix
= attribute
->GetPrefix();
65 if (m_Namespace
[0] == '\0') {
66 // match if the attribute has NO namespace
67 return prefix
.IsEmpty();
69 // match if the attribute has the SPECIFIC namespace
71 const NPT_String
* namespc
= m_Element
.GetNamespaceUri(prefix
);
72 return namespc
&& *namespc
== m_Namespace
;
75 // ANY namespace will match
84 const NPT_XmlElementNode
& m_Element
;
86 const char* m_Namespace
;
89 /*----------------------------------------------------------------------
91 +---------------------------------------------------------------------*/
93 The PLT_XmlHelper class is a set of utility functions for manipulating
94 xml documents and DOM trees.
102 static NPT_Result
Parse(const NPT_String
& xml
, NPT_XmlElementNode
*& tree
) {
107 NPT_XmlParser parser
;
109 NPT_Result result
= parser
.Parse(xml
, node
);
110 if (NPT_FAILED(result
)) {
111 //NPT_LOG_FINEST_1("Failed to parse %s", xml.IsEmpty()?"(empty string)":xml.GetChars());
115 tree
= node
->AsElementNode();
124 static NPT_Result
GetChildText(NPT_XmlElementNode
* node
,
127 const char* namespc
= "",
128 NPT_Cardinal max_size
= 1024) {
131 if (!node
) return NPT_FAILURE
;
133 // special case "" means we look for the same namespace as the parent
134 if (namespc
&& namespc
[0] == '\0') {
135 namespc
= node
->GetNamespace()?node
->GetNamespace()->GetChars():NPT_XML_NO_NAMESPACE
;
138 NPT_XmlElementNode
* child
= node
->GetChild(tag
, namespc
);
139 if (!child
) return NPT_FAILURE
;
141 const NPT_String
* text
= child
->GetText();
144 value
= text
->SubString(0, max_size
);
148 static NPT_Result
RemoveAttribute(NPT_XmlElementNode
* node
,
150 const char* namespc
= "") {
151 if (!node
) return NPT_FAILURE
;
153 // special case "" means we look for the same namespace as the parent
154 if (namespc
&& namespc
[0] == '\0') {
155 namespc
= node
->GetNamespace()?node
->GetNamespace()->GetChars():NPT_XML_NO_NAMESPACE
;
158 NPT_List
<NPT_XmlAttribute
*>::Iterator attribute
;
159 attribute
= node
->GetAttributes().Find(PLT_XmlAttributeFinder(*node
, name
, namespc
));
160 if (!attribute
) return NPT_FAILURE
;
163 NPT_CHECK(node
->GetAttributes().Erase(attribute
));
168 static NPT_Result
GetAttribute(NPT_XmlElementNode
* node
,
170 NPT_XmlAttribute
*& attr
,
171 const char* namespc
= "") {
174 if (!node
) return NPT_FAILURE
;
176 // special case "" means we look for the same namespace as the parent
177 if (namespc
&& namespc
[0] == '\0') {
178 namespc
= node
->GetNamespace()?node
->GetNamespace()->GetChars():NPT_XML_NO_NAMESPACE
;
181 NPT_List
<NPT_XmlAttribute
*>::Iterator attribute
;
182 attribute
= node
->GetAttributes().Find(PLT_XmlAttributeFinder(*node
, name
, namespc
));
184 //NPT_Debug("Failed to find attribute [%s]:%s", namespc, name);
192 static NPT_Result
GetAttribute(NPT_XmlElementNode
* node
,
195 const char* namespc
= "",
196 NPT_Cardinal max_size
= 1024) {
199 NPT_XmlAttribute
* attribute
= NULL
;
200 NPT_Result result
= GetAttribute(node
, name
, attribute
, namespc
);
201 if (NPT_FAILED(result
)) return result
;
203 if (!attribute
) return NPT_FAILURE
;
204 // DLNA 7.3.17 truncate to 1024 bytes
205 value
= attribute
->GetValue().SubString(0, max_size
);
209 static NPT_Result
SetAttribute(NPT_XmlElementNode
* node
,
212 const char* namespc
= "") {
213 NPT_XmlAttribute
* attribute
= NULL
;
214 NPT_CHECK(GetAttribute(node
, name
, attribute
, namespc
));
215 if (!attribute
) return NPT_FAILURE
;
217 attribute
->SetValue(value
);
221 static NPT_Result
AddChildText(NPT_XmlElementNode
* node
,
224 const char* prefix
= NULL
) {
225 if (!node
) return NPT_FAILURE
;
226 NPT_XmlElementNode
* child
= new NPT_XmlElementNode(prefix
, tag
);
227 child
->AddText(text
);
228 return node
->AddChild(child
);
231 static bool IsMatch(const NPT_XmlNode
* const & node
, const char* tag
, const char* namespc_mapped
) {
232 // if m_Namespace is NULL, we're looking for ANY namespace
233 // if m_Namespace is '\0', we're looking for NO namespace
234 // if m_Namespace is non-empty, look for that SPECIFIC namespace
236 const NPT_XmlElementNode
* element
= node
->AsElementNode();
237 // is tag the same (case sensitive)?
238 if (element
&& element
->GetTag() == tag
) {
239 if (namespc_mapped
) {
240 // look for a SPECIFIC namespace or NO namespace
241 const NPT_String
* namespc
= element
->GetNamespace();
243 // the element has a namespace, match if it is equal to
244 // what we're looking for
245 return *namespc
== namespc_mapped
;
247 // the element does not have a namespace, match if we're
248 // looking for NO namespace
249 return namespc_mapped
[0] == '\0';
252 // ANY namespace will match
259 static NPT_Result
GetChildren(NPT_XmlElementNode
* node
,
260 NPT_Array
<NPT_XmlElementNode
*>& children
,
262 const char* namespc
= "") {
263 if (!node
) return NPT_FAILURE
;
265 // special case "" means we look for the same namespace as the parent
266 if (namespc
&& namespc
[0] == '\0') {
267 namespc
= node
->GetNamespace()?node
->GetNamespace()->GetChars():NPT_XML_NO_NAMESPACE
;
270 const char* namespc_mapped
= (namespc
==NULL
)?"":(namespc
[0]=='*' && namespc
[1]=='\0')?NULL
:namespc
;
272 // get all children first
273 NPT_List
<NPT_XmlNode
*>& allchildren
= node
->GetChildren();
275 // iterate through children and add only elements with matching tag
276 NPT_List
<NPT_XmlNode
*>::Iterator child
= allchildren
.GetFirstItem();
278 if (IsMatch(*child
, tag
, namespc_mapped
)) {
279 children
.Add((*child
)->AsElementNode());
286 static NPT_XmlElementNode
* GetChild(NPT_XmlElementNode
* node
,
288 const char* namespc
= "") {
289 if (!node
) return NULL
;
291 // special case "" means we look for the same namespace as the parent
292 if (namespc
&& namespc
[0] == '\0') {
293 namespc
= node
->GetNamespace()?node
->GetNamespace()->GetChars():NPT_XML_NO_NAMESPACE
;
296 return node
->GetChild(tag
, namespc
);
299 static NPT_Result
GetChild(NPT_XmlElementNode
* parent
,
300 NPT_XmlElementNode
*& child
,
302 if (!parent
) return NPT_FAILURE
;
307 // get all children first
308 NPT_List
<NPT_XmlNode
*>::Iterator children
= parent
->GetChildren().GetFirstItem();
310 if ((*children
)->AsElementNode() && n
-- == 0) {
311 child
= (*children
)->AsElementNode();
320 static NPT_Result
Serialize(NPT_XmlNode
& node
, NPT_String
& xml
, bool add_header
= true, NPT_Int8 indentation
= 0) {
321 NPT_XmlWriter
writer(indentation
);
322 NPT_StringOutputStreamReference
stream(new NPT_StringOutputStream(&xml
));
323 NPT_CHECK(writer
.Serialize(node
, *stream
, add_header
));
327 static NPT_String
Serialize(NPT_XmlNode
& node
, bool add_header
= true, NPT_Int8 indentation
= 0) {
328 NPT_XmlWriter
writer(indentation
);
330 NPT_StringOutputStreamReference
stream(new NPT_StringOutputStream(&xml
));
331 if (NPT_FAILED(writer
.Serialize(node
, *stream
, add_header
))) {
332 NPT_Debug("Failed to serialize xml node");
342 /*----------------------------------------------------------------------
344 +---------------------------------------------------------------------*/
346 The NPT_StringFinder class is used to determine if a string is found
347 as part of a list of strings.
349 class NPT_StringFinder
353 explicit NPT_StringFinder(NPT_String
& value
, bool ignore_case
= false) :
354 m_Value(value
.GetChars()), m_IgnoreCase(ignore_case
) {}
356 explicit NPT_StringFinder(const char* value
, bool ignore_case
= false) :
357 m_Value(value
), m_IgnoreCase(ignore_case
) {}
359 virtual ~NPT_StringFinder() {}
361 bool operator()(const NPT_String
* const & value
) const {
362 return value
->Compare(m_Value
, m_IgnoreCase
) ? false : true;
364 bool operator()(const NPT_String
& value
) const {
365 return value
.Compare(m_Value
, m_IgnoreCase
) ? false : true;
374 /*----------------------------------------------------------------------
375 | NPT_IpAddressFinder
376 +---------------------------------------------------------------------*/
378 The NPT_IpAddressFinder class is used to determine if a IP Address is found
379 as part of a list of IP Addresses.
381 class NPT_IpAddressFinder
385 NPT_IpAddressFinder(NPT_IpAddress ip
) : m_Value(ip
) {}
386 virtual ~NPT_IpAddressFinder() {}
388 bool operator()(const NPT_IpAddress
* const & value
) const {
389 return *value
== m_Value
;
391 bool operator()(const NPT_IpAddress
& value
) const {
392 return value
== m_Value
;
397 NPT_IpAddress m_Value
;
401 /*----------------------------------------------------------------------
402 | PLT_UPnPMessageHelper class
403 +---------------------------------------------------------------------*/
405 The PLT_UPnPMessageHelper class is a set of utility functions for manipulating
406 specific UPnP HTTP headers.
408 class PLT_UPnPMessageHelper
412 static const NPT_String
* GetST(const NPT_HttpMessage
& message
) {
413 return message
.GetHeaders().GetHeaderValue("ST");
415 static NPT_Result
SetST(NPT_HttpMessage
& message
,
417 return message
.GetHeaders().SetHeader("ST", st
);
420 static const NPT_String
* GetNT(const NPT_HttpMessage
& message
) {
421 return message
.GetHeaders().GetHeaderValue("NT");
423 static NPT_Result
SetNT(NPT_HttpMessage
& message
,
425 return message
.GetHeaders().SetHeader("NT", nt
);
428 static const NPT_String
* GetNTS(const NPT_HttpMessage
& message
) {
429 return message
.GetHeaders().GetHeaderValue("NTS");
431 static NPT_Result
SetNTS(NPT_HttpMessage
& message
,
433 return message
.GetHeaders().SetHeader("NTS", nts
);
436 static const NPT_String
* GetMAN(const NPT_HttpMessage
& message
) {
437 return message
.GetHeaders().GetHeaderValue("MAN");
439 static NPT_Result
SetMAN(NPT_HttpMessage
& message
,
441 return message
.GetHeaders().SetHeader("MAN", man
);
444 static const NPT_String
* GetLocation(const NPT_HttpMessage
& message
) {
445 return message
.GetHeaders().GetHeaderValue("Location");
447 static NPT_Result
SetLocation(NPT_HttpMessage
& message
,
448 const char* location
) {
449 return message
.GetHeaders().SetHeader("Location", location
);
452 static const NPT_String
* GetServer(const NPT_HttpMessage
& message
) {
453 return message
.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_SERVER
);
455 static NPT_Result
SetServer(NPT_HttpMessage
& message
,
457 bool replace
= true) {
458 return message
.GetHeaders().SetHeader(
459 NPT_HTTP_HEADER_SERVER
,
464 static const NPT_String
* GetUSN(const NPT_HttpMessage
& message
) {
465 return message
.GetHeaders().GetHeaderValue("USN");
467 static NPT_Result
SetUSN(NPT_HttpMessage
& message
,
469 return message
.GetHeaders().SetHeader("USN", usn
);
472 static const NPT_String
* GetCallbacks(const NPT_HttpMessage
& message
) {
473 return message
.GetHeaders().GetHeaderValue("CALLBACK");
475 static NPT_Result
SetCallbacks(NPT_HttpMessage
& message
, const char* callbacks
) {
476 return message
.GetHeaders().SetHeader("CALLBACK", callbacks
);
479 static const NPT_String
* GetSID(const NPT_HttpMessage
& message
) {
480 return message
.GetHeaders().GetHeaderValue("SID");
482 static NPT_Result
SetSID(NPT_HttpMessage
& message
,
484 return message
.GetHeaders().SetHeader("SID", sid
);
487 static NPT_Result
GetLeaseTime(const NPT_HttpMessage
& message
, NPT_TimeInterval
& lease
) {
488 const NPT_String
* cc
=
489 message
.GetHeaders().GetHeaderValue("Cache-Control");
490 NPT_CHECK_POINTER(cc
);
491 return ExtractLeaseTime(*cc
, lease
);
493 static NPT_Result
SetLeaseTime(NPT_HttpMessage
& message
, const NPT_TimeInterval
& lease
) {
494 return message
.GetHeaders().SetHeader("Cache-Control",
495 "max-age="+NPT_String::FromInteger(lease
.ToSeconds()));
498 static NPT_Result
GetBootId(const NPT_HttpMessage
& message
, NPT_UInt32
& bootId
) {
500 const NPT_String
* bid
= message
.GetHeaders().GetHeaderValue("BOOTID.UPNP.ORG");
501 NPT_CHECK_POINTER(bid
);
502 return NPT_ParseInteger32(*bid
, bootId
, false);
504 static NPT_Result
SetBootId(NPT_HttpMessage
& message
, const NPT_UInt32
& bootId
) {
505 return message
.GetHeaders().SetHeader("BOOTID.UPNP.ORG",
506 NPT_String::FromInteger(bootId
));
509 static NPT_Result
GetNextBootId(const NPT_HttpMessage
& message
, NPT_UInt32
& nextBootId
) {
511 const NPT_String
* nbid
= message
.GetHeaders().GetHeaderValue("NEXTBOOTID.UPNP.ORG");
512 NPT_CHECK_POINTER(nbid
);
513 return NPT_ParseInteger32(*nbid
, nextBootId
, false);
515 static NPT_Result
SetNextBootId(NPT_HttpMessage
& message
, const NPT_UInt32
& nextBootId
) {
516 return message
.GetHeaders().SetHeader("NEXTBOOTID.UPNP.ORG",
517 NPT_String::FromInteger(nextBootId
));
520 static NPT_Result
GetConfigId(const NPT_HttpMessage
& message
, NPT_UInt32
& configId
) {
522 const NPT_String
* cid
= message
.GetHeaders().GetHeaderValue("CONFIGID.UPNP.ORG");
523 NPT_CHECK_POINTER(cid
);
524 return NPT_ParseInteger32(*cid
, configId
, false);
526 static NPT_Result
SetConfigId(NPT_HttpMessage
& message
, const NPT_UInt32
& configId
) {
527 return message
.GetHeaders().SetHeader("CONFIGID.UPNP.ORG", NPT_String::FromInteger(configId
));
530 static NPT_Result
GetTimeOut(const NPT_HttpMessage
& message
, NPT_Int32
& seconds
) {
532 const NPT_String
* timeout
=
533 message
.GetHeaders().GetHeaderValue("TIMEOUT");
534 NPT_CHECK_POINTER(timeout
);
535 return ExtractTimeOut(*timeout
, seconds
);
537 static NPT_Result
SetTimeOut(NPT_HttpMessage
& message
, const NPT_Int32 seconds
) {
539 return message
.GetHeaders().SetHeader("TIMEOUT", "Second-"+NPT_String::FromInteger(seconds
));
541 return message
.GetHeaders().SetHeader("TIMEOUT", "Second-infinite");
545 static NPT_Result
SetDate(NPT_HttpMessage
& message
) {
547 NPT_System::GetCurrentTimeStamp(now
);
548 NPT_DateTime
date(now
);
550 return message
.GetHeaders().SetHeader("Date", date
.ToString(NPT_DateTime::FORMAT_RFC_1123
));
553 static NPT_Result
GetIfModifiedSince(const NPT_HttpMessage
& message
, NPT_DateTime
& date
) {
554 const NPT_String
* value
= message
.GetHeaders().GetHeaderValue("If-Modified-Since");
555 if (!value
) return NPT_FAILURE
;
557 // Try RFC 1123, RFC 1036, then ANSI
558 if (NPT_SUCCEEDED(date
.FromString(*value
, NPT_DateTime::FORMAT_RFC_1123
)))
561 if (NPT_SUCCEEDED(date
.FromString(*value
, NPT_DateTime::FORMAT_RFC_1036
)))
564 return date
.FromString(*value
, NPT_DateTime::FORMAT_ANSI
);
566 static NPT_Result
SetIfModifiedSince(NPT_HttpMessage
& message
, const NPT_DateTime
& date
) {
567 return message
.GetHeaders().SetHeader("If-Modified-Since",
568 date
.ToString(NPT_DateTime::FORMAT_RFC_1123
));
571 static NPT_Result
GetMX(const NPT_HttpMessage
& message
, NPT_UInt32
& value
) {
573 const NPT_String
* mx
=
574 message
.GetHeaders().GetHeaderValue("MX");
575 NPT_CHECK_POINTER(mx
);
576 return NPT_ParseInteger32(*mx
, value
, false); // no relax to be UPnP compliant
578 static NPT_Result
SetMX(NPT_HttpMessage
& message
, const NPT_UInt32 mx
) {
579 return message
.GetHeaders().SetHeader("MX",
580 NPT_String::FromInteger(mx
));
583 static NPT_Result
GetSeq(const NPT_HttpMessage
& message
, NPT_UInt32
& value
) {
585 const NPT_String
* seq
=
586 message
.GetHeaders().GetHeaderValue("SEQ");
587 NPT_CHECK_POINTER(seq
);
588 return NPT_ParseInteger32(*seq
, value
);
590 static NPT_Result
SetSeq(NPT_HttpMessage
& message
, const NPT_UInt32 seq
) {
591 return message
.GetHeaders().SetHeader("SEQ",
592 NPT_String::FromInteger(seq
));
595 static const char* GenerateUUID(int count
, NPT_String
& uuid
) {
597 for (int i
=0;i
<(count
<100?count
:100);i
++) {
598 int random
= NPT_System::GetRandomInteger();
599 uuid
+= (char)((random
% 25) + 66);
604 static const char* GenerateSerialNumber(NPT_String
& sn
, int count
= 40) {
606 for (int i
=0;i
<count
;i
++) {
607 char nibble
= (char)(NPT_System::GetRandomInteger() % 16);
608 sn
+= (nibble
< 10) ? ('0' + nibble
) : ('a' + (nibble
-10));
614 static const char* GenerateGUID(NPT_String
& guid
) {
616 for (int i
=0;i
<32;i
++) {
617 char nibble
= (char)(NPT_System::GetRandomInteger() % 16);
618 guid
+= (nibble
< 10) ? ('0' + nibble
) : ('a' + (nibble
-10));
619 if (i
== 7 || i
== 11 || i
== 15 || i
== 19) {
626 static NPT_Result
ExtractLeaseTime(const NPT_String
& cache_control
, NPT_TimeInterval
& lease
) {
628 if (cache_control
.StartsWith("max-age=", true) &&
629 NPT_SUCCEEDED(NPT_ParseInteger32(cache_control
.GetChars()+8, value
))) {
630 lease
.SetSeconds(value
);
636 static NPT_Result
ExtractTimeOut(const char* timeout
, NPT_Int32
& len
) {
637 NPT_String temp
= timeout
;
638 if (temp
.CompareN("Second-", 7, true)) {
639 return NPT_ERROR_INVALID_FORMAT
;
642 if (temp
.Compare("Second-infinite", true) == 0) {
643 len
= NPT_TIMEOUT_INFINITE
;
646 return temp
.SubString(7).ToInteger(len
);
649 static NPT_Result
GetIPAddresses(NPT_List
<NPT_IpAddress
>& ips
, bool with_localhost
= false) {
650 NPT_List
<NPT_NetworkInterface
*> if_list
;
651 NPT_CHECK(GetNetworkInterfaces(if_list
, with_localhost
));
653 NPT_List
<NPT_NetworkInterface
*>::Iterator iface
= if_list
.GetFirstItem();
655 NPT_IpAddress ip
= (*(*iface
)->GetAddresses().GetFirstItem()).GetPrimaryAddress();
656 if (ip
.ToString().Compare("0.0.0.0") &&
657 (with_localhost
|| ip
.ToString().Compare("127.0.0.1"))) {
663 if (with_localhost
&& !ips
.Find(NPT_IpAddressFinder(NPT_IpAddress(127, 0, 0, 1)))) {
664 NPT_IpAddress localhost
;
665 localhost
.Parse("127.0.0.1");
669 if_list
.Apply(NPT_ObjectDeleter
<NPT_NetworkInterface
>());
673 static NPT_Result
GetNetworkInterfaces(NPT_List
<NPT_NetworkInterface
*>& if_list
,
674 bool with_localhost
= false) {
675 NPT_CHECK(_GetNetworkInterfaces(if_list
, with_localhost
, false));
677 // if no valid interfaces or if requested, add localhost interface
678 if (if_list
.GetItemCount() == 0) {
679 NPT_CHECK(_GetNetworkInterfaces(if_list
, true, true));
684 static NPT_Result
GetMACAddresses(NPT_List
<NPT_String
>& addresses
) {
685 NPT_List
<NPT_NetworkInterface
*> if_list
;
686 NPT_CHECK(GetNetworkInterfaces(if_list
));
688 NPT_List
<NPT_NetworkInterface
*>::Iterator iface
= if_list
.GetFirstItem();
690 NPT_String ip
= (*(*iface
)->GetAddresses().GetFirstItem()).GetPrimaryAddress().ToString();
691 if (ip
.Compare("0.0.0.0") && ip
.Compare("127.0.0.1")) {
692 addresses
.Add((*iface
)->GetMacAddress().ToString());
697 if_list
.Apply(NPT_ObjectDeleter
<NPT_NetworkInterface
>());
702 static bool IsLocalNetworkAddress(const NPT_IpAddress
& address
) {
703 if (address
.ToString() == "127.0.0.1") return true;
705 NPT_List
<NPT_NetworkInterface
*> if_list
;
706 NPT_NetworkInterface::GetNetworkInterfaces(if_list
);
708 NPT_List
<NPT_NetworkInterface
*>::Iterator iface
= if_list
.GetFirstItem();
710 if((*iface
)->IsAddressInNetwork(address
)) return true;
714 if_list
.Apply(NPT_ObjectDeleter
<NPT_NetworkInterface
>());
720 static NPT_Result
_GetNetworkInterfaces(NPT_List
<NPT_NetworkInterface
*>& if_list
,
721 bool include_localhost
= false,
722 bool only_localhost
= false) {
723 NPT_List
<NPT_NetworkInterface
*> _if_list
;
724 NPT_CHECK(NPT_NetworkInterface::GetNetworkInterfaces(_if_list
));
726 NPT_NetworkInterface
* iface
;
727 while (NPT_SUCCEEDED(_if_list
.PopHead(iface
))) {
728 // only interested in non PTP & multicast capable interfaces
729 if ((iface
->GetAddresses().GetItemCount() == 0) ||
730 !(iface
->GetFlags() & NPT_NETWORK_INTERFACE_FLAG_MULTICAST
) ||
731 (iface
->GetFlags() & NPT_NETWORK_INTERFACE_FLAG_POINT_TO_POINT
)) {
736 NPT_String ip
= iface
->GetAddresses().GetFirstItem()->GetPrimaryAddress().ToString();
738 if (iface
->GetFlags() & NPT_NETWORK_INTERFACE_FLAG_LOOPBACK
) {
739 if (include_localhost
|| only_localhost
) {
743 } else if (ip
.Compare("0.0.0.0") && !only_localhost
) {
751 // cleanup any remaining items in list if we breaked early
752 _if_list
.Apply(NPT_ObjectDeleter
<NPT_NetworkInterface
>());
757 #endif // _PLT_UTILITIES_H_