⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 btjl.txt

📁 比特精灵 源代码
💻 TXT
📖 第 1 页 / 共 2 页
字号:
比特精靈upnp.h
#ifndef MYUPNP_H_
#include "bt.h"
typedef bool (*PUPNPCALLBACK)(void* lp);
const int UPNPREPEAT = 5;
const int UPNPDELAY = 6;
class QMyUPNP
{
public:
	QMyUPNP();
    QMyUPNP(const QString& device);
	~QMyUPNP();
	void		Clear();
	bool		Comfirmed()const{return (Valid()&&!m_controlurl.IsEmpty());}
	bool		Search(const QString& name, const char* type="service", int repeat=UPNPREPEAT, int delay=UPNPDELAY, int version=1, PUPNPCALLBACK lpCall=NULL);
	bool		GetDescription(int delay=UPNPDELAY);
	QString		GetProperty(const QString& name, const QString& rsp, int delay=UPNPDELAY);
	bool		InvokeCommand(const QString& name, QStringList& args,int delay=UPNPDELAY);
	bool		SetDescriptionUrl(const QString& name, const QString& descri);
	void		SetDeviceName(const QString& p){m_devicename = p;}
	QString		GetDeviceName()const{return m_devicename;}
	QString		GetDescriptionUrl()const{return m_description;}
	QString		GetControlUrl()const{return m_controlurl;}
	QString		GetBaseUrl()const{return m_baseurl;}
	QString		GetDescriptionName()const{return m_name;}
	QString		GetFriendlyName()const{return m_friendlyname;}
	QString		GetModelName()const{return m_modelname;}
	QMyUPNP&	operator=(const QMyUPNP& up);
protected:
	bool		Valid()const{return (!m_name.IsEmpty()&&!m_description.IsEmpty());}
	void		InternalClear();
	bool		InternalSearch(const QString& name, const char* type, int repeat, int delay, int version, ulong ip, PUPNPCALLBACK lpCall);
	bool		InternalSearch2(const QString& name, const char* type, int repeat, int delay, int version, ulong ip, PUPNPCALLBACK lpCall);
	QString		m_devicename;
	QString		m_name;
	QString		m_description;
	QString		m_baseurl;
	QString		m_controlurl;
	QString		m_friendlyname;
	QString		m_modelname;
	int			m_version;
};
inline QMyUPNP& QMyUPNP::operator=(const QMyUPNP& upnp)
{
	if(this==&upnp)return *this;
	m_devicename = upnp.m_devicename;
	m_name = upnp.m_name;
	m_description = upnp.m_description;
	m_baseurl = upnp.m_baseurl;
	m_controlurl = upnp.m_controlurl;
	m_friendlyname = upnp.m_friendlyname;
	m_modelname = upnp.m_modelname;
	m_version = upnp.m_version;
	return *this;
}
#define UPNPPORTMAP0   "WANIPConnection"
#define UPNPPORTMAP1   "WANPPPConnection"
#define UPNPGETEXTERNALIP "GetExternalIPAddress","NewExternalIPAddress"
#define UPNPADDPORTMAP "AddPortMapping"
#define UPNPDELPORTMAP "DeletePortMapping"
void GetAddPortmapArgs(QStringList& args, int eport, int iport, const char* iclient,
			   const char* descri, bool enabled = true, int dur = 0,
			   const char* type = "TCP", const char* remote = NULL);
void GetDeletePortmapArgs(QStringList& args, int eport, const char* type = "TCP", const char* remote=NULL);
#endif

