TrinityCore
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Battlenet::Session Class Reference

#include <Session.h>

Classes

struct  AccountInfo
 
struct  GameAccountInfo
 
struct  LastPlayedCharacterInfo
 

Public Member Functions

 Session (tcp::socket &&socket)
 
 ~Session ()
 
void Start () override
 
bool Update () override
 
uint32 GetAccountId () const
 
uint32 GetGameAccountId () const
 
void SendResponse (uint32 token, pb::Message const *response)
 
void SendResponse (uint32 token, uint32 status)
 
void SendRequest (uint32 serviceHash, uint32 methodId, pb::Message const *request, std::function< void(MessageBuffer)> callback)
 
void SendRequest (uint32 serviceHash, uint32 methodId, pb::Message const *request)
 
uint32 HandleLogon (authentication::v1::LogonRequest const *logonRequest)
 
uint32 HandleVerifyWebCredentials (authentication::v1::VerifyWebCredentialsRequest const *verifyWebCredentialsRequest)
 
uint32 HandleGetAccountState (account::v1::GetAccountStateRequest const *request, account::v1::GetAccountStateResponse *response)
 
uint32 HandleGetGameAccountState (account::v1::GetGameAccountStateRequest const *request, account::v1::GetGameAccountStateResponse *response)
 
uint32 HandleProcessClientRequest (game_utilities::v1::ClientRequest const *request, game_utilities::v1::ClientResponse *response)
 
uint32 HandleGetAllValuesForAttribute (game_utilities::v1::GetAllValuesForAttributeRequest const *request, game_utilities::v1::GetAllValuesForAttributeResponse *response)
 
std::string GetClientInfo () const
 
- Public Member Functions inherited from Socket< Session, SslSocket< SslContext > >
 Socket (tcp::socket &&socket)
 
virtual ~Socket ()
 
boost::asio::ip::address GetRemoteIpAddress () const
 
uint16 GetRemotePort () const
 
void AsyncRead ()
 
void AsyncReadWithCallback (void(Session::*callback)(boost::system::error_code, std::size_t))
 
void QueuePacket (MessageBuffer &&buffer)
 
bool IsOpen () const
 
void CloseSocket ()
 
void DelayedCloseSocket ()
 Marks the socket for closing after write buffer becomes empty. More...
 
MessageBufferGetReadBuffer ()
 

Protected Member Functions

void HandshakeHandler (boost::system::error_code const &error)
 
void ReadHandler () override
 
bool ReadHeaderLengthHandler ()
 
bool ReadHeaderHandler ()
 
bool ReadDataHandler ()
 
- Protected Member Functions inherited from Socket< Session, SslSocket< SslContext > >
virtual void OnClose ()
 
bool AsyncProcessQueue ()
 
void SetNoDelay (bool enable)
 
SslSocket< SslContext > & underlying_stream ()
 

Private Types

typedef Socket< Session,
SslSocket< SslContext > > 
BattlenetSocket
 
typedef uint32(Session::* ClientRequestHandler )(std::unordered_map< std::string, Variant const * > const &, game_utilities::v1::ClientResponse *)
 

Private Member Functions

void AsyncWrite (MessageBuffer *packet)
 
void AsyncHandshake ()
 
void CheckIpCallback (PreparedQueryResult result)
 
uint32 GetRealmListTicket (std::unordered_map< std::string, Variant const * > const &params, game_utilities::v1::ClientResponse *response)
 
uint32 GetLastCharPlayed (std::unordered_map< std::string, Variant const * > const &params, game_utilities::v1::ClientResponse *response)
 
uint32 GetRealmList (std::unordered_map< std::string, Variant const * > const &params, game_utilities::v1::ClientResponse *response)
 
uint32 JoinRealm (std::unordered_map< std::string, Variant const * > const &params, game_utilities::v1::ClientResponse *response)
 

Private Attributes

MessageBuffer _headerLengthBuffer
 
MessageBuffer _headerBuffer
 
MessageBuffer _packetBuffer
 
std::unique_ptr< AccountInfo_accountInfo
 
GameAccountInfo_gameAccountInfo
 
std::string _locale
 
std::string _os
 
uint32 _build
 
std::string _ipCountry
 
std::array< uint8, 32 > _clientSecret
 
bool _authed
 
PreparedQueryResultFuture _queryFuture
 
std::function< void(PreparedQueryResult)> _queryCallback
 
std::unordered_map< uint32,
std::function< void(MessageBuffer)> > 
_responseCallbacks
 
uint32 _requestToken
 

Static Private Attributes

static std::unordered_map
< std::string,
ClientRequestHandler > const 
ClientRequestHandlers
 

Member Typedef Documentation

typedef uint32(Session::* Battlenet::Session::ClientRequestHandler)(std::unordered_map< std::string, Variant const * > const &, game_utilities::v1::ClientResponse *)
private

Constructor & Destructor Documentation

Battlenet::Session::Session ( tcp::socket &&  socket)
explicit
67  : BattlenetSocket(std::move(socket)), _accountInfo(new AccountInfo()), _gameAccountInfo(nullptr), _locale(),
68  _os(), _build(0), _ipCountry(), _authed(false), _requestToken(0)
69 {
71 }
GameAccountInfo * _gameAccountInfo
Definition: Session.h:179
bool _authed
Definition: Session.h:189
uint32 _requestToken
Definition: Session.h:195
Definition: entity_types.pb.h:227
std::string _locale
Definition: Session.h:181
std::unique_ptr< AccountInfo > _accountInfo
Definition: Session.h:178
void Resize(size_type bytes)
Definition: MessageBuffer.h:51
MessageBuffer _headerLengthBuffer
Definition: Session.h:174
std::string _ipCountry
Definition: Session.h:185
Socket< Session, SslSocket< SslContext > > BattlenetSocket
Definition: Session.h:81
std::string _os
Definition: Session.h:182
uint32 _build
Definition: Session.h:183

+ Here is the call graph for this function:

Battlenet::Session::~Session ( )
74 {
75 }

Member Function Documentation

void Battlenet::Session::AsyncHandshake ( )
private
78 {
79  underlying_stream().async_handshake(ssl::stream_base::server, std::bind(&Session::HandshakeHandler, shared_from_this(), std::placeholders::_1));
80 }
SslSocket< SslContext > & underlying_stream()
Definition: Socket.h:194
void HandshakeHandler(boost::system::error_code const &error)
Definition: Session.cpp:562

+ Here is the call graph for this function:

void Battlenet::Session::AsyncWrite ( MessageBuffer packet)
private
141 {
142  if (!IsOpen())
143  return;
144 
145  QueuePacket(std::move(*packet));
146 }
bool IsOpen() const
Definition: Socket.h:140
void QueuePacket(MessageBuffer &&buffer)
Definition: Socket.h:131
void Battlenet::Session::CheckIpCallback ( PreparedQueryResult  result)
private
99 {
100  if (result)
101  {
102  bool banned = false;
103  do
104  {
105  Field* fields = result->Fetch();
106  if (fields[0].GetUInt64() != 0)
107  banned = true;
108 
109  if (!fields[1].GetString().empty())
110  _ipCountry = fields[1].GetString();
111 
112  } while (result->NextRow());
113 
114  if (banned)
115  {
116  TC_LOG_DEBUG("session", "%s tries to log in using banned IP!", GetClientInfo().c_str());
117  CloseSocket();
118  return;
119  }
120  }
121 
122  AsyncHandshake();
123 }
Class used to access individual fields of database query result.
Definition: Field.h:56
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:198
std::string GetClientInfo() const
Definition: Session.cpp:671
void AsyncHandshake()
Definition: Session.cpp:77
std::string _ipCountry
Definition: Session.h:185
std::string GetString() const
Definition: Field.h:276
void CloseSocket()
Definition: Socket.h:142

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

uint32 Battlenet::Session::GetAccountId ( ) const
inline
129 { return _accountInfo->Id; }
std::unique_ptr< AccountInfo > _accountInfo
Definition: Session.h:178
std::string Battlenet::Session::GetClientInfo ( ) const
672 {
673  std::ostringstream stream;
674  stream << '[' << GetRemoteIpAddress() << ':' << GetRemotePort();
675  if (_accountInfo && !_accountInfo->Login.empty())
676  stream << ", Account: " << _accountInfo->Login;
677 
678  if (_gameAccountInfo)
679  stream << ", Game account: " << _gameAccountInfo->Name;
680 
681  stream << ']';
682 
683  return stream.str();
684 }
GameAccountInfo * _gameAccountInfo
Definition: Session.h:179
boost::asio::ip::address GetRemoteIpAddress() const
Definition: Socket.h:99
std::string Name
Definition: Session.h:97
std::unique_ptr< AccountInfo > _accountInfo
Definition: Session.h:178
uint16 GetRemotePort() const
Definition: Socket.h:104

+ Here is the caller graph for this function:

uint32 Battlenet::Session::GetGameAccountId ( ) const
inline
130 { return _gameAccountInfo->Id; }
GameAccountInfo * _gameAccountInfo
Definition: Session.h:179
uint32 Id
Definition: Session.h:96
uint32 Battlenet::Session::GetLastCharPlayed ( std::unordered_map< std::string, Variant const * > const params,
game_utilities::v1::ClientResponse response 
)
private
465 {
466  if (Variant const* subRegion = GetParam(params, "Command_LastCharPlayedRequest_v1_b9"))
467  {
468  auto lastPlayerChar = _gameAccountInfo->LastPlayedCharacters.find(subRegion->string_value());
469  if (lastPlayerChar != _gameAccountInfo->LastPlayedCharacters.end())
470  {
471  std::vector<uint8> compressed = sRealmList->GetRealmEntryJSON(lastPlayerChar->second.RealmId, _build);
472 
473  if (compressed.empty())
475 
476  Attribute* attribute = response->add_attribute();
477  attribute->set_name("Param_RealmEntry");
478  attribute->mutable_value()->set_blob_value(compressed.data(), compressed.size());
479 
480  attribute = response->add_attribute();
481  attribute->set_name("Param_CharacterName");
482  attribute->mutable_value()->set_string_value(lastPlayerChar->second.CharacterName);
483 
484  attribute = response->add_attribute();
485  attribute->set_name("Param_CharacterGUID");
486  attribute->mutable_value()->set_blob_value(&lastPlayerChar->second.CharacterGUID, sizeof(lastPlayerChar->second.CharacterGUID));
487 
488  attribute = response->add_attribute();
489  attribute->set_name("Param_LastPlayedTime");
490  attribute->mutable_value()->set_int_value(int32(lastPlayerChar->second.LastPlayedTime));
491  }
492 
493  return ERROR_OK;
494  }
495 
497 }
Definition: attribute_types.pb.h:67
void set_name(const ::std::string &value)
Definition: attribute_types.pb.h:935
GameAccountInfo * _gameAccountInfo
Definition: Session.h:179
std::unordered_map< std::string, LastPlayedCharacterInfo > LastPlayedCharacters
Definition: Session.h:104
inline::bgs::protocol::Variant * mutable_value()
Definition: attribute_types.pb.h:1009
Definition: BattlenetRpcErrorCodes.h:594
inline::bgs::protocol::Attribute * add_attribute()
Definition: game_utilities_service.pb.h:1617
Definition: BattlenetRpcErrorCodes.h:25
Variant const * GetParam(std::unordered_map< std::string, Variant const * > const &params, char const *paramName)
Definition: Session.cpp:409
Definition: BattlenetRpcErrorCodes.h:604
int32_t int32
Definition: g3dmath.h:167
#define sRealmList
Definition: RealmList.h:101
uint32 _build
Definition: Session.h:183
Definition: attribute_types.pb.h:248

+ Here is the call graph for this function:

