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 (tcp::socket &&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. More...
 
MessageBufferGetReadBuffer ()
 

Protected Member Functions

virtual void OnClose ()
 
virtual void 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

tcp::socket _socket
 
boost::asio::ip::address _remoteAddress
 
uint16 _remotePort
 
MessageBuffer _readBuffer
 
std::queue< MessageBuffer_writeQueue
 
std::atomic< bool > _closed
 
std::atomic< bool > _closing
 
bool _isWritingAsync
 
ProxyHeaderReadingState _proxyHeaderReadingState
 

Detailed Description

template<class T>
class Socket< T >

Constructor & Destructor Documentation

◆ Socket()

template<class T >
Socket< T >::Socket ( tcp::socket &&  socket)
inlineexplicit
54 : _socket(std::move(socket)), _remoteAddress(_socket.remote_endpoint().address()),
55 _remotePort(_socket.remote_endpoint().port()), _readBuffer(), _closed(false), _closing(false), _isWritingAsync(false),
57 {
59 }
#define READ_BLOCK_SIZE
Definition: Socket.h:33
@ PROXY_HEADER_READING_STATE_NOT_STARTED
Definition: Socket.h:39
void Resize(size_type bytes)
Definition: MessageBuffer.h:52
uint16 _remotePort
Definition: Socket.h:419
std::atomic< bool > _closing
Definition: Socket.h:425
std::atomic< bool > _closed
Definition: Socket.h:424
boost::asio::ip::address _remoteAddress
Definition: Socket.h:418
ProxyHeaderReadingState _proxyHeaderReadingState
Definition: Socket.h:429
tcp::socket _socket
Definition: Socket.h:416
MessageBuffer _readBuffer
Definition: Socket.h:421
bool _isWritingAsync
Definition: Socket.h:427

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

◆ ~Socket()

template<class T >
virtual Socket< T >::~Socket ( )
inlinevirtual
62 {
63 _closed = true;
64 boost::system::error_code error;
65 _socket.close(error);
66 }

References Socket< T >::_closed, and Socket< T >::_socket.

Member Function Documentation

◆ AsyncProcessQueue()

template<class T >
bool Socket< T >::AsyncProcessQueue ( )
inlineprotected
180 {
181 if (_isWritingAsync)
182 return false;
183
184 _isWritingAsync = true;
185
186#ifdef AC_SOCKET_USE_IOCP
187 MessageBuffer& buffer = _writeQueue.front();
188 _socket.async_write_some(boost::asio::buffer(buffer.GetReadPointer(), buffer.GetActiveSize()), std::bind(&Socket<T>::WriteHandler,
189 this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
190#else
191 _socket.async_write_some(boost::asio::null_buffers(), std::bind(&Socket<T>::WriteHandlerWrapper,
192 this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
193#endif
194 return false;
195 }
Definition: MessageBuffer.h:26
uint8 * GetReadPointer()
Definition: MessageBuffer.h:58
size_type GetActiveSize() const
Definition: MessageBuffer.h:64
Definition: Socket.h:52
std::queue< MessageBuffer > _writeQueue
Definition: Socket.h:422

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
101 {
102 if (!IsOpen())
103 {
104 return;
105 }
106
109 _socket.async_read_some(boost::asio::buffer(_readBuffer.GetWritePointer(), _readBuffer.GetRemainingSpace()),
110 std::bind(&Socket<T>::ReadHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
111 }
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:153

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

◆ 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
129 {
130 if (!IsOpen())
131 {
132 return;
133 }
134
137
138 _socket.async_read_some(boost::asio::buffer(_readBuffer.GetWritePointer(), _readBuffer.GetRemainingSpace()),
139 std::bind(callback, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
140 }

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
156 {
157 if (_closed.exchange(true))
158 return;
159
160 boost::system::error_code shutdownError;
161 _socket.shutdown(boost::asio::socket_base::shutdown_send, shutdownError);
162
163 if (shutdownError)
164 LOG_DEBUG("network", "Socket::CloseSocket: {} errored when shutting down socket: {} ({})", GetRemoteIpAddress().to_string(),
165 shutdownError.value(), shutdownError.message());
166
167 OnClose();
168 }
#define LOG_DEBUG(filterType__,...)
Definition: Log.h:168
boost::asio::ip::address GetRemoteIpAddress() const
Definition: Socket.h:90
virtual void OnClose()
Definition: Socket.h:176

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

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.

171{ _closing = true; }

References Socket< T >::_closing.

◆ 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
96 {
97 return _remotePort;
98 }

References Socket< T >::_remotePort.

◆ HandleQueue()

template<class T >
bool Socket< T >::HandleQueue ( )
inlineprivate
361 {
362 if (_writeQueue.empty())
363 return false;
364
365 MessageBuffer& queuedMessage = _writeQueue.front();
366
367 std::size_t bytesToSend = queuedMessage.GetActiveSize();
368
369 boost::system::error_code error;
370 std::size_t bytesSent = _socket.write_some(boost::asio::buffer(queuedMessage.GetReadPointer(), bytesToSend), error);
371
372 if (error)
373 {
374 if (error == boost::asio::error::would_block || error == boost::asio::error::try_again)
375 {
376 return AsyncProcessQueue();
377 }
378
379 _writeQueue.pop();
380
381 if (_closing && _writeQueue.empty())
382 {
383 CloseSocket();
384 }
385
386 return false;
387 }
388 else if (bytesSent == 0)
389 {
390 _writeQueue.pop();
391
392 if (_closing && _writeQueue.empty())
393 {
394 CloseSocket();
395 }
396
397 return false;
398 }
399 else if (bytesSent < bytesToSend) // now n > 0
400 {
401 queuedMessage.ReadCompleted(bytesSent);
402 return AsyncProcessQueue();
403 }
404
405 _writeQueue.pop();
406
407 if (_closing && _writeQueue.empty())
408 {
409 CloseSocket();
410 }
411
412 return !_writeQueue.empty();
413 }
void ReadCompleted(size_type bytes)
Definition: MessageBuffer.h:61
bool AsyncProcessQueue()
Definition: Socket.h:179
void CloseSocket()
Definition: Socket.h:155

References Socket< T >::_closing, Socket< T >::_socket, Socket< T >::_writeQueue, Socket< T >::AsyncProcessQueue(), Socket< T >::CloseSocket(), 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.

176{ }

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

◆ ProxyReadHeaderHandler()

template<class T >
void Socket< T >::ProxyReadHeaderHandler ( boost::system::error_code  error,
std::size_t  transferredBytes 
)
inlineprivate
223 {
224 if (error)
225 {
226 CloseSocket();
227 return;
228 }
229
230 _readBuffer.WriteCompleted(transferredBytes);
231
232 MessageBuffer& packet = GetReadBuffer();
233
234 const int minimumProxyProtocolV2Size = 28;
235 if (packet.GetActiveSize() < minimumProxyProtocolV2Size)
236 {
238 return;
239 }
240
241 uint8* readPointer = packet.GetReadPointer();
242
243 const uint8 signatureSize = 12;
244 const uint8 expectedSignature[signatureSize] = {0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A};
245 if (memcmp(packet.GetReadPointer(), expectedSignature, signatureSize) != 0)
246 {
248 LOG_ERROR("network", "Socket::ProxyReadHeaderHandler: received bad PROXY Protocol v2 signature for {}", GetRemoteIpAddress().to_string());
249 return;
250 }
251
252 const uint8 version = (readPointer[signatureSize] & 0xF0) >> 4;
253 const uint8 command = (readPointer[signatureSize] & 0xF);
254
255 if (version != 2)
256 {
258 LOG_ERROR("network", "Socket::ProxyReadHeaderHandler: received bad PROXY Protocol v2 signature for {}", GetRemoteIpAddress().to_string());
259 return;
260 }
261
262 const uint8 addressFamily = readPointer[13];
263 const uint16 len = (readPointer[14] << 8) | readPointer[15];
264 if (static_cast<size_t>(len+16) > packet.GetActiveSize())
265 {
267 return;
268 }
269
270 // Connection created by a proxy itself (health checks?), ignore and do nothing.
271 if (command == 0)
272 {
273 packet.ReadCompleted(len+16);
275 return;
276 }
277
278 auto remainingLen = packet.GetActiveSize() - 16;
279 readPointer += 16; // Skip strait to address.
280
281 switch (addressFamily) {
283 {
284 if (remainingLen < 12)
285 {
287 return;
288 }
289
290 boost::asio::ip::address_v4::bytes_type b;
291 auto addressSize = sizeof(b);
292
293 std::copy(readPointer, readPointer+addressSize, b.begin());
294 _remoteAddress = boost::asio::ip::address_v4(b);
295
296 readPointer += 2 * addressSize; // Skip server address.
297 _remotePort = (readPointer[0] << 8) | readPointer[1];
298
299 break;
300 }
301
303 {
304 if (remainingLen < 36)
305 {
307 return;
308 }
309
310 boost::asio::ip::address_v6::bytes_type b;
311 auto addressSize = sizeof(b);
312
313 std::copy(readPointer, readPointer+addressSize, b.begin());
314 _remoteAddress = boost::asio::ip::address_v6(b);
315
316 readPointer += 2 * addressSize; // Skip server address.
317 _remotePort = (readPointer[0] << 8) | readPointer[1];
318
319 break;
320 }
321
322 default:
324 LOG_ERROR("network", "Socket::ProxyReadHeaderHandler: unsupported address family type {}", GetRemoteIpAddress().to_string());
325 return;
326 }
327
328 packet.ReadCompleted(len+16);
330 }
#define LOG_ERROR(filterType__,...)
Definition: Log.h:156
std::uint8_t uint8
Definition: Define.h:109
std::uint16_t uint16
Definition: Define.h:108
@ PROXY_HEADER_ADDRESS_FAMILY_AND_PROTOCOL_TCP_V6
Definition: Socket.h:47
@ PROXY_HEADER_ADDRESS_FAMILY_AND_PROTOCOL_TCP_V4
Definition: Socket.h:46
@ PROXY_HEADER_READING_STATE_FINISHED
Definition: Socket.h:41
@ PROXY_HEADER_READING_STATE_FAILED
Definition: Socket.h:42
void WriteCompleted(size_type bytes)
Definition: MessageBuffer.h:62
MessageBuffer & GetReadBuffer()
Definition: Socket.h:173
void AsyncReadProxyHeader()
Definition: Socket.h:113

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
143 {
144 _writeQueue.push(std::move(buffer));
145
146#ifdef AC_SOCKET_USE_IOCP
148#endif
149 }

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

◆ ReadHandler()

template<class T >
virtual void 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
209 {
210 if (error)
211 {
212 CloseSocket();
213 return;
214 }
215
216 _readBuffer.WriteCompleted(transferredBytes);
217 ReadHandler();
218 }
virtual void ReadHandler()=0

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

◆ SetNoDelay()

template<class T >
void Socket< T >::SetNoDelay ( bool  enable)
inlineprotected
198 {
199 boost::system::error_code err;
200 _socket.set_option(tcp::no_delay(enable), err);
201
202 if (err)
203 LOG_DEBUG("network", "Socket::SetNoDelay: failed to set_option(boost::asio::ip::tcp::no_delay) for {} - {} ({})",
204 GetRemoteIpAddress().to_string(), err.value(), err.message());
205 }

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.

71 {
72 if (_closed)
73 {
74 return false;
75 }
76
77#ifndef AC_SOCKET_USE_IOCP
78 if (_isWritingAsync || (_writeQueue.empty() && !_closing))
79 {
80 return true;
81 }
82
83 for (; HandleQueue();)
84 ;
85#endif
86
87 return true;
88 }
bool HandleQueue()
Definition: Socket.h:360

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

◆ WriteHandlerWrapper()

template<class T >
void Socket< T >::WriteHandlerWrapper ( boost::system::error_code  ,
std::size_t   
)
inlineprivate
355 {
356 _isWritingAsync = false;
357 HandleQueue();
358 }

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

Member Data Documentation

◆ _closed

template<class T >
std::atomic<bool> Socket< T >::_closed
private

◆ _closing

template<class T >
std::atomic<bool> Socket< T >::_closing
private

◆ _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

◆ _writeQueue

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