blob: 6aa2f8a45f54ffb6cc576d036cb398fe2e7afe47 [file] [log] [blame]
//
// udp_server.cpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <asio/io_context.hpp>
#include <asio/ip/udp.hpp>
#include <boost/shared_ptr.hpp>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include "allocator.hpp"
using asio::ip::udp;
#include "yield.hpp"
class udp_server : coroutine
{
public:
udp_server(asio::io_context& io_context,
unsigned short port, std::size_t buf_size) :
socket_(io_context, udp::endpoint(udp::v4(), port)),
buffer_(buf_size)
{
}
void operator()(asio::error_code ec, std::size_t n = 0)
{
reenter (this) for (;;)
{
yield socket_.async_receive_from(
asio::buffer(buffer_),
sender_, ref(this));
if (!ec)
{
for (std::size_t i = 0; i < n; ++i) buffer_[i] = ~buffer_[i];
socket_.send_to(asio::buffer(buffer_, n), sender_, 0, ec);
}
}
}
friend void* asio_handler_allocate(std::size_t n, udp_server* s)
{
return s->allocator_.allocate(n);
}
friend void asio_handler_deallocate(void* p, std::size_t, udp_server* s)
{
s->allocator_.deallocate(p);
}
struct ref
{
explicit ref(udp_server* p)
: p_(p)
{
}
void operator()(asio::error_code ec, std::size_t n = 0)
{
(*p_)(ec, n);
}
private:
udp_server* p_;
friend void* asio_handler_allocate(std::size_t n, ref* r)
{
return asio_handler_allocate(n, r->p_);
}
friend void asio_handler_deallocate(void* p, std::size_t n, ref* r)
{
asio_handler_deallocate(p, n, r->p_);
}
};
private:
udp::socket socket_;
std::vector<unsigned char> buffer_;
udp::endpoint sender_;
allocator allocator_;
};
#include "unyield.hpp"
int main(int argc, char* argv[])
{
if (argc != 5)
{
std::fprintf(stderr,
"Usage: udp_server <port1> <nports> "
"<bufsize> {spin|block}\n");
return 1;
}
unsigned short first_port = static_cast<unsigned short>(std::atoi(argv[1]));
unsigned short num_ports = static_cast<unsigned short>(std::atoi(argv[2]));
std::size_t buf_size = std::atoi(argv[3]);
bool spin = (std::strcmp(argv[4], "spin") == 0);
asio::io_context io_context(1);
std::vector<boost::shared_ptr<udp_server> > servers;
for (unsigned short i = 0; i < num_ports; ++i)
{
unsigned short port = first_port + i;
boost::shared_ptr<udp_server> s(new udp_server(io_context, port, buf_size));
servers.push_back(s);
(*s)(asio::error_code());
}
if (spin)
for (;;) io_context.poll();
else
io_context.run();
}