]> git.saurik.com Git - apple/mdnsresponder.git/blobdiff - mDNSMacOSX/LegacyNATTraversal.c
mDNSResponder-379.27.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / LegacyNATTraversal.c
index 115719e0334b22e6dbe75edadc2420a6a89ddb9f..8e03d6506112a520f59e09042725a9bf5c5e7c61 100644 (file)
@@ -5,9 +5,9 @@
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *     http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
 #ifdef _LEGACY_NAT_TRAVERSAL_
 
-#include "stdlib.h"                    // For strtol()
-#include "string.h"                    // For strlcpy(), For strncpy(), strncasecmp()
+#include "stdlib.h"         // For strtol()
+#include "string.h"         // For strlcpy(), For strncpy(), strncasecmp()
+#include "assert.h"         // For assert()
 
 #if defined( WIN32 )
-#      include <winsock2.h>
-#      include <ws2tcpip.h>
-#      define strcasecmp       _stricmp
-#      define strncasecmp      _strnicmp
-#      define mDNSASLLog( UUID, SUBDOMAIN, RESULT, SIGNATURE, FORMAT, ... ) ;
+#   include <winsock2.h>
+#   include <ws2tcpip.h>
+#   define strcasecmp   _stricmp
+#   define strncasecmp  _strnicmp
+#   define mDNSASLLog( UUID, SUBDOMAIN, RESULT, SIGNATURE, FORMAT, ... ) ;
 
 static int
 inet_pton( int family, const char * addr, void * dst )
-       {
-       struct sockaddr_storage ss;
-       int sslen = sizeof( ss );
-
-       ZeroMemory( &ss, sizeof( ss ) );
-       ss.ss_family = (ADDRESS_FAMILY)family;
-
-       if ( WSAStringToAddressA( (LPSTR)addr, family, NULL, ( struct sockaddr* ) &ss, &sslen ) == 0 )
-               {
-               if ( family == AF_INET ) { memcpy( dst, &( ( struct sockaddr_in* ) &ss)->sin_addr, sizeof( IN_ADDR ) ); return 1; }
-               else if ( family == AF_INET6 ) { memcpy( dst, &( ( struct sockaddr_in6* ) &ss)->sin6_addr, sizeof( IN6_ADDR ) ); return 1; }
-               else return 0;
-               }
-       else return 0;
-       }
+{
+    struct sockaddr_storage ss;
+    int sslen = sizeof( ss );
+
+    ZeroMemory( &ss, sizeof( ss ) );
+    ss.ss_family = (ADDRESS_FAMILY)family;
+
+    if ( WSAStringToAddressA( (LPSTR)addr, family, NULL, ( struct sockaddr* ) &ss, &sslen ) == 0 )
+    {
+        if ( family == AF_INET ) { memcpy( dst, &( ( struct sockaddr_in* ) &ss)->sin_addr, sizeof( IN_ADDR ) ); return 1; }
+        else if ( family == AF_INET6 ) { memcpy( dst, &( ( struct sockaddr_in6* ) &ss)->sin6_addr, sizeof( IN6_ADDR ) ); return 1; }
+        else return 0;
+    }
+    else return 0;
+}
 #else
-#      include <arpa/inet.h>           // For inet_pton()
+#   include <arpa/inet.h>       // For inet_pton()
 #endif
 
 #include "mDNSEmbeddedAPI.h"
-#include "uDNS.h"                      // For natTraversalHandleAddressReply() etc.
+#include "uDNS.h"           // For natTraversalHandleAddressReply() etc.
 
 // used to format SOAP port mapping arguments
 typedef struct Property_struct
-       {
-       char *name;
-       char *type;
-       char *value;
-       } Property;
+{
+    char *name;
+    char *type;
+    char *value;
+} Property;
 
 // All of the text parsing in this file is intentionally transparent so that we know exactly
 // what's being done to the text, with an eye towards preventing security problems.
@@ -79,828 +80,854 @@ mDNSlocal mStatus SendPortMapRequest(mDNS *m, NATTraversalInfo *n);
 
 // Note that this function assumes src is already NULL terminated
 mDNSlocal void AllocAndCopy(mDNSu8 **const dst, const mDNSu8 *const src)
-       {
-       if (src == mDNSNULL) return;
-       if ((*dst = mDNSPlatformMemAllocate((mDNSu32)strlen((char*)src) + 1)) == mDNSNULL)
-               { LogMsg("AllocAndCopy: can't allocate string"); return; }
-       strcpy((char*)*dst, (char*)src);
-       }
+{
+    if (src == mDNSNULL) return;
+    if ((*dst = mDNSPlatformMemAllocate((mDNSu32)strlen((char*)src) + 1)) == mDNSNULL)
+    { LogMsg("AllocAndCopy: can't allocate string"); return; }
+    strcpy((char*)*dst, (char*)src);
+}
 
 // This function does a simple parse of an HTTP URL that may include a hostname, port, and path
 // If found in the URL, addressAndPort and path out params will point to newly allocated space (and will leak if they were previously pointing at allocated space)
 mDNSlocal mStatus ParseHttpUrl(const mDNSu8 *ptr, const mDNSu8 *const end, mDNSu8 **const addressAndPort, mDNSIPPort *const port, mDNSu8 **const path)
-       {
-       // if the data begins with "http://", we assume there is a hostname and possibly a port number
-       if (end - ptr >= 7 && strncasecmp((char*)ptr, "http://", 7) == 0)
-               {
-               int i;
-               const mDNSu8 *stop = end;
-               const mDNSu8 *addrPtr = mDNSNULL;
-               
-               ptr += 7; //skip over "http://"
-               if (ptr >= end) { LogInfo("ParseHttpUrl: past end of buffer parsing host:port"); return mStatus_BadParamErr; }
-               
-               // find the end of the host:port
-               addrPtr = ptr;
-               for (i = 0; addrPtr && addrPtr != end; i++, addrPtr++) if (*addrPtr == '/') break;
-
-               // allocate the buffer (len i+1 so we have space to terminate the string)
-               if ((*addressAndPort = mDNSPlatformMemAllocate(i+1)) == mDNSNULL)
-                       { LogMsg("ParseHttpUrl: can't allocate address string"); return mStatus_NoMemoryErr; }
-               strncpy((char*)*addressAndPort, (char*)ptr, i);
-               (*addressAndPort)[i] = '\0';
-
-               // find the port number in the string, by looking backwards for the ':'
-               stop = ptr;    // can't go back farther than the original start
-               ptr = addrPtr; // move ptr to the path part
-               
-               for (addrPtr--; addrPtr>stop; addrPtr--)
-                       {
-                       if (*addrPtr == ':')
-                               {
-                               addrPtr++; // skip over ':'
-                               *port = mDNSOpaque16fromIntVal((mDNSu16)strtol((char*)addrPtr, mDNSNULL, 10)); // store it properly converted
-                               break;
-                               }
-                       }
-               }
-               
-       // ptr should now point to the first character we haven't yet processed
-       // everything that remains is the path
-       if (path && ptr < end)
-               {
-               if ((*path = mDNSPlatformMemAllocate((mDNSu32)(end - ptr) + 1)) == mDNSNULL)
-                       { LogMsg("ParseHttpUrl: can't mDNSPlatformMemAllocate path"); return mStatus_NoMemoryErr; }
-               strncpy((char*)*path, (char*)ptr, end - ptr);
-               (*path)[end - ptr] = '\0';
-               }
-               
-       return mStatus_NoError;
-       }
+{
+    // if the data begins with "http://", we assume there is a hostname and possibly a port number
+    if (end - ptr >= 7 && strncasecmp((char*)ptr, "http://", 7) == 0)
+    {
+        int i;
+        const mDNSu8 *stop = end;
+        const mDNSu8 *addrPtr = mDNSNULL;
+
+        ptr += 7; //skip over "http://"
+        if (ptr >= end) { LogInfo("ParseHttpUrl: past end of buffer parsing host:port"); return mStatus_BadParamErr; }
+
+        // find the end of the host:port
+        addrPtr = ptr;
+        for (i = 0; addrPtr && addrPtr != end; i++, addrPtr++) if (*addrPtr == '/') break;
+
+        // allocate the buffer (len i+1 so we have space to terminate the string)
+        if ((*addressAndPort = mDNSPlatformMemAllocate(i+1)) == mDNSNULL)
+        { LogMsg("ParseHttpUrl: can't allocate address string"); return mStatus_NoMemoryErr; }
+        strncpy((char*)*addressAndPort, (char*)ptr, i);
+        (*addressAndPort)[i] = '\0';
+
+        // find the port number in the string, by looking backwards for the ':'
+        stop = ptr;    // can't go back farther than the original start
+        ptr = addrPtr; // move ptr to the path part
+
+        for (addrPtr--; addrPtr>stop; addrPtr--)
+        {
+            if (*addrPtr == ':')
+            {
+                addrPtr++; // skip over ':'
+                *port = mDNSOpaque16fromIntVal((mDNSu16)strtol((char*)addrPtr, mDNSNULL, 10)); // store it properly converted
+                break;
+            }
+        }
+    }
+
+    // ptr should now point to the first character we haven't yet processed
+    // everything that remains is the path
+    if (path && ptr < end)
+    {
+        if ((*path = mDNSPlatformMemAllocate((mDNSu32)(end - ptr) + 1)) == mDNSNULL)
+        { LogMsg("ParseHttpUrl: can't mDNSPlatformMemAllocate path"); return mStatus_NoMemoryErr; }
+        strncpy((char*)*path, (char*)ptr, end - ptr);
+        (*path)[end - ptr] = '\0';
+    }
+
+    return mStatus_NoError;
+}
 
 enum
-       {
-       HTTPCode_NeedMoreData = -1, // No code found in stream
-       HTTPCode_Other        = -2, // Valid code other than those below found in stream
-       HTTPCode_Bad          = -3,
-       HTTPCode_200          = 200,
-       HTTPCode_404          = 404,
-       HTTPCode_500          = 500,
-       };
-       
+{
+    HTTPCode_NeedMoreData = -1, // No code found in stream
+    HTTPCode_Other        = -2, // Valid code other than those below found in stream
+    HTTPCode_Bad          = -3,
+    HTTPCode_200          = 200,
+    HTTPCode_404          = 404,
+    HTTPCode_500          = 500,
+};
+
 mDNSlocal mDNSs16 ParseHTTPResponseCode(const mDNSu8 **const data, const mDNSu8 *const end)
