Beispiel #1
0
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__);
    }
}
Beispiel #2
0
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);
}
Beispiel #3
0
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;
}