SockIt
Public Member Functions | Protected Member Functions | Protected Attributes | Static Protected Attributes | Friends

Tcp Class Reference

#include <Tcp.h>

Inheritance diagram for Tcp:
TcpClient TcpServer

List of all members.

Public Member Functions

 Tcp (string host, int port, boost::asio::io_service &io_service)
virtual ~Tcp ()

Protected Member Functions

bool set_tcp_keepalive (boost::shared_ptr< tcp::socket > socket)
string bool_option_to_string (optional< bool > &arg, string iftrue, string iffalse)
template<class T >
string option_to_string (optional< T > &arg)
void parse_string_bool_arg (map< string, string > &options, string arg, optional< bool > &arg_value)
void parse_string_int_arg (map< string, string > &options, string arg, optional< int > &arg_value)
void parse_args (map< string, string > options)
void log_options ()
virtual void close ()=0
virtual void send_handler (const boost::system::error_code &error_code, std::size_t bytes_transferred, string data, string host, int port, boost::shared_ptr< tcp::socket > connection)
virtual void receive_handler (const boost::system::error_code &error_code, std::size_t bytes_transferred, boost::shared_ptr< tcp::socket > connection, string host, int port)
virtual void fire_error_event (const string &message)=0
virtual void fire_disconnect_event (const string &message)=0
virtual void fire_data_event (const string data, boost::shared_ptr< tcp::socket > connection)=0

Protected Attributes

boost::array< char, BUFFER_SIZEreceive_buffer
boost::asio::io_service & io_service
bool waiting_to_shutdown
optional< bool > using_ipv6
optional< bool > no_delay
optional< bool > do_not_route
optional< bool > keep_alive
optional< int > keep_alive_timeout
int active_jobs
boost::mutex active_jobs_mutex
string host
int port
std::set
< boost::system::error_code > 
disconnect_errors
bool failed

Static Protected Attributes

static const int BUFFER_SIZE = 4096
static const int MAX_DATA_SIZE = 65536

Friends

class TcpEvent

Detailed Description

Interface to abstract out the client-server model for use in the Event. Contains common handlers used by both TCP servers and clients.

See also:
Event

Definition at line 60 of file Tcp.h.


Constructor & Destructor Documentation

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

Builds a generic TCP object, and registers the 'shutdown' method on the API.

Parameters:
hostThe hostname for this TCP object. For clients, this represents the remote host's hostname, and for servers, defaults to 'localhost'.
portThe port for this TCP object, which for clients, represents the port of the remote host to which to connect, and for servers, represents the port to which to bind and listen for incoming connections.
io_serviceThe I/O service used for asynchronous I/O requests

Definition at line 10 of file Tcp.cpp.

References disconnect_errors.

                                                               :
    host(host), port(port), waiting_to_shutdown(false), active_jobs(0), io_service(ioService), using_ipv6(false), failed(false)
{
    // Collect the set of errors classified as 'disconnect' type errors
    disconnect_errors.insert(boost::asio::error::connection_reset);
    disconnect_errors.insert(boost::asio::error::eof);
    disconnect_errors.insert(boost::asio::error::connection_aborted);
    disconnect_errors.insert(boost::asio::error::operation_aborted);
}
virtual Tcp::~Tcp ( ) [inline, virtual]

Immediately calls the close function, freeing all resources for this TCP object and shutting down any open connections.

Definition at line 80 of file Tcp.h.

{}

Member Function Documentation

string Tcp::bool_option_to_string ( optional< bool > &  arg,
string  iftrue,
string  iffalse 
) [inline, protected]

Helper for logging options passed in.

Parameters:
argoptional bool option
iftrueif the arg has been set to true, return this
iffalseif the arg hasn't been set, or is set to false, return this

Definition at line 159 of file Tcp.cpp.

Referenced by log_options().

{
    if (arg && *arg)
        return iftrue;
    return iffalse;
}
virtual void Tcp::close ( ) [protected, pure virtual]

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

Implemented in TcpClient, and TcpServer.

Referenced by send_handler().

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

Helper to fire data event to javascript.

Parameters:
dataThe data received
connectionThe connection on which attempted to receive data.

Implemented in TcpClient, and TcpServer.

Referenced by receive_handler().

virtual void Tcp::fire_disconnect_event ( const string &  message) [protected, pure virtual]

Helper to fire an disconnect error event to javascript.

Parameters:
messageThe error message

Implemented in TcpClient, and TcpServer.

Referenced by receive_handler(), and send_handler().

virtual void Tcp::fire_error_event ( const string &  message) [protected, pure virtual]

Helper to fire an error event to javascript.

Parameters:
messageThe error message

Implemented in TcpClient, and TcpServer.

Referenced by receive_handler(), and send_handler().

void Tcp::log_options ( ) [protected]

Write to the log the options used to create this connection.

Definition at line 229 of file Tcp.cpp.

References bool_option_to_string(), do_not_route, host, Logger::info(), keep_alive, keep_alive_timeout, no_delay, port, and using_ipv6.

Referenced by TcpClient::init(), and parse_args().

{
    string options("These arguments were passed in: ");

    options.append(bool_option_to_string(using_ipv6, "ipv6, ", "ipv4, "));
    options.append(bool_option_to_string(do_not_route, "no routing, ", "use routing, "));
    options.append(bool_option_to_string(no_delay, "no delay, ", "allow delay, "));
    options.append(bool_option_to_string(keep_alive, "keep alive", "don't keep alive"));
    options.append(", keep alive timeout is ");
    options.append(option_to_string<int> (keep_alive_timeout));

    Logger::info(options, port, host);
}
template<class T >
string Tcp::option_to_string ( optional< T > &  arg) [inline, protected]

Helper for logging options passed in.

Parameters:
argthe optional argument

Definition at line 167 of file Tcp.cpp.

{
    if (arg)
        return boost::lexical_cast<string>(*arg);
    return string("unset");
}
void Tcp::parse_args ( map< string, string >  options) [protected]

Parses any options (like whether or use IPv6 or IPv4) from the options. Supported options currently include:

ipv6 if true, use ipv6. otherwise use ipv4. keep alive allow the socket to send keep-alives. do not route option to force TCP to use local interfaces only, prevents routing no delay option to disable Nagle algorithm for possibly improved performance

Parameters:
optionsA map of options to values.

Definition at line 197 of file Tcp.cpp.

References do_not_route, keep_alive, keep_alive_timeout, log_options(), no_delay, parse_string_bool_arg(), parse_string_int_arg(), and using_ipv6.

Referenced by TcpClient::TcpClient(), and TcpServer::TcpServer().

{
    map<string, string>::iterator it;
    map<string, string> transformed_options;

    string t("true");
    string f("false");

    // transform the entire map to lower case
    for (it = options.begin(); it != options.end(); it++)
    {
        string k = it->first;
        string v = it->second;

        std::transform(k.begin(), k.end(), k.begin(), ::tolower);
        std::transform(v.begin(), v.end(), v.begin(), ::tolower);

        k.erase(std::remove_if(k.begin(), k.end(), ::isspace), k.end());
        v.erase(std::remove_if(v.begin(), v.end(), ::isspace), v.end());

        transformed_options.insert(std::pair<string, string>(k, v));
    }

    parse_string_bool_arg(transformed_options, "ipv6", using_ipv6);
    parse_string_bool_arg(transformed_options, "donotroute", do_not_route);
    parse_string_bool_arg(transformed_options, "keepalive", keep_alive);
    parse_string_bool_arg(transformed_options, "nodelay", no_delay);
    parse_string_int_arg(transformed_options, "keepalivetimeout", keep_alive_timeout);

    log_options();
}
void Tcp::parse_string_bool_arg ( map< string, string > &  options,
string  arg,
optional< bool > &  arg_value 
) [inline, protected]

Helper for parsing boolean arguments

Parameters:
optionsA map of strings to string representing the options passed in and their values
argThe specific option to check for
arg_valueThis will hold the value of the argument, if found.

Definition at line 174 of file Tcp.cpp.

Referenced by parse_args().

{
    map<string, string>::iterator it;

    if ((it = options.find(arg)) != options.end())
    {
        if (it->second == std::string("true"))
            arg_value.reset(true);
        if (it->second == std::string("false"))
            arg_value.reset(false);
    }
}
void Tcp::parse_string_int_arg ( map< string, string > &  options,
string  arg,
optional< int > &  arg_value 
) [inline, protected]

Helper for parsing integer arguments

Parameters:
optionsA map of strings to string representing the options passed in and their values
argThe specific option to check for
arg_valueThis will hold the value of the argument, if found.

Definition at line 187 of file Tcp.cpp.

Referenced by parse_args().

{
    map<string, string>::iterator it;

    if ((it = options.find(arg)) != options.end())
    {
        arg_value.reset(boost::lexical_cast<int>(it->second));
    }
}
void Tcp::receive_handler ( const boost::system::error_code &  error_code,
std::size_t  bytes_transferred,
boost::shared_ptr< tcp::socket >  connection,
string  host,
int  port 
) [protected, virtual]

Handler invoked when some data has been received.

Parameters:
error_codeThe error code encountered when trying to receive data, if any occurred. On success, this value is zero, and nonzero on error.
bytes_transferredThe number of bytes successfully received over the connection.
connectionThe connection on which attempted to receive data.
hostThe hostname for this TCP object
portThe port for this TCP object

Reimplemented in TcpServer.

Definition at line 88 of file Tcp.cpp.

References disconnect_errors, Logger::error(), fire_data_event(), fire_disconnect_event(), fire_error_event(), Logger::info(), receive_buffer, and Logger::warn().

Referenced by TcpClient::connect_handler().

{
    // Check for errors
    if (error_code)
    {
        // Check for disconnection errors
        if (disconnect_errors.find(error_code) != disconnect_errors.end())
        {
            if (error_code == boost::asio::error::operation_aborted)
            {
                Logger::info("TCP send failed, aborted", port, host);
                return;
            }
            else
            {
                string message("TCP receive failed, disconnected, error message: '" + error_code.message() + "'");
                Logger::info(message, port, host);
                fire_disconnect_event(message);
                return;
            }
        }

        // Otherwise, this is a more serious error, fail and log the error
        string message(
                "TCP receive failed, error message: '" + error_code.message() + "', value '" + boost::lexical_cast<string>(
                        error_code.value()) + "'");
        Logger::error(message, port, host);
        fire_error_event(message);

        // Shutdown the socket we're receiving from
        if (connection.get() && connection->is_open())
        {
            try
            {
                connection->shutdown(connection->shutdown_receive);
            }
            catch (...)
            {
                Logger::warn("TCP receive failed, shutdown improperly, proceeding anyway", port, host);
            }
        }

        return;
    }

    // Pull out the data we received, and fire a data received event
    string data = string(receive_buffer.c_array(), bytes_transferred);

    // Log success
    string message(
            "Successfully received all " + boost::lexical_cast<string>(bytes_transferred) + " bytes of " + boost::lexical_cast<string>(
                    bytes_transferred) + " total bytes. Data: '" + data + "'");

    Logger::info(message, port, host);

    try
    {
        fire_data_event(data, connection);
    }
    catch (const boost::bad_weak_ptr &p)
    {
        Logger::error("Event is going out of scope", port, host);
    }

    // Try to receive more data
    if (connection.get())
        connection->async_receive(boost::asio::buffer(receive_buffer),
                boost::bind(&Tcp::receive_handler, this, _1, _2, connection, host, port));
}
void Tcp::send_handler ( const boost::system::error_code &  error_code,
std::size_t  bytes_transferred,
string  data,
string  host,
int  port,
boost::shared_ptr< tcp::socket >  connection 
) [protected, virtual]

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

Parameters:
error_codeThe error code encountered when trying to send data, if any occurred. On success, this value is zero, and nonzero on error.
bytes_transferredThe number of bytes successfully sent over the connection.
dataThe data to be sent.
hostThe hostname for this TCP object
portThe port for this TCP object
connectionThe connection this data was sent on

Definition at line 20 of file Tcp.cpp.

References active_jobs, active_jobs_mutex, close(), disconnect_errors, Logger::error(), fire_disconnect_event(), fire_error_event(), Logger::info(), waiting_to_shutdown, and Logger::warn().

Referenced by TcpClient::flush(), TcpEvent::send(), and TcpClient::send().

