📄 upnpnat.cpp
字号:
/* get the baseURL of the device */ if((baseURLNode = xmlnode_get_child(xmlRootNode, "URLBase")) != NULL) { baseURL = g_strdup(xmlnode_get_data(baseURLNode)); } else { baseURL = g_strdup(httpURL); } /* get the serviceType child that has the service type as it's data */ /* get urn:schemas-upnp-org:device:InternetGatewayDevice:1 and it's devicelist */ serviceTypeNode = xmlnode_get_child(xmlRootNode, "device"); while(serviceTypeNode != NULL && !compareDevice(serviceTypeNode, "urn:schemas-upnp-org:device:InternetGatewayDevice:1")) { serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode); } if(serviceTypeNode == NULL) { return false; } serviceTypeNode = xmlnode_get_child(serviceTypeNode, "deviceList"); if(serviceTypeNode == NULL) { return false; } /* get urn:schemas-upnp-org:device:WANDevice:1 and it's devicelist */ serviceTypeNode = xmlnode_get_child(serviceTypeNode, "device"); while(serviceTypeNode != NULL && !compareDevice(serviceTypeNode, "urn:schemas-upnp-org:device:WANDevice:1")) { serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode); } if(serviceTypeNode == NULL) { return false; } serviceTypeNode = xmlnode_get_child(serviceTypeNode, "deviceList"); if(serviceTypeNode == NULL) { return false; } /* get urn:schemas-upnp-org:device:WANConnectionDevice:1 and it's servicelist */ serviceTypeNode = xmlnode_get_child(serviceTypeNode, "device"); while(serviceTypeNode != NULL && !compareDevice(serviceTypeNode, "urn:schemas-upnp-org:device:WANConnectionDevice:1")) { serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode); } if(serviceTypeNode == NULL) { return false; } serviceTypeNode = xmlnode_get_child(serviceTypeNode, "serviceList"); if(serviceTypeNode == NULL) { return false; } /* get the serviceType variable passed to this function */ service = g_strdup_printf(SEARCH_REQUEST_DEVICE, serviceType); serviceTypeNode = xmlnode_get_child(serviceTypeNode, "service"); while(serviceTypeNode != NULL && !compareService(serviceTypeNode, service)) { serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode); } g_free(service); if(serviceTypeNode == NULL) { return false; } /* get the controlURL of the service */ if((controlURLNode = xmlnode_get_child(serviceTypeNode, "controlURL")) == NULL) { return false; } if(g_strstr_len(xmlnode_get_data(controlURLNode), SIZEOF_HTTP, "http://") == NULL && g_strstr_len(xmlnode_get_data(controlURLNode), SIZEOF_HTTP, "HTTP://") == NULL) { controlURL = g_strdup_printf("%s%s", baseURL, xmlnode_get_data(controlURLNode)); }else{ controlURL = g_strdup(xmlnode_get_data(controlURLNode)); } if(_eventHandler != NULL) { _eventHandler->OnGetControlUrl(controlURL, serviceType); } return true;}bool CUPnpNatDescriptionParser::compareService(xmlnode* service, const char* serviceType){ xmlnode* serviceTypeNode = xmlnode_get_child(service, "serviceType"); if(serviceTypeNode == NULL) { return FALSE; } return !g_ascii_strcasecmp(xmlnode_get_data(serviceTypeNode), serviceType); }bool CUPnpNatDescriptionParser::compareDevice(xmlnode* device, const char* deviceType){ xmlnode* deviceTypeNode = xmlnode_get_child(device, "deviceType"); if(deviceTypeNode == NULL) { return FALSE; } return !g_ascii_strcasecmp(xmlnode_get_data(deviceTypeNode), deviceType); }TDescriptionParserState CUPnpNatDescriptionParser::getState(){ return _state;}const char* CPnpNatController::ActionAdd = "AddPortMapping";const char* CPnpNatController::ActionDelete = "DeletePortMapping";CPnpNatController::CPnpNatController(): _reactor(NULL), _state(CS_INIT){}CPnpNatController::~CPnpNatController(){}void CPnpNatController::setSocketReactor(ISocketReactor* reactor){ _reactor = reactor;}void CPnpNatController::setControlUrl(const char*controlUrl, const char* service){ _controlUrl = controlUrl; _service = service;}void CPnpNatController::setAction(const char* action, unsigned short port, const char* protocol){ _actionName = action; _port = port; _protocol = protocol; }void CPnpNatController::start(){ std::string ip; std::string path; unsigned short port; parseUrl(_controlUrl.c_str(), ip, &port, path); _state = CS_WORKING; CSocket::createTCPSocket(); CSocket::setReactor(_reactor); CSocket::maskWrite(true); CSocket::connect(ip.c_str(), port); _timeoutTimerID = _reactor->addTimer(this, 5000, true);}void CPnpNatController::stop(){ LOG_DEBUG("CPnpNatController stopping"); if(_timeoutTimerID != 0 && _reactor != NULL) { _reactor->removeTimer(_timeoutTimerID); _timeoutTimerID = 0; } CSocket::setReactor(NULL); CSocket::close(); LOG_DEBUG("CPnpNatController stoped");}TControllerState CPnpNatController::getState(){ return _state;}int CPnpNatController::handleRead(){ char buffer[1024]; for(;;) { int ret = recv(getHandle(), buffer, sizeof(buffer), 0); LOG_DEBUG("recv return "<<ret); if(ret == 0) { maskRead(false); return -1; } if(ret == -1) { if(errno == EINTR) { continue; } if(errno != EAGAIN) { maskRead(false); return -1; } break; } if(ret > 0) { _recvBuffer.append(buffer, ret); } } return 0; }int CPnpNatController::handleWrite(){ //get local ip from socket handle struct sockaddr_in addr; socklen_t len = sizeof(addr); getsockname(getHandle(), (struct sockaddr*)&addr, &len); _localIP = inet_ntoa(addr.sin_addr); LOG_DEBUG("localIP="<<_localIP); sendRequest(); maskWrite(false); return 0;}void CPnpNatController::handleClose(){ if(_recvBuffer.find(HTTP_OK) != _recvBuffer.npos) { _state = CS_OK; LOG_DEBUG("port mapping ok"); } else { _state = CS_ERROR; LOG_DEBUG("port mapping error"); } CSocket::setReactor(NULL); CSocket::close();}void CPnpNatController::onTimer(unsigned int id){ if(id == _timeoutTimerID && _state == CS_WORKING) { handleClose(); _timeoutTimerID = 0; }}void CPnpNatController::sendRequest(){ gchar* actionParams = g_strdup_printf(ADD_PORT_MAPPING_PARAMS, _port, _protocol.c_str(), _port, _localIP.c_str()); gchar* soapMessage = g_strdup_printf(SOAP_ACTION, _actionName.c_str(), _service.c_str(), actionParams, _actionName.c_str()); std::string ip; std::string path; unsigned short port; parseUrl(_controlUrl.c_str(), ip, &port, path); gchar* addressPortOfControl = g_strdup_printf("%s:%u", ip.c_str(), port); gchar* actionMessage = g_strdup_printf(HTTP_HEADER_ACTION, path.c_str(), addressPortOfControl, _service.c_str(), _actionName.c_str(), strlen(soapMessage)); gchar* totalSendMessage = g_strdup_printf("%s%s", actionMessage, soapMessage); int ret = send(getHandle(), totalSendMessage, strlen(totalSendMessage), 0); LOG_DEBUG("msg len="<<strlen(totalSendMessage)<<" send return "<<ret); LOG_DEBUG("totalSendMessage = \n"<<totalSendMessage); g_free(actionParams); g_free(soapMessage); g_free(addressPortOfControl); g_free(actionMessage); g_free(totalSendMessage); maskRead(true); }CUPnpNat::CUPnpNat(): _reactor(NULL), _state(NS_INIT), _discoverTimerID(0), _controlTimerID(0){}CUPnpNat::~CUPnpNat(){}void CUPnpNat::setReactor(ISocketReactor* reactor){ _reactor = reactor;}void CUPnpNat::start(){ _state = NS_DISCOVER; _natExplorer.setSocketReactor(_reactor); _natExplorer.setEventHandler(this); _natExplorer.start(); _discoverTimerID = _reactor->addTimer(this, 10000, true); _controlTimerID = _reactor->addTimer(this, 2000, false);}void CUPnpNat::stop(){ if(_discoverTimerID != 0) { _reactor->removeTimer(_discoverTimerID); _discoverTimerID = 0; } if(_controlTimerID != 0) { _reactor->removeTimer(_controlTimerID); _controlTimerID = 0; } _natExplorer.stop(); _natParser.stop(); TNatPortInfoList::iterator iter = _portList.begin(); for(; iter!=_portList.end(); ++iter) { if(iter->controller != NULL) { iter->controller->stop(); delete iter->controller; iter->controller = NULL; } } _portList.clear();}TUPnpNATState CUPnpNat::getState(){ return _state;}void CUPnpNat::addPortMapping(unsigned int port,const char* protocol){ TNatPortInfo info; info.port = port; info.protocol = protocol; if(_state != NS_OK) { info.controller = NULL; } else { info.controller = new CPnpNatController(); info.controller->setSocketReactor(_reactor); info.controller->setControlUrl(_controlUrl.c_str(), _service.c_str()); info.controller->setAction(CPnpNatController::ActionAdd, port, protocol); info.controller->start(); } _portList.push_back(info);}void CUPnpNat::removePortMapping(unsigned int port,const char* protocol){}void CUPnpNat::onTimer(unsigned int id){ if(id == _discoverTimerID) { if(_state == NS_OK) { _discoverTimerID = 0; } else { LOG_INFO("NAT discover timeout"); _natExplorer.stop(); start(); } } if(id == _controlTimerID) { if(_state == NS_OK) { TNatPortInfoList::iterator iter = _portList.begin(); for(; iter!=_portList.end(); ++iter) { if(iter->controller == NULL) { iter->controller = new CPnpNatController(); iter->controller->setSocketReactor(_reactor); iter->controller->setControlUrl(_controlUrl.c_str(), _service.c_str()); iter->controller->setAction(CPnpNatController::ActionAdd, iter->port, iter->protocol.c_str()); iter->controller->start(); } } } }}void CUPnpNat::OnGetDescriptionUrl(const char* url){ LOG_DEBUG("CUPnpNat::OnGetDescriptionUrl, url="<<url); if(_state == NS_GETDESCRIPTION) { return; } _state = NS_GETDESCRIPTION; _natParser.stop(); _natParser.setSocketReactor(_reactor); _natParser.setEventHandler(this); _natParser.setDescriptionUrl(url); _natParser.start();}void CUPnpNat::OnGetControlUrl(const char* controlUrl, const char* service){ LOG_DEBUG("controlUrl="<<controlUrl<<" service="<<service); _controlUrl = controlUrl; _service = service; _state = NS_OK;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -