PageRenderTime 49ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/serverscanner.c

https://gitlab.com/fzwoch/fodquake
C | 1124 lines | 1039 code | 67 blank | 18 comment | 71 complexity | d745b0dbabd0d124dee7bf644e6492d9 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. Copyright (C) 2009 Mark Olsen
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include "sys_thread.h"
  18. #include "sys_net.h"
  19. #include "serverscanner.h"
  20. #define MAXCONCURRENTSCANS 16
  21. #define MAXCONCURRENTPINGS 8
  22. #define PINGINTERVAL 20000
  23. #define QWSERVERTIMEOUT 750000
  24. #warning Needs to reattempt scan/ping
  25. struct masterserver
  26. {
  27. char *hostname;
  28. struct netaddr addr;
  29. };
  30. struct qwserverpriv
  31. {
  32. struct qwserverpriv *next;
  33. struct qwserverpriv *nextscaninprogress;
  34. struct qwserverpriv *nextscanwaiting;
  35. struct qwserverpriv *nextpinginprogress;
  36. struct qwserverpriv *nextpingwaiting;
  37. unsigned long long packetsendtime;
  38. struct QWServer pub;
  39. };
  40. struct ServerScanner
  41. {
  42. struct SysNetData *netdata;
  43. struct SysSocket *sockets[NA_NUMTYPES];
  44. struct SysThread *thread;
  45. struct SysMutex *mutex;
  46. unsigned int initialstuffdone;
  47. unsigned long long starttime;
  48. struct masterserver *masterservers;
  49. struct qwserverpriv *qwservers;
  50. struct qwserverpriv *qwserversscaninprogress;
  51. struct qwserverpriv *qwserversscanwaiting;
  52. struct qwserverpriv *qwserverspinginprogress;
  53. struct qwserverpriv *qwserverspingwaiting;
  54. volatile unsigned int quit;
  55. unsigned int nummasterservers;
  56. unsigned int numvalidmasterservers;
  57. unsigned int numqwservers;
  58. unsigned int numqwserversscaninprogress;
  59. unsigned int numqwserverspinginprogress;
  60. unsigned long long lastpingtime;
  61. volatile enum ServerScannerStatus status;
  62. unsigned int updated;
  63. };
  64. static int ServerScanner_Thread_Init(struct ServerScanner *serverscanner)
  65. {
  66. serverscanner->netdata = Sys_Net_Init();
  67. if (serverscanner->netdata)
  68. {
  69. return 1;
  70. }
  71. return 0;
  72. }
  73. static void ServerScanner_Thread_Deinit(struct ServerScanner *serverscanner)
  74. {
  75. Sys_Net_Shutdown(serverscanner->netdata);
  76. }
  77. static void ServerScanner_Thread_LookUpMasters(struct ServerScanner *serverscanner)
  78. {
  79. unsigned int i;
  80. for(i=0;i<serverscanner->nummasterservers;i++)
  81. {
  82. if (!NET_StringToAdr(serverscanner->netdata, serverscanner->masterservers[i].hostname, &serverscanner->masterservers[i].addr))
  83. serverscanner->numvalidmasterservers--;
  84. }
  85. }
  86. static void ServerScanner_Thread_OpenSockets(struct ServerScanner *serverscanner)
  87. {
  88. unsigned int i;
  89. enum netaddrtype addrtype;
  90. for(i=0;i<serverscanner->nummasterservers;i++)
  91. {
  92. addrtype = serverscanner->masterservers[i].addr.type;
  93. if (addrtype == NA_LOOPBACK)
  94. continue;
  95. if (serverscanner->sockets[addrtype] == 0)
  96. serverscanner->sockets[addrtype] = Sys_Net_CreateSocket(serverscanner->netdata, addrtype);
  97. if (serverscanner->sockets[addrtype] == 0)
  98. serverscanner->numvalidmasterservers--;
  99. }
  100. }
  101. static void ServerScanner_Thread_CloseSockets(struct ServerScanner *serverscanner)
  102. {
  103. unsigned int i;
  104. for(i=0;i<NA_NUMTYPES;i++)
  105. {
  106. if (serverscanner->sockets[i])
  107. Sys_Net_DeleteSocket(serverscanner->netdata, serverscanner->sockets[i]);
  108. }
  109. }
  110. static void ServerScanner_Thread_QueryMasters(struct ServerScanner *serverscanner)
  111. {
  112. static const char querystring[] = "c\n";
  113. unsigned int i;
  114. for(i=0;i<serverscanner->nummasterservers;i++)
  115. {
  116. if (serverscanner->sockets[serverscanner->masterservers[i].addr.type])
  117. {
  118. Sys_Net_Send(serverscanner->netdata, serverscanner->sockets[serverscanner->masterservers[i].addr.type], querystring, 3, &serverscanner->masterservers[i].addr);
  119. }
  120. }
  121. }
  122. static void ServerScanner_Thread_ParseQWServerReply(struct ServerScanner *serverscanner, struct qwserverpriv *qwserver, unsigned char *data, unsigned int datalen)
  123. {
  124. struct QWPlayer *qwplayers;
  125. struct QWSpectator *qwspectators;
  126. char *p3;
  127. unsigned int i;
  128. unsigned int j;
  129. unsigned int k;
  130. unsigned int extralength;
  131. char *p;
  132. char *p2;
  133. char *key;
  134. char *value;
  135. unsigned int numplayers;
  136. unsigned int numspectators;
  137. char *name[32];
  138. char *team[32];
  139. int spectator[32];
  140. int frags[32];
  141. int time[32];
  142. unsigned int ping[32];
  143. unsigned int topcolour[32];
  144. unsigned int bottomcolour[32];
  145. qwserver->pub.status = QWSS_FAILED;
  146. if (datalen < 2 || data[0] != 'n')
  147. return;
  148. data++;
  149. datalen--;
  150. p = memchr(data, '\n', datalen);
  151. if (p == 0)
  152. return;
  153. p2 = memchr(data, 0, datalen);
  154. if (p2 && p2 < p)
  155. return;
  156. *p = 0;
  157. p = (char *)(data + 1);
  158. while(*p)
  159. {
  160. key = p;
  161. p = strchr(key, '\\');
  162. if (p == 0)
  163. break;
  164. *p = 0;
  165. value = p + 1;
  166. p = strchr(value, '\\');
  167. if (p)
  168. {
  169. *p = 0;
  170. p++;
  171. }
  172. else
  173. p = value + strlen(value);
  174. #if 0
  175. printf("%s = %s\n", key, value);
  176. #endif
  177. if (*key == '*')
  178. key++;
  179. if (strcmp(key, "maxclients") == 0)
  180. qwserver->pub.maxclients = strtoul(value, 0, 0);
  181. else if (strcmp(key, "maxspectators") == 0)
  182. qwserver->pub.maxspectators = strtoul(value, 0, 0);
  183. else if (strcmp(key, "teamplay") == 0)
  184. qwserver->pub.teamplay = strtoul(value, 0, 0);
  185. else if (strcmp(key, "map") == 0)
  186. qwserver->pub.map = strdup(value);
  187. else if (strcmp(key, "hostname") == 0)
  188. qwserver->pub.hostname = strdup(value);
  189. else if (strcmp(key, "gamedir") == 0)
  190. qwserver->pub.gamedir = strdup(value);
  191. }
  192. if (!p)
  193. return;
  194. datalen -= (p - (char *)data);
  195. data = (unsigned char *)p;
  196. if (datalen == 0)
  197. return;
  198. datalen--;
  199. data++;
  200. qwserver->pub.status = QWSS_DONE;
  201. numplayers = 0;
  202. numspectators = 0;
  203. extralength = 0;
  204. i = 0;
  205. while(1)
  206. {
  207. if (numplayers + numspectators >= 32)
  208. break;
  209. p = memchr(data, '\n', datalen);
  210. if (p == 0)
  211. break;
  212. p2 = memchr(data, 0, datalen);
  213. if (p2 && p2 < p)
  214. break;
  215. *p = 0;
  216. #ifdef DEBUG
  217. printf("%s\n", data);
  218. #endif
  219. p2 = (char *)data;
  220. p2 = strchr(p2, ' ');
  221. if (!p2)
  222. break;
  223. p2++;
  224. frags[i] = atoi(p2);
  225. p2 = strchr(p2, ' ');
  226. if (!p2)
  227. break;
  228. p2++;
  229. time[i] = atoi(p2);
  230. p2 = strchr(p2, ' ');
  231. if (!p2)
  232. break;
  233. p2++;
  234. ping[i] = atoi(p2);
  235. p2 = strchr(p2, ' ');
  236. if (!p2)
  237. break;
  238. p2++;
  239. if (*p2 != '"')
  240. break;
  241. p2++;
  242. name[i] = p2;
  243. p2 = strchr(p2, '"');
  244. if (!p2)
  245. break;
  246. *p2 = 0;
  247. p2++;
  248. if (*p2 != ' ')
  249. break;
  250. p2++;
  251. if (*p2 != '"')
  252. break;
  253. p2++;
  254. p2 = strchr(p2, '"');
  255. if (!p2)
  256. break;
  257. p2++;
  258. if (*p2)
  259. p2++;
  260. topcolour[i] = atoi(p2);
  261. p2 = strchr(p2, ' ');
  262. if (!p2)
  263. break;
  264. p2++;
  265. bottomcolour[i] = atoi(p2);
  266. p2 = strchr(p2, ' ');
  267. if (p2)
  268. p2++;
  269. if (p2 && *p2 == '"')
  270. {
  271. p2++;
  272. team[i] = p2;
  273. p2 = strchr(p2, '"');
  274. if (!p2)
  275. break;
  276. *p2 = 0;
  277. }
  278. else
  279. team[i] = 0;
  280. if (strncmp(name[i], "\\s\\", 3) == 0)
  281. {
  282. numspectators++;
  283. spectator[i] = 1;
  284. time[i] = -time[i];
  285. name[i] += 3;
  286. }
  287. else
  288. {
  289. numplayers++;
  290. spectator[i] = 0;
  291. }
  292. #ifdef DEBUG
  293. printf("frags: %d time: %d ping: %d name: %s topcolour: %d bottomcolour: %d team: %s\n", frags[i], ping[i], time[i], name[i], topcolour[i], bottomcolour[i], team[i]);
  294. #endif
  295. if (name[i])
  296. extralength += strlen(name[i]) + 1;
  297. if (team[i])
  298. extralength += strlen(team[i]) + 1;
  299. datalen -= (p - (char *)data) + 1;
  300. data = (unsigned char *)(p + 1);
  301. i++;
  302. }
  303. qwplayers = malloc(sizeof(*qwplayers) * numplayers + sizeof(*qwspectators) * numspectators + extralength);
  304. if (qwplayers)
  305. {
  306. qwspectators = (struct QWSpectator *)(qwplayers + numplayers);
  307. p3 = (char *)(qwspectators + numspectators);
  308. j = 0;
  309. k = 0;
  310. for(i=0;i<numplayers+numspectators;i++)
  311. {
  312. if (spectator[i])
  313. {
  314. if (name[i])
  315. {
  316. strcpy(p3, name[i]);
  317. qwspectators[j].name = p3;
  318. p3 += strlen(name[i]) + 1;
  319. }
  320. else
  321. qwspectators[j].name = 0;
  322. if (team[i])
  323. {
  324. strcpy(p3, team[i]);
  325. qwspectators[j].team = p3;
  326. p3 += strlen(team[i]) + 1;
  327. }
  328. else
  329. qwspectators[j].team = 0;
  330. qwspectators[j].time = time[i];
  331. qwspectators[j].ping = ping[i];
  332. j++;
  333. }
  334. else
  335. {
  336. if (name[i])
  337. {
  338. strcpy(p3, name[i]);
  339. qwplayers[k].name = p3;
  340. p3 += strlen(name[i]) + 1;
  341. }
  342. else
  343. qwplayers[k].name = 0;
  344. if (team[i])
  345. {
  346. strcpy(p3, team[i]);
  347. qwplayers[k].team = p3;
  348. p3 += strlen(team[i]) + 1;
  349. }
  350. else
  351. qwplayers[k].team = 0;
  352. qwplayers[k].frags = frags[i];
  353. qwplayers[k].time = time[i];
  354. qwplayers[k].ping = ping[i];
  355. qwplayers[k].topcolor = topcolour[i];
  356. qwplayers[k].bottomcolor = bottomcolour[i];
  357. k++;
  358. }
  359. }
  360. qwserver->pub.players = qwplayers;
  361. qwserver->pub.numplayers = numplayers;
  362. qwserver->pub.spectators = qwspectators;
  363. qwserver->pub.numspectators = numspectators;
  364. }
  365. }
  366. static void ServerScanner_Thread_SendQWRequest(struct ServerScanner *serverscanner, struct qwserverpriv *qwserver)
  367. {
  368. static const char querystring[] = "\xff\xff\xff\xff" "status 23\n";
  369. qwserver->packetsendtime = Sys_IntTime();
  370. Sys_Net_Send(serverscanner->netdata, serverscanner->sockets[NA_IPV4], querystring, sizeof(querystring), &qwserver->pub.addr);
  371. if (qwserver->pub.status != QWSS_REQUESTSENT)
  372. {
  373. qwserver->pub.status = QWSS_REQUESTSENT;
  374. serverscanner->numqwserversscaninprogress++;
  375. qwserver->nextscaninprogress = serverscanner->qwserversscaninprogress;
  376. serverscanner->qwserversscaninprogress = qwserver;
  377. }
  378. }
  379. static void ServerScanner_Thread_SendQWPingRequest(struct ServerScanner *serverscanner, struct qwserverpriv *qwserver)
  380. {
  381. unsigned long long curtime;
  382. static const char querystring[] = "\xff\xff\xff\xff" "k";
  383. curtime = Sys_IntTime();
  384. qwserver->packetsendtime = curtime;
  385. Sys_Net_Send(serverscanner->netdata, serverscanner->sockets[NA_IPV4], querystring, sizeof(querystring), &qwserver->pub.addr);
  386. serverscanner->numqwserverspinginprogress++;
  387. qwserver->nextpinginprogress = serverscanner->qwserverspinginprogress;
  388. serverscanner->qwserverspinginprogress = qwserver;
  389. serverscanner->lastpingtime = curtime;
  390. }
  391. static void ServerScanner_Thread_HandlePacket(struct ServerScanner *serverscanner, unsigned char *data, unsigned int datalen, struct netaddr *addr)
  392. {
  393. struct qwserverpriv *qwserver;
  394. struct qwserverpriv *prevqwserver;
  395. unsigned int i;
  396. struct netaddr newaddr;
  397. if (datalen && data[0] == 'l')
  398. {
  399. prevqwserver = 0;
  400. qwserver = serverscanner->qwserverspinginprogress;
  401. while(qwserver)
  402. {
  403. if (NET_CompareAdr(&qwserver->pub.addr, addr))
  404. {
  405. Sys_Thread_LockMutex(serverscanner->mutex);
  406. qwserver->pub.pingtime = Sys_IntTime() - qwserver->packetsendtime;
  407. serverscanner->updated = 1;
  408. Sys_Thread_UnlockMutex(serverscanner->mutex);
  409. if (prevqwserver)
  410. prevqwserver->nextpinginprogress = qwserver->nextpinginprogress;
  411. else
  412. serverscanner->qwserverspinginprogress = qwserver->nextpinginprogress;
  413. qwserver->nextpinginprogress = 0;
  414. serverscanner->numqwserverspinginprogress--;
  415. return;
  416. }
  417. prevqwserver = qwserver;
  418. qwserver = qwserver->nextpinginprogress;
  419. }
  420. return;
  421. }
  422. if (datalen < 4 || data[0] != 255 || data[1] != 255 || data[2] != 255 || data[3] != 255)
  423. return;
  424. data += 4;
  425. datalen -= 4;
  426. for(i=0;i<serverscanner->nummasterservers;i++)
  427. {
  428. if (NET_CompareAdr(&serverscanner->masterservers[i].addr, addr))
  429. {
  430. if (datalen < 2 || data[0] != 'd' || data[1] != '\n')
  431. return;
  432. data += 2;
  433. datalen -= 2;
  434. if ((datalen%6) != 0)
  435. return;
  436. for(i=0;i<datalen;i+=6)
  437. {
  438. if (serverscanner->numqwservers > 10000)
  439. return;
  440. newaddr.type = NA_IPV4;
  441. newaddr.addr.ipv4.address[0] = data[i + 0];
  442. newaddr.addr.ipv4.address[1] = data[i + 1];
  443. newaddr.addr.ipv4.address[2] = data[i + 2];
  444. newaddr.addr.ipv4.address[3] = data[i + 3];
  445. newaddr.addr.ipv4.port = (data[i + 4]<<8)|data[i + 5];
  446. #warning Slow as fucking hell.
  447. qwserver = serverscanner->qwservers;
  448. while(qwserver)
  449. {
  450. if (NET_CompareAdr(&newaddr, &qwserver->pub.addr))
  451. break;
  452. qwserver = qwserver->next;
  453. }
  454. if (qwserver && NET_CompareAdr(&newaddr, &qwserver->pub.addr))
  455. {
  456. continue;
  457. }
  458. qwserver = malloc(sizeof(*qwserver));
  459. if (qwserver == 0)
  460. break;
  461. memset(qwserver, 0, sizeof(*qwserver));
  462. qwserver->pub.addr = newaddr;
  463. qwserver->pub.status = QWSS_WAITING;
  464. if (serverscanner->numqwserversscaninprogress < MAXCONCURRENTSCANS)
  465. {
  466. ServerScanner_Thread_SendQWRequest(serverscanner, qwserver);
  467. }
  468. else
  469. {
  470. qwserver->nextscanwaiting = serverscanner->qwserversscanwaiting;
  471. serverscanner->qwserversscanwaiting = qwserver;
  472. }
  473. Sys_Thread_LockMutex(serverscanner->mutex);
  474. qwserver->next = serverscanner->qwservers;
  475. serverscanner->qwservers = qwserver;
  476. serverscanner->numqwservers++;
  477. Sys_Thread_UnlockMutex(serverscanner->mutex);
  478. }
  479. Sys_Thread_LockMutex(serverscanner->mutex);
  480. serverscanner->updated = 1;
  481. Sys_Thread_UnlockMutex(serverscanner->mutex);
  482. return;
  483. }
  484. }
  485. prevqwserver = 0;
  486. qwserver = serverscanner->qwserversscaninprogress;
  487. while(qwserver)
  488. {
  489. if (NET_CompareAdr(&qwserver->pub.addr, addr) && qwserver->pub.status == QWSS_REQUESTSENT)
  490. {
  491. Sys_Thread_LockMutex(serverscanner->mutex);
  492. serverscanner->updated = 1;
  493. ServerScanner_Thread_ParseQWServerReply(serverscanner, qwserver, data, datalen);
  494. Sys_Thread_UnlockMutex(serverscanner->mutex);
  495. if (prevqwserver)
  496. prevqwserver->nextscaninprogress = qwserver->nextscaninprogress;
  497. else
  498. serverscanner->qwserversscaninprogress = qwserver->nextscaninprogress;
  499. qwserver->nextscaninprogress = 0;
  500. serverscanner->numqwserversscaninprogress--;
  501. qwserver->nextpingwaiting = serverscanner->qwserverspingwaiting;
  502. serverscanner->qwserverspingwaiting = qwserver;
  503. return;
  504. }
  505. prevqwserver = qwserver;
  506. qwserver = qwserver->nextscaninprogress;
  507. }
  508. }
  509. static void ServerScanner_Thread_CheckTimeout(struct ServerScanner *serverscanner)
  510. {
  511. struct qwserverpriv *qwserver;
  512. struct qwserverpriv *prevqwserver;
  513. unsigned long long curtime;
  514. curtime = Sys_IntTime();
  515. prevqwserver = 0;
  516. qwserver = serverscanner->qwserversscaninprogress;
  517. while(qwserver)
  518. {
  519. if (qwserver->packetsendtime + QWSERVERTIMEOUT <= curtime)
  520. {
  521. qwserver->pub.status = QWSS_FAILED;
  522. if (prevqwserver)
  523. prevqwserver->nextscaninprogress = qwserver->nextscaninprogress;
  524. else
  525. serverscanner->qwserversscaninprogress = qwserver->nextscaninprogress;
  526. serverscanner->numqwserversscaninprogress--;
  527. }
  528. else
  529. prevqwserver = qwserver;
  530. qwserver = qwserver->nextscaninprogress;
  531. }
  532. prevqwserver = 0;
  533. qwserver = serverscanner->qwserverspinginprogress;
  534. while(qwserver)
  535. {
  536. if (qwserver->packetsendtime + QWSERVERTIMEOUT <= curtime)
  537. {
  538. qwserver->pub.pingtime = 999999;
  539. if (prevqwserver)
  540. prevqwserver->nextpinginprogress = qwserver->nextpinginprogress;
  541. else
  542. serverscanner->qwserverspinginprogress = qwserver->nextpinginprogress;
  543. serverscanner->numqwserverspinginprogress--;
  544. }
  545. else
  546. prevqwserver = qwserver;
  547. qwserver = qwserver->nextpinginprogress;
  548. }
  549. }
  550. unsigned int ServerScanner_DoStuffInternal(struct ServerScanner *serverscanner)
  551. {
  552. struct qwserverpriv *qwserver;
  553. unsigned int i;
  554. unsigned long long curtime;
  555. unsigned int timeout;
  556. int r;
  557. unsigned char buf[8192];
  558. struct netaddr addr;
  559. if (serverscanner->status == SSS_ERROR || serverscanner->status == SSS_IDLE)
  560. return 50000;
  561. if (!serverscanner->initialstuffdone)
  562. {
  563. if (!ServerScanner_Thread_Init(serverscanner))
  564. {
  565. serverscanner->status = SSS_ERROR;
  566. return 50000;
  567. }
  568. ServerScanner_Thread_LookUpMasters(serverscanner);
  569. ServerScanner_Thread_OpenSockets(serverscanner);
  570. if (!serverscanner->numvalidmasterservers)
  571. {
  572. serverscanner->status = SSS_ERROR;
  573. return 50000;
  574. }
  575. serverscanner->starttime = Sys_IntTime();
  576. ServerScanner_Thread_QueryMasters(serverscanner);
  577. serverscanner->initialstuffdone = 1;
  578. }
  579. for(i=1;i<NA_NUMTYPES;i++)
  580. {
  581. if (!serverscanner->sockets[i])
  582. continue;
  583. while((r = Sys_Net_Receive(serverscanner->netdata, serverscanner->sockets[i], buf, sizeof(buf), &addr)) > 0)
  584. {
  585. ServerScanner_Thread_HandlePacket(serverscanner, buf, r, &addr);
  586. }
  587. }
  588. Sys_Thread_LockMutex(serverscanner->mutex);
  589. ServerScanner_Thread_CheckTimeout(serverscanner);
  590. if (serverscanner->status == SSS_SCANNING)
  591. {
  592. if (serverscanner->qwserversscanwaiting == 0 && serverscanner->qwserversscaninprogress == 0 && Sys_IntTime() > serverscanner->starttime + 2000000)
  593. {
  594. serverscanner->status = SSS_PINGING;
  595. }
  596. }
  597. if (serverscanner->status == SSS_PINGING)
  598. {
  599. if (serverscanner->qwserverspingwaiting == 0 && serverscanner->qwserverspinginprogress == 0)
  600. {
  601. if (serverscanner->qwserversscanwaiting)
  602. serverscanner->status = SSS_SCANNING;
  603. else
  604. serverscanner->status = SSS_IDLE;
  605. }
  606. }
  607. curtime = Sys_IntTime();
  608. #warning Needs to schedule servers for scanning
  609. while (serverscanner->status == SSS_SCANNING && serverscanner->numqwserversscaninprogress < MAXCONCURRENTSCANS && serverscanner->qwserversscanwaiting)
  610. {
  611. qwserver = serverscanner->qwserversscanwaiting;
  612. ServerScanner_Thread_SendQWRequest(serverscanner, qwserver);
  613. serverscanner->qwserversscanwaiting = qwserver->nextscanwaiting;
  614. qwserver->nextscanwaiting = 0;
  615. }
  616. while (serverscanner->status == SSS_PINGING && serverscanner->numqwserverspinginprogress < MAXCONCURRENTPINGS && serverscanner->qwserverspingwaiting && serverscanner->lastpingtime + PINGINTERVAL <= curtime)
  617. {
  618. qwserver = serverscanner->qwserverspingwaiting;
  619. ServerScanner_Thread_SendQWPingRequest(serverscanner, qwserver);
  620. serverscanner->qwserverspingwaiting = qwserver->nextpingwaiting;
  621. qwserver->nextpingwaiting = 0;
  622. }
  623. timeout = 50000;
  624. if (serverscanner->status == SSS_SCANNING)
  625. {
  626. qwserver = serverscanner->qwserversscaninprogress;
  627. while(qwserver)
  628. {
  629. if (qwserver->packetsendtime + QWSERVERTIMEOUT >= curtime && qwserver->packetsendtime + QWSERVERTIMEOUT - curtime < timeout)
  630. {
  631. timeout = qwserver->packetsendtime + QWSERVERTIMEOUT - curtime;
  632. }
  633. qwserver = qwserver->nextscaninprogress;
  634. }
  635. }
  636. else if (serverscanner->status == SSS_PINGING)
  637. {
  638. qwserver = serverscanner->qwserverspinginprogress;
  639. while(qwserver)
  640. {
  641. if (qwserver->packetsendtime + QWSERVERTIMEOUT >= curtime && qwserver->packetsendtime + QWSERVERTIMEOUT - curtime < timeout)
  642. {
  643. timeout = qwserver->packetsendtime + QWSERVERTIMEOUT - curtime;
  644. }
  645. qwserver = qwserver->nextpinginprogress;
  646. }
  647. if (serverscanner->qwserverspingwaiting && serverscanner->lastpingtime + PINGINTERVAL >= curtime)
  648. {
  649. if (serverscanner->lastpingtime + PINGINTERVAL - curtime < timeout)
  650. {
  651. timeout = serverscanner->lastpingtime + PINGINTERVAL - curtime;
  652. }
  653. }
  654. }
  655. Sys_Thread_UnlockMutex(serverscanner->mutex);
  656. return timeout;
  657. }
  658. static void ServerScanner_Thread(void *arg)
  659. {
  660. struct ServerScanner *serverscanner;
  661. unsigned int timeout;
  662. serverscanner = arg;
  663. while(!serverscanner->quit)
  664. {
  665. timeout = ServerScanner_DoStuffInternal(serverscanner);
  666. if (serverscanner->sockets[NA_IPV4])
  667. Sys_Net_Wait(serverscanner->netdata, serverscanner->sockets[NA_IPV4], timeout);
  668. else
  669. Sys_MicroSleep(timeout);
  670. }
  671. ServerScanner_Thread_CloseSockets(serverscanner);
  672. ServerScanner_Thread_Deinit(serverscanner);
  673. }
  674. struct ServerScanner *ServerScanner_Create(const char *masters)
  675. {
  676. struct ServerScanner *serverscanner;
  677. unsigned int nummasterservers;
  678. unsigned int i;
  679. const char *p;
  680. const char *p2;
  681. nummasterservers = 0;
  682. p = masters;
  683. while(*p)
  684. {
  685. p2 = strchr(p, ' ');
  686. if (p2 == 0)
  687. p2 = p + strlen(p);
  688. if (p2 != p)
  689. nummasterservers++;
  690. p = p2;
  691. if (*p)
  692. p++;
  693. }
  694. if (nummasterservers == 0)
  695. return 0;
  696. if (nummasterservers > 1000)
  697. return 0;
  698. serverscanner = malloc(sizeof(*serverscanner));
  699. if (serverscanner)
  700. {
  701. memset(serverscanner, 0, sizeof(*serverscanner));
  702. serverscanner->masterservers = malloc(sizeof(*serverscanner->masterservers)*nummasterservers);
  703. if (serverscanner->masterservers)
  704. {
  705. memset(serverscanner->masterservers, 0, sizeof(*serverscanner->masterservers)*nummasterservers);
  706. p = masters;
  707. for(i=0;i<nummasterservers;)
  708. {
  709. p2 = strchr(p, ' ');
  710. if (p2 == 0)
  711. p2 = p + strlen(p);
  712. if (p2 != p)
  713. {
  714. serverscanner->masterservers[i].hostname = malloc((p2 - p) + 1);
  715. if (serverscanner->masterservers[i].hostname == 0)
  716. break;
  717. memcpy(serverscanner->masterservers[i].hostname, p, p2 - p);
  718. serverscanner->masterservers[i].hostname[p2 - p] = 0;
  719. i++;
  720. }
  721. p = p2;
  722. if (*p)
  723. p++;
  724. }
  725. if (i == nummasterservers)
  726. {
  727. serverscanner->mutex = Sys_Thread_CreateMutex();
  728. if (serverscanner->mutex)
  729. {
  730. serverscanner->status = SSS_SCANNING;
  731. serverscanner->nummasterservers = nummasterservers;
  732. serverscanner->numvalidmasterservers = nummasterservers;
  733. serverscanner->thread = Sys_Thread_CreateThread(ServerScanner_Thread, serverscanner);
  734. #if 0
  735. if (serverscanner->thread)
  736. #endif
  737. return serverscanner;
  738. Sys_Thread_DeleteMutex(serverscanner->mutex);
  739. }
  740. }
  741. for(i=0;i<nummasterservers;i++)
  742. {
  743. free(serverscanner->masterservers[i].hostname);
  744. }
  745. }
  746. free(serverscanner);
  747. }
  748. return 0;
  749. }
  750. void ServerScanner_Delete(struct ServerScanner *serverscanner)
  751. {
  752. struct qwserverpriv *qwserver, *nextqwserver;
  753. unsigned int i;
  754. serverscanner->quit = 1;
  755. if (serverscanner->thread)
  756. Sys_Thread_DeleteThread(serverscanner->thread);
  757. else
  758. ServerScanner_Thread_CloseSockets(serverscanner);
  759. Sys_Thread_DeleteMutex(serverscanner->mutex);
  760. qwserver = serverscanner->qwservers;
  761. while(qwserver)
  762. {
  763. nextqwserver = qwserver->next;
  764. free((void *)qwserver->pub.map);
  765. free((void *)qwserver->pub.hostname);
  766. free((void *)qwserver->pub.players);
  767. free(qwserver);
  768. qwserver = nextqwserver;
  769. }
  770. for(i=0;i<serverscanner->nummasterservers;i++)
  771. {
  772. free(serverscanner->masterservers[i].hostname);
  773. }
  774. free(serverscanner->masterservers);
  775. free(serverscanner);
  776. }
  777. void ServerScanner_DoStuff(struct ServerScanner *serverscanner)
  778. {
  779. if (!serverscanner->thread)
  780. {
  781. ServerScanner_DoStuffInternal(serverscanner);
  782. }
  783. }
  784. int ServerScanner_DataUpdated(struct ServerScanner *serverscanner)
  785. {
  786. int ret;
  787. Sys_Thread_LockMutex(serverscanner->mutex);
  788. ret = serverscanner->updated;
  789. Sys_Thread_UnlockMutex(serverscanner->mutex);
  790. return ret;
  791. }
  792. const struct QWServer **ServerScanner_GetServers(struct ServerScanner *serverscanner, unsigned int *numservers)
  793. {
  794. struct qwserverpriv *qwserver;
  795. const struct QWServer **servers;
  796. unsigned int i;
  797. unsigned int count;
  798. servers = 0;
  799. Sys_Thread_LockMutex(serverscanner->mutex);
  800. if (serverscanner->numqwservers <= 10000)
  801. {
  802. servers = malloc(sizeof(*servers)*serverscanner->numqwservers);
  803. if (servers)
  804. {
  805. qwserver = serverscanner->qwservers;
  806. count = 0;
  807. for(i=0;i<serverscanner->numqwservers;i++)
  808. {
  809. if (qwserver->pub.status >= QWSS_DONE)
  810. {
  811. servers[count++] = &qwserver->pub;
  812. }
  813. qwserver = qwserver->next;
  814. }
  815. *numservers = count;
  816. serverscanner->updated = 0;
  817. }
  818. }
  819. Sys_Thread_UnlockMutex(serverscanner->mutex);
  820. return servers;
  821. }
  822. void ServerScanner_FreeServers(struct ServerScanner *serverscanner, const struct QWServer **servers)
  823. {
  824. free((void *)servers);
  825. }
  826. void ServerScanner_RescanServer(struct ServerScanner *serverscanner, const struct QWServer *server)
  827. {
  828. }
  829. enum ServerScannerStatus ServerScanner_GetStatus(struct ServerScanner *serverscanner)
  830. {
  831. return serverscanner->status;
  832. }
  833. #ifdef DEBUG
  834. int main()
  835. {
  836. unsigned int i;
  837. struct ServerScanner *serverscanner;
  838. const struct QWServer **servers;
  839. unsigned int numservers;
  840. unsigned int numplayers;
  841. unsigned int numspectators;
  842. unsigned int numup;
  843. unsigned int numdown;
  844. #if 1
  845. serverscanner = ServerScanner_Create("asgaard.morphos-team.net:27000 master.quakeservers.net:27000");
  846. #else
  847. serverscanner = ServerScanner_Create("127.0.0.1:27000");
  848. #endif
  849. if (serverscanner)
  850. {
  851. i = 0;
  852. while(ServerScanner_GetStatus(serverscanner) != SSS_IDLE)
  853. {
  854. i++;
  855. if (i == 20)
  856. {
  857. printf("Fail!\n");
  858. break;
  859. }
  860. printf("Waiting...\n");
  861. sleep(1);
  862. }
  863. printf("Done!\n");
  864. servers = ServerScanner_GetServers(serverscanner, &numservers);
  865. if (servers)
  866. {
  867. numplayers = 0;
  868. numspectators = 0;
  869. numup = 0;
  870. numdown = 0;
  871. for(i=0;i<numservers;i++)
  872. {
  873. if (servers[i]->status == QWSS_DONE)
  874. {
  875. numup++;
  876. numplayers += servers[i]->numplayers;
  877. numspectators += servers[i]->numspectators;
  878. }
  879. else
  880. {
  881. printf("%s is down\n", NET_AdrToString(&servers[i]->addr));
  882. numdown++;
  883. }
  884. }
  885. printf("%d servers, %d up, %d down, %d players, %d spectators\n", numservers, numup, numdown, numplayers, numspectators);
  886. ServerScanner_FreeServers(serverscanner, servers);
  887. }
  888. ServerScanner_Delete(serverscanner);
  889. }
  890. return 0;
  891. }
  892. #endif