/*! * This method copies the response data into a supplied buffer. * It skips the response and header lines and only copies the response body. * The amount of data copied is limited by the size of the supplied buffer. * Adds a terminating '\0'. * @param buffer The buffer to copy the data into. * @param size The size of `buffer`. * @param bytesRead The number of bytes copied is written to this parameter. * @param httpCode The HTTP response code is written to this parameter. * @return `false` if there is no data to copy, otherwise `true`. * It will return `false` if the body is empty or cannot be determined. */ bool Sodaq_WifiBee::readHTTPResponse(char* buffer, const size_t size, size_t& bytesRead, uint16_t& httpCode) { if (_bufferUsed == 0) { return false; } // Read HTTP response code parseHTTPResponse(httpCode); // Add 4 to start from after the double newline char* startPos = strstr((char*)_buffer, "\r\n\r\n") + 4; size_t startIndex = startPos - (char*)_buffer; if (startIndex < _bufferUsed) { bytesRead = ((size - 1) < (_bufferUsed - startIndex)) ? (size - 1) : (_bufferUsed - startIndex); } else { bytesRead = 0; } memcpy(buffer, startPos, bytesRead); buffer[bytesRead] = '\0'; return true; }
bool MyUPnP::GetDescription() { if(!Valid())return false; CString post, host, addr; int port = 0; addr = NGetAddressFromUrl(m_description, post, host, port); if(addr.IsEmpty())return false; CString request = CString(_T("GET ")) + post + _T(" HTTP/1.1\r\nHOST: ") + host + _T("\r\nACCEPT-LANGUAGE: en\r\n\r\n"); CString response; if (!SOAP_action(addr, (uint16)port, request, response)) return false; CString result; if (!parseHTTPResponse(response, result)) return false; m_friendlyname = getProperty(result, _T("friendlyName")); m_modelname = getProperty(result, _T("modelName")); m_baseurl = getProperty(result, _T("URLBase")); if(m_baseurl.IsEmpty())m_baseurl = CString(_T("http://")) + host + _T("/"); if(m_baseurl[m_baseurl.GetLength() - 1]!='/')m_baseurl += _T("/"); CString serviceType = _T("<serviceType>") + m_name + _T("</serviceType>"); int pos = result.Find(serviceType); if (pos >= 0) { result.Delete(0, pos + serviceType.GetLength()); pos = result.Find(_T("</service>")); if (pos >= 0) { result = result.Mid(0, pos); m_controlurl = getProperty(result, _T("controlURL")); if (!m_controlurl.IsEmpty() && m_controlurl[0] == '/') { m_controlurl = m_baseurl + m_controlurl.Mid(1); } } } return isComplete(); }
bool MyUPnP::InvokeCommand(const CString& name, const CString& args) { if(!isComplete())return false; CString post, host, addr; int port = 0; addr = NGetAddressFromUrl(m_controlurl, post, host, port); if(addr.IsEmpty())return false; CString cnt; CString psr; cnt.Append(_T("<?xml version=\"1.0\"?><s:Envelope\r\n xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\r\n ")); cnt.Append(_T("s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n <s:Body>\r\n <u:")); cnt.Append(name); cnt.Append(_T(" xmlns:u=\"")); cnt.Append(m_name); cnt.Append(_T("\">\r\n")); cnt.Append(args); cnt.Append(_T(" </u:")); cnt.Append(name); cnt.Append(_T(">\r\n </s:Body>\r\n</s:Envelope>\r\n\r\n")); psr.Append(_T("POST ")); psr.Append(post); psr.Append(_T(" HTTP/1.1\r\nHOST: ")); psr.Append(host); psr.Append(_T("\r\nContent-Length: ")); psr.Append(getString(CStringA(cnt).GetLength())); psr.Append(_T("\r\nContent-Type: text/xml; charset=\"utf-8\"\r\nSOAPAction: \"")); psr.Append(m_name); psr.Append(_T("#")); psr.Append(name); psr.Append(_T("\"\r\n\r\n")); psr.Append(cnt); CString response; CString request = psr; if (!SOAP_action(addr, (uint16)port, request, response)) return false; CString result; if (!parseHTTPResponse(response, result)) return false; return true; }
/*! * This method constructs and sends a generic HTTP request. * @param server The server/host to connect to (IP address or domain). * @param port The port to connect to. * @param The HTTP method to use. e.g. "GET", "POST" etc. * @param location The resource location on the server/host. * @param headers Any additional headers, each must be followed by a CRLF. * HOST & Content-Length headers are added automatically. * @param body The body (can be blank) to send with the request. Must not start with a CRLF. * @param httpCode The HTTP response code is written to this parameter (if a response is received). * @return `true` if a connection is established and the data is sent, `false` otherwise. */ bool Sodaq_WifiBee::HTTPAction(const char* server, const uint16_t port, const char* method, const char* location, const char* headers, const char* body, uint16_t& httpCode) { bool result; // Open the connection result = openConnection(server, port, "net.TCP"); if (result) { createSendBuffer(); sendAscii(method); sendAscii(" "); sendAscii(location); sendAscii(" HTTP/1.1\\r\\n"); sendAscii("HOST: "); sendAscii(server); sendAscii(":"); char buff[11]; itoa(port, buff, 10); sendAscii(buff); sendAscii("\\r\\n"); if (strcmp(method, "GET") != 0) { sendAscii("Content-Length: "); itoa(strlen(body), buff, 10); sendAscii(buff); sendAscii("\\r\\n"); } sendEscapedAscii(headers); sendAscii("\\r\\n"); sendEscapedAscii(body); transmitSendBuffer(); // Wait till we hear that it was sent result = skipTillPrompt(SENT_PROMPT, RESPONSE_TIMEOUT); // Wait till we get the data received prompt if (result) { if (skipTillPrompt(RECEIVED_PROMPT, SERVER_RESPONSE_TIMEOUT)) { while (skipTillPrompt(RECEIVED_PROMPT, NEXT_PACKET_TIMEOUT)) { } readServerResponse(); parseHTTPResponse(httpCode); } else { clearBuffer(); } } // The connection might have closed automatically closeConnection(); } return result; }
bool MyUPnP::InternalSearch(int version) { if(version<=0)version = 1; m_version = version; #define NUMBEROFDEVICES 2 CString devices[][2] = { {UPNPPORTMAP1, _T("service")}, {UPNPPORTMAP0, _T("service")}, {_T("InternetGatewayDevice"), _T("device")}, }; int s = socket(AF_INET, SOCK_DGRAM, 0); u_long lv = 1; ioctlsocket(s, FIONBIO, &lv); int rlen = 0; for (int i=0; rlen<=0 && i<500; i++) { if (!(i%100)) { for (int i=0; i<NUMBEROFDEVICES; i++) { m_name.Format(_T("%s%s:%s:%d"), URNPREFIX, devices[i][1], devices[i][0], version); CString request; request.Format(_T("M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: \"ssdp:discover\"\r\nMX: %d\r\nST: %s\r\n\r\n"), 6, m_name); SSDP_sendRequest(s, UPNPADDR, UPNPPORT, request); } } Sleep(10); char buffer[10240]; rlen = recv(s, buffer, sizeof(buffer), 0); if (rlen <= 0) continue; closesocket(s); CString response = CString(CStringA(buffer, rlen)); CString result; if (!parseHTTPResponse(response, result)) return false; for (int d=0; d<NUMBEROFDEVICES; d++) { m_name.Format(_T("%s%s:%s:%d"), URNPREFIX, devices[d][1], devices[d][0], version); if (result.Find(m_name) >= 0) { for (int pos = 0;;) { CString line = result.Tokenize(_T("\r\n"), pos); if (line.IsEmpty()) return false; CString name = line.Mid(0, 9); name.MakeUpper(); if (name == _T("LOCATION:")) { line.Delete(0, 9); m_description = line; m_description.Trim(); return GetDescription(); } } } } } closesocket(s); return false; }