📄 upnp.cpp
字号:
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, port, request, response)) return false;
CString result;
if (!parseHTTPResponse(response, result)) return false;
return true;
}
bool MyUPnP::addPortmap(int eport, int iport, const CString& iclient, const CString& descri, const CString& type)
{
CString args;
args.Empty();
args.Append(GetArgString(_T("NewRemoteHost"), _T("")));
args.Append(GetArgString(_T("NewExternalPort"), eport));
args.Append(GetArgString(_T("NewProtocol"), type));
args.Append(GetArgString(_T("NewInternalPort"), iport));
args.Append(GetArgString(_T("NewInternalClient"), iclient));
args.Append(GetArgString(_T("NewEnabled"), _T("1")));
args.Append(GetArgString(_T("NewPortMappingDescription"), descri));
args.Append(GetArgString(_T("NewLeaseDuration"), 0));
return InvokeCommand(UPNPADDPORTMAP, args);
}
bool MyUPnP::deletePortmap(int eport, const CString& type)
{
CString args;
args.Empty();
args.Append(GetArgString(_T("NewRemoteHost"), _T("")));
args.Append(GetArgString(_T("NewExternalPort"), eport));
args.Append(GetArgString(_T("NewProtocol"), type));
return InvokeCommand(UPNPDELPORTMAP, args);
}
/////////////////////////////////////////////////////////////////////////////////
// Adds a NAT Port Mapping
// Params:
// UPNPNAT_MAPPING *mapping -> Port Mapping Data
// If mapping->externalPort is 0, then
// mapping->externalPort gets the value of mapping->internalPort
// bool tryRandom:
// If If mapping->externalPort is in use, tries to find a free
// random external port.
//
// Return:
// UNAT_OK:
// Successfull.
// UNAT_EXTERNAL_PORT_IN_USE:
// Error, you are trying to add a port mapping with an external port
// in use.
// UNAT_NOT_IN_LAN:
// Error, you aren't in a LAN -> no router or firewall
// UNAT_ERROR:
// Error, use GetLastError() to get an error description.
/////////////////////////////////////////////////////////////////////////////////
MyUPnP::UPNPNAT_RETURN MyUPnP::AddNATPortMapping(UPNPNAT_MAPPING *mapping, bool tryRandom)
{
CString ProtoStr, Proto;
if(!IsLANIP(GetLocalIP())){
SetLastError(_T("You aren't behind a Hardware Firewall or Router"));
return UNAT_NOT_IN_LAN;
}
if (!isComplete()) {
Search();
if (!isComplete()) {
SetLastError(_T("Can not found a UPnP Router"));
return UNAT_ERROR;
}
}
if (mapping->protocol == UNAT_TCP){
Proto = _T("TCP");
ProtoStr = _T("TCP");
}
else {
Proto = _T("UDP");
ProtoStr = _T("UDP");
}
if(mapping->externalPort == 0)
mapping->externalPort = mapping->internalPort;
int retries = 255;
WORD rndPort = mapping->externalPort;
for (int retries = 255; retries; retries--) {
CString Desc;
Desc.Format(_T("eMule (%s) [%s: %u]"), mapping->description, ProtoStr, mapping->externalPort);
if (addPortmap(mapping->externalPort, mapping->internalPort, GetLocalIPStr(), Desc, Proto)) {
m_Mappings.AddTail(*mapping);
return UNAT_OK;
}
if (!tryRandom) {
SetLastError(_T("External NAT port in use"));
return UNAT_EXTERNAL_PORT_IN_USE;
}
mapping->externalPort = 2049 + (65535 - 2049) * rand() / (RAND_MAX + 1);
}
SetLastError(_T("External NAT port in use: Too many retries"));
return UNAT_EXTERNAL_PORT_IN_USE;
}
/////////////////////////////////////////////////////////////////////////////////
// Removes a NAT Port Mapping
// Params:
// UPNPNAT_MAPPING *mapping -> Port Mapping Data
// Should be the same struct passed to AddNATPortMapping
// bool removeFromList -> Remove the port mapping from the internal list
// Should by allways true (dafault value if not passed).
// If you set it to false can cause an unexpected error.
//
//
// Return:
// UNAT_OK:
// Successfull.
// UNAT_NOT_OWNED_PORTMAPPING:
// Error, you are trying to remove a port mapping not owned by this class
// UNAT_NOT_IN_LAN:
// Error, you aren't in a LAN -> no router or firewall
// UNAT_ERROR:
// Error, use GetLastError() to get an error description.
/////////////////////////////////////////////////////////////////////////////////
MyUPnP::UPNPNAT_RETURN MyUPnP::RemoveNATPortMapping(UPNPNAT_MAPPING mapping, bool removeFromList)
{
if(!IsLANIP(GetLocalIP())){
SetLastError(_T("You aren't behind a Hardware Firewall or Router"));
return UNAT_NOT_IN_LAN;
}
if (!isComplete()) {
Search();
if (!isComplete()) {
SetLastError(_T("Can not found a UPnP Router"));
return UNAT_ERROR;
}
}
for(POSITION pos = m_Mappings.GetHeadPosition(); pos!=NULL; m_Mappings.GetNext(pos)){
UPNPNAT_MAPPING search = m_Mappings.GetAt(pos);
if (search.externalPort == mapping.externalPort
&& search.protocol == mapping.protocol)
{
CString Proto;
if (mapping.protocol == UNAT_TCP)
Proto = _T("TCP");
else
Proto = _T("UDP");
if (deletePortmap(mapping.externalPort, Proto)) {
if(removeFromList)
m_Mappings.RemoveAt(pos);
return UNAT_OK;
} else {
SetLastError(_T("Error getting StaticPortMappingCollection"));
return UNAT_ERROR;
}
}
}
SetLastError(_T("Port mapping not owned by this class"));
return UNAT_NOT_OWNED_PORTMAPPING;
}
void MyUPnP::clearNATPortMapping()
{
UPNPNAT_MAPPING search;
POSITION pos = m_Mappings.GetHeadPosition();
while(pos){
search = m_Mappings.GetNext(pos);
RemoveNATPortMapping(search, false);
}
m_Mappings.RemoveAll();
}
/////////////////////////////////////////////////////////////////////////////////
// Initializes m_localIP variable, for future access to GetLocalIP()
/////////////////////////////////////////////////////////////////////////////////
void MyUPnP::InitLocalIP()
{
#ifndef _DEBUG
try
#endif
{
char szHost[256];
if (gethostname(szHost, sizeof szHost) == 0){
hostent* pHostEnt = gethostbyname(szHost);
if (pHostEnt != NULL && pHostEnt->h_length == 4 && pHostEnt->h_addr_list[0] != NULL){
UPNPNAT_MAPPING mapping;
struct in_addr addr;
memcpy(&addr, pHostEnt->h_addr_list[0], sizeof(struct in_addr));
m_slocalIP = inet_ntoa(addr);
m_uLocalIP = addr.S_un.S_addr;
}
else{
m_slocalIP = _T("");
m_uLocalIP = 0;
}
}
else{
m_slocalIP = _T("");
m_uLocalIP = 0;
}
}
#ifndef _DEBUG
catch(...){
m_slocalIP = _T("");
m_uLocalIP = 0;
}
#endif
}
/////////////////////////////////////////////////////////////////////////////////
// Returns the Local IP
/////////////////////////////////////////////////////////////////////////////////
WORD MyUPnP::GetLocalIP()
{
if(m_uLocalIP == 0)
InitLocalIP();
return m_uLocalIP;
}
/////////////////////////////////////////////////////////////////////////////////
// Returns a CString with the local IP in format xxx.xxx.xxx.xxx
/////////////////////////////////////////////////////////////////////////////////
CString MyUPnP::GetLocalIPStr()
{
if(m_slocalIP.IsEmpty())
InitLocalIP();
return m_slocalIP;
}
/////////////////////////////////////////////////////////////////////////////////
// Sets the value of m_lastError (last error description)
/////////////////////////////////////////////////////////////////////////////////
void MyUPnP::SetLastError(CString error) {
m_slastError = error;
};
/////////////////////////////////////////////////////////////////////////////////
// Returns the last error description in a CString
/////////////////////////////////////////////////////////////////////////////////
CString MyUPnP::GetLastError()
{
return m_slastError;
}
/////////////////////////////////////////////////////////////////////////////////
// Returns true if nIP is a LAN ip, false otherwise
/////////////////////////////////////////////////////////////////////////////////
bool MyUPnP::IsLANIP(WORD nIP){
// filter LAN IP's
// -------------------------------------------
// 0.*
// 10.0.0.0 - 10.255.255.255 class A
// 172.16.0.0 - 172.31.255.255 class B
// 192.168.0.0 - 192.168.255.255 class C
unsigned char nFirst = (unsigned char)nIP;
unsigned char nSecond = (unsigned char)(nIP >> 8);
if (nFirst==192 && nSecond==168) // check this 1st, because those LANs IPs are mostly spreaded
return true;
if (nFirst==172 && nSecond>=16 && nSecond<=31)
return true;
if (nFirst==0 || nFirst==10)
return true;
return false;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -