예제 #1
0
/// 
/// Run when new connection is accepted
/// 
/// @param memory_pool_ptr shared pointer to the allocated memory poll for connections
/// @param i_connect index of current connection in memory pool 
/// @param e reference to error object
///
void T_server::handle_accept( T_memory_pool_ptr memory_pool_ptr, size_t i_connect, const boost::system::error_code& e) {
	try {
		if (!e) {
			std::cout << "handle_accept() \n";
			// get pointer of current connection
			T_connection * const current_memory_pool_raw_ptr = reinterpret_cast<T_connection *>( memory_pool_ptr.get() );
			T_connection * const current_connection_raw_ptr = &(current_memory_pool_raw_ptr[i_connect]);
			T_connection::T_shared_this current_connection_ptr(memory_pool_ptr, current_connection_raw_ptr );

			// schedule new task to thread pool
			current_connection_raw_ptr->run(boost::move(current_connection_ptr));	// sync launch of short-task: run()

			// increment index of connections
			++i_connect;	
		
			// if the limit of connections in the memory pool have been reached, then create a new memory pool
			if(i_connect == connections_in_memory_pool) {
				i_connect = 0;
				memory_pool_ptr.reset(new T_memory_pool, T_memory_pool_deleter() );
			}

			// create next connection, that will accepted
			T_connection * const new_memory_pool_raw_ptr = reinterpret_cast<T_connection *>( memory_pool_ptr.get() );
			T_connection * const new_connection_raw_ptr = 
				T_connection::create(file_name_, new_memory_pool_raw_ptr, i_connect, io_service_executors_, timeout_);

			// start new accept operation		
			acceptor_.async_accept(new_connection_raw_ptr->socket(),
									new_connection_raw_ptr->client_bind(
											   boost::bind(&T_server::handle_accept, this, 
														   boost::move(memory_pool_ptr),   // doesn't copy and doesn't use the atomic counter with memory barrier
														   i_connect,
														   ba::placeholders::error)) );
		}
	} catch(const seh::T_seh_exception& e) {
		std::cerr << "T_seh_exception: " << e.what() << "\n ->throw place: " << THROW_PLACE << std::endl;
	} catch(const bs::system_error& e) {
		std::cerr << "Boost system_error exception: " << e.what() << "\n ->throw place: " << THROW_PLACE << std::endl;
	} catch(const std::exception &e) {
		std::cerr << "Exception: " << e.what() << "\n ->throw place: " << THROW_PLACE << std::endl;
	} catch(...) {
		std::cerr << "Unknown exception!" << "\n ->throw place: " << THROW_PLACE << std::endl;
	}	
}
예제 #2
0
void Connection::handle_read(const boost::system::error_code& e, size_t bytes_transferred,
                                    boost::tuple<ErrorHandler,Handler> handler, boost::shared_ptr<Connection> conn)

{
    try
    {
        if (e)
        {
            boost::get<0>(handler)(e);
        }
        else
        {
            int originalSize = inbound_data_.size();
            inbound_data_.resize(originalSize + bytes_transferred);
            int buffSize = originalSize + bytes_transferred;
            std::cout << originalSize << "+" << bytes_transferred << "=" << buffSize << std::endl;
            std::memcpy(&inbound_data_[originalSize],&inbound_buffer_[0],bytes_transferred);
            while(buffSize>=HEADER_SIZE) { // this means we have at least a header in our buffer
                int sz = inbound_data_[3];
                sz = (sz << 8) | inbound_data_[2];
                sz = (sz << 8) | inbound_data_[1];
                sz = (sz << 8) | inbound_data_[0];
                if(buffSize>=HEADER_SIZE+sz) { // we have a full message to parse!
                    std::string archive_data(&inbound_data_[HEADER_SIZE], sz);
                    Json::Value value;
                    std::cout << archive_data << std::endl;
                    if(reader.parse(archive_data,value))
                    {
                        boost::get<1>(handler)(value);
                    }
                    if(HEADER_SIZE+sz<buffSize) {
                        std::copy(&inbound_data_[HEADER_SIZE+sz],&inbound_data_[buffSize],&inbound_data_[0]);
                        buffSize-=HEADER_SIZE+sz;
                    } else {
                        inbound_data_.clear();
                        buffSize = 0;
                    }
                    inbound_buffer_.resize(4);
                } else {
                    inbound_buffer_.resize(sz);
                }
            }
            std::cout << "async read again: " << inbound_buffer_.size() << std::endl;
            boost::asio::async_read(socket_, boost::asio::buffer(inbound_buffer_),
                            boost::bind(&Connection::handle_read,
                                        this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred,
                                        handler,conn));
        }
    }
    catch(std::exception& e)
    {
        std::cout << "Connection::handle_read_header: " << e.what() << std::endl;
    }
}
예제 #3
0
파일: server.cpp 프로젝트: mdolz/PMLib
void Server::accept_handler(socket_ptr _sock, const boost::system::error_code& e) {
    if ( !e ) {
        try {
            boost::thread(boost::bind( &Server::connection, this, _sock));
            //thread( &Server::connection, this, _sock);
        }
        catch(exception& e) {
            CLOG_ERROR << "Exception: " << e.what() << endl;
        }
    }
    async_accept();
}
예제 #4
0
		void RpcSessionNetHandler::sessionReadError( JMEngine::net::TcpSession::TcpSessionPtr session, boost::system::error_code e )
		{
			try
			{
				session->stop();

				LOGW("Rpc client from [ %s:%s ] disconnected", session->getIp(), session->getPort());
			}
			catch(boost::system::system_error e)
			{
				LOGE("error ==> [ %d:%s ]", e.code().value(), e.what());
			}
		}
예제 #5
0
    void PeerManager::callback(const boost::system::error_code &e)
    {
        try {
            uint32_t minPeers = std::stoi(m_ctx.getDatabase()->getConfigValue("min_peers"));
            uint32_t numPeers = m_ctx.getOutMsgDisp().getTransport()->numPeers();

            I2P_LOG(m_log, debug) << "current number of peers: " << numPeers;
            I2P_LOG(m_log, debug) << boost::log::add_value("peers", (uint32_t) numPeers);
            int32_t gap = minPeers - numPeers;
            for(int32_t i = 0; i < gap; i++)
                m_ctx.getOutMsgDisp().getTransport()->connect(m_ctx.getProfileManager().getPeer());

        } catch(std::exception &e) {
                I2P_LOG(m_log, error) << "exception in PeerManager: " << e.what();
        }
        if ( ! m_graceful ) {
            m_timer.expires_at(m_timer.expires_at() + boost::posix_time::time_duration(0, 0, 10));
            m_timer.async_wait(boost::bind(&PeerManager::callback, this, boost::asio::placeholders::error));
        }
    }
예제 #6
0
////////////////////////////////////////////////////////////////////////////////
/// This is the main communication engine.
///
/// @IO
///     At every timestep, a message is sent to the FPGA via TCP socket
///     connection, then a message is retrieved from FPGA via the same
///     connection.  On the FPGA side, it's the reverse order -- receive and
///     then send.  Both DGI and FPGA receive functions will block until a
///     message arrives, creating a synchronous, lock-step communication between
///     DGI and the FPGA. We keep the timestep (a static member of CRtdsAdapter)
///     very small so that how frequently send and receive get executed is
///     dependent on how fast the FPGA runs.
///
/// @Error_Handling
///     Throws std::runtime_error if reading from or writing to socket fails.
///
/// @pre Connection with FPGA is established.
///
/// @post All values in the receive buffer are sent to the FPGA.  All values in
/// the send buffer are updated with data from the FPGA.
///
/// @limitations This function uses synchronous communication.
////////////////////////////////////////////////////////////////////////////////
void CRtdsAdapter::Run(const boost::system::error_code & e)
{
    Logger.Trace << __PRETTY_FUNCTION__ << std::endl;

    if( e )
    {
        if (e == boost::asio::error::operation_aborted)
        {
            return;
        }
        else
        {
            Logger.Fatal << "Run called with error: " << e.message()
                    << std::endl;
            throw boost::system::system_error(e);
        }
    }

    // Always send data to FPGA first
    if( !m_txBuffer.empty() )
    {
        boost::unique_lock<boost::shared_mutex> writeLock(m_txMutex);
        Logger.Debug << "Obtained the txBuffer mutex." << std::endl;

        EndianSwapIfNeeded(m_txBuffer);
        try
        {
            Logger.Debug << "Blocking for a socket write call." << std::endl;
            TimedWrite(m_socket, boost::asio::buffer(m_txBuffer,
                    m_txBuffer.size() * sizeof(SignalValue)),
                    CTimings::Get("DEV_SOCKET_TIMEOUT"));

        }
        catch(boost::system::system_error & e)
        {
            Logger.Fatal << "Send to FPGA failed: " << e.what();
            throw;
        }
        EndianSwapIfNeeded(m_txBuffer);

        Logger.Debug << "Releasing the txBuffer mutex." << std::endl;
    }

    // Receive data from FPGA next
    if( !m_rxBuffer.empty() )
    {
        // must be a unique_lock for endian swaps
        boost::unique_lock<boost::shared_mutex> writeLock(m_rxMutex);
        Logger.Debug << "Obtained the rxBuffer mutex." << std::endl;

        try
        {
            Logger.Debug << "Blocking for a socket read call." << std::endl;
            TimedRead(m_socket, boost::asio::buffer(m_rxBuffer,
                    m_rxBuffer.size() * sizeof(SignalValue)),
                    CTimings::Get("DEV_SOCKET_TIMEOUT"));
        }
        catch (boost::system::system_error & e)
        {
            Logger.Fatal << "Receive from FPGA failed: " << e.what();
            throw;
        }
        EndianSwapIfNeeded(m_rxBuffer);

        if( m_buffer_initialized == false )
        {
            m_buffer_initialized = true;

            for( unsigned int i = 0; i < m_rxBuffer.size(); i++ )
            {
                if( m_rxBuffer[i] == NULL_COMMAND )
                {
                    m_buffer_initialized = false;
                }
            }
            if( m_buffer_initialized )
            {
                Logger.Status << "Clientdata : " <<m_rxBuffer[0]<< std::endl;

                RevealDevices();
            }
        }

        Logger.Debug << "Releasing the rxBuffer mutex." << std::endl;
    }

    // Start the timer; on timeout, this function is called again
    m_runTimer.expires_from_now(
    boost::posix_time::milliseconds(CTimings::Get("DEV_RTDS_DELAY")));
    m_runTimer.async_wait(boost::bind(&CRtdsAdapter::Run, shared_from_this(),
            boost::asio::placeholders::error));
}
void handler(const boost::system::error_code& e, std::size_t size)
{
	sensor_msgs::Imu imu;
	tf::Quaternion q;
	//using namespace serialization;
	namespace mt = ros::message_traits;
	

	if (!e)
	{
		std::istream is(&b);
		std::string line;
		std::getline(is, line);
	//	cout <<"read:"<<size<<"###"<< line << endl;
		
		std::list<std::string> stringList;
		std::vector<std::string> list2;
		//boost::iter_split(stringList, line, boost::first_finder(","));
		try
		{ 
			boost::iter_split(list2, line, boost::first_finder(","));
		}
		catch (...)
		{

			cout << "bad" << endl;
			return;
		}

		if (list2.size() >= 6)
		{
			try
			{
				cout << "x:" << list2.at(4) << "\ty:" << list2.at(5) << "\tz:" << list2.at(6) << endl;
				cout << "gx:" << list2.at(8) << "\tgy:" << list2.at(9) << "\tgz:" << list2.at(10) << endl;

			/*	auto q= tf::createQuaternionFromRPY(boost::lexical_cast<double>(list2.at(8)), boost::lexical_cast<double>(list2.at(9)),
					boost::lexical_cast<double>(list2.at(10)));
			*/
				imu.orientation = tf::createQuaternionMsgFromRollPitchYaw(boost::lexical_cast<double>(list2.at(8)), boost::lexical_cast<double>(list2.at(9)),
					boost::lexical_cast<double>(list2.at(10)));
				
			/*	imu.orientation.x = q.x();
				imu.orientation.y = q.y();
				imu.orientation.z = q.z();
				imu.orientation.w = q.w();*/
				

				imu.linear_acceleration.x = boost::lexical_cast<double>(list2.at(4));
				imu.linear_acceleration.y = boost::lexical_cast<double>(list2.at(5));
				imu.linear_acceleration.z = boost::lexical_cast<double>(list2.at(6));




				//ROS_ASSERT_MSG(impl_->md5sum_ == "*" || std::string(mt::md5sum<M>(*message)) == "*" || impl_->md5sum_ == mt::md5sum<M>(*message),
					
				
			//	printf("Trying to publish message of type [%s/%s] on a publisher with type [%s/%s]",
				//	mt::datatype<sensor_msgs::Imu>(*imu), mt::md5sum<sensor_msgs::Imu>(*message),
//					imu.datatype_.c_str(), impl_->md5sum_.c_str());

			
		//		imu_pub.publish(imu);


			}
			catch (exception &e)
			{
				cout << "***" << e.what() << "***" << endl;
				cout << "---->" << line << endl;
				cout << "boom size:" << list2.size() << " line:"<<line<< " insize:"<<size<<endl;
				
			}
		}
		
		/*BOOST_FOREACH(std::string token, stringList)
		{
			std::cout << token << '\n'; ;
		}
*/


	}
}
예제 #8
0
void swd::connection::handle_read(const boost::system::error_code& e,
 std::size_t bytes_transferred) {
	/**
	 * If an error occurs then no new asynchronous operations are started. This
	 * means that all shared_ptr references to the connection object will disappear
	 * and the object will be destroyed automatically after this handler returns.
	 * The connection class's destructor closes the socket.
	 */
	if (e) {
		return;
	}

	/**
	 * Since there was no error we can start parsing the input now. The parser
	 * fills the object request_ with data.
	 */
	boost::tribool result;
	boost::tie(result, boost::tuples::ignore) =
		request_parser_.parse(
			request_,
			buffer_.data(),
			buffer_.data() + bytes_transferred
		);

	/**
	 * If result is true the complete request is parsed. If it is false there was
	 * an error. If it is indeterminate then the parsing is not complete yet and
	 * the program will read more input and append it to the old request_ object.
	 */
	if (indeterminate(result)) {
		/* Not finished yet with this request, start reading again. */
		this->start_read();

		/* And don't process the input yet. */
		return;
	}

	/* The handler used to process the reply. */
	swd::reply_handler reply_handler(reply_);

	try {
		if (!result) {
			swd::log::i()->send(swd::warning, "Bad request from "
			 + remote_address_.to_string());
			throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST);
		}

		/* Try to add a profile for the request. */
		try {
			swd::profile_ptr profile = swd::database::i()->get_profile(
				remote_address_.to_string(),
				request_->get_profile_id()
			);

			request_->set_profile(profile);
		} catch (swd::exceptions::database_exception& e) {
			swd::log::i()->send(swd::uncritical_error, e.what());
			throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST);
		}

		/* The handler used to process the incoming request. */
		swd::request_handler request_handler(request_);

		/* Only continue processing the reply if it is signed correctly. */
		if (!request_handler.valid_signature()) {
			swd::log::i()->send(swd::warning, "Bad signature from "
			 + remote_address_.to_string());
			throw swd::exceptions::connection_exception(STATUS_BAD_SIGNATURE);
		}

		/**
		 * Before the request can be processed the input has to be transfered
		 * from the encoded json string to a swd::parameters list.
		 */
		if (!request_handler.decode()) {
			swd::log::i()->send(swd::warning, "Bad json from "
			 + remote_address_.to_string());
			throw swd::exceptions::connection_exception(STATUS_BAD_JSON);
		}

		/* Process the request. */
		std::vector<std::string> threats;

		try {
			if (swd::database::i()->is_flooding(request_->get_client_ip(), request_->get_profile_id())) {
				throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST);
			}

			threats = request_handler.process();
		} catch (swd::exceptions::database_exception& e) {
			swd::log::i()->send(swd::uncritical_error, e.what());

			/**
			 * Problems with the database result in a bad request. If protection
			 * is enabled access to the site will not be granted.
			 */
			throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST);
		}

		if (!threats.empty()) {
			reply_->set_threats(threats);
			reply_->set_status(STATUS_ATTACK);
		} else {
			reply_->set_status(STATUS_OK);
		}
	} catch(swd::exceptions::connection_exception& e) {
		reply_->set_status(e.code());
	}

	/* Encode the reply. */
	reply_handler.encode();

	/* Send the answer to the client. */
	if (ssl_) {
		boost::asio::async_write(
			ssl_socket_,
			reply_->to_buffers(),
			strand_.wrap(
				boost::bind(
					&connection::handle_write,
					shared_from_this(),
					boost::asio::placeholders::error
				)
			)
		);
	} else {
		boost::asio::async_write(
			socket_,
			reply_->to_buffers(),
			strand_.wrap(
				boost::bind(
					&connection::handle_write,
					shared_from_this(),
					boost::asio::placeholders::error
				)
			)
		);
	}
}
void server_session::handle_read_handshake(const boost::system::error_code& e,
	                                       std::size_t bytes_transferred) {
	std::ostringstream line;
	line << &m_buf;
	m_raw_client_handshake += line.str();
	
	access_log(m_raw_client_handshake,ALOG_HANDSHAKE);
	
	std::vector<std::string> tokens;
	std::string::size_type start = 0;
	std::string::size_type end;
	
	// Get request and parse headers
	end = m_raw_client_handshake.find("\r\n",start);
	
	while(end != std::string::npos) {
		tokens.push_back(m_raw_client_handshake.substr(start, end - start));
		
		start = end + 2;
		
		end = m_raw_client_handshake.find("\r\n",start);
	}

	for (size_t i = 0; i < tokens.size(); i++) {
		if (i == 0) {
			m_client_http_request = tokens[i];
		}
		
		end = tokens[i].find(": ",0);
		
		if (end != std::string::npos) {
			std::string h = tokens[i].substr(0,end);

			if (get_client_header(h) == "") {
				m_client_headers[h] = tokens[i].substr(end+2);
			} else {
				m_client_headers[h] += ", " + tokens[i].substr(end+2);
			}
		}
	}
	
	// handshake error checking
	try {
		std::stringstream err;
		std::string h;
		
		// check the method
		if (m_client_http_request.substr(0,4) != "GET ") {
			err << "Websocket handshake has invalid method: "
				<< m_client_http_request.substr(0,4);
			
			throw(handshake_error(err.str(),400));
		}
		
		// check the HTTP version
		// TODO: allow versions greater than 1.1
		end = m_client_http_request.find(" HTTP/1.1",4);
		if (end == std::string::npos) {
			err << "Websocket handshake has invalid HTTP version";
			throw(handshake_error(err.str(),400));
		}
		
		m_resource = m_client_http_request.substr(4,end-4);
		
		// verify the presence of required headers
		h = get_client_header("Host");
		if (h == "") {
			throw(handshake_error("Required Host header is missing",400));
		} else if (!m_server->validate_host(h)) {
			err << "Host " << h << " is not one of this server's names.";
			throw(handshake_error(err.str(),400));
		}
		
		h = get_client_header("Upgrade");
		if (h == "") {
			throw(handshake_error("Required Upgrade header is missing",400));
		} else if (!boost::iequals(h,"websocket")) {
			err << "Upgrade header was " << h << " instead of \"websocket\"";
			throw(handshake_error(err.str(),400));
		}
		
		h = get_client_header("Connection");
		if (h == "") {
			throw(handshake_error("Required Connection header is missing",400));
		} else if (!boost::ifind_first(h,"upgrade")) {
			err << "Connection header, \"" << h 
				<< "\", does not contain required token \"upgrade\"";
			throw(handshake_error(err.str(),400));
		}
		
		if (get_client_header("Sec-WebSocket-Key") == "") {
			throw(handshake_error("Required Sec-WebSocket-Key header is missing",400));
		}
		
		h = get_client_header("Sec-WebSocket-Version");
		if (h == "") {
			throw(handshake_error("Required Sec-WebSocket-Version header is missing",400));
		} else {
			m_version = atoi(h.c_str());
			
			if (m_version != 7 && m_version != 8 && m_version != 13) {
				err << "This server doesn't support WebSocket protocol version "
					<< m_version;
				throw(handshake_error(err.str(),400));
			}
		}
		
		if (m_version < 13) {
			h = get_client_header("Sec-WebSocket-Origin");
		} else {
			h = get_client_header("Origin");
		}
		
		if (h != "") {
			m_client_origin = h;
		}

		// TODO: extract subprotocols
		// TODO: extract extensions

		// optional headers (delegated to the local interface)
		if (m_local_interface) {
			m_local_interface->validate(shared_from_this());
		}
		
		m_server_http_code = 101;
		m_server_http_string = "Switching Protocols";
	} catch (const handshake_error& e) {
		std::stringstream err;
		err << "Caught handshake exception: " << e.what();
		
		access_log(e.what(),ALOG_HANDSHAKE);
		log(err.str(),LOG_ERROR);
		
		m_server_http_code = e.m_http_error_code;
		m_server_http_string = e.m_http_error_msg;
	}
	
	write_handshake();
}
예제 #10
0
void tcp_socket_session::handle_async_read(
        const boost::system::error_code& error,
        std::size_t bytes_transferred)
{
    if (error)
    {
        if (error == boost::asio::error::operation_aborted ||
            !peer_sock.is_open())
        {
            return;
        }

        terminate();

        if (error != boost::asio::error::eof &&
            error != boost::asio::error::connection_reset)
        {
            std::cout << "TCP read error: " << error.message() << std::endl;
        }

        return;
    }

    if ((std::chrono::steady_clock::now() - timeout_timestamp) >=
            tcp_socket_session::TIMEOUT_LENGTH)
    {
        netstring_buffer.clear();
    }
    netstring_buffer.append(buffer.begin(), buffer.begin()+bytes_transferred);

    int netstring_length;
    std::string parsed_message;
    while (netstring_buffer.length() > 0)
    {
        try
        {
            netstring_length =
                utils::netstring::parse(netstring_buffer, parsed_message);
        }
        catch (utils::netstring_error& error)
        {
            write(error.what());
            netstring_buffer.clear();
            break;
        }

        // Zero or more bytes have been processed
        if (netstring_length >= 0)
        {
            try
            {
                msg_center->process(this_session, parsed_message);
            }
            catch (const messaging::session_interface::process_error& e)
            {
                std::cout << "Error processing incoming message: ";
                std::cout << e.what() << std::endl;
            }
            netstring_buffer.erase(0, netstring_length);
        }
        // More bytes are needed to process a valid string
        else
        {
            break;
        }
    }

    if (netstring_buffer.length() > 0)
    {
        timeout_timestamp = std::chrono::steady_clock::now();
    }

    start_async_read();
}
예제 #11
0
    void AsioServer::handleAccept(const boost::system::error_code& e){
        LOG_DEBUG("AsioServer::handleAccept => accept a connection");

        ConnectionPtr acceptConnection = newConnection_;
        newConnection_ = newConnection();
        acceptor_.async_accept(newConnection_->getSocket(),
            boost::bind(&AsioServer::handleAccept, this, 
            boost::asio::placeholders::error));
        LOG_DEBUG("AsioServer::handleAccept => wait a new connection : cid = %d" , newConnection_->getId());
        if(!e){
            try{
                acceptConnection->open();
                LOG_DEBUG("AsioServer::handleAccept => new connection start : cid = %d" , acceptConnection->getId());
            } catch (exception &e){
                LOG_ERROR("AsioServer::handleAccept => new connection start error : what = %s" , e.what());
            }
        } else {
            LOG_ERROR("AsioServer::handleAccept => error : " , e.message().c_str());
        }
    }
예제 #12
0
void swd::connection::handle_read(const boost::system::error_code& e,
 std::size_t bytes_transferred) {
    /**
     * If an error occurs then no new asynchronous operations are started. This
     * means that all shared_ptr references to the connection object will disappear
     * and the object will be destroyed automatically after this handler returns.
     * The connection class's destructor closes the socket.
     */
    if (e) {
        return;
    }

    /**
     * Since there was no error we can start parsing the input now. The parser
     * fills the object request_ with data.
     */
    boost::tribool result;
    boost::tie(result, boost::tuples::ignore) =
        request_parser_.parse(
            request_,
            buffer_.data(),
            buffer_.data() + bytes_transferred
        );

    /**
     * If result is true the complete request is parsed. If it is false there was
     * an error. If it is indeterminate then the parsing is not complete yet and
     * the program will read more input and append it to the old request_ object.
     */
    if (indeterminate(result)) {
        /* Not finished yet with this request, start reading again. */
        this->start_read();

        /* And don't process the input yet. */
        return;
    }

    /* The handler used to process the reply. */
    swd::reply_handler reply_handler(reply_);

    try {
        if (!result) {
            swd::log::i()->send(swd::warning, "Bad request from "
             + remote_address_.to_string());
            throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST);
        }

        /* Try to add a profile for the request. */
        try {
            swd::profile_ptr profile = database_->get_profile(
                remote_address_.to_string(),
                request_->get_profile_id()
            );

            request_->set_profile(profile);
        } catch (swd::exceptions::database_exception& e) {
            swd::log::i()->send(swd::uncritical_error, e.what());
            throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST);
        }

        /* The handler used to process the incoming request. */
        swd::request_handler request_handler(request_, cache_, storage_);

        /* Only continue processing the reply if it is signed correctly. */
        if (!request_handler.valid_signature()) {
            swd::log::i()->send(swd::warning, "Bad signature from "
             + remote_address_.to_string());
            throw swd::exceptions::connection_exception(STATUS_BAD_SIGNATURE);
        }

        /**
         * Before the request can be processed the input has to be transfered
         * from the encoded json string to a swd::parameters list.
         */
        if (!request_handler.decode()) {
            swd::log::i()->send(swd::warning, "Bad json from "
             + remote_address_.to_string());
            throw swd::exceptions::connection_exception(STATUS_BAD_JSON);
        }

        /* Check profile for outdated cache. */
        swd::profile_ptr profile = request_->get_profile();

        if (profile->is_cache_outdated()) {
            cache_->reset(profile->get_id());
        }

        /* Process the request. */
        std::vector<std::string> threats;

        try {
            swd::parameters parameters = request_->get_parameters();

            /**
             * Check security limitations first.
             */
            int max_params = swd::config::i()->get<int>("max-parameters");

            if ((max_params > -1) && (parameters.size() > max_params)) {
                swd::log::i()->send(swd::notice, "Too many parameters");
                throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST);
            }

            int max_length_path = swd::config::i()->get<int>("max-length-path");
            int max_length_value = swd::config::i()->get<int>("max-length-value");

            if ((max_length_path > -1) || (max_length_value > -1)) {
                for (swd::parameters::iterator it_parameter = parameters.begin();
                 it_parameter != parameters.end(); it_parameter++) {
                    swd::parameter_ptr parameter(*it_parameter);

                    if ((max_length_path > -1) && (parameter->get_path().length() > max_length_path)) {
                        swd::log::i()->send(swd::notice, "Too long parameter path");
                        throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST);
                    }

                    if ((max_length_value > -1) && (parameter->get_value().length() > max_length_value)) {
                        swd::log::i()->send(swd::notice, "Too long parameter value");
                        throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST);
                    }
                }
            }

            if (profile->is_flooding_enabled()) {
                if (database_->is_flooding(request_->get_client_ip(), profile->get_id())) {
                    swd::log::i()->send(swd::notice, "Too many requests");
                    throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST);
                }
            }

            /* Time to analyze the request. */
            request_handler.process();
        } catch (swd::exceptions::database_exception& e) {
            swd::log::i()->send(swd::uncritical_error, e.what());

            /**
             * Problems with the database result in a bad request. If protection
             * is enabled access to the site will not be granted.
             */
            throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST);
        }

        if (profile->get_mode() == MODE_ACTIVE) {
            if (request_->is_threat()) {
                reply_->set_status(STATUS_CRITICAL_ATTACK);
            } else if (request_->has_threats()) {
                reply_->set_threats(request_handler.get_threats());
                reply_->set_status(STATUS_ATTACK);
            } else {
                reply_->set_status(STATUS_OK);
            }
        } else {
            reply_->set_status(STATUS_OK);
        }
    } catch(swd::exceptions::connection_exception& e) {
        if (!request_->get_profile()) {
            reply_->set_status(STATUS_BAD_REQUEST);
        } else if (request_->get_profile()->get_mode() == MODE_ACTIVE) {
            reply_->set_status(e.code());
        } else {
            reply_->set_status(STATUS_OK);
        }
    }

    /* Encode the reply. */
    reply_handler.encode();

    /* Send the answer to the client. */
    if (ssl_) {
        boost::asio::async_write(
            ssl_socket_,
            reply_->to_buffers(),
            strand_.wrap(
                boost::bind(
                    &connection::handle_write,
                    shared_from_this(),
                    boost::asio::placeholders::error
                )
            )
        );
    } else {
        boost::asio::async_write(
            socket_,
            reply_->to_buffers(),
            strand_.wrap(
                boost::bind(
                    &connection::handle_write,
                    shared_from_this(),
                    boost::asio::placeholders::error
                )
            )
        );
    }
}
예제 #13
0
void connection::handle_read(const boost::system::error_code& e,
							 std::size_t bytes_transferred)
{
	if (!e)
	{
		if (bytes_transferred != size)
		{
			this->client_->m_main->consoleLogger->information(Poco::format("Did not receive proper amount of bytes : rcv: %?d needed: %?d", bytes_transferred, size));
			server.stop(shared_from_this());
			return;
		}
		char * t = buffer_.data();
		if ((*(int8_t*)t != 0x0a) && (*(int8_t*)(t+1) != 0x0b) && (*(int8_t*)(t+2) != 0x01))
		{
			server.consoleLogger->information(Poco::format("Not an AMF3 object - ip:%s", address));
			server.stop(shared_from_this());
			return;
		}
		//printf("uid("XI64")\n", uid);
		// read object size
		if ((size > MAXPACKETSIZE) || (size <= 0))
		{
			//ERROR - object too large - close connection
			server.stop(shared_from_this());
			return;
		}

		//TODO: Decision: have socket read thread handle packets, or push into a queue
		//socket thread (easy, already done)
		// PRO: typically instant response times due to it being processed as it comes in
		// CON: a large request (legit or non) would cause the socket read thread to lag
		// 
		//process thread (complex, ideally better)
		// PRO: can alleviate lag on socket threads and create multiple thread processing queues depending on importance
		// CON: complexity and large requests would typically land in the same thread (causing even more lag for them) unless
		//		made even more complex to have multiple threads for large requests
		//
		//Option 3: Evony style
		// -- create a process thread per x amount of sockets
		// PRO: lag from one client only affects a set amount of players and not the entire server
		// CON: quite complex. is ultimately the process thread option only for x amount of sockets

		// parse packet
		request_.size = size;
		amf3parser * cparser = new amf3parser(buffer_.data());
		try
		{
			request_.object = cparser->ReadNextObject();
			delete cparser;
		}
		catch (...)
		{
			std::cerr << "uncaught handle_request()::amf3parser exception\n";
		}
		request_.conn = this;
		try {
			request_handler_.handle_request(request_, reply_);
		}
		catch (std::exception& e)
		{
			std::cerr << "handle_request() exception: " << e.what() << "\n";
		}
		// 		if (reply_.objects.size() > 0)
		// 		{
		// 			// send reply packets
		// 			try {
		// 				socket_.write_some(reply_.to_buffers());
		// 			}
		// 			catch (std::exception& e)
		// 			{
		// 				std::cerr << "asio::write_some() exception: " << e.what() << "\n";
		// 			}
		// 			reply_.objects.clear();
		// 		}

		boost::asio::async_read(socket_, boost::asio::buffer(buffer_, 4), boost::bind(&connection::handle_read_header, shared_from_this(),
			boost::asio::placeholders::error,
			boost::asio::placeholders::bytes_transferred));
	}
	else if (e != boost::asio::error::operation_aborted)
	{
		server.stop(shared_from_this());
		return;
	}
}