Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
RealmSocket.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "Log.h"
8#include "RealmSocket.h"
9#include <boost/asio/buffer.hpp>
10#include <boost/asio/error.hpp>
11#include <boost/asio/post.hpp>
12#include <boost/asio/write.hpp>
13#include <algorithm>
14#include <cstring>
15#include <string>
16#include <utility>
17
18namespace
19{
20std::string GetAuthOpcodeNameForLogging(uint8 opcode)
21{
22 switch (opcode)
23 {
24 case 0x00:
25 return "AUTH_LOGON_CHALLENGE";
26 case 0x01:
27 return "AUTH_LOGON_PROOF";
28 case 0x02:
29 return "AUTH_RECONNECT_CHALLENGE";
30 case 0x03:
31 return "AUTH_RECONNECT_PROOF";
32 case 0x10:
33 return "REALM_LIST";
34 case 0x32:
35 return "XFER_ACCEPT";
36 case 0x33:
37 return "XFER_RESUME";
38 case 0x34:
39 return "XFER_CANCEL";
40 default:
41 return "UNKNOWN_AUTH_OPCODE";
42 }
43}
44}
45
47
49
50RealmSocket::RealmSocket(std::unique_ptr<RealmSocketHandle> socket, std::string remoteAddress, uint16 remotePort) :
51 _socket(std::move(socket)), _readBuffer(), _inputBuffer(), _inputReadPos(0), _session(),
52 _remoteAddress(std::move(remoteAddress)), _packetLogAccountName(), _remotePort(remotePort), _writeQueue(),
53 _writeInProgress(false), _closed(false), _closeNotified(false)
54{
55 _inputBuffer.reserve(4096);
56}
57
62
64{
65 if (_session)
66 _session->OnAccept();
67
68 AsyncRead();
69}
70
72{
74}
75
76const std::string& RealmSocket::getRemoteAddress(void) const
77{
78 return _remoteAddress;
79}
80
82{
83 return _remotePort;
84}
85
86void RealmSocket::SetPacketLogAccountName(std::string accountName)
87{
88 _packetLogAccountName = std::move(accountName);
89 sPacketLogServer->RefreshSessionInfo(this, BuildPacketLogSessionInfo());
90}
91
93{
94 return _inputBuffer.size() - _inputReadPos;
95}
96
97bool RealmSocket::PeekBytes(void* buf, size_t len, size_t offset) const
98{
99 if (len == 0)
100 return true;
101
102 if (buf == NULL)
103 return false;
104
105 size_t availableBytes = GetAvailableBytes();
106 if (offset > availableBytes || len > availableBytes - offset)
107 return false;
108
109 memcpy(buf, _inputBuffer.data() + _inputReadPos + offset, len);
110 return true;
111}
112
113bool RealmSocket::ReadBytes(void* buf, size_t len)
114{
115 bool ret = PeekBytes(buf, len);
116
117 if (ret)
118 DiscardBytes(len);
119
120 return ret;
121}
122
124{
125 _inputReadPos = std::min(_inputReadPos + len, _inputBuffer.size());
126}
127
128bool RealmSocket::QueueSend(void const* buf, size_t len)
129{
130 if (buf == NULL || len == 0)
131 return true;
132
133 if (_closed)
134 return false;
135
136 char const* bytes = static_cast<char const*>(buf);
137 std::vector<char> data(bytes, bytes + len);
138 LogAuthPacket(data.data(), data.size(), Skyfire::PACKET_LOG_SERVER_TO_CLIENT);
139
140 std::shared_ptr<RealmSocket> self = shared_from_this();
141 boost::asio::post(_socket->get_executor(),
142 [self, data = std::move(data)]() mutable
143 {
144 self->QueueWrite(std::move(data));
145 });
146
147 return true;
148}
149
150void RealmSocket::set_session(std::unique_ptr<Session> session)
151{
152 _session = std::move(session);
153}
154
156{
157 AsyncRead();
158}
159
161{
162 if (_closed || !IsOpen())
163 return;
164
165 std::shared_ptr<RealmSocket> self = shared_from_this();
166 _socket->async_read_some(boost::asio::buffer(_readBuffer),
167 [self](boost::system::error_code const& error, size_t bytesTransferred)
168 {
169 self->HandleRead(error, bytesTransferred);
170 });
171}
172
173void RealmSocket::HandleRead(boost::system::error_code const& error, size_t bytesTransferred)
174{
175 if (error || bytesTransferred == 0)
176 {
177 CloseSocket();
178 return;
179 }
180
181 _inputBuffer.insert(_inputBuffer.end(), _readBuffer.data(), _readBuffer.data() + bytesTransferred);
183
184 if (_session)
185 {
186 _session->OnRead();
188 }
189
190 if (!_closed)
191 AsyncRead();
192}
193
194void RealmSocket::QueueWrite(std::vector<char> data)
195{
196 if (_closed || !IsOpen())
197 return;
198
199 bool startWrite = !_writeInProgress && _writeQueue.empty();
200 _writeQueue.push_back(std::move(data));
201
202 if (startWrite)
204}
205
207{
208 if (_closed || _writeInProgress || _writeQueue.empty() || !IsOpen())
209 return;
210
211 _writeInProgress = true;
212
213 std::shared_ptr<RealmSocket> self = shared_from_this();
214 boost::asio::async_write(*_socket, boost::asio::buffer(_writeQueue.front()),
215 [self](boost::system::error_code const& error, size_t)
216 {
217 self->HandleWrite(error);
218 });
219}
220
221void RealmSocket::HandleWrite(boost::system::error_code const& error)
222{
223 if (!_writeQueue.empty())
224 _writeQueue.pop_front();
225
226 _writeInProgress = false;
227
228 if (error)
229 {
230 if (error != boost::asio::error::operation_aborted)
231 {
232 SF_LOG_DEBUG("server.authserver", "Socket send failed for %s:%u with error %d",
233 _remoteAddress.c_str(), _remotePort, error.value());
234 }
235
236 CloseSocket();
237 return;
238 }
239
240 if (!_writeQueue.empty())
242}
243
244bool RealmSocket::IsOpen(void) const
245{
246 return _socket && _socket->is_open();
247}
248
250{
251 bool expected = false;
252 if (!_closed.compare_exchange_strong(expected, true))
253 return;
254
255 if (IsOpen())
257
258 NotifyClose();
259}
260
262{
263 bool expected = false;
264 if (!_closeNotified.compare_exchange_strong(expected, true))
265 return;
266
267 if (_session)
268 _session->OnClose();
269
270 sPacketLogServer->CloseSession(this);
271}
272
274{
275 if (_inputReadPos == 0)
276 return;
277
278 if (_inputReadPos >= _inputBuffer.size())
279 _inputBuffer.clear();
280 else
281 _inputBuffer.erase(_inputBuffer.begin(), _inputBuffer.begin() + ptrdiff_t(_inputReadPos));
282
283 _inputReadPos = 0;
284}
285
287{
289 sessionInfo.RemoteAddress = _remoteAddress;
291 sessionInfo.SessionName = "auth";
292 sessionInfo.FilePrefix = "authsession";
293 return sessionInfo;
294}
295
296void RealmSocket::LogAuthPacket(void const* data, size_t len, Skyfire::PacketLogServerDirection direction)
297{
298 if (!sPacketLogServer->CanLogPacket())
299 return;
300
301 uint32 opcode = 0;
302 if (data && len > 0)
303 opcode = *static_cast<uint8 const*>(data);
304
305 sPacketLogServer->LogPacket(this, BuildPacketLogSessionInfo(), direction, opcode,
306 GetAuthOpcodeNameForLogging(uint8(opcode)), data, len);
307}
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
std::uint16_t uint16
Definition Define.h:78
#define SF_LOG_DEBUG(filterType__,...)
Definition Log.h:134
#define sPacketLogServer
virtual ~Session(void)
std::string _packetLogAccountName
Definition RealmSocket.h:76
size_t _inputReadPos
Definition RealmSocket.h:73
void LogAuthPacket(void const *data, size_t len, Skyfire::PacketLogServerDirection direction)
bool PeekBytes(void *buf, size_t len, size_t offset=0) const
void HandleRead(boost::system::error_code const &error, size_t bytesTransferred)
std::deque< std::vector< char > > _writeQueue
Definition RealmSocket.h:78
bool IsOpen(void) const
std::unique_ptr< Session > _session
Definition RealmSocket.h:74
uint16 getRemotePort(void) const
size_t GetAvailableBytes(void) const
bool ReadBytes(void *buf, size_t len)
void CloseSocket()
bool _writeInProgress
Definition RealmSocket.h:79
RealmSocket(std::unique_ptr< RealmSocketHandle > socket, std::string remoteAddress, uint16 remotePort)
void set_session(std::unique_ptr< Session > session)
std::string _remoteAddress
Definition RealmSocket.h:75
Skyfire::PacketLogServerSessionInfo BuildPacketLogSessionInfo() const
const std::string & getRemoteAddress(void) const
std::vector< char > _inputBuffer
Definition RealmSocket.h:72
void DiscardBytes(size_t len)
bool QueueSend(void const *buf, size_t len)
std::atomic< bool > _closeNotified
Definition RealmSocket.h:81
std::atomic< bool > _closed
Definition RealmSocket.h:80
std::array< char, 4096 > _readBuffer
Definition RealmSocket.h:71
void CompactInputBuffer()
~RealmSocket(void)
std::unique_ptr< RealmSocketHandle > _socket
Definition RealmSocket.h:70
void SetPacketLogAccountName(std::string accountName)
void HandleWrite(boost::system::error_code const &error)
void QueueWrite(std::vector< char > data)
void StartAsyncWrite()
uint16 _remotePort
Definition RealmSocket.h:77
void NotifyClose()
void CloseTcpSocket(boost::asio::ip::tcp::socket &socket)
@ PACKET_LOG_SERVER_TO_CLIENT
@ PACKET_LOG_CLIENT_TO_SERVER