UPnP.接受不到设备回应。

TypeCool 2011-03-20 12:16:21
我正确发送了搜索请求,通过Wireshark抓包看见设备回复了消息。可是我无论如何都接受不到。


另外,我提交控制文件,确得到错误回应如下。

找到控制页URL:
http://192.168.1.99:1900/ipc
找到服务类型:
urn:schemas-upnp-org:service:WANIPConnection:1
控制页地址解析:
192.168.1.99
1900
/ipc
控制文件:
POST /ipc HTTP/1.1
HOST: 192.168.1.99:1900
SOAPACTION: "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping"
CONTENT-TYPE: text/xml; charset="utf-8"
CONTENT-LENGTH: 634

<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"s:encodingStyle="
http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:AddPortMapping xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">
<NewRemoteHost> </NewRemoteHost>
<NewExternalPort>20300 </NewExternalPort>
<NewProtocol>TCP </NewProtocol>
<NewInternalPort>20300 </NewInternalPort>
<NewInternalClient>192.168.1.200 </NewInternalClient>
<NewEnabled>1 </NewEnabled>
<NewPortMappingDescription>DNSCall </NewPortMappingDescription>
<NewLeaseDuration>0 </NewLeaseDuration></u:AddPortMapping>
</s:Body>
</s:Envelope>

发送字节数:
789
实际送字节数:
789
回馈:
HTTP/1.1 400 Bad Request
SERVER: ipos/7.0 UPnP/1.0 MW150R/1.0/2.0
CONNECTION: close
CONTENT-LENGTH: 50
CONTENT-TYPE: text/html

<html><body><h1>400 Bad Request</h1></body></html>
程序结束.
...全文
762 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
TypeCool 2011-03-21
  • 打赏
  • 举报
回复
终于成功了~!太感谢你了,hurryboylqs

哈哈,太好了,我的工作又可以继续了。接下来再把端口删除和事件通告看一下,就OK了。

允许我再开心一下:哈哈!
TypeCool 2011-03-21
  • 打赏
  • 举报
回复
恩,,太好了。我能接收到设备回馈了!

还其中的原理,我还没有搞懂.
我之前加入多播组发搜索,能成功,但不能接受回馈.
现在根据这份源码来做,直接不加多播组,往多播地址上丢一个包就跑回来.反倒能接收到回馈了。真诡异啊。
Eleven 2011-03-20
  • 打赏
  • 举报
回复
错误的请求?
hurryboylqs 2011-03-20
  • 打赏
  • 举报
回复
我整了个映射TCP的例子,发你了,你自己一步一步调试进去看回应和映射的过程
samako 2011-03-20
  • 打赏
  • 举报
回复
学习学习
TypeCool 2011-03-20
  • 打赏
  • 举报
回复
好的,我今晚通宵观摩,明天回复。
hurryboylqs 2011-03-20
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 typecool 的回复:]

你能把你这份源码发给我一份吗。我手上的好像和你的不一样。谢谢。

type_cool@163.com
[/Quote]

已经全部贴出来了啊,你看下我那个SearchDevice 函数 就是搜索设备的,从代码看来你的HTTP报文组织错了
,有回应不表明HTTP报文完全正确。
TypeCool 2011-03-20
  • 打赏
  • 举报
回复
你能把你这份源码发给我一份吗。我手上的好像和你的不一样。谢谢。

type_cool@163.com
hurryboylqs 2011-03-20
  • 打赏
  • 举报
回复
看InternalSearch这个函数的实现
TypeCool 2011-03-20
  • 打赏
  • 举报
回复
221. HRESULT CUPnpNat::AddPortMapping(LPCTSTR lpszRemoteHost,
222. USHORT usExternalPort, LPCTSTR lpszPortMappingProtocol,
223. USHORT usInternalPort, LPCTSTR lpszInternalClient,
224. LPCTSTR lpszPortMappingDescription,
225. BOOL bPortMappingEnabled,
226. ULONG ulPortMappingLeaseDuration)
227. {
228. CString args;
229. CString strResponse;
230.
231. args.Empty();
232. args.Append(GetArgString(_T("NewRemoteHost"), CString(lpszRemoteHost)));
233. args.Append(GetArgString(_T("NewExternalPort"), usExternalPort));
234. args.Append(GetArgString(_T("NewProtocol"), CString(lpszPortMappingProtocol)));
235. args.Append(GetArgString(_T("NewInternalPort"), usInternalPort));
236. args.Append(GetArgString(_T("NewInternalClient"), CString(lpszInternalClient)));
237. args.Append(GetArgString(_T("NewEnabled"), bPortMappingEnabled));
238. args.Append(GetArgString(_T("NewPortMappingDescription"), CString(lpszPortMappingDescription)));
239. args.Append(GetArgString(_T("NewLeaseDuration"), ulPortMappingLeaseDuration));
240.
241. return InvokeCommand(_T("AddPortMapping"), args, strResponse);
242.
243. }

这个就是添加端口映射的函数吧。我看了。 先帮我看看 搜索-发现 这一步吧。提交控制页的事情,以后再说。
hurryboylqs 2011-03-20
  • 打赏
  • 举报
回复


bool CUPnpNat::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 (FAILED(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();
}

CString CUPnpNat::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 (FAILED(SOAP_action(addr, (UINT16)port, request, response))) return CString();
CString result;
if (!parseHTTPResponse(response, result)) return CString();

return getProperty(result, response);
}

HRESULT CUPnpNat::InvokeCommand(const CString& name, const CString& args, CString &strResponse)
{
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);

strResponse.Empty();

HRESULT hr;
CString response;
CString request = psr;
hr = SOAP_action(addr, (UINT16)port, request, response);
if (FAILED(hr))
return hr;

strResponse = response;

CString result;
if (!parseHTTPResponse(response, result))
return E_UNAT_ACTION_HTTP_ERRORCODE;


return S_OK;
}

BOOL CUPnpNat::IsLengthedHttpPacketComplete(const char *packet, int len)
{
const char STR_CONTENT_LENGTH[] = "Content-Length:";
const int STRLEN_CONTENT_LENGTH = sizeof(STR_CONTENT_LENGTH) / sizeof(char) - 1;
const char STR_DOUBLE_NEWLINE[] = "\r\n\r\n";
const int STRLEN_DOUBLE_NEWLINE = sizeof(STR_DOUBLE_NEWLINE) / sizeof(char) - 1;

char *pContLenPos = NULL;
pContLenPos = StrStrIA(packet, STR_CONTENT_LENGTH);
if (NULL == pContLenPos)
return FALSE;

char *pNewLinePos = NULL;
pNewLinePos = strstr(pContLenPos, "\r\n");
if (NULL == pNewLinePos)
return FALSE;

// Get number of content length <begin>
int iContentLen = 0;
char *pLenStartPos = pContLenPos + STRLEN_CONTENT_LENGTH;
char *pLenEndPos = pNewLinePos;
size_t nBufSize = pLenEndPos - pLenStartPos + 1;
char *szLength = new char[nBufSize];

memcpy(szLength, pLenStartPos, nBufSize - 1);
szLength[nBufSize - 1] = 0;
iContentLen = atoi(szLength);

delete[] szLength;
szLength = NULL;
// Get number of content length <end>

int iHeadLen = 0;
char *pDoubleNewLinePos = NULL;
pDoubleNewLinePos = (char *)strstr(packet, STR_DOUBLE_NEWLINE);
if (NULL == pDoubleNewLinePos)
return FALSE;

iHeadLen = pDoubleNewLinePos - packet + STRLEN_DOUBLE_NEWLINE;

if (len >= iHeadLen + iContentLen)
return TRUE;
else
return FALSE;
}
hurryboylqs 2011-03-20
  • 打赏
  • 举报
回复

HRESULT CUPnpNat::GetSpecificPortMappingEntry(LPCTSTR lpszRemoteHost, //[in]
USHORT usExternalPort, //[in]
LPCTSTR lpszPortMappingProtocol, //[in]
USHORT *pusInternalPort, //[out]
CString *pstrInternalClient, //[out]
bool *pbEnable, //[out]
CString *pstrDescription, //[out]
ULONG *pulPortMappingLeaseDuration) //[out]
{
CString args;
CString strResponse;

args.Empty();
args.Append(GetArgString(_T("NewRemoteHost"), CString(lpszRemoteHost)));
args.Append(GetArgString(_T("NewExternalPort"), usExternalPort));
args.Append(GetArgString(_T("NewProtocol"), CString(lpszPortMappingProtocol)));

HRESULT hr;
hr = InvokeCommand(_T("GetSpecificPortMappingEntry"), args, strResponse);
if (FAILED(hr))
return hr;

if (NULL != pusInternalPort)
*pusInternalPort = (USHORT) atoi(CStringA(getProperty(strResponse, _T("NewInternalPort"))));
if (NULL != pstrInternalClient)
*pstrInternalClient = getProperty(strResponse, _T("NewInternalClient"));
if (NULL != pbEnable)
*pbEnable = (bool) (atoi(CStringA(getProperty(strResponse, _T("NewEnabled")))) == 0 ? false : true);
if (NULL != pstrDescription)
*pstrDescription = getProperty(strResponse, _T("NewPortMappingDescription"));
if (NULL != pulPortMappingLeaseDuration)
*pulPortMappingLeaseDuration = (ULONG) atoi(CStringA(getProperty(strResponse, _T("NewLeaseDuration"))));

return S_OK;
}

HRESULT CUPnpNat::GetGenericPortMappingEntry(USHORT usIndex, //[in]
CString *pstrRemoteHost, //[out]
USHORT *pusExternalPort, //[out]
CString *pstrProtocol, //[out]
USHORT *pusInternalPort, //[out]
CString *pstrInternalClient, //[out]
bool *pbEnable, //[out]
CString *pstrDescription) //[out]
{
CString args;
CString strResponse;

args.Empty();
args.Append(GetArgString(_T("NewPortMappingIndex"), usIndex));

HRESULT hr;
hr = InvokeCommand(_T("GetGenericPortMappingEntry"), args, strResponse);
if (FAILED(hr))
return hr;


if (NULL != pstrRemoteHost)
*pstrRemoteHost = getProperty(strResponse, _T("NewRemoteHost"));
if (NULL != pusExternalPort)
*pusExternalPort = (USHORT) atoi(CStringA(getProperty(strResponse, _T("NewExternalPort"))));
if (NULL != pstrProtocol)
*pstrProtocol = getProperty(strResponse, _T("NewProtocol"));
if (NULL != pusInternalPort)
*pusInternalPort = (USHORT) atoi(CStringA(getProperty(strResponse, _T("NewInternalPort"))));
if (NULL != pstrInternalClient)
*pstrInternalClient = getProperty(strResponse, _T("NewInternalClient"));
if (NULL != pbEnable)
*pbEnable = (bool) (atoi(CStringA(getProperty(strResponse, _T("NewEnabled")))) == 0 ? false : true);
if (NULL != pstrDescription)
*pstrDescription = getProperty(strResponse, _T("NewPortMappingDescription"));

return S_OK;
}

//////////////////////////////////////////////////////////////////////////
// Protected functions

HRESULT CUPnpNat::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;
SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == s)
return E_UNAT_CREATE_SOCKET_FAILED;

if (! m_strBindAddress.IsEmpty())
{
sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr(CStringA(m_strBindAddress));
sa.sin_port = 0;

int nRet = bind(s, (SOCKADDR*)&sa, sizeof(sa));
if (nRet == SOCKET_ERROR)
{
closesocket(s); // ignore return value - error close anyway
return E_UNAT_SOCKET_BIND_FAILED;
}
}


connect(s, (struct sockaddr *)&sockaddr, sizeof(sockaddr));

//ADDED by VC-fengwen 2007/08/24 <begin> : 仍通过异步处理,使处理回复内容时不用去处理http头里的content-length。
u_long lv = 1;
ioctlsocket(s, FIONBIO, &lv);
//ADDED by VC-fengwen 2007/08/24 <end> : 仍通过异步处理,使处理回复内容时不用去处理http头里的content-length。

//COMMENTED by VC-fengwen 2007/08/23 <begin> : 使用Sleep的方法收集tcp数据
////ADDED by VC-fengwen 2007/08/23 <begin> : 为防止卡死,需要设置Timeout
//setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (const char *)&m_iActionTimeoutMs, sizeof(int));
//setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (const char *)&m_iActionTimeoutMs, sizeof(int));
////ADDED by VC-fengwen 2007/08/23 <end> : 为防止卡死,需要设置Timeout
//COMMENTED by VC-fengwen 2007/08/23 <end> : 使用Sleep的方法收集tcp数据

send(s, buffer, length, 0);

//MODIFIED by VC-fengwen 2007/08/23 <begin> : 接收流数据直到socket断开或超时。
////MODIFIED by VC-fengwen 2007/08/23 <begin> : 根据同步Timeout来实现延时
////int rlen = 0;
////int iSleepMs = 500;
////for (int i = 0; rlen <= 0 && i < m_iActionTimeoutMs; i += iSleepMs)
////{
//// Sleep(iSleepMs);

//// rlen = recv(s, buffer, sizeof(buffer), 0);
////}

//Sleep(m_iActionTimeoutMs);//ADDED by VC-fengwen 2007/08/23 : 由于是TCP连接,等待一段时间使数据收集完整

//int rlen = 0;
//rlen = recv(s, buffer, sizeof(buffer), 0);
////MODIFIED by VC-fengwen 2007/08/23 <end> : 根据同步Timeout来实现延时

int rlen = 0;
int iSleepMs = 500;
char *pCurWritePos = buffer;
int iWritedCount = 0;
for (int i = 0; i < m_iActionTimeoutMs; i += iSleepMs)
{
Sleep(iSleepMs);

rlen = recv(s, pCurWritePos, sizeof(buffer) - iWritedCount, 0);

if (0 == rlen)
break;
else if (rlen > 0)
{
pCurWritePos += rlen;
iWritedCount += rlen;
}

if (IsLengthedHttpPacketComplete(buffer, iWritedCount))
break;
}
rlen = iWritedCount;
//MODIFIED by VC-fengwen 2007/08/23 <end> : 接收流数据直到socket断开或超时。



closesocket(s);

if (rlen <= 0)
return E_UNAT_TIMEOUT;


closesocket(s);
if (rlen == SOCKET_ERROR) return E_UNAT_TIMEOUT;
if (!rlen) return E_UNAT_TIMEOUT;

response = CString(CStringA(buffer, rlen));

CString result;
if (!parseHTTPResponse(response, result))
{
int iResponseCode = -1;
CString strErrorCode = getProperty(response, _T("errorCode"));
if (!strErrorCode.IsEmpty())
iResponseCode = atoi(CStringA(strErrorCode));

SetLastActionErrorCode(iResponseCode);
return E_UNAT_ACTION_HTTP_ERRORCODE;
}

return S_OK;
}

