📄 upnp.cpp
字号:
#include "stdafx.h"
#include "upnp.h"
#define UPNPPORTMAP0 _T("WANIPConnection")
#define UPNPPORTMAP1 _T("WANPPPConnection")
#define UPNPGETEXTERNALIP _T("GetExternalIPAddress"),_T("NewExternalIPAddress")
#define UPNPADDPORTMAP _T("AddPortMapping")
#define UPNPDELPORTMAP _T("DeletePortMapping")
static const ulong UPNPADDR = 0xFAFFFFEF;
static const int UPNPPORT = 1900;
static const CString URNPREFIX = _T("urn:schemas-upnp-org:");
const CString getString(int i)
{
CString s;
s.Format(_T("%d"), i);
return s;
}
const CString GetArgString(const CString& name, const CString& value)
{
return _T("<") + name + _T(">") + value + _T("</") + name + _T(">");
}
const CString GetArgString(const CString& name, int value)
{
return _T("<") + name + _T(">") + getString(value) + _T("</") + name + _T(">");
}
bool SOAP_action(CString addr, uint16 port, const CString request, CString &response)
{
char buffer[10240];
const CStringA sa(request);
int length = sa.GetLength();
strcpy(buffer, (const char*)sa);
uint32 ip = inet_addr(CStringA(addr));
struct sockaddr_in sockaddr;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(port);
sockaddr.sin_addr.S_un.S_addr = ip;
int s = socket(AF_INET, SOCK_STREAM, 0);
u_long lv = 1;
ioctlsocket(s, FIONBIO, &lv);
connect(s, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
Sleep(20);
int n = send(s, buffer, length, 0);
Sleep(100);
int rlen = recv(s, buffer, sizeof(buffer), 0);
closesocket(s);
if (rlen == SOCKET_ERROR) return false;
if (!rlen) return false;
response = CString(CStringA(buffer, rlen));
return true;
}
int SSDP_sendRequest(int s, uint32 ip, uint16 port, const CString& request)
{
char buffer[10240];
const CStringA sa(request);
int length = sa.GetLength();
strcpy(buffer, (const char*)sa);
struct sockaddr_in sockaddr;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(port);
sockaddr.sin_addr.S_un.S_addr = ip;
return sendto(s, buffer, length, 0, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
}
bool parseHTTPResponse(const CString& response, CString& result)
{
int pos = 0;
CString status = response.Tokenize(_T("\r\n"), pos);
result = response;
result.Delete(0, pos);
pos = 0;
status.Tokenize(_T(" "), pos);
status = status.Tokenize(_T(" "), pos);
if (status.IsEmpty() || status[0]!='2') return false;
return true;
}
const CString getProperty(const CString& all, const CString& name)
{
CString startTag = '<' + name + '>';
CString endTag = _T("</") + name + '>';
CString property;
int posStart = all.Find(startTag);
if (posStart<0) return CString();
int posEnd = all.Find(endTag, posStart);
if (posStart>=posEnd) return CString();
return all.Mid(posStart + startTag.GetLength(), posEnd - posStart - startTag.GetLength());
}
MyUPnP::MyUPnP()
: m_version(1)
{
m_uLocalIP = 0;
isSearched = false;
}
MyUPnP::~MyUPnP()
{
UPNPNAT_MAPPING search;
POSITION pos = m_Mappings.GetHeadPosition();
while(pos){
search = m_Mappings.GetNext(pos);
RemoveNATPortMapping(search, false);
}
m_Mappings.RemoveAll();
}
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;
}
bool MyUPnP::Search(int version)
{
if (isSearched) return isComplete();
isSearched = true;
return InternalSearch(version);
}
static CString NGetAddressFromUrl(const CString& str, CString& post, CString& host, int& port)
{
CString s = str;
post = _T("");
host = post;
port = 0;
int pos = s.Find(_T("://"));
if (!pos) return CString();
s.Delete(0, pos + 3);
pos = s.Find('/');
if (!pos) {
host = s;
s = _T("");
} else {
host = s.Mid(0, pos);
s.Delete(0, pos);
}
if (s.IsEmpty()) {
post = _T("");
} else {
post = s;
}
pos = 0;
CString addr = host.Tokenize(_T(":"), pos);
s = host.Tokenize(_T(":"), pos);
if (s.IsEmpty()) {
port = 80;
} else {
port = _tstoi(s);
}
return addr;
}
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, 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();
}
CString MyUPnP::GetProperty(const CString& name, CString& response)
{
if (!isComplete())return CString();
CString post, host, addr;
int port = 0;
addr = NGetAddressFromUrl(m_controlurl, post, host, port);
if(addr.IsEmpty())return CString();
CString cnt;
CString psr;
cnt.Append(_T("<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 </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 request = psr;
if (!SOAP_action(addr, port, request, response)) return CString();
CString result;
if (!parseHTTPResponse(response, result)) return CString();
return getProperty(result, response);
}
bool MyUPnP::InvokeCommand(const CString& name, const CString& args)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -