|
|
1.1 root 1: // net_main.c
2:
3: #include "quakedef.h"
4: #include "net_vcr.h"
5:
6: qsocket_t *net_activeSockets = NULL;
7: qsocket_t *net_freeSockets = NULL;
8: int net_numsockets = 0;
9:
10: qboolean serialAvailable = false;
11: qboolean ipxAvailable = false;
12: qboolean tcpipAvailable = false;
13:
14: char my_ipx_address[NET_NAMELEN];
15: char my_tcpip_address[NET_NAMELEN];
16:
17: void (*GetComPortConfig) (int portNumber, int *port, int *irq, int *baud, qboolean *useModem);
18: void (*SetComPortConfig) (int portNumber, int port, int irq, int baud, qboolean useModem);
19: void (*GetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
20: void (*SetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
21:
22: static qboolean listening = false;
23:
24: qboolean slistInProgress = false;
25: qboolean slistSilent = false;
26: qboolean slistLocal = true;
27: static double slistStartTime;
28: static int slistLastShown;
29:
30: static void Slist_Send(void);
31: static void Slist_Poll(void);
32: PollProcedure slistSendProcedure = {NULL, 0.0, Slist_Send};
33: PollProcedure slistPollProcedure = {NULL, 0.0, Slist_Poll};
34:
35:
36: sizebuf_t net_message;
37: int net_activeconnections = 0;
38:
39: int messagesSent = 0;
40: int messagesReceived = 0;
41: int unreliableMessagesSent = 0;
42: int unreliableMessagesReceived = 0;
43:
44: cvar_t net_messagetimeout = {"net_messagetimeout","300"};
45: cvar_t hostname = {"hostname", "UNNAMED"};
46:
47: qboolean configRestored = false;
48: cvar_t config_com_port = {"_config_com_port", "0x3f8", true};
49: cvar_t config_com_irq = {"_config_com_irq", "4", true};
50: cvar_t config_com_baud = {"_config_com_baud", "57600", true};
51: cvar_t config_com_modem = {"_config_com_modem", "1", true};
52: cvar_t config_modem_dialtype = {"_config_modem_dialtype", "T", true};
53: cvar_t config_modem_clear = {"_config_modem_clear", "ATZ", true};
54: cvar_t config_modem_init = {"_config_modem_init", "", true};
55: cvar_t config_modem_hangup = {"_config_modem_hangup", "AT H", true};
56:
57:
58: int vcrFile = -1;
59: qboolean recording = false;
60:
61: // these two macros are to make the code more readable
62: #define sfunc net_drivers[sock->driver]
63: #define dfunc net_drivers[net_driverlevel]
64:
65: int net_driverlevel;
66:
67:
68: double net_time;
69:
70: double SetNetTime(void)
71: {
72: net_time = Sys_FloatTime();
73: return net_time;
74: }
75:
76:
77: /*
78: ===================
79: NET_NewQSocket
80:
81: Called by drivers when a new communications endpoint is required
82: The sequence and buffer fields will be filled in properly
83: ===================
84: */
85: qsocket_t *NET_NewQSocket (void)
86: {
87: qsocket_t *sock;
88:
89: if (net_freeSockets == NULL)
90: return NULL;
91:
92: if (net_activeconnections >= svs.maxclients)
93: return NULL;
94:
95: // get one from free list
96: sock = net_freeSockets;
97: net_freeSockets = sock->next;
98:
99: // add it to active list
100: sock->next = net_activeSockets;
101: net_activeSockets = sock;
102:
103: sock->disconnected = false;
104: sock->connecttime = net_time;
105: Q_strcpy (sock->address,"UNSET ADDRESS");
106: sock->driver = net_driverlevel;
107: sock->socket = 0;
108: sock->driverdata = NULL;
109: sock->canSend = true;
110: sock->sendNext = false;
111: sock->lastMessageTime = net_time;
112: sock->sendSequence = 0;
113: sock->unreliableSendSequence = 0;
114: sock->sendMessageLength = 0;
115: sock->receiveSequence = 0;
116: sock->unreliableReceiveSequence = 0;
117: sock->receiveMessageLength = 0;
118:
119: return sock;
120: }
121:
122:
123: void NET_FreeQSocket(qsocket_t *sock)
124: {
125: qsocket_t *s;
126:
127: // remove it from active list
128: if (sock == net_activeSockets)
129: net_activeSockets = net_activeSockets->next;
130: else
131: {
132: for (s = net_activeSockets; s; s = s->next)
133: if (s->next == sock)
134: {
135: s->next = sock->next;
136: break;
137: }
138: if (!s)
139: Sys_Error ("NET_FreeQSocket: not active\n");
140: }
141:
142: // add it to free list
143: sock->next = net_freeSockets;
144: net_freeSockets = sock;
145: sock->disconnected = true;
146: }
147:
148:
149: static void NET_Listen_f (void)
150: {
151: if (Cmd_Argc () != 2)
152: {
153: Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);
154: return;
155: }
156:
157: listening = Q_atoi(Cmd_Argv(1)) ? true : false;
158:
159: for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
160: {
161: if (net_drivers[net_driverlevel].initialized == false)
162: continue;
163: dfunc.Listen (listening);
164: }
165: }
166:
167:
168: static void MaxPlayers_f (void)
169: {
170: int n;
171:
172: if (Cmd_Argc () != 2)
173: {
174: Con_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients);
175: return;
176: }
177:
178: if (sv.active)
179: {
180: Con_Printf ("maxplayers can not be changed while a server is running.\n");
181: return;
182: }
183:
184: n = Q_atoi(Cmd_Argv(1));
185: if (n < 1)
186: n = 1;
187: if (n > svs.maxclientslimit)
188: {
189: n = svs.maxclientslimit;
190: Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);
191: }
192:
193: if (n == 1 && svs.maxclients > 1)
1.1.1.2 ! root 194: Cbuf_AddText ("listen 0");
1.1 root 195:
196: if (n > 1 && svs.maxclients == 1)
1.1.1.2 ! root 197: Cbuf_AddText ("listen 1");
1.1 root 198:
199: svs.maxclients = n;
200: if (n == 1)
201: Cvar_Set ("deathmatch", "0");
202: else
203: Cvar_Set ("deathmatch", "1");
204: }
205:
206:
207: static void PrintSlistHeader(void)
208: {
209: Con_Printf("Server Map Users\n");
210: Con_Printf("--------------- --------------- -----\n");
211: slistLastShown = 0;
212: }
213:
214:
215: static void PrintSlist(void)
216: {
217: int n;
218:
219: for (n = slistLastShown; n < hostCacheCount; n++)
220: {
221: if (hostcache[n].maxusers)
222: Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
223: else
224: Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
225: }
226: slistLastShown = n;
227: }
228:
229:
230: static void PrintSlistTrailer(void)
231: {
232: if (hostCacheCount)
233: Con_Printf("== end list ==\n\n");
234: else
235: Con_Printf("No Quake servers found.\n\n");
236: }
237:
238:
239: void NET_Slist_f (void)
240: {
241: if (slistInProgress)
242: return;
243:
244: if (! slistSilent)
245: {
246: Con_Printf("Looking for Quake servers...\n");
247: PrintSlistHeader();
248: }
249:
250: slistInProgress = true;
251: slistStartTime = Sys_FloatTime();
252:
253: SchedulePollProcedure(&slistSendProcedure, 0.0);
254: SchedulePollProcedure(&slistPollProcedure, 0.1);
255:
256: hostCacheCount = 0;
257: }
258:
259:
260: static void Slist_Send(void)
261: {
262: for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
263: {
264: if (!slistLocal && net_driverlevel == 0)
265: continue;
266: if (net_drivers[net_driverlevel].initialized == false)
267: continue;
268: dfunc.SearchForHosts (true);
269: }
270:
271: if ((Sys_FloatTime() - slistStartTime) < 0.5)
272: SchedulePollProcedure(&slistSendProcedure, 0.75);
273: }
274:
275:
276: static void Slist_Poll(void)
277: {
278: for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
279: {
280: if (!slistLocal && net_driverlevel == 0)
281: continue;
282: if (net_drivers[net_driverlevel].initialized == false)
283: continue;
284: dfunc.SearchForHosts (false);
285: }
286:
287: if (! slistSilent)
288: PrintSlist();
289:
290: if ((Sys_FloatTime() - slistStartTime) < 1.5)
291: {
292: SchedulePollProcedure(&slistPollProcedure, 0.1);
293: return;
294: }
295:
296: if (! slistSilent)
297: PrintSlistTrailer();
298: slistInProgress = false;
299: slistSilent = false;
300: slistLocal = true;
301: }
302:
303:
304: /*
305: ===================
306: NET_Connect
307: ===================
308: */
309:
310: int hostCacheCount = 0;
311: hostcache_t hostcache[HOSTCACHESIZE];
312:
313: qsocket_t *NET_Connect (char *host)
314: {
315: qsocket_t *ret;
316: int n;
317:
318: SetNetTime();
319:
320: if (host && *host == 0)
321: host = NULL;
322:
323: if (host && hostCacheCount)
324: {
325: for (n = 0; n < hostCacheCount; n++)
326: if (Q_strcasecmp (host, hostcache[n].name) == 0)
327: {
328: host = hostcache[n].cname;
329: break;
330: }
331: if (n < hostCacheCount)
332: goto JustDoIt;
333: }
334:
335: slistSilent = host ? true : false;
336: NET_Slist_f ();
337:
338: while(slistInProgress)
339: NET_Poll();
340:
341: if (host == NULL)
342: {
343: if (hostCacheCount != 1)
344: return NULL;
345: host = hostcache[0].cname;
346: Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
347: }
348:
349: if (hostCacheCount)
350: for (n = 0; n < hostCacheCount; n++)
351: if (Q_strcasecmp (host, hostcache[n].name) == 0)
352: {
353: host = hostcache[n].cname;
354: break;
355: }
356:
357: JustDoIt:
358: for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
359: {
360: if (net_drivers[net_driverlevel].initialized == false)
361: continue;
362: ret = dfunc.Connect (host);
363: if (ret)
364: return ret;
365: }
366:
367: if (host)
368: {
369: Con_Printf("\n");
370: PrintSlistHeader();
371: PrintSlist();
372: PrintSlistTrailer();
373: }
374:
375: return NULL;
376: }
377:
378:
379: /*
380: ===================
381: NET_CheckNewConnections
382: ===================
383: */
384:
385: struct
386: {
387: double time;
388: int op;
389: long session;
390: } vcrConnect;
391:
392: qsocket_t *NET_CheckNewConnections (void)
393: {
394: qsocket_t *ret;
395:
396: SetNetTime();
397:
398: for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
399: {
400: if (net_drivers[net_driverlevel].initialized == false)
401: continue;
402: if (net_driverlevel && listening == false)
403: continue;
404: ret = dfunc.CheckNewConnections ();
405: if (ret)
406: {
407: if (recording)
408: {
409: vcrConnect.time = host_time;
410: vcrConnect.op = VCR_OP_CONNECT;
411: vcrConnect.session = (long)ret;
412: Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect));
413: Sys_FileWrite (vcrFile, ret->address, NET_NAMELEN);
414: }
415: return ret;
416: }
417: }
418:
419: if (recording)
420: {
421: vcrConnect.time = host_time;
422: vcrConnect.op = VCR_OP_CONNECT;
423: vcrConnect.session = 0;
424: Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect));
425: }
426:
427: return NULL;
428: }
429:
430: /*
431: ===================
432: NET_Close
433: ===================
434: */
435: void NET_Close (qsocket_t *sock)
436: {
437: if (!sock)
438: return;
439:
440: if (sock->disconnected)
441: return;
442:
443: SetNetTime();
444:
445: // call the driver_Close function
446: sfunc.Close (sock);
447:
448: NET_FreeQSocket(sock);
449: }
450:
451:
452: /*
453: =================
454: NET_GetMessage
455:
456: If there is a complete message, return it in net_message
457:
458: returns 0 if no data is waiting
459: returns 1 if a message was received
460: returns -1 if connection is invalid
461: =================
462: */
463:
464: struct
465: {
466: double time;
467: int op;
468: long session;
469: int ret;
470: int len;
471: } vcrGetMessage;
472:
473: extern void PrintStats(qsocket_t *s);
474:
475: int NET_GetMessage (qsocket_t *sock)
476: {
477: int ret;
478:
479: if (!sock)
480: return -1;
481:
482: if (sock->disconnected)
483: {
484: Con_Printf("NET_GetMessage: disconnected socket\n");
485: return -1;
486: }
487:
488: SetNetTime();
489:
490: ret = sfunc.GetMessage(sock);
491:
492: // see if this connection has timed out
493: if (ret == 0 && sock->driver)
494: {
495: if (net_time - sock->lastMessageTime > net_messagetimeout.value)
496: {
497: NET_Close(sock);
498: return -1;
499: }
500: }
501:
502:
503: if (ret > 0)
504: {
505: if (sock->driver)
506: {
507: sock->lastMessageTime = net_time;
508: if (ret == 1)
509: messagesReceived++;
510: else if (ret == 2)
511: unreliableMessagesReceived++;
512: }
513:
514: if (recording)
515: {
516: vcrGetMessage.time = host_time;
517: vcrGetMessage.op = VCR_OP_GETMESSAGE;
518: vcrGetMessage.session = (long)sock;
519: vcrGetMessage.ret = ret;
520: vcrGetMessage.len = net_message.cursize;
521: Sys_FileWrite (vcrFile, &vcrGetMessage, 24);
522: Sys_FileWrite (vcrFile, net_message.data, net_message.cursize);
523: }
524: }
525: else
526: {
527: if (recording)
528: {
529: vcrGetMessage.time = host_time;
530: vcrGetMessage.op = VCR_OP_GETMESSAGE;
531: vcrGetMessage.session = (long)sock;
532: vcrGetMessage.ret = ret;
533: Sys_FileWrite (vcrFile, &vcrGetMessage, 20);
534: }
535: }
536:
537: return ret;
538: }
539:
540:
541: /*
542: ==================
543: NET_SendMessage
544:
545: Try to send a complete length+message unit over the reliable stream.
546: returns 0 if the message cannot be delivered reliably, but the connection
547: is still considered valid
548: returns 1 if the message was sent properly
549: returns -1 if the connection died
550: ==================
551: */
552: struct
553: {
554: double time;
555: int op;
556: long session;
557: int r;
558: } vcrSendMessage;
559:
560: int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
561: {
562: int r;
563:
564: if (!sock)
565: return -1;
566:
567: if (sock->disconnected)
568: {
569: Con_Printf("NET_SendMessage: disconnected socket\n");
570: return -1;
571: }
572:
573: SetNetTime();
574: r = sfunc.SendMessage(sock, data);
575: if (r == 1 && sock->driver)
576: messagesSent++;
577:
578: if (recording)
579: {
580: vcrSendMessage.time = host_time;
581: vcrSendMessage.op = VCR_OP_SENDMESSAGE;
582: vcrSendMessage.session = (long)sock;
583: vcrSendMessage.r = r;
584: Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
585: }
586:
587: return r;
588: }
589:
590:
591: int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
592: {
593: int r;
594:
595: if (!sock)
596: return -1;
597:
598: if (sock->disconnected)
599: {
600: Con_Printf("NET_SendMessage: disconnected socket\n");
601: return -1;
602: }
603:
604: SetNetTime();
605: r = sfunc.SendUnreliableMessage(sock, data);
606: if (r == 1 && sock->driver)
607: unreliableMessagesSent++;
608:
609: if (recording)
610: {
611: vcrSendMessage.time = host_time;
612: vcrSendMessage.op = VCR_OP_SENDMESSAGE;
613: vcrSendMessage.session = (long)sock;
614: vcrSendMessage.r = r;
615: Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
616: }
617:
618: return r;
619: }
620:
621:
622: /*
623: ==================
624: NET_CanSendMessage
625:
626: Returns true or false if the given qsocket can currently accept a
627: message to be transmitted.
628: ==================
629: */
630: qboolean NET_CanSendMessage (qsocket_t *sock)
631: {
632: int r;
633:
634: if (!sock)
635: return false;
636:
637: if (sock->disconnected)
638: return false;
639:
640: SetNetTime();
641:
642: r = sfunc.CanSendMessage(sock);
643:
644: if (recording)
645: {
646: vcrSendMessage.time = host_time;
647: vcrSendMessage.op = VCR_OP_CANSENDMESSAGE;
648: vcrSendMessage.session = (long)sock;
649: vcrSendMessage.r = r;
650: Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
651: }
652:
653: return r;
654: }
655:
656:
657: int NET_SendToAll(sizebuf_t *data, int blocktime)
658: {
659: double start;
660: int i;
661: int count = 0;
662: qboolean state1 [MAX_SCOREBOARD];
663: qboolean state2 [MAX_SCOREBOARD];
664:
665: for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
666: {
667: if (!host_client->netconnection)
668: continue;
669: if (host_client->active)
670: {
671: if (host_client->netconnection->driver == 0)
672: {
673: NET_SendMessage(host_client->netconnection, data);
674: state1[i] = true;
675: state2[i] = true;
676: continue;
677: }
678: count++;
679: state1[i] = false;
680: state2[i] = false;
681: }
682: else
683: {
684: state1[i] = true;
685: state2[i] = true;
686: }
687: }
688:
689: start = Sys_FloatTime();
690: while (count)
691: {
692: count = 0;
693: for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
694: {
695: if (! state1[i])
696: {
697: if (NET_CanSendMessage (host_client->netconnection))
698: {
699: state1[i] = true;
700: NET_SendMessage(host_client->netconnection, data);
701: }
702: else
703: {
704: NET_GetMessage (host_client->netconnection);
705: }
706: count++;
707: continue;
708: }
709:
710: if (! state2[i])
711: {
712: if (NET_CanSendMessage (host_client->netconnection))
713: {
714: state2[i] = true;
715: }
716: else
717: {
718: NET_GetMessage (host_client->netconnection);
719: }
720: count++;
721: continue;
722: }
723: }
724: if ((Sys_FloatTime() - start) > blocktime)
725: break;
726: }
727: return count;
728: }
729:
730:
731: //=============================================================================
732:
733: /*
734: ====================
735: NET_Init
736: ====================
737: */
738:
739: void NET_Init (void)
740: {
741: int i;
742: int controlSocket;
743: qsocket_t *s;
744:
745: if (COM_CheckParm("-playback"))
746: {
747: net_numdrivers = 1;
748: net_drivers[0].Init = VCR_Init;
749: }
750:
751: if (COM_CheckParm("-record"))
752: recording = true;
753:
754: if (COM_CheckParm("-listen") || cls.state == ca_dedicated)
755: listening = true;
756: net_numsockets = svs.maxclientslimit;
757: if (cls.state != ca_dedicated)
758: net_numsockets++;
759:
760: SetNetTime();
761:
762: for (i = 0; i < net_numsockets; i++)
763: {
764: s = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), "qsocket");
765: s->next = net_freeSockets;
766: net_freeSockets = s;
767: s->disconnected = true;
768: }
769:
770: // allocate space for network message buffer
771: SZ_Alloc (&net_message, NET_MAXMESSAGE);
772:
773: Cvar_RegisterVariable (&net_messagetimeout);
774: Cvar_RegisterVariable (&hostname);
775: Cvar_RegisterVariable (&config_com_port);
776: Cvar_RegisterVariable (&config_com_irq);
777: Cvar_RegisterVariable (&config_com_baud);
778: Cvar_RegisterVariable (&config_com_modem);
779: Cvar_RegisterVariable (&config_modem_dialtype);
780: Cvar_RegisterVariable (&config_modem_clear);
781: Cvar_RegisterVariable (&config_modem_init);
782: Cvar_RegisterVariable (&config_modem_hangup);
783:
784: Cmd_AddCommand ("slist", NET_Slist_f);
785: Cmd_AddCommand ("listen", NET_Listen_f);
786: Cmd_AddCommand ("maxplayers", MaxPlayers_f);
787:
788: // initialize all the drivers
789: for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
790: {
791: controlSocket = net_drivers[net_driverlevel].Init();
792: if (controlSocket == -1)
793: continue;
794: net_drivers[net_driverlevel].initialized = true;
795: net_drivers[net_driverlevel].controlSock = controlSocket;
796: if (listening)
797: net_drivers[net_driverlevel].Listen (true);
798: }
799:
800: if (*my_ipx_address)
801: Con_DPrintf("IPX address %s\n", my_ipx_address);
802: if (*my_tcpip_address)
803: Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
804: }
805:
806: /*
807: ====================
808: NET_Shutdown
809: ====================
810: */
811:
812: void NET_Shutdown (void)
813: {
814: qsocket_t *sock;
815:
816: SetNetTime();
817:
818: for (sock = net_activeSockets; sock; sock = sock->next)
819: NET_Close(sock);
820:
821: //
822: // shutdown the drivers
823: //
824: for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
825: {
826: if (net_drivers[net_driverlevel].initialized == true)
827: {
828: net_drivers[net_driverlevel].Shutdown ();
829: net_drivers[net_driverlevel].initialized = false;
830: }
831: }
832:
833: if (vcrFile != -1)
834: {
835: Con_Printf ("Closing vcrfile.\n");
836: Sys_FileClose(vcrFile);
837: }
838: }
839:
840:
841: static PollProcedure *pollProcedureList = NULL;
842:
843: void NET_Poll(void)
844: {
845: PollProcedure *pp;
846: qboolean useModem;
847:
848: if (!configRestored)
849: {
850: if (serialAvailable)
851: {
852: if (config_com_modem.value == 1.0)
853: useModem = true;
854: else
855: useModem = false;
856: SetComPortConfig (0, (int)config_com_port.value, (int)config_com_irq.value, (int)config_com_baud.value, useModem);
857: SetModemConfig (0, config_modem_dialtype.string, config_modem_clear.string, config_modem_init.string, config_modem_hangup.string);
858: }
859: configRestored = true;
860: }
861:
862: SetNetTime();
863:
864: for (pp = pollProcedureList; pp; pp = pp->next)
865: {
866: if (pp->nextTime > net_time)
867: break;
868: pollProcedureList = pp->next;
869: pp->procedure(pp->arg);
870: }
871: }
872:
873:
874: void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
875: {
876: PollProcedure *pp, *prev;
877:
878: proc->nextTime = Sys_FloatTime() + timeOffset;
879: for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
880: {
881: if (pp->nextTime >= proc->nextTime)
882: break;
883: prev = pp;
884: }
885:
886: if (prev == NULL)
887: {
888: proc->next = pollProcedureList;
889: pollProcedureList = proc;
890: return;
891: }
892:
893: proc->next = pp;
894: prev->next = proc;
895: }
896:
897:
898: #ifdef IDGODS
899: #define IDNET 0xc0f62800
900:
901: qboolean IsID(struct qsockaddr *addr)
902: {
903: if (addr->sa_family != 2)
904: return false;
905:
1.1.1.2 ! root 906: if ((ntohl(*(int *)&addr->sa_data[2]) & 0xffffff00) == IDNET)
1.1 root 907: return true;
908: return false;
909: }
910: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.