예제 #1
0
void connection::handle_read(const asio::error_code& e,
									std::size_t bytes_transferred)
{
	if (!e)
	{
		if (bytes_transferred != size)
		{
			Log("Did not receive proper amount of bytes : %d", size);
			connection_manager_.stop(shared_from_this());
			return;
		}
		//printf("uid("XI64")\n", uid);
		// read object size
		if ((size > 8192*4) || (size <= 0))
		{
			//ERROR - object too large - close connection
			connection_manager_.stop(shared_from_this());
			return;
		}

		// parse packet
		request_.size = size;
		amf3parser * cparser = new amf3parser(buffer_.data());
		request_.object = cparser->ReadNextObject();
		request_.connection = this;
		try {
			request_handler_.handle_request(request_, reply_);
		}
		catch (std::exception& e)
		{
			std::cerr << "handle_request() exception: " << e.what() << "\n";
		}
		delete cparser;
		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();
// 			asio::async_write(socket_, reply_.to_buffers(),
// 				boost::bind(&connection::handle_write, shared_from_this(),
// 				asio::placeholders::error));
		}

		asio::async_read(socket_, asio::buffer(buffer_, 4), boost::bind(&connection::handle_read_header, shared_from_this(),
			asio::placeholders::error,
			asio::placeholders::bytes_transferred));
	}
	else if (e != asio::error::operation_aborted)
	{
		connection_manager_.stop(shared_from_this());
		return;
	}
}
예제 #2
0
void natpmp::on_reply(asio::error_code const& e
	, std::size_t bytes_transferred)
{
	using namespace libtorrent::detail;
	if (e) return;

	try
	{

		if (m_remote != m_nat_endpoint)
		{
			m_socket.async_receive_from(asio::buffer(&m_response_buffer, 16)
				, m_remote, bind(&natpmp::on_reply, this, _1, _2));
			return;
		}
		
		m_send_timer.cancel();

		assert(m_currently_mapping >= 0);
		int i = m_currently_mapping;
		mapping& m = m_mappings[i];

		char* in = m_response_buffer;
		int version = read_uint8(in);
		int cmd = read_uint8(in);
		int result = read_uint16(in);
		int time = read_uint32(in);
		int private_port = read_uint16(in);
		int public_port = read_uint16(in);
		int lifetime = read_uint32(in);

		(void)time; // to remove warning

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		m_log << time_now_string()
			<< " <== port map response: " << (cmd - 128 == 1 ? "udp" : "tcp")
			<< " local: " << private_port << " external: " << public_port
			<< " ttl: " << lifetime << std::endl;
#endif

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		if (version != 0)
		{
			m_log << "*** unexpected version: " << version << std::endl;
		}
#endif

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		if (private_port != m.local_port)
		{
			m_log << "*** unexpected local port: " << private_port << std::endl;
		}
#endif

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		if (cmd != 128 + m.protocol)
		{
			m_log << "*** unexpected protocol: " << (cmd - 128) << std::endl;
		}
#endif

		if (public_port == 0 || lifetime == 0)
		{
			// this means the mapping was
			// successfully closed
			m.local_port = 0;
		}
		else
		{
			m.expires = time_now() + seconds(int(lifetime * 0.7f));
			m.external_port = public_port;
		}
		
		if (result != 0)
		{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
			m_log << "*** ERROR: " << result << std::endl;
#endif
			std::stringstream errmsg;
			errmsg << "NAT router reports error (" << result << ") ";
			switch (result)
			{
				case 1: errmsg << "Unsupported protocol version"; break;
				case 2: errmsg << "Not authorized to create port map (enable NAT-PMP on your router)"; break;
				case 3: errmsg << "Network failure"; break;
				case 4: errmsg << "Out of resources"; break;
				case 5: errmsg << "Unsupported opcode"; break;
			}
			throw std::runtime_error(errmsg.str());
		}

		// don't report when we remove mappings
		if (m.local_port != 0)
		{
			int tcp_port = 0;
			int udp_port = 0;
			if (m.protocol == 1) udp_port = m.external_port;
			else tcp_port = public_port;
			m_callback(tcp_port, udp_port, "");
		}
	}
	catch (std::exception& e)
	{
		// try again in two hours
		m_mappings[m_currently_mapping].expires = time_now() + hours(2);
		m_callback(0, 0, e.what());
	}
	int i = m_currently_mapping;
	m_currently_mapping = -1;
	m_mappings[i].need_update = false;
	m_send_timer.cancel();
	update_expiration_timer();
	try_next_mapping(i);
}
예제 #3
0
void connection::handle_read(const asio::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;
		}
		//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());
		request_.object = cparser->ReadNextObject();
		request_.connection = this;
		try {
			request_handler_.handle_request(request_, reply_);
		}
		catch (std::exception& e)
		{
			std::cerr << "handle_request() exception: " << e.what() << "\n";
		}
		delete cparser;
		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();
		}

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