-       {
-       const mDNSu8 *ptr = *data;
-       const mDNSu8 *code;
-       
-       if (end - ptr < 5) return HTTPCode_NeedMoreData;
-       if (strncasecmp((char*)ptr, "HTTP/", 5) != 0) return HTTPCode_Bad;
-       ptr += 5;
-       // should we care about the HTTP protocol version?
-       
-       // look for first space, which must come before first LF
-       while (ptr && ptr != end)
-               {
-               if (*ptr == '\n') return HTTPCode_Bad;
-               if (*ptr == ' ') break;
-               ptr++;
-               }
-       if (ptr == end) return HTTPCode_NeedMoreData;
-       ptr++;
-       
-       if (end - ptr < 3) return HTTPCode_NeedMoreData;
-
-       code = ptr;
-       ptr += 3;
-       while (ptr && ptr != end)
-               {
-               if (*ptr == '\n') break;
-               ptr++;
-               }
-       if (ptr == end) return HTTPCode_NeedMoreData;
-       *data = ++ptr;
-       
-       if (memcmp((char*)code, "200", 3) == 0) return HTTPCode_200;
-       if (memcmp((char*)code, "404", 3) == 0) return HTTPCode_404;
-       if (memcmp((char*)code, "500", 3) == 0) return HTTPCode_500;
-       
-       LogInfo("ParseHTTPResponseCode found unexpected result code: %c%c%c", code[0], code[1], code[2]);
-       return HTTPCode_Other;
-       }
+{
+    const mDNSu8 *ptr = *data;
+    const mDNSu8 *code;
+
+    if (end - ptr < 5) return HTTPCode_NeedMoreData;
+    if (strncasecmp((char*)ptr, "HTTP/", 5) != 0) return HTTPCode_Bad;
+    ptr += 5;
+    // should we care about the HTTP protocol version?
+
+    // look for first space, which must come before first LF
+    while (ptr && ptr != end)
+    {
+        if (*ptr == '\n') return HTTPCode_Bad;
+        if (*ptr == ' ') break;
+        ptr++;
+    }
+    if (ptr == end) return HTTPCode_NeedMoreData;
+    ptr++;
+
+    if (end - ptr < 3) return HTTPCode_NeedMoreData;
+
+    code = ptr;
+    ptr += 3;
+    while (ptr && ptr != end)
+    {
+        if (*ptr == '\n') break;
+        ptr++;
+    }
+    if (ptr == end) return HTTPCode_NeedMoreData;
+    *data = ++ptr;
+
+    if (memcmp((char*)code, "200", 3) == 0) return HTTPCode_200;
+    if (memcmp((char*)code, "404", 3) == 0) return HTTPCode_404;
+    if (memcmp((char*)code, "500", 3) == 0) return HTTPCode_500;
+
+    LogInfo("ParseHTTPResponseCode found unexpected result code: %c%c%c", code[0], code[1], code[2]);
+    return HTTPCode_Other;
+}
 
 // This function parses the xml body of the device description response from the router. Basically, we look to
 // make sure this is a response referencing a service we care about (WANIPConnection or WANPPPConnection),
 // look for the "controlURL" header immediately following, and copy the addressing and URL info we need
 mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo)
-       {
-       mDNS    *m    = tcpInfo->m;
-       const mDNSu8 *ptr  = tcpInfo->Reply;
-       const mDNSu8 *end  = tcpInfo->Reply + tcpInfo->nread;
-       const mDNSu8 *stop;
-       mDNSs16 http_result;
-       
-       if (!mDNSIPPortIsZero(m->UPnPSOAPPort)) return; // already have the info we need
-
-       http_result = ParseHTTPResponseCode(&ptr, end); // Note: modifies ptr
-       if (http_result == HTTPCode_404) LNT_ClearState(m);
-       if (http_result != HTTPCode_200) 
-               {
-               mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "noop", "HTTP Result", "HTTP code: %d", http_result);
-               return;
-               }
-
-       // Always reset our flag to use WANIPConnection.  We'll use WANPPPConnection if we find it and don't find WANIPConnection.
-       m->UPnPWANPPPConnection = mDNSfalse;
-
-       // find either service we care about
-       while (ptr && ptr < end)
-               {
-               if ((*ptr & 0xDF) == 'W' && (strncasecmp((char*)ptr, "WANIPConnection:1", 17) == 0)) break;
-               ptr++;
-               }
-       if (ptr == end)
-               {
-               ptr = tcpInfo->Reply;
-               while (ptr && ptr < end)
-                       {
-                       if ((*ptr & 0xDF) == 'W' && (strncasecmp((char*)ptr, "WANPPPConnection:1", 18) == 0))
-                               {
-                               m->UPnPWANPPPConnection = mDNStrue;
-                               break;
-                               }
-                       ptr++;
-                       }
-               }
-       if (ptr == mDNSNULL || ptr == end) { LogInfo("handleLNTDeviceDescriptionResponse: didn't find WANIPConnection:1 or WANPPPConnection:1 string"); return; }
-
-       // find "controlURL", starting from where we left off
-       while (ptr && ptr < end)
-               {
-               if ((*ptr & 0xDF) == 'C' && (strncasecmp((char*)ptr, "controlURL", 10) == 0)) break;                    // find the first 'c'; is this controlURL? if not, keep looking
-               ptr++;
-               }
-       if (ptr == mDNSNULL || ptr == end) { LogInfo("handleLNTDeviceDescriptionResponse: didn't find controlURL string"); return; }
-       ptr += 11;                                                      // skip over "controlURL>"
-       if (ptr >= end) { LogInfo("handleLNTDeviceDescriptionResponse: past end of buffer and no body!"); return; } // check ptr again in case we skipped over the end of the buffer
-
-       // find the end of the controlURL element
-       for (stop = ptr; stop < end; stop++) { if (*stop == '<') { end = stop; break; } }
-
-       // fill in default port
-       m->UPnPSOAPPort = m->UPnPRouterPort;
-
-       // free string pointers and set to NULL 
-       if (m->UPnPSOAPAddressString != mDNSNULL)
-               {
-               mDNSPlatformMemFree(m->UPnPSOAPAddressString);
-               m->UPnPSOAPAddressString = mDNSNULL;
-               }
-       if (m->UPnPSOAPURL != mDNSNULL)
-               {
-               mDNSPlatformMemFree(m->UPnPSOAPURL);
-               m->UPnPSOAPURL = mDNSNULL; 
-               }
-       
-       if (ParseHttpUrl(ptr, end, &m->UPnPSOAPAddressString, &m->UPnPSOAPPort, &m->UPnPSOAPURL) != mStatus_NoError) return;
-       // the SOAPURL should look something like "/uuid:0013-108c-4b3f0000f3dc"
-
-       if (m->UPnPSOAPAddressString == mDNSNULL)
-               {
-               ptr = tcpInfo->Reply;
-               while (ptr && ptr < end)
-                       {
-                       if ((*ptr & 0xDF) == 'U' && (strncasecmp((char*)ptr, "URLBase", 7) == 0))               break;
-                       ptr++;
-                       }
-
-               if (ptr < end)          // found URLBase
-                       {
-                       LogInfo("handleLNTDeviceDescriptionResponse: found URLBase");                   
-                       ptr += 8; // skip over "URLBase>"
-                       // find the end of the URLBase element
-                       for (stop = ptr; stop < end; stop++) { if (*stop == '<') { end = stop; break; } }
-                       if (ParseHttpUrl(ptr, end, &m->UPnPSOAPAddressString, &m->UPnPSOAPPort, mDNSNULL) != mStatus_NoError)
-                               {
-                               LogInfo("handleLNTDeviceDescriptionResponse: failed to parse URLBase");
-                               }
-                       }
-               
-               // if all else fails, use the router address string
-               if (m->UPnPSOAPAddressString == mDNSNULL) AllocAndCopy(&m->UPnPSOAPAddressString, m->UPnPRouterAddressString);
-               }
-       if (m->UPnPSOAPAddressString == mDNSNULL) LogMsg("handleLNTDeviceDescriptionResponse: UPnPSOAPAddressString is NULL");
-       else LogInfo("handleLNTDeviceDescriptionResponse: SOAP address string [%s]", m->UPnPSOAPAddressString);
-
-       if (m->UPnPSOAPURL == mDNSNULL) AllocAndCopy(&m->UPnPSOAPURL, m->UPnPRouterURL);
-       if (m->UPnPSOAPURL == mDNSNULL) LogMsg("handleLNTDeviceDescriptionResponse: UPnPSOAPURL is NULL");
-       else LogInfo("handleLNTDeviceDescriptionResponse: SOAP URL [%s]", m->UPnPSOAPURL);
-       }
+{
+    mDNS    *m    = tcpInfo->m;
+    const mDNSu8 *ptr  = tcpInfo->Reply;
+    const mDNSu8 *end  = tcpInfo->Reply + tcpInfo->nread;
+    const mDNSu8 *stop;
+    mDNSs16 http_result;
+
+    if (!mDNSIPPortIsZero(m->UPnPSOAPPort)) return; // already have the info we need
+
+    http_result = ParseHTTPResponseCode(&ptr, end); // Note: modifies ptr
+    if (http_result == HTTPCode_404) LNT_ClearState(m);
+    if (http_result != HTTPCode_200)
+    {
+        mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "noop", "HTTP Result", "HTTP code: %d", http_result);
+        return;
+    }
+
+    // Always reset our flag to use WANIPConnection.  We'll use WANPPPConnection if we find it and don't find WANIPConnection.
+    m->UPnPWANPPPConnection = mDNSfalse;
+
+    // find either service we care about
+    while (ptr && ptr < end)
+    {
+        if ((*ptr & 0xDF) == 'W' && (strncasecmp((char*)ptr, "WANIPConnection:1", 17) == 0)) break;
+        ptr++;
+    }
+    if (ptr == end)
+    {
+        ptr = tcpInfo->Reply;
+        while (ptr && ptr < end)
+        {
+            if ((*ptr & 0xDF) == 'W' && (strncasecmp((char*)ptr, "WANPPPConnection:1", 18) == 0))
+            {
+                m->UPnPWANPPPConnection = mDNStrue;
+                break;
+            }
+            ptr++;
+        }
+    }
+    if (ptr == mDNSNULL || ptr == end) { LogInfo("handleLNTDeviceDescriptionResponse: didn't find WANIPConnection:1 or WANPPPConnection:1 string"); return; }
+
+    // find "controlURL", starting from where we left off
+    while (ptr && ptr < end)
+    {
+        if ((*ptr & 0xDF) == 'C' && (strncasecmp((char*)ptr, "controlURL", 10) == 0)) break;            // find the first 'c'; is this controlURL? if not, keep looking
+        ptr++;
+    }
+    if (ptr == mDNSNULL || ptr == end) { LogInfo("handleLNTDeviceDescriptionResponse: didn't find controlURL string"); return; }
+    ptr += 11;                          // skip over "controlURL>"
+    if (ptr >= end) { LogInfo("handleLNTDeviceDescriptionResponse: past end of buffer and no body!"); return; } // check ptr again in case we skipped over the end of the buffer
+
+    // find the end of the controlURL element
+    for (stop = ptr; stop < end; stop++) { if (*stop == '<') { end = stop; break; } }
+
+    // fill in default port
+    m->UPnPSOAPPort = m->UPnPRouterPort;
+
+    // free string pointers and set to NULL
+    if (m->UPnPSOAPAddressString != mDNSNULL)
+    {
+        mDNSPlatformMemFree(m->UPnPSOAPAddressString);
+        m->UPnPSOAPAddressString = mDNSNULL;
+    }
+    if (m->UPnPSOAPURL != mDNSNULL)
+    {
+        mDNSPlatformMemFree(m->UPnPSOAPURL);
+        m->UPnPSOAPURL = mDNSNULL;
+    }
+
+    if (ParseHttpUrl(ptr, end, &m->UPnPSOAPAddressString, &m->UPnPSOAPPort, &m->UPnPSOAPURL) != mStatus_NoError) return;
+    // the SOAPURL should look something like "/uuid:0013-108c-4b3f0000f3dc"
+
+    if (m->UPnPSOAPAddressString == mDNSNULL)
+    {
+        ptr = tcpInfo->Reply;
+        while (ptr && ptr < end)
+        {
+            if ((*ptr & 0xDF) == 'U' && (strncasecmp((char*)ptr, "URLBase", 7) == 0)) break;
+            ptr++;
+        }
+
+        if (ptr < end)      // found URLBase
+        {
+            LogInfo("handleLNTDeviceDescriptionResponse: found URLBase");
+            ptr += 8; // skip over "URLBase>"
+            // find the end of the URLBase element
+            for (stop = ptr; stop < end; stop++) { if (*stop == '<') { end = stop; break; } }
+            if (ParseHttpUrl(ptr, end, &m->UPnPSOAPAddressString, &m->UPnPSOAPPort, mDNSNULL) != mStatus_NoError)
+            {
+                LogInfo("handleLNTDeviceDescriptionResponse: failed to parse URLBase");
+            }
+        }
+
+        // if all else fails, use the router address string
+        if (m->UPnPSOAPAddressString == mDNSNULL) AllocAndCopy(&m->UPnPSOAPAddressString, m->UPnPRouterAddressString);
+    }
+    if (m->UPnPSOAPAddressString == mDNSNULL) LogMsg("handleLNTDeviceDescriptionResponse: UPnPSOAPAddressString is NULL");
+    else LogInfo("handleLNTDeviceDescriptionResponse: SOAP address string [%s]", m->UPnPSOAPAddressString);
+
+    if (m->UPnPSOAPURL == mDNSNULL) AllocAndCopy(&m->UPnPSOAPURL, m->UPnPRouterURL);
+    if (m->UPnPSOAPURL == mDNSNULL) LogMsg("handleLNTDeviceDescriptionResponse: UPnPSOAPURL is NULL");
+    else LogInfo("handleLNTDeviceDescriptionResponse: SOAP URL [%s]", m->UPnPSOAPURL);
+}
 
 mDNSlocal void handleLNTGetExternalAddressResponse(tcpLNTInfo *tcpInfo)