uint32 Battlenet::Session::GetRealmList ( std::unordered_map< std::string, Variant const * > const params,
game_utilities::v1::ClientResponse response 
)
private
500 {
501  if (!_gameAccountInfo)
503 
504  std::string subRegionId;
505  if (Variant const* subRegion = GetParam(params, "Command_RealmListRequest_v1_b9"))
506  subRegionId = subRegion->string_value();
507 
508  std::vector<uint8> compressed = sRealmList->GetRealmList(_build, subRegionId);
509 
510  if (compressed.empty())
512 
513  Attribute* attribute = response->add_attribute();
514  attribute->set_name("Param_RealmList");
515  attribute->mutable_value()->set_blob_value(compressed.data(), compressed.size());
516 
517  ::JSON::RealmList::RealmCharacterCountList realmCharacterCounts;
518  for (auto const& characterCount : _gameAccountInfo->CharacterCounts)
519  {
520  ::JSON::RealmList::RealmCharacterCountEntry* countEntry = realmCharacterCounts.add_counts();
521  countEntry->set_wowrealmaddress(characterCount.first);
522  countEntry->set_count(characterCount.second);
523  }
524 
525  std::string json = "JSONRealmCharacterCountList:" + ::JSON::Serialize(realmCharacterCounts);
526 
527  uLongf compressedLength = compressBound(json.length());
528  compressed.resize(4 + compressedLength);
529  *reinterpret_cast<uint32*>(compressed.data()) = json.length() + 1;
530 
531  if (compress(compressed.data() + 4, &compressedLength, reinterpret_cast<uint8 const*>(json.c_str()), json.length() + 1) != Z_OK)
533 
534  attribute = response->add_attribute();
535  attribute->set_name("Param_CharacterCountList");
536  attribute->mutable_value()->set_blob_value(compressed.data(), compressedLength + 4);
537  return ERROR_OK;
538 }
Definition: attribute_types.pb.h:67
void set_name(const ::std::string &value)
Definition: attribute_types.pb.h:935
GameAccountInfo * _gameAccountInfo
Definition: Session.h:179
inline::bgs::protocol::Variant * mutable_value()
Definition: attribute_types.pb.h:1009
TC_SHARED_API std::string Serialize(google::protobuf::Message const &message)
Definition: ProtobufJSON.cpp:438
std::unordered_map< uint32, uint8 > CharacterCounts
Definition: Session.h:103
Definition: RealmList.pb.h:542
uint32_t uint32
Definition: Define.h:150
Definition: RealmList.pb.h:466
void set_count(::google::protobuf::uint32 value)
Definition: RealmList.pb.h:1814
inline::bgs::protocol::Attribute * add_attribute()
Definition: game_utilities_service.pb.h:1617
Definition: BattlenetRpcErrorCodes.h:25
uLong FAR uLongf
Definition: zconf.h:382
Variant const * GetParam(std::unordered_map< std::string, Variant const * > const &params, char const *paramName)
Definition: Session.cpp:409
Definition: BattlenetRpcErrorCodes.h:604
#define sRealmList
Definition: RealmList.h:101
#define Z_OK
Definition: zlib.h:173
uint8_t uint8
Definition: Define.h:152
#define const
Definition: zconf.h:217
void set_wowrealmaddress(::google::protobuf::uint32 value)
Definition: RealmList.pb.h:1790
uint32 _build
Definition: Session.h:183
Definition: BattlenetRpcErrorCodes.h:624
inline::JSON::RealmList::RealmCharacterCountEntry * add_counts()
Definition: RealmList.pb.h:1839
Definition: attribute_types.pb.h:248

+ Here is the call graph for this function:

uint32 Battlenet::Session::GetRealmListTicket ( std::unordered_map< std::string, Variant const * > const params,
game_utilities::v1::ClientResponse response 
)
private
416 {
417  if (Variant const* identity = GetParam(params, "Param_Identity"))
418  {
420  std::size_t jsonStart = identity->blob_value().find(':');
421  if (jsonStart != std::string::npos && ::JSON::Deserialize(identity->blob_value().substr(jsonStart + 1), &data))
422  {
423  auto itr = _accountInfo->GameAccounts.find(data.gameaccountid());
424  if (itr != _accountInfo->GameAccounts.end())
425  _gameAccountInfo = &itr->second;
426  }
427  }
428 
429  if (!_gameAccountInfo)
431 
432  if (Variant const* clientInfo = GetParam(params, "Param_ClientInfo"))
433  {
435  std::size_t jsonStart = clientInfo->blob_value().find(':');
436  if (jsonStart != std::string::npos && ::JSON::Deserialize(clientInfo->blob_value().substr(jsonStart + 1), &data))
437  {
438  if (_clientSecret.size() == data.info().secret().size())
439  {
440  _build = data.info().version().versionbuild();
441  memcpy(_clientSecret.data(), data.info().secret().data(), _clientSecret.size());
442  }
443  }
444  }
445 
446  if (!_build)
448 
450  stmt->setString(0, GetRemoteIpAddress().to_string());
451  stmt->setUInt8(1, GetLocaleByName(_locale));
452  stmt->setString(2, _os);
453  stmt->setUInt32(3, _accountInfo->Id);
454 
455  LoginDatabase.Execute(stmt);
456 
457  Attribute* attribute = response->add_attribute();
458  attribute->set_name("Param_RealmListTicket");
459  attribute->mutable_value()->set_blob_value("AuthRealmListTicket");
460 
461  return ERROR_OK;
462 }
Definition: attribute_types.pb.h:67
void Execute(const char *sql)
Definition: DatabaseWorkerPool.h:87
Definition: BattlenetRpcErrorCodes.h:599
Definition: LoginDatabase.h:114
const ::JSON::RealmList::ClientInformation & info() const
Definition: RealmList.pb.h:1741
void set_name(const ::std::string &value)
Definition: attribute_types.pb.h:935
const ::JSON::RealmList::ClientVersion & version() const
Definition: RealmList.pb.h:1620
GameAccountInfo * _gameAccountInfo
Definition: Session.h:179
std::array< uint8, 32 > _clientSecret
Definition: Session.h:187
inline::google::protobuf::uint32 gameaccountid() const
Definition: RealmList.pb.h:1172
void setUInt8(const uint8 index, const uint8 value)
Definition: PreparedStatement.cpp:97
boost::asio::ip::address GetRemoteIpAddress() const
Definition: Socket.h:99
void setString(const uint8 index, const std::string &value)
Definition: PreparedStatement.cpp:187
inline::google::protobuf::uint32 versionbuild() const
Definition: RealmList.pb.h:1296
inline::bgs::protocol::Variant * mutable_value()
Definition: attribute_types.pb.h:1009
Definition: PreparedStatement.h:74
LoginDatabaseWorkerPool LoginDatabase
Accessor to the realm/login database.
Definition: DatabaseEnv.cpp:22
std::string _locale
Definition: Session.h:181
LocaleConstant GetLocaleByName(const std::string &name)
Definition: Common.cpp:37
TC_SHARED_API bool Deserialize(std::string json, google::protobuf::Message *message)
Definition: ProtobufJSON.cpp:445
std::unique_ptr< AccountInfo > _accountInfo
Definition: Session.h:178
PreparedStatement * GetPreparedStatement(PreparedStatementIndex index)
Definition: DatabaseWorkerPool.h:263
void setUInt32(const uint8 index, const uint32 value)
Definition: PreparedStatement.cpp:115
const ::std::string & secret() const
Definition: RealmList.pb.h:1663
inline::bgs::protocol::Attribute * add_attribute()
Definition: game_utilities_service.pb.h:1617
Definition: BattlenetRpcErrorCodes.h:25
Variant const * GetParam(std::unordered_map< std::string, Variant const * > const &params, char const *paramName)
Definition: Session.cpp:409
std::string _os
Definition: Session.h:182
uint32 _build
Definition: Session.h:183
Definition: RealmList.pb.h:53
Definition: BattlenetRpcErrorCodes.h:647
Definition: attribute_types.pb.h:248

+ Here is the call graph for this function:

uint32 Battlenet::Session::HandleGetAccountState ( account::v1::GetAccountStateRequest const request,
account::v1::GetAccountStateResponse response 
)
320 {
321  if (!_authed)
322  return ERROR_DENIED;
323 
324  if (request->options().field_privacy_info())
325  {
326  response->mutable_state()->mutable_privacy_info()->set_is_using_rid(false);
327  response->mutable_state()->mutable_privacy_info()->set_is_real_id_visible_for_view_friends(false);
328  response->mutable_state()->mutable_privacy_info()->set_is_hidden_from_friend_finder(true);
329 
330  response->mutable_tags()->set_privacy_info_tag(0xD7CA834D);
331  }
332 
333  return ERROR_OK;
334 }
inline::bgs::protocol::account::v1::AccountFieldTags * mutable_tags()
Definition: account_service.pb.h:5122
bool _authed
Definition: Session.h:189
Definition: BattlenetRpcErrorCodes.h:25
Definition: BattlenetRpcErrorCodes.h:28
inline::bgs::protocol::account::v1::AccountState * mutable_state()
Definition: account_service.pb.h:5081

+ Here is the call graph for this function:

uint32 Battlenet::Session::HandleGetAllValuesForAttribute ( game_utilities::v1::GetAllValuesForAttributeRequest const request,
game_utilities::v1::GetAllValuesForAttributeResponse response 
)
549 {
550  if (!_authed)
551  return ERROR_DENIED;
552 
553  if (request->attribute_key() == "Command_RealmListRequest_v1_b9")
554  {
555  sRealmList->WriteSubRegions(response);
556  return ERROR_OK;
557  }
558 
560 }
bool _authed
Definition: Session.h:189
Definition: BattlenetRpcErrorCodes.h:233
Definition: BattlenetRpcErrorCodes.h:25
#define sRealmList
Definition: RealmList.h:101
Definition: BattlenetRpcErrorCodes.h:28

+ Here is the call graph for this function:

uint32 Battlenet::Session::HandleGetGameAccountState ( account::v1::GetGameAccountStateRequest const request,
account::v1::GetGameAccountStateResponse response 
)
337 {
338  if (!_authed)
339  return ERROR_DENIED;
340 
341  if (request->options().field_game_level_info())
342  {
343  auto itr = _accountInfo->GameAccounts.find(request->game_account_id().low());
344  if (itr != _accountInfo->GameAccounts.end())
345  {
346  response->mutable_state()->mutable_game_level_info()->set_name(itr->second.DisplayName);
347  response->mutable_state()->mutable_game_level_info()->set_program(5730135); // WoW
348  }
349 
350  response->mutable_tags()->set_game_level_info_tag(0x5C46D483);
351  }
352 
353  if (request->options().field_game_status())
354  {
355  auto itr = _accountInfo->GameAccounts.find(request->game_account_id().low());
356  if (itr != _accountInfo->GameAccounts.end())
357  {
358  response->mutable_state()->mutable_game_status()->set_is_suspended(itr->second.IsBanned);
359  response->mutable_state()->mutable_game_status()->set_is_banned(itr->second.IsPermanenetlyBanned);
360  }
361 
362  response->mutable_state()->mutable_game_status()->set_program(5730135); // WoW
363  response->mutable_tags()->set_game_status_tag(0x98B75F99);
364  }
365 
366  return ERROR_OK;
367 }
inline::bgs::protocol::account::v1::GameAccountFieldTags * mutable_tags()
Definition: account_service.pb.h:5376
inline::bgs::protocol::account::v1::GameAccountState * mutable_state()
Definition: account_service.pb.h:5335
bool _authed
Definition: Session.h:189
std::unique_ptr< AccountInfo > _accountInfo
Definition: Session.h:178
Definition: BattlenetRpcErrorCodes.h:25
Definition: BattlenetRpcErrorCodes.h:28

+ Here is the call graph for this function:

uint32 Battlenet::Session::HandleLogon ( authentication::v1::LogonRequest const logonRequest)
214 {
215  if (logonRequest->program() != "WoW")
216  {
217  TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log in with game other than WoW (using %s)!", GetClientInfo().c_str(), logonRequest->program().c_str());
218  return ERROR_BAD_PROGRAM;
219  }
220 
221  if (logonRequest->platform() != "Win" && logonRequest->platform() != "Wn64" && logonRequest->platform() != "Mc64")
222  {
223  TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log in from an unsupported platform (using %s)!", GetClientInfo().c_str(), logonRequest->platform().c_str());
224  return ERROR_BAD_PLATFORM;
225  }
226 
227  if (GetLocaleByName(logonRequest->locale()) == LOCALE_enUS && logonRequest->locale() != "enUS")
228  {
229  TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log in with unsupported locale (using %s)!", GetClientInfo().c_str(), logonRequest->locale().c_str());
230  return ERROR_BAD_LOCALE;
231  }
232 
233  _locale = logonRequest->locale();
234  _os = logonRequest->platform();
235 
236  ip::tcp::endpoint const& endpoint = sLoginService.GetAddressForClient(GetRemoteIpAddress());
237 
238  challenge::v1::ChallengeExternalRequest externalChallenge;
239  externalChallenge.set_payload_type("web_auth_url");
240  externalChallenge.set_payload(Trinity::StringFormat("https://%s:%u/bnetserver/login/", endpoint.address().to_string().c_str(), endpoint.port()));
241  Service<challenge::v1::ChallengeListener>(this).OnExternalChallenge(&externalChallenge);
242  return ERROR_OK;
243 }
Definition: challenge_service.pb.h:1148
Definition: BattlenetRpcErrorCodes.h:95
boost::asio::ip::address GetRemoteIpAddress() const
Definition: Socket.h:99
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:198
Definition: BattlenetRpcErrorCodes.h:94
void set_payload(const ::std::string &value)
Definition: challenge_service.pb.h:2934
std::string GetClientInfo() const
Definition: Session.cpp:671
std::string _locale
Definition: Session.h:181
LocaleConstant GetLocaleByName(const std::string &name)
Definition: Common.cpp:37
std::string StringFormat(Format &&fmt, Args &&...args)
Default TC string format function.
Definition: StringFormat.h:28
Definition: BattlenetRpcErrorCodes.h:25
void set_payload_type(const ::std::string &value)
Definition: challenge_service.pb.h:2858
Definition: Common.h:117
Definition: BattlenetRpcErrorCodes.h:96
#define sLoginService
Definition: LoginRESTService.h:108
std::string _os
Definition: Session.h:182

+ Here is the call graph for this function:

uint32 Battlenet::Session::HandleProcessClientRequest ( game_utilities::v1::ClientRequest const request,
game_utilities::v1::ClientResponse response 
)
378 {
379  if (!_authed)
380  return ERROR_DENIED;
381 
382  Attribute const* command = nullptr;
383  std::unordered_map<std::string, Variant const*> params;
384 
385  for (int32 i = 0; i < request->attribute_size(); ++i)
386  {
387  Attribute const& attr = request->attribute(i);
388  params[attr.name()] = &attr.value();
389  if (strstr(attr.name().c_str(), "Command_") == attr.name().c_str())
390  command = &attr;
391  }
392 
393  if (!command)
394  {
395  TC_LOG_ERROR("session.rpc", "%s sent ClientRequest with no command.", GetClientInfo().c_str());
397  }
398 
399  auto itr = ClientRequestHandlers.find(command->name());
400  if (itr == ClientRequestHandlers.end())
401  {
402  TC_LOG_ERROR("session.rpc", "%s sent ClientRequest with unknown command %s.", GetClientInfo().c_str(), command->name().c_str());
404  }
405 
406  return (this->*itr->second)(params, response);
407 }
const ::std::string & name() const
Definition: attribute_types.pb.h:931
bool _authed
Definition: Session.h:189
Definition: BattlenetRpcErrorCodes.h:231
Definition: BattlenetRpcErrorCodes.h:233
static std::unordered_map< std::string, ClientRequestHandler > const ClientRequestHandlers
Definition: Session.h:167
const ::bgs::protocol::Variant & value() const
Definition: attribute_types.pb.h:1005
std::string GetClientInfo() const
Definition: Session.cpp:671
int32_t int32
Definition: Define.h:146
Definition: BattlenetRpcErrorCodes.h:28
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:207
std::set< uint32 > params[2]
Definition: DisableMgr.cpp:45
Definition: attribute_types.pb.h:248

+ Here is the call graph for this function:

uint32 Battlenet::Session::HandleVerifyWebCredentials ( authentication::v1::VerifyWebCredentialsRequest const verifyWebCredentialsRequest)
246 {
248  logonResult.set_error_code(0);
249  _accountInfo = sLoginService.VerifyLoginTicket(verifyWebCredentialsRequest->web_credentials());
250  if (!_accountInfo)
251  return ERROR_DENIED;
252 
253  std::string ip_address = GetRemoteIpAddress().to_string();
254 
255  // If the IP is 'locked', check that the player comes indeed from the correct IP address
256  if (_accountInfo->IsLockedToIP)
257  {
258  TC_LOG_DEBUG("session", "[Session::HandleVerifyWebCredentials] Account '%s' is locked to IP - '%s' is logging in from '%s'",
259  _accountInfo->Login.c_str(), _accountInfo->LastIP.c_str(), ip_address.c_str());
260 
261  if (_accountInfo->LastIP != ip_address)
263  }
264  else
265  {
266  TC_LOG_DEBUG("session", "[Session::HandleVerifyWebCredentials] Account '%s' is not locked to ip", _accountInfo->Login.c_str());
267  if (_accountInfo->LockCountry.empty() || _accountInfo->LockCountry == "00")
268  TC_LOG_DEBUG("session", "[Session::HandleVerifyWebCredentials] Account '%s' is not locked to country", _accountInfo->Login.c_str());
269  else if (!_accountInfo->LockCountry.empty() && !_ipCountry.empty())
270  {
271  TC_LOG_DEBUG("session", "[Session::HandleVerifyWebCredentials] Account '%s' is locked to country: '%s' Player country is '%s'",
272  _accountInfo->Login.c_str(), _accountInfo->LockCountry.c_str(), _ipCountry.c_str());
273 
274  if (_ipCountry != _accountInfo->LockCountry)
276  }
277  }
278 
279  // If the account is banned, reject the logon attempt
280  if (_accountInfo->IsBanned)
281  {
282  if (_accountInfo->IsPermanenetlyBanned)
283  {
284  TC_LOG_DEBUG("session", "%s [Session::HandleVerifyWebCredentials] Banned account %s tried to login!", GetClientInfo().c_str(), _accountInfo->Login.c_str());
286  }
287  else
288  {
289  TC_LOG_DEBUG("session", "%s [Session::HandleVerifyWebCredentials] Temporarily banned account %s tried to login!", GetClientInfo().c_str(), _accountInfo->Login.c_str());
291  }
292  }
293 
294  logonResult.mutable_account_id()->set_low(_accountInfo->Id);
295  logonResult.mutable_account_id()->set_high(UI64LIT(0x100000000000000));
296  for (auto itr = _accountInfo->GameAccounts.begin(); itr != _accountInfo->GameAccounts.end(); ++itr)
297  {
298  if (!itr->second.IsBanned)
299  {
300  EntityId* gameAccountId = logonResult.add_game_account_id();
301  gameAccountId->set_low(itr->second.Id);
302  gameAccountId->set_high(UI64LIT(0x200000200576F57));
303  }
304  }
305 
306  if (!_ipCountry.empty())
307  logonResult.set_geoip_country(_ipCountry);
308 
309  BigNumber k;
310  k.SetRand(8 * 64);
311  logonResult.set_session_key(k.AsByteArray(64).get(), 64);
312 
313  _authed = true;
314 
315  Service<authentication::v1::AuthenticationListener>(this).OnLogonComplete(&logonResult);
316  return ERROR_OK;
317 }
Definition: BigNumber.h:28
void set_low(::google::protobuf::uint64 value)
Definition: entity_types.pb.h:413
Definition: entity_types.pb.h:45
boost::asio::ip::address GetRemoteIpAddress() const
Definition: Socket.h:99
bool _authed
Definition: Session.h:189
#define UI64LIT(N)
Definition: Define.h:138
void set_high(::google::protobuf::uint64 value)
Definition: entity_types.pb.h:389
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:198
std::string GetClientInfo() const
Definition: Session.cpp:671
Definition: BattlenetRpcErrorCodes.h:548
Definition: BattlenetRpcErrorCodes.h:74
std::unique_ptr< AccountInfo > _accountInfo
Definition: Session.h:178
void SetRand(int32 numbits)
Definition: BigNumber.cpp:74
inline::bgs::protocol::EntityId * mutable_account_id()
Definition: authentication_service.pb.h:3343
void set_error_code(::google::protobuf::uint32 value)
Definition: authentication_service.pb.h:3319
Definition: BattlenetRpcErrorCodes.h:25
inline::bgs::protocol::EntityId * add_game_account_id()
Definition: authentication_service.pb.h:3381
std::unique_ptr< uint8[]> AsByteArray(int32 minSize=0, bool littleEndian=true)
Definition: BigNumber.cpp:177
Definition: authentication_service.pb.h:598
std::string _ipCountry
Definition: Session.h:185
Definition: BattlenetRpcErrorCodes.h:28
#define sLoginService
Definition: LoginRESTService.h:108
void set_session_key(const ::std::string &value)
Definition: authentication_service.pb.h:3698
void set_geoip_country(const ::std::string &value)
Definition: authentication_service.pb.h:3622
Definition: BattlenetRpcErrorCodes.h:75

+ Here is the call graph for this function:

void Battlenet::Session::HandshakeHandler ( boost::system::error_code const error)
protected
563 {
564  if (error)
565  {
566  TC_LOG_ERROR("session", "%s SSL Handshake failed %s", GetClientInfo().c_str(), error.message().c_str());
567  CloseSocket();
568  return;
569  }
570 
571  AsyncRead();
572 }
std::string GetClientInfo() const
Definition: Session.cpp:671
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:207
void AsyncRead()
Definition: Socket.h:109
void CloseSocket()
Definition: Socket.h:142

+ Here is the caller graph for this function:

uint32 Battlenet::Session::JoinRealm ( std::unordered_map< std::string, Variant const * > const params,
game_utilities::v1::ClientResponse response 
)
private
541 {
542  if (Variant const* realmAddress = GetParam(params, "Param_RealmAddress"))
543  return sRealmList->JoinRealm(realmAddress->uint_value(), _build, GetRemoteIpAddress(), _clientSecret, GetLocaleByName(_locale), _os, _gameAccountInfo->Name, response);
544 
546 }
Definition: attribute_types.pb.h:67
GameAccountInfo * _gameAccountInfo
Definition: Session.h:179
std::array< uint8, 32 > _clientSecret
Definition: Session.h:187
boost::asio::ip::address GetRemoteIpAddress() const
Definition: Socket.h:99
std::string Name
Definition: Session.h:97
std::string _locale
Definition: Session.h:181
LocaleConstant GetLocaleByName(const std::string &name)
Definition: Common.cpp:37
Definition: BattlenetRpcErrorCodes.h:643
Variant const * GetParam(std::unordered_map< std::string, Variant const * > const &params, char const *paramName)
Definition: Session.cpp:409
#define sRealmList
Definition: RealmList.h:101
std::string _os
Definition: Session.h:182
uint32 _build
Definition: Session.h:183

+ Here is the call graph for this function:

bool Battlenet::Session::ReadDataHandler ( )
protected
648 {
649  Header header;
651 
652  if (header.service_id() != 0xFE)
653  {
654  sServiceDispatcher.Dispatch(this, header.service_hash(), header.token(), header.method_id(), std::move(_packetBuffer));
655  }
656  else
657  {
658  auto itr = _responseCallbacks.find(header.token());
659  if (itr != _responseCallbacks.end())
660  {
661  itr->second(std::move(_packetBuffer));
662  _responseCallbacks.erase(header.token());
663  }
664  else
666  }
667 
668  return true;
669 }
inline::google::protobuf::uint32 service_hash() const
Definition: rpc_types.pb.h:1383
inline::google::protobuf::uint32 token() const
Definition: rpc_types.pb.h:1179
Definition: rpc_types.pb.h:574
#define sServiceDispatcher
Definition: ServiceDispatcher.h:66
inline::google::protobuf::uint32 method_id() const
Definition: rpc_types.pb.h:1155
std::unordered_map< uint32, std::function< void(MessageBuffer)> > _responseCallbacks
Definition: Session.h:194
MessageBuffer _headerBuffer
Definition: Session.h:175
size_type GetActiveSize() const
Definition: MessageBuffer.h:66
bool ParseFromArray(const void *data, int size)
void Reset()
Definition: MessageBuffer.h:45
inline::google::protobuf::uint32 service_id() const
Definition: rpc_types.pb.h:1131
uint8 * GetReadPointer()
Definition: MessageBuffer.h:58
MessageBuffer _packetBuffer
Definition: Session.h:176

+ Here is the call graph for this function:

void Battlenet::Session::ReadHandler ( )
overrideprotectedvirtual

Implements Socket< Session, SslSocket< SslContext > >.

606 {
607  if (!IsOpen())
608  return;
609 
610  MessageBuffer& packet = GetReadBuffer();
611  while (packet.GetActiveSize() > 0)
612  {
613  if (!PartialProcessPacket<&Battlenet::Session::ReadHeaderLengthHandler, &Battlenet::Session::_headerLengthBuffer>(this, packet))
614  break;
615 
616  if (!PartialProcessPacket<&Battlenet::Session::ReadHeaderHandler, &Battlenet::Session::_headerBuffer>(this, packet))
617  break;
618 
619  if (!PartialProcessPacket<&Battlenet::Session::ReadDataHandler, &Battlenet::Session::_packetBuffer>(this, packet))
620  break;
621 
624  }
625 
626  AsyncRead();
627 }
bool IsOpen() const
Definition: Socket.h:140
MessageBuffer _headerBuffer
Definition: Session.h:175
size_type GetActiveSize() const
Definition: MessageBuffer.h:66
void Reset()
Definition: MessageBuffer.h:45
MessageBuffer _headerLengthBuffer
Definition: Session.h:174
MessageBuffer & GetReadBuffer()
Definition: Socket.h:159
void AsyncRead()
Definition: Socket.h:109
Definition: MessageBuffer.h:24

+ Here is the call graph for this function:

bool Battlenet::Session::ReadHeaderHandler ( )
protected
638 {
639  Header header;
641  return true;
642 
643  _packetBuffer.Resize(header.size());
644  return true;
645 }
inline::google::protobuf::uint32 size() const
Definition: rpc_types.pb.h:1227
Definition: rpc_types.pb.h:574
MessageBuffer _headerBuffer
Definition: Session.h:175
size_type GetActiveSize() const
Definition: MessageBuffer.h:66
void Resize(size_type bytes)
Definition: MessageBuffer.h:51
bool ParseFromArray(const void *data, int size)
uint8 * GetReadPointer()
Definition: MessageBuffer.h:58
MessageBuffer _packetBuffer
Definition: Session.h:176

+ Here is the call graph for this function:

bool Battlenet::Session::ReadHeaderLengthHandler ( )
protected
630 {
631  uint16 len = *reinterpret_cast<uint16*>(_headerLengthBuffer.GetReadPointer());
633  _headerBuffer.Resize(len);
634  return true;
635 }
void EndianConvertReverse(T &)
Definition: ByteConverter.h:49
MessageBuffer _headerBuffer
Definition: Session.h:175
uint16_t uint16
Definition: Define.h:151
void Resize(size_type bytes)
Definition: MessageBuffer.h:51
MessageBuffer _headerLengthBuffer
Definition: Session.h:174
uint8 * GetReadPointer()
Definition: MessageBuffer.h:58

+ Here is the call graph for this function:

void Battlenet::Session::SendRequest ( uint32  serviceHash,
uint32  methodId,
pb::Message const request,
std::function< void(MessageBuffer)>  callback 
)
inline
136  {
137  _responseCallbacks[_requestToken] = std::move(callback);
138  SendRequest(serviceHash, methodId, request);
139  }
uint32 _requestToken
Definition: Session.h:195
std::unordered_map< uint32, std::function< void(MessageBuffer)> > _responseCallbacks
Definition: Session.h:194
void SendRequest(uint32 serviceHash, uint32 methodId, pb::Message const *request, std::function< void(MessageBuffer)> callback)
Definition: Session.h:135
void Battlenet::Session::SendRequest ( uint32  serviceHash,
uint32  methodId,
pb::Message const request 
)
190 {
191  Header header;
192  header.set_service_id(0);
193  header.set_service_hash(serviceHash);
194  header.set_method_id(methodId);
195  header.set_size(request->ByteSize());
196  header.set_token(_requestToken++);
197 
198  uint16 headerSize = header.ByteSize();
199  EndianConvertReverse(headerSize);
200 
201  MessageBuffer packet;
202  packet.Write(&headerSize, sizeof(headerSize));
203  uint8* ptr = packet.GetWritePointer();
204  packet.WriteCompleted(header.ByteSize());
205  header.SerializeToArray(ptr, header.ByteSize());
206  ptr = packet.GetWritePointer();
207  packet.WriteCompleted(request->ByteSize());
208  request->SerializeToArray(ptr, request->ByteSize());
209 
210  AsyncWrite(&packet);
211 }
void set_service_hash(::google::protobuf::uint32 value)
Definition: rpc_types.pb.h:1387
void set_method_id(::google::protobuf::uint32 value)
Definition: rpc_types.pb.h:1159
void set_size(::google::protobuf::uint32 value)
Definition: rpc_types.pb.h:1231
uint32 _requestToken
Definition: Session.h:195
void set_service_id(::google::protobuf::uint32 value)
Definition: rpc_types.pb.h:1135
uint8 * GetWritePointer()
Definition: MessageBuffer.h:60
Definition: rpc_types.pb.h:574
void WriteCompleted(size_type bytes)
Definition: MessageBuffer.h:64
void EndianConvertReverse(T &)
Definition: ByteConverter.h:49
int ByteSize() const
bool SerializeToArray(void *data, int size) const
uint16_t uint16
Definition: Define.h:151
void Write(void const *data, std::size_t size)
Definition: MessageBuffer.h:92
void AsyncWrite(MessageBuffer *packet)
Definition: Session.cpp:140
uint8_t uint8
Definition: Define.h:152
void set_token(::google::protobuf::uint32 value)
Definition: rpc_types.pb.h:1183
Definition: MessageBuffer.h:24

+ Here is the call graph for this function:

void Battlenet::Session::SendResponse ( uint32  token,
pb::Message const response 
)
149 {
150  Header header;
151  header.set_token(token);
152  header.set_service_id(0xFE);
153  header.set_size(response->ByteSize());
154 
155  uint16 headerSize = header.ByteSize();
156  EndianConvertReverse(headerSize);
157 
158  MessageBuffer packet;
159  packet.Write(&headerSize, sizeof(headerSize));
160  uint8* ptr = packet.GetWritePointer();
161  packet.WriteCompleted(header.ByteSize());
162  header.SerializeToArray(ptr, header.ByteSize());
163  ptr = packet.GetWritePointer();
164  packet.WriteCompleted(response->ByteSize());
165  response->SerializeToArray(ptr, response->ByteSize());
166 
167  AsyncWrite(&packet);
168 }
void set_size(::google::protobuf::uint32 value)
Definition: rpc_types.pb.h:1231
void set_service_id(::google::protobuf::uint32 value)
Definition: rpc_types.pb.h:1135
uint8 * GetWritePointer()
Definition: MessageBuffer.h:60
Definition: rpc_types.pb.h:574
void WriteCompleted(size_type bytes)
Definition: MessageBuffer.h:64
void EndianConvertReverse(T &)
Definition: ByteConverter.h:49
int ByteSize() const
bool SerializeToArray(void *data, int size) const
uint16_t uint16
Definition: Define.h:151
void Write(void const *data, std::size_t size)
Definition: MessageBuffer.h:92
void AsyncWrite(MessageBuffer *packet)
Definition: Session.cpp:140
uint8_t uint8
Definition: Define.h:152
void set_token(::google::protobuf::uint32 value)
Definition: rpc_types.pb.h:1183
Definition: MessageBuffer.h:24

+ Here is the call graph for this function:

void Battlenet::Session::SendResponse ( uint32  token,
uint32  status 
)
171 {
172  Header header;
173  header.set_token(token);
174  header.set_status(status);
175  header.set_service_id(0xFE);
176 
177  uint16 headerSize = header.ByteSize();
178  EndianConvertReverse(headerSize);
179 
180  MessageBuffer packet;
181  packet.Write(&headerSize, sizeof(headerSize));
182  uint8* ptr = packet.GetWritePointer();
183  packet.WriteCompleted(header.ByteSize());
184  header.SerializeToArray(ptr, header.ByteSize());
185 
186  AsyncWrite(&packet);
187 }
void set_status(::google::protobuf::uint32 value)
Definition: rpc_types.pb.h:1255
void set_service_id(::google::protobuf::uint32 value)
Definition: rpc_types.pb.h:1135
uint8 * GetWritePointer()
Definition: MessageBuffer.h:60
Definition: rpc_types.pb.h:574
void WriteCompleted(size_type bytes)
Definition: MessageBuffer.h:64
void EndianConvertReverse(T &)
Definition: ByteConverter.h:49
int ByteSize() const
bool SerializeToArray(void *data, int size) const
uint16_t uint16
Definition: Define.h:151
void Write(void const *data, std::size_t size)
Definition: MessageBuffer.h:92
void AsyncWrite(MessageBuffer *packet)
Definition: Session.cpp:140
uint8_t uint8
Definition: Define.h:152
void set_token(::google::protobuf::uint32 value)
Definition: rpc_types.pb.h:1183
Definition: MessageBuffer.h:24

+ Here is the call graph for this function:

void Battlenet::Session::Start ( )
overridevirtual

Implements Socket< Session, SslSocket< SslContext > >.

83 {
84  std::string ip_address = GetRemoteIpAddress().to_string();
85  TC_LOG_TRACE("session", "%s Accepted connection", GetClientInfo().c_str());
86 
87  // Verify that this IP is not in the ip_banned table
89 
91  stmt->setString(0, ip_address);
92  stmt->setUInt32(1, inet_addr(ip_address.c_str()));
93 
94  _queryCallback = std::bind(&Battlenet::Session::CheckIpCallback, this, std::placeholders::_1);
96 }
void Execute(const char *sql)
Definition: DatabaseWorkerPool.h:87
Definition: LoginDatabase.h:33
boost::asio::ip::address GetRemoteIpAddress() const
Definition: Socket.h:99
std::function< void(PreparedQueryResult)> _queryCallback
Definition: Session.h:192
void setString(const uint8 index, const std::string &value)
Definition: PreparedStatement.cpp:187
QueryResultFuture AsyncQuery(const char *sql)
Definition: DatabaseWorkerPool.cpp:149
void CheckIpCallback(PreparedQueryResult result)
Definition: Session.cpp:98
Definition: PreparedStatement.h:74
LoginDatabaseWorkerPool LoginDatabase
Accessor to the realm/login database.
Definition: DatabaseEnv.cpp:22
std::string GetClientInfo() const
Definition: Session.cpp:671
#define TC_LOG_TRACE(filterType__,...)
Definition: Log.h:195
PreparedStatement * GetPreparedStatement(PreparedStatementIndex index)
Definition: DatabaseWorkerPool.h:263
void setUInt32(const uint8 index, const uint32 value)
Definition: PreparedStatement.cpp:115
Definition: LoginDatabase.h:35
PreparedQueryResultFuture _queryFuture
Definition: Session.h:191

+ Here is the call graph for this function:

bool Battlenet::Session::Update ( )
overridevirtual

Reimplemented from Socket< Session, SslSocket< SslContext > >.

126 {
128  return false;
129 
130  if (_queryFuture.valid() && _queryFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
131  {
132  auto callback = std::move(_queryCallback);
133  _queryCallback = nullptr;
134  callback(_queryFuture.get());
135  }
136 
137  return true;
138 }
virtual bool Update()
Definition: Socket.h:83
std::function< void(PreparedQueryResult)> _queryCallback
Definition: Session.h:192
float seconds()
Definition: units.h:97
PreparedQueryResultFuture _queryFuture
Definition: Session.h:191

+ Here is the call graph for this function:

Member Data Documentation

std::unique_ptr<AccountInfo> Battlenet::Session::_accountInfo
private
bool Battlenet::Session::_authed
private
uint32 Battlenet::Session::_build
private
std::array<uint8, 32> Battlenet::Session::_clientSecret
private
GameAccountInfo* Battlenet::Session::_gameAccountInfo
private
MessageBuffer Battlenet::Session::_headerBuffer
private
MessageBuffer Battlenet::Session::_headerLengthBuffer
private
std::string Battlenet::Session::_ipCountry
private
std::string Battlenet::Session::_locale
private
std::string Battlenet::Session::_os
private
MessageBuffer Battlenet::Session::_packetBuffer
private
std::function<void(PreparedQueryResult)> Battlenet::Session::_queryCallback
private
PreparedQueryResultFuture Battlenet::Session::_queryFuture
private
uint32 Battlenet::Session::_requestToken
private
std::unordered_map<uint32, std::function<void(MessageBuffer)> > Battlenet::Session::_responseCallbacks
private
std::unordered_map< std::string, Battlenet::Session::ClientRequestHandler > const Battlenet::Session::ClientRequestHandlers
staticprivate
Initial value:
=
{
{ "Command_RealmListTicketRequest_v1_b9", &Battlenet::Session::GetRealmListTicket },
{ "Command_LastCharPlayedRequest_v1_b9", &Battlenet::Session::GetLastCharPlayed },
{ "Command_RealmListRequest_v1_b9", &Battlenet::Session::GetRealmList },
{ "Command_RealmJoinRequest_v1_b9", &Battlenet::Session::JoinRealm },
}

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