AzerothCore 3.3.5a
OpenSource WoW Emulator
Loading...
Searching...
No Matches
Socket< T > Class Template Referenceabstract

#include "Socket.h"

Inheritance diagram for Socket< T >:

Public Member Functions

 Socket (IoContextTcpSocket &&socket)
 
virtual ~Socket ()
 
virtual void Start ()=0
 
virtual bool Update ()
 
boost::asio::ip::address GetRemoteIpAddress () const
 
uint16 GetRemotePort () const
 
void AsyncRead ()
 
void AsyncReadProxyHeader ()
 
void AsyncReadWithCallback (void(T::*callback)(boost::system::error_code, std::size_t))
 
void QueuePacket (MessageBuffer &&buffer)
 
ProxyHeaderReadingState GetProxyHeaderReadingState () const
 
bool IsOpen () const
 
void CloseSocket ()
 
void DelayedCloseSocket ()
 Marks the socket for closing after write buffer becomes empty.
 
MessageBufferGetReadBuffer ()
 

Protected Member Functions

virtual void OnClose ()
 
virtual SocketReadCallbackResult ReadHandler ()=0
 
bool AsyncProcessQueue ()
 
void SetNoDelay (bool enable)
 

Private Member Functions

void ReadHandlerInternal (boost::system::error_code error, std::size_t transferredBytes)
 
void ProxyReadHeaderHandler (boost::system::error_code error, std::size_t transferredBytes)
 
void WriteHandlerWrapper (boost::system::error_code, std::size_t)
 
bool HandleQueue ()
 

Private Attributes

IoContextTcpSocket _socket
 
boost::asio::ip::address _remoteAddress
 
uint16 _remotePort
 
MessageBuffer _readBuffer
 
std::queue< MessageBuffer_writeQueue
 
std::atomic< SocketState_state
 
bool _isWritingAsync
 
ProxyHeaderReadingState _proxyHeaderReadingState
 

Detailed Description

template<class T>
class Socket< T >

Constructor & Destructor Documentation

◆ Socket()

template<class T >
Socket< T >::Socket ( IoContextTcpSocket< T > &&  socket)
inlineexplicit
70 : _socket(std::move(socket)), _remoteAddress(_socket.remote_endpoint().address()),
71 _remotePort(_socket.remote_endpoint().port()), _readBuffer(), _state(SocketState::Open), _isWritingAsync(false),
73 {
75 }
#define READ_BLOCK_SIZE
Definition Socket.h:32
@ PROXY_HEADER_READING_STATE_NOT_STARTED
Definition Socket.h:55
void Resize(size_type bytes)
Definition MessageBuffer.h:52
IoContextTcpSocket _socket
Definition Socket.h:446
uint16 _remotePort
Definition Socket.h:449
boost::asio::ip::address _remoteAddress
Definition Socket.h:448
std::atomic< SocketState > _state
Definition Socket.h:454
ProxyHeaderReadingState _proxyHeaderReadingState
Definition Socket.h:458
MessageBuffer _readBuffer
Definition Socket.h:451
bool _isWritingAsync
Definition Socket.h:456

References Socket< T >::_readBuffer, READ_BLOCK_SIZE, and MessageBuffer::Resize().

◆ ~Socket()

template<class T >
virtual Socket< T >::~Socket ( )
inlinevirtual
78 {
80 boost::system::error_code error;
81 _socket.close(error);
82 }

References Socket< T >::_socket, Socket< T >::_state, and Closed.

Member Function Documentation

◆ AsyncProcessQueue()

template<class T >
bool Socket< T >::AsyncProcessQueue ( )
inlineprotected
207 {
208 if (_isWritingAsync)
209 return false;
210
211 _isWritingAsync = true;
212
213#ifdef AC_SOCKET_USE_IOCP
214 MessageBuffer& buffer = _writeQueue.front();
215 _socket.async_write_some(boost::asio::buffer(buffer.GetReadPointer(), buffer.GetActiveSize()), std::bind(&Socket<T>::WriteHandler,
216 this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
217#else
218 _socket.async_wait(boost::asio::socket_base::wait_write, [self = this->shared_from_this()](boost::system::error_code error)
219 {
220 self->WriteHandlerWrapper(error, 0);
221 });
222#endif
223 return false;
224 }
Definition MessageBuffer.h:26
uint8 * GetReadPointer()
Definition MessageBuffer.h:58
size_type GetActiveSize() const
Definition MessageBuffer.h:64
Definition Socket.h:68
std::queue< MessageBuffer > _writeQueue
Definition Socket.h:452

References Socket< T >::_isWritingAsync, Socket< T >::_socket, Socket< T >::_writeQueue, MessageBuffer::GetActiveSize(), and MessageBuffer::GetReadPointer().

Referenced by Socket< T >::HandleQueue(), and Socket< T >::QueuePacket().

◆ AsyncRead()

template<class T >
void Socket< T >::AsyncRead ( )
inline
118 {
119 if (!IsOpen())
120 {
121 return;
122 }
123
126 _socket.async_read_some(boost::asio::buffer(_readBuffer.GetWritePointer(), _readBuffer.GetRemainingSpace()),
127 std::bind(&Socket<T>::ReadHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
128 }
size_type GetRemainingSpace() const
Definition MessageBuffer.h:65
uint8 * GetWritePointer()
Definition MessageBuffer.h:59
void EnsureFreeSpace()
Definition MessageBuffer.h:84
void Normalize()
Definition MessageBuffer.h:69
bool IsOpen() const
Definition Socket.h:170

References Socket< T >::_readBuffer, Socket< T >::_socket, MessageBuffer::EnsureFreeSpace(), MessageBuffer::GetRemainingSpace(), MessageBuffer::GetWritePointer(), Socket< T >::IsOpen(), and MessageBuffer::Normalize().

Referenced by Socket< T >::ReadHandlerInternal().

◆ AsyncReadProxyHeader()

template<class T >
void Socket< T >::AsyncReadProxyHeader ( )
inline

◆ AsyncReadWithCallback()

template<class T >
void Socket< T >::AsyncReadWithCallback ( void(T::*)(boost::system::error_code, std::size_t)  callback)
inline
146 {
147 if (!IsOpen())
148 {
149 return;
150 }
151
154
155 _socket.async_read_some(boost::asio::buffer(_readBuffer.GetWritePointer(), _readBuffer.GetRemainingSpace()),
156 std::bind(callback, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
157 }

References Socket< T >::_readBuffer, Socket< T >::_socket, MessageBuffer::EnsureFreeSpace(), MessageBuffer::GetRemainingSpace(), MessageBuffer::GetWritePointer(), Socket< T >::IsOpen(), and MessageBuffer::Normalize().

◆ CloseSocket()

template<class T >
void Socket< T >::CloseSocket ( )
inline
173 {
175 if (!_state.compare_exchange_strong(expected, SocketState::Closed))
176 {
177 // If it was Closing, try to transition to Closed
178 expected = SocketState::Closing;
179 if (!_state.compare_exchange_strong(expected, SocketState::Closed))
180 return; // Already closed
181 }
182
183 boost::system::error_code shutdownError;
184 _socket.shutdown(boost::asio::socket_base::shutdown_send, shutdownError);
185
186 if (shutdownError)
187 LOG_DEBUG("network", "Socket::CloseSocket: {} errored when shutting down socket: {} ({})", GetRemoteIpAddress().to_string(),
188 shutdownError.value(), shutdownError.message());
189
190 OnClose();
191 }
#define LOG_DEBUG(filterType__,...)
Definition Log.h:170
SocketState
Definition Socket.h:48
boost::asio::ip::address GetRemoteIpAddress() const
Definition Socket.h:107
virtual void OnClose()
Definition Socket.h:203

References Socket< T >::_socket, Socket< T >::_state, Closed, Closing, Socket< T >::GetRemoteIpAddress(), LOG_DEBUG, Socket< T >::OnClose(), and Open.

Referenced by Socket< T >::HandleQueue(), Socket< T >::ProxyReadHeaderHandler(), and Socket< T >::ReadHandlerInternal().

◆ DelayedCloseSocket()

template<class T >
void Socket< T >::DelayedCloseSocket ( )
inline

Marks the socket for closing after write buffer becomes empty.

195 {
197 _state.compare_exchange_strong(expected, SocketState::Closing);
198 }

References Socket< T >::_state, Closing, and Open.

◆ GetProxyHeaderReadingState()

template<class T >
ProxyHeaderReadingState Socket< T >::GetProxyHeaderReadingState ( ) const
inline

◆ GetReadBuffer()

template<class T >
MessageBuffer & Socket< T >::GetReadBuffer ( )
inline

◆ GetRemoteIpAddress()

template<class T >
boost::asio::ip::address Socket< T >::GetRemoteIpAddress ( ) const
inline

◆ GetRemotePort()

template<class T >
uint16 Socket< T >::GetRemotePort ( ) const
inline
113 {
114 return _remotePort;
115 }

References Socket< T >::_remotePort.

◆ HandleQueue()

template<class T >
bool Socket< T >::HandleQueue ( )
inlineprivate
391 {
392 if (_writeQueue.empty())
393 return false;
394
395 MessageBuffer& queuedMessage = _writeQueue.front();
396
397 std::size_t bytesToSend = queuedMessage.GetActiveSize();
398
399 boost::system::error_code error;
400 std::size_t bytesSent = _socket.write_some(boost::asio::buffer(queuedMessage.GetReadPointer(), bytesToSend), error);
401
402 if (error)
403 {
404 if (error == boost::asio::error::would_block || error == boost::asio::error::try_again)
405 {
406 return AsyncProcessQueue();
407 }
408
409 _writeQueue.pop();
410
411 if (_state.load() == SocketState::Closing && _writeQueue.empty())
412 {
413 CloseSocket();
414 }
415
416 return false;
417 }
418 else if (bytesSent == 0)
419 {
420 _writeQueue.pop();
421
422 if (_state.load() == SocketState::Closing && _writeQueue.empty())
423 {
424 CloseSocket();
425 }
426
427 return false;
428 }
429 else if (bytesSent < bytesToSend) // now n > 0
430 {
431 queuedMessage.ReadCompleted(bytesSent);
432 return AsyncProcessQueue();
433 }
434
435 _writeQueue.pop();
436
437 if (_state.load() == SocketState::Closing && _writeQueue.empty())
438 {
439 CloseSocket();
440 }
441
442 return !_writeQueue.empty();
443 }
void ReadCompleted(size_type bytes)
Definition MessageBuffer.h:61
bool AsyncProcessQueue()
Definition Socket.h:206
void CloseSocket()
Definition Socket.h:172

References Socket< T >::_socket, Socket< T >::_state, Socket< T >::_writeQueue, Socket< T >::AsyncProcessQueue(), Socket< T >::CloseSocket(), Closing, MessageBuffer::GetActiveSize(), MessageBuffer::GetReadPointer(), and MessageBuffer::ReadCompleted().

Referenced by Socket< T >::Update(), and Socket< T >::WriteHandlerWrapper().

◆ IsOpen()

template<class T >
bool Socket< T >::IsOpen ( ) const
inline

◆ OnClose()

template<class T >
virtual void Socket< T >::OnClose ( )
inlineprotectedvirtual

Reimplemented in WorldSocket.

203{ }

Referenced by Socket< T >::CloseSocket().

◆ ProxyReadHeaderHandler()

template<class T >
void Socket< T >::ProxyReadHeaderHandler ( boost::system::error_code  error,
std::size_t  transferredBytes 
)
inlineprivate
253 {
254 if (error)
255 {
256 CloseSocket();
257 return;
258 }
259
260 _readBuffer.WriteCompleted(transferredBytes);
261
262 MessageBuffer& packet = GetReadBuffer();
263
264 const int minimumProxyProtocolV2Size = 28;
265 if (packet.GetActiveSize() < minimumProxyProtocolV2Size)
266 {
268 return;
269 }
270
271 uint8* readPointer = packet.GetReadPointer();
272
273 const uint8 signatureSize = 12;
274 const uint8 expectedSignature[signatureSize] = {0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A};
275 if (memcmp(packet.GetReadPointer(), expectedSignature, signatureSize) != 0)
276 {
278 LOG_ERROR("network", "Socket::ProxyReadHeaderHandler: received bad PROXY Protocol v2 signature for {}", GetRemoteIpAddress().to_string());
279 return;
280 }
281
282 const uint8 version = (readPointer[signatureSize] & 0xF0) >> 4;
283 const uint8 command = (readPointer[signatureSize] & 0xF);
284
285 if (version != 2)
286 {
288 LOG_ERROR("network", "Socket::ProxyReadHeaderHandler: received bad PROXY Protocol v2 signature for {}", GetRemoteIpAddress().to_string());
289 return;
290 }
291
292 const uint8 addressFamily = readPointer[13];
293 const uint16 len = (readPointer[14] << 8) | readPointer[15];
294 if (static_cast<size_t>(len+16) > packet.GetActiveSize())
295 {
297 return;
298 }
299
300 // Connection created by a proxy itself (health checks?), ignore and do nothing.
301 if (command == 0)
302 {
303 packet.ReadCompleted(len+16);
305 return;
306 }
307
308 auto remainingLen = packet.GetActiveSize() - 16;
309 readPointer += 16; // Skip strait to address.
310
311 switch (addressFamily) {
313 {
314 if (remainingLen < 12)
315 {
317 return;
318 }
319
320 boost::asio::ip::address_v4::bytes_type b;
321 auto addressSize = sizeof(b);
322
323 std::copy(readPointer, readPointer+addressSize, b.begin());
324 _remoteAddress = boost::asio::ip::address_v4(b);
325
326 readPointer += 2 * addressSize; // Skip server address.
327 _remotePort = (readPointer[0] << 8) | readPointer[1];
328
329 break;
330 }
331
333 {
334 if (remainingLen < 36)
335 {
337 return;
338 }
339
340 boost::asio::ip::address_v6::bytes_type b;
341 auto addressSize = sizeof(b);
342
343 std::copy(readPointer, readPointer+addressSize, b.begin());
344 _remoteAddress = boost::asio::ip::address_v6(b);
345
346 readPointer += 2 * addressSize; // Skip server address.
347 _remotePort = (readPointer[0] << 8) | readPointer[1];
348
349 break;
350 }
351
352 default:
354 LOG_ERROR("network", "Socket::ProxyReadHeaderHandler: unsupported address family type {}", GetRemoteIpAddress().to_string());
355 return;
356 }
357
358 packet.ReadCompleted(len+16);
360 }
std::uint8_t uint8
Definition Define.h:109
std::uint16_t uint16
Definition Define.h:108
#define LOG_ERROR(filterType__,...)
Definition Log.h:158
@ PROXY_HEADER_ADDRESS_FAMILY_AND_PROTOCOL_TCP_V6
Definition Socket.h:63
@ PROXY_HEADER_ADDRESS_FAMILY_AND_PROTOCOL_TCP_V4
Definition Socket.h:62
@ PROXY_HEADER_READING_STATE_FINISHED
Definition Socket.h:57
@ PROXY_HEADER_READING_STATE_FAILED
Definition Socket.h:58
void WriteCompleted(size_type bytes)
Definition MessageBuffer.h:62
MessageBuffer & GetReadBuffer()
Definition Socket.h:200
void AsyncReadProxyHeader()
Definition Socket.h:130

References Socket< T >::_proxyHeaderReadingState, Socket< T >::_readBuffer, Socket< T >::_remoteAddress, Socket< T >::_remotePort, Socket< T >::AsyncReadProxyHeader(), Socket< T >::CloseSocket(), MessageBuffer::GetActiveSize(), Socket< T >::GetReadBuffer(), MessageBuffer::GetReadPointer(), Socket< T >::GetRemoteIpAddress(), LOG_ERROR, PROXY_HEADER_ADDRESS_FAMILY_AND_PROTOCOL_TCP_V4, PROXY_HEADER_ADDRESS_FAMILY_AND_PROTOCOL_TCP_V6, PROXY_HEADER_READING_STATE_FAILED, PROXY_HEADER_READING_STATE_FINISHED, MessageBuffer::ReadCompleted(), and MessageBuffer::WriteCompleted().

◆ QueuePacket()

template<class T >
void Socket< T >::QueuePacket ( MessageBuffer &&  buffer)
inline
160 {
161 _writeQueue.push(std::move(buffer));
162
163#ifdef AC_SOCKET_USE_IOCP
165#endif
166 }

References Socket< T >::_writeQueue, and Socket< T >::AsyncProcessQueue().

◆ ReadHandler()

template<class T >
virtual SocketReadCallbackResult Socket< T >::ReadHandler ( )
protectedpure virtual

Implemented in AuthSession, and WorldSocket.

Referenced by Socket< T >::ReadHandlerInternal().

◆ ReadHandlerInternal()

template<class T >
void Socket< T >::ReadHandlerInternal ( boost::system::error_code  error,
std::size_t  transferredBytes 
)
inlineprivate
238 {
239 if (error)
240 {
241 CloseSocket();
242 return;
243 }
244
245 _readBuffer.WriteCompleted(transferredBytes);
247 AsyncRead();
248 }
virtual SocketReadCallbackResult ReadHandler()=0
void AsyncRead()
Definition Socket.h:117

References Socket< T >::_readBuffer, Socket< T >::AsyncRead(), Socket< T >::CloseSocket(), KeepReading, Socket< T >::ReadHandler(), and MessageBuffer::WriteCompleted().

◆ SetNoDelay()

template<class T >
void Socket< T >::SetNoDelay ( bool  enable)
inlineprotected
227 {
228 boost::system::error_code err;
229 _socket.set_option(tcp::no_delay(enable), err);
230
231 if (err)
232 LOG_DEBUG("network", "Socket::SetNoDelay: failed to set_option(boost::asio::ip::tcp::no_delay) for {} - {} ({})",
233 GetRemoteIpAddress().to_string(), err.value(), err.message());
234 }

References Socket< T >::_socket, Socket< T >::GetRemoteIpAddress(), and LOG_DEBUG.

◆ Start()

template<class T >
virtual void Socket< T >::Start ( )
pure virtual

Implemented in AuthSession, and WorldSocket.

◆ Update()

template<class T >
virtual bool Socket< T >::Update ( )
inlinevirtual

Reimplemented in AuthSession, and WorldSocket.

87 {
88 SocketState state = _state.load();
89 if (state == SocketState::Closed)
90 {
91 return false;
92 }
93
94#ifndef AC_SOCKET_USE_IOCP
95 if (_isWritingAsync || (_writeQueue.empty() && state != SocketState::Closing))
96 {
97 return true;
98 }
99
100 for (; HandleQueue();)
101 ;
102#endif
103
104 return true;
105 }
bool HandleQueue()
Definition Socket.h:390

References Socket< T >::_isWritingAsync, Socket< T >::_state, Socket< T >::_writeQueue, Closed, Closing, and Socket< T >::HandleQueue().

◆ WriteHandlerWrapper()

template<class T >
void Socket< T >::WriteHandlerWrapper ( boost::system::error_code  ,
std::size_t   
)
inlineprivate
385 {
386 _isWritingAsync = false;
387 HandleQueue();
388 }

References Socket< T >::_isWritingAsync, and Socket< T >::HandleQueue().

Member Data Documentation

◆ _isWritingAsync

template<class T >
bool Socket< T >::_isWritingAsync
private

◆ _proxyHeaderReadingState

◆ _readBuffer

◆ _remoteAddress

template<class T >
boost::asio::ip::address Socket< T >::_remoteAddress
private

◆ _remotePort

template<class T >
uint16 Socket< T >::_remotePort
private

◆ _socket

◆ _state

◆ _writeQueue

template<class T >
std::queue<MessageBuffer> Socket< T >::_writeQueue
private

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