-       {
-       mDNS       *m = tcpInfo->m;
-       mDNSu16     err = NATErr_None;
-       mDNSv4Addr  ExtAddr;
-       const mDNSu8 *ptr = tcpInfo->Reply;
-       const mDNSu8 *end = tcpInfo->Reply + tcpInfo->nread;
-       mDNSu8       *addrend;
-       static char tagname[20] = { 'N','e','w','E','x','t','e','r','n','a','l','I','P','A','d','d','r','e','s','s' };
-       // Array NOT including a terminating nul
+{
+    mDNS       *m = tcpInfo->m;
+    mDNSu16 err = NATErr_None;
+    mDNSv4Addr ExtAddr;
+    const mDNSu8 *ptr = tcpInfo->Reply;
+    const mDNSu8 *end = tcpInfo->Reply + tcpInfo->nread;
+    mDNSu8       *addrend;
+    static char tagname[20] = { 'N','e','w','E','x','t','e','r','n','a','l','I','P','A','d','d','r','e','s','s' };
+    // Array NOT including a terminating nul
 
 //     LogInfo("handleLNTGetExternalAddressResponse: %s", ptr);
 
-       mDNSs16 http_result = ParseHTTPResponseCode(&ptr, end); // Note: modifies ptr
-       if (http_result == HTTPCode_404) LNT_ClearState(m);
-       if (http_result != HTTPCode_200)
-               {
-               mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest", "noop", "HTTP Result", "HTTP code: %d", http_result);
-               return;
-               }
-
-       while (ptr < end && strncasecmp((char*)ptr, tagname, sizeof(tagname))) ptr++;
-       ptr += sizeof(tagname);                                         // Skip over "NewExternalIPAddress"
-       while (ptr < end && *ptr != '>') ptr++;
-       ptr += 1;                                                                       // Skip over ">"
-
-       // Find the end of the address and terminate the string so inet_pton() can convert it
-       // (Might be better to copy this to a local string here -- this is overwriting tcpInfo->Reply in-place
-       addrend = (mDNSu8*)ptr;
-       while (addrend < end && (mDNSIsDigit(*addrend) || *addrend == '.')) addrend++;
-       if (addrend >= end) return;
-       *addrend = 0;
-
-       if (inet_pton(AF_INET, (char*)ptr, &ExtAddr) <= 0)
-               {
-               mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest", "noop", "inet_pton", "");
-               LogMsg("handleLNTGetExternalAddressResponse: Router returned bad address %s", ptr);
-               err = NATErr_NetFail;
-               ExtAddr = zerov4Addr;
-               }
-       if (!err) LogInfo("handleLNTGetExternalAddressResponse: External IP address is %.4a", &ExtAddr);
-
-       natTraversalHandleAddressReply(m, err, ExtAddr);
-       }
+    mDNSs16 http_result = ParseHTTPResponseCode(&ptr, end); // Note: modifies ptr
+    if (http_result == HTTPCode_404) LNT_ClearState(m);
+    if (http_result != HTTPCode_200)
+    {
+        mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest", "noop", "HTTP Result", "HTTP code: %d", http_result);
+        return;
+    }
+
+    while (ptr < end && strncasecmp((char*)ptr, tagname, sizeof(tagname))) ptr++;
+    ptr += sizeof(tagname);                     // Skip over "NewExternalIPAddress"
+    while (ptr < end && *ptr != '>') ptr++;
+    ptr += 1;                                   // Skip over ">"
+
+    // Find the end of the address and terminate the string so inet_pton() can convert it
+    // (Might be better to copy this to a local string here -- this is overwriting tcpInfo->Reply in-place
+    addrend = (mDNSu8*)ptr;
+    while (addrend < end && (mDNSIsDigit(*addrend) || *addrend == '.')) addrend++;
+    if (addrend >= end) return;
+    *addrend = 0;
+
+    if (inet_pton(AF_INET, (char*)ptr, &ExtAddr) <= 0)
+    {
+        mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest", "noop", "inet_pton", "");
+        LogMsg("handleLNTGetExternalAddressResponse: Router returned bad address %s", ptr);
+        err = NATErr_NetFail;
+        ExtAddr = zerov4Addr;
+    }
+    if (!err) LogInfo("handleLNTGetExternalAddressResponse: External IP address is %.4a", &ExtAddr);
+
+    natTraversalHandleAddressReply(m, err, ExtAddr);
+}
 
 mDNSlocal void handleLNTPortMappingResponse(tcpLNTInfo *tcpInfo)
-       {
-       mDNS             *m         = tcpInfo->m;
-       mDNSIPPort        extport   = zeroIPPort;
-       const mDNSu8     *ptr       = tcpInfo->Reply;
-       const mDNSu8     *const end = tcpInfo->Reply + tcpInfo->nread;
-       NATTraversalInfo *natInfo;
-       mDNSs16 http_result;
-
-       for (natInfo = m->NATTraversals; natInfo; natInfo=natInfo->next) { if (natInfo == tcpInfo->parentNATInfo) break; }
-
-       if (!natInfo) { LogInfo("handleLNTPortMappingResponse: can't find matching tcpInfo in NATTraversals!"); return; }
-
-       http_result = ParseHTTPResponseCode(&ptr, end); // Note: modifies ptr
-       if (http_result == HTTPCode_200)
-               {
-               LogInfo("handleLNTPortMappingResponse: got a valid response, sending reply to natTraversalHandlePortMapReply(internal %d external %d retries %d)",
-                       mDNSVal16(natInfo->IntPort), RequestedPortNum(natInfo), tcpInfo->retries);
-       
-               // Make sure to compute extport *before* we zero tcpInfo->retries
-               extport = mDNSOpaque16fromIntVal(RequestedPortNum(natInfo));
-               tcpInfo->retries = 0;
-               natTraversalHandlePortMapReply(m, natInfo, m->UPnPInterfaceID, mStatus_NoError, extport, NATMAP_DEFAULT_LEASE);
-               }
-       else if (http_result == HTTPCode_500)
-               {
-               while (ptr && ptr != end)
-                       {
-                       if (((*ptr & 0xDF) == 'C' && end - ptr >= 8 && strncasecmp((char*)ptr, "Conflict", 8) == 0) ||
-                               (*ptr == '>' && end - ptr >= 15 && strncasecmp((char*)ptr, ">718</errorCode", 15) == 0))
-                               {
-                               if (tcpInfo->retries < 100)
-                                       { 
-                                       tcpInfo->retries++; SendPortMapRequest(tcpInfo->m, natInfo); 
-                                       mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "Conflict", "Retry %d", tcpInfo->retries);
-                                       }
-                               else
-                                       {
-                                       LogMsg("handleLNTPortMappingResponse too many conflict retries %d %d", mDNSVal16(natInfo->IntPort), mDNSVal16(natInfo->RequestedPort));
-                                       mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "Conflict - too many retries", "Retries: %d", tcpInfo->retries);
-                                       natTraversalHandlePortMapReply(m, natInfo, m->UPnPInterfaceID, NATErr_Res, zeroIPPort, 0);
-                                       }
-                               return;
-                               }
-                       ptr++;
-                       }
-               }
-       else if (http_result == HTTPCode_Bad) LogMsg("handleLNTPortMappingResponse got data that was not a valid HTTP response");
-       else if (http_result == HTTPCode_Other) LogMsg("handleLNTPortMappingResponse got unexpected response code");
-       else if (http_result == HTTPCode_404) LNT_ClearState(m);
-       if (http_result != HTTPCode_200 && http_result != HTTPCode_500)
-               mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "HTTP Result", "HTTP code: %d", http_result);
-       }
+{
+    mDNS             *m         = tcpInfo->m;
+    mDNSIPPort extport   = zeroIPPort;
+    const mDNSu8     *ptr       = tcpInfo->Reply;
+    const mDNSu8     *const end = tcpInfo->Reply + tcpInfo->nread;
+    NATTraversalInfo *natInfo;
+    mDNSs16 http_result;
+
+    for (natInfo = m->NATTraversals; natInfo; natInfo=natInfo->next) { if (natInfo == tcpInfo->parentNATInfo) break;}
+
+    if (!natInfo) { LogInfo("handleLNTPortMappingResponse: can't find matching tcpInfo in NATTraversals!"); return; }
+
+    http_result = ParseHTTPResponseCode(&ptr, end); // Note: modifies ptr
+    if (http_result == HTTPCode_200)
+    {
+        LogInfo("handleLNTPortMappingResponse: got a valid response, sending reply to natTraversalHandlePortMapReply(internal %d external %d retries %d)",
+                mDNSVal16(natInfo->IntPort), RequestedPortNum(natInfo), tcpInfo->retries);
+
+        // Make sure to compute extport *before* we zero tcpInfo->retries
+        extport = mDNSOpaque16fromIntVal(RequestedPortNum(natInfo));
+        tcpInfo->retries = 0;
+        natTraversalHandlePortMapReply(m, natInfo, m->UPnPInterfaceID, mStatus_NoError, extport, NATMAP_DEFAULT_LEASE);
+    }
+    else if (http_result == HTTPCode_500)
+    {
+        while (ptr && ptr != end)
+        {
+            if (((*ptr & 0xDF) == 'C' && end - ptr >= 8 && strncasecmp((char*)ptr, "Conflict", 8) == 0) ||
+                (*ptr == '>' && end - ptr >= 15 && strncasecmp((char*)ptr, ">718</errorCode", 15) == 0))
+            {
+                if (tcpInfo->retries < 100)
+                {
+                    tcpInfo->retries++; SendPortMapRequest(tcpInfo->m, natInfo);
+                    mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "Conflict", "Retry %d", tcpInfo->retries);
+                }
+                else
+                {
+                    LogMsg("handleLNTPortMappingResponse too many conflict retries %d %d", mDNSVal16(natInfo->IntPort), mDNSVal16(natInfo->RequestedPort));
+                    mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "Conflict - too many retries", "Retries: %d", tcpInfo->retries);
+                    natTraversalHandlePortMapReply(m, natInfo, m->UPnPInterfaceID, NATErr_Res, zeroIPPort, 0);
+                }
+                return;
+            }
+            ptr++;
+        }
+    }
+    else if (http_result == HTTPCode_Bad) LogMsg("handleLNTPortMappingResponse got data that was not a valid HTTP response");
+    else if (http_result == HTTPCode_Other) LogMsg("handleLNTPortMappingResponse got unexpected response code");
+    else if (http_result == HTTPCode_404) LNT_ClearState(m);
+    if (http_result != HTTPCode_200 && http_result != HTTPCode_500)
+        mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "HTTP Result", "HTTP code: %d", http_result);
+}
 
 mDNSlocal void DisposeInfoFromUnmapList(mDNS *m, tcpLNTInfo *tcpInfo)
-       {
-       tcpLNTInfo **ptr = &m->tcpInfoUnmapList;
-       while (*ptr && *ptr != tcpInfo) ptr = &(*ptr)->next;
-       if (*ptr) { *ptr = (*ptr)->next; mDNSPlatformMemFree(tcpInfo); }        // If we found it, cut it from our list and free the memory
-       }
+{
+    tcpLNTInfo **ptr = &m->tcpInfoUnmapList;
+    while (*ptr && *ptr != tcpInfo) ptr = &(*ptr)->next;
+    if (*ptr) { *ptr = (*ptr)->next; mDNSPlatformMemFree(tcpInfo); }    // If we found it, cut it from our list and free the memory
+}
 
 mDNSlocal void tcpConnectionCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err)
-       {
-       mStatus     status  = mStatus_NoError;
-       tcpLNTInfo *tcpInfo = (tcpLNTInfo *)context;
-       mDNSBool    closed  = mDNSfalse;
-       long        n       = 0;
-       long        nsent   = 0;
-
-       if (tcpInfo == mDNSNULL) { LogInfo("tcpConnectionCallback: no tcpInfo context"); status = mStatus_Invalid; goto exit; }
-
-       // The handlers below expect to be called with the lock held
-       mDNS_Lock(tcpInfo->m);
-       
-       if (err) { LogInfo("tcpConnectionCallback: received error"); goto exit; }
-
-       if (ConnectionEstablished)              // connection is established - send the message
-               {
-               LogInfo("tcpConnectionCallback: connection established, sending message");
-               nsent = mDNSPlatformWriteTCP(sock, (char*)tcpInfo->Request, tcpInfo->requestLen);
-               if (nsent != (long)tcpInfo->requestLen) { LogMsg("tcpConnectionCallback: error writing"); status = mStatus_UnknownErr; goto exit; }
-               }
-       else
-               {
-               n = mDNSPlatformReadTCP(sock, (char*)tcpInfo->Reply + tcpInfo->nread, tcpInfo->replyLen - tcpInfo->nread, &closed);
-               LogInfo("tcpConnectionCallback: mDNSPlatformReadTCP read %d bytes", n);
-
-               if      (n < 0)  { LogInfo("tcpConnectionCallback - read returned %d", n);                           status = mStatus_ConnFailed; goto exit; }
-               else if (closed) { LogInfo("tcpConnectionCallback: socket closed by remote end %d", tcpInfo->nread); status = mStatus_ConnFailed; goto exit; }
-
-               tcpInfo->nread += n;
-               LogInfo("tcpConnectionCallback tcpInfo->nread %d", tcpInfo->nread);
-               if (tcpInfo->nread > LNT_MAXBUFSIZE)
-                       {
-                       LogInfo("result truncated...");
-                       tcpInfo->nread = LNT_MAXBUFSIZE;
-                       }
-
-               switch (tcpInfo->op)
-                       {
-                       case LNTDiscoveryOp:     handleLNTDeviceDescriptionResponse (tcpInfo); break;
-                       case LNTExternalAddrOp:  handleLNTGetExternalAddressResponse(tcpInfo); break;
-                       case LNTPortMapOp:       handleLNTPortMappingResponse       (tcpInfo); break;
-                       case LNTPortMapDeleteOp: status = mStatus_ConfigChanged;               break;
-                       default: LogMsg("tcpConnectionCallback: bad tcp operation! %d", tcpInfo->op); status = mStatus_Invalid; break;
-                       }
-               }
+{
+    mStatus status  = mStatus_NoError;
+    tcpLNTInfo *tcpInfo = (tcpLNTInfo *)context;
+    mDNSBool closed  = mDNSfalse;
+    long n       = 0;
+    long nsent   = 0;
+    static int LNTERRORcount = 0;
+
+    if (tcpInfo == mDNSNULL) { LogInfo("tcpConnectionCallback: no tcpInfo context"); status = mStatus_Invalid; goto exit; }
+    
+    if (tcpInfo->sock != sock)
+    {
+        LogMsg("tcpConnectionCallback: WARNING- tcpInfo->sock(%p) != sock(%p) !!! Printing tcpInfo struct", tcpInfo->sock, sock);
+        LogMsg("tcpConnectionCallback: tcpInfo->Address:Port [%#a:%d] tcpInfo->op[%d] tcpInfo->retries[%d] tcpInfo->Request[%s] tcpInfo->Reply[%s]", 
+                &tcpInfo->Address, mDNSVal16(tcpInfo->Port), tcpInfo->op, tcpInfo->retries, tcpInfo->Request, tcpInfo->Reply);  
+    }
+        
+    // The handlers below expect to be called with the lock held
+    mDNS_Lock(tcpInfo->m);
+
+    if (err) { LogInfo("tcpConnectionCallback: received error"); goto exit; }
+
+    if (ConnectionEstablished)      // connection is established - send the message
+    {
+        LogInfo("tcpConnectionCallback: connection established, sending message");
+        nsent = mDNSPlatformWriteTCP(sock, (char*)tcpInfo->Request, tcpInfo->requestLen);
+        if (nsent != (long)tcpInfo->requestLen) { LogMsg("tcpConnectionCallback: error writing"); status = mStatus_UnknownErr; goto exit; }
+    }
+    else
+    {
+        n = mDNSPlatformReadTCP(sock, (char*)tcpInfo->Reply + tcpInfo->nread, tcpInfo->replyLen - tcpInfo->nread, &closed);
+        LogInfo("tcpConnectionCallback: mDNSPlatformReadTCP read %d bytes", n);
+
+        if      (n < 0)  { LogInfo("tcpConnectionCallback - read returned %d", n);                           status = mStatus_ConnFailed; goto exit; }
+        else if (closed) { LogInfo("tcpConnectionCallback: socket closed by remote end %d", tcpInfo->nread); status = mStatus_ConnFailed; goto exit; }
+
+        tcpInfo->nread += n;
+        LogInfo("tcpConnectionCallback tcpInfo->nread %d", tcpInfo->nread);
+        if (tcpInfo->nread > LNT_MAXBUFSIZE)
+        {
+            LogInfo("result truncated...");
+            tcpInfo->nread = LNT_MAXBUFSIZE;
+        }
+
+        switch (tcpInfo->op)
+        {
+        case LNTDiscoveryOp:     handleLNTDeviceDescriptionResponse (tcpInfo); break;
+        case LNTExternalAddrOp:  handleLNTGetExternalAddressResponse(tcpInfo); break;
+        case LNTPortMapOp:       handleLNTPortMappingResponse       (tcpInfo); break;
+        case LNTPortMapDeleteOp: status = mStatus_ConfigChanged;               break;
+        default: LogMsg("tcpConnectionCallback: bad tcp operation! %d", tcpInfo->op); status = mStatus_Invalid; break;
+        }
+    }
 exit:
-       if (err || status)
-               {
-               mDNS   *m = tcpInfo->m;
-               switch (tcpInfo->op)
-                       {
-                       case LNTDiscoveryOp:     if (m->UPnPSOAPAddressString == mDNSNULL)
-                                                                               mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "failure", "SOAP Address", "");
-                                                                        if (m->UPnPSOAPURL == mDNSNULL)
-                                                                               mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "failure", "SOAP path", "");
-                                                                        if (m->UPnPSOAPAddressString && m->UPnPSOAPURL)
-                                                                               mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "success", "success", "");
-                                                                        break;
-                       case LNTExternalAddrOp:  mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest",
-                                                                               mDNSIPv4AddressIsZero(m->ExternalAddress) ? "failure" : "success",
-                                                                               mDNSIPv4AddressIsZero(m->ExternalAddress) ? "failure" : "success", "");
-                                                                        break;
-                       case LNTPortMapOp:       if (tcpInfo->parentNATInfo)    
-                                                                               mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", (tcpInfo->parentNATInfo->Result) ? "failure" : "success", 
-                                                                                       (tcpInfo->parentNATInfo->Result) ? "failure" : "success", "Result: %d", tcpInfo->parentNATInfo->Result);
-                                                                        break;
-                       case LNTPortMapDeleteOp: break;
-                       default:                                 break;
-                       }
-
-               mDNSPlatformTCPCloseConnection(tcpInfo->sock);
-               tcpInfo->sock = mDNSNULL;
-               if (tcpInfo->Request) { mDNSPlatformMemFree(tcpInfo->Request); tcpInfo->Request = mDNSNULL; }
-               if (tcpInfo->Reply  ) { mDNSPlatformMemFree(tcpInfo->Reply);   tcpInfo->Reply   = mDNSNULL; }
-               }
-
-       if (tcpInfo) mDNS_Unlock(tcpInfo->m);
-
-       if (status == mStatus_ConfigChanged) DisposeInfoFromUnmapList(tcpInfo->m, tcpInfo);
-       }
+    if (err || status)
+    {
+        mDNS   *m = tcpInfo->m;
+        if ((++LNTERRORcount % 1000) == 0)
+        {   
+            LogMsg("ERROR: tcpconnectioncallback -> got error status %d times", LNTERRORcount);
+            assert(LNTERRORcount < 1000);
+            // Recovery Mechanism to bail mDNSResponder out of trouble: It has been seen that we can get into 
+            // this loop: [tcpKQSocketCallback()--> doTcpSocketCallback()-->tcpconnectionCallback()-->mDNSASLLog()],
+            // if mDNSPlatformTCPCloseConnection() does not close the TCPSocket. Instead of calling mDNSASLLog()
+            // repeatedly and logging the same error msg causing 100% CPU usage, we 
+            // crash mDNSResponder using assert() and restart fresh. See advantages below:
+            // 1.Better User Experience 
+            // 2.CrashLogs frequency can be monitored 
+            // 3.StackTrace can be used for more info 
+        }   
+
+        switch (tcpInfo->op)
+        {
+        case LNTDiscoveryOp:     if (m->UPnPSOAPAddressString == mDNSNULL)
+                mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "failure", "SOAP Address", "");
+            if (m->UPnPSOAPURL == mDNSNULL)
+                mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "failure", "SOAP path", "");
+            if (m->UPnPSOAPAddressString && m->UPnPSOAPURL)
+                mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "success", "success", "");
+            break;
+        case LNTExternalAddrOp:  mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest",
+                                            mDNSIPv4AddressIsZero(m->ExternalAddress) ? "failure" : "success",
+                                            mDNSIPv4AddressIsZero(m->ExternalAddress) ? "failure" : "success", "");
+            break;
+        case LNTPortMapOp:       if (tcpInfo->parentNATInfo)
+                mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", (tcpInfo->parentNATInfo->Result) ? "failure" : "success",
+                           (tcpInfo->parentNATInfo->Result) ? "failure" : "success", "Result: %d", tcpInfo->parentNATInfo->Result);
+            break;
+        case LNTPortMapDeleteOp: break;
+        default:                 break;
+        }
+
+        mDNSPlatformTCPCloseConnection(sock);
+        tcpInfo->sock = mDNSNULL;
+        if (tcpInfo->Request) { mDNSPlatformMemFree(tcpInfo->Request); tcpInfo->Request = mDNSNULL; }
+        if (tcpInfo->Reply  ) { mDNSPlatformMemFree(tcpInfo->Reply);   tcpInfo->Reply   = mDNSNULL; }
+    }
+    else
+    {
+        LNTERRORcount = 0;  // clear LNTERRORcount
+    }
+
+    if (tcpInfo) mDNS_Unlock(tcpInfo->m);
+
+    if (status == mStatus_ConfigChanged) DisposeInfoFromUnmapList(tcpInfo->m, tcpInfo);
+}
 
 mDNSlocal mStatus MakeTCPConnection(mDNS *const m, tcpLNTInfo *info, const mDNSAddr *const Addr, const mDNSIPPort Port, LNTOp_t op)
-       {
-       mStatus err = mStatus_NoError;
-       mDNSIPPort srcport = zeroIPPort;
-
-       if (mDNSIPv4AddressIsZero(Addr->ip.v4) || mDNSIPPortIsZero(Port))
-           { LogMsg("LNT MakeTCPConnection: bad address/port %#a:%d", Addr, mDNSVal16(Port)); return(mStatus_Invalid); }
-       info->m         = m;
-       info->Address   = *Addr;
-       info->Port      = Port;
-       info->op        = op;
-       info->nread     = 0;
-       info->replyLen  = LNT_MAXBUFSIZE;
-       if      (info->Reply != mDNSNULL) mDNSPlatformMemZero(info->Reply, LNT_MAXBUFSIZE);   // reuse previously allocated buffer
-       else if ((info->Reply = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogInfo("can't allocate reply buffer"); return (mStatus_NoMemoryErr); }
-
-       if (info->sock) { LogInfo("MakeTCPConnection: closing previous open connection"); mDNSPlatformTCPCloseConnection(info->sock); info->sock = mDNSNULL; }
-       info->sock = mDNSPlatformTCPSocket(m, kTCPSocketFlags_Zero, &srcport);
-       if (!info->sock) { LogMsg("LNT MakeTCPConnection: unable to create TCP socket"); mDNSPlatformMemFree(info->Reply); info->Reply = mDNSNULL; return(mStatus_NoMemoryErr); }
-       LogInfo("MakeTCPConnection: connecting to %#a:%d", &info->Address, mDNSVal16(info->Port));
-       err = mDNSPlatformTCPConnect(info->sock, Addr, Port, mDNSNULL, 0, tcpConnectionCallback, info);
-
-       if      (err == mStatus_ConnPending) err = mStatus_NoError;
-       else if (err == mStatus_ConnEstablished)
-               {
-               mDNS_DropLockBeforeCallback();
-               tcpConnectionCallback(info->sock, info, mDNStrue, mStatus_NoError);
-               mDNS_ReclaimLockAfterCallback();
-               err = mStatus_NoError;
-               }
-       else
-               {
-               // Don't need to log this in customer builds -- it happens quite often during sleep, wake, configuration changes, etc.
-               LogInfo("LNT MakeTCPConnection: connection failed");
-               mDNSPlatformTCPCloseConnection(info->sock);     // Dispose the socket we created with mDNSPlatformTCPSocket() above
-               info->sock = mDNSNULL;
-               mDNSPlatformMemFree(info->Reply);
-               info->Reply = mDNSNULL;
-               }
-       return(err);
-       }
+{
+    mStatus err = mStatus_NoError;
+    mDNSIPPort srcport = zeroIPPort;
+
+    if (mDNSIPv4AddressIsZero(Addr->ip.v4) || mDNSIPPortIsZero(Port))
+    { LogMsg("LNT MakeTCPConnection: bad address/port %#a:%d", Addr, mDNSVal16(Port)); return(mStatus_Invalid); }
+    info->m         = m;
+    info->Address   = *Addr;
+    info->Port      = Port;
+    info->op        = op;
+    info->nread     = 0;
+    info->replyLen  = LNT_MAXBUFSIZE;
+    if      (info->Reply != mDNSNULL) mDNSPlatformMemZero(info->Reply, LNT_MAXBUFSIZE);   // reuse previously allocated buffer
+    else if ((info->Reply = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogInfo("can't allocate reply buffer"); return (mStatus_NoMemoryErr); }
+
+    if (info->sock) { LogInfo("MakeTCPConnection: closing previous open connection"); mDNSPlatformTCPCloseConnection(info->sock); info->sock = mDNSNULL; }
+    info->sock = mDNSPlatformTCPSocket(m, kTCPSocketFlags_Zero, &srcport, mDNSfalse);
+    if (!info->sock) { LogMsg("LNT MakeTCPConnection: unable to create TCP socket"); mDNSPlatformMemFree(info->Reply); info->Reply = mDNSNULL; return(mStatus_NoMemoryErr); }
+    LogInfo("MakeTCPConnection: connecting to %#a:%d", &info->Address, mDNSVal16(info->Port));
+    err = mDNSPlatformTCPConnect(info->sock, Addr, Port, mDNSNULL, 0, tcpConnectionCallback, info);
+
+    if      (err == mStatus_ConnPending) err = mStatus_NoError;
+    else if (err == mStatus_ConnEstablished)
+    {
+        mDNS_DropLockBeforeCallback();
+        tcpConnectionCallback(info->sock, info, mDNStrue, mStatus_NoError);
+        mDNS_ReclaimLockAfterCallback();
+        err = mStatus_NoError;
+    }
+    else
+    {
+        // Don't need to log this in customer builds -- it happens quite often during sleep, wake, configuration changes, etc.
+        LogInfo("LNT MakeTCPConnection: connection failed");
+        mDNSPlatformTCPCloseConnection(info->sock); // Dispose the socket we created with mDNSPlatformTCPSocket() above
+        info->sock = mDNSNULL;
+        mDNSPlatformMemFree(info->Reply);
+        info->Reply = mDNSNULL;
+    }
+    return(err);
+}
 
 mDNSlocal unsigned int AddSOAPArguments(char *const buf, const unsigned int maxlen, const int numArgs, const Property *const a)
-       {
-       static const char f1[] = "<%s>%s</%s>";
-       static const char f2[] = "<%s xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"%s\">%s</%s>";
-       int i, len = 0;
-       *buf = 0;
-       for (i = 0; i < numArgs; i++)
-               {
-               if (a[i].type) len += mDNS_snprintf(buf + len, maxlen - len, f2, a[i].name, a[i].type, a[i].value, a[i].name);
-               else           len += mDNS_snprintf(buf + len, maxlen - len, f1, a[i].name,            a[i].value, a[i].name);
-               }
-       return(len);
-       }
+{
+    static const char f1[] = "<%s>%s</%s>";
+    static const char f2[] = "<%s xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"%s\">%s</%s>";
+    int i, len = 0;
+    *buf = 0;
+    for (i = 0; i < numArgs; i++)
+    {
+        if (a[i].type) len += mDNS_snprintf(buf + len, maxlen - len, f2, a[i].name, a[i].type, a[i].value, a[i].name);
+        else len += mDNS_snprintf(buf + len, maxlen - len, f1, a[i].name,            a[i].value, a[i].name);
+    }
+    return(len);
+}
 
 mDNSlocal mStatus SendSOAPMsgControlAction(mDNS *m, tcpLNTInfo *info, const char *const Action, const int numArgs, const Property *const Arguments, const LNTOp_t op)
-       {
-       // SOAP message header format -
-       //  - control URL
-       //  - action (string)
-       //  - router's host/port ("host:port")
-       //  - content-length
-       static const char header[] =
-               "POST %s HTTP/1.1\r\n"
-               "Content-Type: text/xml; charset=\"utf-8\"\r\n"
-               "SOAPAction: \"urn:schemas-upnp-org:service:WAN%sConnection:1#%s\"\r\n"
-               "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)\r\n"
-               "Host: %s\r\n"
-               "Content-Length: %d\r\n"
-               "Connection: close\r\n"
-               "Pragma: no-cache\r\n"
-               "\r\n"
-               "%s\r\n";
-
-       static const char body1[] =
-               "<?xml version=\"1.0\"?>\r\n"
-               "<SOAP-ENV:Envelope"
-               " xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\""
-               " SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
-               "<SOAP-ENV:Body>"
-               "<m:%s xmlns:m=\"urn:schemas-upnp-org:service:WAN%sConnection:1\">";
-
-       static const char body2[] =
-               "</m:%s>"
-               "</SOAP-ENV:Body>"
-               "</SOAP-ENV:Envelope>\r\n";
-
-       mStatus err;
-       char   *body = (char*)&m->omsg;                 // Typically requires 1110-1122 bytes; m->omsg is 8952 bytes, which is plenty
-       int     bodyLen;
-
-       if (mDNSIPPortIsZero(m->UPnPSOAPPort) || m->UPnPSOAPURL == mDNSNULL || m->UPnPSOAPAddressString == mDNSNULL)    // if no SOAP URL or address exists get out here
-               { LogInfo("SendSOAPMsgControlAction: no SOAP port, URL or address string"); return mStatus_Invalid; }
-
-       // Create body
-       bodyLen  = mDNS_snprintf   (body,           sizeof(m->omsg),           body1,   Action,   m->UPnPWANPPPConnection ? "PPP" : "IP");
-       bodyLen += AddSOAPArguments(body + bodyLen, sizeof(m->omsg) - bodyLen, numArgs, Arguments);
-       bodyLen += mDNS_snprintf   (body + bodyLen, sizeof(m->omsg) - bodyLen, body2,   Action);
-
-       // Create info->Request; the header needs to contain the bodyLen in the "Content-Length" field
-       if (!info->Request) info->Request = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE);
-       if (!info->Request) { LogMsg("SendSOAPMsgControlAction: Can't allocate info->Request"); return mStatus_NoMemoryErr; }
-       info->requestLen = mDNS_snprintf((char*)info->Request, LNT_MAXBUFSIZE, header, m->UPnPSOAPURL, m->UPnPWANPPPConnection ? "PPP" : "IP", Action, m->UPnPSOAPAddressString, bodyLen, body);
-
-       err = MakeTCPConnection(m, info, &m->Router, m->UPnPSOAPPort, op);
-       if (err) { mDNSPlatformMemFree(info->Request); info->Request = mDNSNULL; }
-       return err;
-       }
+{
+    // SOAP message header format -
+    //  - control URL
+    //  - action (string)
+    //  - router's host/port ("host:port")
+    //  - content-length
+    static const char header[] =
+        "POST %s HTTP/1.1\r\n"
+        "Content-Type: text/xml; charset=\"utf-8\"\r\n"
+        "SOAPAction: \"urn:schemas-upnp-org:service:WAN%sConnection:1#%s\"\r\n"
+        "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)\r\n"
+        "Host: %s\r\n"
+        "Content-Length: %d\r\n"
+        "Connection: close\r\n"
+        "Pragma: no-cache\r\n"
+        "\r\n"
+        "%s\r\n";
+
+    static const char body1[] =
+        "<?xml version=\"1.0\"?>\r\n"
+        "<SOAP-ENV:Envelope"
+        " xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\""
+        " SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
+        "<SOAP-ENV:Body>"
+        "<m:%s xmlns:m=\"urn:schemas-upnp-org:service:WAN%sConnection:1\">";
+
+    static const char body2[] =
+        "</m:%s>"
+        "</SOAP-ENV:Body>"
+        "</SOAP-ENV:Envelope>\r\n";
+
+    mStatus err;
+    char   *body = (char*)&m->omsg;         // Typically requires 1110-1122 bytes; m->omsg is 8952 bytes, which is plenty
+    int bodyLen;
+
+    if (mDNSIPPortIsZero(m->UPnPSOAPPort) || m->UPnPSOAPURL == mDNSNULL || m->UPnPSOAPAddressString == mDNSNULL)    // if no SOAP URL or address exists get out here
+    { LogInfo("SendSOAPMsgControlAction: no SOAP port, URL or address string"); return mStatus_Invalid; }
+
+    // Create body
+    bodyLen  = mDNS_snprintf   (body,           sizeof(m->omsg),           body1,   Action,   m->UPnPWANPPPConnection ? "PPP" : "IP");
+    bodyLen += AddSOAPArguments(body + bodyLen, sizeof(m->omsg) - bodyLen, numArgs, Arguments);
+    bodyLen += mDNS_snprintf   (body + bodyLen, sizeof(m->omsg) - bodyLen, body2,   Action);
+
+    // Create info->Request; the header needs to contain the bodyLen in the "Content-Length" field
+    if (!info->Request) info->Request = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE);
+    if (!info->Request) { LogMsg("SendSOAPMsgControlAction: Can't allocate info->Request"); return mStatus_NoMemoryErr; }
+    info->requestLen = mDNS_snprintf((char*)info->Request, LNT_MAXBUFSIZE, header, m->UPnPSOAPURL, m->UPnPWANPPPConnection ? "PPP" : "IP", Action, m->UPnPSOAPAddressString, bodyLen, body);
+
+    err = MakeTCPConnection(m, info, &m->Router, m->UPnPSOAPPort, op);
+    if (err) { mDNSPlatformMemFree(info->Request); info->Request = mDNSNULL; }
+    return err;
+}
 
 // Build port mapping request with new port (up to max) and send it
 mDNSlocal mStatus SendPortMapRequest(mDNS *m, NATTraversalInfo *n)
