d2gs.c
上传用户:tany51
上传日期:2013-06-12
资源大小:1397k
文件大小:11k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*
  2.  * Copyright (C) 2000,2001 Onlyer (onlyer@263.net)
  3.  *
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version 2
  7.  * of the License, or (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  17.  */
  18. #include "common/setup_before.h"
  19. #include "setup.h"
  20. #ifdef HAVE_STDDEF_H
  21. # include <stddef.h>
  22. #else
  23. # ifndef NULL
  24. #  define NULL ((void *)0)
  25. # endif
  26. #endif
  27. #ifdef STDC_HEADERS
  28. # include <stdlib.h>
  29. #else
  30. # ifdef HAVE_MALLOC_H
  31. #  include <malloc.h>
  32. # endif
  33. #endif
  34. #ifdef HAVE_STRING_H
  35. # include <string.h>
  36. #else
  37. # ifdef HAVE_STRINGS_H
  38. #  include <strings.h>
  39. # endif
  40. #endif
  41. #include "compat/strsep.h"
  42. #include "compat/char_bit.h"
  43. #ifdef HAVE_SYS_TYPES_H
  44. # include <sys/types.h> /* needed to include netinet/in.h */
  45. #endif
  46. #ifdef HAVE_SYS_SOCKET_H
  47. # include <sys/socket.h>
  48. #endif
  49. #include "compat/socket.h"
  50. #ifdef HAVE_SYS_PARAM_H
  51. # include <sys/param.h>
  52. #endif
  53. #ifdef HAVE_NETINET_IN_H
  54. # include <netinet/in.h>
  55. #endif
  56. #include "compat/netinet_in.h"
  57. #ifdef HAVE_ARPA_INET_H
  58. # include <arpa/inet.h> /* FIXME: probably not needed... do some systems put types in here or something? */
  59. #endif
  60. #ifdef TIME_WITH_SYS_TIME
  61. # include <sys/time.h>
  62. # include <time.h>
  63. #else
  64. # ifdef HAVE_SYS_TIME_H
  65. #  include <sys/time.h>
  66. # else
  67. #  include <time.h>
  68. # endif
  69. #endif
  70. #include "compat/psock.h"
  71. #include "d2gs.h"
  72. #include "game.h"
  73. #include "net.h"
  74. #include "bit.h"
  75. #include "prefs.h"
  76. #include "connection.h"
  77. #include "common/introtate.h"
  78. #include "common/addr.h"
  79. #include "common/list.h"
  80. #include "common/eventlog.h"
  81. #include "common/setup_after.h"
  82. static t_list * d2gslist_head=NULL;
  83. static unsigned int d2gs_id=0;
  84. static unsigned int total_d2gs=0;
  85. extern t_list * d2gslist(void)
  86. {
  87. return d2gslist_head;
  88. }
  89. extern int d2gslist_create(void)
  90. {
  91. if (!(d2gslist_head=list_create())) return -1;
  92. return d2gslist_reload(prefs_get_d2gs_list());
  93. }
  94. extern int d2gslist_reload(char const * gslist)
  95. {
  96. char * templist;
  97. char * s, * temp;
  98. t_d2gs * gs;
  99. unsigned int ip;
  100. unsigned int resolveipaddr;
  101. if (!d2gslist_head) return -1;
  102. BEGIN_LIST_TRAVERSE_DATA(d2gslist_head,gs)
  103. {
  104. BIT_CLR_FLAG(gs->flag, D2GS_FLAG_VALID);
  105. }
  106. END_LIST_TRAVERSE_DATA()
  107. /* FIXME: use addr.h addrlist code */
  108. if (!(templist=strdup(gslist))) return -1;
  109. temp=templist;
  110. while ((s=strsep(&temp, ","))) {
  111. host_lookup(s, &resolveipaddr);
  112. if ((ip=net_inet_addr(addr_num_to_ip_str(resolveipaddr)))==~0UL) {
  113. eventlog(eventlog_level_error,__FUNCTION__,"got bad ip address %s", addr_num_to_ip_str(resolveipaddr));
  114. continue;
  115. }
  116. if (!(gs=d2gslist_find_gs_by_ip(ntohl(ip)))) {
  117. gs=d2gs_create(addr_num_to_ip_str(resolveipaddr));
  118. }
  119. if (gs) BIT_SET_FLAG(gs->flag, D2GS_FLAG_VALID);
  120. }
  121. free(templist);
  122. BEGIN_LIST_TRAVERSE_DATA(d2gslist_head,gs)
  123. {
  124. if (!BIT_TST_FLAG(gs->flag, D2GS_FLAG_VALID)) {
  125. d2gs_destroy(gs);
  126. }
  127. }
  128. END_LIST_TRAVERSE_DATA()
  129. return 0;
  130. }
  131. extern int d2gslist_destroy(void)
  132. {
  133. t_d2gs * gs;
  134. BEGIN_LIST_TRAVERSE_DATA_CONST(d2gslist_head,gs)
  135. {
  136. d2gs_destroy(gs);
  137. }
  138. END_LIST_TRAVERSE_DATA_CONST()
  139. if (list_destroy(d2gslist_head)<0) {
  140. eventlog(eventlog_level_error,__FUNCTION__,"error destroy d2gs list");
  141. return -1;
  142. }
  143. d2gslist_head=NULL;
  144. return 0;
  145. }
  146. extern t_d2gs * d2gslist_find_gs_by_ip(unsigned int ip)
  147. {
  148. t_d2gs * gs;
  149. BEGIN_LIST_TRAVERSE_DATA_CONST(d2gslist_head,gs)
  150. {
  151. if (gs->ip==ip) return gs;
  152. }
  153. END_LIST_TRAVERSE_DATA_CONST()
  154. return NULL;
  155. }
  156. extern t_d2gs * d2gslist_find_gs(unsigned int id)
  157. {
  158. t_d2gs * gs;
  159. BEGIN_LIST_TRAVERSE_DATA_CONST(d2gslist_head,gs)
  160. {
  161. if (gs->id==id) return gs;
  162. }
  163. END_LIST_TRAVERSE_DATA_CONST()
  164. return NULL;
  165. }
  166. extern t_d2gs * d2gs_create(char const * ipaddr)
  167. {
  168. t_d2gs  * gs;
  169. unsigned int ip;
  170. ASSERT(ipaddr,NULL);
  171. if ((ip=net_inet_addr(ipaddr))==~0UL) {
  172. eventlog(eventlog_level_error,__FUNCTION__,"got bad ip address %s",ipaddr);
  173. return NULL;
  174. }
  175. if (d2gslist_find_gs_by_ip(ntohl(ip))) {
  176. eventlog(eventlog_level_error,__FUNCTION__,"game server %s already in list",ipaddr);
  177. return NULL;
  178. }
  179. if (!(gs=malloc(sizeof(t_d2gs)))) {;
  180. eventlog(eventlog_level_error,__FUNCTION__,"error allocate memory");
  181. return NULL;
  182. }
  183. gs->ip=ntohl(ip);
  184. gs->id=++d2gs_id;
  185. gs->active=0;
  186. gs->token=0;
  187. gs->state=d2gs_state_none;
  188. gs->gamenum=0;
  189. gs->maxgame=0;
  190. gs->connection=NULL;
  191. if (list_append_data(d2gslist_head,gs)<0) {
  192. eventlog(eventlog_level_error,__FUNCTION__,"error add gs to list");
  193. free(gs);
  194. return NULL;
  195. }
  196. eventlog(eventlog_level_info,__FUNCTION__,"added game server %s (id: %d) to list",ipaddr,gs->id);
  197. return gs;
  198. }
  199. extern int d2gs_destroy(t_d2gs * gs)
  200. {
  201. ASSERT(gs,-1);
  202. if (list_remove_data(d2gslist_head,gs)<0) {
  203. eventlog(eventlog_level_error,__FUNCTION__,"error remove gs from list");
  204. return -1;
  205. }
  206. if (gs->active && gs->connection) {
  207. d2cs_conn_set_state(gs->connection, conn_state_destroy);
  208. d2gs_deactive(gs, gs->connection);
  209. }
  210. eventlog(eventlog_level_info,__FUNCTION__,"removed game server %s (id: %d) from list",addr_num_to_ip_str(gs->ip),gs->id);
  211. free(gs);
  212. return 0;
  213. }
  214. extern t_d2gs * d2gslist_get_server_by_id(unsigned int id)
  215. {
  216. t_d2gs * gs;
  217. BEGIN_LIST_TRAVERSE_DATA_CONST(d2gslist_head,gs)
  218. {
  219. if (gs->id==id) return gs;
  220. }
  221. END_LIST_TRAVERSE_DATA_CONST()
  222. return NULL;
  223. }
  224.   
  225. extern t_d2gs * d2gslist_choose_server(void)
  226. {
  227. t_d2gs * gs;
  228. t_d2gs * ogs;
  229. unsigned int percent;
  230. unsigned int min_percent=100;
  231. ogs=NULL;
  232. BEGIN_LIST_TRAVERSE_DATA_CONST(d2gslist_head,gs)
  233. {
  234. if (!gs->active) continue;
  235. if (!gs->connection) continue;
  236. if (gs->state!=d2gs_state_authed) continue;
  237. if (!gs->maxgame) continue;
  238. if (gs->gamenum>=gs->maxgame) continue;
  239. percent=100*gs->gamenum/gs->maxgame;
  240. if (percent<min_percent) {
  241. min_percent=percent;
  242. ogs=gs;
  243. }
  244. }
  245. END_LIST_TRAVERSE_DATA_CONST()
  246. return ogs;
  247. }
  248. extern int d2gs_set_state(t_d2gs * gs, t_d2gs_state state)
  249. {
  250. ASSERT(gs,-1);
  251. gs->state=state;
  252. return 0;
  253. }
  254. extern t_d2gs_state d2gs_get_state(t_d2gs const * gs)
  255. {
  256. ASSERT(gs,d2gs_state_none);
  257. return gs->state;
  258. }
  259. extern int d2gs_add_gamenum(t_d2gs * gs, int number)
  260. {
  261. ASSERT(gs,-1);
  262. gs->gamenum += number;
  263. return 0;
  264. }
  265. extern unsigned int d2gs_get_gamenum(t_d2gs const * gs)
  266. {
  267. ASSERT(gs,0);
  268. return gs->gamenum;
  269. }
  270. extern int d2gs_set_maxgame(t_d2gs * gs,unsigned int maxgame)
  271. {
  272. ASSERT(gs,-1);
  273. gs->maxgame=maxgame;
  274. return 0;
  275. }
  276. extern unsigned int d2gs_get_maxgame(t_d2gs const * gs)
  277. {
  278. ASSERT(gs,0);
  279. return gs->maxgame;
  280. }
  281. extern unsigned int d2gs_get_id(t_d2gs const * gs)
  282. {
  283. ASSERT(gs,0);
  284. return gs->id;
  285. }
  286. extern unsigned int d2gs_get_ip(t_d2gs const * gs)
  287. {
  288. ASSERT(gs,0);
  289. return gs->ip;
  290. }
  291. extern unsigned int d2gs_get_token(t_d2gs const * gs)
  292. {
  293. return gs->token;
  294. }
  295. extern unsigned int d2gs_make_token(t_d2gs * gs)
  296. {
  297. return ((unsigned int)rand())^((++(gs->token))+((unsigned int)time(NULL)));
  298. }
  299. extern t_connection * d2gs_get_connection(t_d2gs const * gs)
  300. {
  301. ASSERT(gs,NULL);
  302. return gs->connection;
  303. }
  304. extern int d2gs_active(t_d2gs * gs, t_connection * c)
  305. {
  306. ASSERT(gs,-1);
  307. ASSERT(c,-1);
  308. if (gs->active && gs->connection) {
  309. eventlog(eventlog_level_warn,__FUNCTION__,"game server %d is already actived, deactive previous connection first",gs->id);
  310. d2gs_deactive(gs, gs->connection);
  311. }
  312. total_d2gs++;
  313. eventlog(eventlog_level_info,__FUNCTION__,"game server %s (id: %d) actived (%d total)",addr_num_to_addr_str(d2cs_conn_get_addr(c),
  314. d2cs_conn_get_port(c)),gs->id,total_d2gs);
  315. gs->state=d2gs_state_authed;
  316. gs->connection=c;
  317. gs->active=1;
  318. gs->gamenum=0;
  319. gs->maxgame=0;
  320. return 0;
  321. }
  322. extern int d2gs_deactive(t_d2gs * gs, t_connection * c)
  323. {
  324. t_game * game;
  325. ASSERT(gs,-1);
  326. if (!gs->active || !gs->connection) {
  327. eventlog(eventlog_level_warn,__FUNCTION__,"game server %d is not actived yet", gs->id);
  328. return -1;
  329. }
  330. if (gs->connection != c) {
  331. eventlog(eventlog_level_debug,__FUNCTION__,"game server %d connection mismatch,ignore it", gs->id);
  332. return 0;
  333. }
  334. total_d2gs--;
  335. eventlog(eventlog_level_info,__FUNCTION__,"game server %s (id: %d) deactived (%d left)",addr_num_to_addr_str(d2cs_conn_get_addr(gs->connection),d2cs_conn_get_port(gs->connection)),gs->id,total_d2gs);
  336. gs->state=d2gs_state_none;
  337. gs->connection=NULL;
  338. gs->active=0;
  339. gs->maxgame=0;
  340. eventlog(eventlog_level_info,__FUNCTION__,"destroying all games on game server %d",gs->id);
  341. BEGIN_LIST_TRAVERSE_DATA(d2cs_gamelist(),game)
  342. {
  343. if (game_get_d2gs(game)==gs) game_destroy(game);
  344. }
  345. END_LIST_TRAVERSE_DATA()
  346. if (gs->gamenum!=0) {
  347. eventlog(eventlog_level_error,__FUNCTION__,"game server %d deactived but still with games left",gs->id);
  348. }
  349. gs->gamenum=0;
  350. return 0;
  351. }
  352. extern unsigned int d2gs_calc_checksum(t_connection * c)
  353. {
  354. unsigned int sessionnum, checksum, port, addr;
  355. unsigned int i, len, ch;
  356. char const * realmname;
  357. char const * password;
  358. ASSERT(c,0);
  359. sessionnum=d2cs_conn_get_sessionnum(c);
  360. checksum=prefs_get_d2gs_checksum();
  361. port=d2cs_conn_get_port(c);
  362. addr=d2cs_conn_get_addr(c);
  363. realmname=prefs_get_realmname();
  364. password=prefs_get_d2gs_password();
  365. len=strlen(realmname);
  366. for (i=0; i<len ; i++) {
  367. ch = (unsigned int)(unsigned char) realmname[i];
  368. checksum ^= ROTL(sessionnum,i, sizeof(unsigned int) * CHAR_BIT);
  369. checksum ^= ROTL(port , ch, sizeof(unsigned int) * CHAR_BIT);
  370. }
  371. len=strlen(password);
  372. for (i=0; i<len ; i++) {
  373. ch = (unsigned int)(unsigned char) password[i];
  374. checksum ^= ROTL(sessionnum,i, sizeof(unsigned int) * CHAR_BIT);
  375. checksum ^= ROTL(port , ch, sizeof(unsigned int) * CHAR_BIT);
  376. }
  377. checksum ^= addr;
  378. return checksum;
  379. }
  380. extern int d2gs_keepalive(void)
  381. {
  382. t_packet * packet;
  383. t_d2gs * gs;
  384. if (!(packet=packet_create(packet_class_d2gs))) {
  385. eventlog(eventlog_level_error,__FUNCTION__,"error creating packet");
  386. return -1;
  387. }
  388. packet_set_size(packet,sizeof(t_d2cs_d2gs_echoreq));
  389. packet_set_type(packet,D2CS_D2GS_ECHOREQ);
  390.         /* FIXME: sequence number not set */
  391.         bn_int_set(&packet->u.d2cs_d2gs.h.seqno,0);       
  392. BEGIN_LIST_TRAVERSE_DATA(d2gslist_head,gs)
  393. {
  394. if (gs->active && gs->connection) {
  395. conn_push_outqueue(gs->connection,packet);
  396. }
  397. }
  398. END_LIST_TRAVERSE_DATA()
  399. packet_del_ref(packet);
  400. return 0;
  401. }
  402. extern int d2gs_restart_all_gs(void)
  403. {
  404. t_packet        * packet;
  405. t_d2gs          * gs;
  406. if (!(packet=packet_create(packet_class_d2gs))) {
  407.      eventlog(eventlog_level_error, __FUNCTION__, "error creating packet");
  408.      return -1;
  409.         }
  410.         packet_set_size(packet,sizeof(t_d2cs_d2gs_control));
  411.         packet_set_type(packet,D2CS_D2GS_CONTROL);
  412.         /* FIXME: sequence number not set */
  413.         bn_int_set(&packet->u.d2cs_d2gs.h.seqno,0);        
  414.         bn_int_set(&packet->u.d2cs_d2gs_control.cmd, D2CS_D2GS_CONTROL_CMD_RESTART);
  415.         bn_int_set(&packet->u.d2cs_d2gs_control.value, prefs_get_d2gs_restart_delay());
  416.         BEGIN_LIST_TRAVERSE_DATA(d2gslist_head,gs)
  417.         {
  418.      if (gs->connection) {
  419.                  conn_push_outqueue(gs->connection,packet);
  420.                 }
  421.         }
  422.         END_LIST_TRAVERSE_DATA()
  423.         packet_del_ref(packet);
  424.         return 0;
  425. }