PeerThread.cpp 88 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: PeerThread.cpp //////////////////////////////////////////////////////
  24. // GameSpy Peer (chat) thread
  25. // This thread communicates with GameSpy's chat server
  26. // and talks through a message queue with the rest of
  27. // the game.
  28. // Author: Matthew D. Campbell, June 2002
  29. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  30. #include "Common/Registry.h"
  31. #include "Common/StackDump.h"
  32. #include "Common/UserPreferences.h"
  33. #include "Common/Version.h"
  34. #include "GameNetwork/IPEnumeration.h"
  35. #include "GameNetwork/GameSpy/BuddyThread.h"
  36. #include "GameNetwork/GameSpy/PeerDefs.h"
  37. #include "GameNetwork/GameSpy/PeerThread.h"
  38. #include "GameNetwork/GameSpy/PersistentStorageThread.h"
  39. #include "GameNetwork/GameSpy/ThreadUtils.h"
  40. #include "strtok_r.h"
  41. #include "mutex.h"
  42. #include "thread.h"
  43. #include "Common/MiniLog.h"
  44. #ifdef _INTERNAL
  45. // for occasional debugging...
  46. //#pragma optimize("", off)
  47. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  48. #endif
  49. // enable this for trying to track down why SBServers are losing their keyvals -MDC 2/20/2003
  50. #undef SERVER_DEBUGGING
  51. #ifdef SERVER_DEBUGGING
  52. void CheckServers(PEER peer);
  53. #endif // SERVER_DEBUGGING
  54. #ifdef DEBUG_LOGGING
  55. //#define PING_TEST
  56. static LogClass s_pingLog("Ping.txt");
  57. #define PING_LOG(x) s_pingLog.log x
  58. #else // DEBUG_LOGGING
  59. #define PING_LOG(x) {}
  60. #endif // DEBUG_LOGGING
  61. #ifdef DEBUG_LOGGING
  62. static LogClass s_stateChangedLog("StateChanged.txt");
  63. #define STATECHANGED_LOG(x) s_stateChangedLog.log x
  64. #else // DEBUG_LOGGING
  65. #define STATECHANGED_LOG(x) {}
  66. #endif // DEBUG_LOGGING
  67. // we should always be using broadcast keys from now on. Remove the old code sometime when
  68. // we're not in a rush, ok?
  69. // -MDC 2/14/2003
  70. #define USE_BROADCAST_KEYS
  71. #ifdef _INTERNAL
  72. // for occasional debugging...
  73. //#pragma optimize("", off)
  74. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  75. #endif
  76. int isThreadHosting = 0;
  77. static UnsignedInt s_lastStateChangedHeartbeat = 0;
  78. static Bool s_wantStateChangedHeartbeat = FALSE;
  79. static UnsignedInt s_heartbeatInterval = 10000;
  80. static SOCKET qr2Sock = INVALID_SOCKET;
  81. enum
  82. {
  83. EXECRC_KEY = NUM_RESERVED_KEYS + 1,
  84. INICRC_KEY,
  85. PW_KEY,
  86. OBS_KEY,
  87. LADIP_KEY,
  88. LADPORT_KEY,
  89. PINGSTR_KEY,
  90. NUMPLAYER_KEY,
  91. MAXPLAYER_KEY,
  92. NUMOBS_KEY,
  93. NAME__KEY,
  94. FACTION__KEY,
  95. COLOR__KEY,
  96. WINS__KEY,
  97. LOSSES__KEY
  98. };
  99. #define EXECRC_STR "exeCRC"
  100. #define INICRC_STR "iniCRC"
  101. #define PW_STR "pw"
  102. #define OBS_STR "obs"
  103. #define LADIP_STR "ladIP"
  104. #define LADPORT_STR "ladPort"
  105. #define PINGSTR_STR "pings"
  106. #define NUMPLAYER_STR "numRealPlayers"
  107. #define MAXPLAYER_STR "maxRealPlayers"
  108. #define NUMOBS_STR "numObservers"
  109. #define NAME__STR "name"
  110. #define FACTION__STR "faction"
  111. #define COLOR__STR "color"
  112. #define WINS__STR "wins"
  113. #define LOSSES__STR "losses"
  114. //-------------------------------------------------------------------------
  115. typedef std::queue<PeerRequest> RequestQueue;
  116. typedef std::queue<PeerResponse> ResponseQueue;
  117. class PeerThreadClass;
  118. class GameSpyPeerMessageQueue : public GameSpyPeerMessageQueueInterface
  119. {
  120. public:
  121. virtual ~GameSpyPeerMessageQueue();
  122. GameSpyPeerMessageQueue();
  123. virtual void startThread( void );
  124. virtual void endThread( void );
  125. virtual Bool isThreadRunning( void );
  126. virtual Bool isConnected( void );
  127. virtual Bool isConnecting( void );
  128. virtual void addRequest( const PeerRequest& req );
  129. virtual Bool getRequest( PeerRequest& req );
  130. virtual void addResponse( const PeerResponse& resp );
  131. virtual Bool getResponse( PeerResponse& resp );
  132. virtual SerialAuthResult getSerialAuthResult( void ) { return m_serialAuth; }
  133. void setSerialAuthResult( SerialAuthResult result ) { m_serialAuth = result; }
  134. PeerThreadClass* getThread( void );
  135. private:
  136. MutexClass m_requestMutex;
  137. MutexClass m_responseMutex;
  138. RequestQueue m_requests;
  139. ResponseQueue m_responses;
  140. PeerThreadClass *m_thread;
  141. SerialAuthResult m_serialAuth;
  142. };
  143. GameSpyPeerMessageQueueInterface* GameSpyPeerMessageQueueInterface::createNewMessageQueue( void )
  144. {
  145. return NEW GameSpyPeerMessageQueue;
  146. }
  147. GameSpyPeerMessageQueueInterface *TheGameSpyPeerMessageQueue;
  148. #define MESSAGE_QUEUE ((GameSpyPeerMessageQueue *)TheGameSpyPeerMessageQueue)
  149. //-------------------------------------------------------------------------
  150. class PeerThreadClass : public ThreadClass
  151. {
  152. public:
  153. PeerThreadClass() : ThreadClass()
  154. {
  155. //Added By Sadullah Nader
  156. //Initializations inserted
  157. m_roomJoined = m_allowObservers = m_hasPassword = FALSE;
  158. m_exeCRC = m_iniCRC = 0;
  159. m_gameVersion = 0;
  160. m_ladderPort = 0;
  161. m_localRoomID = 0;
  162. m_maxPlayers = 0;
  163. m_numObservers = 0;
  164. m_maxPlayers = 0;
  165. m_qmGroupRoom = 0;
  166. m_sawEndOfEnumPlayers = m_sawMatchbot = FALSE;
  167. m_sawCompleteGameList = FALSE;
  168. //
  169. m_isConnecting = m_isConnected = false;
  170. m_groupRoomID = m_profileID = 0;
  171. m_nextStagingServer = 1; m_stagingServers.clear();
  172. m_pingStr = ""; m_mapName = ""; m_ladderIP = ""; m_isHosting = false;
  173. for (Int i=0; i<MAX_SLOTS; ++i)
  174. {
  175. m_playerNames[i] = "";
  176. //Added by Sadullah Nader
  177. //Initializations
  178. m_playerColors[i] = 0;
  179. m_playerFactions[i] = 0;
  180. m_playerLosses[i] = 0;
  181. m_playerProfileID[i] = 0;
  182. m_playerWins[i] = 0;
  183. //
  184. }
  185. }
  186. void Thread_Function();
  187. void markAsDisconnected( void ) { m_isConnecting = m_isConnected = false; }
  188. void connectCallback( PEER peer, PEERBool success );
  189. void nickErrorCallback( PEER peer, Int type, const char *nick );
  190. Bool isConnecting( void ) { return m_isConnecting; }
  191. Bool isConnected( void ) { return m_isConnected; }
  192. Int addServerToMap( SBServer server );
  193. Int removeServerFromMap( SBServer server );
  194. void clearServers( void );
  195. SBServer findServerByID( Int id );
  196. Int findServer( SBServer server );
  197. // get info about the game we are hosting
  198. Bool isHosting( void ) { return m_isHosting; }
  199. void stopHostingAlready(PEER peer);
  200. Bool hasPassword( void ) { return m_hasPassword; }
  201. Bool allowObservers( void ) { return m_allowObservers; }
  202. std::string getMapName( void ) { return m_mapName; }
  203. UnsignedInt exeCRC( void ) { return m_exeCRC; }
  204. UnsignedInt iniCRC( void ) { return m_iniCRC; }
  205. UnsignedInt gameVersion( void ) { return m_gameVersion; }
  206. std::wstring getLocalStagingServerName( void ) { return m_localStagingServerName; }
  207. Int getLocalRoomID( void ) { return m_localRoomID; }
  208. std::string ladderIP( void ) { return m_ladderIP; }
  209. UnsignedShort ladderPort( void ) { return m_ladderPort; }
  210. std::string pingStr( void ) { return m_pingStr; }
  211. std::string getPlayerName(Int idx) { return m_playerNames[idx]; }
  212. Int getPlayerWins(Int idx) { return m_playerWins[idx]; }
  213. Int getPlayerLosses(Int idx) { return m_playerLosses[idx]; }
  214. Int getPlayerProfileID(Int idx) { return m_playerProfileID[idx]; }
  215. Int getPlayerFaction(Int idx) { return m_playerFactions[idx]; }
  216. Int getPlayerColor(Int idx) { return m_playerColors[idx]; }
  217. Int getNumPlayers(void) { return m_numPlayers; }
  218. Int getMaxPlayers(void) { return m_maxPlayers; }
  219. Int getNumObservers(void) { return m_numObservers; }
  220. void roomJoined( Bool val ) { m_roomJoined = val; }
  221. void setQMGroupRoom( Int groupID ) { m_qmGroupRoom = groupID; }
  222. void sawEndOfEnumPlayers( void ) { m_sawEndOfEnumPlayers = true; }
  223. void sawMatchbot( std::string bot ) { m_sawMatchbot = true; m_matchbotName = bot; }
  224. QMStatus getQMStatus( void ) { return m_qmStatus; }
  225. void handleQMMatch(PEER peer, Int mapIndex, Int seed, char *playerName[MAX_SLOTS], char *playerIP[MAX_SLOTS], char *playerSide[MAX_SLOTS], char *playerColor[MAX_SLOTS], char *playerNAT[MAX_SLOTS]);
  226. std::string getQMBotName( void ) { return m_matchbotName; }
  227. Int getQMGroupRoom( void ) { return m_qmGroupRoom; }
  228. Int getQMLadder( void ) { return m_qmInfo.QM.ladderID; }
  229. Int getCurrentGroupRoom(void) { return m_groupRoomID; }
  230. #ifdef USE_BROADCAST_KEYS
  231. void pushStatsToRoom(PEER peer);
  232. void getStatsFromRoom(PEER peer, RoomType roomType);
  233. void trackStatsForPlayer(RoomType roomType, const char *nick, const char *key, const char *val);
  234. int lookupStatForPlayer(RoomType roomType, const char *nick, const char *key);
  235. void clearPlayerStats(RoomType roomType);
  236. #endif // USE_BROADCAST_KEYS
  237. void setSawCompleteGameList(Bool val) { m_sawCompleteGameList = val; }
  238. Bool getSawCompleteGameList() { return m_sawCompleteGameList; }
  239. private:
  240. Bool m_isConnecting;
  241. Bool m_isConnected;
  242. std::string m_loginName, m_originalName, m_password, m_email;
  243. Int m_profileID;
  244. Int m_groupRoomID;
  245. Bool m_sawCompleteGameList;
  246. #ifdef USE_BROADCAST_KEYS
  247. enum { NumKeys = 6, ValBufSize = 20 };
  248. static const char *s_keys[NumKeys];
  249. static char s_valueBuffers[NumKeys][ValBufSize];
  250. static const char *s_values[NumKeys];
  251. typedef std::map<std::string, int> PlayerStatMap;
  252. PlayerStatMap m_groupRoomStats;
  253. PlayerStatMap m_stagingRoomStats;
  254. std::string packStatKey(const char *nick, const char *key);
  255. #endif // USE_BROADCAST_KEYS
  256. // game-hosting info for GOA callbacks
  257. Bool m_isHosting;
  258. Bool m_hasPassword;
  259. std::string m_mapName;
  260. std::string m_playerNames[MAX_SLOTS];
  261. UnsignedInt m_exeCRC;
  262. UnsignedInt m_iniCRC;
  263. UnsignedInt m_gameVersion;
  264. Bool m_allowObservers;
  265. std::string m_pingStr;
  266. std::string m_ladderIP;
  267. UnsignedShort m_ladderPort;
  268. Int m_playerWins[MAX_SLOTS];
  269. Int m_playerLosses[MAX_SLOTS];
  270. Int m_playerProfileID[MAX_SLOTS];
  271. Int m_playerColors[MAX_SLOTS];
  272. Int m_playerFactions[MAX_SLOTS];
  273. Int m_numPlayers;
  274. Int m_maxPlayers;
  275. Int m_numObservers;
  276. Int m_nextStagingServer;
  277. std::map<Int, SBServer> m_stagingServers;
  278. std::wstring m_localStagingServerName;
  279. Int m_localRoomID;
  280. void doQuickMatch( PEER peer );
  281. QMStatus m_qmStatus;
  282. PeerRequest m_qmInfo;
  283. Bool m_roomJoined;
  284. Int m_qmGroupRoom;
  285. Bool m_sawEndOfEnumPlayers;
  286. Bool m_sawMatchbot;
  287. std::string m_matchbotName;
  288. };
  289. #ifdef USE_BROADCAST_KEYS
  290. const char* PeerThreadClass::s_keys[6] = { "b_locale", "b_wins", "b_losses", "b_points", "b_side", "b_pre" };
  291. char PeerThreadClass::s_valueBuffers[6][20] = { "", "", "", "", "", "" };
  292. const char* PeerThreadClass::s_values[6] = { s_valueBuffers[0], s_valueBuffers[1], s_valueBuffers[2],
  293. s_valueBuffers[3], s_valueBuffers[4], s_valueBuffers[5]};
  294. void PeerThreadClass::trackStatsForPlayer(RoomType roomType, const char *nick, const char *key, const char *val)
  295. {
  296. switch (roomType)
  297. {
  298. case GroupRoom:
  299. m_groupRoomStats[packStatKey(nick, key)] = atoi(val);
  300. break;
  301. case StagingRoom:
  302. m_stagingRoomStats[packStatKey(nick, key)] = atoi(val);
  303. break;
  304. }
  305. }
  306. std::string PeerThreadClass::packStatKey(const char *nick, const char *key)
  307. {
  308. std::string s = nick;
  309. s.append(key);
  310. return s;
  311. }
  312. int PeerThreadClass::lookupStatForPlayer(RoomType roomType, const char *nick, const char *key)
  313. {
  314. std::string fullKey = packStatKey(nick, key);
  315. PlayerStatMap::const_iterator it;
  316. switch (roomType)
  317. {
  318. case GroupRoom:
  319. it = m_groupRoomStats.find(fullKey);
  320. if (it != m_groupRoomStats.end())
  321. return it->second;
  322. break;
  323. case StagingRoom:
  324. it = m_stagingRoomStats.find(fullKey);
  325. if (it != m_stagingRoomStats.end())
  326. return it->second;
  327. break;
  328. }
  329. return 0;
  330. }
  331. void PeerThreadClass::clearPlayerStats(RoomType roomType)
  332. {
  333. switch (roomType)
  334. {
  335. case GroupRoom:
  336. m_groupRoomStats.clear();
  337. break;
  338. case StagingRoom:
  339. m_stagingRoomStats.clear();
  340. break;
  341. }
  342. }
  343. void PeerThreadClass::pushStatsToRoom(PEER peer)
  344. {
  345. DEBUG_LOG(("PeerThreadClass::pushStatsToRoom(): stats are %s=%s,%s=%s,%s=%s,%s=%s,%s=%s,%s=%s\n",
  346. s_keys[0], s_values[0],
  347. s_keys[1], s_values[1],
  348. s_keys[2], s_values[2],
  349. s_keys[3], s_values[3],
  350. s_keys[4], s_values[4],
  351. s_keys[5], s_values[5]));
  352. peerSetRoomKeys(peer, GroupRoom, m_loginName.c_str(), 6, s_keys, s_values);
  353. peerSetRoomKeys(peer, StagingRoom, m_loginName.c_str(), 6, s_keys, s_values);
  354. }
  355. void getRoomKeysCallback(PEER peer, PEERBool success, RoomType roomType, const char *nick, int num, char **keys, char **values, void *param);
  356. void PeerThreadClass::getStatsFromRoom(PEER peer, RoomType roomType)
  357. {
  358. peerGetRoomKeys(peer, GroupRoom, "*", NumKeys, s_keys, getRoomKeysCallback, this, PEERFalse);
  359. }
  360. #endif // USE_BROADCAST_KEYS
  361. Int PeerThreadClass::addServerToMap( SBServer server )
  362. {
  363. Int val = m_nextStagingServer++;
  364. m_stagingServers[val] = server;
  365. return val;
  366. }
  367. Int PeerThreadClass::removeServerFromMap( SBServer server )
  368. {
  369. for (std::map<Int, SBServer>::iterator it = m_stagingServers.begin(); it != m_stagingServers.end(); ++it)
  370. {
  371. if (it->second == server)
  372. {
  373. Int val = it->first;
  374. m_stagingServers.erase(it);
  375. return val;
  376. }
  377. }
  378. return 0;
  379. }
  380. void PeerThreadClass::clearServers( void )
  381. {
  382. m_stagingServers.clear();
  383. }
  384. SBServer PeerThreadClass::findServerByID( Int id )
  385. {
  386. std::map<Int, SBServer>::iterator it = m_stagingServers.find(id);
  387. if (it != m_stagingServers.end())
  388. {
  389. SBServer server = it->second;
  390. if (server && !server->keyvals)
  391. {
  392. DEBUG_CRASH(("Referencing a missing server!"));
  393. return 0;
  394. }
  395. return it->second;
  396. }
  397. return 0;
  398. }
  399. Int PeerThreadClass::findServer( SBServer server )
  400. {
  401. char tmp[10] = "";
  402. const char *newName = SBServerGetStringValue(server, "gamename", tmp);
  403. UnsignedInt newPrivateIP = SBServerGetPrivateInetAddress(server);
  404. UnsignedShort newPrivatePort = SBServerGetPrivateQueryPort(server);
  405. UnsignedInt newPublicIP = SBServerGetPublicInetAddress(server);
  406. SBServer serverToRemove = NULL;
  407. for (std::map<Int, SBServer>::iterator it = m_stagingServers.begin(); it != m_stagingServers.end(); ++it)
  408. {
  409. if (it->second == server)
  410. {
  411. return it->first;
  412. }
  413. else
  414. {
  415. const char *oldName = SBServerGetStringValue(it->second, "gamename", tmp);
  416. UnsignedInt oldPrivateIP = SBServerGetPrivateInetAddress(it->second);
  417. UnsignedShort oldPrivatePort = SBServerGetPrivateQueryPort(it->second);
  418. UnsignedInt oldPublicIP = SBServerGetPublicInetAddress(it->second);
  419. if (!strcmp(oldName, newName) &&
  420. oldPrivateIP == newPrivateIP &&
  421. oldPublicIP == newPublicIP &&
  422. oldPrivatePort == newPrivatePort)
  423. {
  424. serverToRemove = it->second;
  425. }
  426. }
  427. }
  428. if (serverToRemove)
  429. {
  430. // this is the same as another game - it has just migrated to another port. Remove the old and replace it.
  431. PeerResponse resp;
  432. resp.peerResponseType = PeerResponse::PEERRESPONSE_STAGINGROOM;
  433. resp.stagingRoom.id = removeServerFromMap( serverToRemove );
  434. resp.stagingRoom.action = PEER_REMOVE;
  435. resp.stagingRoom.isStaging = TRUE;
  436. resp.stagingRoom.percentComplete = -1;
  437. TheGameSpyPeerMessageQueue->addResponse(resp);
  438. }
  439. return addServerToMap(server);
  440. }
  441. static enum CallbackType
  442. {
  443. CALLBACK_CONNECT,
  444. CALLBACK_ERROR,
  445. CALLBACK_RECVMESSAGE,
  446. CALLBACK_RECVREQUEST,
  447. CALLBACK_RECVSTATUS,
  448. CALLBACK_MAX
  449. };
  450. void connectCallbackWrapper( PEER peer, PEERBool success, void *param )
  451. {
  452. #ifdef SERVER_DEBUGGING
  453. DEBUG_LOG(("In connectCallbackWrapper()\n"));
  454. CheckServers(peer);
  455. #endif // SERVER_DEBUGGING
  456. if (param != NULL)
  457. {
  458. ((PeerThreadClass *)param)->connectCallback( peer, success );
  459. }
  460. }
  461. void nickErrorCallbackWrapper( PEER peer, Int type, const char *nick, void *param )
  462. {
  463. if (param != NULL)
  464. {
  465. ((PeerThreadClass *)param)->nickErrorCallback( peer, type, nick );
  466. }
  467. }
  468. static void joinRoomCallback(PEER peer, PEERBool success, PEERJoinResult result, RoomType roomType, void *param);
  469. //-------------------------------------------------------------------------
  470. GameSpyPeerMessageQueue::GameSpyPeerMessageQueue()
  471. {
  472. m_thread = NULL;
  473. m_serialAuth = SERIAL_OK;
  474. }
  475. GameSpyPeerMessageQueue::~GameSpyPeerMessageQueue()
  476. {
  477. endThread();
  478. }
  479. void GameSpyPeerMessageQueue::startThread( void )
  480. {
  481. if (!m_thread)
  482. {
  483. m_thread = NEW PeerThreadClass;
  484. m_thread->Execute();
  485. }
  486. else
  487. {
  488. if (!m_thread->Is_Running())
  489. {
  490. m_thread->Execute();
  491. }
  492. }
  493. }
  494. void GameSpyPeerMessageQueue::endThread( void )
  495. {
  496. if (m_thread)
  497. delete m_thread;
  498. m_thread = NULL;
  499. }
  500. Bool GameSpyPeerMessageQueue::isThreadRunning( void )
  501. {
  502. return (m_thread) ? m_thread->Is_Running() : false;
  503. }
  504. Bool GameSpyPeerMessageQueue::isConnected( void )
  505. {
  506. return (m_thread) ? m_thread->isConnected() : false;
  507. }
  508. Bool GameSpyPeerMessageQueue::isConnecting( void )
  509. {
  510. return (m_thread) ? m_thread->isConnecting() : false;
  511. }
  512. void GameSpyPeerMessageQueue::addRequest( const PeerRequest& req )
  513. {
  514. MutexClass::LockClass m(m_requestMutex);
  515. if (m.Failed())
  516. return;
  517. m_requests.push(req);
  518. }
  519. //PeerRequest GameSpyPeerMessageQueue::getRequest( void )
  520. Bool GameSpyPeerMessageQueue::getRequest( PeerRequest& req )
  521. {
  522. MutexClass::LockClass m(m_requestMutex, 0);
  523. if (m.Failed())
  524. return false;
  525. if (m_requests.empty())
  526. return false;
  527. req = m_requests.front();
  528. m_requests.pop();
  529. return true;
  530. }
  531. void GameSpyPeerMessageQueue::addResponse( const PeerResponse& resp )
  532. {
  533. if (resp.nick == "(END)")
  534. return;
  535. MutexClass::LockClass m(m_responseMutex);
  536. if (m.Failed())
  537. return;
  538. m_responses.push(resp);
  539. }
  540. //PeerResponse GameSpyPeerMessageQueue::getResponse( void )
  541. Bool GameSpyPeerMessageQueue::getResponse( PeerResponse& resp )
  542. {
  543. MutexClass::LockClass m(m_responseMutex, 0);
  544. if (m.Failed())
  545. return false;
  546. if (m_responses.empty())
  547. return false;
  548. resp = m_responses.front();
  549. m_responses.pop();
  550. return true;
  551. }
  552. PeerThreadClass* GameSpyPeerMessageQueue::getThread( void )
  553. {
  554. return m_thread;
  555. }
  556. //-------------------------------------------------------------------------
  557. static void disconnectedCallback(PEER peer, const char * reason, void * param);
  558. static void roomMessageCallback(PEER peer, RoomType roomType, const char * nick, const char * message, MessageType messageType, void * param);
  559. static void playerMessageCallback(PEER peer, const char * nick, const char * message, MessageType messageType, void * param);
  560. static void playerJoinedCallback(PEER peer, RoomType roomType, const char * nick, void * param);
  561. static void playerLeftCallback(PEER peer, RoomType roomType, const char * nick, const char * reason, void * param);
  562. static void playerChangedNickCallback(PEER peer, RoomType roomType, const char * oldNick, const char * newNick, void * param);
  563. static void playerInfoCallback(PEER peer, RoomType roomType, const char * nick, unsigned int IP, int profileID, void * param);
  564. static void playerFlagsChangedCallback(PEER peer, RoomType roomType, const char * nick, int oldFlags, int newFlags, void * param);
  565. static void listingGamesCallback(PEER peer, PEERBool success, const char * name, SBServer server, PEERBool staging, int msg, Int percentListed, void * param);
  566. static void roomUTMCallback(PEER peer, RoomType roomType, const char * nick, const char * command, const char * parameters, PEERBool authenticated, void * param);
  567. static void playerUTMCallback(PEER peer, const char * nick, const char * command, const char * parameters, PEERBool authenticated, void * param);
  568. static void gameStartedCallback(PEER peer, UnsignedInt IP, const char *message, void *param);
  569. static void globalKeyChangedCallback(PEER peer, const char *nick, const char *key, const char *val, void *param);
  570. static void roomKeyChangedCallback(PEER peer, RoomType roomType, const char *nick, const char *key, const char *val, void *param);
  571. // convenience function to set buddy status
  572. static void updateBuddyStatus( GameSpyBuddyStatus status, Int groupRoom = 0, std::string gameName = "" )
  573. {
  574. if (!TheGameSpyBuddyMessageQueue)
  575. return;
  576. BuddyRequest req;
  577. req.buddyRequestType = BuddyRequest::BUDDYREQUEST_SETSTATUS;
  578. switch(status)
  579. {
  580. case BUDDY_OFFLINE:
  581. req.arg.status.status = GP_OFFLINE;
  582. strcpy(req.arg.status.statusString, "Offline");
  583. strcpy(req.arg.status.locationString, "");
  584. break;
  585. case BUDDY_ONLINE:
  586. req.arg.status.status = GP_ONLINE;
  587. strcpy(req.arg.status.statusString, "Online");
  588. strcpy(req.arg.status.locationString, "");
  589. break;
  590. case BUDDY_LOBBY:
  591. req.arg.status.status = GP_CHATTING;
  592. strcpy(req.arg.status.statusString, "Chatting");
  593. sprintf(req.arg.status.locationString, "%d", groupRoom);
  594. break;
  595. case BUDDY_STAGING:
  596. req.arg.status.status = GP_STAGING;
  597. strcpy(req.arg.status.statusString, "Staging");
  598. sprintf(req.arg.status.locationString, "%s", gameName.c_str());
  599. break;
  600. case BUDDY_LOADING:
  601. req.arg.status.status = GP_PLAYING;
  602. strcpy(req.arg.status.statusString, "Loading");
  603. sprintf(req.arg.status.locationString, "%s", gameName.c_str());
  604. break;
  605. case BUDDY_PLAYING:
  606. req.arg.status.status = GP_PLAYING;
  607. strcpy(req.arg.status.statusString, "Playing");
  608. sprintf(req.arg.status.locationString, "%s", gameName.c_str());
  609. break;
  610. case BUDDY_MATCHING:
  611. req.arg.status.status = GP_ONLINE;
  612. strcpy(req.arg.status.statusString, "Matching");
  613. strcpy(req.arg.status.locationString, "");
  614. break;
  615. }
  616. DEBUG_LOG(("updateBuddyStatus %d:%s\n", req.arg.status.status, req.arg.status.statusString));
  617. TheGameSpyBuddyMessageQueue->addRequest(req);
  618. }
  619. static void createRoomCallback(PEER peer, PEERBool success, PEERJoinResult result, RoomType roomType, void *param)
  620. {
  621. Int *s = (Int *)param;
  622. if (s)
  623. *s = result;
  624. }
  625. static const char * KeyTypeToString(qr2_key_type type)
  626. {
  627. switch(type)
  628. {
  629. case key_server:
  630. return "server";
  631. case key_player:
  632. return "player";
  633. case key_team:
  634. return "team";
  635. }
  636. return "Unkown key type";
  637. }
  638. static const char * ErrorTypeToString(qr2_error_t error)
  639. {
  640. switch(error)
  641. {
  642. case e_qrnoerror:
  643. return "noerror";
  644. case e_qrwsockerror:
  645. return "wsockerror";
  646. case e_qrbinderror:
  647. return "rbinderror";
  648. case e_qrdnserror:
  649. return "dnserror";
  650. case e_qrconnerror:
  651. return "connerror";
  652. }
  653. return "Unknown error type";
  654. }
  655. static void QRServerKeyCallback
  656. (
  657. PEER peer,
  658. int key,
  659. qr2_buffer_t buffer,
  660. void * param
  661. )
  662. {
  663. //DEBUG_LOG(("QR_SERVER_KEY | %d (%s)\n", key, qr2_registered_key_list[key]));
  664. PeerThreadClass *t = (PeerThreadClass *)param;
  665. if (!t)
  666. {
  667. DEBUG_LOG(("QRServerKeyCallback: bailing because of no thread info\n"));
  668. return;
  669. }
  670. if (!t->isHosting())
  671. t->stopHostingAlready(peer);
  672. #ifdef DEBUG_LOGGING
  673. AsciiString val = "";
  674. #define ADD(x) { qr2_buffer_add(buffer, x); val = x; }
  675. #define ADDINT(x) { qr2_buffer_add_int(buffer, x); val.format("%d",x); }
  676. #else
  677. #define ADD(x) { qr2_buffer_add(buffer, x); }
  678. #define ADDINT(x) { qr2_buffer_add_int(buffer, x); }
  679. #endif
  680. switch(key)
  681. {
  682. case HOSTNAME_KEY:
  683. ADD(t->getPlayerName(0).c_str());
  684. break;
  685. case GAMEVER_KEY:
  686. ADDINT(t->gameVersion());
  687. break;
  688. case EXECRC_KEY:
  689. ADDINT(t->exeCRC());
  690. break;
  691. case INICRC_KEY:
  692. ADDINT(t->iniCRC());
  693. break;
  694. case GAMENAME_KEY:
  695. {
  696. std::string tmp = t->getPlayerName(0);
  697. tmp.append(" ");
  698. tmp.append(WideCharStringToMultiByte(t->getLocalStagingServerName().c_str()));
  699. ADD(tmp.c_str());
  700. }
  701. break;
  702. case MAPNAME_KEY:
  703. ADD(t->getMapName().c_str());
  704. break;
  705. case PW_KEY:
  706. ADDINT(t->hasPassword());
  707. break;
  708. case OBS_KEY:
  709. ADDINT(t->allowObservers());
  710. break;
  711. case LADIP_KEY:
  712. ADD(t->ladderIP().c_str());
  713. break;
  714. case LADPORT_KEY:
  715. ADDINT(t->ladderPort());
  716. break;
  717. case PINGSTR_KEY:
  718. ADD(t->pingStr().c_str());
  719. break;
  720. case NUMPLAYER_KEY:
  721. ADDINT(t->getNumPlayers());
  722. break;
  723. case MAXPLAYER_KEY:
  724. ADDINT(t->getMaxPlayers());
  725. break;
  726. case NUMOBS_KEY:
  727. ADDINT(t->getNumObservers());
  728. break;
  729. default:
  730. ADD("");
  731. //DEBUG_LOG(("QR_SERVER_KEY | %d (%s)\n", key, qr2_registered_key_list[key]));
  732. break;
  733. }
  734. DEBUG_LOG(("QR_SERVER_KEY | %d (%s) = [%s]\n", key, qr2_registered_key_list[key], val.str()));
  735. }
  736. static void QRPlayerKeyCallback
  737. (
  738. PEER peer,
  739. int key,
  740. int index,
  741. qr2_buffer_t buffer,
  742. void * param
  743. )
  744. {
  745. //DEBUG_LOG(("QR_PLAYER_KEY | %d | %d (%s)\n", key, index, qr2_registered_key_list[key]));
  746. PeerThreadClass *t = (PeerThreadClass *)param;
  747. if (!t)
  748. {
  749. DEBUG_LOG(("QRPlayerKeyCallback: bailing because of no thread info\n"));
  750. return;
  751. }
  752. if (!t->isHosting())
  753. t->stopHostingAlready(peer);
  754. #undef ADD
  755. #undef ADDINT
  756. #ifdef DEBUG_LOGGING
  757. AsciiString val = "";
  758. #define ADD(x) { qr2_buffer_add(buffer, x); val = x; }
  759. #define ADDINT(x) { qr2_buffer_add_int(buffer, x); val.format("%d",x); }
  760. #else
  761. #define ADD(x) { qr2_buffer_add(buffer, x); }
  762. #define ADDINT(x) { qr2_buffer_add_int(buffer, x); }
  763. #endif
  764. switch(key)
  765. {
  766. case NAME__KEY:
  767. ADD(t->getPlayerName(index).c_str());
  768. break;
  769. case WINS__KEY:
  770. ADDINT(t->getPlayerWins(index));
  771. break;
  772. case LOSSES__KEY:
  773. ADDINT(t->getPlayerLosses(index));
  774. break;
  775. case PID__KEY:
  776. ADDINT(t->getPlayerProfileID(index));
  777. break;
  778. case FACTION__KEY:
  779. ADDINT(t->getPlayerLosses(index));
  780. break;
  781. case COLOR__KEY:
  782. ADDINT(t->getPlayerLosses(index));
  783. break;
  784. default:
  785. ADD("");
  786. //DEBUG_LOG(("QR_PLAYER_KEY | %d | %d (%s)\n", key, index, qr2_registered_key_list[key]));
  787. break;
  788. }
  789. DEBUG_LOG(("QR_PLAYER_KEY | %d | %d (%s) = [%s]\n", key, index, qr2_registered_key_list[key], val.str()));
  790. }
  791. static void QRTeamKeyCallback
  792. (
  793. PEER peer,
  794. int key,
  795. int index,
  796. qr2_buffer_t buffer,
  797. void * param
  798. )
  799. {
  800. //DEBUG_LOG(("QR_TEAM_KEY | %d | %d\n", key, index));
  801. PeerThreadClass *t = (PeerThreadClass *)param;
  802. if (!t)
  803. {
  804. DEBUG_LOG(("QRTeamKeyCallback: bailing because of no thread info\n"));
  805. return;
  806. }
  807. if (!t->isHosting())
  808. t->stopHostingAlready(peer);
  809. // we don't report teams, so this shouldn't get called
  810. qr2_buffer_add(buffer, "");
  811. }
  812. static void QRKeyListCallback
  813. (
  814. PEER peer,
  815. qr2_key_type type,
  816. qr2_keybuffer_t keyBuffer,
  817. void * param
  818. )
  819. {
  820. DEBUG_LOG(("QR_KEY_LIST | %s\n", KeyTypeToString(type)));
  821. /*
  822. PeerThreadClass *t = (PeerThreadClass *)param;
  823. if (!t)
  824. {
  825. DEBUG_LOG(("QRKeyListCallback: bailing because of no thread info\n"));
  826. return;
  827. }
  828. if (!t->isHosting())
  829. t->stopHostingAlready(peer);
  830. */
  831. // register the keys we use
  832. switch(type)
  833. {
  834. case key_server:
  835. qr2_keybuffer_add(keyBuffer, HOSTNAME_KEY);
  836. qr2_keybuffer_add(keyBuffer, GAMEVER_KEY);
  837. //qr2_keybuffer_add(keyBuffer, GAMENAME_KEY);
  838. qr2_keybuffer_add(keyBuffer, MAPNAME_KEY);
  839. qr2_keybuffer_add(keyBuffer, EXECRC_KEY);
  840. qr2_keybuffer_add(keyBuffer, INICRC_KEY);
  841. qr2_keybuffer_add(keyBuffer, PW_KEY);
  842. qr2_keybuffer_add(keyBuffer, OBS_KEY);
  843. qr2_keybuffer_add(keyBuffer, LADIP_KEY);
  844. qr2_keybuffer_add(keyBuffer, LADPORT_KEY);
  845. qr2_keybuffer_add(keyBuffer, PINGSTR_KEY);
  846. qr2_keybuffer_add(keyBuffer, NUMPLAYER_KEY);
  847. qr2_keybuffer_add(keyBuffer, MAXPLAYER_KEY);
  848. qr2_keybuffer_add(keyBuffer, NUMOBS_KEY);
  849. break;
  850. case key_player:
  851. qr2_keybuffer_add(keyBuffer, NAME__KEY);
  852. qr2_keybuffer_add(keyBuffer, WINS__KEY);
  853. qr2_keybuffer_add(keyBuffer, LOSSES__KEY);
  854. qr2_keybuffer_add(keyBuffer, PID__KEY);
  855. qr2_keybuffer_add(keyBuffer, FACTION__KEY);
  856. qr2_keybuffer_add(keyBuffer, COLOR__KEY);
  857. break;
  858. case key_team:
  859. // no custom team keys
  860. break;
  861. }
  862. }
  863. static int QRCountCallback
  864. (
  865. PEER peer,
  866. qr2_key_type type,
  867. void * param
  868. )
  869. {
  870. PeerThreadClass *t = (PeerThreadClass *)param;
  871. if (!t)
  872. {
  873. DEBUG_LOG(("QRCountCallback: bailing because of no thread info\n"));
  874. return 0;
  875. }
  876. if (!t->isHosting())
  877. t->stopHostingAlready(peer);
  878. if(type == key_player)
  879. {
  880. DEBUG_LOG(("QR_COUNT | %s = %d\n", KeyTypeToString(type), t->getNumPlayers() + t->getNumObservers()));
  881. return t->getNumPlayers() + t->getNumObservers();
  882. }
  883. else if(type == key_team)
  884. {
  885. DEBUG_LOG(("QR_COUNT | %s = %d\n", KeyTypeToString(type), 0));
  886. return 0;
  887. }
  888. DEBUG_LOG(("QR_COUNT | %s = %d\n", KeyTypeToString(type), 0));
  889. return 0;
  890. }
  891. void PeerThreadClass::stopHostingAlready(PEER peer)
  892. {
  893. isThreadHosting = 0; // debugging
  894. s_lastStateChangedHeartbeat = 0;
  895. s_wantStateChangedHeartbeat = FALSE;
  896. peerStopGame(peer);
  897. if (qr2Sock != INVALID_SOCKET)
  898. {
  899. closesocket(qr2Sock);
  900. qr2Sock = INVALID_SOCKET;
  901. }
  902. }
  903. static void QRAddErrorCallback
  904. (
  905. PEER peer,
  906. qr2_error_t error,
  907. char * errorString,
  908. void * param
  909. )
  910. {
  911. DEBUG_LOG(("QR_ADD_ERROR | %s | %s\n", ErrorTypeToString(error), errorString));
  912. PeerResponse resp;
  913. resp.peerResponseType = PeerResponse::PEERRESPONSE_FAILEDTOHOST;
  914. TheGameSpyPeerMessageQueue->addResponse(resp);
  915. }
  916. static void QRNatNegotiateCallback
  917. (
  918. PEER peer,
  919. int cookie,
  920. void * param
  921. )
  922. {
  923. DEBUG_LOG(("QR_NAT_NEGOTIATE | 0x%08X\n", cookie));
  924. }
  925. static void KickedCallback
  926. (
  927. PEER peer,
  928. RoomType roomType,
  929. const char * nick,
  930. const char * reason,
  931. void * param
  932. )
  933. {
  934. DEBUG_LOG(("Kicked from %d by %s: \"%s\"\n", roomType, nick, reason));
  935. }
  936. static void NewPlayerListCallback
  937. (
  938. PEER peer,
  939. RoomType roomType,
  940. void * param
  941. )
  942. {
  943. DEBUG_LOG(("NewPlayerListCallback\n"));
  944. }
  945. static void AuthenticateCDKeyCallback
  946. (
  947. PEER peer,
  948. int result,
  949. const char * message,
  950. void * param
  951. )
  952. {
  953. DEBUG_LOG(("CD Key Result: %s (%d) %X\n", message, result, param));
  954. #ifdef SERVER_DEBUGGING
  955. CheckServers(peer);
  956. #endif // SERVER_DEBUGGING
  957. SerialAuthResult *val = (SerialAuthResult *)param;
  958. if (val)
  959. {
  960. if (result >= 1)
  961. {
  962. *val = SERIAL_OK;
  963. }
  964. else
  965. {
  966. *val = SERIAL_AUTHFAILED;
  967. }
  968. }
  969. #ifdef SERVER_DEBUGGING
  970. CheckServers(peer);
  971. #endif // SERVER_DEBUGGING
  972. }
  973. static SerialAuthResult doCDKeyAuthentication( PEER peer )
  974. {
  975. SerialAuthResult retval = SERIAL_NONEXISTENT;
  976. if (!peer)
  977. return retval;
  978. AsciiString s = "";
  979. if (GetStringFromRegistry("\\ergc", "", s) && s.isNotEmpty())
  980. {
  981. #ifdef SERVER_DEBUGGING
  982. DEBUG_LOG(("Before peerAuthenticateCDKey()\n"));
  983. CheckServers(peer);
  984. #endif // SERVER_DEBUGGING
  985. peerAuthenticateCDKey(peer, s.str(), AuthenticateCDKeyCallback, &retval, PEERTrue);
  986. #ifdef SERVER_DEBUGGING
  987. DEBUG_LOG(("After peerAuthenticateCDKey()\n"));
  988. CheckServers(peer);
  989. #endif // SERVER_DEBUGGING
  990. }
  991. if (retval == SERIAL_OK)
  992. {
  993. PSRequest req;
  994. req.requestType = PSRequest::PSREQUEST_READCDKEYSTATS;
  995. req.cdkey = s.str();
  996. TheGameSpyPSMessageQueue->addRequest(req);
  997. }
  998. return retval;
  999. }
  1000. #define INBUF_LEN 256
  1001. void checkQR2Queries( PEER peer, SOCKET sock )
  1002. {
  1003. static char indata[INBUF_LEN];
  1004. struct sockaddr_in saddr;
  1005. int saddrlen = sizeof(struct sockaddr_in);
  1006. fd_set set;
  1007. struct timeval timeout = {0,0};
  1008. int error;
  1009. FD_ZERO ( &set );
  1010. FD_SET ( sock, &set );
  1011. while (1)
  1012. {
  1013. error = select(FD_SETSIZE, &set, NULL, NULL, &timeout);
  1014. if (SOCKET_ERROR == error || 0 == error)
  1015. return;
  1016. //else we have data
  1017. error = recvfrom(sock, indata, INBUF_LEN - 1, 0, (struct sockaddr *)&saddr, &saddrlen);
  1018. if (error != SOCKET_ERROR)
  1019. {
  1020. indata[error] = '\0';
  1021. peerParseQuery( peer, indata, error, (sockaddr *)&saddr );
  1022. }
  1023. }
  1024. }
  1025. static UnsignedInt localIP = 0;
  1026. void PeerThreadClass::Thread_Function()
  1027. {
  1028. try {
  1029. _set_se_translator( DumpExceptionInfo ); // Hook that allows stack trace.
  1030. PEER peer;
  1031. // Setup the callbacks.
  1032. ///////////////////////
  1033. PEERCallbacks callbacks;
  1034. memset(&callbacks, 0, sizeof(PEERCallbacks));
  1035. callbacks.disconnected = disconnectedCallback;
  1036. //callbacks.readyChanged = readyChangedCallback;
  1037. callbacks.roomMessage = roomMessageCallback;
  1038. callbacks.playerMessage = playerMessageCallback;
  1039. callbacks.gameStarted = gameStartedCallback;
  1040. callbacks.playerJoined = playerJoinedCallback;
  1041. callbacks.playerLeft = playerLeftCallback;
  1042. callbacks.playerChangedNick = playerChangedNickCallback;
  1043. callbacks.playerFlagsChanged = playerFlagsChangedCallback;
  1044. callbacks.playerInfo = playerInfoCallback;
  1045. callbacks.roomUTM = roomUTMCallback;
  1046. callbacks.playerUTM = playerUTMCallback;
  1047. callbacks.globalKeyChanged = globalKeyChangedCallback;
  1048. callbacks.roomKeyChanged = roomKeyChangedCallback;
  1049. callbacks.qrServerKey = QRServerKeyCallback;
  1050. callbacks.qrPlayerKey = QRPlayerKeyCallback;
  1051. callbacks.qrTeamKey = QRTeamKeyCallback;
  1052. callbacks.qrKeyList = QRKeyListCallback;
  1053. callbacks.qrCount = QRCountCallback;
  1054. callbacks.qrAddError = QRAddErrorCallback;
  1055. callbacks.qrNatNegotiateCallback = QRNatNegotiateCallback;
  1056. callbacks.kicked = KickedCallback;
  1057. callbacks.newPlayerList = NewPlayerListCallback;
  1058. callbacks.param = this;
  1059. m_qmGroupRoom = 0;
  1060. peer = peerInitialize( &callbacks );
  1061. DEBUG_ASSERTCRASH( peer != NULL, ("NULL peer!") );
  1062. m_isConnected = m_isConnecting = false;
  1063. qr2_register_key(EXECRC_KEY, EXECRC_STR);
  1064. qr2_register_key(INICRC_KEY, INICRC_STR);
  1065. qr2_register_key(PW_KEY, PW_STR);
  1066. qr2_register_key(OBS_KEY, OBS_STR);
  1067. qr2_register_key(LADIP_KEY, LADIP_STR);
  1068. qr2_register_key(LADPORT_KEY, LADPORT_STR);
  1069. qr2_register_key(PINGSTR_KEY, PINGSTR_STR);
  1070. qr2_register_key(NUMOBS_KEY, NUMOBS_STR);
  1071. qr2_register_key(NUMPLAYER_KEY, NUMPLAYER_STR);
  1072. qr2_register_key(MAXPLAYER_KEY, MAXPLAYER_STR);
  1073. qr2_register_key(NAME__KEY, NAME__STR "_");
  1074. qr2_register_key(WINS__KEY, WINS__STR "_");
  1075. qr2_register_key(LOSSES__KEY, LOSSES__STR "_");
  1076. qr2_register_key(FACTION__KEY, FACTION__STR "_");
  1077. qr2_register_key(COLOR__KEY, COLOR__STR "_");
  1078. const Int NumKeys = 14;
  1079. unsigned char allKeysArray[NumKeys] = {
  1080. /*
  1081. PID__KEY,
  1082. NAME__KEY,
  1083. WINS__KEY,
  1084. LOSSES__KEY,
  1085. FACTION__KEY,
  1086. COLOR__KEY,
  1087. */
  1088. MAPNAME_KEY,
  1089. GAMEVER_KEY,
  1090. GAMENAME_KEY,
  1091. EXECRC_KEY,
  1092. INICRC_KEY,
  1093. PW_KEY,
  1094. OBS_KEY,
  1095. LADIP_KEY,
  1096. LADPORT_KEY,
  1097. PINGSTR_KEY,
  1098. NUMOBS_KEY,
  1099. NUMPLAYER_KEY,
  1100. MAXPLAYER_KEY,
  1101. HOSTNAME_KEY
  1102. };
  1103. /*
  1104. const char *allKeys = "\\pid_\\mapname\\gamever\\gamename" \
  1105. "\\" EXECRC_STR "\\" INICRC_STR \
  1106. "\\" PW_STR "\\" OBS_STR "\\" LADIP_STR "\\" LADPORT_STR \
  1107. "\\" PINGSTR_STR "\\" NUMOBS_STR \
  1108. "\\" NUMPLAYER_STR "\\" MAXPLAYER_STR \
  1109. "\\" NAME__STR "_" "\\" WINS__STR "_" "\\" LOSSES__STR "_" "\\" FACTION__STR "_" "\\" COLOR__STR "_";
  1110. */
  1111. const char * key = "username";
  1112. peerSetRoomWatchKeys(peer, StagingRoom, 1, &key, PEERTrue);
  1113. peerSetRoomWatchKeys(peer, GroupRoom, 1, &key, PEERTrue);
  1114. m_localRoomID = 0;
  1115. m_localStagingServerName = L"";
  1116. m_qmStatus = QM_IDLE;
  1117. // Setup which rooms to do pings and cross-pings in.
  1118. ////////////////////////////////////////////////////
  1119. PEERBool pingRooms[NumRooms];
  1120. PEERBool crossPingRooms[NumRooms];
  1121. pingRooms[TitleRoom] = PEERFalse;
  1122. pingRooms[GroupRoom] = PEERFalse;
  1123. pingRooms[StagingRoom] = PEERFalse;
  1124. crossPingRooms[TitleRoom] = PEERFalse;
  1125. crossPingRooms[GroupRoom] = PEERFalse;
  1126. crossPingRooms[StagingRoom] = PEERFalse;
  1127. /*********
  1128. First step, set our game authentication info
  1129. We could do:
  1130. strcpy(gcd_gamename,"ccgenerals");
  1131. strcpy(gcd_secret_key,"h5T2f6");
  1132. or
  1133. strcpy(gcd_gamename,"ccgeneralsb");
  1134. strcpy(gcd_secret_key,"g3T9s2");
  1135. ...but this is more secure:
  1136. **********/
  1137. char gameName[12];
  1138. char secretKey[7];
  1139. /**
  1140. gameName[0]='c';gameName[1]='c';gameName[2]='g';gameName[3]='e';
  1141. gameName[4]='n';gameName[5]='e';gameName[6]='r';gameName[7]='a';
  1142. gameName[8]='l';gameName[9]='s';gameName[10]='b';gameName[11]='\0';
  1143. secretKey[0]='g';secretKey[1]='3';secretKey[2]='T';secretKey[3]='9';
  1144. secretKey[4]='s';secretKey[5]='2';secretKey[6]='\0';
  1145. /**/
  1146. gameName[0]='c';gameName[1]='c';gameName[2]='g';gameName[3]='e';
  1147. gameName[4]='n';gameName[5]='e';gameName[6]='r';gameName[7]='a';
  1148. gameName[8]='l';gameName[9]='s';gameName[10]='\0';
  1149. secretKey[0]='h';secretKey[1]='5';secretKey[2]='T';secretKey[3]='2';
  1150. secretKey[4]='f';secretKey[5]='6';secretKey[6]='\0';
  1151. /**/
  1152. // Set the title.
  1153. /////////////////
  1154. if(!peerSetTitle( peer , gameName, secretKey, gameName, secretKey, GetRegistryVersion(), 30, PEERTrue, pingRooms, crossPingRooms))
  1155. {
  1156. DEBUG_CRASH(("Error setting title"));
  1157. peerShutdown( peer );
  1158. peer = NULL;
  1159. return;
  1160. }
  1161. OptionPreferences pref;
  1162. UnsignedInt preferredIP = INADDR_ANY;
  1163. UnsignedInt selectedIP = pref.getOnlineIPAddress();
  1164. DEBUG_LOG(("Looking for IP %X\n", selectedIP));
  1165. IPEnumeration IPs;
  1166. EnumeratedIP *IPlist = IPs.getAddresses();
  1167. while (IPlist)
  1168. {
  1169. DEBUG_LOG(("Looking at IP %s\n", IPlist->getIPstring().str()));
  1170. if (selectedIP == IPlist->getIP())
  1171. {
  1172. preferredIP = IPlist->getIP();
  1173. DEBUG_LOG(("Connecting to GameSpy chat server via IP address %8.8X\n", preferredIP));
  1174. break;
  1175. }
  1176. IPlist = IPlist->getNext();
  1177. }
  1178. chatSetLocalIP(preferredIP);
  1179. UnsignedInt preferredQRPort = 0;
  1180. AsciiString selectedQRPort = pref["GameSpyQRPort"];
  1181. if (selectedQRPort.isNotEmpty())
  1182. {
  1183. preferredQRPort = atoi(selectedQRPort.str());
  1184. }
  1185. PeerRequest incomingRequest;
  1186. while ( running )
  1187. {
  1188. // deal with requests
  1189. if (TheGameSpyPeerMessageQueue->getRequest(incomingRequest))
  1190. {
  1191. DEBUG_LOG(("TheGameSpyPeerMessageQueue->getRequest() got request of type %d\n", incomingRequest.peerRequestType));
  1192. switch (incomingRequest.peerRequestType)
  1193. {
  1194. case PeerRequest::PEERREQUEST_LOGIN:
  1195. {
  1196. m_isConnecting = true;
  1197. m_originalName = incomingRequest.nick;
  1198. m_loginName = incomingRequest.nick;
  1199. m_profileID = incomingRequest.login.profileID;
  1200. m_password = incomingRequest.password;
  1201. m_email = incomingRequest.email;
  1202. peerConnect( peer, incomingRequest.nick.c_str(), incomingRequest.login.profileID, nickErrorCallbackWrapper, connectCallbackWrapper, this, PEERTrue );
  1203. #ifdef SERVER_DEBUGGING
  1204. DEBUG_LOG(("After peerConnect()\n"));
  1205. CheckServers(peer);
  1206. #endif // SERVER_DEBUGGING
  1207. if (m_isConnected)
  1208. {
  1209. SerialAuthResult ret = doCDKeyAuthentication( peer );
  1210. if (ret != SERIAL_OK)
  1211. {
  1212. m_isConnecting = m_isConnected = false;
  1213. MESSAGE_QUEUE->setSerialAuthResult( ret );
  1214. peerDisconnect( peer );
  1215. }
  1216. }
  1217. m_isConnecting = false;
  1218. // check our connection
  1219. //if (m_isConnected)
  1220. //{
  1221. // GetLocalChatConnectionAddress("peerchat.gamespy.com", 6667, localIP);
  1222. //}
  1223. }
  1224. break;
  1225. case PeerRequest::PEERREQUEST_LOGOUT:
  1226. m_isConnecting = m_isConnected = false;
  1227. peerDisconnect( peer );
  1228. break;
  1229. case PeerRequest::PEERREQUEST_JOINGROUPROOM:
  1230. m_groupRoomID = incomingRequest.groupRoom.id;
  1231. isThreadHosting = 0; // debugging
  1232. s_lastStateChangedHeartbeat = 0;
  1233. s_wantStateChangedHeartbeat = FALSE;
  1234. peerStopGame( peer );
  1235. peerLeaveRoom( peer, GroupRoom, NULL );
  1236. peerLeaveRoom( peer, StagingRoom, NULL );
  1237. if (qr2Sock != INVALID_SOCKET)
  1238. {
  1239. closesocket(qr2Sock);
  1240. qr2Sock = INVALID_SOCKET;
  1241. }
  1242. m_isHosting = false;
  1243. m_localRoomID = m_groupRoomID;
  1244. DEBUG_LOG(("Requesting to join room %d in thread %X\n", m_localRoomID, this));
  1245. peerJoinGroupRoom( peer, incomingRequest.groupRoom.id, joinRoomCallback, (void *)this, PEERTrue );
  1246. break;
  1247. case PeerRequest::PEERREQUEST_LEAVEGROUPROOM:
  1248. m_groupRoomID = 0;
  1249. updateBuddyStatus( BUDDY_ONLINE );
  1250. peerLeaveRoom( peer, GroupRoom, NULL );
  1251. peerLeaveRoom( peer, StagingRoom, NULL ); m_isHosting = false;
  1252. break;
  1253. case PeerRequest::PEERREQUEST_JOINSTAGINGROOM:
  1254. {
  1255. m_groupRoomID = 0;
  1256. updateBuddyStatus( BUDDY_ONLINE );
  1257. peerLeaveRoom( peer, GroupRoom, NULL );
  1258. peerLeaveRoom( peer, StagingRoom, NULL ); m_isHosting = false;
  1259. SBServer server = findServerByID(incomingRequest.stagingRoom.id);
  1260. m_localStagingServerName = incomingRequest.text;
  1261. DEBUG_LOG(("Setting m_localStagingServerName to [%ls]\n", m_localStagingServerName.c_str()));
  1262. m_localRoomID = incomingRequest.stagingRoom.id;
  1263. DEBUG_LOG(("Requesting to join room %d\n", m_localRoomID));
  1264. if (server)
  1265. {
  1266. peerJoinStagingRoom( peer, server, incomingRequest.password.c_str(), joinRoomCallback, (void *)this, PEERTrue );
  1267. }
  1268. else
  1269. {
  1270. PeerResponse resp;
  1271. resp.peerResponseType = PeerResponse::PEERRESPONSE_JOINSTAGINGROOM;
  1272. resp.joinStagingRoom.id = incomingRequest.stagingRoom.id;
  1273. resp.joinStagingRoom.ok = FALSE;
  1274. resp.joinStagingRoom.result = PEERJoinFailed;
  1275. TheGameSpyPeerMessageQueue->addResponse(resp);
  1276. }
  1277. }
  1278. break;
  1279. case PeerRequest::PEERREQUEST_LEAVESTAGINGROOM:
  1280. m_groupRoomID = 0;
  1281. updateBuddyStatus( BUDDY_ONLINE );
  1282. peerLeaveRoom( peer, GroupRoom, NULL );
  1283. peerLeaveRoom( peer, StagingRoom, NULL );
  1284. isThreadHosting = 0; // debugging
  1285. s_lastStateChangedHeartbeat = 0;
  1286. s_wantStateChangedHeartbeat = FALSE;
  1287. if (m_isHosting)
  1288. {
  1289. peerStopGame( peer );
  1290. if (qr2Sock != INVALID_SOCKET)
  1291. {
  1292. closesocket(qr2Sock);
  1293. qr2Sock = INVALID_SOCKET;
  1294. }
  1295. m_isHosting = false;
  1296. }
  1297. break;
  1298. case PeerRequest::PEERREQUEST_MESSAGEPLAYER:
  1299. {
  1300. std::string s = WideCharStringToMultiByte(incomingRequest.text.c_str());
  1301. peerMessagePlayer( peer, incomingRequest.nick.c_str(), s.c_str(), (incomingRequest.message.isAction)?ActionMessage:NormalMessage );
  1302. }
  1303. break;
  1304. case PeerRequest::PEERREQUEST_MESSAGEROOM:
  1305. {
  1306. std::string s = WideCharStringToMultiByte(incomingRequest.text.c_str());
  1307. peerMessageRoom( peer, (m_groupRoomID)?GroupRoom:StagingRoom, s.c_str(), (incomingRequest.message.isAction)?ActionMessage:NormalMessage );
  1308. }
  1309. break;
  1310. case PeerRequest::PEERREQUEST_PUSHSTATS:
  1311. {
  1312. DEBUG_LOG(("PEERREQUEST_PUSHSTATS: stats are %d,%d,%d,%d,%d,%d\n",
  1313. incomingRequest.statsToPush.locale, incomingRequest.statsToPush.wins, incomingRequest.statsToPush.losses, incomingRequest.statsToPush.rankPoints, incomingRequest.statsToPush.side, incomingRequest.statsToPush.preorder));
  1314. // Testing alternate way to push stats
  1315. #ifdef USE_BROADCAST_KEYS
  1316. _snprintf(s_valueBuffers[0], 20, "%d", incomingRequest.statsToPush.locale);
  1317. _snprintf(s_valueBuffers[1], 20, "%d", incomingRequest.statsToPush.wins);
  1318. _snprintf(s_valueBuffers[2], 20, "%d", incomingRequest.statsToPush.losses);
  1319. _snprintf(s_valueBuffers[3], 20, "%d", incomingRequest.statsToPush.rankPoints);
  1320. _snprintf(s_valueBuffers[4], 20, "%d", incomingRequest.statsToPush.side);
  1321. _snprintf(s_valueBuffers[5], 20, "%d", incomingRequest.statsToPush.preorder);
  1322. pushStatsToRoom(peer);
  1323. #else
  1324. const char *keys[6] = { "locale", "wins", "losses", "points", "side", "pre" };
  1325. char valueStrings[6][20];
  1326. char *values[6] = { valueStrings[0], valueStrings[1], valueStrings[2],
  1327. valueStrings[3], valueStrings[4], valueStrings[5]};
  1328. _snprintf(values[0], 20, "%d", incomingRequest.statsToPush.locale);
  1329. _snprintf(values[1], 20, "%d", incomingRequest.statsToPush.wins);
  1330. _snprintf(values[2], 20, "%d", incomingRequest.statsToPush.losses);
  1331. _snprintf(values[3], 20, "%d", incomingRequest.statsToPush.rankPoints);
  1332. _snprintf(values[4], 20, "%d", incomingRequest.statsToPush.side);
  1333. _snprintf(values[5], 20, "%d", incomingRequest.statsToPush.preorder);
  1334. peerSetGlobalKeys(peer, 6, (const char **)keys, (const char **)values);
  1335. peerSetGlobalWatchKeys(peer, GroupRoom, 0, NULL, PEERFalse);
  1336. peerSetGlobalWatchKeys(peer, StagingRoom, 0, NULL, PEERFalse);
  1337. peerSetGlobalWatchKeys(peer, GroupRoom, 6, keys, PEERTrue);
  1338. peerSetGlobalWatchKeys(peer, StagingRoom, 6, keys, PEERTrue);
  1339. #endif
  1340. }
  1341. break;
  1342. case PeerRequest::PEERREQUEST_SETGAMEOPTIONS:
  1343. {
  1344. m_mapName = incomingRequest.gameOptsMapName;
  1345. m_numPlayers = incomingRequest.gameOptions.numPlayers;
  1346. m_numObservers = incomingRequest.gameOptions.numObservers;
  1347. m_maxPlayers = incomingRequest.gameOptions.maxPlayers;
  1348. DEBUG_LOG(("peerStateChanged(): Marking game options state as changed - %d players, %d observers\n", m_numPlayers, m_numObservers));
  1349. for (Int i=0; i<MAX_SLOTS; ++i)
  1350. {
  1351. m_playerNames[i] = incomingRequest.gameOptsPlayerNames[i];
  1352. m_playerWins[i] = incomingRequest.gameOptions.wins[i];
  1353. m_playerLosses[i] = incomingRequest.gameOptions.losses[i];
  1354. m_playerProfileID[i] = incomingRequest.gameOptions.profileID[i];
  1355. m_playerFactions[i] = incomingRequest.gameOptions.faction[i];
  1356. m_playerColors[i] = incomingRequest.gameOptions.color[i];
  1357. }
  1358. s_wantStateChangedHeartbeat = TRUE;
  1359. /*
  1360. peerStateChanged( peer );
  1361. #ifdef DEBUG_LOGGING
  1362. static UnsignedInt prev = 0;
  1363. UnsignedInt now = timeGetTime();
  1364. UnsignedInt diff = now - prev;
  1365. prev = now;
  1366. #endif
  1367. STATECHANGED_LOG(("peerStateChanged() at time %d (difference of %d ms)\n", now, diff));
  1368. */
  1369. peerUTMRoom( peer, StagingRoom, "SL/", incomingRequest.options.c_str(), PEERFalse ); // send the full string to people in the room
  1370. }
  1371. break;
  1372. case PeerRequest::PEERREQUEST_GETEXTENDEDSTAGINGROOMINFO:
  1373. {
  1374. SBServer server = findServerByID( incomingRequest.stagingRoom.id );
  1375. if (server)
  1376. {
  1377. DEBUG_LOG(("Requesting full update on a game\n"));
  1378. peerUpdateGame( peer, server, PEERTrue );
  1379. }
  1380. else
  1381. {
  1382. DEBUG_LOG(("Tried to update non-existent server!\n"));
  1383. }
  1384. }
  1385. break;
  1386. case PeerRequest::PEERREQUEST_CREATESTAGINGROOM:
  1387. {
  1388. Int oldGroupID = m_groupRoomID;
  1389. m_groupRoomID = 0;
  1390. updateBuddyStatus( BUDDY_ONLINE );
  1391. if (!incomingRequest.stagingRoomCreation.restrictGameList)
  1392. {
  1393. peerLeaveRoom( peer, GroupRoom, NULL );
  1394. peerLeaveRoom( peer, StagingRoom, NULL );
  1395. }
  1396. m_isHosting = TRUE;
  1397. Int res = PEERJoinFailed;
  1398. if (qr2Sock == INVALID_SOCKET)
  1399. {
  1400. // allocate a port
  1401. if (preferredQRPort < 1024)
  1402. {
  1403. preferredQRPort = 6500 + (ntohl(localIP) & 0xff);
  1404. }
  1405. DEBUG_LOG(("Using %8.8X:%d for QR2\n", ntohl(localIP), preferredQRPort));
  1406. }
  1407. else
  1408. {
  1409. closesocket(qr2Sock);
  1410. qr2Sock = INVALID_SOCKET;
  1411. }
  1412. qr2Sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  1413. struct sockaddr_in saddr;
  1414. saddr.sin_port=htons(preferredQRPort);
  1415. saddr.sin_addr.s_addr=localIP;
  1416. saddr.sin_family=AF_INET;
  1417. if (bind(qr2Sock, (sockaddr *)&saddr, sizeof(saddr)) != 0)
  1418. {
  1419. DEBUG_LOG(("Could not bind to %d! Falling back to GameSpy's default port\n", preferredQRPort));
  1420. closesocket(qr2Sock);
  1421. qr2Sock = INVALID_SOCKET;
  1422. preferredQRPort = 0;
  1423. }
  1424. std::string compositeGame = m_loginName;
  1425. compositeGame.append(" ");
  1426. compositeGame.append(WideCharStringToMultiByte(incomingRequest.text.c_str()));
  1427. m_localStagingServerName = incomingRequest.text;
  1428. m_playerNames[0] = m_loginName;
  1429. peerCreateStagingRoomWithSocket(peer, compositeGame.c_str(), MAX_SLOTS, incomingRequest.password.c_str(), qr2Sock, preferredQRPort, createRoomCallback, (void *)&res, PEERTrue);
  1430. //peerCreateStagingRoomWithSocket(peer, WideCharStringToMultiByte(incomingRequest.text.c_str()).c_str(), MAX_SLOTS, incomingRequest.password.c_str(), qr2Sock, preferredQRPort, createRoomCallback, (void *)&res, PEERTrue);
  1431. DEBUG_LOG(("PEERREQUEST_CREATESTAGINGROOM - creating staging room, name is %ls, passwd is %s, result = %d\n",
  1432. incomingRequest.text.c_str(), incomingRequest.password.c_str(), res));
  1433. PeerResponse resp;
  1434. resp.peerResponseType = PeerResponse::PEERRESPONSE_CREATESTAGINGROOM;
  1435. resp.createStagingRoom.result = res;
  1436. TheGameSpyPeerMessageQueue->addResponse(resp);
  1437. if (res != PEERJoinSuccess && res != PEERAlreadyInRoom)
  1438. {
  1439. m_localRoomID = oldGroupID;
  1440. DEBUG_LOG(("Requesting to join room %d\n", m_localRoomID));
  1441. if (incomingRequest.stagingRoomCreation.restrictGameList)
  1442. {
  1443. peerLeaveRoom( peer, StagingRoom, NULL );
  1444. }
  1445. else
  1446. {
  1447. peerJoinGroupRoom( peer, oldGroupID, joinRoomCallback, (void *)this, PEERTrue );
  1448. }
  1449. m_isHosting = FALSE;
  1450. m_localStagingServerName = L"";
  1451. m_playerNames[0] = "";
  1452. }
  1453. else
  1454. {
  1455. if (incomingRequest.stagingRoomCreation.restrictGameList)
  1456. {
  1457. peerLeaveRoom( peer, GroupRoom, NULL );
  1458. }
  1459. isThreadHosting = 1; // debugging
  1460. s_lastStateChangedHeartbeat = timeGetTime(); // wait the full interval before updating state
  1461. s_wantStateChangedHeartbeat = FALSE;
  1462. m_isHosting = TRUE;
  1463. m_allowObservers = incomingRequest.stagingRoomCreation.allowObservers;
  1464. m_mapName = "";
  1465. for (Int i=0; i<MAX_SLOTS; ++i)
  1466. {
  1467. m_playerNames[i] = "";
  1468. m_playerWins[i] = 0;
  1469. m_playerLosses[i] = 0;
  1470. m_playerProfileID[i] = 0;
  1471. m_playerFactions[i] = 0;
  1472. m_playerColors[i] = 0;
  1473. }
  1474. if (incomingRequest.password.length() > 0)
  1475. m_hasPassword = true;
  1476. else
  1477. m_hasPassword = false;
  1478. m_playerNames[0] = m_loginName;
  1479. m_exeCRC = incomingRequest.stagingRoomCreation.exeCRC;
  1480. m_iniCRC = incomingRequest.stagingRoomCreation.iniCRC;
  1481. m_gameVersion = incomingRequest.stagingRoomCreation.gameVersion;
  1482. m_localStagingServerName = incomingRequest.text;
  1483. m_ladderIP = incomingRequest.ladderIP;
  1484. m_pingStr = incomingRequest.hostPingStr;
  1485. m_ladderPort = incomingRequest.stagingRoomCreation.ladPort;
  1486. #ifdef USE_BROADCAST_KEYS
  1487. pushStatsToRoom(peer);
  1488. #endif // USE_BROADCAST_KEYS
  1489. DEBUG_LOG(("Setting m_localStagingServerName to [%ls]\n", m_localStagingServerName.c_str()));
  1490. updateBuddyStatus( BUDDY_STAGING, 0, WideCharStringToMultiByte(m_localStagingServerName.c_str()) );
  1491. }
  1492. }
  1493. break;
  1494. case PeerRequest::PEERREQUEST_STARTGAMELIST:
  1495. {
  1496. m_sawCompleteGameList = FALSE;
  1497. PeerResponse resp;
  1498. resp.peerResponseType = PeerResponse::PEERRESPONSE_STAGINGROOM;
  1499. resp.stagingRoom.action = PEER_CLEAR;
  1500. resp.stagingRoom.isStaging = TRUE;
  1501. resp.stagingRoom.percentComplete = 0;
  1502. clearServers();
  1503. TheGameSpyPeerMessageQueue->addResponse(resp);
  1504. peerStartListingGames( peer, allKeysArray, NumKeys, (incomingRequest.gameList.restrictGameList?"~":NULL), listingGamesCallback, this );
  1505. }
  1506. break;
  1507. case PeerRequest::PEERREQUEST_STOPGAMELIST:
  1508. {
  1509. peerStopListingGames( peer );
  1510. }
  1511. break;
  1512. case PeerRequest::PEERREQUEST_STARTGAME:
  1513. {
  1514. peerStartGame( peer, NULL, PEER_STOP_REPORTING);
  1515. }
  1516. break;
  1517. case PeerRequest::PEERREQUEST_UTMPLAYER:
  1518. {
  1519. if (incomingRequest.nick.length() > 0)
  1520. {
  1521. peerUTMPlayer( peer, incomingRequest.nick.c_str(), incomingRequest.id.c_str(), incomingRequest.options.c_str(), PEERFalse );
  1522. }
  1523. }
  1524. break;
  1525. case PeerRequest::PEERREQUEST_UTMROOM:
  1526. {
  1527. peerUTMRoom( peer, (incomingRequest.UTM.isStagingRoom)?StagingRoom:GroupRoom, incomingRequest.id.c_str(), incomingRequest.options.c_str(), PEERFalse );
  1528. }
  1529. break;
  1530. case PeerRequest::PEERREQUEST_STARTQUICKMATCH:
  1531. {
  1532. m_qmInfo = incomingRequest;
  1533. doQuickMatch( peer );
  1534. }
  1535. break;
  1536. }
  1537. }
  1538. if (isThreadHosting && s_wantStateChangedHeartbeat)
  1539. {
  1540. UnsignedInt now = timeGetTime();
  1541. if (now > s_lastStateChangedHeartbeat + s_heartbeatInterval)
  1542. {
  1543. s_lastStateChangedHeartbeat = now;
  1544. s_wantStateChangedHeartbeat = FALSE;
  1545. peerStateChanged( peer );
  1546. #ifdef DEBUG_LOGGING
  1547. static UnsignedInt prev = 0;
  1548. UnsignedInt now = timeGetTime();
  1549. UnsignedInt diff = now - prev;
  1550. prev = now;
  1551. #endif
  1552. STATECHANGED_LOG(("peerStateChanged() at time %d (difference of %d ms)\n", now, diff));
  1553. }
  1554. }
  1555. // update the network
  1556. PEERBool isConnected = PEERTrue;
  1557. isConnected = peerIsConnected( peer );
  1558. if ( isConnected == PEERTrue )
  1559. {
  1560. if (qr2Sock != INVALID_SOCKET)
  1561. {
  1562. // check hosting activity
  1563. checkQR2Queries( peer, qr2Sock );
  1564. }
  1565. peerThink( peer );
  1566. }
  1567. // end our timeslice
  1568. Switch_Thread();
  1569. }
  1570. DEBUG_LOG(("voluntarily ending peer thread %d\n", running));
  1571. peerShutdown( peer );
  1572. } catch ( ... ) {
  1573. DEBUG_CRASH(("Exception in peer thread!"));
  1574. try {
  1575. PeerResponse resp;
  1576. resp.peerResponseType = PeerResponse::PEERRESPONSE_DISCONNECT;
  1577. resp.discon.reason = DISCONNECT_LOSTCON;
  1578. TheGameSpyPeerMessageQueue->addResponse(resp);
  1579. }
  1580. catch (...)
  1581. {
  1582. }
  1583. }
  1584. }
  1585. static void qmProfileIDCallback( PEER peer, PEERBool success, const char *nick, int profileID, void *param )
  1586. {
  1587. Int *i = (Int *)param;
  1588. if (!i || !success || !nick)
  1589. return;
  1590. *i = profileID;
  1591. }
  1592. static Int matchbotProfileID = 0;
  1593. void quickmatchEnumPlayersCallback( PEER peer, PEERBool success, RoomType roomType, int index, const char * nick, int flags, void * param )
  1594. {
  1595. PeerThreadClass *t = (PeerThreadClass *)param;
  1596. if (!t || !success || nick == NULL || nick[0] == '\0')
  1597. {
  1598. t->sawEndOfEnumPlayers();
  1599. return;
  1600. }
  1601. Int id = 0;
  1602. peerGetPlayerProfileID(peer, nick, qmProfileIDCallback, &id, PEERTrue);
  1603. DEBUG_LOG(("Saw player %s with id %d (looking for %d)\n", nick, id, matchbotProfileID));
  1604. if (id == matchbotProfileID)
  1605. {
  1606. t->sawMatchbot(nick);
  1607. }
  1608. PeerResponse resp;
  1609. resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERJOIN;
  1610. resp.nick = nick;
  1611. resp.player.roomType = roomType;
  1612. resp.player.IP = 0;
  1613. TheGameSpyPeerMessageQueue->addResponse(resp);
  1614. }
  1615. void PeerThreadClass::handleQMMatch(PEER peer, Int mapIndex, Int seed,
  1616. char *playerName[MAX_SLOTS],
  1617. char *playerIP[MAX_SLOTS],
  1618. char *playerSide[MAX_SLOTS],
  1619. char *playerColor[MAX_SLOTS],
  1620. char *playerNAT[MAX_SLOTS])
  1621. {
  1622. if (m_qmStatus == QM_WORKING)
  1623. {
  1624. m_qmStatus = QM_MATCHED;
  1625. peerLeaveRoom(peer, GroupRoom, "");
  1626. for (Int i=0; i<MAX_SLOTS; ++i)
  1627. {
  1628. if (playerName[i] && stricmp(playerName[i], m_loginName.c_str()))
  1629. {
  1630. peerMessagePlayer( peer, playerName[i], "We're matched!", NormalMessage );
  1631. }
  1632. }
  1633. PeerResponse resp;
  1634. resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS;
  1635. resp.qmStatus.status = QM_MATCHED;
  1636. for (i=0; i<MAX_SLOTS; ++i)
  1637. {
  1638. if (playerName[i])
  1639. {
  1640. resp.stagingRoomPlayerNames[i] = playerName[i];
  1641. resp.qmStatus.IP[i] = atoi(playerIP[i]);
  1642. resp.qmStatus.side[i] = atoi(playerSide[i]);
  1643. resp.qmStatus.color[i] = atoi(playerColor[i]);
  1644. resp.qmStatus.nat[i] = atoi(playerNAT[i]);
  1645. }
  1646. else
  1647. {
  1648. resp.stagingRoomPlayerNames[i] = "";
  1649. resp.qmStatus.IP[i] = 0;
  1650. resp.qmStatus.side[i] = 0;
  1651. resp.qmStatus.color[i] = 0;
  1652. resp.qmStatus.nat[i] = 0;
  1653. }
  1654. }
  1655. resp.qmStatus.seed = seed;
  1656. resp.qmStatus.mapIdx = mapIndex;
  1657. TheGameSpyPeerMessageQueue->addResponse(resp);
  1658. }
  1659. }
  1660. void PeerThreadClass::doQuickMatch( PEER peer )
  1661. {
  1662. m_qmStatus = QM_JOININGQMCHANNEL;
  1663. Bool done = false;
  1664. matchbotProfileID = m_qmInfo.QM.botID;
  1665. setQMGroupRoom( m_qmInfo.QM.roomID );
  1666. m_sawMatchbot = false;
  1667. updateBuddyStatus( BUDDY_MATCHING );
  1668. while (!done && running)
  1669. {
  1670. if (!peerIsConnected( peer ))
  1671. {
  1672. done = true;
  1673. }
  1674. else
  1675. {
  1676. // update the network
  1677. peerThink( peer );
  1678. // end our timeslice
  1679. Switch_Thread();
  1680. PeerRequest incomingRequest;
  1681. if (TheGameSpyPeerMessageQueue->getRequest(incomingRequest))
  1682. {
  1683. switch (incomingRequest.peerRequestType)
  1684. {
  1685. case PeerRequest::PEERREQUEST_WIDENQUICKMATCHSEARCH:
  1686. {
  1687. if (m_qmStatus != QM_IDLE && m_qmStatus != QM_STOPPED && m_sawMatchbot)
  1688. {
  1689. peerMessagePlayer( peer, m_matchbotName.c_str(), "\\WIDEN", NormalMessage );
  1690. }
  1691. }
  1692. break;
  1693. case PeerRequest::PEERREQUEST_STOPQUICKMATCH:
  1694. {
  1695. m_qmStatus = QM_STOPPED;
  1696. peerLeaveRoom(peer, GroupRoom, "");
  1697. done = true;
  1698. }
  1699. break;
  1700. case PeerRequest::PEERREQUEST_LOGOUT:
  1701. {
  1702. m_qmStatus = QM_STOPPED;
  1703. peerLeaveRoom(peer, GroupRoom, "");
  1704. done = true;
  1705. }
  1706. break;
  1707. case PeerRequest::PEERREQUEST_LEAVEGROUPROOM:
  1708. {
  1709. m_qmStatus = QM_STOPPED;
  1710. peerLeaveRoom(peer, GroupRoom, "");
  1711. done = true;
  1712. }
  1713. break;
  1714. case PeerRequest::PEERREQUEST_UTMPLAYER:
  1715. {
  1716. peerUTMPlayer( peer, incomingRequest.nick.c_str(), incomingRequest.id.c_str(), incomingRequest.options.c_str(), PEERFalse );
  1717. }
  1718. break;
  1719. default:
  1720. {
  1721. DEBUG_CRASH(("Unanticipated request %d to peer thread!", incomingRequest.peerRequestType));
  1722. }
  1723. break;
  1724. }
  1725. }
  1726. if (!done)
  1727. {
  1728. // do the next bit of QM
  1729. switch (m_qmStatus)
  1730. {
  1731. case QM_JOININGQMCHANNEL:
  1732. {
  1733. PeerResponse resp;
  1734. resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS;
  1735. resp.qmStatus.status = QM_JOININGQMCHANNEL;
  1736. TheGameSpyPeerMessageQueue->addResponse(resp);
  1737. m_groupRoomID = m_qmGroupRoom;
  1738. peerLeaveRoom( peer, GroupRoom, NULL );
  1739. peerLeaveRoom( peer, StagingRoom, NULL ); m_isHosting = false;
  1740. m_localRoomID = m_groupRoomID;
  1741. m_roomJoined = false;
  1742. DEBUG_LOG(("Requesting to join room %d in thread %X\n", m_localRoomID, this));
  1743. peerJoinGroupRoom( peer, m_localRoomID, joinRoomCallback, (void *)this, PEERTrue );
  1744. if (m_roomJoined)
  1745. {
  1746. resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS;
  1747. resp.qmStatus.status = QM_LOOKINGFORBOT;
  1748. TheGameSpyPeerMessageQueue->addResponse(resp);
  1749. m_qmStatus = QM_LOOKINGFORBOT;
  1750. m_sawMatchbot = false;
  1751. m_sawEndOfEnumPlayers = false;
  1752. peerEnumPlayers( peer, GroupRoom, quickmatchEnumPlayersCallback, this );
  1753. }
  1754. else
  1755. {
  1756. resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS;
  1757. resp.qmStatus.status = QM_COULDNOTFINDBOT;
  1758. TheGameSpyPeerMessageQueue->addResponse(resp);
  1759. done = true;
  1760. m_qmStatus = QM_STOPPED;
  1761. }
  1762. }
  1763. break;
  1764. case QM_LOOKINGFORBOT:
  1765. {
  1766. if (m_sawEndOfEnumPlayers)
  1767. {
  1768. if (m_sawMatchbot)
  1769. {
  1770. char buf[64];
  1771. buf[63] = '\0';
  1772. std::string msg = "\\CINFO";
  1773. _snprintf(buf, 63, "\\Widen\\%d", m_qmInfo.QM.widenTime);
  1774. msg.append(buf);
  1775. _snprintf(buf, 63, "\\LadID\\%d", m_qmInfo.QM.ladderID);
  1776. msg.append(buf);
  1777. _snprintf(buf, 63, "\\LadPass\\%d", m_qmInfo.QM.ladderPassCRC);
  1778. msg.append(buf);
  1779. _snprintf(buf, 63, "\\PointsMin\\%d", m_qmInfo.QM.minPointPercentage);
  1780. msg.append(buf);
  1781. _snprintf(buf, 63, "\\PointsMax\\%d", m_qmInfo.QM.maxPointPercentage);
  1782. msg.append(buf);
  1783. _snprintf(buf, 63, "\\Points\\%d", m_qmInfo.QM.points);
  1784. msg.append(buf);
  1785. _snprintf(buf, 63, "\\Discons\\%d", m_qmInfo.QM.discons);
  1786. msg.append(buf);
  1787. _snprintf(buf, 63, "\\DisconMax\\%d", m_qmInfo.QM.maxDiscons);
  1788. msg.append(buf);
  1789. _snprintf(buf, 63, "\\NumPlayers\\%d", m_qmInfo.QM.numPlayers);
  1790. msg.append(buf);
  1791. _snprintf(buf, 63, "\\Pings\\%s", m_qmInfo.QM.pings);
  1792. msg.append(buf);
  1793. _snprintf(buf, 63, "\\IP\\%d", ntohl(peerGetLocalIP(peer)));// not ntohl(localIP), as we need EXTERNAL address for proper NAT negotiation!
  1794. msg.append(buf);
  1795. _snprintf(buf, 63, "\\Side\\%d", m_qmInfo.QM.side);
  1796. msg.append(buf);
  1797. _snprintf(buf, 63, "\\Color\\%d", m_qmInfo.QM.color);
  1798. msg.append(buf);
  1799. _snprintf(buf, 63, "\\NAT\\%d", m_qmInfo.QM.NAT);
  1800. msg.append(buf);
  1801. _snprintf(buf, 63, "\\EXE\\%d", m_qmInfo.QM.exeCRC);
  1802. msg.append(buf);
  1803. _snprintf(buf, 63, "\\INI\\%d", m_qmInfo.QM.iniCRC);
  1804. msg.append(buf);
  1805. buf[0] = 0;
  1806. msg.append("\\Maps\\");
  1807. for (Int i=0; i<m_qmInfo.qmMaps.size(); ++i)
  1808. {
  1809. if (m_qmInfo.qmMaps[i])
  1810. msg.append("1");
  1811. else
  1812. msg.append("0");
  1813. }
  1814. DEBUG_LOG(("Sending QM options of [%s] to %s\n", msg.c_str(), m_matchbotName.c_str()));
  1815. peerMessagePlayer( peer, m_matchbotName.c_str(), msg.c_str(), NormalMessage );
  1816. m_qmStatus = QM_WORKING;
  1817. PeerResponse resp;
  1818. resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS;
  1819. resp.qmStatus.status = QM_SENTINFO;
  1820. TheGameSpyPeerMessageQueue->addResponse(resp);
  1821. }
  1822. else
  1823. {
  1824. // no QM bot. Bail.
  1825. PeerResponse resp;
  1826. resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS;
  1827. resp.qmStatus.status = QM_COULDNOTFINDBOT;
  1828. TheGameSpyPeerMessageQueue->addResponse(resp);
  1829. m_qmStatus = QM_STOPPED;
  1830. peerLeaveRoom(peer, GroupRoom, "");
  1831. done = true;
  1832. }
  1833. }
  1834. }
  1835. break;
  1836. case QM_WORKING:
  1837. {
  1838. }
  1839. break;
  1840. case QM_MATCHED:
  1841. {
  1842. // leave QM channel, and clean up. Our work here is done.
  1843. peerLeaveRoom( peer, GroupRoom, NULL );
  1844. peerLeaveRoom( peer, StagingRoom, NULL ); m_isHosting = false;
  1845. m_qmStatus = QM_STOPPED;
  1846. peerLeaveRoom(peer, GroupRoom, "");
  1847. done = true;
  1848. }
  1849. break;
  1850. case QM_INCHANNEL:
  1851. {
  1852. }
  1853. break;
  1854. case QM_NEGOTIATINGFIREWALLS:
  1855. {
  1856. }
  1857. break;
  1858. case QM_STARTINGGAME:
  1859. {
  1860. }
  1861. break;
  1862. case QM_COULDNOTFINDCHANNEL:
  1863. {
  1864. }
  1865. break;
  1866. case QM_COULDNOTNEGOTIATEFIREWALLS:
  1867. {
  1868. }
  1869. break;
  1870. }
  1871. }
  1872. }
  1873. }
  1874. updateBuddyStatus( BUDDY_ONLINE );
  1875. }
  1876. static void getPlayerProfileIDCallback(PEER peer, PEERBool success, const char * nick, int profileID, void * param)
  1877. {
  1878. if (success && param != NULL)
  1879. {
  1880. *((Int *)param) = profileID;
  1881. }
  1882. }
  1883. static void stagingRoomPlayerEnum( PEER peer, PEERBool success, RoomType roomType, int index, const char * nick, int flags, void * param )
  1884. {
  1885. DEBUG_LOG(("Enum: success=%d, index=%d, nick=%s, flags=%d\n", success, index, nick, flags));
  1886. if (!nick || !success)
  1887. return;
  1888. Int id = 0;
  1889. peerGetPlayerProfileID(peer, nick, getPlayerProfileIDCallback, &id, PEERTrue);
  1890. DEBUG_ASSERTCRASH(id != 0, ("Failed to fetch player ID!"));
  1891. PeerResponse *resp = (PeerResponse *)param;
  1892. if (flags & PEER_FLAG_OP)
  1893. {
  1894. resp->joinStagingRoom.isHostPresent = TRUE;
  1895. }
  1896. if (index < MAX_SLOTS)
  1897. {
  1898. resp->stagingRoomPlayerNames[index] = nick;
  1899. }
  1900. if (id)
  1901. {
  1902. PSRequest req;
  1903. req.requestType = PSRequest::PSREQUEST_READPLAYERSTATS;
  1904. req.player.id = id;
  1905. TheGameSpyPSMessageQueue->addRequest(req);
  1906. }
  1907. }
  1908. static void joinRoomCallback(PEER peer, PEERBool success, PEERJoinResult result, RoomType roomType, void *param)
  1909. {
  1910. DEBUG_LOG(("JoinRoomCallback: success==%d, result==%d\n", success, result));
  1911. PeerThreadClass *t = (PeerThreadClass *)param;
  1912. if (!t)
  1913. return;
  1914. DEBUG_LOG(("Room id was %d from thread %X\n", t->getLocalRoomID(), t));
  1915. DEBUG_LOG(("Current staging server name is [%ls]\n", t->getLocalStagingServerName().c_str()));
  1916. DEBUG_LOG(("Room type is %d (GroupRoom=%d, StagingRoom=%d, TitleRoom=%d)\n", roomType, GroupRoom, StagingRoom, TitleRoom));
  1917. #ifdef USE_BROADCAST_KEYS
  1918. if (success)
  1919. {
  1920. t->pushStatsToRoom(peer);
  1921. t->getStatsFromRoom(peer, roomType);
  1922. }
  1923. #endif // USE_BROADCAST_KEYS
  1924. switch (roomType)
  1925. {
  1926. case GroupRoom:
  1927. {
  1928. #ifdef USE_BROADCAST_KEYS
  1929. t->clearPlayerStats(GroupRoom);
  1930. #endif // USE_BROADCAST_KEYS
  1931. PeerResponse resp;
  1932. resp.peerResponseType = PeerResponse::PEERRESPONSE_JOINGROUPROOM;
  1933. resp.joinGroupRoom.id = t->getLocalRoomID();
  1934. resp.joinGroupRoom.ok = success;
  1935. TheGameSpyPeerMessageQueue->addResponse(resp);
  1936. t->roomJoined(success == PEERTrue);
  1937. DEBUG_LOG(("Entered group room %d, qm is %d\n", t->getLocalRoomID(), t->getQMGroupRoom()));
  1938. if ((!t->getQMGroupRoom()) || (t->getQMGroupRoom() != t->getLocalRoomID()))
  1939. {
  1940. DEBUG_LOG(("Updating buddy status\n"));
  1941. updateBuddyStatus( BUDDY_LOBBY, t->getLocalRoomID() );
  1942. }
  1943. }
  1944. break;
  1945. case StagingRoom:
  1946. {
  1947. #ifdef USE_BROADCAST_KEYS
  1948. t->clearPlayerStats(StagingRoom);
  1949. #endif // USE_BROADCAST_KEYS
  1950. PeerResponse resp;
  1951. resp.peerResponseType = PeerResponse::PEERRESPONSE_JOINSTAGINGROOM;
  1952. resp.joinStagingRoom.id = t->getLocalRoomID();
  1953. resp.joinStagingRoom.ok = success;
  1954. resp.joinStagingRoom.result = result;
  1955. if (success)
  1956. {
  1957. DEBUG_LOG(("joinRoomCallback() - game name is now '%ls'\n", t->getLocalStagingServerName().c_str()));
  1958. updateBuddyStatus( BUDDY_STAGING, 0, WideCharStringToMultiByte(t->getLocalStagingServerName().c_str()) );
  1959. }
  1960. resp.joinStagingRoom.isHostPresent = FALSE;
  1961. DEBUG_LOG(("Enum of staging room players\n"));
  1962. peerEnumPlayers(peer, StagingRoom, stagingRoomPlayerEnum, &resp);
  1963. DEBUG_LOG(("Host %s present\n", (resp.joinStagingRoom.isHostPresent)?"is":"is not"));
  1964. TheGameSpyPeerMessageQueue->addResponse(resp);
  1965. }
  1966. break;
  1967. }
  1968. }
  1969. // Gets called once for each group room when listing group rooms.
  1970. // After this has been called for each group room, it will be
  1971. // called one more time with groupID==0 and name==NULL.
  1972. /////////////////////////////////////////////////////////////////
  1973. static void listGroupRoomsCallback(PEER peer, PEERBool success,
  1974. int groupID, SBServer server,
  1975. const char * name, int numWaiting,
  1976. int maxWaiting, int numGames,
  1977. int numPlaying, void * param)
  1978. {
  1979. DEBUG_LOG(("listGroupRoomsCallback, success=%d, server=%X, groupID=%d\n", success, server, groupID));
  1980. #ifdef SERVER_DEBUGGING
  1981. CheckServers(peer);
  1982. #endif // SERVER_DEBUGGING
  1983. PeerThreadClass *t = (PeerThreadClass *)param;
  1984. if (!t)
  1985. {
  1986. DEBUG_LOG(("No thread! Bailing!\n"));
  1987. return;
  1988. }
  1989. if (success)
  1990. {
  1991. DEBUG_LOG(("Saw group room of %d (%s) at address %X %X\n", groupID, name, server, (server)?server->keyvals:0));
  1992. PeerResponse resp;
  1993. resp.peerResponseType = PeerResponse::PEERRESPONSE_GROUPROOM;
  1994. resp.groupRoom.id = groupID;
  1995. resp.groupRoom.numWaiting = numWaiting;
  1996. resp.groupRoom.maxWaiting = maxWaiting;
  1997. resp.groupRoom.numGames = numGames;
  1998. resp.groupRoom.numPlaying = numPlaying;
  1999. if (name)
  2000. {
  2001. resp.groupRoomName = name;
  2002. //t->setQMGroupRoom(groupID);
  2003. }
  2004. else
  2005. {
  2006. resp.groupRoomName.empty();
  2007. }
  2008. TheGameSpyPeerMessageQueue->addResponse(resp);
  2009. #ifdef SERVER_DEBUGGING
  2010. CheckServers(peer);
  2011. DEBUG_LOG(("\n"));
  2012. #endif // SERVER_DEBUGGING
  2013. }
  2014. else
  2015. {
  2016. DEBUG_LOG(("Failure!\n"));
  2017. }
  2018. }
  2019. void PeerThreadClass::connectCallback( PEER peer, PEERBool success )
  2020. {
  2021. PeerResponse resp;
  2022. if(!success)
  2023. {
  2024. //updateBuddyStatus( BUDDY_OFFLINE );
  2025. resp.peerResponseType = PeerResponse::PEERRESPONSE_DISCONNECT;
  2026. resp.discon.reason = DISCONNECT_COULDNOTCONNECT;
  2027. TheGameSpyPeerMessageQueue->addResponse(resp);
  2028. return;
  2029. }
  2030. updateBuddyStatus( BUDDY_ONLINE );
  2031. m_isConnected = true;
  2032. DEBUG_LOG(("Connected as profile %d (%s)\n", m_profileID, m_loginName.c_str()));
  2033. resp.peerResponseType = PeerResponse::PEERRESPONSE_LOGIN;
  2034. resp.player.profileID = m_profileID;
  2035. resp.nick = m_loginName;
  2036. GetLocalChatConnectionAddress("peerchat.gamespy.com", 6667, localIP);
  2037. chatSetLocalIP(localIP);
  2038. resp.player.internalIP = ntohl(localIP);
  2039. resp.player.externalIP = ntohl(peerGetLocalIP(peer));
  2040. TheGameSpyPeerMessageQueue->addResponse(resp);
  2041. PSRequest psReq;
  2042. psReq.requestType = PSRequest::PSREQUEST_READPLAYERSTATS;
  2043. psReq.player.id = m_profileID;
  2044. psReq.nick = m_originalName;
  2045. psReq.email = m_email;
  2046. psReq.password = m_password;
  2047. TheGameSpyPSMessageQueue->addRequest(psReq);
  2048. #ifdef SERVER_DEBUGGING
  2049. DEBUG_LOG(("Before peerListGroupRooms()\n"));
  2050. CheckServers(peer);
  2051. #endif // SERVER_DEBUGGING
  2052. peerListGroupRooms( peer, NULL, listGroupRoomsCallback, this, PEERTrue );
  2053. #ifdef SERVER_DEBUGGING
  2054. DEBUG_LOG(("After peerListGroupRooms()\n"));
  2055. CheckServers(peer);
  2056. #endif // SERVER_DEBUGGING
  2057. }
  2058. void PeerThreadClass::nickErrorCallback( PEER peer, Int type, const char *nick )
  2059. {
  2060. if(type == PEER_IN_USE)
  2061. {
  2062. Int len = strlen(nick);
  2063. std::string nickStr = nick;
  2064. Int newVal = 0;
  2065. if (nick[len-1] == '}' && nick[len-3] == '{' && isdigit(nick[len-2]))
  2066. {
  2067. newVal = nick[len-2] - '0' + 1;
  2068. nickStr.erase(len-3, 3);
  2069. }
  2070. DEBUG_LOG(("Nickname taken: was %s, new val = %d, new nick = %s\n", nick, newVal, nickStr.c_str()));
  2071. if (newVal < 10)
  2072. {
  2073. nickStr.append("{");
  2074. char tmp[2];
  2075. tmp[0] = '0'+newVal;
  2076. tmp[1] = '\0';
  2077. nickStr.append(tmp);
  2078. nickStr.append("}");
  2079. // Retry the connect with a similar nick.
  2080. m_loginName = nickStr;
  2081. peerRetryWithNick(peer, nickStr.c_str());
  2082. }
  2083. else
  2084. {
  2085. PeerResponse resp;
  2086. resp.peerResponseType = PeerResponse::PEERRESPONSE_DISCONNECT;
  2087. resp.discon.reason = DISCONNECT_NICKTAKEN;
  2088. TheGameSpyPeerMessageQueue->addResponse(resp);
  2089. // Cancel the connect.
  2090. peerRetryWithNick(peer, NULL);
  2091. }
  2092. }
  2093. else
  2094. {
  2095. PeerResponse resp;
  2096. resp.peerResponseType = PeerResponse::PEERRESPONSE_DISCONNECT;
  2097. resp.discon.reason = DISCONNECT_BADNICK;
  2098. TheGameSpyPeerMessageQueue->addResponse(resp);
  2099. // Cancel the connect.
  2100. peerRetryWithNick(peer, NULL);
  2101. }
  2102. }
  2103. void disconnectedCallback(PEER peer, const char * reason, void * param)
  2104. {
  2105. DEBUG_LOG(("disconnectedCallback(): reason was '%s'\n", reason));
  2106. PeerThreadClass *t = (PeerThreadClass *)param;
  2107. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2108. if (t)
  2109. t->markAsDisconnected();
  2110. //updateBuddyStatus( BUDDY_OFFLINE );
  2111. PeerResponse resp;
  2112. resp.peerResponseType = PeerResponse::PEERRESPONSE_DISCONNECT;
  2113. resp.discon.reason = DISCONNECT_LOSTCON;
  2114. SerialAuthResult res = TheGameSpyPeerMessageQueue->getSerialAuthResult();
  2115. switch (res)
  2116. {
  2117. case SERIAL_NONEXISTENT:
  2118. resp.discon.reason = DISCONNECT_SERIAL_NOT_PRESENT;
  2119. break;
  2120. case SERIAL_AUTHFAILED:
  2121. resp.discon.reason = DISCONNECT_SERIAL_INVALID;
  2122. break;
  2123. case SERIAL_BANNED:
  2124. resp.discon.reason = DISCONNECT_SERIAL_BANNED;
  2125. break;
  2126. }
  2127. TheGameSpyPeerMessageQueue->addResponse(resp);
  2128. }
  2129. void roomMessageCallback(PEER peer, RoomType roomType, const char * nick, const char * message, MessageType messageType, void * param)
  2130. {
  2131. PeerResponse resp;
  2132. resp.peerResponseType = PeerResponse::PEERRESPONSE_MESSAGE;
  2133. resp.nick = nick;
  2134. resp.text = MultiByteToWideCharSingleLine(message);
  2135. resp.message.isPrivate = FALSE;
  2136. resp.message.isAction = (messageType == ActionMessage);
  2137. TheGameSpyPeerMessageQueue->addResponse(resp);
  2138. DEBUG_LOG(("Saw text [%hs] (%ls) %d chars Orig was %s (%d chars)\n", nick, resp.text.c_str(), resp.text.length(), message, strlen(message)));
  2139. UnsignedInt IP;
  2140. peerGetPlayerInfoNoWait(peer, nick, &IP, &resp.message.profileID);
  2141. PeerThreadClass *t = (PeerThreadClass *)param;
  2142. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2143. if (t && (t->getQMStatus() != QM_IDLE && t->getQMStatus() != QM_STOPPED))
  2144. {
  2145. if (resp.message.profileID == matchbotProfileID)
  2146. {
  2147. char *lastStr = NULL;
  2148. char *cmd = strtok_r((char *)message, " ", &lastStr);
  2149. if ( cmd && strcmp(cmd, "MBOT:POOLSIZE") == 0 )
  2150. {
  2151. Int poolSize = 0;
  2152. while (1)
  2153. {
  2154. char *poolStr = strtok_r(NULL, " ", &lastStr);
  2155. char *sizeStr = strtok_r(NULL, " ", &lastStr);
  2156. if (poolStr && sizeStr)
  2157. {
  2158. Int pool = atoi(poolStr);
  2159. Int size = atoi(sizeStr);
  2160. if (pool == t->getQMLadder())
  2161. {
  2162. poolSize = size;
  2163. break;
  2164. }
  2165. }
  2166. else
  2167. break;
  2168. }
  2169. PeerResponse resp;
  2170. resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS;
  2171. resp.qmStatus.status = QM_POOLSIZE;
  2172. resp.qmStatus.poolSize = poolSize;
  2173. TheGameSpyPeerMessageQueue->addResponse(resp);
  2174. }
  2175. }
  2176. }
  2177. }
  2178. void gameStartedCallback( PEER peer, UnsignedInt IP, const char *message, void *param )
  2179. {
  2180. PeerResponse resp;
  2181. resp.peerResponseType = PeerResponse::PEERRESPONSE_GAMESTART;
  2182. TheGameSpyPeerMessageQueue->addResponse(resp);
  2183. }
  2184. void playerMessageCallback(PEER peer, const char * nick, const char * message, MessageType messageType, void * param)
  2185. {
  2186. PeerResponse resp;
  2187. resp.peerResponseType = PeerResponse::PEERRESPONSE_MESSAGE;
  2188. resp.nick = nick;
  2189. resp.text = MultiByteToWideCharSingleLine(message);
  2190. resp.message.isPrivate = TRUE;
  2191. resp.message.isAction = (messageType == ActionMessage);
  2192. UnsignedInt IP;
  2193. peerGetPlayerInfoNoWait(peer, nick, &IP, &resp.message.profileID);
  2194. TheGameSpyPeerMessageQueue->addResponse(resp);
  2195. PeerThreadClass *t = (PeerThreadClass *)param;
  2196. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2197. if (t && (t->getQMStatus() != QM_IDLE && t->getQMStatus() != QM_STOPPED))
  2198. {
  2199. if (resp.message.isPrivate && resp.message.profileID == matchbotProfileID)
  2200. {
  2201. char *lastStr = NULL;
  2202. char *cmd = strtok_r((char *)message, " ", &lastStr);
  2203. if ( cmd && strcmp(cmd, "MBOT:MATCHED") == 0 )
  2204. {
  2205. char *mapNumStr = strtok_r(NULL, " ", &lastStr);
  2206. char *seedStr = strtok_r(NULL, " ", &lastStr);
  2207. char *playerStr[MAX_SLOTS];
  2208. char *playerIPStr[MAX_SLOTS];
  2209. char *playerSideStr[MAX_SLOTS];
  2210. char *playerColorStr[MAX_SLOTS];
  2211. char *playerNATStr[MAX_SLOTS];
  2212. Int numPlayers = 0;
  2213. for (Int i=0; i<MAX_SLOTS; ++i)
  2214. {
  2215. playerStr[i] = strtok_r(NULL, " ", &lastStr);
  2216. playerIPStr[i] = strtok_r(NULL, " ", &lastStr);
  2217. playerSideStr[i] = strtok_r(NULL, " ", &lastStr);
  2218. playerColorStr[i] = strtok_r(NULL, " ", &lastStr);
  2219. playerNATStr[i] = strtok_r(NULL, " ", &lastStr);
  2220. if (playerNATStr[i])
  2221. {
  2222. ++numPlayers;
  2223. }
  2224. else
  2225. {
  2226. playerStr[i] = NULL;
  2227. playerIPStr[i] = NULL;
  2228. playerSideStr[i] = NULL;
  2229. playerColorStr[i] = NULL;
  2230. playerNATStr[i] = NULL;
  2231. }
  2232. }
  2233. if (numPlayers > 1)
  2234. {
  2235. // woohoo! got everything needed for a match!
  2236. DEBUG_LOG(("Saw %d-player QM match: map index = %s, seed = %s\n", numPlayers, mapNumStr, seedStr));
  2237. t->handleQMMatch(peer, atoi(mapNumStr), atoi(seedStr), playerStr, playerIPStr, playerSideStr, playerColorStr, playerNATStr);
  2238. }
  2239. }
  2240. else if ( cmd && strcmp(cmd, "MBOT:WORKING") == 0 )
  2241. {
  2242. Int poolSize = 0;
  2243. char *poolStr = strtok_r(NULL, " ", &lastStr);
  2244. if (poolStr)
  2245. poolSize = atoi(poolStr);
  2246. PeerResponse resp;
  2247. resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS;
  2248. resp.qmStatus.status = QM_WORKING;
  2249. resp.qmStatus.poolSize = poolSize;
  2250. TheGameSpyPeerMessageQueue->addResponse(resp);
  2251. }
  2252. else if ( cmd && strcmp(cmd, "MBOT:WIDENINGSEARCH") == 0 )
  2253. {
  2254. PeerResponse resp;
  2255. resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS;
  2256. resp.qmStatus.status = QM_WIDENINGSEARCH;
  2257. TheGameSpyPeerMessageQueue->addResponse(resp);
  2258. }
  2259. }
  2260. }
  2261. }
  2262. void roomUTMCallback(PEER peer, RoomType roomType, const char * nick, const char * command, const char * parameters, PEERBool authenticated, void * param)
  2263. {
  2264. DEBUG_LOG(("roomUTMCallback: %s says %s = [%s]\n", nick, command, parameters));
  2265. if (roomType != StagingRoom)
  2266. return;
  2267. PeerResponse resp;
  2268. resp.peerResponseType = PeerResponse::PEERRESPONSE_ROOMUTM;
  2269. resp.nick = nick;
  2270. resp.command = command;
  2271. resp.commandOptions = parameters;
  2272. TheGameSpyPeerMessageQueue->addResponse(resp);
  2273. }
  2274. void playerUTMCallback(PEER peer, const char * nick, const char * command, const char * parameters, PEERBool authenticated, void * param)
  2275. {
  2276. DEBUG_LOG(("playerUTMCallback: %s says %s = [%s]\n", nick, command, parameters));
  2277. PeerResponse resp;
  2278. resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERUTM;
  2279. resp.nick = nick;
  2280. resp.command = command;
  2281. resp.commandOptions = parameters;
  2282. TheGameSpyPeerMessageQueue->addResponse(resp);
  2283. }
  2284. static void getPlayerInfo(PeerThreadClass *t, PEER peer, const char *nick, Int& id, UnsignedInt& IP,
  2285. std::string& locale, Int& wins, Int& losses, Int& rankPoints, Int& side, Int& preorder,
  2286. RoomType roomType, Int& flags)
  2287. {
  2288. if (!t || !nick)
  2289. return;
  2290. peerGetPlayerInfoNoWait(peer, nick, &IP, &id);
  2291. #ifdef USE_BROADCAST_KEYS
  2292. //locale.printf
  2293. Int localeIndex = t->lookupStatForPlayer(roomType, nick, "b_locale");
  2294. AsciiString tmp;
  2295. tmp.format("%d", localeIndex);
  2296. locale = tmp.str();
  2297. wins = t->lookupStatForPlayer(roomType, nick, "b_wins");
  2298. losses = t->lookupStatForPlayer(roomType, nick, "b_losses");
  2299. rankPoints = t->lookupStatForPlayer(roomType, nick, "b_points");
  2300. side = t->lookupStatForPlayer(roomType, nick, "b_side");
  2301. preorder = t->lookupStatForPlayer(roomType, nick, "b_pre");
  2302. #else // USE_BROADCAST_KEYS
  2303. const char *s;
  2304. s = peerGetGlobalWatchKey(peer, nick, "locale");
  2305. locale = (s)?s:"";
  2306. s = peerGetGlobalWatchKey(peer, nick, "wins");
  2307. wins = atoi((s)?s:"");
  2308. s = peerGetGlobalWatchKey(peer, nick, "losses");
  2309. losses = atoi((s)?s:"");
  2310. s = peerGetGlobalWatchKey(peer, nick, "points");
  2311. rankPoints = atoi((s)?s:"");
  2312. s = peerGetGlobalWatchKey(peer, nick, "side");
  2313. side = atoi((s)?s:"");
  2314. s = peerGetGlobalWatchKey(peer, nick, "pre");
  2315. preorder = atoi((s)?s:"");
  2316. #endif // USE_BROADCAST_KEYS
  2317. flags = 0;
  2318. peerGetPlayerFlags(peer, nick, roomType, &flags);
  2319. DEBUG_LOG(("getPlayerInfo(%d) - %s has locale %s, wins:%d, losses:%d, rankPoints:%d, side:%d, preorder:%d\n",
  2320. id, nick, locale.c_str(), wins, losses, rankPoints, side, preorder));
  2321. }
  2322. static void roomKeyChangedCallback(PEER peer, RoomType roomType, const char *nick, const char *key, const char *val, void *param)
  2323. {
  2324. #ifdef USE_BROADCAST_KEYS
  2325. PeerThreadClass *t = (PeerThreadClass *)param;
  2326. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2327. DEBUG_ASSERTCRASH(nick && key && val, ("Bad values %X %X %X\n", nick, key, val));
  2328. if (!t || !nick || !key || !val)
  2329. {
  2330. DEBUG_ASSERTLOG(!nick, ("nick = %s\n", nick));
  2331. DEBUG_ASSERTLOG(!key, ("key = %s\n", key));
  2332. DEBUG_ASSERTLOG(!val, ("val = %s\n", val));
  2333. return;
  2334. }
  2335. #ifdef DEBUG_LOGGING
  2336. if (strcmp(key, "username") && strcmp(key, "b_flags"))
  2337. {
  2338. DEBUG_LOG(("roomKeyChangedCallback() - %s set %s=%s\n", nick, key, val));
  2339. }
  2340. #endif
  2341. t->trackStatsForPlayer(roomType, nick, key, val);
  2342. PeerResponse resp;
  2343. resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERINFO;
  2344. resp.nick = nick;
  2345. resp.player.roomType = roomType;
  2346. getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP,
  2347. resp.locale, resp.player.wins, resp.player.losses,
  2348. resp.player.rankPoints, resp.player.side, resp.player.preorder,
  2349. resp.player.roomType, resp.player.flags);
  2350. TheGameSpyPeerMessageQueue->addResponse(resp);
  2351. #endif // USE_BROADCAST_KEYS
  2352. }
  2353. #ifdef USE_BROADCAST_KEYS
  2354. void getRoomKeysCallback(PEER peer, PEERBool success, RoomType roomType, const char *nick, int num, char **keys, char **values, void *param)
  2355. {
  2356. PeerThreadClass *t = (PeerThreadClass *)param;
  2357. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2358. DEBUG_ASSERTCRASH(keys && values, ("bad key/value %X/%X", keys, values));
  2359. if (!t || !nick || !num || !success || !keys || !values)
  2360. return;
  2361. for (Int i=0; i<num; ++i)
  2362. {
  2363. t->trackStatsForPlayer(roomType, nick, keys[i], values[i]);
  2364. }
  2365. PeerResponse resp;
  2366. resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERINFO;
  2367. resp.nick = nick;
  2368. resp.player.roomType = roomType;
  2369. getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP,
  2370. resp.locale, resp.player.wins, resp.player.losses,
  2371. resp.player.rankPoints, resp.player.side, resp.player.preorder,
  2372. resp.player.roomType, resp.player.flags);
  2373. TheGameSpyPeerMessageQueue->addResponse(resp);
  2374. }
  2375. #endif // USE_BROADCAST_KEYS
  2376. static void globalKeyChangedCallback(PEER peer, const char *nick, const char *key, const char *val, void *param)
  2377. {
  2378. if (!nick)
  2379. return;
  2380. PeerThreadClass *t = (PeerThreadClass *)param;
  2381. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2382. if (!t)
  2383. return;
  2384. PeerResponse resp;
  2385. resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERINFO;
  2386. resp.nick = nick;
  2387. resp.player.roomType = t->getCurrentGroupRoom()?GroupRoom:StagingRoom;
  2388. getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP,
  2389. resp.locale, resp.player.wins, resp.player.losses,
  2390. resp.player.rankPoints, resp.player.side, resp.player.preorder,
  2391. resp.player.roomType, resp.player.flags);
  2392. TheGameSpyPeerMessageQueue->addResponse(resp);
  2393. }
  2394. void playerJoinedCallback(PEER peer, RoomType roomType, const char * nick, void * param)
  2395. {
  2396. if (!nick)
  2397. return;
  2398. PeerThreadClass *t = (PeerThreadClass *)param;
  2399. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2400. if (!t)
  2401. return;
  2402. PeerResponse resp;
  2403. resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERJOIN;
  2404. resp.nick = nick;
  2405. resp.player.roomType = roomType;
  2406. getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP,
  2407. resp.locale, resp.player.wins, resp.player.losses,
  2408. resp.player.rankPoints, resp.player.side, resp.player.preorder,
  2409. roomType, resp.player.flags);
  2410. TheGameSpyPeerMessageQueue->addResponse(resp);
  2411. }
  2412. void playerLeftCallback(PEER peer, RoomType roomType, const char * nick, const char * reason, void * param)
  2413. {
  2414. PeerResponse resp;
  2415. resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERLEFT;
  2416. resp.nick = nick;
  2417. resp.player.roomType = roomType;
  2418. resp.player.profileID = 0;
  2419. PeerThreadClass *t = (PeerThreadClass *)param;
  2420. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2421. if (!t)
  2422. return;
  2423. getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP,
  2424. resp.locale, resp.player.wins, resp.player.losses,
  2425. resp.player.rankPoints, resp.player.side, resp.player.preorder,
  2426. roomType, resp.player.flags);
  2427. TheGameSpyPeerMessageQueue->addResponse(resp);
  2428. if (t->getQMStatus() != QM_IDLE && t->getQMStatus() != QM_STOPPED)
  2429. {
  2430. if (!stricmp(t->getQMBotName().c_str(), nick))
  2431. {
  2432. // matchbot left - bail
  2433. PeerResponse resp;
  2434. resp.peerResponseType = PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS;
  2435. resp.qmStatus.status = QM_COULDNOTFINDBOT;
  2436. TheGameSpyPeerMessageQueue->addResponse(resp);
  2437. PeerRequest req;
  2438. req.peerRequestType = PeerRequest::PEERREQUEST_STOPQUICKMATCH;
  2439. TheGameSpyPeerMessageQueue->addRequest(req);
  2440. }
  2441. }
  2442. }
  2443. void playerChangedNickCallback(PEER peer, RoomType roomType, const char * oldNick, const char * newNick, void * param)
  2444. {
  2445. PeerResponse resp;
  2446. resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERCHANGEDNICK;
  2447. resp.nick = newNick;
  2448. resp.oldNick = oldNick;
  2449. resp.player.roomType = roomType;
  2450. PeerThreadClass *t = (PeerThreadClass *)param;
  2451. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2452. if (!t)
  2453. return;
  2454. getPlayerInfo(t, peer, newNick, resp.player.profileID, resp.player.IP,
  2455. resp.locale, resp.player.wins, resp.player.losses,
  2456. resp.player.rankPoints, resp.player.side, resp.player.preorder,
  2457. roomType, resp.player.flags);
  2458. TheGameSpyPeerMessageQueue->addResponse(resp);
  2459. }
  2460. static void playerInfoCallback(PEER peer, RoomType roomType, const char * nick, unsigned int IP, int profileID, void * param)
  2461. {
  2462. if (!nick)
  2463. return;
  2464. PeerResponse resp;
  2465. resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERINFO;
  2466. resp.nick = nick;
  2467. resp.player.roomType = roomType;
  2468. PeerThreadClass *t = (PeerThreadClass *)param;
  2469. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2470. if (!t)
  2471. return;
  2472. getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP,
  2473. resp.locale, resp.player.wins, resp.player.losses,
  2474. resp.player.rankPoints, resp.player.side, resp.player.preorder,
  2475. roomType, resp.player.flags);
  2476. TheGameSpyPeerMessageQueue->addResponse(resp);
  2477. }
  2478. static void playerFlagsChangedCallback(PEER peer, RoomType roomType, const char * nick, int oldFlags, int newFlags, void * param)
  2479. {
  2480. if (!nick)
  2481. return;
  2482. PeerResponse resp;
  2483. resp.peerResponseType = PeerResponse::PEERRESPONSE_PLAYERCHANGEDFLAGS;
  2484. resp.nick = nick;
  2485. resp.player.roomType = roomType;
  2486. PeerThreadClass *t = (PeerThreadClass *)param;
  2487. DEBUG_ASSERTCRASH(t, ("No Peer thread!"));
  2488. if (!t)
  2489. return;
  2490. getPlayerInfo(t, peer, nick, resp.player.profileID, resp.player.IP,
  2491. resp.locale, resp.player.wins, resp.player.losses,
  2492. resp.player.rankPoints, resp.player.side, resp.player.preorder,
  2493. roomType, resp.player.flags);
  2494. TheGameSpyPeerMessageQueue->addResponse(resp);
  2495. }
  2496. #ifdef DEBUG_LOGGING
  2497. /*
  2498. static void enumFunc(char *key, char *val, void *param)
  2499. {
  2500. DEBUG_LOG((" [%s] = [%s]\n", key, val));
  2501. }
  2502. */
  2503. #endif
  2504. static void listingGamesCallback(PEER peer, PEERBool success, const char * name, SBServer server, PEERBool staging, int msg, Int percentListed, void * param)
  2505. {
  2506. #ifdef DEBUG_LOGGING
  2507. AsciiString cmdStr = "<Unknown>";
  2508. switch(msg)
  2509. {
  2510. case PEER_ADD:
  2511. cmdStr = "PEER_ADD";
  2512. break;
  2513. case PEER_UPDATE:
  2514. cmdStr = "PEER_UPDATE";
  2515. break;
  2516. case PEER_REMOVE:
  2517. cmdStr = "PEER_REMOVE";
  2518. break;
  2519. case PEER_CLEAR:
  2520. cmdStr = "PEER_CLEAR";
  2521. break;
  2522. case PEER_COMPLETE:
  2523. cmdStr = "PEER_COMPLETE";
  2524. break;
  2525. }
  2526. DEBUG_LOG(("listingGamesCallback() - doing command %s on server %X\n", cmdStr.str(), server));
  2527. #endif // DEBUG_LOGGING
  2528. PeerThreadClass *t = (PeerThreadClass *)param;
  2529. DEBUG_ASSERTCRASH(name, ("Game has no name!\n"));
  2530. if (!t || !success || (!name && (msg == PEER_ADD || msg == PEER_UPDATE)))
  2531. {
  2532. DEBUG_LOG(("Bailing from listingGamesCallback() - success=%d, name=%X, server=%X, msg=%X\n", success, name, server, msg));
  2533. return;
  2534. }
  2535. if (!name)
  2536. name = "bogus";
  2537. if (server && (msg == PEER_ADD || msg == PEER_UPDATE))
  2538. {
  2539. DEBUG_ASSERTCRASH(server->keyvals, ("Looking at an already-freed server for msg type %d!", msg));
  2540. if (!server->keyvals)
  2541. {
  2542. msg = PEER_REMOVE;
  2543. }
  2544. }
  2545. if (server && success && (msg == PEER_ADD || msg == PEER_UPDATE))
  2546. {
  2547. DEBUG_LOG(("Game name is '%s'\n", name));
  2548. const char *newname = SBServerGetStringValue(server, "gamename", (char *)name);
  2549. if (strcmp(newname, "ccgenerals"))
  2550. name = newname;
  2551. DEBUG_LOG(("Game name is now '%s'\n", name));
  2552. }
  2553. DEBUG_LOG(("listingGamesCallback - got percent complete %d\n", percentListed));
  2554. if (percentListed == 100)
  2555. {
  2556. if (!t->getSawCompleteGameList())
  2557. {
  2558. t->setSawCompleteGameList(TRUE);
  2559. PeerResponse completeResp;
  2560. completeResp.peerResponseType = PeerResponse::PEERRESPONSE_STAGINGROOMLISTCOMPLETE;
  2561. TheGameSpyPeerMessageQueue->addResponse(completeResp);
  2562. }
  2563. }
  2564. AsciiString gameName = name;
  2565. AsciiString tmp = gameName;
  2566. AsciiString hostName;
  2567. tmp.nextToken(&hostName, " ");
  2568. const char *firstSpace = gameName.find(' ');
  2569. if(firstSpace)
  2570. {
  2571. gameName.set(firstSpace + 1);
  2572. //gameName.trim();
  2573. DEBUG_LOG(("Hostname/Gamename split leaves '%s' hosting '%s'\n", hostName.str(), gameName.str()));
  2574. }
  2575. PeerResponse resp;
  2576. resp.peerResponseType = PeerResponse::PEERRESPONSE_STAGINGROOM;
  2577. resp.stagingRoom.action = msg;
  2578. resp.stagingRoom.isStaging = staging;
  2579. resp.stagingRoom.percentComplete = percentListed;
  2580. if (server && (msg == PEER_ADD || msg == PEER_UPDATE))
  2581. {
  2582. Bool hasPassword = (Bool)SBServerGetIntValue(server, PW_STR, FALSE);
  2583. Bool allowObservers = (Bool)SBServerGetIntValue(server, OBS_STR, FALSE);
  2584. const char *verStr = SBServerGetStringValue(server, "gamever", "000000");
  2585. const char *exeStr = SBServerGetStringValue(server, EXECRC_STR, "000000");
  2586. const char *iniStr = SBServerGetStringValue(server, INICRC_STR, "000000");
  2587. const char *ladIPStr = SBServerGetStringValue(server, LADIP_STR, "000000");
  2588. const char *pingStr = SBServerGetStringValue(server, PINGSTR_STR, "FFFFFFFFFFFFFFFF");
  2589. UnsignedShort ladPort = (UnsignedShort)SBServerGetIntValue(server, LADPORT_STR, 0);
  2590. UnsignedInt verVal = strtoul(verStr, NULL, 10);
  2591. UnsignedInt exeVal = strtoul(exeStr, NULL, 10);
  2592. UnsignedInt iniVal = strtoul(iniStr, NULL, 10);
  2593. resp.stagingRoom.requiresPassword = hasPassword;
  2594. resp.stagingRoom.allowObservers = allowObservers;
  2595. resp.stagingRoom.version = verVal;
  2596. resp.stagingRoom.exeCRC = exeVal;
  2597. resp.stagingRoom.iniCRC = iniVal;
  2598. resp.stagingServerLadderIP = ladIPStr;
  2599. resp.stagingServerPingString = pingStr;
  2600. resp.stagingRoom.ladderPort = ladPort;
  2601. resp.stagingRoom.numPlayers = SBServerGetIntValue(server, NUMPLAYER_STR, 0);
  2602. resp.stagingRoom.numObservers = SBServerGetIntValue(server, NUMOBS_STR, 0);
  2603. resp.stagingRoom.maxPlayers = SBServerGetIntValue(server, MAXPLAYER_STR, 8);
  2604. resp.stagingRoomMapName = SBServerGetStringValue(server, "mapname", "");
  2605. for (Int i=0; i<MAX_SLOTS; ++i)
  2606. {
  2607. resp.stagingRoomPlayerNames[i] = SBServerGetPlayerStringValue(server, i, NAME__STR, "");
  2608. resp.stagingRoom.wins[i] = SBServerGetPlayerIntValue(server, i, WINS__STR, 0);
  2609. resp.stagingRoom.losses[i] = SBServerGetPlayerIntValue(server, i, LOSSES__STR, 0);
  2610. resp.stagingRoom.profileID[i] = SBServerGetPlayerIntValue(server, i, "pid", 0);
  2611. resp.stagingRoom.color[i] = SBServerGetPlayerIntValue(server, i, COLOR__STR, 0);
  2612. resp.stagingRoom.faction[i] = SBServerGetPlayerIntValue(server, i, FACTION__STR, 0);
  2613. #ifdef DEBUG_LOGGING
  2614. if (resp.stagingRoomPlayerNames[i].length())
  2615. {
  2616. DEBUG_LOG(("Player %d raw stuff: [%s] [%d] [%d] [%d]\n", i, resp.stagingRoomPlayerNames[i].c_str(), resp.stagingRoom.wins[i], resp.stagingRoom.losses[i], resp.stagingRoom.profileID[i]));
  2617. }
  2618. #endif
  2619. }
  2620. if (resp.stagingRoomPlayerNames[0].empty())
  2621. {
  2622. resp.stagingRoomPlayerNames[0] = hostName.str();
  2623. }
  2624. DEBUG_ASSERTCRASH(resp.stagingRoomPlayerNames[0].empty() == false, ("No host!"));
  2625. DEBUG_LOG(("Raw stuff: [%s] [%s] [%s] [%d] [%d]\n", verStr, exeStr, iniStr, hasPassword, allowObservers));
  2626. DEBUG_LOG(("Raw stuff: [%s] [%s] [%d]\n", pingStr, ladIPStr, ladPort));
  2627. DEBUG_LOG(("Saw game with stuff %s %d %X %X %X %s\n", resp.stagingRoomMapName.c_str(), hasPassword, verVal, exeVal, iniVal, SBServerGetStringValue(server, "password", "missing")));
  2628. #ifdef PING_TEST
  2629. PING_LOG(("%s\n", pingStr));
  2630. #endif
  2631. }
  2632. if (msg == PEER_ADD || msg == PEER_UPDATE)
  2633. {
  2634. if (!resp.stagingRoom.exeCRC || !resp.stagingRoom.iniCRC)
  2635. {
  2636. if (SBServerHasBasicKeys(server))
  2637. {
  2638. DEBUG_LOG(("Server %x does not have basic keys\n", server));
  2639. return;
  2640. }
  2641. else
  2642. {
  2643. DEBUG_LOG(("Server %x has basic keys, yet has no info\n", server));
  2644. }
  2645. if (msg == PEER_UPDATE)
  2646. {
  2647. PeerRequest req;
  2648. req.peerRequestType = PeerRequest::PEERREQUEST_GETEXTENDEDSTAGINGROOMINFO;
  2649. req.stagingRoom.id = t->findServer( server );
  2650. DEBUG_LOG(("Add/update a 0/0 server %X (%d, %s) - requesting full update to see if that helps.\n",
  2651. server, resp.stagingRoom.id, gameName.str()));
  2652. TheGameSpyPeerMessageQueue->addRequest(req);
  2653. }
  2654. return; // don't actually try to list it.
  2655. }
  2656. }
  2657. switch (msg)
  2658. {
  2659. case PEER_CLEAR:
  2660. t->clearServers();
  2661. break;
  2662. case PEER_ADD:
  2663. case PEER_UPDATE:
  2664. resp.stagingRoom.id = t->findServer( server );
  2665. DEBUG_LOG(("Add/update on server %X (%d, %s)\n", server, resp.stagingRoom.id, gameName.str()));
  2666. resp.stagingServerName = MultiByteToWideCharSingleLine( gameName.str() );
  2667. DEBUG_LOG(("Server had basic=%d, full=%d\n", SBServerHasBasicKeys(server), SBServerHasFullKeys(server)));
  2668. #ifdef DEBUG_LOGGING
  2669. //SBServerEnumKeys(server, enumFunc, NULL);
  2670. #endif
  2671. break;
  2672. case PEER_REMOVE:
  2673. DEBUG_LOG(("Removing server %X (%d)\n", server, resp.stagingRoom.id));
  2674. resp.stagingRoom.id = t->removeServerFromMap( server );
  2675. break;
  2676. }
  2677. TheGameSpyPeerMessageQueue->addResponse(resp);
  2678. }
  2679. //-------------------------------------------------------------------------