-       {
-       char              externalPort[6];
-       char              internalPort[6];
-       char              localIPAddrString[30];
-       char              publicPortString[40];
-       Property          propArgs[8];
-       mDNSu16           ReqPortNum = RequestedPortNum(n);
-       NATTraversalInfo *n2 = m->NATTraversals;
-
-       // Scan our m->NATTraversals list to make sure the external port we're requesting is locally unique.
-       // UPnP gateways will report conflicts if different devices request the same external port, but if two
-       // clients on the same device request the same external port the second one just stomps over the first.
-       // One way this can happen is like this:
-       // 1. Client A binds local port 80
-       // 2. Client A requests external port 80 -> internal port 80
-       // 3. UPnP NAT gateway refuses external port 80 (some other client already has it)
-       // 4. Client A tries again, and successfully gets external port 80 -> internal port 81
-       // 5. Client B on same machine tries to bind local port 80, and fails
-       // 6. Client B tries again, and successfully binds local port 81
-       // 7. Client B now requests external port 81 -> internal port 81
-       // 8. UPnP NAT gateway allows this, stomping over Client A's existing mapping
-
-       while (n2)
-               {
-               if (n2 == n || RequestedPortNum(n2) != ReqPortNum) n2=n2->next;
-               else
-                       {
-                       if (n->tcpInfo.retries < 100)
-                               {
-                               n->tcpInfo.retries++;
-                               ReqPortNum = RequestedPortNum(n);       // Pick a new port number
-                               n2 = m->NATTraversals;                          // And re-scan the list looking for conflicts
-                               }
-                       else
-                               {
-                               natTraversalHandlePortMapReply(m, n, m->UPnPInterfaceID, NATErr_Res, zeroIPPort, 0);
-                               return mStatus_NoError;
-                               }
-                       }
-               }
-
-       // create strings to use in the message
-       mDNS_snprintf(externalPort,      sizeof(externalPort),      "%u",   ReqPortNum);
-       mDNS_snprintf(internalPort,      sizeof(internalPort),      "%u",   mDNSVal16(n->IntPort));
-       mDNS_snprintf(publicPortString,  sizeof(publicPortString),  "iC%u", ReqPortNum);
-       mDNS_snprintf(localIPAddrString, sizeof(localIPAddrString), "%u.%u.%u.%u",
-           m->AdvertisedV4.ip.v4.b[0], m->AdvertisedV4.ip.v4.b[1], m->AdvertisedV4.ip.v4.b[2], m->AdvertisedV4.ip.v4.b[3]);
-
-       // build the message
-       mDNSPlatformMemZero(propArgs, sizeof(propArgs));
-       propArgs[0].name  = "NewRemoteHost";
-       propArgs[0].type  = "string";
-       propArgs[0].value = "";
-       propArgs[1].name  = "NewExternalPort";
-       propArgs[1].type  = "ui2";
-       propArgs[1].value = externalPort;
-       propArgs[2].name  = "NewProtocol";
-       propArgs[2].type  = "string";
-       propArgs[2].value = (n->Protocol == NATOp_MapUDP) ? "UDP" : "TCP";
-       propArgs[3].name  = "NewInternalPort";
-       propArgs[3].type  = "ui2";
-       propArgs[3].value = internalPort;
-       propArgs[4].name  = "NewInternalClient";
-       propArgs[4].type  = "string";
-       propArgs[4].value = localIPAddrString;
-       propArgs[5].name  = "NewEnabled";
-       propArgs[5].type  = "boolean";
-       propArgs[5].value = "1";
-       propArgs[6].name  = "NewPortMappingDescription";
-       propArgs[6].type  = "string";
-       propArgs[6].value = publicPortString;
-       propArgs[7].name  = "NewLeaseDuration";
-       propArgs[7].type  = "ui4";
-       propArgs[7].value = "0";
-
-       LogInfo("SendPortMapRequest: internal %u external %u", mDNSVal16(n->IntPort), ReqPortNum);
-       return SendSOAPMsgControlAction(m, &n->tcpInfo, "AddPortMapping", 8, propArgs, LNTPortMapOp);
-       }
+{
+    char externalPort[6];
+    char internalPort[6];
+    char localIPAddrString[30];
+    char publicPortString[40];
+    Property propArgs[8];
+    mDNSu16 ReqPortNum = RequestedPortNum(n);
+    NATTraversalInfo *n2 = m->NATTraversals;
+
+    // Scan our m->NATTraversals list to make sure the external port we're requesting is locally unique.
+    // UPnP gateways will report conflicts if different devices request the same external port, but if two
+    // clients on the same device request the same external port the second one just stomps over the first.
+    // One way this can happen is like this:
+    // 1. Client A binds local port 80
+    // 2. Client A requests external port 80 -> internal port 80
+    // 3. UPnP NAT gateway refuses external port 80 (some other client already has it)
+    // 4. Client A tries again, and successfully gets external port 80 -> internal port 81
+    // 5. Client B on same machine tries to bind local port 80, and fails
+    // 6. Client B tries again, and successfully binds local port 81
+    // 7. Client B now requests external port 81 -> internal port 81
+    // 8. UPnP NAT gateway allows this, stomping over Client A's existing mapping
+
+    while (n2)
+    {
+        if (n2 == n || RequestedPortNum(n2) != ReqPortNum) n2=n2->next;
+        else
+        {
+            if (n->tcpInfo.retries < 100)
+            {
+                n->tcpInfo.retries++;
+                ReqPortNum = RequestedPortNum(n);   // Pick a new port number
+                n2 = m->NATTraversals;              // And re-scan the list looking for conflicts
+            }
+            else
+            {
+                natTraversalHandlePortMapReply(m, n, m->UPnPInterfaceID, NATErr_Res, zeroIPPort, 0);
+                return mStatus_NoError;
+            }
+        }
+    }
+
+    // create strings to use in the message
+    mDNS_snprintf(externalPort,      sizeof(externalPort),      "%u",   ReqPortNum);
+    mDNS_snprintf(internalPort,      sizeof(internalPort),      "%u",   mDNSVal16(n->IntPort));
+    mDNS_snprintf(publicPortString,  sizeof(publicPortString),  "iC%u", ReqPortNum);
+    mDNS_snprintf(localIPAddrString, sizeof(localIPAddrString), "%u.%u.%u.%u",
+                  m->AdvertisedV4.ip.v4.b[0], m->AdvertisedV4.ip.v4.b[1], m->AdvertisedV4.ip.v4.b[2], m->AdvertisedV4.ip.v4.b[3]);
+
+    // build the message
+    mDNSPlatformMemZero(propArgs, sizeof(propArgs));
+    propArgs[0].name  = "NewRemoteHost";
+    propArgs[0].type  = "string";
+    propArgs[0].value = "";
+    propArgs[1].name  = "NewExternalPort";
+    propArgs[1].type  = "ui2";
+    propArgs[1].value = externalPort;
+    propArgs[2].name  = "NewProtocol";
+    propArgs[2].type  = "string";
+    propArgs[2].value = (n->Protocol == NATOp_MapUDP) ? "UDP" : "TCP";
+    propArgs[3].name  = "NewInternalPort";
+    propArgs[3].type  = "ui2";
+    propArgs[3].value = internalPort;
+    propArgs[4].name  = "NewInternalClient";
+    propArgs[4].type  = "string";
+    propArgs[4].value = localIPAddrString;
+    propArgs[5].name  = "NewEnabled";
+    propArgs[5].type  = "boolean";
+    propArgs[5].value = "1";
+    propArgs[6].name  = "NewPortMappingDescription";
+    propArgs[6].type  = "string";
+    propArgs[6].value = publicPortString;
+    propArgs[7].name  = "NewLeaseDuration";
+    propArgs[7].type  = "ui4";
+    propArgs[7].value = "0";
+
+    LogInfo("SendPortMapRequest: internal %u external %u", mDNSVal16(n->IntPort), ReqPortNum);
+    return SendSOAPMsgControlAction(m, &n->tcpInfo, "AddPortMapping", 8, propArgs, LNTPortMapOp);
+}
 
 mDNSexport mStatus LNT_MapPort(mDNS *m, NATTraversalInfo *const n)
-       {
-       LogInfo("LNT_MapPort");
-       if (n->tcpInfo.sock) return(mStatus_NoError);   // If we already have a connection up don't make another request for the same thing
-       n->tcpInfo.parentNATInfo = n;
-       n->tcpInfo.retries       = 0;
-       return SendPortMapRequest(m, n);
-       }
+{
+    LogInfo("LNT_MapPort");
+    if (n->tcpInfo.sock) return(mStatus_NoError);   // If we already have a connection up don't make another request for the same thing
+    n->tcpInfo.parentNATInfo = n;
+    n->tcpInfo.retries       = 0;
+    return SendPortMapRequest(m, n);
+}
 
 mDNSexport mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *const n)
-       {
-       char        externalPort[10];
-       Property    propArgs[3];
-       tcpLNTInfo  *info;
-       tcpLNTInfo  **infoPtr = &m->tcpInfoUnmapList;
-       mStatus     err;
-
-       // If no NAT gateway to talk to, no need to do all this work for nothing
-       if (mDNSIPPortIsZero(m->UPnPSOAPPort) || !m->UPnPSOAPURL || !m->UPnPSOAPAddressString) return mStatus_NoError;
-
-       mDNS_snprintf(externalPort, sizeof(externalPort), "%u", mDNSVal16(mDNSIPPortIsZero(n->RequestedPort) ? n->IntPort : n->RequestedPort));
-
-       mDNSPlatformMemZero(propArgs, sizeof(propArgs));
-       propArgs[0].name  = "NewRemoteHost";
-       propArgs[0].type  = "string";
-       propArgs[0].value = "";
-       propArgs[1].name  = "NewExternalPort";
-       propArgs[1].type  = "ui2";
-       propArgs[1].value = externalPort;
-       propArgs[2].name  = "NewProtocol";
-       propArgs[2].type  = "string";
-       propArgs[2].value = (n->Protocol == NATOp_MapUDP) ? "UDP" : "TCP";
-
-       n->tcpInfo.parentNATInfo = n;
-
-       // clean up previous port mapping requests and allocations
-       if (n->tcpInfo.sock) LogInfo("LNT_UnmapPort: closing previous open connection");
-       if (n->tcpInfo.sock   ) { mDNSPlatformTCPCloseConnection(n->tcpInfo.sock); n->tcpInfo.sock    = mDNSNULL; }
-       if (n->tcpInfo.Request) { mDNSPlatformMemFree(n->tcpInfo.Request);         n->tcpInfo.Request = mDNSNULL; }
-       if (n->tcpInfo.Reply  ) { mDNSPlatformMemFree(n->tcpInfo.Reply);           n->tcpInfo.Reply   = mDNSNULL; }
-       
-       // make a copy of the tcpInfo that we can clean up later (the one passed in will be destroyed by the client as soon as this returns)
-       if ((info = mDNSPlatformMemAllocate(sizeof(tcpLNTInfo))) == mDNSNULL)
-               { LogInfo("LNT_UnmapPort: can't allocate tcpInfo"); return(mStatus_NoMemoryErr); }
-       *info = n->tcpInfo;
-       
-       while (*infoPtr) infoPtr = &(*infoPtr)->next;   // find the end of the list
-       *infoPtr = info;    // append
-
-       err = SendSOAPMsgControlAction(m, info, "DeletePortMapping", 3, propArgs, LNTPortMapDeleteOp);
-       if (err) DisposeInfoFromUnmapList(m, info);
-       return err;
-       }
+{
+    char externalPort[10];
+    Property propArgs[3];
+    tcpLNTInfo  *info;
+    tcpLNTInfo  **infoPtr = &m->tcpInfoUnmapList;
+    mStatus err;
+
+    // If no NAT gateway to talk to, no need to do all this work for nothing
+    if (mDNSIPPortIsZero(m->UPnPSOAPPort) || !m->UPnPSOAPURL || !m->UPnPSOAPAddressString) return mStatus_NoError;
+
+    mDNS_snprintf(externalPort, sizeof(externalPort), "%u", mDNSVal16(mDNSIPPortIsZero(n->RequestedPort) ? n->IntPort : n->RequestedPort));
+
+    mDNSPlatformMemZero(propArgs, sizeof(propArgs));
+    propArgs[0].name  = "NewRemoteHost";
+    propArgs[0].type  = "string";
+    propArgs[0].value = "";
+    propArgs[1].name  = "NewExternalPort";
+    propArgs[1].type  = "ui2";
+    propArgs[1].value = externalPort;
+    propArgs[2].name  = "NewProtocol";
+    propArgs[2].type  = "string";
+    propArgs[2].value = (n->Protocol == NATOp_MapUDP) ? "UDP" : "TCP";
+
+    n->tcpInfo.parentNATInfo = n;
+
+    // clean up previous port mapping requests and allocations
+    if (n->tcpInfo.sock) LogInfo("LNT_UnmapPort: closing previous open connection");
+    if (n->tcpInfo.sock   ) { mDNSPlatformTCPCloseConnection(n->tcpInfo.sock); n->tcpInfo.sock    = mDNSNULL; }
+    if (n->tcpInfo.Request) { mDNSPlatformMemFree(n->tcpInfo.Request);         n->tcpInfo.Request = mDNSNULL; }
+    if (n->tcpInfo.Reply  ) { mDNSPlatformMemFree(n->tcpInfo.Reply);           n->tcpInfo.Reply   = mDNSNULL; }
+
+    // make a copy of the tcpInfo that we can clean up later (the one passed in will be destroyed by the client as soon as this returns)
+    if ((info = mDNSPlatformMemAllocate(sizeof(tcpLNTInfo))) == mDNSNULL)
+    { LogInfo("LNT_UnmapPort: can't allocate tcpInfo"); return(mStatus_NoMemoryErr); }
+    *info = n->tcpInfo;
+
+    while (*infoPtr) infoPtr = &(*infoPtr)->next;   // find the end of the list
+    *infoPtr = info;    // append
+
+    err = SendSOAPMsgControlAction(m, info, "DeletePortMapping", 3, propArgs, LNTPortMapDeleteOp);
+    if (err) DisposeInfoFromUnmapList(m, info);
+    return err;
+}
 
 mDNSexport mStatus LNT_GetExternalAddress(mDNS *m)
-       {
-       return SendSOAPMsgControlAction(m, &m->tcpAddrInfo, "GetExternalIPAddress", 0, mDNSNULL, LNTExternalAddrOp);
-       }
+{
+    return SendSOAPMsgControlAction(m, &m->tcpAddrInfo, "GetExternalIPAddress", 0, mDNSNULL, LNTExternalAddrOp);
+}
 
 mDNSlocal mStatus GetDeviceDescription(mDNS *m, tcpLNTInfo *info)
