]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - net_dgrm.c
fixed all the signed/unsigned mismatch warnings
[xonotic/darkplaces.git] / net_dgrm.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // net_dgrm.c
21
22 // This is enables a simple IP banning mechanism
23 #define BAN_TEST
24
25 #ifdef BAN_TEST
26 #if defined(_WIN32)
27 #include <windows.h>
28 #elif defined (NeXT)
29 #include <sys/socket.h>
30 #include <arpa/inet.h>
31 #else
32 #define AF_INET                 2       /* internet */
33 struct in_addr
34 {
35         union
36         {
37                 struct { unsigned char s_b1,s_b2,s_b3,s_b4; } S_un_b;
38                 struct { unsigned short s_w1,s_w2; } S_un_w;
39                 unsigned long S_addr;
40         } S_un;
41 };
42 #define s_addr  S_un.S_addr     /* can be used for most tcp & ip code */
43 struct sockaddr_in
44 {
45     short                       sin_family;
46     unsigned short      sin_port;
47         struct in_addr  sin_addr;
48     char                        sin_zero[8];
49 };
50 char *inet_ntoa(struct in_addr in);
51 unsigned long inet_addr(const char *cp);
52 #endif
53 #endif  // BAN_TEST
54
55 #include "quakedef.h"
56 #include "net_dgrm.h"
57 #include "net_master.h"
58
59 cvar_t cl_port = {CVAR_SAVE, "cl_port", "0"};
60
61 // these two macros are to make the code more readable
62 #define sfunc   net_landrivers[sock->landriver]
63 #define dfunc   net_landrivers[net_landriverlevel]
64
65 static int net_landriverlevel;
66
67 /* statistic counters */
68 int     packetsSent = 0;
69 int     packetsReSent = 0;
70 int packetsReceived = 0;
71 int receivedDuplicateCount = 0;
72 int shortPacketCount = 0;
73 int droppedDatagrams;
74
75 static int myDriverLevel;
76
77 struct
78 {
79         unsigned int    length;
80         unsigned int    sequence;
81         qbyte                   data[MAX_DATAGRAM];
82 } packetBuffer;
83
84
85 //#ifdef DEBUG
86 char *StrAddr (struct qsockaddr *addr)
87 {
88         static char buf[34];
89         qbyte *p = (qbyte *)addr;
90         int n;
91
92         for (n = 0; n < 16; n++)
93                 sprintf (buf + n * 2, "%02x", *p++);
94         return buf;
95 }
96 //#endif
97
98
99 #ifdef BAN_TEST
100 unsigned long banAddr = 0x00000000;
101 unsigned long banMask = 0xffffffff;
102
103 void NET_Ban_f (void)
104 {
105         char    addrStr [32];
106         char    maskStr [32];
107         void    (*print) (const char *fmt, ...);
108
109         if (cmd_source == src_command)
110         {
111                 if (!sv.active)
112                 {
113                         Cmd_ForwardToServer ();
114                         return;
115                 }
116                 print = Con_Printf;
117         }
118         else
119         {
120                 if (pr_global_struct->deathmatch)
121                         return;
122                 print = SV_ClientPrintf;
123         }
124
125         switch (Cmd_Argc ())
126         {
127                 case 1:
128                         if (((struct in_addr *)&banAddr)->s_addr)
129                         {
130                                 strcpy(addrStr, inet_ntoa(*(struct in_addr *)&banAddr));
131                                 strcpy(maskStr, inet_ntoa(*(struct in_addr *)&banMask));
132                                 print("Banning %s [%s]\n", addrStr, maskStr);
133                         }
134                         else
135                                 print("Banning not active\n");
136                         break;
137
138                 case 2:
139                         if (Q_strcasecmp(Cmd_Argv(1), "off") == 0)
140                                 banAddr = 0x00000000;
141                         else
142                                 banAddr = inet_addr(Cmd_Argv(1));
143                         banMask = 0xffffffff;
144                         break;
145
146                 case 3:
147                         banAddr = inet_addr(Cmd_Argv(1));
148                         banMask = inet_addr(Cmd_Argv(2));
149                         break;
150
151                 default:
152                         print("BAN ip_address [mask]\n");
153                         break;
154         }
155 }
156 #endif
157
158
159 int Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data)
160 {
161         unsigned int    packetLen;
162         unsigned int    dataLen;
163         unsigned int    eom;
164
165 #ifdef DEBUG
166         if (data->cursize == 0)
167                 Sys_Error("Datagram_SendMessage: zero length message\n");
168
169         if (data->cursize > NET_MAXMESSAGE)
170                 Sys_Error("Datagram_SendMessage: message too big %u\n", data->cursize);
171
172         if (sock->canSend == false)
173                 Sys_Error("SendMessage: called with canSend == false\n");
174 #endif
175
176         memcpy(sock->sendMessage, data->data, data->cursize);
177         sock->sendMessageLength = data->cursize;
178
179         if (data->cursize <= MAX_DATAGRAM)
180         {
181                 dataLen = data->cursize;
182                 eom = NETFLAG_EOM;
183         }
184         else
185         {
186                 dataLen = MAX_DATAGRAM;
187                 eom = 0;
188         }
189         packetLen = NET_HEADERSIZE + dataLen;
190
191         packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
192         packetBuffer.sequence = BigLong(sock->sendSequence++);
193         memcpy (packetBuffer.data, sock->sendMessage, dataLen);
194
195         sock->canSend = false;
196
197         if (sfunc.Write (sock->socket, (qbyte *)&packetBuffer, packetLen, &sock->addr) == -1)
198                 return -1;
199
200         sock->lastSendTime = net_time;
201         packetsSent++;
202         return 1;
203 }
204
205
206 int SendMessageNext (qsocket_t *sock)
207 {
208         unsigned int    packetLen;
209         unsigned int    dataLen;
210         unsigned int    eom;
211
212         if (sock->sendMessageLength <= MAX_DATAGRAM)
213         {
214                 dataLen = sock->sendMessageLength;
215                 eom = NETFLAG_EOM;
216         }
217         else
218         {
219                 dataLen = MAX_DATAGRAM;
220                 eom = 0;
221         }
222         packetLen = NET_HEADERSIZE + dataLen;
223
224         packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
225         packetBuffer.sequence = BigLong(sock->sendSequence++);
226         memcpy (packetBuffer.data, sock->sendMessage, dataLen);
227
228         sock->sendNext = false;
229
230         if (sfunc.Write (sock->socket, (qbyte *)&packetBuffer, packetLen, &sock->addr) == -1)
231                 return -1;
232
233         sock->lastSendTime = net_time;
234         packetsSent++;
235         return 1;
236 }
237
238
239 int ReSendMessage (qsocket_t *sock)
240 {
241         unsigned int    packetLen;
242         unsigned int    dataLen;
243         unsigned int    eom;
244
245         if (sock->sendMessageLength <= MAX_DATAGRAM)
246         {
247                 dataLen = sock->sendMessageLength;
248                 eom = NETFLAG_EOM;
249         }
250         else
251         {
252                 dataLen = MAX_DATAGRAM;
253                 eom = 0;
254         }
255         packetLen = NET_HEADERSIZE + dataLen;
256
257         packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
258         packetBuffer.sequence = BigLong(sock->sendSequence - 1);
259         memcpy (packetBuffer.data, sock->sendMessage, dataLen);
260
261         sock->sendNext = false;
262
263         if (sfunc.Write (sock->socket, (qbyte *)&packetBuffer, packetLen, &sock->addr) == -1)
264                 return -1;
265
266         sock->lastSendTime = net_time;
267         packetsReSent++;
268         return 1;
269 }
270
271
272 qboolean Datagram_CanSendMessage (qsocket_t *sock)
273 {
274         if (sock->sendNext)
275                 SendMessageNext (sock);
276
277         return sock->canSend;
278 }
279
280
281 qboolean Datagram_CanSendUnreliableMessage (qsocket_t *sock)
282 {
283         return true;
284 }
285
286
287 int Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
288 {
289         int     packetLen;
290
291 #ifdef DEBUG
292         if (data->cursize == 0)
293                 Sys_Error("Datagram_SendUnreliableMessage: zero length message\n");
294
295         if (data->cursize > MAX_DATAGRAM)
296                 Sys_Error("Datagram_SendUnreliableMessage: message too big %u\n", data->cursize);
297 #endif
298
299         packetLen = NET_HEADERSIZE + data->cursize;
300
301         packetBuffer.length = BigLong(packetLen | NETFLAG_UNRELIABLE);
302         packetBuffer.sequence = BigLong(sock->unreliableSendSequence++);
303         memcpy (packetBuffer.data, data->data, data->cursize);
304
305         if (sfunc.Write (sock->socket, (qbyte *)&packetBuffer, packetLen, &sock->addr) == -1)
306                 return -1;
307
308         packetsSent++;
309         return 1;
310 }
311
312
313 int     Datagram_GetMessage (qsocket_t *sock)
314 {
315         unsigned int    length;
316         unsigned int    flags;
317         int                             ret = 0;
318         struct qsockaddr readaddr;
319         unsigned int    sequence;
320         unsigned int    count;
321
322         if (!sock->canSend)
323                 if ((net_time - sock->lastSendTime) > 1.0)
324                         ReSendMessage (sock);
325
326         while(1)
327         {
328                 length = sfunc.Read (sock->socket, (qbyte *)&packetBuffer, NET_DATAGRAMSIZE, &readaddr);
329
330                 if (length == 0)
331                         break;
332
333                 if ((int)length == -1)
334                 {
335                         Con_Printf("Read error\n");
336                         return -1;
337                 }
338
339                 if (sfunc.AddrCompare(&readaddr, &sock->addr) != 0)
340                 {
341 #ifdef DEBUG
342                         Con_DPrintf("Forged packet received\n");
343                         Con_DPrintf("Expected: %s\n", StrAddr (&sock->addr));
344                         Con_DPrintf("Received: %s\n", StrAddr (&readaddr));
345 #endif
346                         continue;
347                 }
348
349                 if (length < NET_HEADERSIZE)
350                 {
351                         shortPacketCount++;
352                         continue;
353                 }
354
355                 length = BigLong(packetBuffer.length);
356                 flags = length & (~NETFLAG_LENGTH_MASK);
357                 length &= NETFLAG_LENGTH_MASK;
358
359                 if (flags & NETFLAG_CTL)
360                         continue;
361
362                 sequence = BigLong(packetBuffer.sequence);
363                 packetsReceived++;
364
365                 if (flags & NETFLAG_UNRELIABLE)
366                 {
367                         if (sequence < sock->unreliableReceiveSequence)
368                         {
369                                 Con_DPrintf("Got a stale datagram\n");
370                                 ret = 0;
371                                 break;
372                         }
373                         if (sequence != sock->unreliableReceiveSequence)
374                         {
375                                 count = sequence - sock->unreliableReceiveSequence;
376                                 droppedDatagrams += count;
377                                 Con_DPrintf("Dropped %u datagram(s)\n", count);
378                         }
379                         sock->unreliableReceiveSequence = sequence + 1;
380
381                         length -= NET_HEADERSIZE;
382
383                         SZ_Clear (&net_message);
384                         SZ_Write (&net_message, packetBuffer.data, length);
385
386                         ret = 2;
387                         break;
388                 }
389
390                 if (flags & NETFLAG_ACK)
391                 {
392                         if (sequence != (sock->sendSequence - 1))
393                         {
394                                 Con_DPrintf("Stale ACK received\n");
395                                 continue;
396                         }
397                         if (sequence == sock->ackSequence)
398                         {
399                                 sock->ackSequence++;
400                                 if (sock->ackSequence != sock->sendSequence)
401                                         Con_DPrintf("ack sequencing error\n");
402                         }
403                         else
404                         {
405                                 Con_DPrintf("Duplicate ACK received\n");
406                                 continue;
407                         }
408                         sock->sendMessageLength -= MAX_DATAGRAM;
409                         if (sock->sendMessageLength > 0)
410                         {
411                                 memcpy(sock->sendMessage, sock->sendMessage+MAX_DATAGRAM, sock->sendMessageLength);
412                                 sock->sendNext = true;
413                         }
414                         else
415                         {
416                                 sock->sendMessageLength = 0;
417                                 sock->canSend = true;
418                         }
419                         continue;
420                 }
421
422                 if (flags & NETFLAG_DATA)
423                 {
424                         packetBuffer.length = BigLong(NET_HEADERSIZE | NETFLAG_ACK);
425                         packetBuffer.sequence = BigLong(sequence);
426                         sfunc.Write (sock->socket, (qbyte *)&packetBuffer, NET_HEADERSIZE, &readaddr);
427
428                         if (sequence != sock->receiveSequence)
429                         {
430                                 receivedDuplicateCount++;
431                                 continue;
432                         }
433                         sock->receiveSequence++;
434
435                         length -= NET_HEADERSIZE;
436
437                         if (flags & NETFLAG_EOM)
438                         {
439                                 SZ_Clear(&net_message);
440                                 SZ_Write(&net_message, sock->receiveMessage, sock->receiveMessageLength);
441                                 SZ_Write(&net_message, packetBuffer.data, length);
442                                 sock->receiveMessageLength = 0;
443
444                                 ret = 1;
445                                 break;
446                         }
447
448                         memcpy(sock->receiveMessage + sock->receiveMessageLength, packetBuffer.data, length);
449                         sock->receiveMessageLength += length;
450                         continue;
451                 }
452         }
453
454         if (sock->sendNext)
455                 SendMessageNext (sock);
456
457         return ret;
458 }
459
460
461 void PrintStats(qsocket_t *s)
462 {
463         Con_Printf("canSend = %4u   \n", s->canSend);
464         Con_Printf("sendSeq = %4u   ", s->sendSequence);
465         Con_Printf("recvSeq = %4u   \n", s->receiveSequence);
466         Con_Printf("\n");
467 }
468
469 void NET_Stats_f (void)
470 {
471         qsocket_t       *s;
472
473         if (Cmd_Argc () == 1)
474         {
475                 Con_Printf("unreliable messages sent   = %i\n", unreliableMessagesSent);
476                 Con_Printf("unreliable messages recv   = %i\n", unreliableMessagesReceived);
477                 Con_Printf("reliable messages sent     = %i\n", messagesSent);
478                 Con_Printf("reliable messages received = %i\n", messagesReceived);
479                 Con_Printf("packetsSent                = %i\n", packetsSent);
480                 Con_Printf("packetsReSent              = %i\n", packetsReSent);
481                 Con_Printf("packetsReceived            = %i\n", packetsReceived);
482                 Con_Printf("receivedDuplicateCount     = %i\n", receivedDuplicateCount);
483                 Con_Printf("shortPacketCount           = %i\n", shortPacketCount);
484                 Con_Printf("droppedDatagrams           = %i\n", droppedDatagrams);
485         }
486         else if (strcmp(Cmd_Argv(1), "*") == 0)
487         {
488                 for (s = net_activeSockets; s; s = s->next)
489                         PrintStats(s);
490         }
491         else
492         {
493                 for (s = net_activeSockets; s; s = s->next)
494                         if (Q_strcasecmp(Cmd_Argv(1), s->address) == 0)
495                                 break;
496                 if (s == NULL)
497                         return;
498                 PrintStats(s);
499         }
500 }
501
502
503 static qboolean testInProgress = false;
504 static int              testPollCount;
505 static int              testDriver;
506 static int              testSocket;
507
508 static void Test_Poll(void);
509 PollProcedure   testPollProcedure = {NULL, 0.0, Test_Poll};
510
511 static void Test_Poll(void)
512 {
513         struct qsockaddr clientaddr;
514         int             control;
515         int             len;
516         char    name[32];
517         char    address[64];
518         int             colors;
519         int             frags;
520         int             connectTime;
521         qbyte   playerNumber;
522         int             c;
523
524         net_landriverlevel = testDriver;
525
526         while (1)
527         {
528                 len = dfunc.Read (testSocket, net_message.data, net_message.maxsize, &clientaddr);
529                 if (len < (int)sizeof(int))
530                         break;
531
532                 net_message.cursize = len;
533
534                 MSG_BeginReading ();
535                 control = BigLong(*((int *)net_message.data));
536                 MSG_ReadLong();
537                 if (control == -1)
538                         break;
539                 if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL)
540                         break;
541                 if ((control & NETFLAG_LENGTH_MASK) != len)
542                         break;
543
544                 c = MSG_ReadByte();
545                 if (c != CCREP_PLAYER_INFO)
546                         Sys_Error("Unexpected repsonse to Player Info request\n");
547
548                 playerNumber = MSG_ReadByte();
549                 strcpy(name, MSG_ReadString());
550                 colors = MSG_ReadLong();
551                 frags = MSG_ReadLong();
552                 connectTime = MSG_ReadLong();
553                 strcpy(address, MSG_ReadString());
554
555                 Con_Printf("%s\n  frags:%3i  colors:%u %u  time:%u\n  %s\n", name, frags, colors >> 4, colors & 0x0f, connectTime / 60, address);
556         }
557
558         testPollCount--;
559         if (testPollCount)
560         {
561                 SchedulePollProcedure(&testPollProcedure, 0.1);
562         }
563         else
564         {
565                 dfunc.CloseSocket(testSocket);
566                 testInProgress = false;
567         }
568 }
569
570 static void Test_f (void)
571 {
572         const char *host;
573         int n, max = MAX_SCOREBOARD;
574         struct qsockaddr sendaddr;
575
576         if (testInProgress)
577                 return;
578
579         host = Cmd_Argv (1);
580
581         if (host && hostCacheCount)
582         {
583                 for (n = 0; n < hostCacheCount; n++)
584                         if (Q_strcasecmp (host, hostcache[n].name) == 0)
585                         {
586                                 if (hostcache[n].driver != myDriverLevel)
587                                         continue;
588                                 net_landriverlevel = hostcache[n].ldriver;
589                                 max = hostcache[n].maxusers;
590                                 memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr));
591                                 break;
592                         }
593                 if (n < hostCacheCount)
594                         goto JustDoIt;
595         }
596
597         for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
598         {
599                 if (!net_landrivers[net_landriverlevel].initialized)
600                         continue;
601
602                 // see if we can resolve the host name
603                 if (dfunc.GetAddrFromName(host, &sendaddr) != -1)
604                         break;
605         }
606         if (net_landriverlevel == net_numlandrivers)
607                 return;
608
609 JustDoIt:
610         testSocket = dfunc.OpenSocket(0);
611         if (testSocket == -1)
612                 return;
613
614         testInProgress = true;
615         testPollCount = 20;
616         testDriver = net_landriverlevel;
617
618         for (n = 0; n < max; n++)
619         {
620                 SZ_Clear(&net_message);
621                 // save space for the header, filled in later
622                 MSG_WriteLong(&net_message, 0);
623                 MSG_WriteByte(&net_message, CCREQ_PLAYER_INFO);
624                 MSG_WriteByte(&net_message, n);
625                 *((int *)net_message.data) = BigLong(NETFLAG_CTL |      (net_message.cursize & NETFLAG_LENGTH_MASK));
626                 dfunc.Write (testSocket, net_message.data, net_message.cursize, &sendaddr);
627         }
628         SZ_Clear(&net_message);
629         SchedulePollProcedure(&testPollProcedure, 0.1);
630 }
631
632
633 static qboolean test2InProgress = false;
634 static int              test2Driver;
635 static int              test2Socket;
636
637 static void Test2_Poll(void);
638 PollProcedure   test2PollProcedure = {NULL, 0.0, Test2_Poll};
639
640 static void Test2_Poll(void)
641 {
642         struct qsockaddr clientaddr;
643         int             control;
644         int             len;
645         int             c;
646         char    name[256];
647         char    value[256];
648
649         net_landriverlevel = test2Driver;
650         name[0] = 0;
651
652         len = dfunc.Read (test2Socket, net_message.data, net_message.maxsize, &clientaddr);
653         if (len < (int)sizeof(int))
654                 goto Reschedule;
655
656         net_message.cursize = len;
657
658         MSG_BeginReading ();
659         control = BigLong(*((int *)net_message.data));
660         MSG_ReadLong();
661         if (control == -1)
662                 goto Error;
663         if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL)
664                 goto Error;
665         if ((control & NETFLAG_LENGTH_MASK) != len)
666                 goto Error;
667
668         c = MSG_ReadByte();
669         if (c != CCREP_RULE_INFO)
670                 goto Error;
671
672         strcpy(name, MSG_ReadString());
673         if (name[0] == 0)
674                 goto Done;
675         strcpy(value, MSG_ReadString());
676
677         Con_Printf("%-16.16s  %-16.16s\n", name, value);
678
679         SZ_Clear(&net_message);
680         // save space for the header, filled in later
681         MSG_WriteLong(&net_message, 0);
682         MSG_WriteByte(&net_message, CCREQ_RULE_INFO);
683         MSG_WriteString(&net_message, name);
684         *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
685         dfunc.Write (test2Socket, net_message.data, net_message.cursize, &clientaddr);
686         SZ_Clear(&net_message);
687
688 Reschedule:
689         SchedulePollProcedure(&test2PollProcedure, 0.05);
690         return;
691
692 Error:
693         Con_Printf("Unexpected repsonse to Rule Info request\n");
694 Done:
695         dfunc.CloseSocket(test2Socket);
696         test2InProgress = false;
697         return;
698 }
699
700 static void Test2_f (void)
701 {
702         const char *host;
703         int n;
704         struct qsockaddr sendaddr;
705
706         if (test2InProgress)
707                 return;
708
709         host = Cmd_Argv (1);
710
711         if (host && hostCacheCount)
712         {
713                 for (n = 0; n < hostCacheCount; n++)
714                         if (Q_strcasecmp (host, hostcache[n].name) == 0)
715                         {
716                                 if (hostcache[n].driver != myDriverLevel)
717                                         continue;
718                                 net_landriverlevel = hostcache[n].ldriver;
719                                 memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr));
720                                 break;
721                         }
722                 if (n < hostCacheCount)
723                         goto JustDoIt;
724         }
725
726         for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
727         {
728                 if (!net_landrivers[net_landriverlevel].initialized)
729                         continue;
730
731                 // see if we can resolve the host name
732                 if (dfunc.GetAddrFromName(host, &sendaddr) != -1)
733                         break;
734         }
735         if (net_landriverlevel == net_numlandrivers)
736                 return;
737
738 JustDoIt:
739         test2Socket = dfunc.OpenSocket(0);
740         if (test2Socket == -1)
741                 return;
742
743         test2InProgress = true;
744         test2Driver = net_landriverlevel;
745
746         SZ_Clear(&net_message);
747         // save space for the header, filled in later
748         MSG_WriteLong(&net_message, 0);
749         MSG_WriteByte(&net_message, CCREQ_RULE_INFO);
750         MSG_WriteString(&net_message, "");
751         *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
752         dfunc.Write (test2Socket, net_message.data, net_message.cursize, &sendaddr);
753         SZ_Clear(&net_message);
754         SchedulePollProcedure(&test2PollProcedure, 0.05);
755 }
756
757
758 int Datagram_Init (void)
759 {
760         int i;
761         int csock;
762
763         myDriverLevel = net_driverlevel;
764         Cmd_AddCommand ("net_stats", NET_Stats_f);
765         Cvar_RegisterVariable (&cl_port);
766
767         if (COM_CheckParm("-nolan"))
768                 return -1;
769
770         for (i = 0; i < net_numlandrivers; i++)
771                 {
772                 csock = net_landrivers[i].Init ();
773                 if (csock == -1)
774                         continue;
775                 net_landrivers[i].initialized = true;
776                 net_landrivers[i].controlSock = csock;
777                 }
778
779 #ifdef BAN_TEST
780         Cmd_AddCommand ("ban", NET_Ban_f);
781 #endif
782         Cmd_AddCommand ("test", Test_f);
783         Cmd_AddCommand ("test2", Test2_f);
784
785         return 0;
786 }
787
788
789 void Datagram_Shutdown (void)
790 {
791         int i;
792
793 //
794 // shutdown the lan drivers
795 //
796         for (i = 0; i < net_numlandrivers; i++)
797         {
798                 if (net_landrivers[i].initialized)
799                 {
800                         net_landrivers[i].Shutdown ();
801                         net_landrivers[i].initialized = false;
802                 }
803         }
804 }
805
806
807 void Datagram_Close (qsocket_t *sock)
808 {
809         sfunc.CloseSocket(sock->socket);
810 }
811
812
813 void Datagram_Listen (qboolean state)
814 {
815         int i;
816
817         for (i = 0; i < net_numlandrivers; i++)
818                 if (net_landrivers[i].initialized)
819                         net_landrivers[i].Listen (state);
820 }
821
822
823 static qsocket_t *_Datagram_CheckNewConnections (void)
824 {
825         struct qsockaddr clientaddr;
826         struct qsockaddr newaddr;
827         int                     newsock;
828         int                     acceptsock;
829         qsocket_t       *sock;
830         qsocket_t       *s;
831         int                     len;
832         int                     command;
833         int                     control;
834         int                     ret;
835         int                     c;
836
837         acceptsock = dfunc.CheckNewConnections();
838         if (acceptsock == -1)
839                 return NULL;
840
841         SZ_Clear(&net_message);
842
843         len = dfunc.Read (acceptsock, net_message.data, net_message.maxsize, &clientaddr);
844         if (len < (int)sizeof(int))
845                 return NULL;
846         net_message.cursize = len;
847
848         MSG_BeginReading ();
849         control = BigLong(*((int *)net_message.data));
850         MSG_ReadLong();
851
852         // Messages starting by 0xFFFFFFFF are master server messages
853         if ((unsigned int)control == 0xFFFFFFFF)
854         {
855                 int responsesize = Master_HandleMessage();
856                 if (responsesize > 0)
857                 {
858                         dfunc.Write(acceptsock, net_message.data, responsesize, &clientaddr);
859                         SZ_Clear(&net_message);
860                 }
861                 return NULL;
862         }
863         if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL)
864                 return NULL;
865         if ((control & NETFLAG_LENGTH_MASK) != len)
866                 return NULL;
867
868         command = MSG_ReadByte();
869         if (command == CCREQ_SERVER_INFO)
870         {
871                 if (strcmp(MSG_ReadString(), "QUAKE") != 0)
872                         return NULL;
873
874                 Con_DPrintf("Datagram_CheckNewConnections: received CCREQ_SERVERINFO, replying.\n");
875
876                 SZ_Clear(&net_message);
877                 // save space for the header, filled in later
878                 MSG_WriteLong(&net_message, 0);
879                 MSG_WriteByte(&net_message, CCREP_SERVER_INFO);
880                 dfunc.GetSocketAddr(acceptsock, &newaddr);
881                 MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr));
882                 MSG_WriteString(&net_message, hostname.string);
883                 MSG_WriteString(&net_message, sv.name);
884                 MSG_WriteByte(&net_message, net_activeconnections);
885                 MSG_WriteByte(&net_message, svs.maxclients);
886                 MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
887                 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
888                 dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
889                 SZ_Clear(&net_message);
890                 return NULL;
891         }
892
893         if (command == CCREQ_PLAYER_INFO)
894         {
895                 int                     playerNumber;
896                 int                     activeNumber;
897                 int                     clientNumber;
898                 client_t        *client;
899
900                 playerNumber = MSG_ReadByte();
901                 activeNumber = -1;
902                 for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++)
903                 {
904                         if (client->active)
905                         {
906                                 activeNumber++;
907                                 if (activeNumber == playerNumber)
908                                         break;
909                         }
910                 }
911                 if (clientNumber == svs.maxclients)
912                         return NULL;
913
914                 SZ_Clear(&net_message);
915                 // save space for the header, filled in later
916                 MSG_WriteLong(&net_message, 0);
917                 MSG_WriteByte(&net_message, CCREP_PLAYER_INFO);
918                 MSG_WriteByte(&net_message, playerNumber);
919                 MSG_WriteString(&net_message, client->name);
920                 MSG_WriteLong(&net_message, client->colors);
921                 MSG_WriteLong(&net_message, (int)client->edict->v->frags);
922                 MSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime));
923                 MSG_WriteString(&net_message, client->netconnection->address);
924                 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
925                 dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
926                 SZ_Clear(&net_message);
927
928                 return NULL;
929         }
930
931         if (command == CCREQ_RULE_INFO)
932         {
933                 char    *prevCvarName;
934                 cvar_t  *var;
935
936                 // find the search start location
937                 prevCvarName = MSG_ReadString();
938                 var = Cvar_FindVarAfter(prevCvarName, CVAR_NOTIFY);
939
940                 // send the response
941
942                 SZ_Clear(&net_message);
943                 // save space for the header, filled in later
944                 MSG_WriteLong(&net_message, 0);
945                 MSG_WriteByte(&net_message, CCREP_RULE_INFO);
946                 if (var)
947                 {
948                         MSG_WriteString(&net_message, var->name);
949                         MSG_WriteString(&net_message, var->string);
950                 }
951                 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
952                 dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
953                 SZ_Clear(&net_message);
954
955                 return NULL;
956         }
957
958         if (command != CCREQ_CONNECT)
959                 return NULL;
960
961         if (strcmp(MSG_ReadString(), "QUAKE") != 0)
962                 return NULL;
963
964         c = MSG_ReadByte();
965         if (c != NET_PROTOCOL_VERSION)
966         {
967                 SZ_Clear(&net_message);
968                 // save space for the header, filled in later
969                 MSG_WriteLong(&net_message, 0);
970                 MSG_WriteByte(&net_message, CCREP_REJECT);
971                 MSG_WriteString(&net_message, "Incompatible version.\n");
972                 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
973                 dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
974                 SZ_Clear(&net_message);
975                 return NULL;
976         }
977
978 #ifdef BAN_TEST
979         // check for a ban
980         if (clientaddr.sa_family == AF_INET)
981         {
982                 unsigned long testAddr;
983                 testAddr = ((struct sockaddr_in *)&clientaddr)->sin_addr.s_addr;
984                 if ((testAddr & banMask) == banAddr)
985                 {
986                         SZ_Clear(&net_message);
987                         // save space for the header, filled in later
988                         MSG_WriteLong(&net_message, 0);
989                         MSG_WriteByte(&net_message, CCREP_REJECT);
990                         MSG_WriteString(&net_message, "You have been banned.\n");
991                         *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
992                         dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
993                         SZ_Clear(&net_message);
994                         return NULL;
995                 }
996         }
997 #endif
998
999         // see if this guy is already connected
1000         for (s = net_activeSockets; s; s = s->next)
1001         {
1002                 if (s->driver != net_driverlevel)
1003                         continue;
1004                 ret = dfunc.AddrCompare(&clientaddr, &s->addr);
1005                 if (ret >= 0)
1006                 {
1007                         // is this a duplicate connection reqeust?
1008                         if (ret == 0 && net_time - s->connecttime < 2.0)
1009                         {
1010                                 // yes, so send a duplicate reply
1011                                 SZ_Clear(&net_message);
1012                                 // save space for the header, filled in later
1013                                 MSG_WriteLong(&net_message, 0);
1014                                 MSG_WriteByte(&net_message, CCREP_ACCEPT);
1015                                 dfunc.GetSocketAddr(s->socket, &newaddr);
1016                                 MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));
1017                                 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
1018                                 dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
1019                                 SZ_Clear(&net_message);
1020                                 return NULL;
1021                         }
1022                         // it's somebody coming back in from a crash/disconnect
1023                         // so close the old qsocket and let their retry get them back in
1024                         NET_Close(s);
1025                         return NULL;
1026                 }
1027         }
1028
1029         // allocate a QSocket
1030         sock = NET_NewQSocket ();
1031         if (sock == NULL)
1032         {
1033                 // no room; try to let him know
1034                 SZ_Clear(&net_message);
1035                 // save space for the header, filled in later
1036                 MSG_WriteLong(&net_message, 0);
1037                 MSG_WriteByte(&net_message, CCREP_REJECT);
1038                 MSG_WriteString(&net_message, "Server is full.\n");
1039                 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
1040                 dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
1041                 SZ_Clear(&net_message);
1042                 return NULL;
1043         }
1044
1045         // allocate a network socket
1046         newsock = dfunc.OpenSocket(0);
1047         if (newsock == -1)
1048         {
1049                 NET_FreeQSocket(sock);
1050                 return NULL;
1051         }
1052
1053         // connect to the client
1054         if (dfunc.Connect (newsock, &clientaddr) == -1)
1055         {
1056                 dfunc.CloseSocket(newsock);
1057                 NET_FreeQSocket(sock);
1058                 return NULL;
1059         }
1060
1061         // everything is allocated, just fill in the details
1062         sock->socket = newsock;
1063         sock->landriver = net_landriverlevel;
1064         sock->addr = clientaddr;
1065         strcpy(sock->address, dfunc.AddrToString(&clientaddr));
1066
1067         // send him back the info about the server connection he has been allocated
1068         SZ_Clear(&net_message);
1069         // save space for the header, filled in later
1070         MSG_WriteLong(&net_message, 0);
1071         MSG_WriteByte(&net_message, CCREP_ACCEPT);
1072         dfunc.GetSocketAddr(newsock, &newaddr);
1073         MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));
1074         *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
1075         dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
1076         SZ_Clear(&net_message);
1077
1078         return sock;
1079 }
1080
1081 qsocket_t *Datagram_CheckNewConnections (void)
1082 {
1083         qsocket_t *ret = NULL;
1084
1085         for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
1086                 if (net_landrivers[net_landriverlevel].initialized)
1087                         if ((ret = _Datagram_CheckNewConnections ()) != NULL)
1088                                 break;
1089         return ret;
1090 }
1091
1092
1093 static qboolean Datagram_HandleServerInfo (struct qsockaddr *readaddr)
1094 {
1095         struct qsockaddr myaddr;
1096         int control;
1097         int c, n, i;
1098
1099         if (net_message.cursize < (int)sizeof(int))
1100                 return false;
1101
1102         // don't answer our own query
1103         dfunc.GetSocketAddr (dfunc.controlSock, &myaddr);
1104         //if (dfunc.AddrCompare(readaddr, &myaddr) >= 0)
1105         //      return false;
1106
1107         // is the cache full?
1108         if (hostCacheCount == HOSTCACHESIZE)
1109                 return false;
1110
1111         MSG_BeginReading ();
1112         control = BigLong(*((int *)net_message.data));
1113         MSG_ReadLong();
1114         if (control == -1)
1115                 return false;
1116         if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL)
1117                 return false;
1118         if ((control & NETFLAG_LENGTH_MASK) != net_message.cursize)
1119                 return false;
1120
1121         c = MSG_ReadByte();
1122         if (c != CCREP_SERVER_INFO)
1123                 return false;
1124
1125         dfunc.GetAddrFromName(MSG_ReadString(), readaddr);
1126         // search the cache for this server
1127         for (n = 0; n < hostCacheCount; n++)
1128                 if (dfunc.AddrCompare(readaddr, &hostcache[n].addr) == 0)
1129                         break;
1130
1131         // is it already there?
1132         if (n < hostCacheCount)
1133                 return false;;
1134
1135         // add it
1136         hostCacheCount++;
1137         strcpy(hostcache[n].name, MSG_ReadString());
1138         strcpy(hostcache[n].map, MSG_ReadString());
1139         hostcache[n].users = MSG_ReadByte();
1140         hostcache[n].maxusers = MSG_ReadByte();
1141         c = MSG_ReadByte();
1142         if (c != NET_PROTOCOL_VERSION)
1143         {
1144                 strcpy(hostcache[n].cname, hostcache[n].name);
1145                 hostcache[n].cname[14] = 0;
1146                 strcpy(hostcache[n].name, "*");
1147                 strcat(hostcache[n].name, hostcache[n].cname);
1148         }
1149         memcpy(&hostcache[n].addr, readaddr, sizeof(struct qsockaddr));
1150         hostcache[n].driver = net_driverlevel;
1151         hostcache[n].ldriver = net_landriverlevel;
1152         strcpy(hostcache[n].cname, dfunc.AddrToString(readaddr));
1153
1154         // check for a name conflict
1155         for (i = 0; i < hostCacheCount; i++)
1156         {
1157                 if (i == n)
1158                         continue;
1159                 if (Q_strcasecmp (hostcache[n].name, hostcache[i].name) == 0)
1160                 {
1161                         i = strlen(hostcache[n].name);
1162                         if (i < 15 && hostcache[n].name[i-1] > '8')
1163                         {
1164                                 hostcache[n].name[i] = '0';
1165                                 hostcache[n].name[i+1] = 0;
1166                         }
1167                         else
1168                                 hostcache[n].name[i-1]++;
1169                         i = -1;
1170                 }
1171         }
1172
1173         return true;
1174 }
1175
1176
1177 static void _Datagram_SearchForHosts (qboolean xmit)
1178 {
1179         int             ret;
1180         struct qsockaddr readaddr;
1181
1182         if (xmit)
1183         {
1184                 SZ_Clear(&net_message);
1185                 // save space for the header, filled in later
1186                 MSG_WriteLong(&net_message, 0);
1187                 MSG_WriteByte(&net_message, CCREQ_SERVER_INFO);
1188                 MSG_WriteString(&net_message, "QUAKE");
1189                 MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
1190                 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
1191                 dfunc.Broadcast(dfunc.controlSock, net_message.data, net_message.cursize);
1192                 SZ_Clear(&net_message);
1193         }
1194
1195         while ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0)
1196         {
1197                 net_message.cursize = ret;
1198                 Datagram_HandleServerInfo (&readaddr);
1199         }
1200 }
1201
1202 void Datagram_SearchForHosts (qboolean xmit)
1203 {
1204         for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
1205         {
1206                 if (hostCacheCount == HOSTCACHESIZE)
1207                         break;
1208                 if (net_landrivers[net_landriverlevel].initialized)
1209                         _Datagram_SearchForHosts (xmit);
1210         }
1211 }
1212
1213
1214 static qboolean _Datagram_SearchForInetHosts (const char *master)
1215 {
1216         qboolean result = false;
1217         struct qsockaddr masteraddr;
1218         struct qsockaddr readaddr;
1219         int ret;
1220
1221         if (master)
1222         {
1223                 if (dfunc.GetAddrFromName(master, &masteraddr) != -1)
1224                 {
1225                         int portnum = 0;
1226                         const char* port = strrchr (master, ':');
1227                         if (port)
1228                                 portnum = atoi (port + 1);
1229                         if (!portnum)
1230                                 portnum = MASTER_PORT;
1231                         Con_DPrintf("Datagram_SearchForInetHosts: sending %d byte message to master %s\n", net_message.cursize, master);
1232                         dfunc.SetSocketPort (&masteraddr, portnum);
1233                         dfunc.Send (net_message.data, net_message.cursize, &masteraddr);
1234                 }
1235         }
1236
1237         while ((ret = dfunc.Recv (net_message.data, net_message.maxsize, &readaddr)) > 0)
1238         {
1239                 net_message.cursize = ret;
1240                 Con_DPrintf("Datagram_SearchForInetHosts: Recv received %d byte message\n", net_message.cursize);
1241                 Master_ParseServerList (&dfunc);
1242         }
1243
1244         while ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0)
1245         {
1246                 net_message.cursize = ret;
1247                 Con_DPrintf("Datagram_SearchForInetHosts: Read received %d byte message\n", net_message.cursize);
1248                 if (Datagram_HandleServerInfo (&readaddr))
1249                         result = true;
1250         }
1251
1252         return result;
1253 }
1254
1255
1256 qboolean Datagram_SearchForInetHosts (const char *master)
1257 {
1258         qboolean result = false;
1259         for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
1260         {
1261                 if (hostCacheCount == HOSTCACHESIZE)
1262                         break;
1263                 if (net_landrivers[net_landriverlevel].initialized)
1264                         if (_Datagram_SearchForInetHosts (master))
1265                                 result = true;
1266         }
1267
1268         return result;
1269 }
1270
1271
1272 static qsocket_t *_Datagram_Connect (const char *host)
1273 {
1274         struct qsockaddr sendaddr;
1275         struct qsockaddr readaddr;
1276         qsocket_t       *sock;
1277         int                     newsock;
1278         int                     ret;
1279         int                     reps;
1280         double          start_time;
1281         int                     control;
1282         char            *reason;
1283
1284         // see if we can resolve the host name
1285         if (dfunc.GetAddrFromName(host, &sendaddr) == -1)
1286                 return NULL;
1287
1288         newsock = dfunc.OpenSocket (cl_port.integer);
1289         if (newsock == -1)
1290                 return NULL;
1291
1292         sock = NET_NewQSocket ();
1293         if (sock == NULL)
1294                 goto ErrorReturn2;
1295         sock->socket = newsock;
1296         sock->landriver = net_landriverlevel;
1297
1298         // connect to the host
1299         if (dfunc.Connect (newsock, &sendaddr) == -1)
1300                 goto ErrorReturn;
1301
1302         // send the connection request
1303         Con_Printf("trying...\n");CL_UpdateScreen();CL_UpdateScreen();
1304         start_time = net_time;
1305
1306         for (reps = 0; reps < 3; reps++)
1307         {
1308                 SZ_Clear(&net_message);
1309                 // save space for the header, filled in later
1310                 MSG_WriteLong(&net_message, 0);
1311                 MSG_WriteByte(&net_message, CCREQ_CONNECT);
1312                 MSG_WriteString(&net_message, "QUAKE");
1313                 MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
1314                 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
1315                 dfunc.Write (newsock, net_message.data, net_message.cursize, &sendaddr);
1316                 SZ_Clear(&net_message);
1317                 do
1318                 {
1319                         ret = dfunc.Read (newsock, net_message.data, net_message.maxsize, &readaddr);
1320                         // if we got something, validate it
1321                         if (ret > 0)
1322                         {
1323                                 // is it from the right place?
1324                                 if (sfunc.AddrCompare(&readaddr, &sendaddr) != 0)
1325                                 {
1326                                         Con_DPrintf("wrong reply address\n");
1327                                         Con_DPrintf("Expected: %s\n", StrAddr (&sendaddr));
1328                                         Con_DPrintf("Received: %s\n", StrAddr (&readaddr));
1329                                         CL_UpdateScreen ();
1330                                         ret = 0;
1331                                         continue;
1332                                 }
1333
1334                                 if (ret < (int)sizeof(int))
1335                                 {
1336                                         ret = 0;
1337                                         continue;
1338                                 }
1339
1340                                 net_message.cursize = ret;
1341                                 MSG_BeginReading ();
1342
1343                                 control = BigLong(*((int *)net_message.data));
1344                                 MSG_ReadLong();
1345                                 if (control == -1)
1346                                 {
1347                                         ret = 0;
1348                                         continue;
1349                                 }
1350                                 if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL)
1351                                 {
1352                                         ret = 0;
1353                                         continue;
1354                                 }
1355                                 if ((control & NETFLAG_LENGTH_MASK) != ret)
1356                                 {
1357                                         ret = 0;
1358                                         continue;
1359                                 }
1360                         }
1361                 }
1362                 while (ret == 0 && (SetNetTime() - start_time) < 2.5);
1363                 if (ret)
1364                         break;
1365                 Con_Printf("still trying...\n");CL_UpdateScreen();CL_UpdateScreen();
1366                 start_time = SetNetTime();
1367         }
1368
1369         if (ret == 0)
1370         {
1371                 reason = "No Response";
1372                 Con_Printf("%s\n", reason);
1373                 strcpy(m_return_reason, reason);
1374                 goto ErrorReturn;
1375         }
1376
1377         if (ret == -1)
1378         {
1379                 reason = "Network Error";
1380                 Con_Printf("%s\n", reason);
1381                 strcpy(m_return_reason, reason);
1382                 goto ErrorReturn;
1383         }
1384
1385         ret = MSG_ReadByte();
1386         if (ret == CCREP_REJECT)
1387         {
1388                 reason = MSG_ReadString();
1389                 Con_Printf("%s", reason);
1390                 strncpy(m_return_reason, reason, 31);
1391                 goto ErrorReturn;
1392         }
1393
1394         if (ret == CCREP_ACCEPT)
1395         {
1396                 memcpy(&sock->addr, &sendaddr, sizeof(struct qsockaddr));
1397                 dfunc.SetSocketPort (&sock->addr, MSG_ReadLong());
1398         }
1399         else
1400         {
1401                 reason = "Bad Response";
1402                 Con_Printf("%s\n", reason);
1403                 strcpy(m_return_reason, reason);
1404                 goto ErrorReturn;
1405         }
1406
1407         dfunc.GetNameFromAddr (&sendaddr, sock->address);
1408
1409         Con_Printf ("Connection accepted to %s\n", sock->address);
1410         sock->lastMessageTime = SetNetTime();
1411
1412         // switch the connection to the specified address
1413         if (dfunc.Connect (newsock, &sock->addr) == -1)
1414         {
1415                 reason = "Connect to Game failed";
1416                 Con_Printf("%s\n", reason);
1417                 strcpy(m_return_reason, reason);
1418                 goto ErrorReturn;
1419         }
1420
1421         m_return_onerror = false;
1422         return sock;
1423
1424 ErrorReturn:
1425         NET_FreeQSocket(sock);
1426 ErrorReturn2:
1427         dfunc.CloseSocket(newsock);
1428         if (m_return_onerror)
1429         {
1430                 key_dest = key_menu;
1431                 m_state = m_return_state;
1432                 m_return_onerror = false;
1433         }
1434         return NULL;
1435 }
1436
1437 qsocket_t *Datagram_Connect (const char *host)
1438 {
1439         qsocket_t *ret = NULL;
1440
1441         for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
1442                 if (net_landrivers[net_landriverlevel].initialized)
1443                         if ((ret = _Datagram_Connect (host)) != NULL)
1444                                 break;
1445         return ret;
1446 }
1447
1448 static void _Datagram_Heartbeat (const char *master)
1449 {
1450         struct qsockaddr masteraddr;
1451         int portnum;
1452         const char* port;
1453
1454         if (dfunc.GetAddrFromName(master, &masteraddr) == -1)
1455                 return;
1456
1457         portnum = 0;
1458         port = strrchr (master, ':');
1459         if (port)
1460                 portnum = atoi (port + 1);
1461         if (!portnum)
1462                 portnum = MASTER_PORT;
1463         dfunc.SetSocketPort (&masteraddr, portnum);
1464
1465         dfunc.Send (net_message.data, net_message.cursize, &masteraddr);
1466 }
1467
1468 void Datagram_Heartbeat (const char *master)
1469 {
1470         for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
1471                 if (net_landrivers[net_landriverlevel].initialized)
1472                         _Datagram_Heartbeat (master);
1473 }