void Battlenet::Session::HandleProofResponse(Authentication::ProofResponse const& proofResponse) { if (_modulesWaitingForData.size() < proofResponse.Modules.size()) { Authentication::LogonResponse* complete = new Authentication::LogonResponse(); complete->SetAuthResult(AUTH_CORRUPTED_MODULE); AsyncWrite(complete); return; } ServerPacket* response = nullptr; for (size_t i = 0; i < proofResponse.Modules.size(); ++i) { if (!(this->*(ModuleHandlers[_modulesWaitingForData.front()]))(proofResponse.Modules[i], &response)) break; _modulesWaitingForData.pop(); } if (!response) { response = new Authentication::LogonResponse(); static_cast<Authentication::LogonResponse*>(response)->SetAuthResult(AUTH_INTERNAL_ERROR); } AsyncWrite(response); }
void Battlenet::Session::UpdateRealms(std::vector<Realm const*>& realms, std::vector<Battlenet::RealmHandle>& deletedRealms) { for (Realm const* realm : realms) AsyncWrite(BuildListUpdate(realm)); for (Battlenet::RealmHandle& deleted : deletedRealms) { WoWRealm::ListUpdate* listUpdate = new WoWRealm::ListUpdate(); listUpdate->UpdateState = WoWRealm::ListUpdate::DELETED; listUpdate->Id = deleted; AsyncWrite(listUpdate); } }
void Battlenet::Session::HandleResumeRequest(Authentication::ResumeRequest const& resumeRequest) { _accountName = resumeRequest.Login; _locale = resumeRequest.Locale; _os = resumeRequest.Platform; auto baseComponent = std::find_if(resumeRequest.Components.begin(), resumeRequest.Components.end(), [](Component const& c) { return c.Program == "base"; }); if (baseComponent != resumeRequest.Components.end()) _build = baseComponent->Build; Utf8ToUpperOnlyLatin(_accountName); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_RECONNECT_INFO); stmt->setString(0, _accountName); stmt->setString(1, resumeRequest.GameAccountName); PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) { Authentication::ResumeResponse* resumeResponse = new Authentication::ResumeResponse(); resumeResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); AsyncWrite(resumeResponse); return; } Field* fields = result->Fetch(); _accountId = fields[0].GetUInt32(); K.SetHexStr(fields[1].GetString().c_str()); _gameAccountId = fields[2].GetUInt32(); _gameAccountName = resumeRequest.GameAccountName; ModuleInfo* thumbprint = sModuleMgr->CreateModule(_os, "Thumbprint"); ModuleInfo* resume = sModuleMgr->CreateModule(_os, "Resume"); BitStream resumeData; uint8 state = 0; _reconnectProof.SetRand(16 * 8); resumeData.WriteBytes(&state, 1); resumeData.WriteBytes(_reconnectProof.AsByteArray().get(), 16); resume->DataSize = resumeData.GetSize(); resume->Data = new uint8[resume->DataSize]; memcpy(resume->Data, resumeData.GetBuffer(), resume->DataSize); _modulesWaitingForData.push(MODULE_RESUME); Authentication::ProofRequest* proofRequest = new Authentication::ProofRequest(); proofRequest->Modules.push_back(thumbprint); proofRequest->Modules.push_back(resume); AsyncWrite(proofRequest); }
void Battlenet::Session::HandleResumeRequest(Authentication::ResumeRequest const& resumeRequest) { if (_queryCallback) { Authentication::ResumeResponse* logonResponse = new Authentication::ResumeResponse(); logonResponse->SetAuthResult(AUTH_LOGON_TOO_FAST); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "[Battlenet::ResumeRequest] %s attempted to log too quick after previous attempt!", GetClientInfo().c_str()); return; } std::string login = resumeRequest.Login; _locale = resumeRequest.Locale; _os = resumeRequest.Platform; auto baseComponent = std::find_if(resumeRequest.Components.begin(), resumeRequest.Components.end(), [](Component const& c) { return c.Program == "base"; }); if (baseComponent != resumeRequest.Components.end()) _build = baseComponent->Build; Utf8ToUpperOnlyLatin(login); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_RECONNECT_INFO); stmt->setString(0, login); stmt->setString(1, resumeRequest.GameAccountName); _queryCallback = std::bind(&Battlenet::Session::HandleResumeRequestCallback, this, std::placeholders::_1); _queryFuture = LoginDatabase.AsyncQuery(stmt); }
void Battlenet::Session::HandleListSubscribeRequest(WoWRealm::ListSubscribeRequest const& /*listSubscribeRequest*/) { WoWRealm::ListSubscribeResponse* listSubscribeResponse = new WoWRealm::ListSubscribeResponse(); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS); stmt->setUInt32(0, _gameAccountId); if (PreparedQueryResult countResult = LoginDatabase.Query(stmt)) { do { Field* fields = countResult->Fetch(); uint32 build = fields[4].GetUInt32(); listSubscribeResponse->CharacterCounts.push_back({ RealmId(fields[2].GetUInt8(), fields[3].GetUInt8(), fields[1].GetUInt32(), (_build != build ? build : 0)), fields[0].GetUInt8() }); } while (countResult->NextRow()); } for (RealmList::RealmMap::value_type const& i : sRealmList->GetRealms()) listSubscribeResponse->RealmData.push_back(BuildListUpdate(&i.second)); listSubscribeResponse->RealmData.push_back(new WoWRealm::ListComplete()); AsyncWrite(listSubscribeResponse); _subscribedToRealmListUpdates = true; }
void CNetwork::Execute(string cmd, ReadCallback_t callback) { boost::lock_guard<boost::mutex> queue_lock_guard(m_CmdQueueMutex); m_CmdQueue.push(boost::make_tuple(boost::move(cmd), boost::move(callback))); if (m_CmdQueue.size() == 1) AsyncWrite(m_CmdQueue.front().get<0>()); }
VOID WINAPI CompletedWriteRoutine( DWORD err, DWORD written, LPOVERLAPPED overlap) { auto context = (Connection::IoCompletionRoutine*)overlap; auto self = context->self; if (err == ERROR_OPERATION_ABORTED) { SetEvent(self->cancel_io_event_.get()); assert(("write operation should not be cancelled", false)); return; } bool io = false; // The write operation has finished, so read() the next request (if // there is no error) or continue write if necessary. if ((err == 0) && (written == self->write_size_)) { bool pendding = false; std::string message; { std::unique_lock<std::mutex> lock(self->sending_queue_mutex_); pendding = !self->sending_queue_.empty(); if (pendding) { message = self->sending_queue_.front(); self->sending_queue_.pop_front(); self->state_ = Connection::SEND_PENDDING; } else { self->state_ = Connection::CONNECTED; } } io = pendding ? self->AsyncWrite(message, CompletedWriteRoutine) : self->AsyncRead(CompletedReadRoutine); } if (!io) { self->Shutdown(); } }
void Battlenet::Session::CheckIpCallback(PreparedQueryResult result) { if (result) { bool banned = false; do { Field* fields = result->Fetch(); if (fields[0].GetUInt64() != 0) banned = true; if (!fields[1].GetString().empty()) _ipCountry = fields[1].GetString(); } while (result->NextRow()); if (banned) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_INTERNAL_ERROR); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Banned ip '%s:%d' tries to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort()); return; } } AsyncRead(); }
void Battlenet::Session::HandleGetStreamItemsRequest(Cache::GetStreamItemsRequest const& getStreamItemsRequest) { if (ModuleInfo* module = sModuleMgr->CreateModule(getStreamItemsRequest.Locale, getStreamItemsRequest.ItemName)) { Cache::GetStreamItemsResponse* getStreamItemsResponse = new Cache::GetStreamItemsResponse(); getStreamItemsResponse->Index = getStreamItemsRequest.Index; getStreamItemsResponse->Modules.push_back(module); AsyncWrite(getStreamItemsResponse); } }
/// <summary> /// Asynchronous write of a string message. /// NB if the length of the message is greater than MTU it will be split across datagrams. /// </summary> /// <param name="msg">The string message to send.</param> /// <param name="nullTerminate">Whether to null terminate the string or not.</param> void DgramListener::AsyncWrite(std::string&& msg, bool nullTerminate) { auto listener = _udpListener.lock(); if (!listener) { throw runtime_error("Connection expired."); } listener->AsyncWrite(std::move(msg), nullTerminate); }
/// <summary> /// Asynchronous write of a string message. /// NB if the length of the message is greater than MTU it will be split across datagrams. /// </summary> /// <param name="msg">The byte vector message to send.</param> void DgramListener::AsyncWrite(std::vector<uint8_t>&& msg) { auto listener = _udpListener.lock(); if (!listener) { throw runtime_error("Connection expired."); } listener->AsyncWrite(std::move(msg)); }
void TCPConnection::ProcessOperationQueue_(int recurse_level) { if (recurse_level > 10) { throw std::logic_error(Formatter::FormatAsAnsi("Recurse level {0} was reached in TCPConnection::ProcessOperationQueue_ for session {1}", recurse_level, session_id_)); } // Pick out the next item to process... std::shared_ptr<IOOperation> operation = operation_queue_.Front(); if (!operation) { // We're no longer sending... return; } switch (operation->GetType()) { case IOOperation::BCTHandshake: { AsyncHandshake(); break; } case IOOperation::BCTWrite: { std::shared_ptr<ByteBuffer> pBuf = operation->GetBuffer(); AsyncWrite(pBuf); break; } case IOOperation::BCTRead: { AsyncRead(operation->GetString()); break; } case IOOperation::BCTShutdownSend: { Shutdown(boost::asio::ip::tcp::socket::shutdown_send); operation_queue_.Pop(IOOperation::BCTShutdownSend); ProcessOperationQueue_(recurse_level + 1); break; } case IOOperation::BCTDisconnect: { Disconnect(); operation_queue_.Pop(IOOperation::BCTDisconnect); ProcessOperationQueue_(recurse_level + 1); break; } } }
void Battlenet::Session::HandleJoinRequestV2(WoWRealm::JoinRequestV2 const& joinRequest) { WoWRealm::JoinResponseV2* joinResponse = new WoWRealm::JoinResponseV2(); Realm const* realm = sRealmList->GetRealm(joinRequest.Realm); if (!realm || realm->Flags & (REALM_FLAG_VERSION_MISMATCH | REALM_FLAG_OFFLINE)) { joinResponse->Response = WoWRealm::JoinResponseV2::FAILURE; AsyncWrite(joinResponse); return; } joinResponse->ServerSeed = rand32(); uint8 sessionKey[40]; HmacSha1 hmac(K.GetNumBytes(), K.AsByteArray().get()); hmac.UpdateData((uint8*)"WoW\0", 4); hmac.UpdateData((uint8*)&joinRequest.ClientSeed, 4); hmac.UpdateData((uint8*)&joinResponse->ServerSeed, 4); hmac.Finalize(); memcpy(sessionKey, hmac.GetDigest(), hmac.GetLength()); HmacSha1 hmac2(K.GetNumBytes(), K.AsByteArray().get()); hmac2.UpdateData((uint8*)"WoW\0", 4); hmac2.UpdateData((uint8*)&joinResponse->ServerSeed, 4); hmac2.UpdateData((uint8*)&joinRequest.ClientSeed, 4); hmac2.Finalize(); memcpy(sessionKey + hmac.GetLength(), hmac2.GetDigest(), hmac2.GetLength()); LoginDatabase.DirectPExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = %u, failed_logins = 0, os = '%s' WHERE id = %u", ByteArrayToHexStr(sessionKey, 40, true).c_str(), GetRemoteIpAddress().to_string().c_str(), GetLocaleByName(_locale), _os.c_str(), _gameAccountInfo->Id); joinResponse->IPv4.emplace_back(realm->ExternalAddress, realm->Port); if (realm->ExternalAddress != realm->LocalAddress) joinResponse->IPv4.emplace_back(realm->LocalAddress, realm->Port); AsyncWrite(joinResponse); }
bool Connection::AsyncWaitWrite() { if (CancelIo(pipe_.get())) { while (WAIT_OBJECT_0 != WaitForSingleObjectEx( cancel_io_event_.get(), INFINITE, TRUE)) { continue; } } std::string message; std::unique_lock<std::mutex> lock(transact_message_buffer_mutex_); message.swap(transact_message_buffer_); transact_message_buffer_cond.notify_all(); return AsyncWrite(message, CompletedWriteRoutineForWait); }
void Battlenet::Session::HandleListSubscribeRequestCallback(PreparedQueryResult result) { WoWRealm::ListSubscribeResponse* listSubscribeResponse = new WoWRealm::ListSubscribeResponse(); if (result) { do { Field* fields = result->Fetch(); listSubscribeResponse->CharacterCounts.push_back({ Battlenet::RealmHandle(fields[2].GetUInt8(), fields[3].GetUInt8(), fields[1].GetUInt32()), fields[0].GetUInt8() }); } while (result->NextRow()); } AsyncWrite(listSubscribeResponse); for (RealmList::RealmMap::value_type const& i : sRealmList->GetRealms()) AsyncWrite(BuildListUpdate(&i.second)); AsyncWrite(new WoWRealm::ListComplete()); _subscribedToRealmListUpdates = true; }
void Battlenet::Session::HandleResumeRequestCallback(PreparedQueryResult result) { if (!result) { Authentication::ResumeResponse* resumeResponse = new Authentication::ResumeResponse(); resumeResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); AsyncWrite(resumeResponse); return; } Field* fields = result->Fetch(); _accountInfo->LoadResult(fields); K.SetHexStr(fields[8].GetString().c_str()); _gameAccounts.resize(1); _gameAccountInfo = &_gameAccounts[0]; _gameAccountInfo->LoadResult(fields + 9); ModuleInfo* thumbprint = sModuleMgr->CreateModule(_os, "Thumbprint"); ModuleInfo* resume = sModuleMgr->CreateModule(_os, "Resume"); BitStream resumeData; uint8 state = 0; _reconnectProof.SetRand(16 * 8); resumeData.WriteBytes(&state, 1); resumeData.WriteBytes(_reconnectProof.AsByteArray().get(), 16); resume->DataSize = resumeData.GetSize(); resume->Data = new uint8[resume->DataSize]; memcpy(resume->Data, resumeData.GetBuffer(), resume->DataSize); _modulesWaitingForData.push(MODULE_RESUME); Authentication::ProofRequest* proofRequest = new Authentication::ProofRequest(); proofRequest->Modules.push_back(thumbprint); proofRequest->Modules.push_back(resume); AsyncWrite(proofRequest); }
bool Connection::AsyncWrite() { // must cancel read operation first if (CancelIo(pipe_.get())) { while (WAIT_OBJECT_0 != WaitForSingleObjectEx( cancel_io_event_.get(), INFINITE, TRUE)) { continue; } } std::string message; { std::unique_lock<std::mutex> lock(sending_queue_mutex_); assert(("no more message to send", !sending_queue_.empty())); message = sending_queue_.front(); sending_queue_.pop_front(); } return AsyncWrite(message, CompletedWriteRoutine); }
void Battlenet::Session::SendResponse(uint32 token, uint32 status) { Header header; header.set_token(token); header.set_status(status); header.set_service_id(0xFE); uint16 headerSize = header.ByteSize(); EndianConvertReverse(headerSize); MessageBuffer packet; packet.Write(&headerSize, sizeof(headerSize)); uint8* ptr = packet.GetWritePointer(); packet.WriteCompleted(header.ByteSize()); header.SerializeToArray(ptr, header.ByteSize()); AsyncWrite(&packet); }
void Battlenet::Session::SendRequest(uint32 serviceHash, uint32 methodId, pb::Message const* request) { Header header; header.set_service_id(0); header.set_service_hash(serviceHash); header.set_method_id(methodId); header.set_size(request->ByteSize()); header.set_token(_requestToken++); uint16 headerSize = header.ByteSize(); EndianConvertReverse(headerSize); MessageBuffer packet; packet.Write(&headerSize, sizeof(headerSize)); uint8* ptr = packet.GetWritePointer(); packet.WriteCompleted(header.ByteSize()); header.SerializeToArray(ptr, header.ByteSize()); ptr = packet.GetWritePointer(); packet.WriteCompleted(request->ByteSize()); request->SerializeToArray(ptr, request->ByteSize()); AsyncWrite(&packet); }
void Battlenet::Session::Start() { std::string ip_address = GetRemoteIpAddress().to_string(); TC_LOG_TRACE("session", "Accepted connection from %s", ip_address.c_str()); if (_queryCallback) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_LOGON_TOO_FAST); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "[Session::Start] %s attempted to log too quick after previous attempt!", GetClientInfo().c_str()); return; } // Verify that this IP is not in the ip_banned table LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO); stmt->setString(0, ip_address); stmt->setUInt32(1, inet_addr(ip_address.c_str())); _queryCallback = std::bind(&Battlenet::Session::CheckIpCallback, this, std::placeholders::_1); _queryFuture = LoginDatabase.AsyncQuery(stmt); }
/* - result data is sent as a string which ends with "\n\r" - the Teamspeak3 server can send multiple strings - the end of a result set is always an error result string */ void CNetwork::OnRead(const boost::system::error_code &error_code) { if (error_code.value() == 0) { static vector<string> captured_data; std::istream tmp_stream(&m_ReadStreamBuf); string read_data; std::getline(tmp_stream, read_data, '\r'); #ifdef _DEBUG string dbg_read_data(read_data); bool first_line = true; do { logprintf("%s> %s", first_line == true ? ">>>" : " ", dbg_read_data.substr(0, 512).c_str()); dbg_read_data.erase(0, 512); first_line = false; } while (dbg_read_data.empty() == false); #endif //regex: parse error //if this is an error message, it means that no other result data will come static const boost::regex error_rx("error id=([0-9]+) msg=([^ \n]+)"); boost::smatch error_rx_result; if (boost::regex_search(read_data, error_rx_result, error_rx)) { if (error_rx_result[1].str() == "0") { for (auto i = captured_data.begin(); i != captured_data.end(); ++i) { string &data = *i; if (data.find('|') == string::npos) continue; //we have multiple data rows with '|' as delimiter here, //split them up and re-insert every single row vector<string> result_set; size_t delim_pos = 0; do { size_t old_delim_pos = delim_pos; delim_pos = data.find('|', delim_pos); string row = data.substr(old_delim_pos, delim_pos - old_delim_pos); result_set.push_back(row); } while (delim_pos != string::npos && ++delim_pos); i = captured_data.erase(i); for (auto j = result_set.begin(), jend = result_set.end(); j != jend; ++j) i = captured_data.insert(i, *j); } //call callback and send next command m_CmdQueueMutex.lock(); if (m_CmdQueue.empty() == false) { ReadCallback_t &callback = m_CmdQueue.front().get<1>(); if (callback) { m_CmdQueueMutex.unlock(); callback(captured_data); //calls the callback m_CmdQueueMutex.lock(); } m_CmdQueue.pop(); if (m_CmdQueue.empty() == false) AsyncWrite(m_CmdQueue.front().get<0>()); } m_CmdQueueMutex.unlock(); } else { string error_str(error_rx_result[2].str()); unsigned int error_id = 0; CUtils::Get()->UnEscapeString(error_str); CUtils::Get()->ConvertStringToInt(error_rx_result[1].str(), error_id); m_CmdQueueMutex.lock(); CCallbackHandler::Get()->ForwardError( EErrorType::TEAMSPEAK_ERROR, error_id, fmt::format("error while executing \"{}\": {}", m_CmdQueue.front().get<0>(), error_str)); m_CmdQueue.pop(); if (m_CmdQueue.empty() == false) AsyncWrite(m_CmdQueue.front().get<0>()); m_CmdQueueMutex.unlock(); } captured_data.clear(); } else if (read_data.find("notify") == 0) { //check if notify is duplicate static string last_notify_data; static const vector<string> duplicate_notifies{ "notifyclientmoved", "notifycliententerview", "notifyclientleftview" }; bool is_duplicate = false; for (auto &s : duplicate_notifies) { if (read_data.find(s) == 0) { if (last_notify_data == read_data) is_duplicate = true; break; } } if (is_duplicate == false) { //notify event boost::smatch event_result; for (auto &event : m_EventList) { if (boost::regex_search(read_data, event_result, event.get<0>())) { event.get<1>()(event_result); break; } } } last_notify_data = read_data; } else { //stack the result data if it is not an error or notification message captured_data.push_back(read_data); } AsyncRead(); } else //error { CCallbackHandler::Get()->ForwardError( EErrorType::CONNECTION_ERROR, error_code.value(), fmt::format("error while reading: {}", error_code.message())); //"disable" the plugin, since calling Disconnect() or //destroying CNetwork here is not very smart CServer::CSingleton::Destroy(); m_Connected = false; //we're not _really_ connected, are we? } }
void Battlenet::Session::HandleSocialNetworkCheckConnected(Friends::SocialNetworkCheckConnected const& socialNetworkCheckConnected) { Friends::SocialNetworkCheckConnectedResult* socialNetworkCheckConnectedResult = new Friends::SocialNetworkCheckConnectedResult(); socialNetworkCheckConnectedResult->SocialNetworkId = socialNetworkCheckConnected.SocialNetworkId; AsyncWrite(socialNetworkCheckConnectedResult); }
void Battlenet::Session::HandlePing(Connection::Ping const& /*ping*/) { AsyncWrite(new Connection::Pong()); }
void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest3 const& logonRequest) { // Verify that this IP is not in the ip_banned table LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); std::string ip_address = GetRemoteIpAddress().to_string(); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_BANNED); stmt->setString(0, ip_address); if (PreparedQueryResult result = LoginDatabase.Query(stmt)) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(LOGIN_BANNED); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Banned ip '%s:%d' tries to login!", ip_address.c_str(), GetRemotePort()); return; } if (logonRequest.Program != "WoW") { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_INVALID_PROGRAM); AsyncWrite(logonResponse); 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()); return; } if (!sComponentMgr->HasPlatform(logonRequest.Platform)) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_INVALID_OS); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log in from an unsupported platform (using %s)!", GetClientInfo().c_str(), logonRequest.Platform.c_str()); return; } if (!sComponentMgr->HasPlatform(logonRequest.Locale)) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_UNSUPPORTED_LANGUAGE); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log in with unsupported locale (using %s)!", GetClientInfo().c_str(), logonRequest.Locale.c_str()); return; } for (Component const& component : logonRequest.Components) { if (!sComponentMgr->HasComponent(&component)) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); if (!sComponentMgr->HasProgram(component.Program)) { logonResponse->SetAuthResult(AUTH_INVALID_PROGRAM); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is using unsupported component program %s!", GetClientInfo().c_str(), component.Program.c_str()); } else if (!sComponentMgr->HasPlatform(component.Platform)) { logonResponse->SetAuthResult(AUTH_INVALID_OS); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is using unsupported component platform %s!", GetClientInfo().c_str(), component.Platform.c_str()); } else { if (component.Program != "WoW" || AuthHelper::IsBuildSupportingBattlenet(component.Build)) logonResponse->SetAuthResult(AUTH_REGION_BAD_VERSION); else logonResponse->SetAuthResult(AUTH_USE_GRUNT_LOGON); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is using unsupported component version %u!", GetClientInfo().c_str(), component.Build); } AsyncWrite(logonResponse); return; } if (component.Platform == "base") _build = component.Build; } _accountName = logonRequest.Login; _locale = logonRequest.Locale; _os = logonRequest.Platform; Utf8ToUpperOnlyLatin(_accountName); stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO); stmt->setString(0, _accountName); PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is trying to log in from unknown account!", GetClientInfo().c_str()); return; } Field* fields = result->Fetch(); _accountId = fields[1].GetUInt32(); // If the IP is 'locked', check that the player comes indeed from the correct IP address if (fields[2].GetUInt8() == 1) // if ip is locked { TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is locked to IP - '%s' is logging in from '%s'", _accountName.c_str(), fields[4].GetCString(), ip_address.c_str()); if (strcmp(fields[4].GetCString(), ip_address.c_str()) != 0) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_ACCOUNT_LOCKED); AsyncWrite(logonResponse); return; } } else { TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is not locked to ip", _accountName.c_str()); std::string accountCountry = fields[3].GetString(); if (accountCountry.empty() || accountCountry == "00") TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is not locked to country", _accountName.c_str()); else if (!accountCountry.empty()) { uint32 ip = inet_addr(ip_address.c_str()); EndianConvertReverse(ip); stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGON_COUNTRY); stmt->setUInt32(0, ip); if (PreparedQueryResult sessionCountryQuery = LoginDatabase.Query(stmt)) { std::string loginCountry = (*sessionCountryQuery)[0].GetString(); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is locked to country: '%s' Player country is '%s'", _accountName.c_str(), accountCountry.c_str(), loginCountry.c_str()); if (loginCountry != accountCountry) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_ACCOUNT_LOCKED); AsyncWrite(logonResponse); return; } } } } //set expired bans to inactive LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_BNET_EXPIRED_BANS)); // If the account is banned, reject the logon attempt stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN); stmt->setUInt32(0, _accountId); PreparedQueryResult banresult = LoginDatabase.Query(stmt); if (banresult) { Field* fields = banresult->Fetch(); if (fields[0].GetUInt32() == fields[1].GetUInt32()) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(LOGIN_BANNED); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::LogonRequest] Banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountName.c_str()); return; } else { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(LOGIN_SUSPENDED); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::LogonRequest] Temporarily banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountName.c_str()); return; } } SHA256Hash sha; sha.UpdateData(_accountName); sha.Finalize(); I.SetBinary(sha.GetDigest(), sha.GetLength()); ModuleInfo* password = sModuleMgr->CreateModule(_os, "Password"); ModuleInfo* thumbprint = sModuleMgr->CreateModule(_os, "Thumbprint"); std::string pStr = fields[0].GetString(); std::string databaseV = fields[5].GetString(); std::string databaseS = fields[6].GetString(); if (databaseV.size() != size_t(BufferSizes::SRP_6_V) * 2 || databaseS.size() != size_t(BufferSizes::SRP_6_S) * 2) _SetVSFields(pStr); else { s.SetHexStr(databaseS.c_str()); v.SetHexStr(databaseV.c_str()); } b.SetRand(128 * 8); B = ((v * k) + g.ModExp(b, N)) % N; BigNumber unk; unk.SetRand(128 * 8); BitStream passwordData; uint8 state = 0; passwordData.WriteBytes(&state, 1); passwordData.WriteBytes(I.AsByteArray(32).get(), 32); passwordData.WriteBytes(s.AsByteArray(32).get(), 32); passwordData.WriteBytes(B.AsByteArray(128).get(), 128); passwordData.WriteBytes(unk.AsByteArray(128).get(), 128); password->DataSize = passwordData.GetSize(); password->Data = new uint8[password->DataSize]; memcpy(password->Data, passwordData.GetBuffer(), password->DataSize); _modulesWaitingForData.push(MODULE_PASSWORD); Authentication::ProofRequest* proofRequest = new Authentication::ProofRequest(); proofRequest->Modules.push_back(password); // if has authenticator, send Token module proofRequest->Modules.push_back(thumbprint); AsyncWrite(proofRequest); }
void Battlenet::Session::HandleLogonRequestCallback(PreparedQueryResult result) { if (!result) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is trying to log in from unknown account!", GetClientInfo().c_str()); return; } Field* fields = result->Fetch(); _accountInfo->LoadResult(fields); std::string pStr = fields[8].GetString(); std::string databaseV = fields[9].GetString(); std::string databaseS = fields[10].GetString(); _gameAccounts.resize(result->GetRowCount()); uint32 i = 0; do { _gameAccounts[i++].LoadResult(result->Fetch() + 11); } while (result->NextRow()); std::string ip_address = GetRemoteIpAddress().to_string(); // If the IP is 'locked', check that the player comes indeed from the correct IP address if (_accountInfo->IsLockedToIP) { TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is locked to IP - '%s' is logging in from '%s'", _accountInfo->Login.c_str(), _accountInfo->LastIP.c_str(), ip_address.c_str()); if (_accountInfo->LastIP != ip_address) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_ACCOUNT_LOCKED); AsyncWrite(logonResponse); return; } } else { TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is not locked to ip", _accountInfo->Login.c_str()); if (_accountInfo->LockCountry.empty() || _accountInfo->LockCountry == "00") TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is not locked to country", _accountInfo->Login.c_str()); else if (!_accountInfo->LockCountry.empty() && !_ipCountry.empty()) { TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is locked to country: '%s' Player country is '%s'", _accountInfo->Login.c_str(), _accountInfo->LockCountry.c_str(), _ipCountry.c_str()); if (_ipCountry != _accountInfo->LockCountry) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_ACCOUNT_LOCKED); AsyncWrite(logonResponse); return; } } } // If the account is banned, reject the logon attempt if (_accountInfo->IsBanned) { if (_accountInfo->IsPermanentlyBanned) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(LOGIN_BANNED); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::LogonRequest] Banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountInfo->Login.c_str()); return; } else { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(LOGIN_SUSPENDED); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::LogonRequest] Temporarily banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountInfo->Login.c_str()); return; } } SHA256Hash sha; sha.UpdateData(_accountInfo->Login); sha.Finalize(); I.SetBinary(sha.GetDigest(), sha.GetLength()); ModuleInfo* password = sModuleMgr->CreateModule(_os, "Password"); ModuleInfo* thumbprint = sModuleMgr->CreateModule(_os, "Thumbprint"); if (databaseV.size() != size_t(BufferSizes::SRP_6_V) * 2 || databaseS.size() != size_t(BufferSizes::SRP_6_S) * 2) _SetVSFields(pStr); else { s.SetHexStr(databaseS.c_str()); v.SetHexStr(databaseV.c_str()); } b.SetRand(128 * 8); B = ((v * k) + g.ModExp(b, N)) % N; BigNumber unk; unk.SetRand(128 * 8); BitStream passwordData; uint8 state = 0; passwordData.WriteBytes(&state, 1); passwordData.WriteBytes(I.AsByteArray(32).get(), 32); passwordData.WriteBytes(s.AsByteArray(32).get(), 32); passwordData.WriteBytes(B.AsByteArray(128).get(), 128); passwordData.WriteBytes(unk.AsByteArray(128).get(), 128); password->DataSize = passwordData.GetSize(); password->Data = new uint8[password->DataSize]; memcpy(password->Data, passwordData.GetBuffer(), password->DataSize); _modulesWaitingForData.push(MODULE_PASSWORD); Authentication::ProofRequest* proofRequest = new Authentication::ProofRequest(); proofRequest->Modules.push_back(password); // if has authenticator, send Token module proofRequest->Modules.push_back(thumbprint); AsyncWrite(proofRequest); }
void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const& logonRequest) { if (_queryCallback) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_LOGON_TOO_FAST); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log too quick after previous attempt!", GetClientInfo().c_str()); return; } if (logonRequest.Program != "WoW") { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_INVALID_PROGRAM); AsyncWrite(logonResponse); 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()); return; } if (!sComponentMgr->HasPlatform(logonRequest.Platform)) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_INVALID_OS); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log in from an unsupported platform (using %s)!", GetClientInfo().c_str(), logonRequest.Platform.c_str()); return; } if (!sComponentMgr->HasPlatform(logonRequest.Locale)) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_UNSUPPORTED_LANGUAGE); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log in with unsupported locale (using %s)!", GetClientInfo().c_str(), logonRequest.Locale.c_str()); return; } for (Component const& component : logonRequest.Components) { if (!sComponentMgr->HasComponent(&component)) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); if (!sComponentMgr->HasProgram(component.Program)) { logonResponse->SetAuthResult(AUTH_INVALID_PROGRAM); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is using unsupported component program %s!", GetClientInfo().c_str(), component.Program.c_str()); } else if (!sComponentMgr->HasPlatform(component.Platform)) { logonResponse->SetAuthResult(AUTH_INVALID_OS); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is using unsupported component platform %s!", GetClientInfo().c_str(), component.Platform.c_str()); } else { if (component.Program != "WoW" || AuthHelper::IsBuildSupportingBattlenet(component.Build)) logonResponse->SetAuthResult(AUTH_REGION_BAD_VERSION); else logonResponse->SetAuthResult(AUTH_USE_GRUNT_LOGON); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is using unsupported component version %u!", GetClientInfo().c_str(), component.Build); } AsyncWrite(logonResponse); return; } if (component.Platform == "base") _build = component.Build; } std::string login = logonRequest.Login; _locale = logonRequest.Locale; _os = logonRequest.Platform; Utf8ToUpperOnlyLatin(login); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO); stmt->setString(0, login); _queryCallback = std::bind(&Battlenet::Session::HandleLogonRequestCallback, this, std::placeholders::_1); _queryFuture = LoginDatabase.AsyncQuery(stmt); }
BOOL WriteAsync(PAIO_DEV dev, LPVOID buffer, int bsize, AIO_CALLBACK cb, LPVOID ctx) { SetAioOper(dev, cb, ctx); return AsyncWrite(dev->dev, buffer, bsize, &dev->ioStatus); }
//! asynchronously write buffer and callback when delivered. COPIES the data //! into a Buffer! void DispatcherThread::AsyncWriteCopy(Connection& c, const void* buffer, size_t size, AsyncWriteCallback done_cb) { return AsyncWrite(c, Buffer(buffer, size), done_cb); }
cf_void OnReadComplete(cf::T_SESSION session, std::shared_ptr < cl::ReadBuffer > readBuffer) { CF_PRINT_FUNC; #if 1 fprintf (stderr, "OnReadComplete,fd=%d,addr=%s,total()=%d,buf=%s \n", session->Fd(),session->Addr().c_str(),readBuffer->GetTotal(), (cf_char *)(readBuffer->GetBuffer())); #endif TYPE_TID_CLIENTFD::const_iterator it =g_tid_fd.begin(); bool found =false; for(;it!=g_tid_fd.end();it++) { printf( "for,tid=%u,fd=%d g_tid_fd.size()=%u\n",(cf_uint32)(it->first),it->second, (cf_uint32)(g_tid_fd.size()) ); if(it->second==session->Fd()) { found =true; break; } } if(found) { printf( "is db query. \n" ); QueueElement qeOut =g_outQueue[_tid].Get(); int clientfd =qeOut.fd; std::string output_data =qeOut.pack; AsyncWrite(clientfd, output_data.c_str(), output_data.size()); return; } printf( "recv query request \n" ); cf_uint32 totalLen =readBuffer->GetTotal(); if(_recvHeader[session->Fd()]) { if(_headLen!=totalLen) { fprintf (stderr, "OnReadComplete,fd=%d,_headLen{%u}!=totalLen{%u} \n", session->Fd(),_headLen,totalLen); } else { cf_uint32 * p =(cf_uint32 *)(readBuffer->GetBuffer()); cf_uint32 size =ntohl(*p); _recvHeader[session->Fd()] =false; if(size>0) AsyncRead(session->Fd(), size); else _THROW(cf::ValueError, "size==0 !"); } } else { _recvHeader[session->Fd()] =true; //AsyncWrite(session->Fd(), readBuffer->GetBuffer(), totalLen); std::string packet((const char*)(readBuffer->GetBuffer()), size_t(totalLen)); QueueElement qe; qe.fd =session->Fd(); qe.pack =packet; g_inQueue[g_tid_pipe[_tid]].Put(qe); AsyncRead(session->Fd(), _headLen); } }