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.
 
MessageBuffer & GetReadBuffer ()
 

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:157
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:145
@ 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: