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

TcpServer Class Reference

#include <TcpServer.h>

Inheritance diagram for TcpServer:
Tcp Server NetworkObject

List of all members.

Public Member Functions

 TcpServer (int port, boost::asio::io_service &io_service)
 TcpServer (int port, boost::asio::io_service &io_service, map< string, string > options)
virtual ~TcpServer ()
virtual void start_listening ()
virtual void shutdown ()
virtual int get_port ()
 FB_JSAPI_EVENT (disconnect, 1,(const string &))
 FB_JSAPI_EVENT (connect, 0,())

Protected Member Functions

void receive_handler (const boost::system::error_code &error_code, std::size_t bytesTransferred, boost::shared_ptr< tcp::socket > connection, string host, int port)
virtual void fire_error_event (const string &message)
virtual void fire_disconnect_event (const string &message)
virtual void fire_data_event (const string data, boost::shared_ptr< tcp::socket > connection)
virtual void close ()

Private Member Functions

void init ()
void init_socket (boost::shared_ptr< tcp::socket > connection)
 TcpServer (const TcpServer &other)
void accept_handler (const boost::system::error_code &error_code, boost::shared_ptr< tcp::socket > connection, string host, int port)

Private Attributes

boost::shared_ptr< tcp::acceptor > acceptor
set< boost::shared_ptr
< tcp::socket > > 
connections

Detailed Description

This class represents a TCP server, which inherits basic TCP handling functionality from Tcp, and defines additional functionality to bind to a port and accept incoming connections.

Definition at line 24 of file TcpServer.h.


Constructor & Destructor Documentation

TcpServer::TcpServer ( int  port,
boost::asio::io_service &  io_service 
)

Builds a TCP server to listen on the specified port, but does not start the server listening on it. Using this constructor uses IPv4, given an I/O service to use for asynchronous I/O.

Parameters:
portThe port on which the server should listen
io_serviceThe I/O service to use for background I/O requests

Definition at line 10 of file TcpServer.cpp.

References init().

                                                               :
    Tcp("SERVER", port, io_service)
{
    init();
}
TcpServer::TcpServer ( int  port,
boost::asio::io_service &  io_service,
map< string, string >  options 
)

Builds a TCP server to listen on the specified port, but does not start the server listening on it. Using this constructor creates a server using IPv6, given an I/O service to use for asynchronous I/O.

Parameters:
portThe port on which the server should listen
io_serviceThe I/O service to use for background I/O requests
optionsA map of options specifying the behavior of the socket

Definition at line 16 of file TcpServer.cpp.

References init(), and Tcp::parse_args().

                                                                                            :
    Tcp("SERVER", port, io_service)
{
    parse_args(options);
    init();
}
TcpServer::~TcpServer ( ) [virtual]

Deconstructs this TCP server, by immediately ceasing to accept incoming connections, shutdown all necessary resources.

Definition at line 23 of file TcpServer.cpp.

References close().

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

Disallows copying a TCP server


Member Function Documentation

void TcpServer::accept_handler ( const boost::system::error_code &  error_code,
boost::shared_ptr< tcp::socket >  connection,
string  host,
int  port 
) [private]

Handler invoked when a new connection is made to this server. This handler tries to start receiving data from the new incoming connection if there was no error accepting the connection.

Parameters:
error_codeThe error code encountered when trying to receive data, if any occurred. On success, this value is zero, and nonzero on error.
connectionThe new connection created by this accept, from which this function will attempt to receive data.
hostThe host from which this accept was attempted
portThe port from which this accept was attempted

Definition at line 218 of file TcpServer.cpp.

References Tcp::disconnect_errors, Logger::error(), Logger::info(), init_socket(), Tcp::receive_buffer, receive_handler(), start_listening(), Tcp::waiting_to_shutdown, and Logger::warn().

Referenced by start_listening().

{
    // Log error & return if there is an error
    if (error_code)
    {
        // Check for disconnection errors
        std::set<boost::system::error_code>::iterator find_result = disconnect_errors.find(error_code);
        if (find_result != disconnect_errors.end())
        {
            if (error_code == boost::asio::error::operation_aborted)
            {
                // If we're waiting to shutdown, this is part of the normal process
                if(waiting_to_shutdown)
                {
                    Logger::info("TCP server stopped listening for new connections", port, host);
                }
                else
                {
                    Logger::warn("TCP accept was aborted", port, host);
                }
            }
            else
            {
                string message("TCP accept failed, disconnected: '" + error_code.message() + "'");
                Logger::warn(message, port, host);
                fire_disconnect(message);
            }
            return;
        }

        string message("Error accepting incoming connection: '" + error_code.message() + "'");
        Logger::error(message, port, host);
        fire_error(message);
        return;
    }

    // Initialize the socket options before we start using it
    init_socket(connection);

    // Log that we've successfully accepted a new connection, and fire the 'onconnect' event
    string message("TCP server accepted new connection from " + connection->remote_endpoint().address().to_string() + " port "
            + boost::lexical_cast<string>(connection->remote_endpoint().port()));
    Logger::info(message, port, host);
    fire_connect();

    if (connection.get())
        connection->async_receive(boost::asio::buffer(receive_buffer),
                boost::bind(&TcpServer::receive_handler, this, _1, _2, connection, host, port));

    // Start listening for new connections, if we're not waiting to close
    if (!waiting_to_shutdown)
    {
        start_listening();
    }
}
void TcpServer::close ( ) [protected, virtual]

Closes down this TCP server immediately, by immediately ceasing to accept incoming connections, shutdown all necessary resources.

Implements Tcp.

Definition at line 28 of file TcpServer.cpp.

References acceptor, connections, Tcp::host, Tcp::port, Tcp::waiting_to_shutdown, and Logger::warn().

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

{
    // Shutdown the IO service, cancel any transfers on the socket, and close the socket
    waiting_to_shutdown = true;

    set<boost::shared_ptr<tcp::socket> >::iterator it;
    for(it = connections.begin(); it != connections.end(); it++)
    {
        try
        {
            if((*it) && (*it).get() && (*it)->is_open())
            {
                (*it)->close();
            }
        }
        catch(boost::system::error_code &e)
        {
            Logger::warn("Error in TcpServer deconstructor: " + e.message(), port, host);
        }
        catch(std::exception &er)
        {
            Logger::warn("Error in TcpServer deconstructor: " + std::string(er.what()), port, host);
        }
        catch(...)
        {
            Logger::warn("Error occured that could not be caught");
        }
    }

    connections.clear();

    if (acceptor && acceptor->is_open())
    {
        acceptor->close();
    }
    else
    {
        // Don't fire an error, otherwise the plugin will crash
        string message("Could not cleanly shut down acceptor in TCP server, desctructing anyways");
        Logger::warn(message, port, host);
    }
}
TcpServer::FB_JSAPI_EVENT ( disconnect  ,
,
(const string &)   
)

The javascript event fired on a disconnect-type network error. This is fired on the following boost errors:

  • boost::asio::error::connection_reset
  • boost::asio::error::eof
  • boost::asio::error::connection_aborted
  • boost::asio::error::operation_aborted
TcpServer::FB_JSAPI_EVENT ( connect  ,
,
()   
)

The javascript event fired once a client has connected to its remote endpoint, or once a server has accepted a connection successfully (but has not yet receieved data), in this class, the former.

void TcpServer::fire_data_event ( const string  data,
boost::shared_ptr< tcp::socket >  connection 
) [protected, virtual]

Helper to fire data event to javascript.

Parameters:
dataThe data received
connectionThe connection on which to reply to the data

Implements Tcp.

Definition at line 299 of file TcpServer.cpp.

{
    fire_data(boost::make_shared<TcpEvent>(this, connection, data));
}
void TcpServer::fire_disconnect_event ( const string &  message) [protected, virtual]

Helper to fire an disconnect error event to javascript.

Parameters:
messageThe error message

Implements Tcp.

Definition at line 294 of file TcpServer.cpp.

{
    fire_disconnect(message);
}
void TcpServer::fire_error_event ( const string &  message) [protected, virtual]

Helper to fire an error event to javascript.

Parameters:
messageThe error message

Implements Tcp.

Definition at line 289 of file TcpServer.cpp.

{
    fire_error(message);
}
int TcpServer::get_port ( void  ) [virtual]

Returns the port on which this server listens

Implements Server.

Definition at line 284 of file TcpServer.cpp.

References Tcp::port.

{
    return port;
}
void TcpServer::init ( ) [private]

Helper function to initialize the acceptor. If this was not successfully initialized, fail is true.

Definition at line 71 of file TcpServer.cpp.

References acceptor, Logger::error(), Tcp::failed, Tcp::host, Tcp::io_service, Tcp::port, and Tcp::using_ipv6.

Referenced by TcpServer().

