args+=(GetArgString(_T("NewProtocol"), type));//填TCP或UDP args+=(GetArgString(_T("NewInternalPort"), iport));//内部端口 args+=(GetArgString(_T("NewInternalClient"), iclient));//一般就是本地IP地址 args+=(GetArgString(_T("NewEnabled"), _T("1"))); args+=(GetArgString(_T("NewPortMappingDescription"), descri));//填写端口映射的描述, //比如什么程序建立了这个端口 args+=(GetArgString(_T("NewLeaseDuration"), 0));//端口映射的时间,0表示不永久 return InvokeCommand(UPNPADDPORTMAP, args); }//删除一端口映射 bool MyUPnP::deletePortmap(int eport, const CString& type) { CString args; args.Empty(); args+=(GetArgString(_T("NewRemoteHost"), _T(""))); args+=(GetArgString(_T("NewExternalPort"), eport)); args+=(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("%s (%s) [%s: %u]"),m_mapdescription, 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; } // srand( (unsigned)time( NULL ) ); mapping->externalPort =(WORD)( 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; }
return m_uLocalIP; }///////////////////////////////////////////////////////////////////////////////// // Returns a CString with the local IP in format xxx.xxx.xxx.xxx ///////////////////////////////////////////////////////////////////////////////// //以XXX.XXX.XXX.XXX的方式返回本地IP 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 ///////////////////////////////////////////////////////////////////////////////// //判断IP是否是局域网的IP 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; }
#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:");bool MyUPnP::SetLocalIP(CString localIP)
{//设置需要被映射局域网IP
DWORD ip = inet_addr(localIP);
if(IsLANIP(ip))
{
m_slocalIP = localIP;
m_uLocalIP = ip;
return true;
}
else
{
m_slocalIP.Empty();
return false;
}
}
//提供给外部的接口
bool MyUPnP::AddPortMap(WORD internalPort ,CString protocol,CString description,WORD externalPort)
{
srand( (unsigned)time( NULL ) );
if(m_slocalIP=="" || m_slocalIP.IsEmpty())
{
InitLocalIP();//自动获得本机的本地ip;
}
UPNPNAT_MAPPING m_maping;
if(externalPort!=0)
{
m_maping.externalPort = externalPort;
}
else
{
srand( (unsigned)time( NULL ) );
m_maping.externalPort = (WORD)( 2049 + (65535 - 2049) * rand() / (RAND_MAX + 1) );
// m_maping.externalPort = (WORD)(2049+rand()%3000);
}
m_maping.internalPort = internalPort; if(protocol=="TCP")
{
m_maping.protocol= UNAT_TCP;
}
else
if(protocol=="UDP")
{
m_maping.protocol= UNAT_UDP;
}
else
{
return false;
}
if(description!="")
m_mapdescription =description;
AddNATPortMapping(&m_maping);
return true;
}
bool MyUPnP::DeletePortMap(WORD externalPort,WORD internalPort )
{
return true;
}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(">");
}//SOAP是一种在分散,分布环境中用来交换结构化信息的轻量级协议。SOAP使用XML 技术来定义一个可扩展的消息框架,
//这个消息框架提供了一个能在多种下层(underlying)协议上进行交换的消息构造。
//框架被设计成独立于任何特定的编程模型和其他实现的具体语义。
bool SOAP_action(CString addr, WORD port, const CString request, CString &response)//发送请求,并接收响应
{
//简单对象访问协议(SOAP)
char buffer[10240]; const CString sa(request);
int length = sa.GetLength();
strcpy(buffer, (const char*)sa); DWORD ip = inet_addr(CString(addr));
struct sockaddr_in sockaddr;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(port);
//sockaddr.sin_port = htons(1900);
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(CString(buffer, rlen)); return true;
}//发送请求
//SSDP服务(用于寻找upnp设备)
int SSDP_sendRequest(int s, DWORD ip, WORD port, const CString& request)
{
// AfxMessageBox(request);
//简单服务发现协议(SSDP)
char buffer[10240]; const CString sa(request);
int length = sa.GetLength();
strcpy(buffer, (const char*)sa); CString strIP="239.255.255.250";
DWORD dwIP;
dwIP = inet_addr(strIP); 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 = dwIP; return sendto(s, buffer, length, 0, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
}//分析HTTP的响应
bool parseHTTPResponse(const CString& response, CString& result)
{
int pos = 0;
//CString status = response.Tokenize(_T("\r\n"), pos);
int endpos=response.Find(_T("\r\n"),pos);
CString status = response.Mid(pos,endpos-pos); result = response;
result.Delete(0, endpos); pos = 0;
endpos =status.Find(_T(" "), pos);
pos= endpos+1;
endpos = status.Find(_T(" "),pos);
status = status.Mid(pos,endpos-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)
{
WORD VersionRequested;
WSADATA WsaData;
VersionRequested=MAKEWORD(2,2);
WSAStartup(VersionRequested,&WsaData); //启动WinSock2
m_slocalIP="";
m_uLocalIP = 0;
m_mapdescription = "ItvSky";
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();
}
//内部搜索,向路由器发送HTTP请求,并分析得到的HTTP响应
bool MyUPnP::InternalSearch(int version)
{
if(version<=0)version = 1;
m_version = version;//#define UPNPPORTMAP0 _T("WANIPConnection")
//#define UPNPPORTMAP1 _T("WANPPPConnection")
//设备数
#define NUMBEROFDEVICES 3
CString devices[][2] = {
{UPNPPORTMAP1, _T("service")},
{UPNPPORTMAP0, _T("service")},
{_T("InternetGatewayDevice"), _T("device")},
}; SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
sockaddr_in sa;
sa.sin_family = AF_INET;
//sa.sin_addr.s_addr = inet_addr(CT2CA(theApp.GetBindAddress()));
sa.sin_addr.s_addr = INADDR_ANY;
// sa.sin_addr.s_addr=inet_addr("192.168.1.125");
sa.sin_port = htons(9990);
if (s != INVALID_SOCKET)
{
int nRet = bind((SOCKET)s, (SOCKADDR*)&sa, sizeof(sa));
if (nRet==SOCKET_ERROR)
{
closesocket(s); // ignore return value - error close anyway
return false;
}
}else
return false;
u_long lv = 1;
//设置为非阻塞模式
ioctlsocket(s, FIONBIO, &lv);
//static const CString URNPREFIX = _T("urn:schemas-upnp-org:")
/*
urn:schemas-UPnP-org:service:serviceType:v
搜索同类服务.服务类型与版本由UPnP论坛工作委员会定义.
*/
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);
int sendtoresult=SSDP_sendRequest(s, UPNPADDR, UPNPPORT, request);//向路由器发送HTTP请求
}
} Sleep(10);
//3月12日加
// CString m_request = _T("M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: \"ssdp:discover\"\r\nMX: 3\r\nST: UPnP:rootdevice\r\n\r\n");
// SSDP_sendRequest(s,UPNPADDR,UPNPPORT,m_request);
char buffer[10240];
rlen = recv(s, buffer, sizeof(buffer), 0);//接收响应
if (rlen <= 0) continue;
closesocket(s); CString response = CString(CString(buffer, rlen));
CString result;
// AfxMessageBox(response);
//分析从路由器来的HTTP响应
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;;) {
int beginpos = result.Find(_T("LOCATION:"),pos);
int endpos = result.Find(_T("\r\n"),beginpos);
CString line = result.Mid(beginpos,endpos-beginpos);
pos = endpos+1;
// CString line = result.Tokenize(_T("\r\n"), pos);
if (line.IsEmpty()) return false;
CString name = line.Mid(0, 9); //取前9个字符
name.MakeUpper(); //转换成大写字母
if (name == _T("LOCATION:")) {
//LOCATION 包含根设备UPnP描述的URL地址
line.Delete(0, 9);//删除前9个字符
m_description = line;
m_description.TrimLeft();
return GetDescription();//获得属性
}
}
}
}
}
closesocket(s); return false;
}bool MyUPnP::Search(int version)
{
// bool isComplete() const { return !m_controlurl.IsEmpty(); }
if (isSearched) return isComplete(); isSearched = true; return InternalSearch(version); //内部搜索,向路由器发送HTTP请求,并分析得到的HTTP响应,
//并获得属性
}//从m_description中获得端口和地址
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;
int endpos = host.Find(_T(":"),pos);
CString addr= host.Mid(pos,endpos-pos);
pos = endpos+1;
endpos = host.Find(_T(":"),pos);
s = host.Mid(pos,host.GetLength()-pos);
//CString addr = host.Tokenize(_T(":"), pos);
//s = host.Tokenize(_T(":"), pos);
if (s.IsEmpty()) {
port = 80;
} else {
port = atoi(s);
} return addr;
}
bool MyUPnP::GetDescription()
{
//bool Valid()const{return (!m_name.IsEmpty()&&!m_description.IsEmpty());}
if(!Valid())return false;
CString post, host, addr;
int port = 0;
//从m_description中获得端口和地址,并再返回给addr
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;
//Append附加
cnt+=(_T("<s:Envelope\r\n xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\r\n "));
cnt+=(_T("s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n <s:Body>\r\n <u:"));
cnt+=(name);
cnt+=(_T(" xmlns:u=\""));
cnt+=(m_name);
cnt+=(_T("\">\r\n </u:"));
cnt+=(name);
cnt+=(_T(">\r\n </s:Body>\r\n</s:Envelope>\r\n\r\n"));
psr+=(_T("POST "));
psr+=(post);
psr+=(_T(" HTTP/1.1\r\nHOST: "));
psr+=(host);
psr+=(_T("\r\nContent-Length: "));
psr+=(getString(CString(cnt).GetLength()));
psr+=(_T("\r\nContent-Type: text/xml; charset=\"utf-8\"\r\nSOAPAction: \""));
psr+=(m_name);
psr+=(_T("#"));
psr+=(name);
psr+=(_T("\"\r\n\r\n"));
psr+=(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);
}//调用命令,被deletePortmap和addPortmap调用
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+=(_T("<?xml version=\"1.0\"?><s:Envelope\r\n xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\r\n "));
cnt+=(_T("s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n <s:Body>\r\n <u:"));
cnt+=(name);
cnt+=(_T(" xmlns:u=\""));
cnt+=(m_name);
cnt+=(_T("\">\r\n"));
cnt+=(args);
cnt+=(_T(" </u:"));
cnt+=(name);
cnt+=(_T(">\r\n </s:Body>\r\n</s:Envelope>\r\n\r\n"));
psr+=(_T("POST "));
psr+=(post);
psr+=(_T(" HTTP/1.1\r\nHOST: "));
psr+=(host);
psr+=(_T("\r\nContent-Length: "));//Content-Length是这个XML文档的长度
psr+=(getString(CString(cnt).GetLength()));
psr+=(_T("\r\nContent-Type: text/xml; charset=\"utf-8\"\r\nSOAPAction: \""));
psr+=(m_name);
psr+=(_T("#"));
psr+=(name);
psr+=(_T("\"\r\n\r\n"));
psr+=(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+=(GetArgString(_T("NewRemoteHost"), _T("")));
args+=(GetArgString(_T("NewExternalPort"), eport));//外部端口
//GetArgString后,
//变成<NewRxternalPort>eport</NexExternalPort>
args+=(GetArgString(_T("NewProtocol"), type));//填TCP或UDP
args+=(GetArgString(_T("NewInternalPort"), iport));//内部端口
args+=(GetArgString(_T("NewInternalClient"), iclient));//一般就是本地IP地址
args+=(GetArgString(_T("NewEnabled"), _T("1")));
args+=(GetArgString(_T("NewPortMappingDescription"), descri));//填写端口映射的描述,
//比如什么程序建立了这个端口 args+=(GetArgString(_T("NewLeaseDuration"), 0));//端口映射的时间,0表示不永久 return InvokeCommand(UPNPADDPORTMAP, args);
}//删除一端口映射
bool MyUPnP::deletePortmap(int eport, const CString& type)
{
CString args; args.Empty();
args+=(GetArgString(_T("NewRemoteHost"), _T("")));
args+=(GetArgString(_T("NewExternalPort"), eport));
args+=(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("%s (%s) [%s: %u]"),m_mapdescription, 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;
}
// srand( (unsigned)time( NULL ) );
mapping->externalPort =(WORD)( 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()
/////////////////////////////////////////////////////////////////////////////////
//获得本地IP,被GetLocalIP和GetLocalIPStr调用
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
/////////////////////////////////////////////////////////////////////////////////
//返回本地IP,以WORD的值返回
WORD MyUPnP::GetLocalIP()
{
if(m_uLocalIP == 0)
InitLocalIP();
return m_uLocalIP;
}/////////////////////////////////////////////////////////////////////////////////
// Returns a CString with the local IP in format xxx.xxx.xxx.xxx
/////////////////////////////////////////////////////////////////////////////////
//以XXX.XXX.XXX.XXX的方式返回本地IP
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
/////////////////////////////////////////////////////////////////////////////////
//判断IP是否是局域网的IP
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;
}
加奖:120分