SockIt
|
#include <TcpClient.h>
Public Member Functions | |
TcpClient (const string &host, int port, boost::asio::io_service &io_service) | |
TcpClient (const string &host, int port, boost::asio::io_service &io_service, map< string, string > options) | |
virtual | ~TcpClient () |
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 () |
FB_JSAPI_EVENT (disconnect, 1,(const string &)) | |
FB_JSAPI_EVENT (connect, 0,()) | |
Protected Member Functions | |
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 | |
TcpClient (const TcpClient &other) | |
void | init () |
void | init_socket () |
void | resolve_handler (const boost::system::error_code &error_code, tcp::resolver::iterator endpoint_iterator) |
void | connect_handler (const boost::system::error_code &error_code, tcp::resolver::iterator endpoint_iterator) |
void | listen () |
void | flush () |
Private Attributes | |
boost::shared_ptr< tcp::socket > | connection |
boost::shared_ptr< tcp::resolver > | resolver |
bool | connected |
boost::mutex | connected_mutex |
queue< string > | data_queue |
boost::mutex | data_queue_mutex |
This class represents a TCP client, which inherits basic TCP handling functionality from Tcp
, and defines additional functionality to resolve and connect to a remote host.
Definition at line 26 of file TcpClient.h.
TcpClient::TcpClient | ( | const string & | host, |
int | port, | ||
boost::asio::io_service & | io_service | ||
) |
Builds a TCP client to connect to a specified remote host and port, and begins asynchronously resolving and connecting to the remote host, given an I/O service to asynchronously perform I/O requests.
host | The hostname of the remote host to which this client will connect |
port | The port of the remote host to which this client will connect |
io_service | The I/O service to use to perform asynchronous I/O requests |
Definition at line 10 of file TcpClient.cpp.
References connection, Logger::error(), Tcp::failed, init(), and resolver.
: Tcp(host, port, io_service), resolver(new tcp::resolver(io_service)), connection(new tcp::socket(io_service)) { // Check that the connection and resolver are valid, and fail gracefully if they are not if (!resolver.get() || !connection.get()) { failed = true; string message("Failed to initialize TCP client, failed to initialize properly"); Logger::error(message, port, host); fire_error(message); return; } init(); }
TcpClient::TcpClient | ( | const string & | host, |
int | port, | ||
boost::asio::io_service & | io_service, | ||
map< string, string > | options | ||
) |
Builds a TCP client to connect to a specified remote host and port, and begins asynchronously resolving and connecting to the remote host, given an I/O service to asynchronously perform I/O requests.
host | The hostname of the remote host to which this client will connect |
port | The port of the remote host to which this client will connect |
io_service | The I/O service to use to perform asynchronous I/O requests |
options | A map of options specifying the behavior of the socket |
Definition at line 26 of file TcpClient.cpp.
References connection, Logger::error(), Tcp::failed, init(), Tcp::parse_args(), and resolver.
: Tcp(host, port, io_service), resolver(new tcp::resolver(io_service)), connection(new tcp::socket(io_service)) { // Check that the connection and resolver are valid, and fail gracefully if they are not if (!resolver.get() || !connection.get()) { failed = true; string message("Failed to initialize TCP client, failed to initialize properly"); Logger::error(message, port, host); fire_error(message); return; } parse_args(options); init(); }
TcpClient::~TcpClient | ( | ) | [virtual] |
Deconstructs a TCP client, immediately calling close
to shutdown this client's socket and stop listening for responses.
Definition at line 114 of file TcpClient.cpp.
References close().
{ close(); }
TcpClient::TcpClient | ( | const TcpClient & | other | ) | [private] |
Disallows copying a TCP client
void TcpClient::close | ( | ) | [protected, virtual] |
Immediately cancels any pending operations and closes this client's socket.
Implements Tcp.
Definition at line 119 of file TcpClient.cpp.
References connection, Tcp::host, Tcp::port, resolver, Tcp::waiting_to_shutdown, and Logger::warn().
Referenced by shutdown(), and ~TcpClient().
{ waiting_to_shutdown = true; resolver->cancel(); // Shutdown the IO service, cancel any transfers on the socket, and close the socket if (connection->is_open()) { try { connection->shutdown(connection->shutdown_both); } catch (...) { Logger::warn("Socket shutdown improperly, proceeding anyway", port, host); } connection->close(); } else { Logger::warn("Failed to cleanly shutdown TCP client connection, continuing anyways", port, host); } }
void TcpClient::connect_handler | ( | const boost::system::error_code & | error_code, |
tcp::resolver::iterator | endpoint_iterator | ||
) | [private] |
I/O handler invoked when this client has attempted to connect to its remote host. If the connection failed, this handler will reattempt the connection by using another resolver if possible, and otherwise fail permanently.
error_code | The error code encountered when trying to receive data, if any occurred. On success, this value is zero, and nonzero on error. |
endpoint_iterator | Allows the client to iterate through resolvers to retry the connection if it initially fails to connect. |
Definition at line 278 of file TcpClient.cpp.
References connected, connected_mutex, connection, Tcp::disconnect_errors, Logger::error(), flush(), Tcp::host, Logger::info(), Tcp::port, Tcp::receive_buffer, Tcp::receive_handler(), resolve_handler(), resolver, and Logger::warn().
Referenced by resolve_handler().
{ // If there was an error to connect, log the error and abort connection 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::warn("TCP connect was aborted"); return; } else { string message("TCP connect failed, disconnected: '" + error_code.message() + "'"); Logger::warn(message, port, host); fire_disconnect(message); return; } } // Check if this was not the last possible connection in the iterator tcp::resolver::iterator end; if (endpoint_iterator != end && error_code == boost::asio::error::host_not_found) { // Create a query to resolve this host & port tcp::resolver::query query(host, boost::lexical_cast<string>(port)); // Try the next possible endpoint resolver->async_resolve(query, boost::bind(&TcpClient::resolve_handler, this, _1, endpoint_iterator++)); } else { // If we've tried every possible endpoint, fail permanently string message("Failed to connect to host, with message: '" + error_code.message() + "'"); Logger::error(message, port, host); fire_error(message); return; } } // Log success, and record that we are now connected Logger::info("Connection established to host", port, host); fire_connect(); // Start receiving data on this connection connection->async_receive(boost::asio::buffer(receive_buffer), boost::bind(&TcpClient::receive_handler, this, _1, _2, connection, host, port)); // Flush data from the queue if necessary flush(); connected_mutex.lock(); connected = true; connected_mutex.unlock(); }
TcpClient::FB_JSAPI_EVENT | ( | disconnect | , |
1 | , | ||
(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
TcpClient::FB_JSAPI_EVENT | ( | connect | , |
0 | , | ||
() | |||
) |
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 TcpClient::fire_data_event | ( | const string | data, |
boost::shared_ptr< tcp::socket > | connection | ||
) | [protected, virtual] |
Helper to fire data event to javascript.
data | The data received |
connection | The connection on which to reply to the data |
Implements Tcp.
Definition at line 378 of file TcpClient.cpp.
{ fire_data(boost::make_shared<TcpEvent>(this, connection, data)); }
void TcpClient::fire_disconnect_event | ( | const string & | message | ) | [protected, virtual] |
Helper to fire an disconnect error event to javascript.
message | The error message |
Implements Tcp.
Definition at line 373 of file TcpClient.cpp.
{ fire_disconnect(message); }
void TcpClient::fire_error_event | ( | const string & | message | ) | [protected, virtual] |
Helper to fire an error event to javascript.
message | The error message |
Implements Tcp.
Definition at line 368 of file TcpClient.cpp.
{ fire_error(message); }
void TcpClient::flush | ( | ) | [private] |
Helper function to flush the queue of data if sends are requested before the client is connected
Definition at line 338 of file TcpClient.cpp.
References connection, TcpEvent::data, data_queue, data_queue_mutex, Tcp::host, Tcp::port, and Tcp::send_handler().
Referenced by connect_handler(), and send().
{ data_queue_mutex.lock(); while (!data_queue.empty()) { data_queue_mutex.unlock(); // Pull the next data chunk to be sent off the queue data_queue_mutex.lock(); string data = data_queue.front(); data_queue.pop(); data_queue_mutex.unlock(); // Asynchronously send the data across the connection connection->async_send(boost::asio::buffer(data.data(), data.size()), boost::bind(&TcpClient::send_handler, this, _1, _2, data, host, port, connection)); } data_queue_mutex.unlock(); }
string TcpClient::get_host | ( | void | ) | [virtual] |
Returns the host to which this client connects
Implements Client.
Definition at line 363 of file TcpClient.cpp.
References Tcp::host.
{ return host; }
int TcpClient::get_port | ( | void | ) | [virtual] |
Returns the port of the remote host on which this client connects
Implements Client.
Definition at line 358 of file TcpClient.cpp.
References Tcp::port.
{ return port; }
void TcpClient::init | ( | ) | [private] |
Helper function to initialize this client
Definition at line 44 of file TcpClient.cpp.
References connected, Logger::error(), Tcp::failed, Tcp::host, Logger::info(), Tcp::log_options(), Tcp::port, resolve_handler(), resolver, and Tcp::using_ipv6.
Referenced by TcpClient().
{ connected = false; Logger::info( "Initializing TCP client to host '" + boost::lexical_cast<string>(host) + "' on port " + boost::lexical_cast<string>(port), port, host); log_options(); Logger::info( "Trying to resolve DNS information for host " + boost::lexical_cast<string>(host) + "', port " + boost::lexical_cast<string>( port), port, host); // 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 tcp::resolver::query query(tcp::v6(), host, boost::lexical_cast<string>(port), boost::asio::ip::resolver_query_base::numeric_service); if (resolver.get()) resolver->async_resolve(query, boost::bind(&TcpClient::resolve_handler, this, _1, _2)); else { failed = true; string message("TCP client failed to resolve, invalid resolver"); Logger::error(message, port, host); fire_error(message); } } else { // Asynchronously resolve the remote host, and once the host is resolved, create a connection tcp::resolver::query query(tcp::v4(), host, boost::lexical_cast<string>(port), boost::asio::ip::resolver_query_base::numeric_service); if (resolver.get()) resolver->async_resolve(query, boost::bind(&TcpClient::resolve_handler, this, _1, _2)); else { failed = true; string message("TCP client failed to resolve, invalid resolver"); Logger::error(message, port, host); fire_error(message); } } }
void TcpClient::init_socket | ( | ) | [private] |
Initialize the properties of this socket
Definition at line 89 of file TcpClient.cpp.
References connection, Tcp::do_not_route, Tcp::keep_alive, Tcp::keep_alive_timeout, Tcp::no_delay, and Tcp::set_tcp_keepalive().
Referenced by resolve_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); } 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 TcpClient::listen | ( | ) | [private] |
Helper function that will listen for incoming data on the TCP connection for the client, specifically responses to data already sent.
void TcpClient::resolve_handler | ( | const boost::system::error_code & | error_code, |
tcp::resolver::iterator | endpoint_iterator | ||
) | [private] |
I/O handler invoked when the remote host is resolved. This handler attempts to asynchronously establish a TCP connection with the remote host.
error_code | The error code encountered when trying to receive data, if any occurred. On success, this value is zero, and nonzero on error. |
endpoint_iterator | Allows the client to iterate through resolvers to retry the connection if it initially fails to connect. |
Definition at line 215 of file TcpClient.cpp.
References connect_handler(), connection, Tcp::disconnect_errors, Logger::error(), Tcp::failed, Tcp::host, Logger::info(), init_socket(), Tcp::port, Tcp::using_ipv6, and Logger::warn().
Referenced by connect_handler(), and init().
{ // If we encountered 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) { Logger::warn("TCP resolve was aborted"); return; } else { string message("TCP resolve failed, disconnected: '" + error_code.message() + "'"); Logger::warn(message, port, host); fire_disconnect(message); return; } } // We failed permanently, fail permanently and log it string message("Failed to resolve host with error: " + error_code.message()); Logger::error(message, port, host); fire_error(message); return; } if (connection.get()) { // Attempt to connect to the endpoint, using IPv6 if specified tcp::endpoint receiver_endpoint = *endpoint_iterator; if (using_ipv6 && *using_ipv6) { connection->open(tcp::v6()); } else { connection->open(tcp::v4()); } // Initialize the socket if it's open if (!connection->is_open()) init_socket(); // Log success Logger::info("Host has been resolved, attempting to connect to host", port, host); fire_resolve(); // Try to asynchronously establish a connection to the host connection->async_connect(receiver_endpoint, boost::bind(&TcpClient::connect_handler, this, _1, endpoint_iterator)); } else { failed = true; string message("TCP client failed to resolve, invalid connection"); Logger::error(message, port, host); fire_error(message); } }
void TcpClient::send | ( | const string & | data | ) | [virtual] |
Asynchronously sends data to the remote host to which this client is connected.
data | The data to send across the wire |
Implements Client.
Definition at line 177 of file TcpClient.cpp.
References Tcp::active_jobs, Tcp::active_jobs_mutex, connected, connected_mutex, connection, data_queue, data_queue_mutex, Logger::error(), Tcp::failed, flush(), Tcp::host, Tcp::port, and Tcp::send_handler().
Referenced by send_bytes().
{ if (failed) { // Log & fire an error string message("Trying to send data on a TCP client that has permanently failed!"); Logger::error(message, port, host); return; } // If we're not already connected, then queue this data to be send connected_mutex.lock(); bool connected_now = connected; connected_mutex.unlock(); if (!connected_now) { active_jobs_mutex.lock(); active_jobs++; active_jobs_mutex.unlock(); data_queue_mutex.lock(); data_queue.push(data); data_queue_mutex.unlock(); } else { // Check if the queue needs to be flushed, and if so, flush it flush(); // Send the data, and record that we've started a new send job active_jobs_mutex.lock(); active_jobs++; active_jobs_mutex.unlock(); connection->async_send(boost::asio::buffer(data.data(), data.size()), boost::bind(&TcpClient::send_handler, this, _1, _2, data, host, port, connection)); } }
void TcpClient::send_bytes | ( | const vector< byte > & | bytes | ) | [virtual] |
Asynchronously sends bytes to the remote host to which this client is connected.
bytes | The bytes of data to send across the wire |
Implements Client.
Definition at line 165 of file TcpClient.cpp.
References TcpEvent::data, and send().
{ string data; for (int i = 0; i < bytes.size(); i++) { data.push_back((unsigned char) bytes[i]); } send(data); }
void TcpClient::shutdown | ( | ) | [virtual] |
Gracefully shutdown this TCP client, waiting until all sends have completed before freeing all resources for this TCP client and shutting down any open connections. This function is exposed the javascript API.
Implements NetworkObject.
Definition at line 144 of file TcpClient.cpp.
References Tcp::active_jobs, Tcp::active_jobs_mutex, close(), Logger::error(), Tcp::failed, Tcp::host, Tcp::port, and Tcp::waiting_to_shutdown.
{ if (!failed) { active_jobs_mutex.lock(); int current_jobs = active_jobs; active_jobs_mutex.unlock(); waiting_to_shutdown = true; if (current_jobs == 0) { fire_close(); close(); } } else { // Log & fire an error Logger::error("Trying to start the server listening, but the server has permanently failed!", port, host); } }
bool TcpClient::connected [private] |
A flag recording whether this client is connected yet or not, used to queue send requests made before this client is connected if necessary.
Definition at line 197 of file TcpClient.h.
Referenced by connect_handler(), init(), and send().
boost::mutex TcpClient::connected_mutex [private] |
A mutex used to access the queue for pending jobs
Definition at line 202 of file TcpClient.h.
Referenced by connect_handler(), and send().
boost::shared_ptr<tcp::socket> TcpClient::connection [private] |
A shared reference to the socket used to connect to the remote host
Definition at line 186 of file TcpClient.h.
Referenced by close(), connect_handler(), flush(), init_socket(), resolve_handler(), send(), and TcpClient().
queue<string> TcpClient::data_queue [private] |
A queue of data to be sent, which fills as 'send' or 'send_bytes' commands occur before the client is connected
Definition at line 207 of file TcpClient.h.
boost::mutex TcpClient::data_queue_mutex [private] |
A mutex used to access the queue for pending jobs
Definition at line 212 of file TcpClient.h.
boost::shared_ptr<tcp::resolver> TcpClient::resolver [private] |
Resolver object provided by boost
to resolve the remote hostname and port
Definition at line 191 of file TcpClient.h.
Referenced by close(), connect_handler(), init(), and TcpClient().