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