bool MemCacheClient::AddServer( const char * aServerAddress, const char * aServerName, unsigned aServices ) { if (!aServerName) { aServerName = aServerAddress; } // if we the server address is valid then we allow the server // to be added. All servers being added are assumed to be available // or to be soon made available. Server * pServer = new Server(mTrace); if (!pServer->Set(aServerAddress)) { mTrace.Trace(CLERROR, "Ignoring invalid server: %s (%s)", aServerAddress, aServerName); delete pServer; return false; } for (size_t n = 0; n < mServer.size(); ++n) { if (*pServer == *mServer[n]) { mTrace.Trace(CLERROR, "Ignoring duplicate server: %s (%s)", aServerAddress, aServerName); return true; // already have it } } mServer.push_back(pServer); // for each salt we generate a string hash for the consistent hash // table. To ensure stability of the hashing for multiple servers, // we want to have a number of entries for each server. static const char * rgpSalt[] = { "{DEA60AAB-CFF9-4a20-A799-4E5E93369656}", "{C05167CC-57DA-40f2-9EB8-18F65E56FD21}", "{57939537-0966-49e7-B675-ACE63246BFA5}", "{F0C8BE5C-A0F1-478f-BC45-28D42AF0CA1E}" }; string_t sKey; ConsistentHash entry(0, pServer, aServices, 0); for (size_t n = 0; n < sizeof(rgpSalt)/sizeof(rgpSalt[0]); ++n) { sKey = pServer->GetAddress(); sKey += rgpSalt[n]; entry.mEntry++; entry.mHash = CreateKeyHash(sKey.data()); mServerHash.push_back(entry); } // sort the vector so that we can binary search it std::sort(mServerHash.begin(), mServerHash.end()); mTrace.Trace(CLINFO, "Adding server: %s (%s:%u), services: 0x%x", aServerAddress, aServerName, pServer->GetPort(), aServices); return true; }
bool MemCacheClient::AddServer( const char * a_pszServer ) { // if we the server address is valid then we allow the server // to be added. All servers being added are assumed to be available // or to be soon made available. Uncontactable servers will cause // extra load on the database because the caching will not be available. Server * pServer = new Server; if (!pServer->Set(a_pszServer)) { delete pServer; return false; } for (size_t n = 0; n < m_rgpServer.size(); ++n) { if (*pServer == *m_rgpServer[n]) return true; // already have it } m_rgpServer.push_back(pServer); // for each salt we generate a string hash for the consistent hash // table. To ensure stability of the hashing for multiple servers, // we want to have a number of entries for each server. static const char * rgpSalt[] = { "{DD4C855D-7548-4804-8F1A-166CDBACEFE7}", "{9BF02198-1D29-4aa3-9466-A4AF4372D5B1}", "{0F20CD2F-ACF2-44bc-8CE3-54529D7B738D}", "{DEA60AAB-CFF9-4a20-A799-4E5E93369656}", "{C05167CC-57DA-40f2-9EB8-18F65E56FD21}", "{57939537-0966-49e7-B675-ACE63246BFA5}", "{F0C8BE5C-A0F1-478f-BC45-28D42AF0CA1E}" }; string_t sKey; ConsistentHash entry(0, pServer); for (size_t n = 0; n < sizeof(rgpSalt)/sizeof(rgpSalt[0]); ++n) { sKey = pServer->GetAddress(); sKey += rgpSalt[n]; entry.mHash = CreateKeyHash(sKey.data()); m_rgServerHash.push_back(entry); } // sort the vector so that we can binary search it std::sort(m_rgServerHash.begin(), m_rgServerHash.end()); #if 0 printf("\nSERVER RING (%d servers):\n", m_rgpServer.size()); for (size_t n = 0; n < m_rgServerHash.size(); ++n) { printf("%08x = %s\n", m_rgServerHash[n].mHash, m_rgServerHash[n].mServer->GetAddress()); } #endif return true; }
MCResult MemCacheClient::IncDec( const char * aType, unsigned aService, const char * aKey, uint64_t * aNewValue, uint64_t aDiff, bool aWantReply ) { string_t key(aKey); Server * pServer = FindServer(key, aService); if (!pServer) return MCERR_NOSERVER; char szBuf[50]; string_t sRequest(aType); sRequest += ' '; sRequest += aKey; snprintf(szBuf, sizeof(szBuf), " %" PRIu64, aDiff); sRequest += szBuf; if (!aWantReply) { sRequest += " noreply"; } sRequest += "\r\n"; try { pServer->SendBytes(sRequest.data(), sRequest.length()); if (!aWantReply) { return MCERR_NOREPLY; } string_t sValue; sValue = pServer->GetByte(); while (sValue[sValue.length()-1] != '\n') { sValue += pServer->GetByte(); } if (sValue == "NOT_FOUND\r\n") { return MCERR_NOTFOUND; } if (aNewValue) { *aNewValue = strtoull(sValue.data(), NULL, 10); } return MCERR_OK; } catch (const Socket::Exception & e) { mTrace.Trace(CLINFO, "IncDec: error '%s' at %s, marking request as NOSERVER", e.mDetail, pServer->GetAddress()); pServer->Disconnect(); return MCERR_NOSERVER; } }
/* Takes a server structure and adds it to the list control if insert is 1, then add an item to the list, otherwise it will update the current item with new data */ void LstOdaServerList::AddServerToList(const Server &s, wxInt32 index, bool insert) { wxFileConfig ConfigInfo; wxInt32 PQGood, PQPlayable, PQLaggy; wxInt32 i = 0; wxListItem li; wxUint64 Ping = 0; wxString GameType = wxT(""); size_t WadCount = 0; li.m_mask = wxLIST_MASK_TEXT; if (insert) { li.m_itemId = ALCInsertItem(); } else { // All cells must be cleared on a "replace" operation, otherwise if the // server failed to respond a second time 'round, we would end up with // some stale data (which is highly dependent on the response check // below) ClearItemCells(index); li.m_itemId = index; } // Address column li.m_col = serverlist_field_address; li.m_text = stdstr_towxstr(s.GetAddress()); SetItem(li); // break here so atleast we have an ip address to go by if (s.GotResponse() == false) return; // Server name column li.m_col = serverlist_field_name; li.m_text = stdstr_towxstr(s.Info.Name); SetItem(li); // Ping column Ping = s.GetPing(); li.m_col = serverlist_field_ping; li.m_text = wxString::Format(_T("%llu"), Ping); SetItem(li); // Number of players, Maximum players column // TODO: acquire max players, max clients and spectators from these 2 and // create some kind of graphical column maybe li.m_col = serverlist_field_players; li.m_text = wxString::Format(_T("%d/%d"),s.Info.Players.size(),s.Info.MaxClients); // Colour the entire text column (wx/windows bug - exploited) if there are // players // TODO: Allow the user to select prefered colours if (s.Info.Players.size()) li.SetTextColour(wxColor(0,192,0)); SetItem(li); // WAD files column WadCount = s.Info.Wads.size(); // build a list of pwads if (WadCount) { // pwad list std::string wadlist; std::string pwad; for (i = 2; i < WadCount; ++i) { pwad = s.Info.Wads[i].Name.substr(0, s.Info.Wads[i].Name.find('.')); wadlist.append(pwad); wadlist.append(" "); } li.m_col = serverlist_field_wads; li.m_text = stdstr_towxstr(wadlist); SetItem(li); } // Map name column li.m_col = serverlist_field_map; li.m_text = stdstr_towxstr(s.Info.CurrentMap).Upper(); SetItem(li); // Game type column switch (s.Info.GameType) { case GT_Cooperative: { // Detect a single player server if (s.Info.MaxPlayers > 1) GameType = wxT("Cooperative"); else GameType = wxT("Single Player"); } break; case GT_Deathmatch: { GameType = wxT("Deathmatch"); } break; case GT_TeamDeathmatch: { GameType = wxT("Team Deathmatch"); } break; case GT_CaptureTheFlag: { GameType = wxT("Capture The Flag"); } break; default: { GameType = wxT("Unknown"); } break; } li.m_col = serverlist_field_type; li.m_text = GameType; SetItem(li); // IWAD column if (WadCount) { std::string iwad; iwad = s.Info.Wads[1].Name.substr(0, s.Info.Wads[1].Name.find('.')); li.m_col = serverlist_field_iwad; li.m_text = stdstr_towxstr(iwad); } SetItem(li); // Icons // ----- // Padlock icon for passworded servers SetItemColumnImage(li.m_itemId, serverlist_field_name, (s.Info.PasswordHash.length() ? ImageList_Padlock : -1)); ConfigInfo.Read(wxT("IconPingQualityGood"), &PQGood, 150); ConfigInfo.Read(wxT("IconPingQualityPlayable"), &PQPlayable, 300); ConfigInfo.Read(wxT("IconPingQualityLaggy"), &PQLaggy, 350); // Coloured bullets for ping quality if (Ping < PQGood) { SetItemColumnImage(li.m_itemId, serverlist_field_ping, ImageList_PingGreen); } else if (Ping < PQPlayable) { SetItemColumnImage(li.m_itemId, serverlist_field_ping, ImageList_PingOrange); } else if (Ping < PQLaggy) { SetItemColumnImage(li.m_itemId, serverlist_field_ping, ImageList_PingRed); } else { SetItemColumnImage(li.m_itemId, serverlist_field_ping, ImageList_PingGray); } }