asio write succeeding but no information sent - c++

I am having a problem while creating a client program that sends requests. The request are using keep alive TCP HTTP connections. When a connection is closed(due to timeout or max being hit), I try and start a new connection if none are available, and resend the request. The connect works fine however, when I try and send the write, nothing is sent(according to Wireshark), but my error code for the write was a success. The receiving server does not receive any information either. Here is the main parts of my code:
void request_handler::send_1(std::vector<std::string> *bid_vector, std::string request_path, boost::mutex *bids_mutex)
{
try
{
boost::asio::streambuf request;
std::ostream request_stream(&request);
std::string reply_information;
request_stream << "GET /tests HTTP/1.1\r\n";
request_stream << "Host: 10.1.10.160\r\n";
request_stream << "Accept: */*\r\n";
request_stream << "Connection: keep-alive\r\n\r\n";
server1_mutex_.lock();
if(server1_available_map_.size() == 0)
{
server1_mutex_.unlock();
persistent_connection *new_connection = new persistent_connection("10.1.10.160","80");
if(new_connection->send(request, reply_information))
{
server1_mutex_.lock();
server1_available_map_[new_connection->get_id()] = new_connection;
server1_mutex_.unlock();
}
}
else
{
persistent_connection *current_connection = (*(server1_available_map_.begin())).second;
server1_available_map_.erase(current_connection->get_id());
server1_mutex_.unlock();
int retry_counter = 20;
while(!current_connection->query_rtb(request, reply_information) && --retry_counter != 0)
{
delete current_connection;
server1_mutex_.lock();
if(server1_available_map_.size() == 0)
{
server1_mutex_.unlock();
current_connection = new persistent_connection("10.1.10.160","80");
}
else
{
current_connection = (*(server1_available_map_.begin())).second;
server1_available_map_.erase(current_connection->get_id());
server1_mutex_.unlock();
}
}
//Could not connect to 20 connections
if(retry_counter == 0)
{
Log::fatal("Could not connect in 20 tries");
delete current_connection;
return;
}
server1_mutex_.lock();
server1_available_map_[current_connection->get_id()] = current_connection;
server1_mutex_.unlock();
}
bids_mutex->lock();
bid_vector->push_back(reply_information);
bids_mutex->unlock();
}
catch(boost::thread_interrupted& e)
{
std::cout << "before cancel 1" << std::endl;
return;
}
catch(...)
{
std::cout << "blah blah blah" << std::endl;
}
}
And my persistent_connection class
persistent_connection::persistent_connection(std::string ip, std::string port):
io_service_(), socket_(io_service_), host_ip_(ip)
{
boost::uuids::uuid uuid = boost::uuids::random_generator()();
id_ = boost::lexical_cast<std::string>(uuid);
boost::asio::ip::tcp::resolver resolver(io_service_);
boost::asio::ip::tcp::resolver::query query(host_ip_,port);
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
boost::asio::ip::tcp::endpoint endpoint = *iterator;
socket_.async_connect(endpoint, boost::bind(&persistent_connection::handler_connect, this, boost::asio::placeholders::error, iterator));
io_service_.run();
}
void persistent_connection::handler_connect(const boost::system::error_code &ec, boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
{
if(ec)
{
std::cout << "Couldn't connect" << ec << std::endl;
return;
}
else
{
boost::asio::socket_base::keep_alive keep_option(true);
socket_.set_option(keep_option);
std::cout << "Connect handler" << std::endl;
}
}
bool persistent_connection::send(boost::asio::streambuf &request_information, std::string &reply_information)
{
std::cout << "DOING QUERY in " << id_ << std::endl;
boost::system::error_code write_ec, read_ec;
try
{
std::cout << "Before write" << std::endl;
boost::asio::write(socket_, request_information, write_ec);
std::cout << write_ec.message() << std::endl;
}catch(std::exception& e)
{
std::cout << "Write exception: " << e.what() << std::endl;
}
if(write_ec)
{
std::cout <<"Write error: " << write_ec.message() << std::endl;
return false;
}
boost::array<char,8192> buf;
buf.assign(0);
try
{
std::cout << "Before read" << std::endl;
boost::asio::read(socket_, boost::asio::buffer(buf), boost::asio::transfer_at_least(1), read_ec);
std::cout << read_ec.message() << std::endl;
}catch(std::exception& e)
{
std::cout << "Read exception: " << e.what() << std::endl;
}
if(read_ec)
{
std::cout << "Read error: " << read_ec.message() << std::endl;
return false;
}
reply_information = buf.data();
return true;
}
std::string persistent_connection::get_id()
{
return id_;
}
The path for this to happen is if server1_available_map_.size() > 0, and if the while executes, and fails. And then if the size == 0 on the second server1_available_map_.size();
The output for the call is:
DOING QUERY in 69a8f0ab-2a06-45b4-be26-37aea6d93ff2
Before write
Success
Before read
End of file
Read error: End of file
Connect handler
DOING QUERY in 4eacaa96-1040-4878-8bf5-c29b87fa1232
Before write
Success
Before read
Which shows that the first connection gets an end of file(connection closed by server on other end). The second connection connects fine(Connect handler message), and the query is executed in the second connection(different id), and the write is apparently successful, and the program hangs on the read(because there is nothing to read).
Does anyone have any idea why this would be happening? Is there something I seem to be doing wrong?
Thank you

It looks like you are passing the same boost::asio::streambuf to multiple write calls.
boost::asio::write(socket_, request_information, write_ec);
The contents of the buffer are consumed by the first call to boost::asio::write. This effectively empties the buffer so that there is nothing left to send. Pass a const string if you want to use the same buffer for multiple writes.

Related

Telnet server always returns garbage when connecting to it using Boost Asio

So I am trying to make a telnet client that connects to some address part for work and part for Boost::Asio learning purpose.
My small project has three handlers:
Resolve handler:
void resolverHandler(const boost::system::error_code& ec, ip::tcp::resolver::iterator iter) {
if (ec) {
cout << "Resolved failed with message: " << ec.message() << endl;
}
else {
ip::tcp::endpoint endpoint = *iter;
cout << "Connection to: " << endpoint.address() << ":" << endpoint.port() << endl;
tcpSocket.async_connect(endpoint, connectHandler);
}
}
Connect handler
void connectHandler(const boost::system::error_code& ec) {
if (ec) {
cout << "Connect failed with message: " << ec.message() << endl;
}
else {
cout << "Connection established" << endl;
tcpSocket.async_read_some(buffer(_data), readHandler);
}
}
Read handler:
void readHandler(const boost::system::error_code& ec, size_t amountOfBytes) {
if (ec) {
cout << "Read failed with message: " << ec.message() << endl;
}
else {
cout << amountOfBytes << endl;
cout << _data.data() << endl;
tcpSocket.async_read_some(buffer(_data), readHandler);
}
}
And this is my main function:
io_service ioservice;
ip::tcp::resolver resolver(ioservice);
ip::tcp::socket tcpSocket(ioservice);
array<char, 16> _data;
ip::tcp::resolver::query query("192.168.200.200", "23");
int main() {
resolver.async_resolve(query, resolverHandler);
ioservice.run();
return 0;
}
But I always get garbage like this:
Connection to: 192.168.206.226:23
Connection established
15
 ² ²  ²# ²' ²$
I admit that I am new to telnet, but I am not sure why do I get this response ? Not sure if I need to null terminate the data that I receive before printing it, but even like that I have the same response.
Here is the normal response I should receive - tried with Windows Telnet:
Welcome Message (localhost) (ttyp0)
login:
Apreciate if someone has any ideas on what to do.

Boost.Asio/OpenSSL HTTPS GET certificate trouble

I am using Boost Asio and my goal is to send an HTTPS GET request to www.realmofthemadgod.com. I found some code on GitHub claiming to do that which I've included below but first I'll go through some observations:
The code fails with an error sslv3 alert handshake failure.
On command line, the command openssl s_client -connect www.realmofthemadgod.com:443 results in the same error and some other messages about no certificates being available
However, the command openssl s_client -connect www.realmofthemadgod.com:443 -servername www.realmofthemadgod.com does find the correct certificate!
Now, the problem is how do I achieve what the -servername switch does, in code.
What I have so far:
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#pragma comment(lib, "libcryptoMD.lib")
#pragma comment(lib, "libsslMD.lib")
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/bind.hpp>
using boost::asio::ip::tcp;
class client
{
public:
client(boost::asio::io_service& io_service, boost::asio::ssl::context& context, const std::string& server, const std::string& path)
: resolver_(io_service), socket_(io_service, context)
{
// Form the request. We specify the "Connection: close" header so that the
// server will close the socket after transmitting the response. This will
// allow us to treat all data up until the EOF as the content.
std::ostream request_stream(&request_);
request_stream << "GET " << path << " HTTP/1.1\r\n";
request_stream << "Host: " << server << "\r\n";
request_stream << "Accept: */*\r\n";
request_stream << "Connection: close\r\n\r\n";
// Start an asynchronous resolve to translate the server and service names
// into a list of endpoints.
tcp::resolver::query query(server, "https");
resolver_.async_resolve(query,
boost::bind(&client::handle_resolve, this,
boost::asio::placeholders::error,
boost::asio::placeholders::iterator));
}
private:
void handle_resolve(const boost::system::error_code& err,
tcp::resolver::iterator endpoint_iterator)
{
if (!err)
{
std::cout << "Resolve OK" << "\n";
socket_.set_verify_mode(boost::asio::ssl::verify_peer);
//socket_.set_verify_mode(boost::asio::ssl::verify_none);
socket_.set_verify_callback(
boost::bind(&client::verify_certificate, this, _1, _2));
boost::asio::async_connect(socket_.lowest_layer(), endpoint_iterator,
boost::bind(&client::handle_connect, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "Error resolve: " << err.message() << "\n";
}
}
bool verify_certificate(bool preverified,
boost::asio::ssl::verify_context& ctx)
{
// The verify callback can be used to check whether the certificate that is
// being presented is valid for the peer. For example, RFC 2818 describes
// the steps involved in doing this for HTTPS. Consult the OpenSSL
// documentation for more details. Note that the callback is called once
// for each certificate in the certificate chain, starting from the root
// certificate authority.
// In this example we will simply print the certificate's subject name.
char subject_name[256];
X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
std::cout << "Verifying " << subject_name << "\n";
return preverified;
}
void handle_connect(const boost::system::error_code& err)
{
if (!err)
{
std::cout << "Connect OK " << "\n";
socket_.async_handshake(boost::asio::ssl::stream_base::client,
boost::bind(&client::handle_handshake, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "Connect failed: " << err.message() << "\n";
}
}
void handle_handshake(const boost::system::error_code& error)
{
if (!error)
{
std::cout << "Handshake OK " << "\n";
std::cout << "Request: " << "\n";
const char* header = boost::asio::buffer_cast<const char*>(request_.data());
std::cout << header << "\n";
// The handshake was successful. Send the request.
boost::asio::async_write(socket_, request_,
boost::bind(&client::handle_write_request, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "Handshake failed: " << error.message() << "\n";
}
}
void handle_write_request(const boost::system::error_code& err)
{
if (!err)
{
// Read the response status line. The response_ streambuf will
// automatically grow to accommodate the entire line. The growth may be
// limited by passing a maximum size to the streambuf constructor.
boost::asio::async_read_until(socket_, response_, "\r\n",
boost::bind(&client::handle_read_status_line, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "Error write req: " << err.message() << "\n";
}
}
void handle_read_status_line(const boost::system::error_code& err)
{
if (!err)
{
// Check that response is OK.
std::istream response_stream(&response_);
std::string http_version;
response_stream >> http_version;
unsigned int status_code;
response_stream >> status_code;
std::string status_message;
std::getline(response_stream, status_message);
if (!response_stream || http_version.substr(0, 5) != "HTTP/")
{
std::cout << "Invalid response\n";
return;
}
if (status_code != 200)
{
std::cout << "Response returned with status code ";
std::cout << status_code << "\n";
return;
}
std::cout << "Status code: " << status_code << "\n";
// Read the response headers, which are terminated by a blank line.
boost::asio::async_read_until(socket_, response_, "\r\n\r\n",
boost::bind(&client::handle_read_headers, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "Error: " << err.message() << "\n";
}
}
void handle_read_headers(const boost::system::error_code& err)
{
if (!err)
{
// Process the response headers.
std::istream response_stream(&response_);
std::string header;
while (std::getline(response_stream, header) && header != "\r")
std::cout << header << "\n";
std::cout << "\n";
// Write whatever content we already have to output.
if (response_.size() > 0)
std::cout << &response_;
// Start reading remaining data until EOF.
boost::asio::async_read(socket_, response_,
boost::asio::transfer_at_least(1),
boost::bind(&client::handle_read_content, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "Error: " << err << "\n";
}
}
void handle_read_content(const boost::system::error_code& err)
{
if (!err)
{
// Write all of the data that has been read so far.
std::cout << &response_;
// Continue reading remaining data until EOF.
boost::asio::async_read(socket_, response_,
boost::asio::transfer_at_least(1),
boost::bind(&client::handle_read_content, this,
boost::asio::placeholders::error));
}
else if (err != boost::asio::error::eof)
{
std::cout << "Error: " << err << "\n";
}
}
tcp::resolver resolver_;
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
boost::asio::streambuf request_;
boost::asio::streambuf response_;
};
int main(int argc, char* argv[])
{
try
{
//boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
boost::asio::ssl::context ctx(boost::asio::ssl::context::tlsv12);
ctx.set_default_verify_paths();
boost::asio::io_service io_service;
client c(io_service, ctx, "www.realmofthemadgod.com", "/");
io_service.run();
}
catch (std::exception& e)
{
std::cout << "Exception: " << e.what() << "\n";
}
return 0;
}
I did some digging and learned that the switch -servername enables something called server name indication (SNI) and I found a way to enable it in code.
This is added to the client constructor:
// Set SNI Hostname (many hosts need this to handshake successfully)
if (!SSL_set_tlsext_host_name(stream.native_handle(), host))
{
boost::system::error_code ec((int)ERR_get_error(), boost::asio::error::get_ssl_category());
throw boost::system::system_error(ec);
}
The code still doesn't quite work (it waits for an async callback to happen and times out) but this solves the original problem presented in the question.

Asynchronous Call to Read returns immediately

I've been trying to use boost in order to asynchronously read from a serial_port until it puts incoming data into a buffer that I have specified. However, when I call:
boost::asio::async_read(*port_,
*readBuf_,
boost::bind(&Serial::async_read_handler,
this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
it calls async_read_handler immediately, which triggers the code inside my read_handler.
void Serial::async_read_handler(const boost::system::error_code &e,
std::size_t bytes_read)
{
namespace basio = boost::asio;
if(!e)
{
std::cout << e.message() << std::endl;
std::cout << bytes_read << std::endl;
if(bytes_read <= 0)
{
std::string read = *basio::buffer_cast<std::string*>(*readBuf_);
std::cout << read << std::endl;
basio::async_read(*port_,
*readBuf_,
boost::bind(&Serial::async_read_handler,
this,
basio::placeholders::error,
basio::placeholders::bytes_transferred));
}
else
{
std::string read = *basio::buffer_cast<std::string*>(*readBuf_);
std::cout << read << std::endl;
std::cout << "Bytes read: " << bytes_read << std::endl;
}
}
else
{
std::cerr << e.message() << std::endl;
}
}
I first call a thread to run async_read in my main
int main()
{
boost::asio::io_service io;
Serial::Serial serial(PORT, &io);
if(!serial.is_open())
{
serial.open(PORT);
}
serial.async_read();
io.run();
return 0;
}
I want the async_read call to wait until it has read data from the buffer to call the handler. How can I do this? Thanks.

Connecting to an IRC server, getting Ping timeout without receiving PING message

I'm trying my hands at network programming for the first time, implementing a small IRC bot using the SFML network functionality.
The connection gets established, but from there on I can't do much else. Trying to receive any data from the server yields nothing, until I get the "Ping timeout" message after a few seconds.
Removing all or some of the receive() calls in the loginOnIRC function doesn't do any good.
Trying to connect via telnet with the exact same messages works. Here I get a PING message right after sending my NICK message.
Am I missing something?
My code is as follows
#include <iostream>
#include <string>
#include <SFML/Network.hpp>
#define ARRAY_LEN(x) (sizeof(x)/sizeof(*x))
void receive(sf::TcpSocket* sck)
{
char rcvData[100];
memset(rcvData, 0, ARRAY_LEN(rcvData));
std::size_t received;
if (sck->receive(rcvData, ARRAY_LEN(rcvData), received) != sf::Socket::Done)
{
std::cout << "oops" << std::endl;
}
std::cout << "Received " << received << " bytes" << std::endl;
std::cout << rcvData << std::endl;
}
int establishConnection(sf::TcpSocket* sck)
{
sf::Socket::Status status = sck->connect("irc.euirc.net", 6667, sf::seconds(5.0f));
if (status != sf::Socket::Done)
{
std::cout << "Error on connect!" << std::endl;
return 1;
}
std::cout << "Connect was successful!" << std::endl;
return 0;
}
int loginOnIRC(sf::TcpSocket* sck)
{
receive(sck); // We get a Ping timeout here
std::string data{ "NICK NimBot" };
if(sck->send(data.c_str(), data.length()) != sf::Socket::Done)
{
std::cout << "Error on sending " << data << std::endl;
return 1;
}
receive(sck);
data = "USER NimBot * * :Nimelrians Bot";
if (sck->send(data.c_str(), data.length()) != sf::Socket::Done)
{
std::cout << "Error on sending " << data << std::endl;
return 1;
}
receive(sck);
data = "JOIN #nimbottest";
if (sck->send(data.c_str(), data.length()) != sf::Socket::Done)
{
std::cout << "Error on sending " << data << std::endl;
return 1;
}
return 0;
}
int main()
{
sf::TcpSocket sck{};
establishConnection(&sck); // works
loginOnIRC(&sck);
while(true)
{
char data[100];
memset(data, 0, ARRAY_LEN(data));
std::size_t received;
sf::Socket::Status rcvStatus = sck.receive(data, ARRAY_LEN(data), received);
if (rcvStatus != sf::Socket::Done)
{
std::cout << "oops" << std::endl;
if (rcvStatus == sf::Socket::Disconnected)
{
break;
}
}
std::cout << "Received " << received << " bytes" << std::endl;
std::cout << data << std::endl;
}
return 0;
}

asynchronous UDP client/server communication (BOOST) - server does not read

Hello I ve been trying to implement a simple server/client app to communicate through UDP socket and understand how UDP works using boost library, my problem is that async_receive is not being invoked or is not getting complete in order to jump on the handler
UDP server:
#include "udp_server.h"
udp_server::udp_server(boost::asio::io_service& io_service, string bind_address, uint16_t bind_port)
: socket_(io_service)
{
cout << "udp_server constructor start" << endl;
boost::shared_ptr<boost::asio::io_service::work> work(
new boost::asio::io_service::work(io_service));
for(int x=0; x<5; ++x)
{
worker_threads.create_thread(boost::bind(&udp_server::WorkerThread, this , boost::ref(io_service)));
}
boost::system::error_code myError;
boost::asio::ip::address IP;
IP = boost::asio::ip::address::from_string(bind_address, myError);
local_udppoint_.address(IP);
cout << "IP Address: " << local_udppoint_.address().to_string() << endl;
local_udppoint_.port(bind_port);
cout << "Port: " << local_udppoint_.port() << endl;
socket_.open(local_udppoint_.protocol(), myError);
std::cout << "Open - " << myError.message() << std::endl;
socket_.bind( local_udppoint_, myError );
std::cout << "Bind - " << myError.message() << std::endl;
udp::endpoint sender_endpoint_;
struct test *request = (struct test *) malloc (sizeof(struct test));
socket_.async_receive_from(
boost::asio::buffer(&request, sizeof(request->type)), sender_endpoint_,
boost::bind(&udp_server::handle_receive_from, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
cout << "udp_server constructor end" << endl;
}
void udp_server::WorkerThread(io_service &io_service_)
{
std::cout << "Thread Start\n";
io_service_.run();
std::cout << "Thread Finish\n";
}
void udp_server::handle_receive_from(const boost::system::error_code& err, size_t bytes_recvd)
{
cout << "udp_server::handle_receive_from enters?" << endl;
if(!err)
{
cout << "no message" << endl;
}
else
{
cout << err.message() << endl;
}
if (!err && bytes_recvd > 0)
{
cout << "All good" << endl;
}
else
{
cout << err.message() << "2" << endl;
}
}
udp_server::~udp_server(void)
{
//io_service.stop();
worker_threads.join_all();
cout << "udp_server::destructor" << endl;
}
Server's Main:
#include "udp_server.h"
int main()
{
try
{
boost::asio::io_service io_service;
//boost::asio::io_service::work work( io_service);
udp_server s(io_service, "127.0.0.1", 4000);
//io_service.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
string a;
cin >> a;
return 0;
}
UDP Client:
#include "udp_client.h"
udp_client::udp_client(boost::asio::io_service& io_service, string send_address, uint16_t send_port)
: io_service_(io_service), socket_(io_service)
{
cout << "udp_client::constructor_start" << endl;
boost::system::error_code myError;
boost::asio::ip::address IP;
IP = boost::asio::ip::address::from_string(send_address, myError);
remote_endpoint_.address(IP);
cout << "IP Address: " << remote_endpoint_.address().to_string() << endl;
remote_endpoint_.port(send_port);
cout << "Port: " << remote_endpoint_.port() << endl;
struct test *request = (struct test *) malloc (sizeof(struct test));
request->type = START_STORAGE;
socket_.async_send_to(boost::asio::buffer(&request, sizeof(request->type)), remote_endpoint_,
boost::bind(&udp_client::start_handler, this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
cout << "udp_client::constructor_end" << endl;
}
void
udp_client::start_handler(const boost::system::error_code&, std::size_t)
{
cout << "udp_client::start_handler()" << endl;
}
udp_client::~udp_client(void)
{
}
Client's main:
#include "udp_client.h"
int main(int argc, char* argv[])
{
try
{
boost::asio::io_service io_service;
udp_client client(io_service, "127.0.0.1", 4000);
io_service.run ();
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
string a;
cin >> a;
return 0;
}
As you can see in the outputs below client invoked async_send_to and the message on the handler is being printed but on the server side nothing happens
UDP Server Console output:
udp_server constructor star
Thread Start
Thread Start
Thread Start
Thread Start
Thread Start
IP Address: 127.0.0.1
Port: 4000
Open - The operation completed successfully
Bind - The operation completed successfullyudp_server constructor end
_
UDP Client Console:
udp_client::constructor_start
IP Address: 127.0.0.1
Port: 4000
udp_client::constructor_end
udp_client::start_handler()
Any ideas why async_receive_from is not completed or invoked?
Right off the bat, calling join_all on your listening threads in your destructor is going to lead to undefined behavior. You're trying to keep your server running while it's right in the middle of being destroyed. Don't do this. As an example, running the io_service from these threads, you have handlers that bind to this* that those threads will be hooking into. Inside the destructor, this* is no longer a valid object. In all of your callbacks, you should be checking the error param you were passed to see if it is set.
if(error)
{
std::cout << "Error in MyClass::MyFunc(...): " << error << std::endl;
}
.. to get the errors printed to the console. Guaranteed you're going to see an error from ::bind that such and such is an invalid object.
You should be doing something inside your server main where you're blocking to prevent main from exiting. Move your thread group that runs your server's io_service and the io_service itself outside of the server object. Wrap the io_service with a ::work() object to prevent the io_service from stopping itself when it thinks that it's run out of work (no more connections to process).
Beyond that, the simplest thing to do is point you to the droves of TCP and UDP client and server examples that boost docs provide. http://www.boost.org/doc/libs/1_57_0/doc/html/boost_asio/examples.html