Uncommented beaudio code
[pwlib.git] / src / ptclib / pstun.cxx
blob0f83ee3fa806568585c68f40cc2e67b0618ac0d1
1 /*
2 * pstun.cxx
4 * STUN Client
6 * Portable Windows Library
8 * Copyright (c) 2003 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
26 * $Log$
27 * Revision 1.13 2004/03/14 05:47:52 rjongbloed
28 * Fixed incorrect detection of symmetric NAT (eg Linux masquerading) and also
29 * some NAT systems which are partially blocked due to firewall rules.
31 * Revision 1.12 2004/02/24 11:15:48 rjongbloed
32 * Added function to get external router address, also did a bunch of documentation.
34 * Revision 1.11 2004/02/17 11:11:05 rjongbloed
35 * Added missing #pragma pack() to turn off byte alignment for the last class, thanks Ted Szoczei
37 * Revision 1.10 2004/01/17 17:54:02 rjongbloed
38 * Added function to get server name from STUN client.
40 * Revision 1.9 2003/10/08 22:00:18 dereksmithies
41 * Fix unsigned/signed warning message. Thanks to Craig Southeren.
43 * Revision 1.8 2003/10/05 00:56:25 rjongbloed
44 * Rewrite of STUN to not to use imported code with undesirable license.
46 * Revision 1.5 2003/02/05 06:26:49 robertj
47 * More work in making the STUN usable for Symmetric NAT systems.
49 * Revision 1.4 2003/02/04 07:02:17 robertj
50 * Added ip/port version of constructor.
51 * Removed creating sockets for Open type.
53 * Revision 1.3 2003/02/04 05:55:04 craigs
54 * Added socket pair function
56 * Revision 1.2 2003/02/04 05:06:24 craigs
57 * Added new functions
59 * Revision 1.1 2003/02/04 03:31:04 robertj
60 * Added STUN
64 #ifdef __GNUC__
65 #pragma implementation "pstun.h"
66 #endif
69 #include <ptlib.h>
70 #include <ptclib/pstun.h>
71 #include <ptclib/random.h>
74 // Sample server is at larry.gloo.net
77 ///////////////////////////////////////////////////////////////////////
79 PSTUNClient::PSTUNClient(const PString & server,
80 WORD portBase, WORD portMax,
81 WORD portPairBase, WORD portPairMax)
82 : serverAddress(0),
83 cachedExternalAddress(0),
84 timeAddressObtained(0)
86 serverPort = DefaultPort;
87 Construct();
89 SetServer(server);
90 SetPortRanges(portBase, portMax, portPairBase, portPairMax);
94 PSTUNClient::PSTUNClient(const PIPSocket::Address & address, WORD port,
95 WORD portBase, WORD portMax,
96 WORD portPairBase, WORD portPairMax)
97 : serverAddress(address),
98 serverPort(port),
99 cachedExternalAddress(0),
100 timeAddressObtained(0)
102 Construct();
103 SetPortRanges(portBase, portMax, portPairBase, portPairMax);
107 void PSTUNClient::Construct()
109 singlePortInfo.basePort = 0;
110 singlePortInfo.maxPort = 0;
111 singlePortInfo.currentPort = 0;
112 pairedPortInfo.basePort = 0;
113 pairedPortInfo.maxPort = 0;
114 pairedPortInfo.currentPort = 0;
115 numSocketsForPairing = 3;
116 natType = UnknownNat;
120 PString PSTUNClient::GetServer() const
122 PStringStream str;
123 str << serverAddress << ':' << serverPort;
124 return str;
128 BOOL PSTUNClient::SetServer(const PString & server)
130 PINDEX colon = server.Find(':');
131 if (colon == P_MAX_INDEX) {
132 if (!PIPSocket::GetHostAddress(server, serverAddress))
133 return FALSE;
135 else {
136 if (!PIPSocket::GetHostAddress(server.Left(colon), serverAddress))
137 return FALSE;
138 serverPort = PIPSocket::GetPortByService("udp", server.Mid(colon+1));
141 return serverAddress.IsValid() && serverPort != 0;
145 BOOL PSTUNClient::SetServer(const PIPSocket::Address & address, WORD port)
147 serverAddress = address;
148 serverPort = port;
149 return serverAddress.IsValid() && serverPort != 0;
153 void PSTUNClient::SetPortRanges(WORD portBase, WORD portMax,
154 WORD portPairBase, WORD portPairMax)
156 singlePortInfo.mutex.Wait();
158 singlePortInfo.basePort = portBase;
159 if (portBase == 0)
160 singlePortInfo.maxPort = 0;
161 else if (portMax == 0)
162 singlePortInfo.maxPort = (WORD)(singlePortInfo.basePort+99);
163 else if (portMax < portBase)
164 singlePortInfo.maxPort = portBase;
165 else
166 singlePortInfo.maxPort = portMax;
168 singlePortInfo.currentPort = singlePortInfo.basePort;
170 singlePortInfo.mutex.Signal();
172 pairedPortInfo.mutex.Wait();
174 pairedPortInfo.basePort = (WORD)((portPairBase+1)&0xfffe);
175 if (portPairBase == 0) {
176 pairedPortInfo.basePort = 0;
177 pairedPortInfo.maxPort = 0;
179 else if (portPairMax == 0)
180 pairedPortInfo.maxPort = (WORD)(pairedPortInfo.basePort+99);
181 else if (portPairMax < portPairBase)
182 pairedPortInfo.maxPort = portPairBase;
183 else
184 pairedPortInfo.maxPort = portPairMax;
186 pairedPortInfo.currentPort = pairedPortInfo.basePort;
188 pairedPortInfo.mutex.Signal();
192 #pragma pack(1)
194 struct PSTUNAttribute
196 enum Types {
197 MAPPED_ADDRESS = 0x0001,
198 RESPONSE_ADDRESS = 0x0002,
199 CHANGE_REQUEST = 0x0003,
200 SOURCE_ADDRESS = 0x0004,
201 CHANGED_ADDRESS = 0x0005,
202 USERNAME = 0x0006,
203 PASSWORD = 0x0007,
204 MESSAGE_INTEGRITY = 0x0008,
205 ERROR_CODE = 0x0009,
206 UNKNOWN_ATTRIBUTES = 0x000a,
207 REFLECTED_FROM = 0x000b,
210 PUInt16b type;
211 PUInt16b length;
213 PSTUNAttribute * GetNext() const { return (PSTUNAttribute *)(((const BYTE *)this)+length+4); }
216 class PSTUNAddressAttribute : public PSTUNAttribute
218 public:
219 BYTE pad;
220 BYTE family;
221 PUInt16b port;
222 BYTE ip[4];
224 PIPSocket::Address GetIP() const { return PIPSocket::Address(4, ip); }
226 protected:
227 enum { SizeofAddressAttribute = sizeof(BYTE)+sizeof(BYTE)+sizeof(WORD)+sizeof(PIPSocket::Address) };
228 void InitAddrAttr(Types newType)
230 type = (WORD)newType;
231 length = SizeofAddressAttribute;
232 pad = 0;
233 family = 1;
235 bool IsValidAddrAttr(Types checkType) const
237 return type == checkType && length == SizeofAddressAttribute;
241 class PSTUNMappedAddress : public PSTUNAddressAttribute
243 public:
244 void Initialise() { InitAddrAttr(MAPPED_ADDRESS); }
245 bool IsValid() const { return IsValidAddrAttr(MAPPED_ADDRESS); }
248 class PSTUNChangedAddress : public PSTUNAddressAttribute
250 public:
251 void Initialise() { InitAddrAttr(CHANGED_ADDRESS); }
252 bool IsValid() const { return IsValidAddrAttr(CHANGED_ADDRESS); }
255 class PSTUNChangeRequest : public PSTUNAttribute
257 public:
258 BYTE flags[4];
260 PSTUNChangeRequest() { }
262 PSTUNChangeRequest(bool changeIP, bool changePort)
264 Initialise();
265 SetChangeIP(changeIP);
266 SetChangePort(changePort);
269 void Initialise()
271 type = CHANGE_REQUEST;
272 length = sizeof(flags);
273 memset(flags, 0, sizeof(flags));
275 bool IsValid() const { return type == CHANGE_REQUEST && length == sizeof(flags); }
277 bool GetChangeIP() const { return (flags[3]&4) != 0; }
278 void SetChangeIP(bool on) { if (on) flags[3] |= 4; else flags[3] &= ~4; }
280 bool GetChangePort() const { return (flags[3]&2) != 0; }
281 void SetChangePort(bool on) { if (on) flags[3] |= 2; else flags[3] &= ~2; }
284 class PSTUNMessageIntegrity : public PSTUNAttribute
286 public:
287 BYTE hmac[20];
289 void Initialise()
291 type = MESSAGE_INTEGRITY;
292 length = sizeof(hmac);
293 memset(hmac, 0, sizeof(hmac));
295 bool IsValid() const { return type == MESSAGE_INTEGRITY && length == sizeof(hmac); }
298 struct PSTUNMessageHeader
300 PUInt16b msgType;
301 PUInt16b msgLength;
302 BYTE transactionId[16];
306 #pragma pack()
309 class PSTUNMessage : public PBYTEArray
311 public:
312 enum MsgType {
313 BindingRequest = 0x0001,
314 BindingResponse = 0x0101,
315 BindingError = 0x0111,
317 SharedSecretRequest = 0x0002,
318 SharedSecretResponse = 0x0102,
319 SharedSecretError = 0x0112,
322 PSTUNMessage()
325 PSTUNMessage(MsgType newType, const BYTE * id = NULL)
326 : PBYTEArray(sizeof(PSTUNMessageHeader))
328 SetType(newType, id);
331 void SetType(MsgType newType, const BYTE * id = NULL)
333 SetMinSize(sizeof(PSTUNMessageHeader));
334 PSTUNMessageHeader * hdr = (PSTUNMessageHeader *)theArray;
335 hdr->msgType = (WORD)newType;
336 for (PINDEX i = 0; i < ((PINDEX)sizeof(hdr->transactionId)); i++)
337 hdr->transactionId[i] = id != NULL ? id[i] : (BYTE)PRandom::Number();
340 const PSTUNMessageHeader * operator->() const { return (PSTUNMessageHeader *)theArray; }
342 PSTUNAttribute * GetFirstAttribute() { return (PSTUNAttribute *)(theArray+sizeof(PSTUNMessageHeader)); }
344 bool Validate()
346 int length = ((PSTUNMessageHeader *)theArray)->msgLength;
347 PSTUNAttribute * attrib = GetFirstAttribute();
348 while (length > 0) {
349 length -= attrib->length + 4;
350 attrib = attrib->GetNext();
353 return length == 0; // Exactly correct length
356 void AddAttribute(const PSTUNAttribute & attribute)
358 PSTUNMessageHeader * hdr = (PSTUNMessageHeader *)theArray;
359 int oldLength = hdr->msgLength;
360 int attrSize = attribute.length + 4;
361 int newLength = oldLength + attrSize;
362 hdr->msgLength = (WORD)newLength;
363 // hdr pointer may be invalidated by next statement
364 SetMinSize(newLength+sizeof(PSTUNMessageHeader));
365 memcpy(theArray+sizeof(PSTUNMessageHeader)+oldLength, &attribute, attrSize);
368 void SetAttribute(const PSTUNAttribute & attribute)
370 int length = ((PSTUNMessageHeader *)theArray)->msgLength;
371 PSTUNAttribute * attrib = GetFirstAttribute();
372 while (length > 0) {
373 if (attrib->type == attribute.type) {
374 if (attrib->length == attribute.length)
375 *attrib = attribute;
376 else {
377 // More here
379 return;
382 length -= attrib->length + 4;
383 attrib = attrib->GetNext();
386 AddAttribute(attribute);
389 PSTUNAttribute * FindAttribute(PSTUNAttribute::Types type)
391 int length = ((PSTUNMessageHeader *)theArray)->msgLength;
392 PSTUNAttribute * attrib = GetFirstAttribute();
393 while (length > 0) {
394 if (attrib->type == type)
395 return attrib;
397 length -= attrib->length + 4;
398 attrib = attrib->GetNext();
400 return NULL;
404 bool Read(PUDPSocket & socket)
406 if (!socket.Read(GetPointer(1000), 1000))
407 return false;
408 SetSize(socket.GetLastReadCount());
409 return true;
412 bool Write(PUDPSocket & socket) const
414 return socket.Write(theArray, ((PSTUNMessageHeader *)theArray)->msgLength+sizeof(PSTUNMessageHeader)) != FALSE;
417 bool Poll(PUDPSocket & socket, const PSTUNMessage & request)
419 for (int retry = 0; retry < 3; retry++) {
420 if (!request.Write(socket))
421 break;
423 if (Read(socket) && Validate() &&
424 memcmp(request->transactionId, (*this)->transactionId, sizeof(request->transactionId)) == 0)
425 return true;
428 return false;
433 bool PSTUNClient::OpenSocket(PUDPSocket & socket, PortInfo & portInfo) const
435 PWaitAndSignal mutex(portInfo.mutex);
437 WORD startPort = portInfo.currentPort;
439 do {
440 portInfo.currentPort++;
441 if (portInfo.currentPort > portInfo.maxPort)
442 portInfo.currentPort = portInfo.basePort;
444 if (socket.Listen(1, portInfo.currentPort)) {
445 socket.SetSendAddress(serverAddress, serverPort);
446 socket.SetReadTimeout(500);
447 return true;
450 } while (portInfo.currentPort != startPort);
452 PTRACE(1, "STUN\tFailed to bind to local UDP port in range "
453 << portInfo.currentPort << '-' << portInfo.maxPort);
454 return false;
458 PSTUNClient::NatTypes PSTUNClient::GetNatType(BOOL force)
460 if (!force && natType != UnknownNat)
461 return natType;
463 PUDPSocket socket;
464 if (!OpenSocket(socket, singlePortInfo))
465 return natType = UnknownNat;
467 // RFC3489 discovery
469 /* test I - the client sends a STUN Binding Request to a server, without
470 any flags set in the CHANGE-REQUEST attribute, and without the
471 RESPONSE-ADDRESS attribute. This causes the server to send the response
472 back to the address and port that the request came from. */
473 PSTUNMessage requestI(PSTUNMessage::BindingRequest);
474 requestI.AddAttribute(PSTUNChangeRequest(false, false));
475 PSTUNMessage responseI;
476 if (!responseI.Poll(socket, requestI)) {
477 if (socket.GetErrorCode(PChannel::LastWriteError) != PChannel::NoError) {
478 PTRACE(1, "STUN\tError writing to server " << serverAddress << ':' << serverPort << " - " << socket.GetErrorText(PChannel::LastWriteError));
479 return natType = UnknownNat; // No response usually means blocked
482 PTRACE(3, "STUN\tNo response to server " << serverAddress << ':' << serverPort << " - " << socket.GetErrorText(PChannel::LastReadError));
483 return natType = BlockedNat; // No response usually means blocked
486 PSTUNMappedAddress * mappedAddress = (PSTUNMappedAddress *)responseI.FindAttribute(PSTUNAttribute::MAPPED_ADDRESS);
487 if (mappedAddress == NULL) {
488 PTRACE(2, "STUN\tExpected mapped address attribute from server " << serverAddress << ':' << serverPort);
489 return natType = UnknownNat; // Protocol error
492 PIPSocket::Address mappedAddressI = mappedAddress->GetIP();
493 WORD mappedPortI = mappedAddress->port;
494 bool notNAT = socket.GetPort() == mappedPortI && PIPSocket::IsLocalHost(mappedAddressI);
496 /* Test II - the client sends a Binding Request with both the "change IP"
497 and "change port" flags from the CHANGE-REQUEST attribute set. */
498 PSTUNMessage requestII(PSTUNMessage::BindingRequest);
499 requestII.AddAttribute(PSTUNChangeRequest(true, true));
500 PSTUNMessage responseII;
501 bool testII = responseII.Poll(socket, requestII);
503 if (notNAT) {
504 // Is not NAT or symmetric firewall
505 return natType = (testII ? OpenNat : SymmetricFirewall);
508 if (testII)
509 return natType = ConeNat;
511 PSTUNChangedAddress * changedAddress = (PSTUNChangedAddress *)responseI.FindAttribute(PSTUNAttribute::CHANGED_ADDRESS);
512 if (changedAddress == NULL)
513 return natType = UnknownNat; // Protocol error
515 // Send test I to another server, to see if restricted or symmetric
516 PIPSocket::Address secondaryServer = changedAddress->GetIP();
517 WORD secondaryPort = changedAddress->port;
518 socket.SetSendAddress(secondaryServer, secondaryPort);
519 PSTUNMessage requestI2(PSTUNMessage::BindingRequest);
520 requestI2.AddAttribute(PSTUNChangeRequest(false, false));
521 PSTUNMessage responseI2;
522 if (!responseI2.Poll(socket, requestI2)) {
523 PTRACE(2, "STUN\tPoll of secondary server " << secondaryServer << ':' << secondaryPort
524 << " failed, NAT partially blocked by firwall rules.");
525 return natType = PartialBlockedNat;
528 mappedAddress = (PSTUNMappedAddress *)responseI2.FindAttribute(PSTUNAttribute::MAPPED_ADDRESS);
529 if (mappedAddress == NULL) {
530 PTRACE(2, "STUN\tExpected mapped address attribute from server " << serverAddress << ':' << serverPort);
531 return UnknownNat; // Protocol error
534 if (mappedAddress->port != mappedPortI || mappedAddress->GetIP() != mappedAddressI)
535 return natType = SymmetricNat;
537 socket.SetSendAddress(serverAddress, serverPort);
538 PSTUNMessage requestIII(PSTUNMessage::BindingRequest);
539 requestIII.SetAttribute(PSTUNChangeRequest(false, true));
540 PSTUNMessage responseIII;
541 return natType = (responseIII.Poll(socket, requestIII) ? RestrictedNat : PortRestrictedNat);
545 PString PSTUNClient::GetNatTypeName(BOOL force)
547 static const char * const Names[NumNatTypes] = {
548 "Unknown NAT",
549 "Open NAT",
550 "Cone NAT",
551 "Restricted NAT",
552 "Port Restricted NAT",
553 "Symmetric NAT",
554 "Symmetric Firewall",
555 "Blocked",
556 "Partially Blocked"
559 return Names[GetNatType(force)];
563 BOOL PSTUNClient::GetExternalAddress(PIPSocket::Address & externalAddress,
564 const PTimeInterval & maxAge)
566 if (cachedExternalAddress.IsValid() && (PTime() - timeAddressObtained > maxAge)) {
567 externalAddress = cachedExternalAddress;
568 return TRUE;
571 externalAddress = 0; // Set to invalid address
573 PUDPSocket socket;
574 if (!OpenSocket(socket, singlePortInfo))
575 return false;
577 PSTUNMessage request(PSTUNMessage::BindingRequest);
578 request.AddAttribute(PSTUNChangeRequest(false, false));
579 PSTUNMessage response;
580 if (!response.Poll(socket, request))
582 PTRACE(1, "STUN\tServer " << serverAddress << ':' << serverPort << " unexpectedly went offline.");
583 return false;
586 PSTUNMappedAddress * mappedAddress = (PSTUNMappedAddress *)response.FindAttribute(PSTUNAttribute::MAPPED_ADDRESS);
587 if (mappedAddress == NULL)
589 PTRACE(2, "STUN\tExpected mapped address attribute from server " << serverAddress << ':' << serverPort);
590 return false;
594 externalAddress = cachedExternalAddress = mappedAddress->GetIP();
595 timeAddressObtained = PTime();
596 return true;
600 BOOL PSTUNClient::CreateSocket(PUDPSocket * & socket)
602 socket = NULL;
604 switch (GetNatType(FALSE)) {
605 case ConeNat :
606 case RestrictedNat :
607 case PortRestrictedNat :
608 break;
610 case SymmetricNat :
611 if (singlePortInfo.basePort == 0 || singlePortInfo.basePort > singlePortInfo.maxPort)
613 PTRACE(1, "STUN\tInvalid local UDP port range "
614 << singlePortInfo.currentPort << '-' << singlePortInfo.maxPort);
615 return FALSE;
617 break;
619 default : // UnknownNet, SymmetricFirewall, BlockedNat
620 PTRACE(1, "STUN\tCannot create socket using NAT type " << GetNatTypeName());
621 return FALSE;
624 PSTUNUDPSocket * stunSocket = new PSTUNUDPSocket;
625 if (OpenSocket(*stunSocket, singlePortInfo))
627 PSTUNMessage request(PSTUNMessage::BindingRequest);
628 request.AddAttribute(PSTUNChangeRequest(false, false));
629 PSTUNMessage response;
631 if (response.Poll(*stunSocket, request))
633 PSTUNMappedAddress * mappedAddress = (PSTUNMappedAddress *)response.FindAttribute(PSTUNAttribute::MAPPED_ADDRESS);
634 if (mappedAddress != NULL)
636 stunSocket->externalIP = mappedAddress->GetIP();
637 if (GetNatType(FALSE) != SymmetricNat)
638 stunSocket->port = mappedAddress->port;
639 stunSocket->SetSendAddress(0, 0);
640 stunSocket->SetReadTimeout(PMaxTimeInterval);
641 socket = stunSocket;
642 return true;
645 PTRACE(2, "STUN\tExpected mapped address attribute from server " << serverAddress << ':' << serverPort);
647 else
648 PTRACE(1, "STUN\tServer " << serverAddress << ':' << serverPort << " unexpectedly went offline.");
651 delete stunSocket;
652 return false;
656 BOOL PSTUNClient::CreateSocketPair(PUDPSocket * & socket1,
657 PUDPSocket * & socket2)
659 socket1 = NULL;
660 socket2 = NULL;
662 switch (GetNatType(FALSE)) {
663 case ConeNat :
664 case RestrictedNat :
665 case PortRestrictedNat :
666 break;
668 case SymmetricNat :
669 if (pairedPortInfo.basePort == 0 || pairedPortInfo.basePort > pairedPortInfo.maxPort)
671 PTRACE(1, "STUN\tInvalid local UDP port range "
672 << pairedPortInfo.currentPort << '-' << pairedPortInfo.maxPort);
673 return FALSE;
675 break;
677 default : // UnknownNet, SymmetricFirewall, BlockedNat
678 PTRACE(1, "STUN\tCannot create socket pair using NAT type " << GetNatTypeName());
679 return FALSE;
682 int i;
684 PList<PSTUNUDPSocket> stunSocket;
685 PList<PSTUNMessage> request;
686 PList<PSTUNMessage> response;
688 for (i = 0; i < numSocketsForPairing; i++)
690 PINDEX idx = stunSocket.Append(new PSTUNUDPSocket);
691 if (!OpenSocket(stunSocket[idx], pairedPortInfo))
692 return false;
694 idx = request.Append(new PSTUNMessage(PSTUNMessage::BindingRequest));
695 request[idx].AddAttribute(PSTUNChangeRequest(false, false));
697 response.Append(new PSTUNMessage);
700 for (i = 0; i < numSocketsForPairing; i++)
702 if (!response[i].Poll(stunSocket[i], request[i]))
704 PTRACE(1, "STUN\tServer " << serverAddress << ':' << serverPort << " unexpectedly went offline.");
705 return false;
709 for (i = 0; i < numSocketsForPairing; i++)
711 PSTUNMappedAddress * mappedAddress = (PSTUNMappedAddress *)response[i].FindAttribute(PSTUNAttribute::MAPPED_ADDRESS);
712 if (mappedAddress == NULL)
714 PTRACE(2, "STUN\tExpected mapped address attribute from server " << serverAddress << ':' << serverPort);
715 return false;
717 if (GetNatType(FALSE) != SymmetricNat)
718 stunSocket[i].port = mappedAddress->port;
719 stunSocket[i].externalIP = mappedAddress->GetIP();
722 for (i = 0; i < numSocketsForPairing; i++)
724 for (int j = 0; j < numSocketsForPairing; j++)
726 if (stunSocket[i].port+1 == stunSocket[j].port)
728 stunSocket[i].SetSendAddress(0, 0);
729 stunSocket[i].SetReadTimeout(PMaxTimeInterval);
730 stunSocket[j].SetSendAddress(0, 0);
731 stunSocket[j].SetReadTimeout(PMaxTimeInterval);
732 socket1 = &stunSocket[i];
733 socket2 = &stunSocket[j];
734 stunSocket.DisallowDeleteObjects();
735 stunSocket.Remove(socket1);
736 stunSocket.Remove(socket2);
737 stunSocket.AllowDeleteObjects();
738 return true;
743 PTRACE(2, "STUN\tCould not get a pair of adjacent port numbers from NAT");
744 return false;
748 ////////////////////////////////////////////////////////////////
750 PSTUNUDPSocket::PSTUNUDPSocket()
751 : externalIP(0)
756 BOOL PSTUNUDPSocket::GetLocalAddress(Address & addr)
758 if (!externalIP.IsValid())
759 return PUDPSocket::GetLocalAddress(addr);
761 addr = externalIP;
762 return true;
766 BOOL PSTUNUDPSocket::GetLocalAddress(Address & addr, WORD & port)
768 if (!externalIP.IsValid())
769 return PUDPSocket::GetLocalAddress(addr, port);
771 addr = externalIP;
772 port = GetPort();
773 return true;
777 // End of File ////////////////////////////////////////////////////////////////