-       {
-       // Device description format -
-       //  - device description URL
-       //  - host/port
-       static const char szSSDPMsgDescribeDeviceFMT[] =
-               "GET %s HTTP/1.1\r\n"
-               "Accept: text/xml, application/xml\r\n"
-               "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n"
-               "Host: %s\r\n"
-               "Connection: close\r\n"
-               "\r\n";
-
-       if (!mDNSIPPortIsZero(m->UPnPSOAPPort)) return mStatus_NoError; // already have the info we need
-       
-       if (m->UPnPRouterURL == mDNSNULL || m->UPnPRouterAddressString == mDNSNULL) { LogInfo("GetDeviceDescription: no router URL or address string!"); return (mStatus_Invalid); }
-
-       // build message
-       if      (info->Request != mDNSNULL) mDNSPlatformMemZero(info->Request, LNT_MAXBUFSIZE); // reuse previously allocated buffer
-       else if ((info->Request = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogInfo("can't allocate send buffer for discovery"); return (mStatus_NoMemoryErr); }
-       info->requestLen = mDNS_snprintf((char*)info->Request, LNT_MAXBUFSIZE, szSSDPMsgDescribeDeviceFMT, m->UPnPRouterURL, m->UPnPRouterAddressString);
-       LogInfo("Describe Device: [%s]", info->Request);
-       return MakeTCPConnection(m, info, &m->Router, m->UPnPRouterPort, LNTDiscoveryOp);
-       }
+{
+    // Device description format -
+    //  - device description URL
+    //  - host/port
+    static const char szSSDPMsgDescribeDeviceFMT[] =
+        "GET %s HTTP/1.1\r\n"
+        "Accept: text/xml, application/xml\r\n"
+        "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n"
+        "Host: %s\r\n"
+        "Connection: close\r\n"
+        "\r\n";
+
+    if (!mDNSIPPortIsZero(m->UPnPSOAPPort)) return mStatus_NoError; // already have the info we need
+
+    if (m->UPnPRouterURL == mDNSNULL || m->UPnPRouterAddressString == mDNSNULL) { LogInfo("GetDeviceDescription: no router URL or address string!"); return (mStatus_Invalid); }
+
+    // build message
+    if      (info->Request != mDNSNULL) mDNSPlatformMemZero(info->Request, LNT_MAXBUFSIZE); // reuse previously allocated buffer
+    else if ((info->Request = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogInfo("can't allocate send buffer for discovery"); return (mStatus_NoMemoryErr); }
+    info->requestLen = mDNS_snprintf((char*)info->Request, LNT_MAXBUFSIZE, szSSDPMsgDescribeDeviceFMT, m->UPnPRouterURL, m->UPnPRouterAddressString);
+    LogInfo("Describe Device: [%s]", info->Request);
+    return MakeTCPConnection(m, info, &m->Router, m->UPnPRouterPort, LNTDiscoveryOp);
+}
 
 // This function parses the response to our SSDP discovery message. Basically, we look to make sure this is a response
 // referencing a service we care about (WANIPConnection or WANPPPConnection), then look for the "Location:" header and copy the addressing and
 // URL info we need.
 mDNSexport void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID InterfaceID, const mDNSu8 *const data, const mDNSu16 len)
-       {
-       const mDNSu8 *ptr = data;
-       const mDNSu8 *end = data + len;
-       const mDNSu8 *stop = ptr;
-       
-       if (!mDNSIPPortIsZero(m->UPnPRouterPort)) return; // already have the info we need
-
-       // The formatting of the HTTP header is not always the same when it comes to the placement of
-       // the service and location strings, so we just look for each of them from the beginning for every response
-       
-       // figure out if this is a message from a service we care about
-       while (ptr && ptr != end)
-               {
-               if ((*ptr & 0xDF) == 'W' && (strncasecmp((char*)ptr, "WANIPConnection:1", 17) == 0)) break;
-               ptr++;
-               }
-       if (ptr == end)
-               {
-               ptr = data;
-               while (ptr && ptr != end)
-                       {
-                       if ((*ptr & 0xDF) == 'W' && (strncasecmp((char*)ptr, "WANPPPConnection:1", 18) == 0)) break;
-                       ptr++;
-                       }
-               }
-       if (ptr == mDNSNULL || ptr == end) return;      // not a message we care about
-
-       // find "Location:", starting from the beginning
-       ptr = data;
-       while (ptr && ptr != end)
-               {
-               if ((*ptr & 0xDF) == 'L' && (strncasecmp((char*)ptr, "Location:", 9) == 0)) break;                      // find the first 'L'; is this Location? if not, keep looking
-               ptr++;
-               }
-       if (ptr == mDNSNULL || ptr == end) 
-               {
-               mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Location", "");
-               return; // not a message we care about
-               }
-       ptr += 9; //Skip over 'Location:'
-       while (*ptr == ' ' && ptr < end) ptr++; // skip over spaces
-       if (ptr >= end) return;
-       
-       // find the end of the line
-       for (stop = ptr; stop != end; stop++) { if (*stop == '\r') { end = stop; break; } }
-       
-       // fill in default port
-       m->UPnPRouterPort = mDNSOpaque16fromIntVal(80);
-
-       // free string pointers and set to NULL 
-       if (m->UPnPRouterAddressString != mDNSNULL)
-               {
-               mDNSPlatformMemFree(m->UPnPRouterAddressString);
-               m->UPnPRouterAddressString = mDNSNULL;
-               }
-       if (m->UPnPRouterURL != mDNSNULL)
-               {
-               mDNSPlatformMemFree(m->UPnPRouterURL);
-               m->UPnPRouterURL = mDNSNULL; 
-               }
-       
-       // the Router URL should look something like "/dyndev/uuid:0013-108c-4b3f0000f3dc"
-       if (ParseHttpUrl(ptr, end, &m->UPnPRouterAddressString, &m->UPnPRouterPort, &m->UPnPRouterURL) != mStatus_NoError)
-               {
-               mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Parse URL", "");
-               return;
-               }
-
-       m->UPnPInterfaceID = InterfaceID;
-
-       if (m->UPnPRouterAddressString == mDNSNULL) 
-               {
-               mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Router address", "");
-               LogMsg("LNT_ConfigureRouterInfo: UPnPRouterAddressString is NULL");
-               }
-       else LogInfo("LNT_ConfigureRouterInfo: Router address string [%s]", m->UPnPRouterAddressString);
-
-       if (m->UPnPRouterURL == mDNSNULL) 
-               {
-               mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Router path", "");
-               LogMsg("LNT_ConfigureRouterInfo: UPnPRouterURL is NULL");
-               }
-       else LogInfo("LNT_ConfigureRouterInfo: Router URL [%s]", m->UPnPRouterURL);
-
-       LogInfo("LNT_ConfigureRouterInfo: Router port %d", mDNSVal16(m->UPnPRouterPort));
-       LogInfo("LNT_ConfigureRouterInfo: Router interface %d", m->UPnPInterfaceID);
-
-       // Don't need the SSDP socket anymore
-       if (m->SSDPSocket) { debugf("LNT_ConfigureRouterInfo destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
-
-       mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "success", "success", "");
-       // now send message to get the device description
-       GetDeviceDescription(m, &m->tcpDeviceInfo);
-       }
+{
+    const mDNSu8 *ptr = data;
+    const mDNSu8 *end = data + len;
+    const mDNSu8 *stop = ptr;
+
+    if (!mDNSIPPortIsZero(m->UPnPRouterPort)) return; // already have the info we need
+
+    // The formatting of the HTTP header is not always the same when it comes to the placement of
+    // the service and location strings, so we just look for each of them from the beginning for every response
+
+    // figure out if this is a message from a service we care about
+    while (ptr && ptr != end)
+    {
+        if ((*ptr & 0xDF) == 'W' && (strncasecmp((char*)ptr, "WANIPConnection:1", 17) == 0)) break;
+        ptr++;
+    }
+    if (ptr == end)
+    {
+        ptr = data;
+        while (ptr && ptr != end)
+        {
+            if ((*ptr & 0xDF) == 'W' && (strncasecmp((char*)ptr, "WANPPPConnection:1", 18) == 0)) break;
+            ptr++;
+        }
+    }
+    if (ptr == mDNSNULL || ptr == end) return;  // not a message we care about
+
+    // find "Location:", starting from the beginning
+    ptr = data;
+    while (ptr && ptr != end)
+    {
+        if ((*ptr & 0xDF) == 'L' && (strncasecmp((char*)ptr, "Location:", 9) == 0)) break;          // find the first 'L'; is this Location? if not, keep looking
+        ptr++;
+    }
+    if (ptr == mDNSNULL || ptr == end)
+    {
+        mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Location", "");
+        return; // not a message we care about
+    }
+    ptr += 9; //Skip over 'Location:'
+    while (*ptr == ' ' && ptr < end) ptr++; // skip over spaces
+    if (ptr >= end) return;
+
+    // find the end of the line
+    for (stop = ptr; stop != end; stop++) { if (*stop == '\r') { end = stop; break; } }
+
+    // fill in default port
+    m->UPnPRouterPort = mDNSOpaque16fromIntVal(80);
+
+    // free string pointers and set to NULL
+    if (m->UPnPRouterAddressString != mDNSNULL)
+    {
+        mDNSPlatformMemFree(m->UPnPRouterAddressString);
+        m->UPnPRouterAddressString = mDNSNULL;
+    }
+    if (m->UPnPRouterURL != mDNSNULL)
+    {
+        mDNSPlatformMemFree(m->UPnPRouterURL);
+        m->UPnPRouterURL = mDNSNULL;
+    }
+
+    // the Router URL should look something like "/dyndev/uuid:0013-108c-4b3f0000f3dc"
+    if (ParseHttpUrl(ptr, end, &m->UPnPRouterAddressString, &m->UPnPRouterPort, &m->UPnPRouterURL) != mStatus_NoError)
+    {
+        mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Parse URL", "");
+        return;
+    }
+
+    m->UPnPInterfaceID = InterfaceID;
+
+    if (m->UPnPRouterAddressString == mDNSNULL)
+    {
+        mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Router address", "");
+        LogMsg("LNT_ConfigureRouterInfo: UPnPRouterAddressString is NULL");
+    }
+    else LogInfo("LNT_ConfigureRouterInfo: Router address string [%s]", m->UPnPRouterAddressString);
+
+    if (m->UPnPRouterURL == mDNSNULL)
+    {
+        mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Router path", "");
+        LogMsg("LNT_ConfigureRouterInfo: UPnPRouterURL is NULL");
+    }
+    else LogInfo("LNT_ConfigureRouterInfo: Router URL [%s]", m->UPnPRouterURL);
+
+    LogInfo("LNT_ConfigureRouterInfo: Router port %d", mDNSVal16(m->UPnPRouterPort));
+    LogInfo("LNT_ConfigureRouterInfo: Router interface %d", m->UPnPInterfaceID);
+
+    // Don't need the SSDP socket anymore
+    if (m->SSDPSocket) { debugf("LNT_ConfigureRouterInfo destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
+
+    mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "success", "success", "");
+    // now send message to get the device description
+    GetDeviceDescription(m, &m->tcpDeviceInfo);
+}
 
 mDNSexport void LNT_SendDiscoveryMsg(mDNS *m)
-       {
-       static const char msg[] =
-               "M-SEARCH * HTTP/1.1\r\n"
-               "Host:239.255.255.250:1900\r\n"
-               "ST:urn:schemas-upnp-org:service:WAN%sConnection:1\r\n"
-               "Man:\"ssdp:discover\"\r\n"
-               "MX:3\r\n\r\n";
-       static const mDNSAddr multicastDest = { mDNSAddrType_IPv4, { { { 239, 255, 255, 250 } } } };
-       
-       mDNSu8 *buf = (mDNSu8*)&m->omsg; //m->omsg is 8952 bytes, which is plenty
-       unsigned int bufLen;
-       
-       if (!mDNSIPPortIsZero(m->UPnPRouterPort))
-               {
-               if (m->SSDPSocket) { debugf("LNT_SendDiscoveryMsg destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
-               if (mDNSIPPortIsZero(m->UPnPSOAPPort) && !m->tcpDeviceInfo.sock) GetDeviceDescription(m, &m->tcpDeviceInfo);
-               return;
-               }
-
-       // Always query for WANIPConnection in the first SSDP packet
-       if (m->retryIntervalGetAddr <= NATMAP_INIT_RETRY) m->SSDPWANPPPConnection = mDNSfalse;
-
-       // Create message
-       bufLen = mDNS_snprintf((char*)buf, sizeof(m->omsg), msg, m->SSDPWANPPPConnection ? "PPP" : "IP");
-
-       debugf("LNT_SendDiscoveryMsg Router %.4a Current External Address %.4a", &m->Router.ip.v4, &m->ExternalAddress);
-
-       if (!mDNSIPv4AddressIsZero(m->Router.ip.v4))
-               {
-               if (!m->SSDPSocket) { m->SSDPSocket = mDNSPlatformUDPSocket(m, zeroIPPort); debugf("LNT_SendDiscoveryMsg created SSDPSocket %p", &m->SSDPSocket); }
-               mDNSPlatformSendUDP(m, buf, buf + bufLen, 0, m->SSDPSocket, &m->Router,     SSDPPort);
-               mDNSPlatformSendUDP(m, buf, buf + bufLen, 0, m->SSDPSocket, &multicastDest, SSDPPort);
-               }
-               
-       m->SSDPWANPPPConnection = !m->SSDPWANPPPConnection;
-       }
+{
+    static const char msg[] =
+        "M-SEARCH * HTTP/1.1\r\n"
+        "Host:239.255.255.250:1900\r\n"
+        "ST:urn:schemas-upnp-org:service:WAN%sConnection:1\r\n"
+        "Man:\"ssdp:discover\"\r\n"
+        "MX:3\r\n\r\n";
+    static const mDNSAddr multicastDest = { mDNSAddrType_IPv4, { { { 239, 255, 255, 250 } } } };
+
+    mDNSu8 *buf = (mDNSu8*)&m->omsg; //m->omsg is 8952 bytes, which is plenty
+    unsigned int bufLen;
+
+    if (!mDNSIPPortIsZero(m->UPnPRouterPort))
+    {
+        if (m->SSDPSocket) { debugf("LNT_SendDiscoveryMsg destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
+        if (mDNSIPPortIsZero(m->UPnPSOAPPort) && !m->tcpDeviceInfo.sock) GetDeviceDescription(m, &m->tcpDeviceInfo);
+        return;
+    }
+
+    // Always query for WANIPConnection in the first SSDP packet
+    if (m->retryIntervalGetAddr <= NATMAP_INIT_RETRY) m->SSDPWANPPPConnection = mDNSfalse;
+
+    // Create message
+    bufLen = mDNS_snprintf((char*)buf, sizeof(m->omsg), msg, m->SSDPWANPPPConnection ? "PPP" : "IP");
+
+    debugf("LNT_SendDiscoveryMsg Router %.4a Current External Address %.4a", &m->Router.ip.v4, &m->ExternalAddress);
+
+    if (!mDNSIPv4AddressIsZero(m->Router.ip.v4))
+    {
+        if (!m->SSDPSocket) { m->SSDPSocket = mDNSPlatformUDPSocket(m, zeroIPPort); debugf("LNT_SendDiscoveryMsg created SSDPSocket %p", &m->SSDPSocket); }
+        mDNSPlatformSendUDP(m, buf, buf + bufLen, 0, m->SSDPSocket, &m->Router,     SSDPPort, mDNSfalse);
+        mDNSPlatformSendUDP(m, buf, buf + bufLen, 0, m->SSDPSocket, &multicastDest, SSDPPort, mDNSfalse);
+    }
+
+    m->SSDPWANPPPConnection = !m->SSDPWANPPPConnection;
+}
 
 mDNSexport void LNT_ClearState(mDNS *const m)
-       {
-       if (m->tcpAddrInfo.sock)   { mDNSPlatformTCPCloseConnection(m->tcpAddrInfo.sock);   m->tcpAddrInfo.sock   = mDNSNULL; }
-       if (m->tcpDeviceInfo.sock) { mDNSPlatformTCPCloseConnection(m->tcpDeviceInfo.sock); m->tcpDeviceInfo.sock = mDNSNULL; }
-       m->UPnPSOAPPort = m->UPnPRouterPort = zeroIPPort;       // Reset UPnP ports
-       }
+{
+    if (m->tcpAddrInfo.sock)   { mDNSPlatformTCPCloseConnection(m->tcpAddrInfo.sock);   m->tcpAddrInfo.sock   = mDNSNULL; }
+    if (m->tcpDeviceInfo.sock) { mDNSPlatformTCPCloseConnection(m->tcpDeviceInfo.sock); m->tcpDeviceInfo.sock = mDNSNULL; }
+    m->UPnPSOAPPort = m->UPnPRouterPort = zeroIPPort;   // Reset UPnP ports
+}
 
 #endif /* _LEGACY_NAT_TRAVERSAL_ */