{
    // Bind the acceptor to the correct port & set the options on this acceptor
    try
    {
        if (using_ipv6 && *using_ipv6)
        {
            acceptor = boost::shared_ptr<tcp::acceptor>(new tcp::acceptor(io_service, tcp::endpoint(tcp::v6(), port)));
        }
        else
        {
            acceptor = boost::shared_ptr<tcp::acceptor>(new tcp::acceptor(io_service, tcp::endpoint(tcp::v4(), port)));
        }
    }
    catch (boost::system::system_error &e)
    {
        // Catch this error, and fail gracefully
        string message(string("Caught error initializing TCP server: '") + e.what() + "'");
        Logger::error(message, port, host);

        // Stop this server from ever doing anything again
        failed = true;
    }

    // Check that acceptor was created successfully
    if (!acceptor.get())
    {
        // Fail gracefully and stop this server from ever doing anything again
        string message("Failed to initialized TCP server acceptor");
        Logger::error(message, port, host);
        failed = true;
    }
}
void TcpServer::init_socket ( boost::shared_ptr< tcp::socket >  connection) [private]

Initialize the properties of this socket

Definition at line 105 of file TcpServer.cpp.

References Tcp::do_not_route, Tcp::keep_alive, Tcp::keep_alive_timeout, Tcp::no_delay, and Tcp::set_tcp_keepalive().

Referenced by accept_handler().

{
    // Set the socket options for this client's TCP socket
    if (do_not_route)
    {
        boost::asio::socket_base::do_not_route option(*do_not_route);
        connection->set_option(option);
    }

    // Toggle keep alive (enabled/disabled)
    if (keep_alive)
    {
        boost::asio::socket_base::keep_alive option(*keep_alive);
        connection->set_option(option);
    }
    if (no_delay)
    {
        boost::asio::ip::tcp::no_delay option(*no_delay);
        connection->set_option(option);
    }

    if (keep_alive_timeout)
    {
        // Set the TCP keep-alive timeout - ignores return value
        set_tcp_keepalive(connection);
    }
}
void TcpServer::receive_handler ( const boost::system::error_code &  error_code,
std::size_t  bytesTransferred,
boost::shared_ptr< tcp::socket >  connection,
string  host,
int  port 
) [protected, virtual]

Inherited from Tcp. Handler invoked when the data has been sent (or sending terminated in error).

Reimplemented from Tcp.

Definition at line 275 of file TcpServer.cpp.

References connections.

Referenced by accept_handler().

{
    Tcp::receive_handler(error_code, bytesTransferred, connection, host, port);

    if(connection && connection.get() && !connection->is_open())
        connections.erase(connection);
}
void TcpServer::shutdown ( ) [virtual]

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

Implements NetworkObject.

Definition at line 199 of file TcpServer.cpp.

References Tcp::active_jobs, close(), Logger::error(), Tcp::failed, Tcp::host, Tcp::port, and Tcp::waiting_to_shutdown.

{
    if(!failed)
    {
        waiting_to_shutdown = true;
        if (active_jobs == 0)
        {
            fire_close();
            close();
        }
    }
    else
    {
        // Log & fire an error
        string message("Trying to shutdown the TCP server, but the server has permanently failed!");
        Logger::error(message, port, host);
    }
}
void TcpServer::start_listening ( ) [virtual]

Called to start the the server listening for the first time, fires the 'open' event, and is exposed to the javascript. This should only be called once, and starts the server listening for incoming connections.

Implements Server.

Definition at line 164 of file TcpServer.cpp.

References accept_handler(), acceptor, connections, Logger::error(), Tcp::failed, Tcp::host, Logger::info(), Tcp::io_service, Tcp::port, and socket_deallocate().

Referenced by accept_handler().

{
    if(failed)
    {
        // Log & fire an error
        string message("Trying to start the server listening, but the server has permanently failed!");
        Logger::error(message, port, host);
    }

    // Log listening
    Logger::info("TCP server about to start listening for incoming connections on port "
            + boost::lexical_cast<string>(port), port, host);

    // Prepare to accept a new connection and asynchronously accept new incoming connections
    boost::shared_ptr < tcp::socket > connection(new tcp::socket(io_service), socket_deallocate);
    connections.insert(connection);

    // Try to accept any new connection
    if(acceptor.get())
    {
        acceptor->async_accept(*connection, boost::bind(&TcpServer::accept_handler, this, _1, connection, host, port));
    }
    else
    {
        // Fail gracefully and stop this server from ever doing anything again
        string message("TCP server failed to accept, acceptor invalid");
        Logger::error(message, port, host);
        failed = true;
        return;
    }

    // Callback acknowledging that the server has opened
    fire_open();
}

Member Data Documentation

boost::shared_ptr<tcp::acceptor> TcpServer::acceptor [private]

The acceptor for incoming connections for this server

Definition at line 159 of file TcpServer.h.

Referenced by close(), init(), and start_listening().

set<boost::shared_ptr<tcp::socket> > TcpServer::connections [private]

A set of established connections.

Definition at line 162 of file TcpServer.h.

Referenced by close(), receive_handler(), and start_listening().


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