int CUPnpNat::SSDP_sendRequest(SOCKET 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 CUPnpNat::InternalSearch(int version, BOOL bUseDefaultGateway)
{
if(version<=0)version = 1;
m_version = version;

#define NUMBEROFDEVICES 3
CString devices[][2] = {
{UPNPPORTMAP1, _T("service")},
{UPNPPORTMAP0, _T("service")},
{_T("InternetGatewayDevice"), _T("device")},
};

SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
if (INVALID_SOCKET == s)
return false;

if (! m_strBindAddress.IsEmpty())
{
sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr(CStringA(m_strBindAddress));
sa.sin_port = 0;

int nRet = bind(s, (SOCKADDR*)&sa, sizeof(sa));
if (nRet == SOCKET_ERROR)
{
closesocket(s); // ignore return value - error close anyway
return false;
}
}

UINT32 uReqIp = 0;
UINT32 uDefGW = 0;
if (bUseDefaultGateway && GetDefaultGateway(uDefGW))
uReqIp = uDefGW;
else
uReqIp = UPNPADDR;


int iSleepTime = 1000;

u_long lv = 1;
ioctlsocket(s, FIONBIO, &lv);
//MODIFIED by VC-fengwen 2007/08/24 <end> : udp设置timeout似乎无效,仍使用sleep来控置timeout


int rlen = 0;
char buffer[10240];
for (int i = 0; rlen <= 0 && i < SEARCH_TIMEOUT_MS; i += iSleepTime) {
if (i % 3000 == 0) { //在没收到回复的情况下,每3秒广播一次请求。
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, uReqIp, UPNPPORT, request);
}
}

Sleep(iSleepTime);

rlen = recv(s, buffer, sizeof(buffer), 0);
}
closesocket(s);

if(rlen <= 0)
return false;

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();
}
}
}
}

return false;
}

hurryboylqs 2011-03-20
  • 打赏
  • 举报
回复

#include "upnpnat.h"
#include "IpHlpApi.h"
#pragma comment (lib, "IpHlpApi.lib")
#define UPNPPORTMAP0 _T("WANIPConnection")
#define UPNPPORTMAP1 _T("WANPPPConnection")
static const ULONG UPNPADDR = 0xFAFFFFEF;
static const int UPNPPORT = 1900;
static const CString URNPREFIX = _T("urn:schemas-upnp-org:");

//////////////////////////////////////////////////////////////////////////
extern const CString getString(int i);
extern const CString GetArgString(const CString& name, const CString& value);
extern const CString GetArgString(const CString& name, int value);
extern bool parseHTTPResponse(const CString& response, CString& result);
extern const CString getProperty(const CString& all, const CString& name);

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 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());
}

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();
if (-1 == pos) return CString(); //MODIFIED by fengwen on 2006/11/29 : Find返回-1表示没找到。
s.Delete(0, pos + 3);

pos = s.Find('/');
//if (!pos) {
if (-1 == pos) { //MODIFIED by fengwen on 2006/11/29 : Find返回-1表示没找到。
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);

//MODIFIED by fengwen on 2006/11/29 <begin> : 如果用pos==-1,调用Tokenize会抛出异常。
//s = host.Tokenize(_T(":"), pos);
if (addr.IsEmpty() || -1 == pos)
s = _T("");
else
s = host.Tokenize(_T(":"), pos);
//MODIFIED by fengwen on 2006/11/29 <end> : 如果用pos==-1,调用Tokenize会抛出异常。

if (s.IsEmpty()) {
port = 80;
} else {
port = _tstoi(s);
}

return addr;
}

BOOL GetDefaultGateway(UINT32 &ip)
{
PIP_ADAPTER_INFO pAdapterInfo = NULL, pCurAdapterInfo;
ULONG ulOutBufLen = 0;
DWORD dwRetVal = 0;
BOOL bRet;

bRet = FALSE;

pAdapterInfo = (IP_ADAPTER_INFO *) malloc( sizeof(IP_ADAPTER_INFO) );
ulOutBufLen = sizeof(IP_ADAPTER_INFO);

dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);

if (ERROR_BUFFER_OVERFLOW == dwRetVal)
{
free(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *) malloc (ulOutBufLen);
dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
}

if (ERROR_SUCCESS == dwRetVal)
{
pCurAdapterInfo = pAdapterInfo;
do {
ip = inet_addr(pCurAdapterInfo->GatewayList.IpAddress.String);
} while(ip == 0 && (pCurAdapterInfo = pCurAdapterInfo->Next) != NULL);
bRet = TRUE;
}

free(pAdapterInfo);
pAdapterInfo = NULL;

return bRet;
}

//////////////////////////////////////////////////////////////////////////
// member functions

CUPnpNat::CUPnpNat(void)
{
m_strBindAddress.Empty();
m_iActionTimeoutMs = DEF_ACTION_TIMEOUT_MS;

m_dwLastErrorCode = 0;

m_version = 1;
m_isSearched = FALSE;
}

CUPnpNat::~CUPnpNat(void)
{
}

HRESULT CUPnpNat::SearchDevice(BOOL bUseDefaultGateway)
{
if (m_isSearched)
{
if (isComplete())
return S_OK;
else
return E_UNAT_SEARCH_PENDING;
}

m_isSearched = TRUE;

if (InternalSearch(1, bUseDefaultGateway))
return S_OK;
else
return E_UNAT_UNKNOWN_ERROR;
}

HRESULT CUPnpNat::AddPortMapping(LPCTSTR lpszRemoteHost,
USHORT usExternalPort, LPCTSTR lpszPortMappingProtocol,
USHORT usInternalPort, LPCTSTR lpszInternalClient,
LPCTSTR lpszPortMappingDescription,
BOOL bPortMappingEnabled,
ULONG ulPortMappingLeaseDuration)
{
CString args;
CString strResponse;

args.Empty();
args.Append(GetArgString(_T("NewRemoteHost"), CString(lpszRemoteHost)));
args.Append(GetArgString(_T("NewExternalPort"), usExternalPort));
args.Append(GetArgString(_T("NewProtocol"), CString(lpszPortMappingProtocol)));
args.Append(GetArgString(_T("NewInternalPort"), usInternalPort));
args.Append(GetArgString(_T("NewInternalClient"), CString(lpszInternalClient)));
args.Append(GetArgString(_T("NewEnabled"), bPortMappingEnabled));
args.Append(GetArgString(_T("NewPortMappingDescription"), CString(lpszPortMappingDescription)));
args.Append(GetArgString(_T("NewLeaseDuration"), ulPortMappingLeaseDuration));

return InvokeCommand(_T("AddPortMapping"), args, strResponse);

}

HRESULT CUPnpNat::DeletePortMapping(LPCTSTR lpszRemoteHost,
USHORT usExternalPort,
LPCTSTR lpszPortMappingProtocol)
{
CString args;
CString strResponse;

args.Empty();
args.Append(GetArgString(_T("NewRemoteHost"), CString(lpszRemoteHost)));
args.Append(GetArgString(_T("NewExternalPort"), usExternalPort));
args.Append(GetArgString(_T("NewProtocol"), CString(lpszPortMappingProtocol)));

return InvokeCommand(_T("DeletePortMapping"), args, strResponse);
}
TypeCool 2011-03-20
  • 打赏
  • 举报
回复
你说是
CONST CHAR sData[] = "M-SEARCH * HTTP/1.1\nHOST: 239.255.255.250:1900\nMAN: \"ssdp:discover\"\nMX: 3\nST: upnp:rootdevice\n";
这个数据不对嘛?
可是有回应啊。
hurryboylqs 2011-03-20
  • 打赏
  • 举报
回复
我看了下你的HTTP数据都准备的不太对,我帖出代码来吧,也是电驴里抽出来的:

#pragma once
#include "UPnpError.h"
#include <atlbase.h>
#include <atlstr.h>

class CUPnpNat
{
public:
CUPnpNat(void);
~CUPnpNat(void);

enum {SEARCH_TIMEOUT_MS = 15000,
DEF_ACTION_TIMEOUT_MS = 9000};

void SetBindAddress(LPCTSTR lpszBindAddress){m_strBindAddress = lpszBindAddress;}
void SetActionTimeout(int iActionTimeoutMs = DEF_ACTION_TIMEOUT_MS){m_iActionTimeoutMs = iActionTimeoutMs;}
int GetActionTimeout(){return m_iActionTimeoutMs;}


HRESULT SearchDevice(BOOL bUseDefaultGateway = TRUE);


HRESULT AddPortMapping(LPCTSTR lpszRemoteHost,
USHORT usExternalPort, LPCTSTR lpszPortMappingProtocol,
USHORT usInternalPort, LPCTSTR lpszInternalClient,
LPCTSTR lpszPortMappingDescription = NULL,
BOOL bPortMappingEnabled = TRUE,
ULONG ulPortMappingLeaseDuration = 0);

HRESULT DeletePortMapping(LPCTSTR lpszRemoteHost,
USHORT usExternalPort,
LPCTSTR lpszPortMappingProtocol);


HRESULT GetSpecificPortMappingEntry(LPCTSTR lpszRemoteHost, //[in]
USHORT usExternalPort, //[in]
LPCTSTR lpszPortMappingProtocol, //[in]
USHORT *pusInternalPort, //[out]
CString *pstrInternalClient, //[out]
bool *pbEnable, //[out]
CString *pstrDescription, //[out]
ULONG *pulPortMappingLeaseDuration); //[out]


HRESULT GetGenericPortMappingEntry(USHORT usIndex, //[in]
CString *pstrRemoteHost, //[out]
USHORT *pusExternalPort, //[out]
CString *pstrProtocol, //[out]
USHORT *pusInternalPort, //[out]
CString *pstrInternalClient, //[out]
bool *pbEnable, //[out]
CString *pstrDescription); //[out]

DWORD GetLastActionErrorCode(){return m_dwLastErrorCode;}

protected:
void SetLastActionErrorCode(DWORD dwLastErrorCode){m_dwLastErrorCode = dwLastErrorCode;}

HRESULT SOAP_action(CString addr, UINT16 port, const CString request, CString &response);
int SSDP_sendRequest(SOCKET s, UINT32 ip, UINT16 port, const CString& request);

bool InternalSearch(int version, BOOL bUseDefaultGateway = FALSE);
bool GetDescription();
CString GetProperty(const CString& name, CString& response);
bool isComplete() const { return !m_controlurl.IsEmpty(); }
bool Valid()const{return (/*!m_name.IsEmpty()&&*/!m_description.IsEmpty());}

HRESULT InvokeCommand(const CString& name, const CString& args, CString &strResponse);

static BOOL IsLengthedHttpPacketComplete(const char *packet, int len);
protected:
CString m_strBindAddress;
int m_iActionTimeoutMs;

DWORD m_dwLastErrorCode;

BOOL m_isSearched;

int m_version;
CString m_devicename;
CString m_name;
CString m_description;
CString m_baseurl;
CString m_controlurl;
CString m_friendlyname;
CString m_modelname;

};
TypeCool 2011-03-20
  • 打赏
  • 举报
回复
要不你帮忙测试一下我的代码吧。贴上就能用,传个缓冲区给它就行了。
TypeCool 2011-03-20
  • 打赏
  • 举报
回复
没有发现设备,先解决这个问题吧。毕竟这是第一步。
就像我主贴上说的,我能发送 搜索请求 ,设备也回应了。但是在我的函数里却不能收到这个回应。
TypeCool 2011-03-20
  • 打赏
  • 举报
回复
Msock = WSAJoinLeaf(Ssock,(SOCKADDR *)&remote,sizeof(remote),NULL,NULL,NULL,NULL,JL_SENDER_ONLY);

这个JL_SENDER_ONLY旗标,我之前是用的JL_BOTH 收发兼并 ,没效果,收不到。后面换了套接字,这次发的时候忘记改了。
hurryboylqs 2011-03-20
  • 打赏
  • 举报
回复
你现在是哪步错了?没搜索到设备吗?还是在映射的时候失败了?
TypeCool 2011-03-20
  • 打赏
  • 举报
回复
电驴也是用的UPnP组件,我看了。我想知道用winsocke怎么做。要不我把我的 搜索-发现 函数发出来,你帮看看把。

#include "stdafx.h"

BOOL AddMCAST(CHAR * rData,INT len)
{
CONST CHAR sData[] = "M-SEARCH * HTTP/1.1\nHOST: 239.255.255.250:1900\nMAN: \"ssdp:discover\"\nMX: 3\nST: upnp:rootdevice\n";
CONST DWORD port = 1900;
CONST CHAR MCAST[] = "239.255.255.250";
WSAData wsaData;
SOCKET Ssock, Rsock, Msock;
INT loopback = 0,
on = 1;
sockaddr_in local,remote;

if( WSAStartup(MAKEWORD(2,0), &wsaData) != 0 )
return FALSE;

if ((Ssock = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0,
WSA_FLAG_MULTIPOINT_C_LEAF
| WSA_FLAG_MULTIPOINT_D_LEAF
| WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
WSACleanup();
return FALSE;
}
if ((Rsock = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
closesocket(Ssock);
WSACleanup();
return FALSE;
}
// 禁止回馈多播数据
if( setsockopt(Ssock,IPPROTO_IP,IP_MULTICAST_LOOP,(char *)&loopback,sizeof(loopback)) == SOCKET_ERROR )
{
closesocket(Ssock);
closesocket(Rsock);
WSACleanup();
return FALSE;
}
// 允许同一端口被多个套接字绑定
if (setsockopt(Ssock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) == SOCKET_ERROR )
{
closesocket(Ssock);
closesocket(Rsock);
WSACleanup();
return FALSE;
}
// 允许同一端口被多个套接字绑定
if (setsockopt(Rsock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) == SOCKET_ERROR )
{
closesocket(Ssock);
closesocket(Rsock);
WSACleanup();
return FALSE;
}
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(port); // 本地端口
local.sin_addr.S_un.S_addr = INADDR_ANY; // 本地全部地址
if( bind(Ssock, (sockaddr*)(&local), sizeof(local)) == SOCKET_ERROR )
{
closesocket(Ssock);
closesocket(Rsock);
WSACleanup();
return FALSE;
}
if( bind(Rsock, (sockaddr*)(&local), sizeof(local)) == SOCKET_ERROR )
{
closesocket(Ssock);
closesocket(Rsock);
WSACleanup();
return FALSE;
}
memset(&remote, 0, sizeof(remote));
remote.sin_family = AF_INET;
remote.sin_port = htons(port); // 多播端口
remote.sin_addr.S_un.S_addr = inet_addr(MCAST); // 多播地址
Msock = WSAJoinLeaf(Ssock,(SOCKADDR *)&remote,sizeof(remote),NULL,NULL,NULL,NULL,JL_SENDER_ONLY);
if(Msock == INVALID_SOCKET)
{
closesocket(Ssock);
closesocket(Rsock);
WSACleanup();
return FALSE;
}

// 探测 UPnP 设备

if( sendto(Msock, sData, strlen(sData), 0, (sockaddr*)(&remote), sizeof(sockaddr_in)) == SOCKET_ERROR )
{
closesocket(Msock);
closesocket(Ssock);
closesocket(Rsock);
WSACleanup();
return FALSE;
}
// 读取回馈
memset(rData, '\0', len);
// 我在上面多注册了一个UDP套接字Rsock,我分别用这两个套接字来接受回馈,都失败了。
if( recv(Msock, rData, len, 0) == SOCKET_ERROR )
{
closesocket(Msock);
closesocket(Ssock);
closesocket(Rsock);
WSACleanup();
return FALSE;
}
closesocket(Msock);
closesocket(Ssock);
closesocket(Rsock);
WSACleanup();
return TRUE;
}
加载更多回复(6)

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