比特精靈upnp.cpp
#include "upnp.h"
#include "qsocket.h"
#include "qudp.h"
/*ReloadIp: 獲取本機上最類似於192.168.0.x的內網IP
如果本機沒有內網IP,則返回INADDR_NONE*/
static ulong ReloadIp()//get 192.168.0.x
{
	int				len = 256;
	char			name[256+1];
	hostent			*host;
	ulong			tmpip = INADDR_NONE, 
					retip = INADDR_NONE;
	memset(name, 0, len+1);
	if(gethostname(name,len)==0)
	{
		host = gethostbyname(name);
		if(host&&host->h_length>=sizeof(ulong))
		{
			len = 0;
			while(host->h_addr_list[len])
			{
				tmpip = *((ulong*)(host->h_addr_list[len++]));
if(((tmpip&0xFF)==192&&((tmpip>>8)&0xFF)==168&&((tmpip>>16)&0xFF)==0)||IsLAN(tmpip)||!is_validip(retip))
				{
					retip = tmpip;
				}
			}
		}
	}
	return retip;
}
static const ulong	UPNPADDR = 0xFAFFFFEF;
static const int	UPNPPORT = 1900;
static const char*	URNPREFIX = "urn:schemas-upnp-org:";
static const char*  LCA = "Location:";
static const char*  LCB = "LOCATION:";
static const char*  LCC = "location:";
/*LCA,LCB,LCC: 有些UPnP設備以LCA作為字段名稱,有些則用LCB,有些則用LCC,對於其他那些喜歡亂命名的廠商只好說抱歉了.*/
QMyUPNP::QMyUPNP()
: m_version(1)
{
}
QMyUPNP::QMyUPNP(const QString& device)
: m_devicename(device), m_version(1)
{

}
QMyUPNP::~QMyUPNP()
{
	Clear();
}
/*InternalClear: 清空對像,但保留對像*/
void QMyUPNP::InternalClear()
{
	m_baseurl = "";
	m_controlurl = "";
	m_friendlyname = "";
	m_modelname = "";
}
/*Clear: 清空對像,同時對像失效.*/
void QMyUPNP::Clear()
{
	m_name = "";
	m_description = "";
	m_version = 1;
	InternalClear();
}
/*InternalSearch: 查找UPnP設備
實現過程:首先調用InternalSearch2進行查找的操作,如果沒有找到,則設置對象的設備名為IGD,再次調用InternalSearch2查找.
之所以分兩次查找是因為有些設備支持以服務名查找,而有些設備則只支持以設備名查找.
參數含義:
name: 要查找的服務/設備的名稱
type: name表示的是服務或設備(service/device)
repeat: 嘗試查找的次數
delay: 查找結果的最長等待時間
version: UPnP版本,默認1
ip: 查詢的目標IP,默認為UPnP的廣播IP0xFAFFFFEF,也可以指定IP以便當程序運行在某些主機上時也能查找.
lpCall: 一個回調函數,在查找過程中隨機調用.
返回值: 成功返回true,否則返回false*/
bool QMyUPNP::InternalSearch(const QString& name, const char* type, int repeat,
				int delay, int version, ulong ip, PUPNPCALLBACK lpCall)
{
	if(InternalSearch2(name,type,repeat,delay,version,ip,lpCall))return true;
	QString back = m_devicename;
	m_devicename = QString("urn:schemas-upnp-org:device:InternetGatewayDevice:") + m_version;
	bool ok = InternalSearch2(name,type,repeat,delay,version,ip,lpCall);
	m_devicename = back;
	return ok;
}
/*InternalSearch2: 執行查找操作.
實現過程:
創建UDP套接字,如果IP為0,則先對255.255.255.255的1900端口發送廣播消息,再對UPnP的廣播IP發送消息.
參數函數同InternalSearch.*/
bool QMyUPNP::InternalSearch2(const QString& name, const char* type, int repeat,
				 int delay, int version, ulong ip, PUPNPCALLBACK lpCall)
{
	static const char*	USRS = "M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\n"
							  "MAN: \"ssdp:discover\"\r\nMX: ";
	const int			RCVLEN = 4096;
	Clear();
	if(name.IsEmpty())return false;
	if(type==NULL)type = "service";
	if(repeat<=0)repeat = UPNPREPEAT;
	if(delay<=0)delay = UPNPDELAY;
	if(version<=0)version = 1;
	m_version = version;
	m_name = QString(URNPREFIX) + type + ":" + name + ":" + version;
	QString finding = m_devicename.IsEmpty() ? m_name : m_devicename;
	QString shrs = QString(USRS) + delay + "\r\nST: " + finding + "\r\n\r\n";
	QUdpSocket	udp(true);
	char 		a[50], b[50], c[50];
	char		rcv[RCVLEN + 1];
	int			rlen = 0;
	int			retry = 0;
	const char* lc = "";
	const char* le = "";
	bool		broad = (!is_validip(ip)); //send to 255.255.255.255
	do
	{
		if(retry)sleep(1);
		if(!is_validip(ip)) ip = UPNPADDR;
		if(broad&&!udp.SendPacket(shrs.c_str(),shrs.Length(),INADDR_BROADCAST,UPNPPORT,delay/2))continue;
		if(!udp.SendPacket(shrs.c_str(),shrs.Length(),ip,UPNPPORT,delay/2)
		   ||(rlen=udp.RecvPacket(rcv,RCVLEN,delay))<=0)continue;
		if(lpCall&&!lpCall(NULL))break;
		if(rlen<=0||rlen>RCVLEN)continue;
		rcv[rlen] = 0;
		if(SplitterString(rcv,a,b,c,40,40,40)!=3||b[0]!='2')continue;
		if(strstr(rcv,finding.c_str())==NULL)continue;
		lc = strstr(rcv,LCA);
		if(lc==NULL) lc = strstr(rcv,LCB);
		if(lc==NULL) lc = strstr(rcv,LCC);
		if(lc==NULL)continue;
		lc += strlen(LCA);
		while(lc[0]>0&&lc[0]<=0x20) lc++;
		le = strchr(lc,'\n');
		if(le==NULL)continue;
		m_description = QString(lc,le - lc).Trim();
	}while(++retry<repeat&&!Valid());
	return GetDescription(delay);
}
/*Search: QMyUPnP的公開接口,由外部對像調用進行設備或服務的查找.
執行過程: 先對默認IP調用InternalSearch進行查找,如果沒找到,再判斷本機是否有局域網IP,如果有,則指定最類似於192.168.0.x的IP進行查詢.參數函數同InternalSearch.*/
bool QMyUPNP::Search(const QString& name,const char* type,int repeat,int delay,
					 int version, PUPNPCALLBACK lpCall)
{
	ulong	rip = 0;
	if(InternalSearch(name,type,repeat,delay,version,0,lpCall))return true;
	rip = ReloadIp();
	if(is_validip(rip))return InternalSearch(name,type,repeat,delay,version,rip,lpCall);
	return false;
}
/*SetDescriptionUrl: 由外部對像調用不通過查詢過程來創建一個有效的UPnP對像.
實現過程:對指定的URL執行GetDescription操作來判斷是否有效的UPnP對像.
參數含義:
name: 服務/設備名稱(全稱:如:urn:schemas-upnp-org:service:WANPPPConnection:1)
descri: 用於獲取設備/服務描述的目標URL.*/
bool QMyUPNP::SetDescriptionUrl(const QString& name, const QString& descri)
{
	Clear();
	m_name = name;
	m_description = descri;
	return GetDescription();
}
inline bool PPIsDigitChar(const char p)
{
	return (p>='0'&&p<='9');
}
static int ParseInteger(const char* cstr)
{
	const unsigned char* str = (const unsigned char*) cstr;
	int value = 0;
	assert(str);
	if(str)
	{
		int retry = 20;
		bool neg = (str[0]=='-');
		if(neg)str++;
		while(PPIsDigitChar(str[0])&&(--retry)>0)
		{
			value*=10;
			value+=(str[0]-'0');
			str++;
		}
		if(neg)value = -value;
	}
	return value;
}
static QString NGetAddressFromUrl(const QString& str,QString& post,QString& host,int& port)
{
	port = 0;
	post = "";
	if(str.IsEmpty())return QString();
	const char* src = str.c_str();
	const char* start,
			  * pstart,
			  *	end;
	start = strstr(src,"://");
	start = (start==NULL)?src:(start+3);
	end = strchr(start,'/');
	if(end==NULL)end = src + strlen(src);
	host = QString(start,end-start);
	post = (end[0]=='/')?QString(end):QString("/");
	pstart = strchr(start,':');
	port = (pstart==NULL||pstart>=end)?80:ParseInteger(pstart+1);
	if(port==0)port = 80;
	if(pstart&&pstart<end)end = pstart;
	return QString(start,end-start);
}
/*GetDescription: 在目標對象的描述URL已經獲取的情況下獲取該對象的描述.
實現過程: 對指定的URL實行一個UPnP規範指定的GET操作,解析返回的模板.只有成功解析了,對像才有效.
參數: 
delay: 最大等待時間.*/
bool QMyUPNP::GetDescription(int delay)
{
	if(!Valid())return false;
	InternalClear();
	QString post, host, addr;
	int port = 0;
	addr = NGetAddressFromUrl(m_description, post, host, port);
	if(addr.IsEmpty()||!is_validport(port))return false;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -