Horizon Official Technical Documentation
Horizon::Networking::Socket< SocketType > Class Template Referenceabstract

A Socket object that handles a single connection. More...

#include <Socket.hpp>

+ Inheritance diagram for Horizon::Networking::Socket< SocketType >:
+ Collaboration diagram for Horizon::Networking::Socket< SocketType >:

Public Member Functions

 Socket (uint64_t socket_id)
 
 Socket (uint64_t socket_id, std::shared_ptr< tcp::socket > socket)
 
virtual ~Socket ()
 
virtual void start ()=0
 Initial method invoked once from the network thread that handles the AuthSocket. More...
 
virtual bool update ()
 Socket update loop called from its NetworkThread every n nanoseconds. More...
 
uint64_t get_socket_id ()
 
std::string & remote_ip_address ()
 
uint16_t remote_port () const
 
void async_read ()
 Asynchronous read operation @thread NetworkThread. More...
 
void async_read_with_callback (ByteBuffer &buf, void(Socket< SocketType >::*)(boost::system::error_code, std::size_t))
 Asynchronous read operation with callback handler @thread NetworkThread. More...
 
virtual void queue_buffer (ByteBuffer &&buffer)
 
bool is_open ()
 
void close_socket ()
 Socket close operation that performs cleanups before shutting down the connection. More...
 
void delayed_close_socket ()
 
ByteBufferget_read_buffer ()
 

Protected Member Functions

virtual void on_close ()=0
 
virtual void read_handler ()=0
 
virtual void on_error ()=0
 
bool async_process_queue ()
 Socket write operation. More...
 
void set_no_delay (bool enable)
 Disable the Nagle Algorithm on our socket. More...
 
std::size_t write_buffer_and_send (ByteBuffer &to_send, boost::system::error_code &error)
 Write a message to the buffer. More...
 

Private Member Functions

void read_handler_internal (boost::system::error_code error, size_t transferredBytes)
 Aysnchronous reading handler method. More...
 
void write_handler_wrapper (boost::system::error_code, std::size_t)
 Write handler wrapper. More...
 
bool handle_queue ()
 Handle the queue. More...
 
std::shared_ptr< tcp::socket > get_socket ()
 

Private Attributes

uint64_t _socket_id
 
std::shared_ptr< tcp::socket > _socket
 After accepting, the reference count of this pointer should be 1. More...
 
std::string _remote_ip_address
 
uint16_t _remote_port
 
ByteBuffer _read_buffer
 
ThreadSafeQueue< ByteBuffer_write_queue
 
std::atomic< bool > _closed
 
std::atomic< bool > _closing
 
bool _is_writing_async
 

Detailed Description

template<class SocketType>
class Horizon::Networking::Socket< SocketType >

A Socket object that handles a single connection.

Sockets are moved into the thread by SocketMgr, once accepted or connected. Once started, the object blocks to handle I/O events and requires explicit stopping.

Template Parameters
SocketTypeThe type of the Socket object. The Socket object is templated to allow the SocketMgr to handle different types of Socket objects. The Socket object must inherit from the Socket class. The SocketMgr will call the start() method of the Socket object. The Socket object must implement the start() method. The start() method is called once from the NetworkThread. The Socket object must implement the update() method. The update() method is called every n nanoseconds from the NetworkThread.
Parameters
socket_idThe unique identifier of the Socket object.
socketThe boost::asio::ip::tcp::socket object.
_remote_ip_addressThe remote IP address of the Socket object.
_remote_portThe remote port of the Socket object.
_read_bufferThe ByteBuffer object that holds the read buffer.
_closedThe atomic boolean that indicates whether the Socket object is closed. The variables are set only from the NetworkThread. Once set, the Socket object will not accept any new read/write requests.
_closingThe atomic boolean that indicates whether the Socket object is closing. The variables are set only from the NetworkThread. Once set, the Socket object will not accept any new write requests. The Socket object will continue to read until the read buffer is empty. Once the read buffer is empty, the Socket object will be closed.
_is_writing_asyncThe atomic boolean that indicates whether the Socket object is writing asynchronously.
_write_queueThe ThreadSafeQueue object that holds the write queue. The write queue is processed in the NetworkThread.

Constructor & Destructor Documentation

◆ Socket() [1/2]

template<class SocketType >
Horizon::Networking::Socket< SocketType >::Socket ( uint64_t  socket_id)
inlineexplicit
85 : _socket_id(socket_id), _socket(nullptr), _read_buffer(), _closed(false), _closing(false), _is_writing_async(false)
86 {
88 }
#define READ_BLOCK_SIZE
Definition: Socket.hpp:52
void resize(size_t new_size)
Definition: ByteBuffer.hpp:357
bool _is_writing_async
Definition: Socket.hpp:366
ByteBuffer _read_buffer
Definition: Socket.hpp:362
uint64_t _socket_id
Definition: Socket.hpp:358
std::atomic< bool > _closing
Definition: Socket.hpp:365
std::atomic< bool > _closed
Definition: Socket.hpp:364
std::shared_ptr< tcp::socket > _socket
After accepting, the reference count of this pointer should be 1.
Definition: Socket.hpp:359

References Horizon::Networking::Socket< SocketType >::_read_buffer, READ_BLOCK_SIZE, and ByteBuffer::resize().

+ Here is the call graph for this function:

◆ Socket() [2/2]

template<class SocketType >
Horizon::Networking::Socket< SocketType >::Socket ( uint64_t  socket_id,
std::shared_ptr< tcp::socket >  socket 
)
inlineexplicit
91 : _socket_id(socket_id), _socket(socket), _remote_ip_address(_socket->remote_endpoint().address().to_string()),
92 _remote_port(_socket->remote_endpoint().port()), _read_buffer(), _closed(false), _closing(false), _is_writing_async(false)
93 {
95 }
uint16_t _remote_port
Definition: Socket.hpp:361
std::string _remote_ip_address
Definition: Socket.hpp:360

References Horizon::Networking::Socket< SocketType >::_read_buffer, READ_BLOCK_SIZE, and ByteBuffer::resize().

+ Here is the call graph for this function:

◆ ~Socket()

template<class SocketType >
virtual Horizon::Networking::Socket< SocketType >::~Socket ( )
inlinevirtual
98 {
99 boost::system::error_code error;
100 _socket->close(error);
101 }

References Horizon::Networking::Socket< SocketType >::_socket.

Member Function Documentation

◆ async_process_queue()

template<class SocketType >
bool Horizon::Networking::Socket< SocketType >::async_process_queue ( )
inlineprotected

Socket write operation.

@thread NetworkThread

214 {
216 return false;
217
218 _is_writing_async = true;
219
220 _socket->async_write_some(boost::asio::null_buffers(),
222 this, boost::placeholders::_1, boost::placeholders::_2));
223
224 return true;
225 }
void write_handler_wrapper(boost::system::error_code, std::size_t)
Write handler wrapper.
Definition: Socket.hpp:306

References Horizon::Networking::Socket< SocketType >::_is_writing_async, and Horizon::Networking::Socket< SocketType >::_socket.

Referenced by Horizon::Networking::Socket< SocketType >::handle_queue().

+ Here is the caller graph for this function:

◆ async_read()

template<class SocketType >
void Horizon::Networking::Socket< SocketType >::async_read ( )
inline

Asynchronous read operation @thread NetworkThread.

141 {
142 if (!is_open())
143 return;
144
147
148 _socket->async_read_some(boost::asio::buffer(_read_buffer.get_write_pointer(), _read_buffer.remaining_space()),
149 boost::bind(&Socket<SocketType>::read_handler_internal, this, boost::placeholders::_1, boost::placeholders::_2));
150 }
void ensure_free_space()
Definition: ByteBuffer.hpp:350
size_t remaining_space() const
Definition: ByteBuffer.hpp:334
uint8_t * get_write_pointer()
Definition: ByteBuffer.hpp:328
void flush()
Definition: ByteBuffer.hpp:339
void read_handler_internal(boost::system::error_code error, size_t transferredBytes)
Aysnchronous reading handler method.
Definition: Socket.hpp:262
bool is_open()
Definition: Socket.hpp:170

References Horizon::Networking::Socket< SocketType >::_read_buffer, Horizon::Networking::Socket< SocketType >::_socket, ByteBuffer::ensure_free_space(), ByteBuffer::flush(), ByteBuffer::get_write_pointer(), Horizon::Networking::Socket< SocketType >::is_open(), and ByteBuffer::remaining_space().

Referenced by Horizon::Networking::Socket< SocketType >::read_handler_internal().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ async_read_with_callback()

template<class SocketType >
void Horizon::Networking::Socket< SocketType >::async_read_with_callback ( ByteBuffer buf,
void(Socket< SocketType >::*)(boost::system::error_code, std::size_t)   
)
inline

Asynchronous read operation with callback handler @thread NetworkThread.

157 {
158 if (!is_open())
159 return;
160
163
164 _socket->async_read_some(boost::asio::buffer(buf.get_write_pointer(), buf.remaining_space()),
165 boost::bind(&Socket<SocketType>::read_handler_internal, this, boost::placeholders::_1, boost::placeholders::_2));
166 }

References Horizon::Networking::Socket< SocketType >::_read_buffer, Horizon::Networking::Socket< SocketType >::_socket, ByteBuffer::ensure_free_space(), ByteBuffer::flush(), ByteBuffer::get_write_pointer(), Horizon::Networking::Socket< SocketType >::is_open(), and ByteBuffer::remaining_space().

+ Here is the call graph for this function:

◆ close_socket()

template<class SocketType >
void Horizon::Networking::Socket< SocketType >::close_socket ( )
inline

Socket close operation that performs cleanups before shutting down the connection.

@thread NetworkThread

Socket finalisation.

177 {
178 boost::system::error_code socket_error;
179
180 if (_closed.exchange(true))
181 return;
182
183 // Finalise the child-class socket first.
184 on_close();
185
189 // Shutdown the socket.
190 _socket->shutdown(boost::asio::socket_base::shutdown_send, socket_error);
191 // Close the socket.
192 _socket->close();
193
194 if (socket_error) {
195 HLog(error) << "Error when shutting down socket from IP " <<
196 remote_ip_address() << "(error code:" << socket_error.value() << " - " << socket_error.message().c_str() << ")";
197 }
198 }
#define HLog(type)
Definition: Logger.hpp:122
virtual void on_close()=0
std::string & remote_ip_address()
Definition: Socket.hpp:133

References Horizon::Networking::Socket< SocketType >::_closed, Horizon::Networking::Socket< SocketType >::_socket, HLog, Horizon::Networking::Socket< SocketType >::on_close(), and Horizon::Networking::Socket< SocketType >::remote_ip_address().

Referenced by Horizon::Networking::Socket< SocketType >::handle_queue(), and Horizon::Networking::Socket< SocketType >::read_handler_internal().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ delayed_close_socket()

template<class SocketType >
void Horizon::Networking::Socket< SocketType >::delayed_close_socket ( )
inline
200{ if (_closing.exchange(true)) return; }

References Horizon::Networking::Socket< SocketType >::_closing.

◆ get_read_buffer()

template<class SocketType >
ByteBuffer & Horizon::Networking::Socket< SocketType >::get_read_buffer ( )
inline

◆ get_socket()

template<class SocketType >
std::shared_ptr< tcp::socket > Horizon::Networking::Socket< SocketType >::get_socket ( )
inlineprivate

◆ get_socket_id()

template<class SocketType >
uint64_t Horizon::Networking::Socket< SocketType >::get_socket_id ( )
inline

◆ handle_queue()

template<class SocketType >
bool Horizon::Networking::Socket< SocketType >::handle_queue ( )
inlineprivate

Handle the queue.

Returns
true if the queue is not empty, false otherwise. @thread NetworkThread

If we have a would block error, we need to re-process the queue.

Re-process queue if we have remaining bytes.

318 {
319 boost::system::error_code error;
320
321 if (_write_queue.empty())
322 return false;
323
324 std::shared_ptr<ByteBuffer> to_send = _write_queue.front();
325
326 //HLog(debug) << "Sent bytes: " << to_send->to_string();
327
328 std::size_t bytes_sent = write_buffer_and_send(*to_send, error);
329
333 if (error == boost::asio::error::would_block || error == boost::asio::error::try_again)
334 return async_process_queue();
335
339 if (!error && bytes_sent < to_send->active_length()) {
340 to_send->read_completed(bytes_sent);
341 return async_process_queue();
342 }
343
344 // Pop the front element.
346
347 // Close if required.
348 if (_closing && _write_queue.empty())
349 close_socket();
350
351 // Return true if the queue is not empty. Indicating that the sending operation was successful.
352 return !_write_queue.empty() && bytes_sent;
353 }
ThreadSafeQueue< ByteBuffer > _write_queue
Definition: Socket.hpp:363
void close_socket()
Socket close operation that performs cleanups before shutting down the connection.
Definition: Socket.hpp:176
bool async_process_queue()
Socket write operation.
Definition: Socket.hpp:213
std::size_t write_buffer_and_send(ByteBuffer &to_send, boost::system::error_code &error)
Write a message to the buffer.
Definition: Socket.hpp:246
bool empty()
Definition: ThreadSafeQueue.hpp:116
std::shared_ptr< T > front()
Definition: ThreadSafeQueue.hpp:126
std::shared_ptr< T > try_pop()
Definition: ThreadSafeQueue.hpp:84

References Horizon::Networking::Socket< SocketType >::_closing, Horizon::Networking::Socket< SocketType >::_write_queue, Horizon::Networking::Socket< SocketType >::async_process_queue(), Horizon::Networking::Socket< SocketType >::close_socket(), ThreadSafeQueue< T >::empty(), ThreadSafeQueue< T >::front(), ThreadSafeQueue< T >::try_pop(), and Horizon::Networking::Socket< SocketType >::write_buffer_and_send().

Referenced by Horizon::Networking::Socket< SocketType >::update(), and Horizon::Networking::Socket< SocketType >::write_handler_wrapper().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ is_open()

◆ on_close()

template<class SocketType >
virtual void Horizon::Networking::Socket< SocketType >::on_close ( )
protectedpure virtual

◆ on_error()

template<class SocketType >
virtual void Horizon::Networking::Socket< SocketType >::on_error ( )
protectedpure virtual

◆ queue_buffer()

template<class SocketType >
virtual void Horizon::Networking::Socket< SocketType >::queue_buffer ( ByteBuffer &&  buffer)
inlinevirtual
168{ _write_queue.push(std::move(buffer)); }
void push(T &&new_value)
Definition: ThreadSafeQueue.hpp:90

References Horizon::Networking::Socket< SocketType >::_write_queue, and ThreadSafeQueue< T >::push().

+ Here is the call graph for this function:

◆ read_handler()

template<class SocketType >
virtual void Horizon::Networking::Socket< SocketType >::read_handler ( )
protectedpure virtual

◆ read_handler_internal()

template<class SocketType >
void Horizon::Networking::Socket< SocketType >::read_handler_internal ( boost::system::error_code  error,
size_t  transferredBytes 
)
inlineprivate

Aysnchronous reading handler method.

Parameters
error
transferredBytes@thread NetworkThread
263 {
264 // If there is an error on the socket, we need to close it.
265 if (error) {
266 // If the socket is already closed, we don't need to do anything.
267 if (error.value() == boost::asio::error::eof) {
268 close_socket();
269 // If the connection was reset or timed out, we need to close the socket.
270 } else if (error.value() == boost::system::errc::connection_reset
271 || error.value() == boost::system::errc::timed_out) {
272 on_error();
273 close_socket();
274 // If there was any unknown error on the socket, we need to close it.
275 } else {
276 on_error();
277 close_socket();
278 }
279 // Retreive the error code and handle it accordingly.
280 switch (error.value())
281 {
282 case 2: // End of file
283 break;
284 default:
285 HLog(debug) << "Socket::read_handler_internal: " << error.value() << " (Code: " << error.message() << ").";
286 }
287 return;
288 }
289
290 if (transferredBytes > 0) {
291 // write_completed will move the write pointer forward, so we need to save the current position of the write pointer.
292 _read_buffer.write_completed(transferredBytes);
293 // read handler will process the data that has been written to the buffer.
294 read_handler();
295 }
296
297 // Invoke the next read operation.
298 async_read();
299 }
void write_completed(size_t bytes)
Definition: ByteBuffer.hpp:322
virtual void read_handler()=0
virtual void on_error()=0
void async_read()
Asynchronous read operation @thread NetworkThread.
Definition: Socket.hpp:140

References Horizon::Networking::Socket< SocketType >::_read_buffer, Horizon::Networking::Socket< SocketType >::async_read(), Horizon::Networking::Socket< SocketType >::close_socket(), HLog, Horizon::Networking::Socket< SocketType >::on_error(), Horizon::Networking::Socket< SocketType >::read_handler(), and ByteBuffer::write_completed().

+ Here is the call graph for this function:

◆ remote_ip_address()

template<class SocketType >
std::string & Horizon::Networking::Socket< SocketType >::remote_ip_address ( )
inline

◆ remote_port()

template<class SocketType >
uint16_t Horizon::Networking::Socket< SocketType >::remote_port ( ) const
inline

◆ set_no_delay()

template<class SocketType >
void Horizon::Networking::Socket< SocketType >::set_no_delay ( bool  enable)
inlineprotected

Disable the Nagle Algorithm on our socket.

Parameters
enable
232 {
233 boost::system::error_code error;
234 _socket->set_option(tcp::no_delay(enable), error);
235 if (error) {
236 HLog(error) << "Networking: Socket::set_no_delay: failed to set_option(boost::asio::ip::tcp::no_delay) for IP " << remote_ip_address() << " (error_code: " << error.value() << " - " << error.message().c_str() << ")";
237 }
238 }

References Horizon::Networking::Socket< SocketType >::_socket, HLog, and Horizon::Networking::Socket< SocketType >::remote_ip_address().

+ Here is the call graph for this function:

◆ start()

template<class SocketType >
virtual void Horizon::Networking::Socket< SocketType >::start ( )
pure virtual

Initial method invoked once from the network thread that handles the AuthSocket.

@thread NetworkThread

Implemented in Horizon::Auth::AuthSocket, Horizon::Char::CharSocket, and Horizon::Zone::ZoneSocket.

◆ update()

template<class SocketType >
virtual bool Horizon::Networking::Socket< SocketType >::update ( )
inlinevirtual

Socket update loop called from its NetworkThread every n nanoseconds.

Processes the message queue. @thread NetworkThread

Reimplemented in Horizon::Auth::AuthSocket, Horizon::Char::CharSocket, and Horizon::Zone::ZoneSocket.

115 {
116 if (_closed)
117 return false;
118
120 return true;
121 }
122
123 while (handle_queue())
124 ;
125
126 return true;
127 }
bool handle_queue()
Handle the queue.
Definition: Socket.hpp:317

References Horizon::Networking::Socket< SocketType >::_closed, Horizon::Networking::Socket< SocketType >::_closing, Horizon::Networking::Socket< SocketType >::_is_writing_async, Horizon::Networking::Socket< SocketType >::_write_queue, ThreadSafeQueue< T >::empty(), and Horizon::Networking::Socket< SocketType >::handle_queue().

+ Here is the call graph for this function:

◆ write_buffer_and_send()

template<class SocketType >
std::size_t Horizon::Networking::Socket< SocketType >::write_buffer_and_send ( ByteBuffer to_send,
boost::system::error_code &  error 
)
inlineprotected

Write a message to the buffer.

Parameters
to_send
error
Returns
247 {
248 int16_t packet_id;
249 std::size_t bytes_to_send = to_send.active_length();
250 memcpy(&packet_id, to_send.get_read_pointer(), sizeof(int16_t));
251 std::size_t bytes_sent = _socket->write_some(boost::asio::buffer(to_send.get_read_pointer(), bytes_to_send), error);
252 return bytes_sent;
253 }
uint8_t * get_read_pointer()
Definition: ByteBuffer.hpp:327
size_t active_length() const
Definition: ByteBuffer.hpp:333

References Horizon::Networking::Socket< SocketType >::_socket, ByteBuffer::active_length(), and ByteBuffer::get_read_pointer().

Referenced by Horizon::Networking::Socket< SocketType >::handle_queue().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ write_handler_wrapper()

template<class SocketType >
void Horizon::Networking::Socket< SocketType >::write_handler_wrapper ( boost::system::error_code  ,
std::size_t   
)
inlineprivate

Write handler wrapper.

Parameters
error
transferedBytes
307 {
308 _is_writing_async = false;
309 handle_queue();
310 }

References Horizon::Networking::Socket< SocketType >::_is_writing_async, and Horizon::Networking::Socket< SocketType >::handle_queue().

+ Here is the call graph for this function:

Member Data Documentation

◆ _closed

◆ _closing

◆ _is_writing_async

◆ _read_buffer

◆ _remote_ip_address

template<class SocketType >
std::string Horizon::Networking::Socket< SocketType >::_remote_ip_address
private

◆ _remote_port

template<class SocketType >
uint16_t Horizon::Networking::Socket< SocketType >::_remote_port
private

◆ _socket

◆ _socket_id

template<class SocketType >
uint64_t Horizon::Networking::Socket< SocketType >::_socket_id
private

◆ _write_queue


The documentation for this class was generated from the following file: