void UPnP::processPacket(BaseLib::Http& http) { try { BaseLib::Http::Header& header = http.getHeader(); if(header.method != "M-SEARCH" || header.fields.find("st") == header.fields.end() || header.host.empty()) return; BaseLib::HelperFunctions::toLower(header.fields.at("st")); if(header.fields.at("st") == "urn:schemas-upnp-org:device:basic:1" || header.fields.at("st") == "urn:schemas-upnp-org:device:basic:1.0" || header.fields.at("st") == "ssdp:all" || header.fields.at("st") == "upnp:rootdevice" || header.fields.at("st") == _st) { if(GD::bl->debugLevel >= 5) _out.printDebug("Debug: Discovery packet received from " + header.host); std::pair<std::string, std::string> address = BaseLib::HelperFunctions::splitLast(header.host, ':'); int32_t port = BaseLib::Math::getNumber(address.second, false); if(!address.first.empty() && port > 0) { int32_t mx = 500; if(header.fields.find("mx") != header.fields.end()) mx = BaseLib::Math::getNumber(header.fields.at("mx"), false) * 1000; std::this_thread::sleep_for(std::chrono::milliseconds(20)); //Wait for 0 to mx seconds for load balancing if(mx > 500) { mx = BaseLib::HelperFunctions::getRandomNumber(0, mx - 500); GD::out.printDebug("Debug: Sleeping " + std::to_string(mx) + "ms before sending response."); std::this_thread::sleep_for(std::chrono::milliseconds(mx)); } sendOK(address.first, port, header.fields.at("st") == "upnp:rootdevice"); std::this_thread::sleep_for(std::chrono::milliseconds(100)); sendNotify(); } } } catch(const std::exception& ex) { _out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); } catch(BaseLib::Exception& ex) { _out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); } catch(...) { _out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); } }
void UPnP::listen() { try { getSocketDescriptor(); _out.printInfo("Info: Started listening."); _lastAdvertisement = BaseLib::HelperFunctions::getTimeSeconds(); char buffer[1024]; int32_t bytesReceived = 0; struct sockaddr_in si_other; socklen_t slen = sizeof(si_other); fd_set readFileDescriptor; timeval timeout; int32_t nfds = 0; BaseLib::Http http; while(!_stopServer) { try { if(!_serverSocketDescriptor || _serverSocketDescriptor->descriptor == -1) { if(_stopServer) break; std::this_thread::sleep_for(std::chrono::milliseconds(5000)); getSocketDescriptor(); continue; } timeout.tv_sec = 0; timeout.tv_usec = 100000; FD_ZERO(&readFileDescriptor); { auto fileDescriptorGuard = GD::bl->fileDescriptorManager.getLock(); fileDescriptorGuard.lock(); nfds = _serverSocketDescriptor->descriptor + 1; if(nfds <= 0) { fileDescriptorGuard.unlock(); _out.printError("Error: Socket closed (1)."); GD::bl->fileDescriptorManager.shutdown(_serverSocketDescriptor); } FD_SET(_serverSocketDescriptor->descriptor, &readFileDescriptor); } bytesReceived = select(nfds, &readFileDescriptor, NULL, NULL, &timeout); if(bytesReceived == 0) { if(BaseLib::HelperFunctions::getTimeSeconds() - _lastAdvertisement >= 60) sendNotify(); continue; } if(bytesReceived != 1) { _out.printError("Error: Socket closed (2)."); GD::bl->fileDescriptorManager.shutdown(_serverSocketDescriptor); } bytesReceived = recvfrom(_serverSocketDescriptor->descriptor, buffer, 1024, 0, (struct sockaddr *)&si_other, &slen); if(bytesReceived <= 0) continue; http.reset(); http.process(buffer, bytesReceived, false); if(http.isFinished()) processPacket(http); } catch(const std::exception& ex) { _out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); } catch(BaseLib::Exception& ex) { _out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); } catch(...) { _out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); } } } catch(const std::exception& ex) { _out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); } catch(BaseLib::Exception& ex) { _out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); } catch(...) { _out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); } GD::bl->fileDescriptorManager.shutdown(_serverSocketDescriptor); }
bool Auth::basicServer(BaseLib::Http& httpPacket) { if(!_initialized) throw AuthException("Not initialized."); _http.reset(); uint32_t bufferLength = 1024; char buffer[bufferLength + 1]; if(httpPacket.getHeader().authorization.empty()) { if(_basicAuthHTTPHeader.empty()) { _basicAuthHTTPHeader.append("HTTP/1.1 401 Authorization Required\r\n"); _basicAuthHTTPHeader.append("WWW-Authenticate: Basic realm=\"Authentication Required\"\r\n"); _basicAuthHTTPHeader.append("Connection: Keep-Alive\r\n"); std::string content("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\"><html><head><meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"><title>Authorization Required</title></head><body>Authorization Required</body></html>"); _basicAuthHTTPHeader.append("Content-Length: " + std::to_string(content.size()) + "\r\n\r\n"); _basicAuthHTTPHeader.append(content); } std::shared_ptr<std::vector<char>> data(new std::vector<char>()); data->insert(data->begin(), _basicAuthHTTPHeader.begin(), _basicAuthHTTPHeader.end()); try { _socket->proofwrite(data); int32_t bytesRead = _socket->proofread(buffer, bufferLength); //Some clients send only one byte in the first packet if(bytesRead == 1) bytesRead += _socket->proofread(&buffer[1], bufferLength - 1); buffer[bytesRead] = '\0'; try { _http.process(buffer, bufferLength); } catch(BaseLib::HttpException& ex) { throw AuthException("Authorization failed because of HTTP exception: " + ex.what()); } } catch(const BaseLib::SocketOperationException& ex) { throw AuthException("Authorization failed because of socket exception: " + ex.what()); } } else _http = httpPacket; if(_http.getHeader().authorization.empty()) { sendBasicUnauthorized(false); throw AuthException("No header field \"Authorization\""); } std::pair<std::string, std::string> authData = BaseLib::HelperFunctions::splitLast(_http.getHeader().authorization, ' '); BaseLib::HelperFunctions::toLower(authData.first); if(authData.first != "basic") { sendBasicUnauthorized(false); throw AuthException("Authorization type is not basic but: " + authData.first); } std::string decodedData; BaseLib::Base64::decode(authData.second, decodedData); std::pair<std::string, std::string> credentials = BaseLib::HelperFunctions::splitLast(decodedData, ':'); BaseLib::HelperFunctions::toLower(credentials.first); if(std::find(_validUsers.begin(), _validUsers.end(), credentials.first) == _validUsers.end()) { sendBasicUnauthorized(false); throw AuthException("User name " + credentials.first + " is not in the list of valid users in /etc/homegear/rpcservers.conf."); } if(User::verify(credentials.first, credentials.second)) return true; sendBasicUnauthorized(false); return false; }