SockIt
Public Member Functions | Protected Member Functions | Private Member Functions | Private Attributes

UdpClient Class Reference

#include <UdpClient.h>

Inheritance diagram for UdpClient:
Udp Client NetworkObject

List of all members.

Public Member Functions

 UdpClient (const string &host, int port, boost::asio::io_service &io_service)
 UdpClient (const string &host, int port, boost::asio::io_service &io_service, map< string, string > options)
virtual ~UdpClient ()
virtual void send (const string &data)
virtual void send_bytes (const vector< byte > &bytes)
virtual void shutdown ()
virtual int get_port ()
virtual string get_host ()

Protected Member Functions

void init_socket ()
virtual void fire_error_event (const string &message)
virtual void fire_data_event (const string data, boost::shared_ptr< udp::socket > socket, boost::shared_ptr< udp::endpoint > endpoint)
virtual void close ()

Private Member Functions

 UdpClient (const UdpClient &other)
virtual void listen ()
void resolve_handler (const boost::system::error_code &err, udp::resolver::iterator endpoint_iterator)
void flush ()

Private Attributes

boost::shared_ptr< udp::resolver > resolver
boost::shared_ptr< udp::socket > socket
boost::mutex queue_mtx
std::queue< string > msgs_not_sent
bool resolved_endpoint

Detailed Description

Definition at line 22 of file UdpClient.h.


Constructor & Destructor Documentation

UdpClient::UdpClient ( const string &  host,
int  port,
boost::asio::io_service &  io_service 
)

Asynchronously resolves the host and port number after creation. The client will not be able to send messages until after the resolve handler has run to completion.

Parameters:
hostThe host to connect to
portThe port the host is listening on
io_serviceThe I/O service to be used for asynchronous I/O requests

Definition at line 16 of file UdpClient.cpp.

References Logger::error(), Udp::failed, resolver, and socket.

                                                                                  :
    Udp(host, port, ioService), resolver(new udp::resolver(io_service)), socket(new udp::socket(io_service)), resolved_endpoint(false)
{
    // Check that the connection and resolver are valid, and fail gracefully if they are not
    if (!resolver.get() || !socket.get())
    {
        failed = true;
        string message("Failed to initialize UDP client, failed to initialize properly");
        Logger::error(message, port, host);
        fire_error(message);
        return;
    }
}
UdpClient::UdpClient ( const string &  host,
int  port,
boost::asio::io_service &  io_service,
map< string, string >  options 
)

Asynchronously resolves the host and port number after creation. The client will not be able to send messages until after the resolve handler has run to completion.

Parameters:
hostThe host to connect to
portThe port the host is listening on
io_serviceThe I/O service to be used for asynchronous I/O requests
optionsA map of additional options to configure this UDP client

Definition at line 30 of file UdpClient.cpp.

References Logger::error(), Udp::failed, Udp::parse_args(), resolver, and socket.

                                                                                                               :
    Udp(host, port, ioService), resolver(new udp::resolver(io_service)), socket(new udp::socket(io_service)), resolved_endpoint(false)
{
    // Check that the connection and resolver are valid, and fail gracefully if they are not
    if (!resolver.get() || !socket.get())
    {
        failed = true;
        string message("Failed to initialize UDP client, failed to initialize properly");
        Logger::error(message, port, host);
        fire_error(message);
        return;
    }

    parse_args(options);
}
UdpClient::~UdpClient ( ) [virtual]

Deconstructs a UDP client, immediately calling close to shutdown this client's socket and stop listening for responses.

Definition at line 92 of file UdpClient.cpp.

References close().

{
    close();
}
UdpClient::UdpClient ( const UdpClient other) [private]

Disallows copying a UDP client


Member Function Documentation

void UdpClient::close ( ) [protected, virtual]

Immediately cancels any pending operations and closes this client's socket.

Implements Udp.

Definition at line 97 of file UdpClient.cpp.

References Udp::should_close, and socket.

Referenced by shutdown(), and ~UdpClient().

{
    should_close = true;

    if (socket->is_open())
    {
        socket->close();
    }
}
void UdpClient::fire_data_event ( const string  data,
boost::shared_ptr< udp::socket >  socket,
boost::shared_ptr< udp::endpoint >  endpoint 
) [protected, virtual]

Helper to fire data event to javascript.

Parameters:
dataThe data received
socketThe socket on which to reply to this data
endpointThe connected endpoint to the remote host

Implements Udp.

Definition at line 281 of file UdpClient.cpp.

References Udp::should_close.

{
    if (should_close)
        return;

    fire_data(boost::make_shared<UdpEvent>(this, socket, endpoint, data));
}
void UdpClient::fire_error_event ( const string &  message) [protected, virtual]

Helper to fire an error event to javascript.

Parameters:
messageThe error message

Implements Udp.

Definition at line 273 of file UdpClient.cpp.

References Udp::should_close.

{
    if (should_close)
        return;

    fire_error(message);
}
void UdpClient::flush ( ) [private]

Flush all pending messages.

Definition at line 238 of file UdpClient.cpp.

References msgs_not_sent, queue_mtx, and send().

Referenced by resolve_handler(), and send().

{
    queue_mtx.lock();

    while (!msgs_not_sent.empty())
    {
        string msg = msgs_not_sent.front();
        msgs_not_sent.pop();
        queue_mtx.unlock();
        send(msg);
        queue_mtx.lock();
    }

    queue_mtx.unlock();
}
string UdpClient::get_host ( void  ) [virtual]

Returns the host to which this client connects

Implements Client.

Definition at line 263 of file UdpClient.cpp.

References Udp::host.

{
    return host;
}
int UdpClient::get_port ( void  ) [virtual]

Returns the port of the remote host on which this client connects

Implements Client.

Definition at line 268 of file UdpClient.cpp.

References Udp::port.

{
    return port;
}
void UdpClient::init_socket ( ) [protected]

Initializes the socket according to the passed in options (if any).

Definition at line 46 of file UdpClient.cpp.

References Udp::BUFFER_SIZE, Udp::do_not_route, Logger::error(), Udp::host, Logger::info(), Udp::log_options(), Udp::multicast, Udp::multicast_ttl, Udp::port, Udp::reuse_address, socket, and Udp::using_ipv6.

Referenced by resolve_handler().

{
    Logger::info(
            "Initializing UDP client to host '" + boost::lexical_cast<string>(host) + "' on port " + boost::lexical_cast<string>(port),
            port, host);
    log_options();

    if (using_ipv6 && *using_ipv6)
        socket->open(udp::v6());
    else
        socket->open(udp::v4());

    if (!socket->is_open())
    {
        string message("Failed to open UDP client socket");
        Logger::error(message, port, host);
        fire_error(message);
    }

    // synchronize the buffer size of the socket with this class's buffer size
    boost::asio::socket_base::receive_buffer_size buf_size_option(BUFFER_SIZE);
    socket->set_option(buf_size_option);

    // set multicast ttl and out going interface
    if (multicast && *multicast)
    {
        if (multicast_ttl)
        {
            boost::asio::ip::multicast::hops option(*multicast_ttl);
            socket->set_option(option);
        }
    }

    if (do_not_route)
    {
        boost::asio::socket_base::do_not_route option(*do_not_route);
        socket->set_option(option);
    }

    if (reuse_address)
    {
        boost::asio::socket_base::reuse_address option(*reuse_address);
        socket->set_option(option);
    }
}
void UdpClient::listen ( void  ) [private, virtual]

Helper function that will listen for incoming data on the UDP connection for the client, specifically responses to data already sent.

Implements Udp.

Definition at line 254 of file UdpClient.cpp.

References Udp::host, Udp::port, Udp::receive_buffer, Udp::receive_handler(), Udp::remote_endpoint, socket, and Logger::warn().

Referenced by send().

{
    if (remote_endpoint && remote_endpoint.get())
        socket->async_receive_from(boost::asio::buffer(receive_buffer), *remote_endpoint,
                boost::bind(&UdpClient::receive_handler, this, _1, _2, socket, remote_endpoint, host, port));
    else
        Logger::warn("remote endpoint is null", port, host);
}
void UdpClient::resolve_handler ( const boost::system::error_code &  err,
udp::resolver::iterator  endpoint_iterator 
) [private]

I/O handler invoked when the remote host is resolved. This handler attempts to asynchronously establish a UDP connection with the remote host.

Parameters:
errThe error code encountered when trying to receive data, if any occurred. On success, this value is zero, and nonzero on error.
endpoint_iteratorAllows the client to iterate through resolvers to retry the connection if it initially fails to connect.

Definition at line 200 of file UdpClient.cpp.

References Logger::error(), flush(), Udp::host, Logger::info(), init_socket(), Udp::port, Udp::remote_endpoint, resolved_endpoint, resolver, and socket.

Referenced by send().

{
    if (err)
    {
        udp::resolver::iterator end;
        if (endpoint_iterator != end && err == boost::asio::error::host_not_found)
        {
            // If we haven't tried resolving using all resolvers, try with another
            udp::resolver::query query(host, boost::lexical_cast<string>(port));
            resolver->async_resolve(query, boost::bind(&UdpClient::resolve_handler, this, _1, endpoint_iterator++));
        }
        else
        { // We have tried and cannot recover, fail permanently
            string message("Error: resolving host " + host + ":" + boost::lexical_cast<string>(port) + " error was " + err.message());

            Logger::error(message, port, host);
            fire_error(message);

            return;
        }
    }

    fire_resolve();

    Logger::info("udpclient: resolved, going to send", port, host);

    // We succeeded resolving the endpoint, continue
    remote_endpoint = boost::make_shared<udp::endpoint>(*endpoint_iterator);

    if (!socket->is_open())
        init_socket();

    // This endpoint has now been initialized
    resolved_endpoint = true;

    flush();
}
void UdpClient::send ( const string &  data) [virtual]

Asynchronously sends data to the remote host to which this client is connected.

Parameters:
dataThe data to send across the wire

Implements Client.

Definition at line 137 of file UdpClient.cpp.

References Logger::error(), Udp::failed, flush(), Udp::host, Logger::info(), listen(), msgs_not_sent, Udp::pending_sends, Udp::pending_sends_mutex, Udp::port, queue_mtx, Udp::remote_endpoint, resolve_handler(), resolved_endpoint, resolver, Udp::send_handler(), Udp::should_close, socket, and Udp::using_ipv6.

Referenced by flush(), and send_bytes().

{
    if (failed)
    {
        // Log & fire an error
        string message("Trying to send from a UDP client that has permanently failed!");
        Logger::error(message, port, host);
        return;
    }

    if (should_close)
        return;

    Logger::info("udpclient: sending a msg of size: " + boost::lexical_cast<std::string>(msg.size()) + " which is: " + msg, port, host);

    pending_sends_mutex.lock();
    pending_sends++;
    pending_sends_mutex.unlock();

    if (!resolved_endpoint)
    {
        Logger::info("udpclient: resolving " + host + ":" + boost::lexical_cast<string>(port), port, host);

        queue_mtx.lock();
        msgs_not_sent.push(msg);
        queue_mtx.unlock();

        // Create a query to resolve this host & port
        if (using_ipv6 && *using_ipv6)
        {
            // Asynchronously resolve the remote host, and once the host is resolved, create a connection
            udp::resolver::query query(udp::v6(), host, boost::lexical_cast<string>(port),
                    boost::asio::ip::resolver_query_base::numeric_service);
            resolver->async_resolve(query, boost::bind(&UdpClient::resolve_handler, this, _1, _2));
        }
        else
        {
            // Asynchronously resolve the remote host, and once the host is resolved, create a connection
            udp::resolver::query query(udp::v4(), host, boost::lexical_cast<string>(port),
                    boost::asio::ip::resolver_query_base::numeric_service);
            resolver->async_resolve(query, boost::bind(&UdpClient::resolve_handler, this, _1, _2));
        }
    }
    else
    {
        flush(); // any pending messages? send them.

        Logger::info("udpclient: attempting to send " + boost::lexical_cast<string>(msg.size()) + " bytes of data: " + msg, port, host);

        // send the message
        if (socket->is_open() && remote_endpoint.get())
        {
            socket->async_send_to(boost::asio::buffer(msg.data(), msg.size()), *remote_endpoint,
                    boost::bind(&UdpClient::send_handler, this, _1, _2, msg, host, port));

            Logger::info("udpclient: (async) send called", port, host);

            if (!should_close)
                listen(); // listen for responses
        }
    }
}
void UdpClient::send_bytes ( const vector< byte > &  bytes) [virtual]

Asynchronously sends bytes to the remote host to which this client is connected.

Parameters:
bytesThe data to send across the wire

Implements Client.

Definition at line 125 of file UdpClient.cpp.

References UdpEvent::data, and send().

{
    string data;

    for (int i = 0; i < bytes.size(); i++)
    {
        data.push_back((unsigned char) bytes[i]);
    }

    send(data);
}
void UdpClient::shutdown ( ) [virtual]

Gracefully shutdown this UDP client, waiting until all sends have completed before freeing all resources for this UDP client and shutting down any open connections. This function is exposed the javascript API.

Implements NetworkObject.

Definition at line 107 of file UdpClient.cpp.

References close(), Udp::failed, Udp::pending_sends, Udp::pending_sends_mutex, and Udp::should_close.

{
    if (!failed)
    {
        should_close = true;

        pending_sends_mutex.lock();
        int pending_sends_now = pending_sends;
        pending_sends_mutex.unlock();

        if (pending_sends_now == 0)
        {
            fire_close();
            close();
        }
    }
}

Member Data Documentation

std::queue<string> UdpClient::msgs_not_sent [private]

Messages waiting to be sent, since the host hasn't been resolved yet.

Definition at line 159 of file UdpClient.h.

Referenced by flush(), and send().

boost::mutex UdpClient::queue_mtx [private]

Mutex for the message queue.

Definition at line 154 of file UdpClient.h.

Referenced by flush(), and send().

A flag representing whether the remote host for this UDP client has already been resolved.

Definition at line 164 of file UdpClient.h.

Referenced by resolve_handler(), and send().

boost::shared_ptr<udp::resolver> UdpClient::resolver [private]

Resolver object provided by boost to resolve the remote hostname and port

Definition at line 144 of file UdpClient.h.

Referenced by resolve_handler(), send(), and UdpClient().

boost::shared_ptr<udp::socket> UdpClient::socket [private]

A shared reference to the socket used to connect to the remote host

Definition at line 149 of file UdpClient.h.

Referenced by close(), init_socket(), listen(), resolve_handler(), send(), and UdpClient().


The documentation for this class was generated from the following files:
 All Classes Files Functions Variables Typedefs Friends Defines