{
    // Check the error code
    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)
            {
                Logger::info("TCP send failed, aborted", port, host);
            }
            else
            {
                string message("TCP send failed, disconnected, error message: '" + error_code.message() + "'");
                Logger::info(message, port, host);
                fire_disconnect_event(message);
            }
            return;
        }

        string message(
                "TCP send failed, error message '" + error_code.message() + "', error code '" + boost::lexical_cast<string>(
                        error_code.value()) + "' was encountered");
        Logger::error(message, port, host);
        fire_error_event(message);
        return;
    }

    if (bytes_transferred != data.size())
    {
        // Get the rest of the message, and try resending it
        string rest_of_buffer(((char*) data.data()) + bytes_transferred, data.size() - bytes_transferred);

        active_jobs_mutex.lock();
        active_jobs++;
        active_jobs_mutex.unlock();

        connection->async_send(boost::asio::buffer(rest_of_buffer.data(), rest_of_buffer.size()),
                boost::bind(&Tcp::send_handler, this, _1, _2, rest_of_buffer, host, port, connection));

        // Log that we had to do this
        // We could not send all of the message, fire an error and log it
        string message(
                string("TCP send failed, only ") + boost::lexical_cast<string>(bytes_transferred) + " of " + boost::lexical_cast<string>(
                        data.size()) + " total bytes were sent");
        Logger::warn(message, port, host);
        return;
    }
    else
    {
        string message("TCP send succeeded, sent " + boost::lexical_cast<string>(bytes_transferred) + " bytes, data is: " + data);
        Logger::info(message, port, host);
    }

    // Check to see if this is for the last send to complete, and if we're waiting to shutdown
    active_jobs_mutex.lock();
    active_jobs--;
    active_jobs_mutex.unlock();
    int current_jobs = active_jobs;
    if (waiting_to_shutdown && current_jobs == 0)
    {
        close();
    }
}
bool Tcp::set_tcp_keepalive ( boost::shared_ptr< tcp::socket >  socket) [protected]

Helper for setting tcp keep alive options (varies from platform to platform).

Parameters:
socketThe boost socket to set the tcp keep alive options on
Returns:
true if successful, otherwise false.

Definition at line 243 of file Tcp.cpp.

References Logger::error(), host, keep_alive_timeout, and port.

Referenced by TcpServer::init_socket(), and TcpClient::init_socket().

{
#ifdef __UNIX__

    // For *n*x systems
    int native_fd = socket->native();
    int timeout = *keep_alive_timeout;
    int intvl = 1;
    int probes = 10;
    int on = 1;

    int ret_keepalive = setsockopt(native_fd, SOL_SOCKET, SO_KEEPALIVE, (void*) &on, sizeof(int));
    int ret_keepidle = setsockopt(native_fd, SOL_TCP, TCP_KEEPIDLE, (void*) &timeout, sizeof(int));
    int ret_keepintvl = setsockopt(native_fd, SOL_TCP, TCP_KEEPINTVL, (void*) &intvl, sizeof(int));
    int ret_keepinit = setsockopt(native_fd, SOL_TCP, TCP_KEEPCNT, (void*) &probes, sizeof(int));

    if(ret_keepalive || ret_keepidle || ret_keepintvl || ret_keepinit)
    {
        string message("Failed to enable keep alive on TCP client socket!");
        Logger::error(message, port, host);
        return false;
    }

#elif defined(__OSX__)

    int native_fd = socket->native();
    int timeout = *keep_alive_timeout;
    int intvl = 1;
    int on = 1;

    // Set the timeout before the first keep alive message
    int ret_sokeepalive = setsockopt(native_fd, SOL_SOCKET, SO_KEEPALIVE, (void*) &on, sizeof(int));
    int ret_tcpkeepalive = setsockopt(native_fd, IPPROTO_TCP, TCP_KEEPALIVE, (void*) &timeout, sizeof(int));
    int ret_tcpkeepintvl = setsockopt(native_fd, IPPROTO_TCP, TCP_CONNECTIONTIMEOUT, (void*) &intvl, sizeof(int));

    if(ret_sokeepalive || ret_tcpkeepalive || ret_tcpkeepintvl)
    {
        string message("Failed to enable keep alive on TCP client socket!");
        Logger::error(message, port, host);
        return false;
    }

#else
    // Partially supported on windows
    struct tcp_keepalive keepalive_options;
    keepalive_options.onoff = 1;
    keepalive_options.keepalivetime = *keep_alive_timeout * 1000;
    keepalive_options.keepaliveinterval = 2000;

    BOOL keepalive_val = true;
    SOCKET native = socket->native();
    DWORD bytes_returned;

    int ret_keepalive = setsockopt(native, SOL_SOCKET, SO_KEEPALIVE, (const char *) &keepalive_val, sizeof(keepalive_val));
    int ret_iotcl = WSAIoctl(native, SIO_KEEPALIVE_VALS, (LPVOID) & keepalive_options, (DWORD) sizeof(keepalive_options), NULL, 0,
            (LPDWORD) & bytes_returned, NULL, NULL);

    if (ret_keepalive || ret_iotcl)
    {
        string message("Failed to set keep alive timeout on TCP client socket!");
        Logger::error(message, port, host);
        return false;
    }
#endif
    return true;
}

Friends And Related Function Documentation

friend class TcpEvent [friend]

Definition at line 82 of file Tcp.h.


Member Data Documentation

int Tcp::active_jobs [protected]

The current count of active jobs on the socket

Definition at line 254 of file Tcp.h.

Referenced by TcpEvent::send(), TcpClient::send(), send_handler(), TcpServer::shutdown(), and TcpClient::shutdown().

boost::mutex Tcp::active_jobs_mutex [protected]

A mutex around the current count of active jobs on the socket

Definition at line 259 of file Tcp.h.

Referenced by TcpClient::send(), send_handler(), and TcpClient::shutdown().

const int Tcp::BUFFER_SIZE = 4096 [static, protected]

A constant representing the size of the buffer in which to receive data.

Definition at line 203 of file Tcp.h.

std::set<boost::system::error_code> Tcp::disconnect_errors [protected]

The set of boost::system::error_code errors considered to be 'disconnection' errors.

See also:
boost::system::error_code

Definition at line 276 of file Tcp.h.

Referenced by TcpServer::accept_handler(), TcpClient::connect_handler(), receive_handler(), TcpClient::resolve_handler(), send_handler(), and Tcp().

optional<bool> Tcp::do_not_route [protected]

Option to force TCP to use local interfaces only, prevents routing

Definition at line 239 of file Tcp.h.

Referenced by TcpServer::init_socket(), TcpClient::init_socket(), log_options(), and parse_args().

bool Tcp::failed [protected]

A flag that is set to true whenever this TCP client or server encounters an unrecoverable error and cannot continue.

Definition at line 281 of file Tcp.h.

Referenced by TcpServer::init(), TcpClient::init(), TcpClient::resolve_handler(), TcpEvent::send(), TcpClient::send(), TcpServer::shutdown(), TcpClient::shutdown(), TcpServer::start_listening(), and TcpClient::TcpClient().

string Tcp::host [protected]
boost::asio::io_service& Tcp::io_service [protected]

The I/O service for perform nonblocking actions

Definition at line 219 of file Tcp.h.

Referenced by TcpServer::init(), and TcpServer::start_listening().

optional<bool> Tcp::keep_alive [protected]

Allow the socket to send keep-alives

Definition at line 244 of file Tcp.h.

Referenced by TcpServer::init_socket(), TcpClient::init_socket(), log_options(), and parse_args().

optional<int> Tcp::keep_alive_timeout [protected]

Allow setting the socket's keep-alive timeout

Definition at line 249 of file Tcp.h.

Referenced by TcpServer::init_socket(), TcpClient::init_socket(), log_options(), parse_args(), and set_tcp_keepalive().

const int Tcp::MAX_DATA_SIZE = 65536 [static, protected]

A constant representing the maximum number of bytes that a TCP message can be in boost. If our message is larger than this, keep trying to send it until all successful bytes were sent.

Definition at line 209 of file Tcp.h.

optional<bool> Tcp::no_delay [protected]

Option to disable Nagle algorithm for possibly improved performance

Definition at line 234 of file Tcp.h.

Referenced by TcpServer::init_socket(), TcpClient::init_socket(), log_options(), and parse_args().

int Tcp::port [protected]
boost::array<char, BUFFER_SIZE> Tcp::receive_buffer [protected]

A buffer for receiving data from the remote host.

Definition at line 214 of file Tcp.h.

Referenced by TcpServer::accept_handler(), TcpClient::connect_handler(), and receive_handler().

optional<bool> Tcp::using_ipv6 [protected]

Flag to say whether or not this TCP object uses IPv6

Definition at line 229 of file Tcp.h.

Referenced by TcpServer::init(), TcpClient::init(), log_options(), parse_args(), and TcpClient::resolve_handler().

bool Tcp::waiting_to_shutdown [protected]

A flag to say whether or not this server is waiting to shutdown

Definition at line 224 of file Tcp.h.

Referenced by TcpServer::accept_handler(), TcpServer::close(), TcpClient::close(), send_handler(), TcpServer::shutdown(), and TcpClient::shutdown().


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