RSS

boost::asio udp relay server

16 3월

조만간 회사에서 쓸 일이 있을 것 같아서 만들어본 udp relay 서버. 하는 일이라고는 패킷을 잠시 저장해뒀다가 원래 주소로 쏘는 일인데, ASIO를 쓰면 얼마나 코드가 간단해질까 해서 만들어봤다. 이 코드는 서버에만 쓰고, 클라이언트에 붙일 넘은 IOCP까지는 필요없고 그냥 Win32 + winsock2 + 폴링 쓰레드로 만들어볼까 싶다.

class udp_relay_server
{
	struct relay_policy
	{
		udp::endpoint from_, to_;
		DWORD delay_;
	};

	struct relay_message
	{
		boost::shared_ptr<std::string> message_;
		udp::endpoint destination_;
		DWORD expire_clock_;
	};

	enum
	{
		MIN_SLEEP_DELAY = 10
	};

public:

	udp_relay_server(boost::asio::io_service& io_service, short port)
		: socket_(io_service, udp::endpoint(udp::v4(), port))
		, timer_(io_service)
	{
		do_receive();
		do_timer();
	}

	udp_relay_server(boost::asio::io_service& io_service, const udp::endpoint & endpoint_ )
		: socket_(io_service, endpoint_)
		, timer_(io_service)
	{
		do_receive();
		do_timer();
	}

	void add_policy( const udp::endpoint & from_, const udp::endpoint & to_, DWORD delay = 0 )
	{
		relay_policy p;
		p.from_ = from_;
		p.to_ = to_;
		p.delay_ = delay;
		policies.push_back(p);
	}

	void add_policy( string from_addr, short from_port, string to_addr, short to_port, DWORD delay = 0 )
	{
		udp::endpoint from_( boost::asio::ip::address::from_string(from_addr), from_port );
		udp::endpoint to_( boost::asio::ip::address::from_string(to_addr), to_port );
		add_policy( from_, to_, delay );
	}

	void clear_policy() { policies.clear(); }

private:

	void do_timer()
	{
		timer_.expires_from_now(boost::posix_time::milliseconds(MIN_SLEEP_DELAY));
		timer_.async_wait(boost::bind(&udp_relay_server::handle_timer,this,boost::asio::placeholders::error));
	}

	void handle_timer( const boost::system::error_code & ec )
	{
		if ( !queue_.empty() )
		{
			DWORD cur_clock = GetTickCount();
			std::list< relay_message >::iterator itr = queue_.begin();
			while ( itr != queue_.end() )
			{
				relay_message & m = *itr;
				if ( cur_clock > m.expire_clock_ )
				{
					socket_.async_send_to(boost::asio::buffer(*m.message_), m.destination_,
						boost::bind(&udp_relay_server::handle_send, this, m.message_, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred) );
					itr = queue_.erase(itr++);
				}
				else
				{
					itr++;
				}
			}
		}
		do_timer();
	}

	void do_receive()
	{
		socket_.async_receive_from(
			boost::asio::buffer(recv_buffer_), remote_endpoint_,
			boost::bind(&udp_relay_server::handle_receive, this,
			boost::asio::placeholders::error,
			boost::asio::placeholders::bytes_transferred));
	}

	void handle_receive(const boost::system::error_code& error, std::size_t bytes_transferred)
	{
		if (!error)
		{
			bool bRelayed = false;
			for(size_t i = 0 ; i < policies.size() ; i ++ )
			{
				relay_policy & p = policies&#91;i&#93;;
				if ( p.from_ == remote_endpoint_ )
				{
					udp::endpoint relay_to(p.to_);
					boost::shared_ptr<std::string> message(new string(recv_buffer_.data(),bytes_transferred));
					if ( p.delay_ > 0 )
					{
						relay_message m;
						m.message_ = message;
						m.destination_ = relay_to;
						m.expire_clock_ = GetTickCount() + p.delay_;
						queue_.push_back( m );
					}
					else
					{
						do_send( message, relay_to );
					}
					bRelayed = true;
					break;
				}
			}
			do_receive();
		}
	}

	void do_send( boost::shared_ptr<std::string> message, const udp::endpoint & destination )
	{
		socket_.async_send_to(boost::asio::buffer(*message), destination,
			boost::bind(&udp_relay_server::handle_send, this,
				message, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred) );
	}

	void handle_send(boost::shared_ptr<std::string> message, const boost::system::error_code& error, std::size_t bytes_transferred )
	{
	}

	udp::socket socket_;
	udp::endpoint remote_endpoint_;
	boost::array<char, 128> recv_buffer_;
	vector<relay_policy> policies;
	boost::asio::deadline_timer timer_;
	std::list< relay_message > queue_;
};
 
댓글 한 개

게시자: 켬 2008/03/16 in Uncategorized

 

boost::asio udp relay server”에 대한 1개의 응답

  1. Luke Choi

    2008/03/17 at 10:34 am

    오옷…잼있는 물건인듯…
    부스트에 이런것이 있었군요…훔훔
    성능이 어떨지 궁금하네요.^_^

     

댓글 남기기