1 #ifdef _WIN32
2 #define _WIN32_WINNT 0x0600
3 #define WIN32_LEAN_AND_MEAN
4 #endif
5 
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 
10 #define USE_IPV6
11 //#define MMULTI_DEBUG_SENDRECV
12 //#define MMULTI_DEBUG_SENDRECV_WIRE
13 
14 #ifdef _WIN32
15 #include <winsock2.h>
16 #include <ws2tcpip.h>
17 #include <mswsock.h>
18 
19 #define IPV6_RECVPKTINFO IPV6_PKTINFO
20 #define IS_INVALID_SOCKET(sock) (sock == INVALID_SOCKET)
21 
22 #ifndef CMSG_FIRSTHDR
23 #define CMSG_FIRSTHDR(m) WSA_CMSG_FIRSTHDR(m)
24 #endif
25 #ifndef CMSG_NXTHDR
26 #define CMSG_NXTHDR(m,c) WSA_CMSG_NXTHDR(m,c)
27 #endif
28 #ifndef CMSG_LEN
29 #define CMSG_LEN(l) WSA_CMSG_LEN(l)
30 #endif
31 #ifndef CMSG_SPACE
32 #define CMSG_SPACE(l) WSA_CMSG_SPACE(l)
33 #endif
34 #define CMSG_DATA(c) WSA_CMSG_DATA(c)
35 
36 LPFN_WSASENDMSG WSASendMsgPtr;
37 LPFN_WSARECVMSG WSARecvMsgPtr;
38 
39 #else
40 
41 #ifdef __APPLE__
42 # define __APPLE_USE_RFC_3542
43 #endif
44 #ifdef __GNUC__
45 # define __USE_GNU
46 #endif
47 
48 #include <unistd.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
51 #include <sys/ioctl.h>
52 #include <sys/socket.h>
53 #include <netdb.h>
54 #define SOCKET int
55 
56 #include <sys/time.h>
GetTickCount(void)57 static int GetTickCount(void)
58 {
59 	struct timeval tv;
60 	int ti;
61 	if (gettimeofday(&tv,NULL) < 0) return 0;
62 	// tv is sec.usec, GTC gives msec
63 	ti = tv.tv_sec * 1000;
64 	ti += tv.tv_usec / 1000;
65 	return ti;
66 }
67 
68 #define IS_INVALID_SOCKET(sock) (sock < 0)
69 
70 #endif
71 
72 #include "build.h"
73 #include "mmulti.h"
74 #include "baselayer.h"
75 #define printf buildprintf
76 
77 #ifndef min
78 #define min(a,b) ((a)<(b)?(a):(b))
79 #endif
80 
81 #define MAXPLAYERS 16
82 #define MAXPAKSIZ 256 //576
83 
84 #define PAKRATE 40   //Packet rate/sec limit ... necessary?
85 #define SIMMIS 0     //Release:0  Test:100 Packets per 256 missed.
86 #define SIMLAG 0     //Release:0  Test: 10 Packets to delay receipt
87 #define PRESENCETIMEOUT 2000
88 static int simlagcnt[MAXPLAYERS];
89 static unsigned char simlagfif[MAXPLAYERS][SIMLAG+1][MAXPAKSIZ+2];
90 #if ((SIMMIS != 0) || (SIMLAG != 0))
91 #pragma message("\n\nWARNING! INTENTIONAL PACKET LOSS SIMULATION IS ENABLED!\nREMEMBER TO CHANGE SIMMIS&SIMLAG to 0 before RELEASE!\n\n")
92 #endif
93 
94 int myconnectindex, numplayers, networkmode = -1;
95 int connecthead, connectpoint2[MAXPLAYERS];
96 
97 static int tims, lastsendtims[MAXPLAYERS], lastrecvtims[MAXPLAYERS], prevlastrecvtims[MAXPLAYERS];
98 static unsigned char pakbuf[MAXPAKSIZ], playerslive[MAXPLAYERS];
99 
100 #define FIFSIZ 512 //16384/40 = 6min:49sec
101 static int ipak[MAXPLAYERS][FIFSIZ], icnt0[MAXPLAYERS];
102 static int opak[MAXPLAYERS][FIFSIZ], ocnt0[MAXPLAYERS], ocnt1[MAXPLAYERS];
103 static unsigned char pakmem[4194304]; static int pakmemi = 1;
104 
105 #define NETPORT 0x5bd9
106 static SOCKET mysock = -1;
107 static int domain = PF_UNSPEC;
108 static struct sockaddr_storage otherhost[MAXPLAYERS], snatchhost;	// IPV4/6 address of peers
109 static struct in_addr replyfrom4[MAXPLAYERS], snatchreplyfrom4;		// our IPV4 address peers expect to hear from us on
110 static struct in6_addr replyfrom6[MAXPLAYERS], snatchreplyfrom6;	// our IPV6 address peers expect to hear from us on
111 static int netready = 0;
112 
113 static int lookuphost(const char *name, struct sockaddr *host, int warnifmany);
114 static int issameaddress(struct sockaddr *a, struct sockaddr *b);
115 static const char *presentaddress(struct sockaddr *a);
116 static void savesnatchhost(int other);
117 
netuninit()118 void netuninit ()
119 {
120 #ifdef _WIN32
121 	if (mysock != INVALID_SOCKET) closesocket(mysock);
122 	WSACleanup();
123 	mysock = INVALID_SOCKET;
124 
125 	WSASendMsgPtr = NULL;
126 	WSARecvMsgPtr = NULL;
127 #else
128 	if (mysock >= 0) close(mysock);
129 	mysock = -1;
130 #endif
131 	domain = PF_UNSPEC;
132 }
133 
netinit(int portnum)134 int netinit (int portnum)
135 {
136 #ifdef _WIN32
137 	WSADATA ws;
138 	u_long off = 0, on = 1;
139 #else
140 	unsigned int off = 0, on = 1;
141 #endif
142 
143 #ifdef _WIN32
144 	if (WSAStartup(0x202, &ws) != 0) return(0);
145 #endif
146 
147 #ifdef USE_IPV6
148 	domain = PF_INET6;
149 #else
150 	domain = PF_INET;
151 #endif
152 
153 	while (domain != PF_UNSPEC) {
154 		// Tidy up from last cycle.
155 #ifdef _WIN32
156 		if (mysock != INVALID_SOCKET) closesocket(mysock);
157 		WSASendMsgPtr = NULL;
158 		WSARecvMsgPtr = NULL;
159 #else
160 		if (mysock >= 0) close(mysock);
161 #endif
162 
163 		mysock = socket(domain, SOCK_DGRAM, 0);
164 		if (IS_INVALID_SOCKET(mysock)) {
165 			if (domain == PF_INET6) {
166 				// Retry for IPV4.
167 				printf("mmulti warning: could not create IPV6 socket, trying for IPV4.\n");
168 				domain = PF_INET;
169 				continue;
170 			} else {
171 				// No IPV4 is a total loss.
172 				printf("mmulti error: could not create IPV4 socket, no multiplayer possible.\n");
173 				break;
174 			}
175 		}
176 
177 #ifdef _WIN32
178 		DWORD len;
179 		GUID sendguid = WSAID_WSASENDMSG, recvguid = WSAID_WSARECVMSG;
180 		if (WSAIoctl(mysock, SIO_GET_EXTENSION_FUNCTION_POINTER,
181 				&sendguid, sizeof(sendguid), &WSASendMsgPtr, sizeof(WSASendMsgPtr),
182 				&len, NULL, NULL) == SOCKET_ERROR) {
183 			printf("mmulti error: could not get sendmsg entry point.\n");
184 			break;
185 		}
186 		if (WSAIoctl(mysock, SIO_GET_EXTENSION_FUNCTION_POINTER,
187 				&recvguid, sizeof(recvguid), &WSARecvMsgPtr, sizeof(WSARecvMsgPtr),
188 				&len, NULL, NULL) == SOCKET_ERROR) {
189 			printf("mmulti error: could not get recvmsg entry point.\n");
190 			break;
191 		}
192 #endif
193 
194 		// Set non-blocking IO on the socket.
195 #ifdef _WIN32
196 		if (ioctlsocket(mysock, FIONBIO, &on) != 0)
197 #else
198 		if (ioctl(mysock, FIONBIO, &on) != 0)
199 #endif
200 		{
201 			printf("mmulti error: could not enable non-blocking IO on socket.\n");
202 			break;
203 		}
204 
205 		// Allow local address reuse.
206 		if (setsockopt(mysock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)) != 0) {
207 			printf("mmulti error: could not enable local address reuse on socket.\n");
208 			break;
209 		}
210 
211 		// Request that we receive IPV4 packet info.
212 #if defined(__linux) || defined(_WIN32)
213 		if (setsockopt(mysock, IPPROTO_IP, IP_PKTINFO, (void *)&on, sizeof(on)) != 0)
214 #else
215 		if (domain == PF_INET && setsockopt(mysock, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on)) != 0)
216 #endif
217 		{
218 			if (domain == PF_INET) {
219 				printf("mmulti error: could not enable IPV4 packet info on socket.\n");
220 				break;
221 			} else {
222 				printf("mmulti warning: could not enable IPV4 packet info on socket.\n");
223 			}
224 		}
225 
226 		if (domain == PF_INET6) {
227 			// Allow dual-stack IPV4/IPV6 on the socket.
228 			if (setsockopt(mysock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&off, sizeof(off)) != 0) {
229 				printf("mmulti warning: could not enable dual-stack socket, retrying for IPV4.\n");
230 				domain = PF_INET;
231 				continue;
232 			}
233 
234 			// Request that we receive IPV6 packet info.
235 			if (setsockopt(mysock, IPPROTO_IPV6, IPV6_RECVPKTINFO, (void *)&on, sizeof(on)) != 0) {
236 				printf("mmulti error: could not enable IPV6 packet info on socket.\n");
237 				break;
238 			}
239 
240 			struct sockaddr_in6 host;
241 			memset(&host, 0, sizeof(host));
242 			host.sin6_family = AF_INET6;
243 			host.sin6_port = htons(portnum);
244 			host.sin6_addr = in6addr_any;
245 			if (bind(mysock, (struct sockaddr *)&host, sizeof(host)) != 0) {
246 				// Retry for IPV4.
247 				domain = PF_INET;
248 				continue;
249 			}
250 		} else {
251 			struct sockaddr_in host;
252 			memset(&host, 0, sizeof(host));
253 			host.sin_family = AF_INET;
254 			host.sin_port = htons(portnum);
255 			host.sin_addr.s_addr = INADDR_ANY;
256 			if (bind(mysock, (struct sockaddr *)&host, sizeof(host)) != 0) {
257 				// No IPV4 is a total loss.
258 				break;
259 			}
260 		}
261 
262 		// Complete success.
263 		return 1;
264 	}
265 
266 	netuninit();
267 
268 	return 0;
269 }
270 
netsend(int other,void * dabuf,int bufsiz)271 int netsend (int other, void *dabuf, int bufsiz) //0:buffer full... can't send
272 {
273 	char msg_control[1024];
274 	if (otherhost[other].ss_family == AF_UNSPEC) return(0);
275 
276 	if (otherhost[other].ss_family != domain) {
277 #ifdef MMULTI_DEBUG_SENDRECV_WIRE
278 		debugprintf("mmulti debug send error: tried sending to a different protocol family\n");
279 #endif
280 		return 0;
281 	}
282 
283 #ifdef MMULTI_DEBUG_SENDRECV_WIRE
284 	{
285 		int i;
286 		const unsigned char *pakbuf = dabuf;
287 		debugprintf("mmulti debug send: "); for(i=0;i<bufsiz;i++) debugprintf("%02x ",pakbuf[i]); debugprintf("\n");
288 	}
289 #endif
290 
291 #ifdef _WIN32
292 	WSABUF iovec;
293 	WSAMSG msg;
294 	WSACMSGHDR *cmsg;
295 	DWORD len = 0;
296 
297 	iovec.buf = dabuf;
298 	iovec.len = bufsiz;
299 	msg.name = (LPSOCKADDR)&otherhost[other];
300 	if (otherhost[other].ss_family == AF_INET) {
301 		msg.namelen = sizeof(struct sockaddr_in);
302 	} else {
303 		msg.namelen = sizeof(struct sockaddr_in6);
304 	}
305 	msg.lpBuffers = &iovec;
306 	msg.dwBufferCount = 1;
307 	msg.Control.buf = msg_control;
308 	msg.Control.len = sizeof(msg_control);
309 	msg.dwFlags = 0;
310 #else
311 	struct iovec iovec;
312 	struct msghdr msg;
313 	struct cmsghdr *cmsg;
314 	int len;
315 
316 	iovec.iov_base = dabuf;
317 	iovec.iov_len = bufsiz;
318 	msg.msg_name = &otherhost[other];
319 	if (otherhost[other].ss_family == AF_INET) {
320 		msg.msg_namelen = sizeof(struct sockaddr_in);
321 	} else {
322 		msg.msg_namelen = sizeof(struct sockaddr_in6);
323 	}
324 	msg.msg_iov = &iovec;
325 	msg.msg_iovlen = 1;
326 	msg.msg_control = msg_control;
327 	msg.msg_controllen = sizeof(msg_control);
328 	msg.msg_flags = 0;
329 #endif
330 
331 	len = 0;
332 	memset(msg_control, 0, sizeof(msg_control));
333 
334 	cmsg = CMSG_FIRSTHDR(&msg);
335 #if !defined(__APPLE__) && !defined(__DragonFly__)
336 	// OS X doesn't implement setting the UDP4 source. We'll
337 	// just have to cross our fingers.
338 	if (replyfrom4[other].s_addr != INADDR_ANY) {
339 		cmsg->cmsg_level = IPPROTO_IP;
340 #if defined(__linux) || defined(_WIN32)
341 		cmsg->cmsg_type = IP_PKTINFO;
342 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
343 		#ifdef _WIN32
344 		((struct in_pktinfo *)CMSG_DATA(cmsg))->ipi_addr = replyfrom4[other];
345 		#else
346 		((struct in_pktinfo *)CMSG_DATA(cmsg))->ipi_spec_dst = replyfrom4[other];
347 		#endif
348 		len += CMSG_SPACE(sizeof(struct in_pktinfo));
349 #else
350 		cmsg->cmsg_type = IP_SENDSRCADDR;
351 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
352 		*(struct in_addr *)CMSG_DATA(cmsg) = replyfrom4[other];
353 		len += CMSG_SPACE(sizeof(struct in_addr));
354 #endif
355 		cmsg = CMSG_NXTHDR(&msg, cmsg);
356 	}
357 #endif
358 	if (!IN6_IS_ADDR_UNSPECIFIED(&replyfrom6[other])) {
359 		cmsg->cmsg_level = IPPROTO_IPV6;
360 		cmsg->cmsg_type = IPV6_PKTINFO;
361 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
362 		((struct in6_pktinfo *)CMSG_DATA(cmsg))->ipi6_addr = replyfrom6[other];
363 		len += CMSG_SPACE(sizeof(struct in6_pktinfo));
364 		cmsg = CMSG_NXTHDR(&msg, cmsg);
365 	}
366 #ifdef _WIN32
367 	msg.Control.len = len;
368 	if (len == 0) {
369 		msg.Control.buf = NULL;
370 	}
371 #else
372 	msg.msg_controllen = len;
373 	if (len == 0) {
374 		msg.msg_control = NULL;
375 	}
376 #endif
377 
378 #ifdef _WIN32
379 	if (WSASendMsgPtr(mysock, &msg, 0, &len, NULL, NULL) == SOCKET_ERROR)
380 #else
381 	if ((len = sendmsg(mysock, &msg, 0)) < 0)
382 #endif
383 	{
384 #ifdef MMULTI_DEBUG_SENDRECV_WIRE
385 		debugprintf("mmulti debug send error: %s\n", strerror(errno));
386 #endif
387 		return 0;
388 	}
389 
390 	return 1;
391 }
392 
netread(int * other,void * dabuf,int bufsiz)393 int netread (int *other, void *dabuf, int bufsiz) //0:no packets in buffer
394 {
395 	char msg_control[1024];
396 	int i;
397 
398 #ifdef _WIN32
399 	WSABUF iovec;
400 	WSAMSG msg;
401 	WSACMSGHDR *cmsg;
402 	DWORD len = 0;
403 
404 	iovec.buf = dabuf;
405 	iovec.len = bufsiz;
406 	msg.name = (LPSOCKADDR)&snatchhost;
407 	msg.namelen = sizeof(snatchhost);
408 	msg.lpBuffers = &iovec;
409 	msg.dwBufferCount = 1;
410 	msg.Control.buf = msg_control;
411 	msg.Control.len = sizeof(msg_control);
412 	msg.dwFlags = 0;
413 
414 	if (WSARecvMsgPtr(mysock, &msg, &len, NULL, NULL) == SOCKET_ERROR) return 0;
415 #else
416 	struct iovec iovec;
417 	struct msghdr msg;
418 	struct cmsghdr *cmsg;
419 	int len;
420 
421 	iovec.iov_base = dabuf;
422 	iovec.iov_len = bufsiz;
423 	msg.msg_name = &snatchhost;
424 	msg.msg_namelen = sizeof(snatchhost);
425 	msg.msg_iov = &iovec;
426 	msg.msg_iovlen = 1;
427 	msg.msg_control = msg_control;
428 	msg.msg_controllen = sizeof(msg_control);
429 	msg.msg_flags = 0;
430 
431 	if ((len = recvmsg(mysock, &msg, 0)) < 0) return 0;
432 #endif
433 	if (len == 0) return 0;
434 
435 	if (snatchhost.ss_family != domain) {
436 #ifdef MMULTI_DEBUG_SENDRECV_WIRE
437 		debugprintf("mmulti debug recv error: received from a different protocol family\n");
438 #endif
439 		return 0;
440 	}
441 
442 #if (SIMMIS > 0)
443 	if ((rand()&255) < SIMMIS) return(0);
444 #endif
445 
446 	// Decode the message headers to record what of our IP addresses the
447 	// packet came in on. We reply on that same address so the peer knows
448 	// who it came from.
449 	memset(&snatchreplyfrom4, 0, sizeof(snatchreplyfrom4));
450 	memset(&snatchreplyfrom6, 0, sizeof(snatchreplyfrom6));
451 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
452 #if defined(__linux) || defined(_WIN32)
453 		if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
454 			snatchreplyfrom4 = ((struct in_pktinfo *)CMSG_DATA(cmsg))->ipi_addr;
455 #ifdef MMULTI_DEBUG_SENDRECV_WIRE
456 			debugprintf("mmulti debug recv: received at %s\n", inet_ntoa(snatchreplyfrom4));
457 #endif
458 		}
459 #else
460 		if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) {
461 			snatchreplyfrom4 = *(struct in_addr *)CMSG_DATA(cmsg);
462 #ifdef MMULTI_DEBUG_SENDRECV_WIRE
463 			debugprintf("mmulti debug recv: received at %s\n", inet_ntoa(snatchreplyfrom4));
464 #endif
465 		}
466 #endif
467 		else if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
468 			snatchreplyfrom6 = ((struct in6_pktinfo *)CMSG_DATA(cmsg))->ipi6_addr;
469 #ifdef MMULTI_DEBUG_SENDRECV_WIRE
470 			char addr[INET6_ADDRSTRLEN+1];
471 			debugprintf("mmulti debug recv: received at %s\n", inet_ntop(AF_INET6, &snatchreplyfrom6, addr, sizeof(addr)));
472 #endif
473 		}
474 	}
475 
476 #ifdef MMULTI_DEBUG_SENDRECV_WIRE
477 	{
478 		const unsigned char *pakbuf = dabuf;
479 		debugprintf("mmulti debug recv: ");
480 		for(i=0;i<len;i++) debugprintf("%02x ",pakbuf[i]);
481 		debugprintf("\n");
482 	}
483 #endif
484 
485 	(*other) = myconnectindex;
486 	for(i=0;i<MAXPLAYERS;i++) {
487 		if (issameaddress((struct sockaddr *)&snatchhost, (struct sockaddr *)&otherhost[i]))
488 			{ (*other) = i; break; }
489 	}
490 
491 #if (SIMLAG > 1)
492 	i = simlagcnt[*other]%(SIMLAG+1);
493 	*(short *)&simlagfif[*other][i][0] = bufsiz; memcpy(&simlagfif[*other][i][2],dabuf,bufsiz);
494 	simlagcnt[*other]++; if (simlagcnt[*other] < SIMLAG+1) return(0);
495 	i = simlagcnt[*other]%(SIMLAG+1);
496 	bufsiz = *(short *)&simlagfif[*other][i][0]; memcpy(dabuf,&simlagfif[*other][i][2],bufsiz);
497 #endif
498 
499 	return(1);
500 }
501 
issameaddress(struct sockaddr * a,struct sockaddr * b)502 static int issameaddress(struct sockaddr *a, struct sockaddr *b) {
503 	if (a->sa_family != b->sa_family) {
504 		// Different families.
505 		return 0;
506 	}
507 	if (a->sa_family == AF_INET) {
508 		// IPV4.
509 		struct sockaddr_in *a4 = (struct sockaddr_in *)a;
510 		struct sockaddr_in *b4 = (struct sockaddr_in *)b;
511 		return a4->sin_addr.s_addr == b4->sin_addr.s_addr &&
512 			a4->sin_port == b4->sin_port;
513 	}
514 	if (a->sa_family == AF_INET6) {
515 		// IPV6.
516 		struct sockaddr_in6 *a6 = (struct sockaddr_in6 *)a;
517 		struct sockaddr_in6 *b6 = (struct sockaddr_in6 *)b;
518 		return IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr) &&
519 			a6->sin6_port == b6->sin6_port;
520 	}
521 	return 0;
522 }
523 
presentaddress(struct sockaddr * a)524 static const char *presentaddress(struct sockaddr *a) {
525 	static char str[128+32];
526 	char addr[128];
527 	int port;
528 
529 	if (a->sa_family == AF_INET) {
530 		struct sockaddr_in *s = (struct sockaddr_in *)a;
531 		inet_ntop(AF_INET, &s->sin_addr, addr, sizeof(addr));
532 		port = ntohs(s->sin_port);
533 	} else if (a->sa_family == AF_INET6) {
534 		struct sockaddr_in6 *s = (struct sockaddr_in6 *)a;
535 		strcpy(addr, "[");
536 		inet_ntop(AF_INET6, &s->sin6_addr, addr+1, sizeof(addr)-2);
537 		strcat(addr, "]");
538 		port = ntohs(s->sin6_port);
539 	} else {
540 		return NULL;
541 	}
542 
543 	strcpy(str, addr);
544 	sprintf(addr, ":%d", port);
545 	strcat(str, addr);
546 
547 	return str;
548 }
549 
550 //---------------------------------- Obsolete variables&functions ----------------------------------
551 unsigned char syncstate = 0;
setpackettimeout(int UNUSED (datimeoutcount),int UNUSED (daresendagaincount))552 void setpackettimeout (int UNUSED(datimeoutcount), int UNUSED(daresendagaincount)) {}
genericmultifunction(int UNUSED (other),unsigned char * UNUSED (bufptr),int UNUSED (messleng),int UNUSED (command))553 void genericmultifunction (int UNUSED(other), unsigned char *UNUSED(bufptr), int UNUSED(messleng), int UNUSED(command)) {}
getoutputcirclesize()554 int getoutputcirclesize () { return(0); }
setsocket(int UNUSED (newsocket))555 void setsocket (int UNUSED(newsocket)) { }
sendlogon()556 void sendlogon () {}
sendlogoff()557 void sendlogoff () {}
558 //--------------------------------------------------------------------------------------------------
559 
560 static int crctab16[256];
initcrc16()561 static void initcrc16 ()
562 {
563 	int i, j, k, a;
564 	for(j=0;j<256;j++)
565 	{
566 		for(i=7,k=(j<<8),a=0;i>=0;i--,k=((k<<1)&65535))
567 		{
568 			if ((k^a)&0x8000) a = ((a<<1)&65535)^0x1021;
569 							 else a = ((a<<1)&65535);
570 		}
571 		crctab16[j] = (a&65535);
572 	}
573 }
574 #define updatecrc16(crc,dat) crc = (((crc<<8)&65535)^crctab16[((((unsigned short)crc)>>8)&65535)^dat])
getcrc16(unsigned char * buffer,int bufleng)575 static unsigned short getcrc16 (unsigned char *buffer, int bufleng)
576 {
577 	int i, j;
578 
579 	j = 0;
580 	for(i=bufleng-1;i>=0;i--) updatecrc16(j,buffer[i]);
581 	return((unsigned short)(j&65535));
582 }
583 
uninitmultiplayers()584 void uninitmultiplayers () { netuninit(); }
585 
initmultiplayers_reset(void)586 static void initmultiplayers_reset(void)
587 {
588 	int i;
589 
590 	initcrc16();
591 	memset(icnt0,0,sizeof(icnt0));
592 	memset(ocnt0,0,sizeof(ocnt0));
593 	memset(ocnt1,0,sizeof(ocnt1));
594 	memset(ipak,0,sizeof(ipak));
595 	//memset(opak,0,sizeof(opak)); //Don't need to init opak
596 	//memset(pakmem,0,sizeof(pakmem)); //Don't need to init pakmem
597 #if (SIMLAG > 1)
598 	memset(simlagcnt,0,sizeof(simlagcnt));
599 #endif
600 
601 	lastsendtims[0] = GetTickCount();
602 	for(i=0;i<MAXPLAYERS;i++) {
603 		lastsendtims[i] = lastsendtims[0];
604 		lastrecvtims[i] = prevlastrecvtims[i] = 0;
605 		connectpoint2[i] = -1;
606 		playerslive[i] = 0;
607 	}
608 	connecthead = 0;
609 	numplayers = 1; myconnectindex = 0;
610 
611 	memset(otherhost,0,sizeof(otherhost));
612 }
613 
initsingleplayers(void)614 void initsingleplayers(void)
615 {
616     initmultiplayers_reset();
617 }
618 
619 	// Multiplayer command line summary. Assume myconnectindex always = 0 for 192.168.1.2
620 	//
621 	// /n0 (mast/slav) 2 player:               3 player:
622 	// 192.168.1.2     game /n0                game /n0:3
623 	// 192.168.1.100   game /n0 192.168.1.2    game /n0 192.168.1.2
624 	// 192.168.1.4                             game /n0 192.168.1.2
625 	//
626 	// /n1 (peer-peer) 2 player:               3 player:
627 	// 192.168.1.2     game /n1 * 192.168.1.100  game /n1 * 192.168.1.100 192.168.1.4
628 	// 192.168.1.100   game /n2 192.168.1.2 *    game /n1 192.168.1.2 * 192.168.1.4
629 	// 192.168.1.4                               game /n1 192.168.1.2 192.168.1.100 *
630 	// Note: '.' may also be used in place of '*'
initmultiplayersparms(int argc,char const * const argv[])631 int initmultiplayersparms(int argc, char const * const argv[])
632 {
633 	int i, j, daindex, danumplayers, danetmode, portnum = NETPORT;
634 	struct sockaddr_storage resolvhost;
635 
636 	initmultiplayers_reset();
637 	danetmode = 255; daindex = 0; danumplayers = 0;
638 
639 	for (i=0;i<argc;i++) {
640 		if (argv[i][0] != '-' && argv[i][0] != '/') continue;
641 
642 		// -p1234 = Listen port
643 		if ((argv[i][1] == 'p' || argv[i][1] == 'P') && argv[i][2]) {
644 			char *p;
645 			j = strtol(argv[i]+2, &p, 10);
646 			if (!(*p) && j > 0 && j<65535) portnum = j;
647 
648 			printf("mmulti: Using port %d\n", portnum);
649 			continue;
650 		}
651 
652 		// -nm,   -n0   = Master/slave, 2 players
653 		// -nm:n, -n0:n = Master/slave, n players
654 		// -np,   -n1   = Peer-to-peer
655 		if ((argv[i][1] == 'N') || (argv[i][1] == 'n') || (argv[i][1] == 'I') || (argv[i][1] == 'i'))
656 		{
657 			danumplayers = 2;
658 			if (argv[i][2] == '0' || argv[i][2] == 'm' || argv[i][2] == 'M')
659 			{
660 				danetmode = MMULTI_MODE_MS;
661 				printf("mmulti: Master-slave mode\n");
662 
663 				if ((argv[i][3] == ':') && (argv[i][4] >= '0') && (argv[i][4] <= '9'))
664 				{
665 					char *p;
666 					j = strtol(argv[i]+4, &p, 10);
667 					if (!(*p) && j > 0 && j <= MAXPLAYERS) {
668 						danumplayers = j;
669 						printf("mmulti: %d-player game\n", danumplayers);
670 					} else {
671 						printf("mmulti error: Invalid number of players\n");
672 						return 0;
673 					}
674 				}
675 			}
676 			else if (argv[i][2] == '1' || argv[i][2] == 'p' || argv[i][2] == 'P')
677 			{
678 				danetmode = MMULTI_MODE_P2P;
679 				printf("mmulti: Peer-to-peer mode\n");
680 			}
681 			continue;
682 		}
683 	}
684 
685 	if (!netinit(portnum)) {
686 		printf("mmulti error: Could not initialise networking\n");
687 		return 0;
688 	}
689 
690 	for(i=0;i<argc;i++)
691 	{
692 		if ((argv[i][0] == '-') || (argv[i][0] == '/')) {
693 			continue;
694 		}
695 
696 		if (danetmode == MMULTI_MODE_MS && daindex >= 1) {
697 			printf("mmulti warning: Too many host names given for master-slave mode\n");
698 			continue;
699 		}
700 		if (daindex >= MAXPLAYERS) {
701 			printf("mmulti error: More than %d players provided\n", MAXPLAYERS);
702 			netuninit();
703 			return 0;
704 		}
705 
706 		if ((argv[i][0] == '*' || argv[i][0] == '.') && argv[i][1] == 0) {
707 			// 'self' placeholder
708 			if (danetmode == MMULTI_MODE_MS) {
709 				printf("mmulti: %c is not valid in master-slave mode\n", argv[i][0]);
710 				netuninit();
711 				return 0;
712 			} else {
713 				myconnectindex = daindex++;
714 				printf("mmulti: This machine is player %d\n", myconnectindex);
715 			}
716 			continue;
717 		}
718 
719 		if (!lookuphost(argv[i], (struct sockaddr *)&resolvhost, danetmode == MMULTI_MODE_P2P)) {
720 			printf("mmulti error: Could not resolve %s\n", argv[i]);
721 			netuninit();
722 			return 0;
723 		} else {
724 			memcpy(&otherhost[daindex], &resolvhost, sizeof(resolvhost));
725 			printf("mmulti: Player %d at %s (%s)\n", daindex,
726 				presentaddress((struct sockaddr *)&resolvhost), argv[i]);
727 			daindex++;
728 		}
729 	}
730 
731 	if ((danetmode == 255) && (daindex)) { danumplayers = 2; danetmode = MMULTI_MODE_MS; } //an IP w/o /n# defaults to /n0
732 	if ((danumplayers >= 2) && (daindex) && (danetmode == MMULTI_MODE_MS)) myconnectindex = 1;
733 	if (daindex > danumplayers) danumplayers = daindex;
734 	else if (danumplayers == 0) danumplayers = 1;
735 
736 	if (danetmode == MMULTI_MODE_MS && myconnectindex == 0) {
737 		printf("mmulti: This machine is master\n");
738 	}
739 
740 	networkmode = danetmode;
741 	numplayers = danumplayers;
742 
743 	connecthead = 0;
744 	for(i=0;i<numplayers-1;i++) connectpoint2[i] = i+1;
745 	connectpoint2[numplayers-1] = -1;
746 
747 	netready = 0;
748 
749 	if (((danetmode == MMULTI_MODE_MS) && (numplayers >= 2)) || (numplayers == 2)) {
750 		return 1;
751 	} else {
752 		netuninit();
753 		return 0;
754 	}
755 }
756 
initmultiplayerscycle(void)757 int initmultiplayerscycle(void)
758 {
759 	int i, k, dnetready = 1;
760 
761 	getpacket(&i,0);
762 
763 	tims = GetTickCount();
764 
765 	if (networkmode == MMULTI_MODE_MS && myconnectindex == connecthead)
766 	{
767 		// The master waits for all players to check in.
768 		for(i=numplayers-1;i>0;i--) {
769 			if (i == myconnectindex) continue;
770 			if (otherhost[i].ss_family == AF_UNSPEC) {
771 				// There's a slot to be filled.
772 				dnetready = 0;
773 			} else if (lastrecvtims[i] == 0) {
774 				// There's a player who hasn't checked in.
775 				dnetready = 0;
776 			} else if (prevlastrecvtims[i] != lastrecvtims[i]) {
777 				if (!playerslive[i]) {
778 					printf("mmulti: Player %d is here\n", i);
779 					playerslive[i] = 1;
780 				}
781 				prevlastrecvtims[i] = lastrecvtims[i];
782 			} else if (tims - lastrecvtims[i] > PRESENCETIMEOUT) {
783 				if (playerslive[i]) {
784 					printf("mmulti: Player %d has gone\n", i);
785 					playerslive[i] = 0;
786 				}
787 				prevlastrecvtims[i] = lastrecvtims[i];
788 				dnetready = 0;
789 			}
790 		}
791 	}
792 	else
793 	{
794 		if (networkmode == MMULTI_MODE_MS) {
795 			// As a slave, we send the master pings. The netready flag gets
796 			// set by getpacket() and is sent by the master when it is OK
797 			// to launch.
798 			dnetready = 0;
799 			i = connecthead;
800 
801 		} else {
802 			// In peer-to-peer mode we send pings to our peer group members
803 			// and wait for them all to check in. The netready flag is set
804 			// when everyone responds together within the timeout.
805 			i = numplayers - 1;
806 		}
807 		while (1) {
808 			if (i != myconnectindex) {
809 				if (tims < lastsendtims[i]) lastsendtims[i] = tims;
810 				if (tims >= lastsendtims[i]+250) //1000/PAKRATE)
811 				{
812 #ifdef MMULTI_DEBUG_SENDRECV
813 					debugprintf("mmulti debug: sending player %d a ping\n", i);
814 #endif
815 
816 					lastsendtims[i] = tims;
817 
818 						//   short crc16ofs;       //offset of crc16
819 						//   int icnt0;           //-1 (special packet for MMULTI.C's player collection)
820 						//   ...
821 						//   unsigned short crc16; //CRC16 of everything except crc16
822 					k = 2;
823 					*(int *)&pakbuf[k] = -1; k += 4;
824 					pakbuf[k++] = 0xaa;
825 					*(unsigned short *)&pakbuf[0] = (unsigned short)k;
826 					*(unsigned short *)&pakbuf[k] = getcrc16(pakbuf,k); k += 2;
827 					netsend(i,pakbuf,k);
828 				}
829 
830 				if (lastrecvtims[i] == 0) {
831 					// There's a player who hasn't checked in.
832 					dnetready = 0;
833 				} else if (prevlastrecvtims[i] != lastrecvtims[i]) {
834 					if (!playerslive[i]) {
835 						printf("mmulti: Player %d is here\n", i);
836 						playerslive[i] = 1;
837 					}
838 					prevlastrecvtims[i] = lastrecvtims[i];
839 				} else if (prevlastrecvtims[i] - tims > PRESENCETIMEOUT) {
840 					if (playerslive[i]) {
841 						printf("mmulti: Player %d has gone\n", i);
842 						playerslive[i] = 0;
843 					}
844 					prevlastrecvtims[i] = lastrecvtims[i];
845 					dnetready = 0;
846 				}
847 			}
848 
849 			if (networkmode == MMULTI_MODE_MS) {
850 				break;
851 			} else {
852 				if (--i < 0) break;
853 			}
854 		}
855 	}
856 
857 	netready = netready || dnetready;
858 
859 	return !netready;
860 }
861 
initmultiplayers(int argc,char const * const argv[])862 void initmultiplayers (int argc, char const * const argv[])
863 {
864 	int i, j, k, otims;
865 
866 	if (initmultiplayersparms(argc,argv))
867 	{
868 		while (initmultiplayerscycle())
869 		{
870 		}
871 	}
872 }
873 
lookuphost(const char * name,struct sockaddr * host,int warnifmany)874 static int lookuphost(const char *name, struct sockaddr *host, int warnifmany)
875 {
876 	struct addrinfo * result, *res;
877 	struct addrinfo hints;
878 	char *wname, *portch;
879 	int error, port = 0, found = 0;
880 
881 	// ipv6 for future thought:
882 	//  [2001:db8::1]:1234
883 
884 	wname = strdup(name);
885 	if (!wname) {
886 		return 0;
887 	}
888 
889 	// Parse a port.
890 	portch = strrchr(wname, ':');
891 	if (portch) {
892 		*(portch++) = 0;
893 		if (*portch != 0) {
894 			port = strtol(portch, NULL, 10);
895 		}
896 	}
897 	if (port < 1025 || port > 65534) port = NETPORT;
898 
899 	memset(&hints, 0, sizeof(hints));
900 	hints.ai_flags = AI_ADDRCONFIG;
901 	hints.ai_family = domain;
902 	if (domain == PF_INET6) {
903 		hints.ai_flags |= AI_V4MAPPED;
904 	}
905 	hints.ai_socktype = SOCK_DGRAM;
906 	hints.ai_protocol = IPPROTO_UDP;
907 
908 	error = getaddrinfo(wname, NULL, &hints, &result);
909 	if (error) {
910 		printf("mmulti error: problem resolving %s (%s)\n", name, gai_strerror(error));
911 		free(wname);
912 		return 0;
913 	}
914 
915 	for (res = result; res; res = res->ai_next) {
916 		if (res->ai_family == PF_INET && !found) {
917 			memcpy((struct sockaddr_in *)host, (struct sockaddr_in *)res->ai_addr, sizeof(struct sockaddr_in));
918 			((struct sockaddr_in *)host)->sin_port = htons(port);
919 			found = 1;
920 		} else if (res->ai_family == PF_INET6 && !found) {
921 			memcpy((struct sockaddr_in6 *)host, (struct sockaddr_in6 *)res->ai_addr, sizeof(struct sockaddr_in6));
922 			((struct sockaddr_in6 *)host)->sin6_port = htons(port);
923 			found = 1;
924 		} else if (found && warnifmany) {
925 			printf("mmulti warning: host name %s has another address: %s\n", wname, presentaddress(res->ai_addr));
926 		}
927 	}
928 
929 	freeaddrinfo(result);
930 	free(wname);
931 	return found;
932 }
933 
dosendpackets(int other)934 void dosendpackets (int other)
935 {
936 	int i, j, k;
937 
938 	if (otherhost[other].ss_family == AF_UNSPEC) return;
939 
940 		//Packet format:
941 		//   short crc16ofs;       //offset of crc16
942 		//   int icnt0;           //earliest unacked packet
943 		//   char ibits[32];       //ack status of packets icnt0<=i<icnt0+256
944 		//   while (short leng)    //leng: !=0 for packet, 0 for no more packets
945 		//   {
946 		//      int ocnt;         //index of following packet data
947 		//      char pak[leng];    //actual packet data :)
948 		//   }
949 		//   unsigned short crc16; //CRC16 of everything except crc16
950 
951 
952 	tims = GetTickCount();
953 	if (tims < lastsendtims[other]) lastsendtims[other] = tims;
954 	if (tims < lastsendtims[other]+1000/PAKRATE) return;
955 	lastsendtims[other] = tims;
956 
957 	k = 2;
958 	*(int *)&pakbuf[k] = icnt0[other]; k += 4;
959 	memset(&pakbuf[k],0,32);
960 	for(i=icnt0[other];i<icnt0[other]+256;i++)
961 		if (ipak[other][i&(FIFSIZ-1)])
962 			pakbuf[((i-icnt0[other])>>3)+k] |= (1<<((i-icnt0[other])&7));
963 	k += 32;
964 
965 	while ((ocnt0[other] < ocnt1[other]) && (!opak[other][ocnt0[other]&(FIFSIZ-1)])) ocnt0[other]++;
966 	for(i=ocnt0[other];i<ocnt1[other];i++)
967 	{
968 		j = *(short *)&pakmem[opak[other][i&(FIFSIZ-1)]]; if (!j) continue; //packet already acked
969 		if (k+6+j+4 > (int)sizeof(pakbuf)) break;
970 
971 		*(unsigned short *)&pakbuf[k] = (unsigned short)j; k += 2;
972 		*(int *)&pakbuf[k] = i; k += 4;
973 		memcpy(&pakbuf[k],&pakmem[opak[other][i&(FIFSIZ-1)]+2],j); k += j;
974 	}
975 	*(unsigned short *)&pakbuf[k] = 0; k += 2;
976 	*(unsigned short *)&pakbuf[0] = (unsigned short)k;
977 	*(unsigned short *)&pakbuf[k] = getcrc16(pakbuf,k); k += 2;
978 	netsend(other,pakbuf,k);
979 }
980 
sendpacket(int other,unsigned char * bufptr,int messleng)981 void sendpacket (int other, unsigned char *bufptr, int messleng)
982 {
983 	int i, j;
984 
985 	if (numplayers < 2) return;
986 
987 	if (pakmemi+messleng+2 > (int)sizeof(pakmem)) pakmemi = 1;
988 	opak[other][ocnt1[other]&(FIFSIZ-1)] = pakmemi;
989 	*(short *)&pakmem[pakmemi] = messleng;
990 	memcpy(&pakmem[pakmemi+2],bufptr,messleng); pakmemi += messleng+2;
991 	ocnt1[other]++;
992 
993 	dosendpackets(other);
994 }
995 
996 	//passing bufptr == 0 enables receive&sending raw packets but does not return any received packets
997 	//(used as hack for player collection)
getpacket(int * retother,unsigned char * bufptr)998 int getpacket (int *retother, unsigned char *bufptr)
999 {
1000 	int i, j, k, ic0, crc16ofs, messleng, other;
1001 	static int warned = 0;
1002 
1003 	if (numplayers < 2) return(0);
1004 
1005 	if (netready)
1006 	{
1007 		for(i=connecthead;i>=0;i=connectpoint2[i])
1008 		{
1009 			if (i != myconnectindex) dosendpackets(i);
1010 			if ((networkmode == MMULTI_MODE_MS) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master
1011 		}
1012 	}
1013 
1014 	tims = GetTickCount();
1015 
1016 	while (netread(&other,pakbuf,sizeof(pakbuf)))
1017 	{
1018 			//Packet format:
1019 			//   short crc16ofs;       //offset of crc16
1020 			//   int icnt0;           //earliest unacked packet
1021 			//   char ibits[32];       //ack status of packets icnt0<=i<icnt0+256
1022 			//   while (short leng)    //leng: !=0 for packet, 0 for no more packets
1023 			//   {
1024 			//      int ocnt;         //index of following packet data
1025 			//      char pak[leng];    //actual packet data :)
1026 			//   }
1027 			//   unsigned short crc16; //CRC16 of everything except crc16
1028 		k = 0;
1029 		crc16ofs = (int)(*(unsigned short *)&pakbuf[k]); k += 2;
1030 
1031 		if (crc16ofs+2 > (int)sizeof(pakbuf)) {
1032 #ifdef MMULTI_DEBUG_SENDRECV
1033 			debugprintf("mmulti debug: wrong-sized packet from %d\n", other);
1034 #endif
1035 		} else if (getcrc16(pakbuf,crc16ofs) != (*(unsigned short *)&pakbuf[crc16ofs])) {
1036 #ifdef MMULTI_DEBUG_SENDRECV
1037 			debugprintf("mmulti debug: bad crc in packet from %d\n", other);
1038 #endif
1039 		} else {
1040 			ic0 = *(int *)&pakbuf[k]; k += 4;
1041 			if (ic0 == -1)
1042 			{
1043 				// Peers send each other 0xaa and respond with 0xab containing their opinion
1044 				// of the requesting peer's placement within the order.
1045 
1046 				// Slave sends 0xaa to Master at initmultiplayerscycle() and waits for 0xab response.
1047 				// Master responds to slave with 0xab whenever it receives a 0xaa - even if during game!
1048 				if (pakbuf[k] == 0xaa)
1049 				{
1050 					int sendother = -1;
1051 #ifdef MMULTI_DEBUG_SENDRECV
1052 					const char *addr = presentaddress((struct sockaddr *)&snatchhost);
1053 #endif
1054 
1055 					if (networkmode == MMULTI_MODE_MS) {
1056 						// Master-slave.
1057 						if (other == myconnectindex && myconnectindex == connecthead) {
1058 							// This the master and someone new is calling. Find them a place.
1059 #ifdef MMULTI_DEBUG_SENDRECV
1060 							debugprintf("mmulti debug: got ping from new host %s\n", addr);
1061 #endif
1062 							for (other = 1; other < numplayers; other++) {
1063 								if (otherhost[other].ss_family == PF_UNSPEC) {
1064 									sendother = other;
1065 #ifdef MMULTI_DEBUG_SENDRECV
1066 									debugprintf("mmulti debug: giving %s player %d\n", addr, other);
1067 #endif
1068 									break;
1069 								}
1070 							}
1071 						} else {
1072 							// Repeat back to them their position.
1073 #ifdef MMULTI_DEBUG_SENDRECV
1074 							debugprintf("mmulti debug: got ping from player %d\n", other);
1075 #endif
1076 							sendother = other;
1077 						}
1078 					} else {
1079 						// Peer-to-peer mode.
1080 						if (other == myconnectindex) {
1081 #ifdef MMULTI_DEBUG_SENDRECV
1082 							debugprintf("mmulti debug: got ping from unknown host %s\n", addr);
1083 #endif
1084 						} else {
1085 #ifdef MMULTI_DEBUG_SENDRECV
1086 							debugprintf("mmulti debug: got ping from peer %d\n", other);
1087 #endif
1088 							sendother = other;
1089 						}
1090 					}
1091 
1092 					if (sendother >= 0) {
1093 						savesnatchhost(sendother);
1094 						lastrecvtims[sendother] = tims;
1095 
1096 							//   short crc16ofs;        //offset of crc16
1097 							//   int icnt0;             //-1 (special packet for MMULTI.C's player collection)
1098 							//   char type;				// 0xab
1099 							//   char connectindex;
1100 							//   char numplayers;
1101 							//   char netready;
1102 							//   unsigned short crc16;  //CRC16 of everything except crc16
1103 						k = 2;
1104 						*(int *)&pakbuf[k] = -1; k += 4;
1105 						pakbuf[k++] = 0xab;
1106 						pakbuf[k++] = (char)sendother;
1107 						pakbuf[k++] = (char)numplayers;
1108 						pakbuf[k++] = (char)netready;
1109 						*(unsigned short *)&pakbuf[0] = (unsigned short)k;
1110 						*(unsigned short *)&pakbuf[k] = getcrc16(pakbuf,k); k += 2;
1111 						netsend(sendother,pakbuf,k);
1112 					}
1113 				}
1114 				else if (pakbuf[k] == 0xab)
1115 				{
1116 					if (networkmode == MMULTI_MODE_MS) {
1117 						// Master-slave.
1118 						if (((unsigned int)pakbuf[k+1] < (unsigned int)pakbuf[k+2]) &&
1119 							 ((unsigned int)pakbuf[k+2] < (unsigned int)MAXPLAYERS) &&
1120 							 other == connecthead)
1121 						{
1122 #ifdef MMULTI_DEBUG_SENDRECV
1123 								debugprintf("mmulti debug: master gave us player %d in a %d player game\n",
1124 									(int)pakbuf[k+1], (int)pakbuf[k+2]);
1125 #endif
1126 
1127 							if ((int)pakbuf[k+1] != myconnectindex ||
1128 									(int)pakbuf[k+2] != numplayers)
1129 							{
1130 								myconnectindex = (int)pakbuf[k+1];
1131 								numplayers = (int)pakbuf[k+2];
1132 
1133 								connecthead = 0;
1134 								for(i=0;i<numplayers-1;i++) connectpoint2[i] = i+1;
1135 								connectpoint2[numplayers-1] = -1;
1136 							}
1137 
1138 							netready = netready || (int)pakbuf[k+3];
1139 
1140 							savesnatchhost(connecthead);
1141 							lastrecvtims[connecthead] = tims;
1142 						}
1143 					} else {
1144 						// Peer-to-peer. Verify that our peer's understanding of the
1145 						// order and player count matches with ours.
1146 						if (myconnectindex != (int)pakbuf[k+1] ||
1147 								numplayers != (int)pakbuf[k+2]) {
1148 							if (!warned) {
1149 								const char *addr = presentaddress((struct sockaddr *)&snatchhost);
1150 								printf("mmulti error: host %s (peer %d) believes this machine is "
1151 									"player %d in a %d-player game! The game will not start until "
1152 									"every machine is in agreement.\n",
1153 									addr, other, (int)pakbuf[k+1], (int)pakbuf[k+2]);
1154 							}
1155 							warned = 1;
1156 						} else {
1157 							savesnatchhost(other);
1158 							lastrecvtims[other] = tims;
1159 						}
1160 					}
1161 				}
1162 			}
1163 			else
1164 			{
1165 				if (other == myconnectindex) {
1166 #ifdef MMULTI_DEBUG_SENDRECV
1167 					debugprintf("mmulti debug: got a packet from unknown host %s\n",
1168 								presentaddress((struct sockaddr *)&snatchhost));
1169 					return 0;
1170 #endif
1171 				}
1172 				if (ocnt0[other] < ic0) ocnt0[other] = ic0;
1173 				for(i=ic0;i<min(ic0+256,ocnt1[other]);i++)
1174 					if (pakbuf[((i-ic0)>>3)+k]&(1<<((i-ic0)&7)))
1175 						opak[other][i&(FIFSIZ-1)] = 0;
1176 				k += 32;
1177 
1178 				messleng = (int)(*(unsigned short *)&pakbuf[k]); k += 2;
1179 				while (messleng)
1180 				{
1181 					j = *(int *)&pakbuf[k]; k += 4;
1182 					if ((j >= icnt0[other]) && (!ipak[other][j&(FIFSIZ-1)]))
1183 					{
1184 						if (pakmemi+messleng+2 > (int)sizeof(pakmem)) pakmemi = 1;
1185 						ipak[other][j&(FIFSIZ-1)] = pakmemi;
1186 						*(short *)&pakmem[pakmemi] = messleng;
1187 						memcpy(&pakmem[pakmemi+2],&pakbuf[k],messleng); pakmemi += messleng+2;
1188 					}
1189 					k += messleng;
1190 					messleng = (int)(*(unsigned short *)&pakbuf[k]); k += 2;
1191 				}
1192 
1193 				lastrecvtims[other] = tims;
1194 			}
1195 		}
1196 	}
1197 
1198 		//Return next valid packet from any player
1199 	if (!bufptr) return(0);
1200 	for(i=connecthead;i>=0;i=connectpoint2[i])
1201 	{
1202 		if (i != myconnectindex)
1203 		{
1204 			j = ipak[i][icnt0[i]&(FIFSIZ-1)];
1205 			if (j)
1206 			{
1207 				messleng = *(short *)&pakmem[j]; memcpy(bufptr,&pakmem[j+2],messleng);
1208 				*retother = i; ipak[i][icnt0[i]&(FIFSIZ-1)] = 0; icnt0[i]++;
1209 				return(messleng);
1210 			}
1211 		}
1212 		if ((networkmode == MMULTI_MODE_MS) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master
1213 	}
1214 
1215 	return(0);
1216 }
1217 
flushpackets(void)1218 void flushpackets(void)
1219 {
1220 	int i;
1221 	getpacket(&i,0);	// Process acks but no messages, do retransmission.
1222 }
1223 
1224 // Records the IP address of a peer, along with our IPV4 and/or IPV6 addresses
1225 // their packet came in on. We send our reply from the same address.
savesnatchhost(int other)1226 void savesnatchhost(int other)
1227 {
1228 	if (other == myconnectindex) return;
1229 
1230 	memcpy(&otherhost[other], &snatchhost, sizeof(snatchhost));
1231 	replyfrom4[other] = snatchreplyfrom4;
1232 	replyfrom6[other] = snatchreplyfrom6;
1233 }
1234