int GetUrl(char *url, char **reply_ret, int *len_ret) { char *hostname, *path; int port; XtransConnInfo trans; int status = 0; if (ParseHttpUrl(url, &hostname, &port, &path) != 0) return 1; /* invalid URL */ trans = OpenConnection(hostname, port); if (trans == NULL) { status = 1; /* connection failed */ goto end; } SendGetRequest(trans, path); *len_ret = ReadGetReply(trans, reply_ret); CloseConnection(trans); end: Free(hostname); Free(path); return status; }
// 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, mDNSu8 *data, mDNSu16 len) { char *ptr = (char *)data; char *end = (char *)data + len; char *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 == 'W' && (strncasecmp(ptr, "WANIPConnection:1", 17) == 0)) break; ptr++; } if (ptr == end) { ptr = (char *)data; while (ptr && ptr != end) { if (*ptr == 'W' && (strncasecmp(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 = (char *)data; while (ptr && ptr != end) { if ((*ptr & 0xDF) == 'L' && (strncasecmp(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); }
// 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; char *ptr = (char *)tcpInfo->Reply; char *end = (char *)tcpInfo->Reply + tcpInfo->nread; char *stop = mDNSNULL; mDNSs16 http_result; if (!mDNSIPPortIsZero(m->UPnPSOAPPort)) return; // already have the info we need http_result = ParseHTTPResponseCode((mDNSu8**)&ptr, (mDNSu8*)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 == 'W' && (strncasecmp(ptr, "WANIPConnection:1", 17) == 0)) break; ptr++; } if (ptr == end) { ptr = (char *)tcpInfo->Reply; while (ptr && ptr < end) { if (*ptr == 'W' && (strncasecmp(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 == 'c' && (strncasecmp(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 = (char *)tcpInfo->Reply; while (ptr && ptr < end) { if (*ptr == 'U' && (strncasecmp(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); }