1 /*
2  * Copyright (C) 2004 CreepLord (creeplord@pvpgn.org)
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 
19 #include "common/setup_before.h"
20 #ifdef HAVE_STRING_H
21 # include <string.h>
22 #else
23 # ifdef HAVE_STRINGS_H
24 #  include <strings.h>
25 # endif
26 # ifdef HAVE_MEMORY_H
27 #  include <memory.h>
28 # endif
29 #endif
30 #ifdef STDC_HEADERS
31 # include <stdlib.h>
32 #else
33 # ifdef HAVE_MALLOC_H
34 #  include <malloc.h>
35 # endif
36 #endif
37 
38 #ifdef WIN32
39 # include "compat/socket.h"	/* is this needed */
40 #endif
41 
42 #include "compat/strdup.h"
43 #include "common/packet.h"
44 #include "common/eventlog.h"
45 #include "common/tag.h"
46 #include "team.h"
47 #include "account.h"
48 #include "account_wrap.h"
49 #include "connection.h"
50 #include "common/queue.h"
51 #include "prefs.h"
52 #include "common/bn_type.h"
53 #include "common/list.h"
54 #include "common/addr.h"
55 #include "common/xalloc.h"
56 #include "versioncheck.h"
57 #include "anongame.h"
58 #include "tournament.h"
59 #include "timer.h"
60 #include "ladder.h"
61 #include "server.h"
62 #include "anongame_maplists.h"
63 #include "anongame_gameresult.h"
64 #include "common/trans.h"
65 #include "common/setup_after.h"
66 
67 #define MAX_LEVEL 100
68 
69 /* [quetzal] 20020827 - this one get modified by anongame_queue player when there're enough
70  * players and map has been chosen based on their preferences. otherwise its NULL
71  */
72 static char *mapname = NULL;
73 
74 static int players[ANONGAME_TYPES] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
75 static t_connection *player[ANONGAME_TYPES][ANONGAME_MAX_GAMECOUNT];
76 
77 /* [quetzal] 20020815 - queue to hold matching players */
78 static t_list *matchlists[ANONGAME_TYPES][MAX_LEVEL];
79 
80 long average_anongame_search_time = 30;
81 unsigned int anongame_search_count = 0;
82 
83 /**********************************************************************************/
84 static t_connection *_connlist_find_connection_by_uid(int uid);
85 static char const *_conn_get_versiontag(t_connection * c);
86 
87 static int _anongame_gametype_to_queue(int type, int gametype);
88 static int _anongame_level_by_queue(t_connection * c, int queue);
89 static char *_get_map_from_prefs(int queue, t_uint32 cur_prefs, t_clienttag clienttag);
90 static unsigned int _anongame_get_gametype_tab(int queue);
91 
92 static int _anongame_totalplayers(int queue);
93 static int _anongame_totalteams(int queue);
94 
95 static int _handle_anongame_search(t_connection * c, t_packet const *packet);
96 static int _anongame_queue(t_connection * c, int queue, t_uint32 map_prefs);
97 static int _anongame_compare_level(void const *a, void const *b);
98 static int _anongame_order_queue(int queue);
99 static int _anongame_match(t_connection * c, int queue);
100 static int _anongame_search_found(int queue);
101 /**********************************************************************************/
102 
_connlist_find_connection_by_uid(int uid)103 static t_connection *_connlist_find_connection_by_uid(int uid)
104 {
105     return connlist_find_connection_by_account(accountlist_find_account_by_uid(uid));
106 }
107 
_conn_get_versiontag(t_connection * c)108 static char const *_conn_get_versiontag(t_connection * c)
109 {
110     return versioncheck_get_versiontag(conn_get_versioncheck(c));
111 }
112 
113 /**********/
114 
_anongame_queue_to_string(int queue)115 static char const *_anongame_queue_to_string(int queue)
116 {
117     switch (queue) {
118 	case ANONGAME_TYPE_1V1:
119 	    return "PG 1v1";
120 	case ANONGAME_TYPE_2V2:
121 	    return "PG 2v2";
122 	case ANONGAME_TYPE_3V3:
123 	    return "PG 3v3";
124 	case ANONGAME_TYPE_4V4:
125 	    return "PG 4v4";
126 	case ANONGAME_TYPE_SMALL_FFA:
127 	    return "PG SFFA";
128 	case ANONGAME_TYPE_AT_2V2:
129 	    return "AT 2v2";
130 	case ANONGAME_TYPE_TEAM_FFA:
131 	    return "AT TFFA";
132 	case ANONGAME_TYPE_AT_3V3:
133 	    return "AT 3v3";
134 	case ANONGAME_TYPE_AT_4V4:
135 	    return "AT 4v4";
136 	case ANONGAME_TYPE_TY:
137 	    return "TOURNEY";
138 	case ANONGAME_TYPE_5V5:
139 	    return "PG 5v5";
140 	case ANONGAME_TYPE_6V6:
141 	    return "PG 6v6";
142 	case ANONGAME_TYPE_2V2V2:
143 	    return "PG 2v2v2";
144 	case ANONGAME_TYPE_3V3V3:
145 	    return "PG 3v3v3";
146 	case ANONGAME_TYPE_4V4V4:
147 	    return "PG 4v4v4";
148 	case ANONGAME_TYPE_2V2V2V2:
149 	    return "PG 2v2v2v2";
150 	case ANONGAME_TYPE_3V3V3V3:
151 	    return "PG 3v3v3v3";
152 	case ANONGAME_TYPE_AT_2V2V2:
153 	    return "AT 2v2v2";
154 	default:
155 	    eventlog(eventlog_level_error, __FUNCTION__, "invalid queue number %d", queue);
156 	    return "error";
157     }
158 }
159 
_anongame_gametype_to_queue(int type,int gametype)160 static int _anongame_gametype_to_queue(int type, int gametype)
161 {
162     switch (type) {
163 	case 0:		/* PG */
164 	    switch (gametype) {
165 		case 0:
166 		    return ANONGAME_TYPE_1V1;
167 		case 1:
168 		    return ANONGAME_TYPE_2V2;
169 		case 2:
170 		    return ANONGAME_TYPE_3V3;
171 		case 3:
172 		    return ANONGAME_TYPE_4V4;
173 		case 4:
174 		    return ANONGAME_TYPE_SMALL_FFA;
175 		case 5:
176 		    return ANONGAME_TYPE_5V5;
177 		case 6:
178 		    return ANONGAME_TYPE_6V6;
179 		case 7:
180 		    return ANONGAME_TYPE_2V2V2;
181 		case 8:
182 		    return ANONGAME_TYPE_3V3V3;
183 		case 9:
184 		    return ANONGAME_TYPE_4V4V4;
185 		case 10:
186 		    return ANONGAME_TYPE_2V2V2V2;
187 		case 11:
188 		    return ANONGAME_TYPE_3V3V3V3;
189 		default:
190 		    eventlog(eventlog_level_error, __FUNCTION__, "invalid PG game type: %d", gametype);
191 		    return -1;
192 	    }
193 	case 1:		/* AT */
194 	    switch (gametype) {
195 		case 0:
196 		    return ANONGAME_TYPE_AT_2V2;
197 		case 2:
198 		    return ANONGAME_TYPE_AT_3V3;
199 		case 3:
200 		    return ANONGAME_TYPE_AT_4V4;
201 		case 4:
202 		    return ANONGAME_TYPE_AT_2V2V2;
203 		default:
204 		    eventlog(eventlog_level_error, __FUNCTION__, "invalid AT game type: %d", gametype);
205 		    return -1;
206 	    }
207 	case 2:		/* TY */
208 	    return ANONGAME_TYPE_TY;
209 	default:
210 	    eventlog(eventlog_level_error, __FUNCTION__, "invalid type: %d", type);
211 	    return -1;
212     }
213 }
214 
_anongame_level_by_queue(t_connection * c,int queue)215 static int _anongame_level_by_queue(t_connection * c, int queue)
216 {
217     t_clienttag ct = conn_get_clienttag(c);
218 
219     switch (queue) {
220 	case ANONGAME_TYPE_1V1:
221 	    return account_get_ladder_level(conn_get_account(c), ct, ladder_id_solo);
222 	case ANONGAME_TYPE_2V2:
223 	case ANONGAME_TYPE_3V3:
224 	case ANONGAME_TYPE_4V4:
225 	case ANONGAME_TYPE_5V5:
226 	case ANONGAME_TYPE_6V6:
227 	case ANONGAME_TYPE_2V2V2:
228 	case ANONGAME_TYPE_3V3V3:
229 	case ANONGAME_TYPE_4V4V4:
230 	case ANONGAME_TYPE_2V2V2V2:
231 	case ANONGAME_TYPE_3V3V3V3:
232 	    return account_get_ladder_level(conn_get_account(c), ct, ladder_id_ffa);
233 	case ANONGAME_TYPE_SMALL_FFA:
234 	case ANONGAME_TYPE_TEAM_FFA:
235 	    return account_get_ladder_level(conn_get_account(c), ct, ladder_id_ffa);
236 	case ANONGAME_TYPE_AT_2V2:
237 	case ANONGAME_TYPE_AT_3V3:
238 	case ANONGAME_TYPE_AT_4V4:
239 	case ANONGAME_TYPE_AT_2V2V2:
240 	    return 0;
241 	case ANONGAME_TYPE_TY:	/* set to ((wins * 3) + ties - losses) ie. prelim score */
242 	    return tournament_get_player_score(conn_get_account(c));
243 	default:
244 	    eventlog(eventlog_level_error, __FUNCTION__, "unknown queue: %d", queue);
245 	    return -1;
246     }
247 }
248 
_get_map_from_prefs(int queue,t_uint32 cur_prefs,t_clienttag clienttag)249 static char *_get_map_from_prefs(int queue, t_uint32 cur_prefs, t_clienttag clienttag)
250 {
251     int i, j = 0;
252     char *default_map, *selected;
253     char *res_maps[32];
254     char clienttag_str[5];
255 
256     if (clienttag == CLIENTTAG_WARCRAFT3_UINT)
257 	default_map = "Maps\\(8)PlainsOfSnow.w3m";
258     else if (clienttag == CLIENTTAG_WAR3XP_UINT)
259 	default_map = "Maps\\(8)PlainsOfSnow.w3m";
260     else {
261 	eventlog(eventlog_level_error, __FUNCTION__, "invalid clienttag : %s", tag_uint_to_str(clienttag_str,clienttag));
262 	return "Maps\\(8)PlainsOfSnow.w3m";
263     }
264 
265     for (i = 0; i < 32; i++)
266 	res_maps[i] = NULL;
267 
268     for (i = 0; i < 32; i++) {
269 	if (cur_prefs & 1)
270 	    res_maps[j++] = maplists_get_map(queue, clienttag, i + 1);
271 	cur_prefs >>= 1;
272     }
273 
274     i = rand() % j;
275     if (res_maps[i])
276 	selected = res_maps[i];
277     else
278 	selected = default_map;
279 
280     eventlog(eventlog_level_trace, __FUNCTION__, "got map %s from prefs", selected);
281     return selected;
282 }
283 
_anongame_get_gametype_tab(int queue)284 static unsigned int _anongame_get_gametype_tab(int queue)
285 {
286     /* dizzy: this changed in 1.05 */
287     switch (queue) {
288 	case ANONGAME_TYPE_1V1:
289 	    return SERVER_ANONGAME_SOLO_STR;
290 	case ANONGAME_TYPE_2V2:
291 	case ANONGAME_TYPE_3V3:
292 	case ANONGAME_TYPE_4V4:
293 	case ANONGAME_TYPE_5V5:
294 	case ANONGAME_TYPE_6V6:
295 	case ANONGAME_TYPE_2V2V2:
296 	case ANONGAME_TYPE_3V3V3:
297 	case ANONGAME_TYPE_4V4V4:
298 	case ANONGAME_TYPE_2V2V2V2:
299 	case ANONGAME_TYPE_3V3V3V3:
300 	    return SERVER_ANONGAME_TEAM_STR;
301 	case ANONGAME_TYPE_SMALL_FFA:
302 	    return SERVER_ANONGAME_SFFA_STR;
303 	case ANONGAME_TYPE_TEAM_FFA:
304 	    return 0;		/* Team FFA is no longer supported */
305 	case ANONGAME_TYPE_AT_2V2:
306 	    return SERVER_ANONGAME_AT2v2_STR;
307 	case ANONGAME_TYPE_AT_3V3:
308 	    return SERVER_ANONGAME_AT3v3_STR;
309 	case ANONGAME_TYPE_AT_4V4:
310 	    return SERVER_ANONGAME_AT4v4_STR;
311 	case ANONGAME_TYPE_AT_2V2V2:
312 	    return SERVER_ANONGAME_AT2v2_STR;	/* fixme */
313 	case ANONGAME_TYPE_TY:
314 	    return SERVER_ANONGAME_TY_STR;
315 	default:
316 	    eventlog(eventlog_level_error, __FUNCTION__, "invalid queue (%d)", queue);
317 	    return 0;
318     }
319 }
320 
_anongame_totalplayers(int queue)321 static int _anongame_totalplayers(int queue)
322 {
323     switch (queue) {
324 	case ANONGAME_TYPE_1V1:
325 	    return 2;
326 	case ANONGAME_TYPE_2V2:
327 	case ANONGAME_TYPE_AT_2V2:
328 	case ANONGAME_TYPE_SMALL_FFA:	/* fixme: total players not always 4 */
329 	    return 4;
330 	case ANONGAME_TYPE_3V3:
331 	case ANONGAME_TYPE_AT_3V3:
332 	case ANONGAME_TYPE_2V2V2:
333 	case ANONGAME_TYPE_AT_2V2V2:
334 	    return 6;
335 	case ANONGAME_TYPE_4V4:
336 	case ANONGAME_TYPE_AT_4V4:
337 	case ANONGAME_TYPE_TEAM_FFA:
338 	case ANONGAME_TYPE_2V2V2V2:
339 	    return 8;
340 	case ANONGAME_TYPE_3V3V3:
341 	    return 9;
342 	case ANONGAME_TYPE_5V5:
343 	    return 10;
344 	case ANONGAME_TYPE_6V6:
345 	case ANONGAME_TYPE_4V4V4:
346 	case ANONGAME_TYPE_3V3V3V3:
347 	    return 12;
348 	case ANONGAME_TYPE_TY:
349 	    return tournament_get_totalplayers();
350 	default:
351 	    eventlog(eventlog_level_error, __FUNCTION__, "unknown queue: %d", queue);
352 	    return 0;
353     }
354 }
355 
_anongame_totalteams(int queue)356 static int _anongame_totalteams(int queue)
357 {
358 /* dont forget to change this if you make some game type with more teams */
359 #define ANONGAME_MAX_TEAMS	4
360     switch (queue) {
361 	case ANONGAME_TYPE_1V1:
362 	case ANONGAME_TYPE_SMALL_FFA:
363 	    return 0;
364 	case ANONGAME_TYPE_2V2:
365 	case ANONGAME_TYPE_3V3:
366 	case ANONGAME_TYPE_4V4:
367 	case ANONGAME_TYPE_5V5:
368 	case ANONGAME_TYPE_6V6:
369 	case ANONGAME_TYPE_AT_2V2:
370 	case ANONGAME_TYPE_AT_3V3:
371 	case ANONGAME_TYPE_AT_4V4:
372 	    return 2;
373 	case ANONGAME_TYPE_2V2V2:
374 	case ANONGAME_TYPE_3V3V3:
375 	case ANONGAME_TYPE_4V4V4:
376 	case ANONGAME_TYPE_AT_2V2V2:
377 	    return 3;
378 	case ANONGAME_TYPE_TEAM_FFA:	/* not even used */
379 	case ANONGAME_TYPE_2V2V2V2:
380 	case ANONGAME_TYPE_3V3V3V3:
381 	    return 4;
382 	case ANONGAME_TYPE_TY:
383 	    return 2;		/* fixme: does not support 2v2v2 - tournament_get_totalteams() */
384 	default:
385 	    eventlog(eventlog_level_error, __FUNCTION__, "unknown queue: %d", queue);
386 	    return 0;
387     }
388 }
389 
390 /**********/
_handle_anongame_search(t_connection * c,t_packet const * packet)391 static int _handle_anongame_search(t_connection * c, t_packet const *packet)
392 {
393     int i, j, temp, set = 1;
394     t_packet *rpacket;
395     t_connection *tc[6];
396     t_anongame *a, *ta;
397     t_uint8 teamsize = 0;
398     t_uint8 option = bn_byte_get(packet->u.client_findanongame.option);
399 
400     if (!(a = conn_get_anongame(c))) {
401 	if (!(a = conn_create_anongame(c))) {
402 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] conn_create_anongame failed", conn_get_socket(c));
403 	    return -1;
404 	}
405     }
406 
407     conn_set_anongame_search_starttime(c, now);
408 
409     switch (option) {
410 	case CLIENT_FINDANONGAME_AT_INVITER_SEARCH:
411 	    a->count = bn_int_get(packet->u.client_findanongame_at_inv.count);
412 	    a->id = bn_int_get(packet->u.client_findanongame_at_inv.id);
413 	    a->tid = bn_int_get(packet->u.client_findanongame_at_inv.tid);
414 	    a->race = bn_int_get(packet->u.client_findanongame_at_inv.race);
415 	    a->map_prefs = bn_int_get(packet->u.client_findanongame_at_inv.map_prefs);
416 	    a->type = bn_byte_get(packet->u.client_findanongame_at_inv.type);
417 	    a->gametype = bn_byte_get(packet->u.client_findanongame_at_inv.gametype);
418 	    teamsize = bn_byte_get(packet->u.client_findanongame_at_inv.teamsize);
419 	    break;
420 	case CLIENT_FINDANONGAME_AT_SEARCH:
421 	    a->count = bn_int_get(packet->u.client_findanongame_at.count);
422 	    a->id = bn_int_get(packet->u.client_findanongame_at.id);
423 	    a->tid = bn_int_get(packet->u.client_findanongame_at.tid);
424 	    a->race = bn_int_get(packet->u.client_findanongame_at.race);
425 	    teamsize = bn_byte_get(packet->u.client_findanongame_at.teamsize);
426 	    break;
427 	case CLIENT_FINDANONGAME_SEARCH:
428 	    a->count = bn_int_get(packet->u.client_findanongame.count);
429 	    a->id = bn_int_get(packet->u.client_findanongame.id);
430 	    a->race = bn_int_get(packet->u.client_findanongame.race);
431 	    a->map_prefs = bn_int_get(packet->u.client_findanongame.map_prefs);
432 	    a->type = bn_byte_get(packet->u.client_findanongame.type);
433 	    a->gametype = bn_byte_get(packet->u.client_findanongame.gametype);
434 	    break;
435 	default:
436 	    eventlog(eventlog_level_error, __FUNCTION__, "invalid search option (%d)", option);
437 	    return -1;
438     }
439 
440     if (option != CLIENT_FINDANONGAME_AT_SEARCH)
441 	if ((a->queue = _anongame_gametype_to_queue(a->type, a->gametype)) < 0) {
442 	    eventlog(eventlog_level_error, __FUNCTION__, "invalid queue: %d", a->queue);
443 	    return -1;
444 	}
445 
446     account_set_w3pgrace(conn_get_account(c), conn_get_clienttag(c), a->race);
447 
448     /* send search reply to client */
449     if (!(rpacket = packet_create(packet_class_bnet)))
450 	return -1;
451     packet_set_size(rpacket, sizeof(t_server_anongame_search_reply));
452     packet_set_type(rpacket, SERVER_ANONGAME_SEARCH_REPLY);
453     bn_byte_set(&rpacket->u.server_anongame_search_reply.option, SERVER_FINDANONGAME_SEARCH);
454     bn_int_set(&rpacket->u.server_anongame_search_reply.count, a->count);
455     bn_int_set(&rpacket->u.server_anongame_search_reply.reply, 0);
456     temp = (int) average_anongame_search_time;
457     packet_append_data(rpacket, &temp, 2);
458     conn_push_outqueue(c, rpacket);
459     packet_del_ref(rpacket);
460     /* end search reply */
461 
462     switch (option) {
463 	case CLIENT_FINDANONGAME_AT_INVITER_SEARCH:
464 	    for (i = 0; i < teamsize; i++) {	/* assign player conns to tc[] array */
465 		if (!(tc[i] = _connlist_find_connection_by_uid(bn_int_get(packet->u.client_findanongame_at_inv.info[i])))) {
466 		    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got NULL connection", conn_get_socket(tc[i]));
467 		    return -1;
468 		}
469 	    }
470 	    for (i = 0; i < teamsize; i++) {	/* assign info from inviter to other team players */
471 		if (!(ta = conn_get_anongame(tc[i]))) {
472 		    if (!(ta = conn_create_anongame(tc[i]))) {
473 			eventlog(eventlog_level_error, __FUNCTION__, "[%d] conn_create_anongame failed", conn_get_socket(tc[i]));
474 			return -1;
475 		    }
476 		}
477 		for (j = 0; j < teamsize; j++)	/* add each players conn to each anongame struct */
478 		    ta->tc[j] = tc[j];
479 
480 		ta->type = a->type;
481 		ta->gametype = a->gametype;
482 		ta->queue = a->queue;
483 		ta->map_prefs = a->map_prefs;
484 
485 		if (ta->tid != a->tid)
486 		    set = 0;
487 	    }
488 	    if (!set)		/* check if search packet has been recieved from each team member */
489 		return 0;
490 	    break;
491 	case CLIENT_FINDANONGAME_AT_SEARCH:
492 	    for (i = 0; i < teamsize; i++) {	/* assign player conns to tc[] array */
493 		if (!(tc[i] = _connlist_find_connection_by_uid(bn_int_get(packet->u.client_findanongame_at.info[i])))) {
494 		    eventlog(eventlog_level_error, __FUNCTION__, "[%d] got NULL connection", conn_get_socket(tc[i]));
495 		    return -1;
496 		}
497 	    }
498 	    for (i = 0; i < teamsize; i++) {	/* check if search packet has been recieved from each team member */
499 		if (!(ta = conn_get_anongame(tc[i])))
500 		    return 0;
501 		if (ta->tid != a->tid)
502 		    return 0;
503 	    }
504 	    break;
505 	case CLIENT_FINDANONGAME_SEARCH:
506 	    tc[0] = c;
507 	    a->tc[0] = c;
508 	    break;
509 	default:
510 	    eventlog(eventlog_level_error, __FUNCTION__, "invalid search option (%d)", option);
511 	    return -1;
512     }
513 
514     if (_anongame_queue(tc[0], a->queue, a->map_prefs) < 0) {
515 	eventlog(eventlog_level_error, __FUNCTION__, "queue failed");
516 	return -1;
517     }
518 
519     _anongame_match(c, a->queue);
520 
521     /* if enough players are queued send found packet */
522     if (players[a->queue] == _anongame_totalplayers(a->queue))
523 	if (_anongame_search_found(a->queue) < 0)
524 	    return -1;
525 
526     return 0;
527 }
528 
_anongame_queue(t_connection * c,int queue,t_uint32 map_prefs)529 static int _anongame_queue(t_connection * c, int queue, t_uint32 map_prefs)
530 {
531     int level;
532     t_matchdata *md;
533 
534     if (!c) {
535 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL connection");
536     }
537 
538     if (queue >= ANONGAME_TYPES) {
539 	eventlog(eventlog_level_error, __FUNCTION__, "unknown queue: %d", queue);
540 	return -1;
541     }
542 
543     level = _anongame_level_by_queue(c, queue);
544 
545     if (!matchlists[queue][level])
546 	matchlists[queue][level] = list_create();
547 
548     md = xmalloc(sizeof(t_matchdata));
549     md->c = c;
550     md->map_prefs = map_prefs;
551     md->versiontag = _conn_get_versiontag(c);
552 
553     list_append_data(matchlists[queue][level], md);
554 
555     return 0;
556 }
557 
_anongame_compare_level(void const * a,void const * b)558 static int _anongame_compare_level(void const *a, void const *b)
559 {
560     t_connection *ca = *(t_connection * const *) a;
561     t_connection *cb = *(t_connection * const *) b;
562 
563     int level_a = _anongame_level_by_queue(ca, anongame_get_queue(conn_get_anongame(ca)));
564     int level_b = _anongame_level_by_queue(cb, anongame_get_queue(conn_get_anongame(cb)));
565 
566     return (level_a > level_b) ? -1 : ((level_a < level_b) ? 1 : 0);
567 }
568 
_anongame_order_queue(int queue)569 static int _anongame_order_queue(int queue)
570 {
571     if (_anongame_totalteams(queue) != 0 && !anongame_arranged(queue)) {	/* no need to reorder 1v1, sffa, or AT queues */
572 	int i, j;
573 	t_connection *temp;
574 	int level[ANONGAME_MAX_TEAMS];
575 	int teams = _anongame_totalteams(queue);	/* number of teams */
576 	int ppt = players[queue] / teams;	/* players per team */
577 
578 	for (i = 0; i < ANONGAME_MAX_TEAMS; i++)
579 	    level[i] = 0;
580 
581 	for (i = 0; i < ppt - 1; i++) {	/* loop through the number of players per team */
582 	    for (j = 0; j < teams; j++) {
583 		level[j] = level[j] + _anongame_level_by_queue(player[queue][i * ppt + j], queue);
584 	    }
585 
586 	    if (teams == 2) {
587 		/* 1 >= 2 */
588 		if (level[i * teams] >= level[i * teams + 1]) {
589 		    temp = player[queue][(i + 1) * teams];
590 		    player[queue][(i + 1) * teams] = player[queue][(i + 1) * teams + 1];
591 		    player[queue][(i + 1) * teams + 1] = temp;
592 		}
593 		/* 2 >= 1 */
594 		else if (level[i * teams + 1] >= level[i * teams]) {
595 		    ;		/* nothing to do */
596 		}
597 	    }
598 	    /* end 2 teams */
599 	    else if (teams == 3) {
600 		/* 1 >= 2 >= 3 */
601 		if (level[i * 3] >= level[i * 3 + 1] && level[i * 3 + 1] >= level[i * 3 + 2]) {
602 		    temp = player[queue][(i + 1) * 3];
603 		    player[queue][(i + 1) * 3] = player[queue][(i + 1) * 3 + 2];
604 		    player[queue][(i + 1) * 3 + 2] = temp;
605 		}
606 		/* 1 >= 3 >= 2 */
607 		else if (level[i * 3] >= level[i * 3 + 2] && level[i * 3 + 2] >= level[i * 3 + 1]) {
608 		    temp = player[queue][(i + 1) * 3];
609 		    player[queue][(i + 1) * 3] = player[queue][(i + 1) * 3 + 2];
610 		    player[queue][(i + 1) * 3 + 2] = player[queue][(i + 1) * 3 + 1];
611 		    player[queue][(i + 1) * 3 + 1] = temp;
612 		}
613 		/* 2 >= 1 >= 3 */
614 		else if (level[i * 3 + 1] >= level[i * 3] && level[i * 3] >= level[i * 3 + 2]) {
615 		    temp = player[queue][(i + 1) * 3];
616 		    player[queue][(i + 1) * 3] = player[queue][(i + 1) * 3 + 1];
617 		    player[queue][(i + 1) * 3 + 1] = player[queue][(i + 1) * 3 + 2];
618 		    player[queue][(i + 1) * 3 + 2] = temp;
619 		}
620 		/* 2 >= 3 >= 1 */
621 		else if (level[i * 3 + 1] >= level[i * 3 + 2] && level[i * 3 + 2] >= level[i * 3]) {
622 		    temp = player[queue][(i + 1) * 3 + 1];
623 		    player[queue][(i + 1) * 3 + 1] = player[queue][(i + 1) * 3 + 2];
624 		    player[queue][(i + 1) * 3 + 2] = temp;
625 		}
626 		/* 3 >= 1 >= 2 */
627 		else if (level[i * 3 + 2] >= level[i * 3] && level[i * 3] >= level[i * 3 + 1]) {
628 		    temp = player[queue][(i + 1) * 3];
629 		    player[queue][(i + 1) * 3] = player[queue][(i + 1) * 3 + 1];
630 		    player[queue][(i + 1) * 3 + 1] = temp;
631 		}
632 		/* 3 >= 2 >= 1 */
633 		else if (level[i * 3 + 2] >= level[i * 3 + 1] && level[i * 3 + 1] >= level[i * 3]) {
634 		    ;		/* nothing to do */
635 		}
636 	    }
637 	    /* end 3 teams */
638 	    else if (teams == 4) {
639 		/* 1234 */
640 		if (level[i * 4] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4 + 3]) {
641 		    temp = player[queue][(i + 1) * 4];
642 		    player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 3];
643 		    player[queue][(i + 1) * 4 + 3] = temp;
644 		    temp = player[queue][(i + 1) * 4 + 1];
645 		    player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 2];
646 		    player[queue][(i + 1) * 4 + 2] = temp;
647 		}
648 		/* 1243 */
649 		else if (level[i * 4] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4 + 2] && level[i * 4 + 3] >= level[i * 4 + 2]) {
650 		    temp = player[queue][(i + 1) * 4];
651 		    player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 3];
652 		    player[queue][(i + 1) * 4 + 3] = player[queue][(i + 1) * 4 + 1];
653 		    player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 2];
654 		    player[queue][(i + 1) * 4 + 2] = temp;
655 		}
656 		/* 1324 */
657 		else if (level[i * 4] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4 + 3]) {
658 		    temp = player[queue][(i + 1) * 4];
659 		    player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 3];
660 		    player[queue][(i + 1) * 4 + 3] = temp;
661 		}
662 		/* 1342 */
663 		else if (level[i * 4] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4 + 1]) {
664 		    temp = player[queue][(i + 1) * 4];
665 		    player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 3];
666 		    player[queue][(i + 1) * 4 + 3] = player[queue][(i + 1) * 4 + 1];
667 		    player[queue][(i + 1) * 4 + 1] = temp;
668 		}
669 		/* 1423 */
670 		else if (level[i * 4] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4 + 2]) {
671 		    temp = player[queue][(i + 1) * 4];
672 		    player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 3];
673 		    player[queue][(i + 1) * 4 + 3] = player[queue][(i + 1) * 4 + 2];
674 		    player[queue][(i + 1) * 4 + 2] = temp;
675 		}
676 		/* 1432 */
677 		else if (level[i * 4] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4 + 1]) {
678 		    temp = player[queue][(i + 1) * 4];
679 		    player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 3];
680 		    player[queue][(i + 1) * 4 + 3] = player[queue][(i + 1) * 4 + 2];
681 		    player[queue][(i + 1) * 4 + 2] = player[queue][(i + 1) * 4 + 1];
682 		    player[queue][(i + 1) * 4 + 1] = temp;
683 		}
684 		/* 2134 */
685 		else if (level[i * 4 + 1] >= level[i * 4] && level[i * 4] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4 + 3]) {
686 		    temp = player[queue][(i + 1) * 4];
687 		    player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 2];
688 		    player[queue][(i + 1) * 4 + 2] = player[queue][(i + 1) * 4 + 1];
689 		    player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 3];
690 		    player[queue][(i + 1) * 4 + 3] = temp;
691 		}
692 		/* 2143 */
693 		else if (level[i * 4 + 1] >= level[i * 4] && level[i * 4] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4 + 2]) {
694 		    temp = player[queue][(i + 1) * 4];
695 		    player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 2];
696 		    player[queue][(i + 1) * 4 + 2] = temp;
697 		    temp = player[queue][(i + 1) * 4 + 1];
698 		    player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 3];
699 		    player[queue][(i + 1) * 4 + 3] = temp;
700 		}
701 		/* 2314 */
702 		else if (level[i * 4 + 1] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4] && level[i * 4] >= level[i * 4 + 3]) {
703 		    temp = player[queue][(i + 1) * 4];
704 		    player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 3];
705 		    player[queue][(i + 1) * 4 + 3] = player[queue][(i + 1) * 4 + 1];
706 		    player[queue][(i + 1) * 4 + 1] = temp;
707 		}
708 		/* 2341 */
709 		else if (level[i * 4 + 1] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4]) {
710 		    temp = player[queue][(i + 1) * 4 + 1];
711 		    player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 2];
712 		    player[queue][(i + 1) * 4 + 2] = player[queue][(i + 1) * 4 + 3];
713 		    player[queue][(i + 1) * 4 + 3] = temp;
714 		}
715 		/* 2413 */
716 		else if (level[i * 4 + 1] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4] && level[i * 4] >= level[i * 4 + 2]) {
717 		    temp = player[queue][(i + 1) * 4];
718 		    player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 1];
719 		    player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 3];
720 		    player[queue][(i + 1) * 4 + 3] = player[queue][(i + 1) * 4 + 2];
721 		    player[queue][(i + 1) * 4 + 2] = temp;
722 		}
723 		/* 2431 */
724 		else if (level[i * 4 + 1] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4]) {
725 		    temp = player[queue][(i + 1) * 4 + 1];
726 		    player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 3];
727 		    player[queue][(i + 1) * 4 + 3] = player[queue][(i + 1) * 4 + 2];
728 		    player[queue][(i + 1) * 4 + 2] = temp;
729 		}
730 		/* 3124 */
731 		else if (level[i * 4 + 2] >= level[i * 4] && level[i * 4] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4 + 3]) {
732 		    temp = player[queue][(i + 1) * 4];
733 		    player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 2];
734 		    player[queue][(i + 1) * 4 + 2] = player[queue][(i + 1) * 4 + 3];
735 		    player[queue][(i + 1) * 4 + 3] = temp;
736 		}
737 		/* 3142 */
738 		else if (level[i * 4 + 2] >= level[i * 4] && level[i * 4] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4 + 1]) {
739 		    temp = player[queue][(i + 1) * 4];
740 		    player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 2];
741 		    player[queue][(i + 1) * 4 + 2] = player[queue][(i + 1) * 4 + 3];
742 		    player[queue][(i + 1) * 4 + 3] = player[queue][(i + 1) * 4 + 1];
743 		    player[queue][(i + 1) * 4 + 1] = temp;
744 		}
745 		/* 3214 */
746 		else if (level[i * 4 + 2] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4] && level[i * 4] >= level[i * 4 + 3]) {
747 		    temp = player[queue][(i + 1) * 4];
748 		    player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 1];
749 		    player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 2];
750 		    player[queue][(i + 1) * 4 + 2] = player[queue][(i + 1) * 4 + 3];
751 		    player[queue][(i + 1) * 4 + 3] = temp;
752 		}
753 		/* 3241 */
754 		else if (level[i * 4 + 2] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4]) {
755 		    temp = player[queue][(i + 1) * 4 + 1];
756 		    player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 2];
757 		    player[queue][(i + 1) * 4 + 2] = player[queue][(i + 1) * 4 + 3];
758 		    player[queue][(i + 1) * 4 + 3] = temp;
759 		}
760 		/* 3412 */
761 		else if (level[i * 4 + 2] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4] && level[i * 4] >= level[i * 4 + 1]) {
762 		    temp = player[queue][(i + 1) * 4];
763 		    player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 1];
764 		    player[queue][(i + 1) * 4 + 1] = temp;
765 		    temp = player[queue][(i + 1) * 4 + 2];
766 		    player[queue][(i + 1) * 4 + 2] = player[queue][(i + 1) * 4 + 3];
767 		    player[queue][(i + 1) * 4 + 3] = temp;
768 		}
769 		/* 3421 */
770 		else if (level[i * 4 + 2] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4]) {
771 		    temp = player[queue][(i + 1) * 4 + 2];
772 		    player[queue][(i + 1) * 4 + 2] = player[queue][(i + 1) * 4 + 3];
773 		    player[queue][(i + 1) * 4 + 3] = temp;
774 		}
775 		/* 4123 */
776 		else if (level[i * 4 + 3] >= level[i * 4] && level[i * 4] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4 + 2]) {
777 		    temp = player[queue][(i + 1) * 4];
778 		    player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 2];
779 		    player[queue][(i + 1) * 4 + 2] = temp;
780 		}
781 		/* 4132 */
782 		else if (level[i * 4 + 3] >= level[i * 4] && level[i * 4] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4 + 1]) {
783 		    temp = player[queue][(i + 1) * 4];
784 		    player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 2];
785 		    player[queue][(i + 1) * 4 + 2] = player[queue][(i + 1) * 4 + 1];
786 		    player[queue][(i + 1) * 4 + 1] = temp;
787 		}
788 		/* 4213 */
789 		else if (level[i * 4 + 3] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4] && level[i * 4] >= level[i * 4 + 2]) {
790 		    temp = player[queue][(i + 1) * 4];
791 		    player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 1];
792 		    player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 2];
793 		    player[queue][(i + 1) * 4 + 2] = temp;
794 		}
795 		/* 4231 */
796 		else if (level[i * 4 + 3] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4]) {
797 		    temp = player[queue][(i + 1) * 4 + 1];
798 		    player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 2];
799 		    player[queue][(i + 1) * 4 + 2] = temp;
800 		}
801 		/* 4312 */
802 		else if (level[i * 4 + 3] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4] && level[i * 4] >= level[i * 4 + 1]) {
803 		    temp = player[queue][(i + 1) * 4];
804 		    player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 1];
805 		    player[queue][(i + 1) * 4 + 1] = temp;
806 		}
807 		/* 4321 */
808 		else if (level[i * 4 + 3] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4]) {
809 		    ;		/* nothing to do */
810 		}
811 	    }			/* end 4 teams */
812 	}			/* end ppt loop */
813     }				/* end "if" statement */
814     return 0;
815 }
816 
_anongame_match(t_connection * c,int queue)817 static int _anongame_match(t_connection * c, int queue)
818 {
819     int level = _anongame_level_by_queue(c, queue);
820     int delta = 0;
821     int i;
822     t_matchdata *md;
823     t_elem *curr;
824     int diff;
825     t_anongame *a = conn_get_anongame(c);
826     t_uint32 cur_prefs = a->map_prefs;
827     t_connection *inv_c[ANONGAME_MAX_TEAMS];
828     int maxlevel, minlevel;
829     int teams = 0;
830     players[queue] = 0;
831 
832     eventlog(eventlog_level_trace, __FUNCTION__, "[%d] matching started for level %d player in queue %d", conn_get_socket(c), level, queue);
833 
834     diff = war3_get_maxleveldiff();
835     maxlevel = level + diff;
836     minlevel = (level - diff < 0) ? 0 : level - diff;
837 
838     while (abs(delta) < (diff + 1)) {
839 	if ((level + delta <= maxlevel) && (level + delta >= minlevel)) {
840 	    eventlog(eventlog_level_trace, __FUNCTION__, "Traversing level %d players", level + delta);
841 
842 	    LIST_TRAVERSE(matchlists[queue][level + delta], curr) {
843 		md = elem_get_data(curr);
844 		if (md->versiontag && _conn_get_versiontag(c) && !strcmp(md->versiontag, _conn_get_versiontag(c)) && (cur_prefs & md->map_prefs)) {
845 		    /* set maxlevel and minlevel to keep all players within 6 levels */
846 		    maxlevel = (level + delta + diff < maxlevel) ? level + delta + diff : maxlevel;
847 		    minlevel = (level + delta - diff > minlevel) ? level + delta - diff : minlevel;
848 		    cur_prefs &= md->map_prefs;
849 
850 		    /* AT match */
851 		    if (anongame_arranged(queue)) {
852 
853 			/* set the inv_c for unqueueing later */
854 			inv_c[teams] = md->c;
855 
856 			a = conn_get_anongame(md->c);
857 
858 			/* add all the players on the team to player[][] */
859 			for (i = 0; i < _anongame_totalplayers(queue) / _anongame_totalteams(queue); i++) {
860 			    player[queue][teams + i * _anongame_totalteams(queue)] = a->tc[i];
861 			    players[queue]++;
862 			}
863 			teams++;
864 
865 			/* check for enough players */
866 			if (players[queue] == _anongame_totalplayers(queue)) {
867 
868 			    /* unqueue just the single team entry */
869 			    for (i = 0; i < teams; i++)
870 				anongame_unqueue(inv_c[i], queue);
871 
872 			    mapname = _get_map_from_prefs(queue, cur_prefs, conn_get_clienttag(c));
873 			    return 0;
874 			}
875 
876 			/* PG match */
877 		    } else {
878 			player[queue][players[queue]++] = md->c;
879 
880 			if (players[queue] == _anongame_totalplayers(queue)) {
881 			    /* first sort queue by level */
882 			    qsort(player[queue], players[queue], sizeof(t_connection *), _anongame_compare_level);
883 			    /* next call reodering function */
884 			    _anongame_order_queue(queue);
885 			    /* unqueue players */
886 			    for (i = 0; i < players[queue]; i++)
887 				anongame_unqueue(player[queue][i], queue);
888 
889 			    mapname = _get_map_from_prefs(queue, cur_prefs, conn_get_clienttag(c));
890 			    return 0;
891 			}
892 		    }
893 		}
894 	    }
895 	}
896 
897 	if (delta <= 0 || level - delta < 0)
898 	    delta = abs(delta) + 1;
899 	else
900 	    delta = -delta;
901 
902 	if (level + delta > MAX_LEVEL)
903 	    delta = -delta;
904 
905 	if (level + delta < 0)
906 	    break;		/* cant really happen */
907 
908     }
909     eventlog(eventlog_level_trace, __FUNCTION__, "[%d] Matching finished, not enough players (found %d)", conn_get_socket(c), players[queue]);
910     mapname = NULL;
911     return 0;
912 }
913 
914 static int w3routeip = -1;	/* changed by dizzy to show the w3routeshow addr if available */
915 static unsigned short w3routeport = BNETD_W3ROUTE_PORT;
916 
_anongame_search_found(int queue)917 static int _anongame_search_found(int queue)
918 {
919     t_packet *rpacket;
920     t_anongameinfo *info;
921     t_anongame *a;
922     int i, j;
923     t_saf_pt2 *pt2;
924 
925     /* FIXME: maybe periodically lookup w3routeaddr to support dynamic ips?
926      * (or should dns lookup be even quick enough to do it everytime?)
927      */
928 
929     if (w3routeip == -1) {
930 	t_addr *routeraddr;
931 
932 	routeraddr = addr_create_str(prefs_get_w3route_addr(), 0, BNETD_W3ROUTE_PORT);
933 
934 	if (!routeraddr) {
935 	    eventlog(eventlog_level_error, __FUNCTION__, "error getting w3route_addr");
936 	    return -1;
937 	}
938 
939 	w3routeip = addr_get_ip(routeraddr);
940 	w3routeport = addr_get_port(routeraddr);
941 	addr_destroy(routeraddr);
942     }
943 
944     info = anongameinfo_create(_anongame_totalplayers(queue));
945 
946     if (!info) {
947 	eventlog(eventlog_level_error, __FUNCTION__, "anongameinfo_create failed");
948 	return -1;
949     }
950 
951     /* create data to be appended to end of packet */
952     pt2 = xmalloc(sizeof(t_saf_pt2));
953     bn_int_set(&pt2->unknown1, 0xFFFFFFFF);
954     bn_int_set(&pt2->anongame_string, _anongame_get_gametype_tab(queue));
955     bn_byte_set(&pt2->totalplayers, _anongame_totalplayers(queue));
956     bn_byte_set(&pt2->totalteams, _anongame_totalteams(queue));	/* 1v1 & sffa are set to zero in _anongame_totalteams() */
957     bn_short_set(&pt2->unknown2, 0);
958     bn_byte_set(&pt2->visibility, 2);	/* visibility. 0x01 - dark 0x02 - default */
959     bn_byte_set(&pt2->unknown3, 2);
960 
961     /* send found packet to each of the players */
962     for (i = 0; i < players[queue]; i++) {
963 	if (!(a = conn_get_anongame(player[queue][i]))) {
964 	    eventlog(eventlog_level_error, __FUNCTION__, "no anongame struct for queued player");
965 	    xfree(pt2);
966 	    return -1;
967 	}
968 
969 	a->info = info;
970 	a->playernum = i + 1;
971 
972 	for (j = 0; j < players[queue]; j++) {
973 	    a->info->player[j] = player[queue][j];
974 	    a->info->account[j] = conn_get_account(player[queue][j]);
975 	}
976 
977 	if (!(rpacket = packet_create(packet_class_bnet))) {
978 	    xfree(pt2);
979 	    return -1;
980 	}
981 
982 	packet_set_size(rpacket, sizeof(t_server_anongame_found));
983 	packet_set_type(rpacket, SERVER_ANONGAME_FOUND);
984 	bn_byte_set(&rpacket->u.server_anongame_found.option, 1);
985 	bn_int_set(&rpacket->u.server_anongame_found.count, a->count);
986 	bn_int_set(&rpacket->u.server_anongame_found.unknown1, 0);
987 	{			/* trans support */
988 	    unsigned int w3ip = w3routeip;
989 	    unsigned short w3port = w3routeport;
990 
991 	    trans_net(conn_get_addr(player[queue][i]), &w3ip, &w3port);
992 
993 	    /* if ip to send is 0.0.0.0 (which will not work anyway) try
994 	     * to guess the reachable IP of pvpgn by using the local
995 	     * endpoing address of the bnet class connection */
996 	    if (!w3ip)
997 		w3ip = conn_get_real_local_addr(player[queue][i]);
998 
999 	    bn_int_nset(&rpacket->u.server_anongame_found.ip, w3ip);
1000 	    bn_short_set(&rpacket->u.server_anongame_found.port, w3port);
1001 	}
1002 	bn_byte_set(&rpacket->u.server_anongame_found.unknown2, i + 1);
1003 	bn_byte_set(&rpacket->u.server_anongame_found.unknown3, queue);
1004 	bn_short_set(&rpacket->u.server_anongame_found.unknown4, 0);
1005 	bn_int_set(&rpacket->u.server_anongame_found.id, 0xdeadbeef);
1006 	bn_byte_set(&rpacket->u.server_anongame_found.unknown5, 6);
1007 	bn_byte_set(&rpacket->u.server_anongame_found.type, a->type);
1008 	bn_byte_set(&rpacket->u.server_anongame_found.gametype, a->gametype);
1009 	packet_append_string(rpacket, mapname);
1010 	packet_append_data(rpacket, pt2, sizeof(t_saf_pt2));
1011 	conn_push_outqueue(player[queue][i], rpacket);
1012 	packet_del_ref(rpacket);
1013     }
1014 
1015     /* clear queue */
1016     players[queue] = 0;
1017     xfree(pt2);
1018     return 0;
1019 }
1020 
1021 /**********************************************************************************/
1022 /* external functions */
1023 /**********************************************************************************/
anongame_matchlists_create()1024 extern int anongame_matchlists_create()
1025 {
1026     int i, j;
1027 
1028     for (i = 0; i < ANONGAME_TYPES; i++) {
1029 	for (j = 0; j < MAX_LEVEL; j++) {
1030 	    matchlists[i][j] = NULL;
1031 	}
1032     }
1033     return 0;
1034 }
1035 
anongame_matchlists_destroy()1036 extern int anongame_matchlists_destroy()
1037 {
1038     int i, j;
1039     for (i = 0; i < ANONGAME_TYPES; i++) {
1040 	for (j = 0; j < MAX_LEVEL; j++) {
1041 	    if (matchlists[i][j]) {
1042 		list_destroy(matchlists[i][j]);
1043 	    }
1044 	}
1045     }
1046     return 0;
1047 }
1048 
1049 /**********/
handle_anongame_search(t_connection * c,t_packet const * packet)1050 extern int handle_anongame_search(t_connection * c, t_packet const *packet)
1051 {
1052     return _handle_anongame_search(c, packet);
1053 }
1054 
anongame_unqueue(t_connection * c,int queue)1055 extern int anongame_unqueue(t_connection * c, int queue)
1056 {
1057     int i;
1058     t_elem *curr;
1059     t_matchdata *md;
1060 
1061     if (queue < 0) {
1062 	eventlog(eventlog_level_error, __FUNCTION__, "got negative queue id (%d)", queue);
1063 	return -1;
1064     }
1065 
1066     if (queue >= ANONGAME_TYPES) {
1067 	eventlog(eventlog_level_error, __FUNCTION__, "unknown queue: %d", queue);
1068 	return -1;
1069     }
1070 
1071     if (conn_get_anongame_search_starttime(c) != ((time_t) 0)) {
1072 	average_anongame_search_time *= anongame_search_count;
1073 	average_anongame_search_time += (long) difftime(time(NULL), conn_get_anongame_search_starttime(c));
1074 	anongame_search_count++;
1075 	average_anongame_search_time /= anongame_search_count;
1076 	if (anongame_search_count > 20000)
1077 	    anongame_search_count = anongame_search_count / 2;	/* to prevent an overflow of the average time */
1078 	conn_set_anongame_search_starttime(c, ((time_t) 0));
1079     }
1080 
1081     for (i = 0; i < MAX_LEVEL; i++) {
1082 	if (matchlists[queue][i] == NULL)
1083 	    continue;
1084 
1085 	LIST_TRAVERSE(matchlists[queue][i], curr) {
1086 	    md = elem_get_data(curr);
1087 	    if (md->c == c) {
1088 		eventlog(eventlog_level_trace, __FUNCTION__, "unqueued player [%d] level %d", conn_get_socket(c), i);
1089 		list_remove_elem(matchlists[queue][i], &curr);
1090 		xfree(md);
1091 		return 0;
1092 	    }
1093 	}
1094     }
1095 
1096     /* Output error to log for PG queues, AT players are queued with single
1097      * entry. Because anongame_unqueue() is called for each player, only the first
1098      * time called will the team be removed, the rest are therefore not an error.
1099      * [Omega]
1100      */
1101     if (anongame_arranged(queue) == 0) {
1102 	eventlog(eventlog_level_trace, __FUNCTION__, "[%d] player not found in \"%s\" queue", conn_get_socket(c), _anongame_queue_to_string(queue));
1103 	return -1;
1104     }
1105 
1106     return 0;
1107 }
1108 
1109 /**********/
anongame_arranged(int queue)1110 extern char anongame_arranged(int queue)
1111 {
1112     switch (queue) {
1113 	case ANONGAME_TYPE_AT_2V2:
1114 	case ANONGAME_TYPE_AT_3V3:
1115 	case ANONGAME_TYPE_AT_4V4:
1116 	case ANONGAME_TYPE_AT_2V2V2:
1117 	    return 1;
1118 	case ANONGAME_TYPE_TY:
1119 	    return tournament_is_arranged();
1120 	default:
1121 	    return 0;
1122     }
1123 }
1124 
anongame_evaluate_results(t_anongame * anongame)1125 extern int anongame_evaluate_results(t_anongame * anongame)
1126 {
1127     int i, j, number;
1128     int wins[ANONGAME_MAX_GAMECOUNT];
1129     int losses[ANONGAME_MAX_GAMECOUNT];
1130     int result;
1131     t_anongame_gameresult *results;
1132     t_anongameinfo *anoninfo = anongame->info;
1133 
1134     for (i = 0; i < ANONGAME_MAX_GAMECOUNT; i++) {
1135 	wins[i] = 0;
1136 	losses[i] = 0;
1137     }
1138 
1139     for (i = 0; i < anongame_get_totalplayers(anongame); i++) {
1140 	if ((results = anoninfo->results[i])) {
1141 	    for (j = 0; j < gameresult_get_number_of_results(results); j++) {
1142 		number = gameresult_get_player_number(results, j) - 1;
1143 		result = gameresult_get_player_result(results, j);
1144 
1145 		if ((result == W3_GAMERESULT_WIN))
1146 		    wins[number]++;
1147 		if ((result == W3_GAMERESULT_LOSS))
1148 		    losses[number]++;
1149 	    }
1150 	}
1151     }
1152 
1153     for (i = 0; i < anongame_get_totalplayers(anongame); i++) {
1154 	if ((wins[i] > losses[i])) {
1155 	    if ((anoninfo->result[i] != W3_GAMERESULT_WIN)) {
1156 		eventlog(eventlog_level_trace, __FUNCTION__, "player %d reported DISC/LOSS for self, but others agree on WIN", i + 1);
1157 		anoninfo->result[i] = W3_GAMERESULT_WIN;
1158 	    }
1159 	} else {
1160 	    if ((anoninfo->result[i] != W3_GAMERESULT_LOSS)) {
1161 		eventlog(eventlog_level_trace, __FUNCTION__, "player %d reported DISC/WIN for self, but others agree on LOSS", i + 1);
1162 		anoninfo->result[i] = W3_GAMERESULT_LOSS;
1163 	    }
1164 	}
1165     }
1166 
1167     return 0;
1168 
1169 }
1170 
anongame_stats(t_connection * c)1171 extern int anongame_stats(t_connection * c)
1172 {
1173     int i;
1174     int wins = 0, losses = 0, discs = 0;
1175     t_connection *gamec = conn_get_routeconn(c);
1176     t_anongame *a = conn_get_anongame(gamec);
1177     int tp = anongame_get_totalplayers(a);
1178     int oppon_level[ANONGAME_MAX_GAMECOUNT];
1179     t_uint8 gametype = a->queue;
1180     t_uint8 plnum = a->playernum;
1181     t_clienttag ct = conn_get_clienttag(c);
1182     int tt = _anongame_totalteams(gametype);
1183 
1184     /* do nothing till all other players have w3route conn closed */
1185     for (i = 0; i < tp; i++)
1186 	if (i + 1 != plnum && a->info->player[i])
1187 	    if (conn_get_routeconn(a->info->player[i]))
1188 		return 0;
1189 
1190     anongame_evaluate_results(a);
1191 
1192     /* count wins, losses, discs */
1193     for (i = 0; i < tp; i++) {
1194 	if (a->info->result[i] == W3_GAMERESULT_WIN)
1195 	    wins++;
1196 	else if (a->info->result[i] == W3_GAMERESULT_LOSS)
1197 	    losses++;
1198 	else
1199 	    discs++;
1200     }
1201 
1202     /* do some sanity checking (hack prevention) */
1203     switch (gametype) {
1204 	case ANONGAME_TYPE_SMALL_FFA:
1205 	    if (wins != 1) {
1206 		eventlog(eventlog_level_info, __FUNCTION__, "bogus game result: wins != 1 in small ffa game");
1207 		return -1;
1208 	    }
1209 	    break;
1210 	case ANONGAME_TYPE_TEAM_FFA:
1211 	    if (!discs && wins != 2) {
1212 		eventlog(eventlog_level_info, __FUNCTION__, "bogus game result: wins != 2 in team ffa game");
1213 		return -1;
1214 	    }
1215 	    break;
1216 	default:
1217 	    if (!discs && wins > losses) {
1218 		eventlog(eventlog_level_info, __FUNCTION__, "bogus game result: wins > losses");
1219 		return -1;
1220 	    }
1221 	    break;
1222     }
1223 
1224     /* prevent users from getting loss if server is shutdown (does not prevent errors from crash) - [Omega] */
1225     /* also discard games with no winners at all (i.e. games where game host disc'ed and so all players do) */
1226     if (!wins)
1227 	return -1;
1228 
1229     /* according to zap, order of players in anongame is:
1230      * for PG: t1_p1, t2_p1, t1_p2, t2_p2, ...
1231      * for AT: t1_p1, t1_p2, ..., t2_p1, t2_p2, ...
1232      *
1233      * (Not True.. follows same order as PG)
1234      *  4v4     = t1_p1, t2_p1, t1_p2, t2_p2, t1_p3, t2_p3, t1_p4, t2_p4
1235      *  3v3v3   = t1_p1, t2_p1, t3_p1, t1_p2, t2_p2, t3_p2, t1_p3, t2_p3, t3_p3
1236      *  2v2v2v2 = t1_p1, t2_p1, t3_p1, t4_p1, t1_p2, t2_p2, t3_p2, t4_p2
1237      */
1238 
1239     /* opponent level calculation has to be done here, because later on, the level of other players
1240      * may allready be modified
1241      */
1242     for (i = 0; i < tp; i++) {
1243 	int j, k, l;
1244 	t_account *oacc;
1245 	oppon_level[i] = 0;
1246 	switch (gametype) {
1247 	    case ANONGAME_TYPE_TY:
1248 		/* FIXME-TY: ADD TOURNAMENT STATS RECORDING (this part not required?) */
1249 		break;
1250 	    case ANONGAME_TYPE_1V1:
1251 		oppon_level[i] = account_get_ladder_level(a->info->account[(i + 1) % tp], ct, ladder_id_solo);
1252 		break;
1253 	    case ANONGAME_TYPE_SMALL_FFA:
1254 		/* oppon_level = average level of all other players */
1255 		for (j = 0; j < tp; j++)
1256 		    if (i != j)
1257 			oppon_level[i] += account_get_ladder_level(a->info->account[j], ct, ladder_id_ffa);
1258 		oppon_level[i] /= (tp - 1);
1259 		break;
1260 	    case ANONGAME_TYPE_AT_2V2:
1261 	    case ANONGAME_TYPE_AT_3V3:
1262 	    case ANONGAME_TYPE_AT_4V4:
1263 		oacc = a->info->account[(i + 1) % tp];
1264 		oppon_level[i] = team_get_level(account_find_team_by_teamid(oacc, account_get_currentatteam(oacc)));
1265 		break;
1266 	    case ANONGAME_TYPE_AT_2V2V2:
1267 		oacc = a->info->account[(i + 1) % tp];
1268 		oppon_level[i] = team_get_level(account_find_team_by_teamid(oacc, account_get_currentatteam(oacc)));
1269 		oacc = a->info->account[(i + 2) % tp];
1270 		oppon_level[i] = team_get_level(account_find_team_by_teamid(oacc, account_get_currentatteam(oacc)));
1271 		oppon_level[i] /= 2;
1272 		break;
1273 	    default:
1274 		/* oppon_level = average level of all opponents
1275 		 * this should work for all PG team games
1276 		 * [Omega] */
1277 		k = i + 1;
1278 		for (j = 0; j < (tp / tt); j++) {
1279 		    for (l = 0; l < (tt - 1); l++) {
1280 			oppon_level[i] += account_get_ladder_level(a->info->account[k % tp], ct, ladder_id_team);
1281 			k++;
1282 		    }
1283 		    k++;
1284 		}
1285 		oppon_level[i] /= (tp / tt * (tt - 1));
1286 	}
1287     }
1288 
1289     for (i = 0; i < tp; i++) {
1290 	t_account *acc;
1291 	t_team *team;
1292 	unsigned int currteam;
1293 	int result = a->info->result[i];
1294 
1295 	if (result == -1)
1296 	    result = W3_GAMERESULT_LOSS;
1297 
1298 	acc = a->info->account[i];
1299 
1300 	switch (gametype) {
1301 	    case ANONGAME_TYPE_TY:
1302 		if (result == W3_GAMERESULT_WIN)
1303 		    tournament_add_stat(acc, 1);
1304 		if (result == W3_GAMERESULT_LOSS)
1305 		    tournament_add_stat(acc, 2);
1306 		/* FIXME-TY: how to do ties? */
1307 		break;
1308 	    case ANONGAME_TYPE_AT_2V2:
1309 	    case ANONGAME_TYPE_AT_3V3:
1310 	    case ANONGAME_TYPE_AT_4V4:
1311 	    case ANONGAME_TYPE_AT_2V2V2:
1312 
1313 		if ((currteam = account_get_currentatteam(acc))) {
1314 		    team = account_find_team_by_teamid(acc, currteam);
1315 		    team_set_saveladderstats(team, gametype, result, oppon_level[i], ct);
1316 		}
1317 
1318 		break;
1319 	    case ANONGAME_TYPE_1V1:
1320 	    case ANONGAME_TYPE_2V2:
1321 	    case ANONGAME_TYPE_3V3:
1322 	    case ANONGAME_TYPE_4V4:
1323 	    case ANONGAME_TYPE_SMALL_FFA:
1324 	    case ANONGAME_TYPE_5V5:
1325 	    case ANONGAME_TYPE_6V6:
1326 	    case ANONGAME_TYPE_2V2V2:
1327 	    case ANONGAME_TYPE_3V3V3:
1328 	    case ANONGAME_TYPE_4V4V4:
1329 	    case ANONGAME_TYPE_2V2V2V2:
1330 	    case ANONGAME_TYPE_3V3V3V3:
1331 		if (result == W3_GAMERESULT_WIN)
1332 		    account_set_saveladderstats(acc, gametype, game_result_win, oppon_level[i], ct);
1333 		if (result == W3_GAMERESULT_LOSS)
1334 		    account_set_saveladderstats(acc, gametype, game_result_loss, oppon_level[i], ct);
1335 		break;
1336 	    default:
1337 		break;
1338 	}
1339     }
1340     /* aaron: now update war3 ladders */
1341     ladder_update_all_accounts();
1342     return 1;
1343 }
1344 
1345 /**********/
anongameinfo_create(int totalplayers)1346 extern t_anongameinfo *anongameinfo_create(int totalplayers)
1347 {
1348     t_anongameinfo *temp;
1349     int i;
1350 
1351     temp = xmalloc(sizeof(t_anongameinfo));
1352 
1353     temp->totalplayers = temp->currentplayers = totalplayers;
1354     for (i = 0; i < ANONGAME_MAX_GAMECOUNT; i++) {
1355 	temp->player[i] = NULL;
1356 	temp->account[i] = NULL;
1357 	temp->result[i] = -1;	/* consider DISC default */
1358 	temp->results[i] = NULL;
1359     }
1360 
1361     return temp;
1362 }
1363 
anongameinfo_destroy(t_anongameinfo * i)1364 extern void anongameinfo_destroy(t_anongameinfo * i)
1365 {
1366     int j;
1367 
1368     if (!i) {
1369 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongameinfo");
1370 	return;
1371     }
1372     for (j = 0; j < ANONGAME_MAX_GAMECOUNT; j++)
1373 	if (i->results[j])
1374 	    gameresult_destroy(i->results[j]);
1375     xfree(i);
1376 }
1377 
1378 /**********/
anongame_get_info(t_anongame * a)1379 extern t_anongameinfo *anongame_get_info(t_anongame * a)
1380 {
1381     if (!a) {
1382 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1383 	return NULL;
1384     }
1385 
1386     return a->info;
1387 }
1388 
anongame_get_currentplayers(t_anongame * a)1389 extern int anongame_get_currentplayers(t_anongame * a)
1390 {
1391     if (!a) {
1392 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1393 	return 0;
1394     }
1395     if (!a->info) {
1396 	eventlog(eventlog_level_error, __FUNCTION__, "NULL anongameinfo");
1397 	return 0;
1398     }
1399 
1400     return a->info->currentplayers;
1401 }
1402 
anongame_get_totalplayers(t_anongame * a)1403 extern int anongame_get_totalplayers(t_anongame * a)
1404 {
1405     if (!a) {
1406 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1407 	return 0;
1408     }
1409     if (!a->info) {
1410 	eventlog(eventlog_level_error, __FUNCTION__, "NULL anongameinfo");
1411 	return 0;
1412     }
1413 
1414     return a->info->totalplayers;
1415 }
1416 
anongame_get_player(t_anongame * a,int plnum)1417 extern t_connection *anongame_get_player(t_anongame * a, int plnum)
1418 {
1419     if (!a) {
1420 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1421 	return NULL;
1422     }
1423     if (!a->info) {
1424 	eventlog(eventlog_level_error, __FUNCTION__, "NULL anongameinfo");
1425 	return NULL;
1426     }
1427 
1428     if (plnum < 0 || plnum > 7 || plnum >= a->info->totalplayers) {
1429 	eventlog(eventlog_level_error, __FUNCTION__, "invalid plnum: %d", plnum);
1430 	return NULL;
1431     }
1432 
1433     return a->info->player[plnum];
1434 }
1435 
anongame_get_count(t_anongame * a)1436 extern int anongame_get_count(t_anongame * a)
1437 {
1438     if (!a) {
1439 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1440 	return 0;
1441     }
1442     return a->count;
1443 }
1444 
anongame_get_id(t_anongame * a)1445 extern t_uint32 anongame_get_id(t_anongame * a)
1446 {
1447     if (!a) {
1448 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1449 	return 0;
1450     }
1451     return a->id;
1452 }
1453 
anongame_get_tc(t_anongame * a,int tpnumber)1454 extern t_connection *anongame_get_tc(t_anongame * a, int tpnumber)
1455 {
1456     if (!a) {
1457 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1458 	return 0;
1459     }
1460     return a->tc[tpnumber];
1461 }
1462 
anongame_get_race(t_anongame * a)1463 extern t_uint32 anongame_get_race(t_anongame * a)
1464 {
1465     if (!a) {
1466 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1467 	return 0;
1468     }
1469     return a->race;
1470 }
1471 
anongame_get_handle(t_anongame * a)1472 extern t_uint32 anongame_get_handle(t_anongame * a)
1473 {
1474     if (!a) {
1475 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1476 	return 0;
1477     }
1478     return a->handle;
1479 }
1480 
anongame_get_addr(t_anongame * a)1481 extern unsigned int anongame_get_addr(t_anongame * a)
1482 {
1483     if (!a) {
1484 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1485 	return 0;
1486     }
1487     return a->addr;
1488 }
1489 
anongame_get_loaded(t_anongame * a)1490 extern char anongame_get_loaded(t_anongame * a)
1491 {
1492     if (!a) {
1493 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1494 	return 0;
1495     }
1496     return a->loaded;
1497 }
1498 
anongame_get_joined(t_anongame * a)1499 extern char anongame_get_joined(t_anongame * a)
1500 {
1501     if (!a) {
1502 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1503 	return 0;
1504     }
1505     return a->joined;
1506 }
1507 
anongame_get_playernum(t_anongame * a)1508 extern t_uint8 anongame_get_playernum(t_anongame * a)
1509 {
1510     if (!a) {
1511 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1512 	return 0;
1513     }
1514     return a->playernum;
1515 }
1516 
anongame_get_queue(t_anongame * a)1517 extern t_uint8 anongame_get_queue(t_anongame * a)
1518 {
1519     if (!a) {
1520 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1521 	return 0;
1522     }
1523     return a->queue;
1524 }
1525 
1526 /**********/
anongame_set_result(t_anongame * a,int result)1527 extern void anongame_set_result(t_anongame * a, int result)
1528 {
1529     if (!a) {
1530 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1531 	return;
1532     }
1533     if (!a->info) {
1534 	eventlog(eventlog_level_error, __FUNCTION__, "NULL anongameinfo");
1535 	return;
1536     }
1537 
1538     if (a->playernum < 1 || a->playernum > ANONGAME_MAX_GAMECOUNT) {
1539 	eventlog(eventlog_level_error, __FUNCTION__, "invalid playernum: %d", a->playernum);
1540 	return;
1541     }
1542 
1543     a->info->result[a->playernum - 1] = result;
1544 }
1545 
anongame_set_gameresults(t_anongame * a,t_anongame_gameresult * results)1546 extern void anongame_set_gameresults(t_anongame * a, t_anongame_gameresult * results)
1547 {
1548     if (!a) {
1549 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1550 	return;
1551     }
1552     if (!a->info) {
1553 	eventlog(eventlog_level_error, __FUNCTION__, "NULL anongameinfo");
1554 	return;
1555     }
1556 
1557     if (a->playernum < 1 || a->playernum > ANONGAME_MAX_GAMECOUNT) {
1558 	eventlog(eventlog_level_error, __FUNCTION__, "invalid playernum: %d", a->playernum);
1559 	return;
1560     }
1561 
1562     a->info->results[a->playernum - 1] = results;
1563 }
1564 
anongame_set_handle(t_anongame * a,t_uint32 h)1565 extern void anongame_set_handle(t_anongame * a, t_uint32 h)
1566 {
1567     if (!a) {
1568 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1569 	return;
1570     }
1571 
1572     a->handle = h;
1573 }
1574 
anongame_set_addr(t_anongame * a,unsigned int addr)1575 extern void anongame_set_addr(t_anongame * a, unsigned int addr)
1576 {
1577     if (!a) {
1578 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1579 	return;
1580     }
1581 
1582     a->addr = addr;
1583 }
1584 
anongame_set_loaded(t_anongame * a,char loaded)1585 extern void anongame_set_loaded(t_anongame * a, char loaded)
1586 {
1587     if (!a) {
1588 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1589 	return;
1590     }
1591 
1592     a->loaded = loaded;
1593 }
1594 
anongame_set_joined(t_anongame * a,char joined)1595 extern void anongame_set_joined(t_anongame * a, char joined)
1596 {
1597     if (!a) {
1598 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1599 	return;
1600     }
1601 
1602     a->joined = joined;
1603 }
1604 
1605 /**********/
1606 /* move to own .c/.h file for handling w3route connections */
handle_w3route_packet(t_connection * c,t_packet const * const packet)1607 extern int handle_w3route_packet(t_connection * c, t_packet const *const packet)
1608 {
1609 /* [smith] 20030427 fixed Big-Endian/Little-Endian conversion (Solaris bug) then
1610  * use  packet_append_data for append platform dependent data types - like
1611  * "int", cos this code was broken for BE platforms. it's rewriten in platform
1612  * independent style whis usege bn_int and other bn_* like datatypes and
1613  * fuctions for wor with datatypes - bn_int_set(), what provide right
1614  * byteorder, not depended on LE/BE
1615  * fixed broken htonl() conversion for BE platforms - change it to
1616  * bn_int_nset(). i hope it's worked on intel too %) */
1617 
1618     t_packet *rpacket;
1619     t_connection *gamec;
1620     char const *username;
1621     t_anongame *a = NULL;
1622     t_uint8 gametype, plnum;
1623     int tp, i;
1624 
1625     if (!c) {
1626 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got NULL connection", conn_get_socket(c));
1627 	return -1;
1628     }
1629     if (!packet) {
1630 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got NULL packet", conn_get_socket(c));
1631 	return -1;
1632     }
1633     if (packet_get_class(packet) != packet_class_w3route) {
1634 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad packet (class %d)", conn_get_socket(c), packet_get_class(packet));
1635 	return -1;
1636     }
1637     if (conn_get_state(c) != conn_state_connected) {
1638 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] not connected", conn_get_socket(c));
1639 	return -1;
1640     }
1641 
1642     /* init route connection */
1643     if (packet_get_type(packet) == CLIENT_W3ROUTE_REQ) {
1644 	t_connection *oldc;
1645 
1646 	eventlog(eventlog_level_trace, __FUNCTION__, "[%d] sizeof t_client_w3route_req %d", conn_get_socket(c), sizeof(t_client_w3route_req));
1647 	username = packet_get_str_const(packet, sizeof(t_client_w3route_req), USER_NAME_MAX);
1648 	eventlog(eventlog_level_info, __FUNCTION__, "[%d] got username '%s'", conn_get_socket(c), username);
1649 	gamec = connlist_find_connection_by_accountname(username);
1650 
1651 	if (!gamec) {
1652 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] no game connection found for this w3route connection; closing", conn_get_socket(c));
1653 	    conn_set_state(c, conn_state_destroy);
1654 	    return 0;
1655 	}
1656 
1657 	if (!(a = conn_get_anongame(gamec))) {
1658 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] no anongame struct for game connection", conn_get_socket(c));
1659 	    conn_set_state(c, conn_state_destroy);
1660 	    return 0;
1661 	}
1662 
1663 	if (bn_int_get((unsigned char const *) packet->u.data + sizeof(t_client_w3route_req) + strlen(username) + 2) != anongame_get_id(a)) {
1664 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] client sent wrong id for user '%s', closing connection", conn_get_socket(c), username);
1665 	    conn_set_state(c, conn_state_destroy);
1666 	    return 0;
1667 	}
1668 
1669 	oldc = conn_get_routeconn(gamec);
1670 	if (oldc) {
1671 	    conn_set_routeconn(oldc, NULL);
1672 	    conn_set_state(oldc, conn_state_destroy);
1673 	}
1674 
1675 	if (conn_set_routeconn(c, gamec) < 0 || conn_set_routeconn(gamec, c) < 0) {
1676 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] conn_set_routeconn failed", conn_get_socket(c));
1677 	    return -1;
1678 	}
1679 
1680 	/* set clienttag for w3route connections; we can do conn_get_clienttag() on them */
1681 	conn_set_clienttag(c, conn_get_clienttag(gamec));
1682 
1683 	anongame_set_addr(a, bn_int_get((unsigned char const *) packet->u.data + sizeof(t_client_w3route_req) + strlen(username) + 2 + 12));
1684 	anongame_set_joined(a, 0);
1685 	anongame_set_loaded(a, 0);
1686 	anongame_set_result(a, -1);
1687 	anongame_set_gameresults(a, NULL);
1688 
1689 	anongame_set_handle(a, bn_int_get(packet->u.client_w3route_req.handle));
1690 
1691 	if (!(rpacket = packet_create(packet_class_w3route))) {
1692 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] packet_create failed", conn_get_socket(c));
1693 	    return -1;
1694 	}
1695 
1696 	packet_set_size(rpacket, sizeof(t_server_w3route_ack));
1697 	packet_set_type(rpacket, SERVER_W3ROUTE_ACK);
1698 	bn_byte_set(&rpacket->u.server_w3route_ack.unknown1, 7);
1699 	bn_short_set(&rpacket->u.server_w3route_ack.unknown2, 0);
1700 	bn_int_set(&rpacket->u.server_w3route_ack.unknown3, SERVER_W3ROUTE_ACK_UNKNOWN3);
1701 
1702 	bn_short_set(&rpacket->u.server_w3route_ack.unknown4, 0xcccc);
1703 	bn_byte_set(&rpacket->u.server_w3route_ack.playernum, anongame_get_playernum(a));
1704 	bn_short_set(&rpacket->u.server_w3route_ack.unknown5, 0x0002);
1705 	bn_short_set(&rpacket->u.server_w3route_ack.port, conn_get_port(c));
1706 	bn_int_nset(&rpacket->u.server_w3route_ack.ip, conn_get_addr(c));
1707 	bn_int_set(&rpacket->u.server_w3route_ack.unknown7, 0);
1708 	bn_int_set(&rpacket->u.server_w3route_ack.unknown8, 0);
1709 	conn_push_outqueue(c, rpacket);
1710 	packet_del_ref(rpacket);
1711 
1712 	return 0;
1713     } else {
1714 	gamec = conn_get_routeconn(c);
1715 	if (gamec)
1716 	    a = conn_get_anongame(gamec);
1717     }
1718 
1719     if (!gamec) {
1720 	eventlog(eventlog_level_info, __FUNCTION__, "[%d] no game connection found for this w3route connection", conn_get_socket(c));
1721 	return 0;
1722     }
1723 
1724     if (!a) {
1725 	eventlog(eventlog_level_info, __FUNCTION__, "[%d] no anongame struct found for this w3route connection", conn_get_socket(c));
1726 	return 0;
1727     }
1728 
1729     gametype = anongame_get_queue(a);
1730     plnum = anongame_get_playernum(a);
1731     tp = anongame_get_totalplayers(a);
1732 
1733     /* handle these packets _before_ checking for routeconn of other players */
1734     switch (packet_get_type(packet)) {
1735 	case CLIENT_W3ROUTE_ECHOREPLY:
1736 	    return 0;
1737 	case CLIENT_W3ROUTE_CONNECTED:
1738 	    return 0;
1739 	case CLIENT_W3ROUTE_GAMERESULT:
1740 	case CLIENT_W3ROUTE_GAMERESULT_W3XP:
1741 	    {
1742 
1743 		/* insert reading of whole packet into t_gameresult */
1744 
1745 		t_anongame_gameresult *gameresult;
1746 		int result;
1747 
1748 		t_timer_data data;
1749 		t_anongameinfo *inf = anongame_get_info(a);
1750 		t_connection *ac;
1751 
1752 		data.p = NULL;
1753 
1754 		if (!(gameresult = anongame_gameresult_parse(packet)))
1755 		    result = -1;
1756 		else		/* own result is always stored as first result */
1757 		    result = gameresult_get_player_result(gameresult, 0);
1758 
1759 		eventlog(eventlog_level_trace, __FUNCTION__, "[%d] got W3ROUTE_GAMERESULT: %08x", conn_get_socket(c), result);
1760 
1761 		if (!inf) {
1762 		    eventlog(eventlog_level_error, __FUNCTION__, "[%d] NULL anongameinfo", conn_get_socket(c));
1763 		    return -1;
1764 		}
1765 
1766 		anongame_set_gameresults(a, gameresult);
1767 		anongame_set_result(a, result);
1768 
1769 		conn_set_state(c, conn_state_destroy);
1770 
1771 		/* activate timers on open w3route connectons */
1772 		if (result == W3_GAMERESULT_WIN) {
1773 		    for (i = 0; i < tp; i++) {
1774 			if (anongame_get_player(a, i)) {
1775 			    ac = conn_get_routeconn(anongame_get_player(a, i));
1776 			    if (ac) {
1777 				/* 300 seconds or 5 minute timer */
1778 				timerlist_add_timer(ac, now + (time_t) 300, conn_shutdown, data);
1779 				eventlog(eventlog_level_trace, __FUNCTION__, "[%d] started timer to close w3route", conn_get_socket(ac));
1780 			    }
1781 			}
1782 		    }
1783 		}
1784 
1785 		return 0;
1786 	    }
1787     }
1788 
1789     for (i = 0; i < tp; i++)
1790 	if (i + 1 != plnum && anongame_get_player(a, i))
1791 	    if (!conn_get_routeconn(anongame_get_player(a, i)) || !conn_get_anongame(anongame_get_player(a, i))) {
1792 		eventlog(eventlog_level_info, __FUNCTION__, "[%d] not all players have w3route connections up yet", conn_get_socket(c));
1793 		return 0;
1794 	    }
1795 
1796     /* handle these packets _after_ checking for routeconns of other players */
1797     switch (packet_get_type(packet)) {
1798 	case CLIENT_W3ROUTE_LOADINGDONE:
1799 	    eventlog(eventlog_level_trace, __FUNCTION__, "[%d] got LOADINGDONE, playernum: %d", conn_get_socket(c), plnum);
1800 
1801 	    anongame_set_loaded(a, 1);
1802 
1803 	    for (i = 0; i < tp; i++) {
1804 		if (!anongame_get_player(a, i))	/* ignore disconnected players */
1805 		    continue;
1806 		if (!(rpacket = packet_create(packet_class_w3route))) {
1807 		    eventlog(eventlog_level_error, __FUNCTION__, "[%d] packet_create failed", conn_get_socket(c));
1808 		    return -1;
1809 		}
1810 		packet_set_size(rpacket, sizeof(t_server_w3route_loadingack));
1811 		packet_set_type(rpacket, SERVER_W3ROUTE_LOADINGACK);
1812 		bn_byte_set(&rpacket->u.server_w3route_loadingack.playernum, plnum);
1813 		conn_push_outqueue(conn_get_routeconn(anongame_get_player(a, i)), rpacket);
1814 		packet_del_ref(rpacket);
1815 	    }
1816 
1817 	    /* have all players loaded? */
1818 	    for (i = 0; i < tp; i++)
1819 		if (i + 1 != plnum && anongame_get_player(a, i) && !anongame_get_loaded(conn_get_anongame(anongame_get_player(a, i))))
1820 		    return 0;
1821 
1822 	    for (i = 0; i < tp; i++) {
1823 		if (!anongame_get_player(a, i))
1824 		    continue;
1825 
1826 		if (!(rpacket = packet_create(packet_class_w3route))) {
1827 		    eventlog(eventlog_level_error, __FUNCTION__, "[%d] packet_create failed", conn_get_socket(c));
1828 		    return -1;
1829 		}
1830 
1831 		packet_set_size(rpacket, sizeof(t_server_w3route_ready));
1832 		packet_set_type(rpacket, SERVER_W3ROUTE_READY);
1833 		bn_byte_set(&rpacket->u.server_w3route_host.unknown1, 0);
1834 		conn_push_outqueue(conn_get_routeconn(anongame_get_player(a, i)), rpacket);
1835 		packet_del_ref(rpacket);
1836 	    }
1837 
1838 	    break;
1839 
1840 	case CLIENT_W3ROUTE_ABORT:
1841 	    eventlog(eventlog_level_debug, __FUNCTION__, "[%d] got W3ROUTE_ABORT", conn_get_socket(c));
1842 	    break;
1843 
1844 	default:
1845 	    eventlog(eventlog_level_trace, __FUNCTION__, "[%d] default: got packet type: %04x", conn_get_socket(c), packet_get_type(packet));
1846     }
1847 
1848     return 0;
1849 }
1850 
handle_anongame_join(t_connection * c)1851 extern int handle_anongame_join(t_connection * c)
1852 {
1853     t_anongame *a, *ja, *oa;
1854     t_connection *jc, *o;
1855     t_packet *rpacket;
1856     int tp, level;
1857     char gametype;
1858     t_account *acct;
1859     t_clienttag ct = conn_get_clienttag(c);
1860 
1861     static t_server_w3route_playerinfo2 pl2;
1862     static t_server_w3route_levelinfo2 li2;
1863     static t_server_w3route_playerinfo_addr pl_addr;
1864 
1865     int i, j;
1866 
1867     if (!c) {
1868 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] got NULL connection", conn_get_socket(c));
1869 	return -1;
1870     }
1871     if (!(conn_get_routeconn(c))) {
1872 	eventlog(eventlog_level_info, __FUNCTION__, "[%d] no route connection", conn_get_socket(c));
1873 	return -1;
1874     }
1875     if (!(a = conn_get_anongame(c))) {
1876 	eventlog(eventlog_level_error, __FUNCTION__, "[%d] no anongame struct", conn_get_socket(c));
1877 	return -1;
1878     }
1879 
1880     anongame_set_joined(a, 1);
1881     gametype = anongame_get_queue(a);
1882     tp = anongame_get_totalplayers(a);
1883 
1884     /* wait till all players have w3route conns */
1885     for (i = 0; i < tp; i++)
1886 	if (anongame_get_player(a, i) && (!conn_get_routeconn(anongame_get_player(a, i)) || !conn_get_anongame(anongame_get_player(a, i)) || !anongame_get_joined(conn_get_anongame(anongame_get_player(a, i))))) {
1887 	    eventlog(eventlog_level_info, __FUNCTION__, "[%d] not all players have joined game BNet yet", conn_get_socket(c));
1888 	    return 0;
1889 	}
1890 
1891     /* then send each player info about all others */
1892     for (j = 0; j < tp; j++) {
1893 	jc = anongame_get_player(a, j);
1894 	if (!jc)		/* ignore disconnected players */
1895 	    continue;
1896 	ja = conn_get_anongame(jc);
1897 
1898 	/* send a playerinfo packet for this player to each other player */
1899 	for (i = 0; i < tp; i++) {
1900 	    if (i + 1 != anongame_get_playernum(ja)) {
1901 		eventlog(eventlog_level_trace, __FUNCTION__, "i = %d", i);
1902 
1903 		if (!(o = anongame_get_player(ja, i))) {
1904 		    eventlog(eventlog_level_warn, __FUNCTION__, "[%d] player %d disconnected, ignoring", conn_get_socket(c), i);
1905 		    continue;
1906 		}
1907 
1908 		if (!(rpacket = packet_create(packet_class_w3route))) {
1909 		    eventlog(eventlog_level_error, __FUNCTION__, "[%d] packet_create failed", conn_get_socket(c));
1910 		    return -1;
1911 		}
1912 
1913 		packet_set_size(rpacket, sizeof(t_server_w3route_playerinfo));
1914 		packet_set_type(rpacket, SERVER_W3ROUTE_PLAYERINFO);
1915 
1916 
1917 		if (!(oa = conn_get_anongame(o))) {
1918 		    eventlog(eventlog_level_error, __FUNCTION__, "[%d] no anongame struct of player %d", conn_get_socket(c), i);
1919 		    return -1;
1920 		}
1921 
1922 		bn_int_set(&rpacket->u.server_w3route_playerinfo.handle, anongame_get_handle(oa));
1923 		bn_byte_set(&rpacket->u.server_w3route_playerinfo.playernum, anongame_get_playernum(oa));
1924 
1925 		packet_append_string(rpacket, conn_get_username(o));
1926 
1927 		/* playerinfo2 */
1928 		bn_byte_set(&pl2.unknown1, 8);
1929 		bn_int_set(&pl2.id, anongame_get_id(oa));
1930 		bn_int_set(&pl2.race, anongame_get_race(oa));
1931 		packet_append_data(rpacket, &pl2, sizeof(pl2));
1932 
1933 		/* external addr */
1934 		bn_short_set(&pl_addr.unknown1, 2);
1935 		{		/* trans support */
1936 		    unsigned short port = conn_get_game_port(o);
1937 		    unsigned int addr = conn_get_game_addr(o);
1938 
1939 		    trans_net(conn_get_game_addr(jc), &addr, &port);
1940 
1941 		    bn_short_nset(&pl_addr.port, port);
1942 		    bn_int_nset(&pl_addr.ip, addr);
1943 		}
1944 		bn_int_set(&pl_addr.unknown2, 0);
1945 		bn_int_set(&pl_addr.unknown3, 0);
1946 		packet_append_data(rpacket, &pl_addr, sizeof(pl_addr));
1947 
1948 		/* local addr */
1949 		bn_short_set(&pl_addr.unknown1, 2);
1950 		bn_short_nset(&pl_addr.port, conn_get_game_port(o));
1951 		bn_int_set(&pl_addr.ip, anongame_get_addr(oa));
1952 		bn_int_set(&pl_addr.unknown2, 0);
1953 		bn_int_set(&pl_addr.unknown3, 0);
1954 		packet_append_data(rpacket, &pl_addr, sizeof(pl_addr));
1955 
1956 		conn_push_outqueue(conn_get_routeconn(jc), rpacket);
1957 		packet_del_ref(rpacket);
1958 	    }
1959 	}
1960 
1961 	/* levelinfo */
1962 	if (!(rpacket = packet_create(packet_class_w3route))) {
1963 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] packet_create failed", conn_get_socket(c));
1964 	    return -1;
1965 	}
1966 
1967 	packet_set_size(rpacket, sizeof(t_server_w3route_levelinfo));
1968 	packet_set_type(rpacket, SERVER_W3ROUTE_LEVELINFO);
1969 	bn_byte_set(&rpacket->u.server_w3route_levelinfo.numplayers, anongame_get_currentplayers(a));
1970 
1971 	for (i = 0; i < tp; i++) {
1972 	    if (!anongame_get_player(ja, i))
1973 		continue;
1974 
1975 	    bn_byte_set(&li2.plnum, i + 1);
1976 	    bn_byte_set(&li2.unknown1, 3);
1977 
1978 	    switch (gametype) {
1979 		case ANONGAME_TYPE_1V1:
1980 		    level = account_get_ladder_level(conn_get_account(anongame_get_player(ja, i)), ct, ladder_id_solo);
1981 		    break;
1982 		case ANONGAME_TYPE_SMALL_FFA:
1983 		case ANONGAME_TYPE_TEAM_FFA:
1984 		    level = account_get_ladder_level(conn_get_account(anongame_get_player(ja, i)), ct, ladder_id_ffa);
1985 		    break;
1986 		case ANONGAME_TYPE_AT_2V2:
1987 		case ANONGAME_TYPE_AT_3V3:
1988 		case ANONGAME_TYPE_AT_4V4:
1989 		case ANONGAME_TYPE_AT_2V2V2:
1990 		    acct = conn_get_account(anongame_get_player(ja, i));
1991 		    level = team_get_level(account_find_team_by_teamid(acct, account_get_currentatteam(acct)));
1992 		    break;
1993 		case ANONGAME_TYPE_TY:
1994 		    level = 0;	/* FIXME-TY: WHAT TO DO HERE */
1995 		    break;
1996 		default:
1997 		    level = account_get_ladder_level(conn_get_account(anongame_get_player(ja, i)), ct, ladder_id_team);
1998 		    break;
1999 	    }
2000 
2001 	    /* first anongame shows level 0 as level 1 */
2002 	    bn_byte_set(&li2.level, level ? level : 1);
2003 
2004 	    bn_short_set(&li2.unknown2, 0);
2005 	    packet_append_data(rpacket, &li2, sizeof(li2));
2006 	}
2007 
2008 	conn_push_outqueue(conn_get_routeconn(jc), rpacket);
2009 	packet_del_ref(rpacket);
2010 
2011 	/* startgame1 */
2012 	if (!(rpacket = packet_create(packet_class_w3route))) {
2013 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] packet_create failed", conn_get_socket(c));
2014 	    return -1;
2015 	}
2016 	packet_set_size(rpacket, sizeof(t_server_w3route_startgame1));
2017 	packet_set_type(rpacket, SERVER_W3ROUTE_STARTGAME1);
2018 	conn_push_outqueue(conn_get_routeconn(jc), rpacket);
2019 	packet_del_ref(rpacket);
2020 
2021 	/* startgame2 */
2022 	if (!(rpacket = packet_create(packet_class_w3route))) {
2023 	    eventlog(eventlog_level_error, __FUNCTION__, "[%d] packet_create failed", conn_get_socket(c));
2024 	    return -1;
2025 	}
2026 	packet_set_size(rpacket, sizeof(t_server_w3route_startgame2));
2027 	packet_set_type(rpacket, SERVER_W3ROUTE_STARTGAME2);
2028 	conn_push_outqueue(conn_get_routeconn(jc), rpacket);
2029 	packet_del_ref(rpacket);
2030     }
2031     return 0;
2032 }
2033