]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - net_dgrm.c
This is the network rewrite I've been working on for over a week; multiplayer should...
[xonotic/darkplaces.git] / net_dgrm.c
diff --git a/net_dgrm.c b/net_dgrm.c
deleted file mode 100644 (file)
index 53ab0bd..0000000
+++ /dev/null
@@ -1,1504 +0,0 @@
-/*
-Copyright (C) 1996-1997 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-*/
-// net_dgrm.c
-
-// This is enables a simple IP banning mechanism
-#define BAN_TEST
-
-#ifdef BAN_TEST
-#if defined(_WIN32)
-#include <windows.h>
-#elif defined (NeXT)
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#else
-#define AF_INET                2       /* internet */
-struct in_addr
-{
-       union
-       {
-               struct { unsigned char s_b1,s_b2,s_b3,s_b4; } S_un_b;
-               struct { unsigned short s_w1,s_w2; } S_un_w;
-               unsigned long S_addr;
-       } S_un;
-};
-#define        s_addr  S_un.S_addr     /* can be used for most tcp & ip code */
-struct sockaddr_in
-{
-    short                      sin_family;
-    unsigned short     sin_port;
-       struct in_addr  sin_addr;
-    char                       sin_zero[8];
-};
-char *inet_ntoa(struct in_addr in);
-unsigned long inet_addr(const char *cp);
-#endif
-#endif // BAN_TEST
-
-#include "quakedef.h"
-#include "net_dgrm.h"
-#include "net_master.h"
-
-cvar_t cl_port = {CVAR_SAVE, "cl_port", "0"};
-
-// these two macros are to make the code more readable
-#define sfunc  net_landrivers[sock->landriver]
-#define dfunc  net_landrivers[net_landriverlevel]
-
-static int net_landriverlevel;
-
-/* statistic counters */
-int    packetsSent = 0;
-int    packetsReSent = 0;
-int packetsReceived = 0;
-int receivedDuplicateCount = 0;
-int shortPacketCount = 0;
-int droppedDatagrams;
-
-static int myDriverLevel;
-
-struct
-{
-       unsigned int    length;
-       unsigned int    sequence;
-       qbyte                   data[MAX_DATAGRAM];
-} packetBuffer;
-
-/*
-#ifdef DEBUG
-char *StrAddr (struct qsockaddr *addr)
-{
-       static char buf[34];
-       qbyte *p = (qbyte *)addr;
-       int n;
-
-       for (n = 0; n < 16; n++)
-               sprintf (buf + n * 2, "%02x", *p++);
-       return buf;
-}
-#endif
-*/
-
-
-#ifdef BAN_TEST
-unsigned long banAddr = 0x00000000;
-unsigned long banMask = 0xffffffff;
-
-void NET_Ban_f (void)
-{
-       char    addrStr [32];
-       char    maskStr [32];
-       void    (*print) (const char *fmt, ...);
-
-       if (cmd_source == src_command)
-       {
-               if (!sv.active)
-               {
-                       Cmd_ForwardToServer ();
-                       return;
-               }
-               print = Con_Printf;
-       }
-       else
-       {
-               if (pr_global_struct->deathmatch)
-                       return;
-               print = SV_ClientPrintf;
-       }
-
-       switch (Cmd_Argc ())
-       {
-               case 1:
-                       if (((struct in_addr *)&banAddr)->s_addr)
-                       {
-                               strcpy(addrStr, inet_ntoa(*(struct in_addr *)&banAddr));
-                               strcpy(maskStr, inet_ntoa(*(struct in_addr *)&banMask));
-                               print("Banning %s [%s]\n", addrStr, maskStr);
-                       }
-                       else
-                               print("Banning not active\n");
-                       break;
-
-               case 2:
-                       if (strcasecmp(Cmd_Argv(1), "off") == 0)
-                               banAddr = 0x00000000;
-                       else
-                               banAddr = inet_addr(Cmd_Argv(1));
-                       banMask = 0xffffffff;
-                       break;
-
-               case 3:
-                       banAddr = inet_addr(Cmd_Argv(1));
-                       banMask = inet_addr(Cmd_Argv(2));
-                       break;
-
-               default:
-                       print("BAN ip_address [mask]\n");
-                       break;
-       }
-}
-#endif
-
-
-int Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data)
-{
-       unsigned int    packetLen;
-       unsigned int    dataLen;
-       unsigned int    eom;
-
-#ifdef DEBUG
-       if (data->cursize == 0)
-               Sys_Error("Datagram_SendMessage: zero length message\n");
-
-       if (data->cursize > NET_MAXMESSAGE)
-               Sys_Error("Datagram_SendMessage: message too big %u\n", data->cursize);
-
-       if (sock->canSend == false)
-               Sys_Error("SendMessage: called with canSend == false\n");
-#endif
-
-       memcpy(sock->sendMessage, data->data, data->cursize);
-       sock->sendMessageLength = data->cursize;
-
-       if (data->cursize <= MAX_DATAGRAM)
-       {
-               dataLen = data->cursize;
-               eom = NETFLAG_EOM;
-       }
-       else
-       {
-               dataLen = MAX_DATAGRAM;
-               eom = 0;
-       }
-       packetLen = NET_HEADERSIZE + dataLen;
-
-       packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
-       packetBuffer.sequence = BigLong(sock->sendSequence++);
-       memcpy (packetBuffer.data, sock->sendMessage, dataLen);
-
-       sock->canSend = false;
-
-       if (sfunc.Write (sock->socket, (qbyte *)&packetBuffer, packetLen, &sock->addr) == -1)
-               return -1;
-
-       sock->lastSendTime = net_time;
-       packetsSent++;
-       return 1;
-}
-
-
-int SendMessageNext (qsocket_t *sock)
-{
-       unsigned int    packetLen;
-       unsigned int    dataLen;
-       unsigned int    eom;
-
-       if (sock->sendMessageLength <= MAX_DATAGRAM)
-       {
-               dataLen = sock->sendMessageLength;
-               eom = NETFLAG_EOM;
-       }
-       else
-       {
-               dataLen = MAX_DATAGRAM;
-               eom = 0;
-       }
-       packetLen = NET_HEADERSIZE + dataLen;
-
-       packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
-       packetBuffer.sequence = BigLong(sock->sendSequence++);
-       memcpy (packetBuffer.data, sock->sendMessage, dataLen);
-
-       sock->sendNext = false;
-
-       if (sfunc.Write (sock->socket, (qbyte *)&packetBuffer, packetLen, &sock->addr) == -1)
-               return -1;
-
-       sock->lastSendTime = net_time;
-       packetsSent++;
-       return 1;
-}
-
-
-int ReSendMessage (qsocket_t *sock)
-{
-       unsigned int    packetLen;
-       unsigned int    dataLen;
-       unsigned int    eom;
-
-       if (sock->sendMessageLength <= MAX_DATAGRAM)
-       {
-               dataLen = sock->sendMessageLength;
-               eom = NETFLAG_EOM;
-       }
-       else
-       {
-               dataLen = MAX_DATAGRAM;
-               eom = 0;
-       }
-       packetLen = NET_HEADERSIZE + dataLen;
-
-       packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
-       packetBuffer.sequence = BigLong(sock->sendSequence - 1);
-       memcpy (packetBuffer.data, sock->sendMessage, dataLen);
-
-       sock->sendNext = false;
-
-       if (sfunc.Write (sock->socket, (qbyte *)&packetBuffer, packetLen, &sock->addr) == -1)
-               return -1;
-
-       sock->lastSendTime = net_time;
-       packetsReSent++;
-       return 1;
-}
-
-
-qboolean Datagram_CanSendMessage (qsocket_t *sock)
-{
-       if (sock->sendNext)
-               SendMessageNext (sock);
-
-       return sock->canSend;
-}
-
-
-qboolean Datagram_CanSendUnreliableMessage (qsocket_t *sock)
-{
-       return true;
-}
-
-
-int Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
-{
-       int     packetLen;
-
-#ifdef DEBUG
-       if (data->cursize == 0)
-               Sys_Error("Datagram_SendUnreliableMessage: zero length message\n");
-
-       if (data->cursize > MAX_DATAGRAM)
-               Sys_Error("Datagram_SendUnreliableMessage: message too big %u\n", data->cursize);
-#endif
-
-       packetLen = NET_HEADERSIZE + data->cursize;
-
-       packetBuffer.length = BigLong(packetLen | NETFLAG_UNRELIABLE);
-       packetBuffer.sequence = BigLong(sock->unreliableSendSequence++);
-       memcpy (packetBuffer.data, data->data, data->cursize);
-
-       if (sfunc.Write (sock->socket, (qbyte *)&packetBuffer, packetLen, &sock->addr) == -1)
-               return -1;
-
-       packetsSent++;
-       return 1;
-}
-
-
-int    Datagram_GetMessage (qsocket_t *sock)
-{
-       unsigned int    length;
-       unsigned int    flags;
-       int                             ret = 0;
-       struct qsockaddr readaddr;
-       unsigned int    sequence;
-       unsigned int    count;
-       int                             temp;
-
-       if (!sock->canSend)
-               if ((net_time - sock->lastSendTime) > 1.0)
-                       ReSendMessage (sock);
-
-       while(1)
-       {
-               length = sfunc.Read (sock->socket, (qbyte *)&packetBuffer, NET_DATAGRAMSIZE, &readaddr);
-
-               if (length == 0)
-                       break;
-
-               if ((int)length == -1)
-               {
-                       Con_Printf("Read error\n");
-                       return -1;
-               }
-
-               if ((temp = sfunc.AddrCompare(&readaddr, &sock->addr)) != 0)
-               {
-                       char tempaddress1[64], tempaddress2[64];
-                       if (temp == 1)
-                       {
-                               if (developer_networking.integer)
-                               {
-                                       dfunc.GetNameFromAddr (&sock->addr, tempaddress1);
-                                       dfunc.GetNameFromAddr (&readaddr, tempaddress2);
-                                       Con_Printf("Packet from wrong port received but accepted (Expected: %s Received: %s)\n", tempaddress1, tempaddress2);
-                               }
-                       }
-                       else
-                       {
-                               dfunc.GetNameFromAddr (&sock->addr, tempaddress1);
-                               dfunc.GetNameFromAddr (&readaddr, tempaddress2);
-                               Con_Printf("Forged packet received (Expected: %s Received: %s)\n", tempaddress1, tempaddress2);
-                               continue;
-                       }
-               }
-
-               if (length < NET_HEADERSIZE)
-               {
-                       shortPacketCount++;
-                       continue;
-               }
-
-               length = BigLong(packetBuffer.length);
-               flags = length & (~NETFLAG_LENGTH_MASK);
-               length &= NETFLAG_LENGTH_MASK;
-
-               if (flags & NETFLAG_CTL)
-                       continue;
-
-               sequence = BigLong(packetBuffer.sequence);
-               packetsReceived++;
-
-               if (flags & NETFLAG_UNRELIABLE)
-               {
-                       if (sequence < sock->unreliableReceiveSequence)
-                       {
-                               Con_DPrintf("Got a stale datagram\n");
-                               ret = 0;
-                               break;
-                       }
-                       if (sequence != sock->unreliableReceiveSequence)
-                       {
-                               count = sequence - sock->unreliableReceiveSequence;
-                               droppedDatagrams += count;
-                               Con_DPrintf("Dropped %u datagram(s)\n", count);
-                       }
-                       sock->unreliableReceiveSequence = sequence + 1;
-
-                       length -= NET_HEADERSIZE;
-
-                       SZ_Clear (&net_message);
-                       SZ_Write (&net_message, packetBuffer.data, length);
-
-                       ret = 2;
-                       break;
-               }
-
-               if (flags & NETFLAG_ACK)
-               {
-                       if (sequence != (sock->sendSequence - 1))
-                       {
-                               Con_DPrintf("Stale ACK received\n");
-                               continue;
-                       }
-                       if (sequence == sock->ackSequence)
-                       {
-                               sock->ackSequence++;
-                               if (sock->ackSequence != sock->sendSequence)
-                                       Con_DPrintf("ack sequencing error\n");
-                       }
-                       else
-                       {
-                               Con_DPrintf("Duplicate ACK received\n");
-                               continue;
-                       }
-                       sock->sendMessageLength -= MAX_DATAGRAM;
-                       if (sock->sendMessageLength > 0)
-                       {
-                               memcpy(sock->sendMessage, sock->sendMessage+MAX_DATAGRAM, sock->sendMessageLength);
-                               sock->sendNext = true;
-                       }
-                       else
-                       {
-                               sock->sendMessageLength = 0;
-                               sock->canSend = true;
-                       }
-                       continue;
-               }
-
-               if (flags & NETFLAG_DATA)
-               {
-                       packetBuffer.length = BigLong(NET_HEADERSIZE | NETFLAG_ACK);
-                       packetBuffer.sequence = BigLong(sequence);
-                       sfunc.Write (sock->socket, (qbyte *)&packetBuffer, NET_HEADERSIZE, &readaddr);
-
-                       if (sequence != sock->receiveSequence)
-                       {
-                               receivedDuplicateCount++;
-                               continue;
-                       }
-                       sock->receiveSequence++;
-
-                       length -= NET_HEADERSIZE;
-
-                       if (flags & NETFLAG_EOM)
-                       {
-                               SZ_Clear(&net_message);
-                               SZ_Write(&net_message, sock->receiveMessage, sock->receiveMessageLength);
-                               SZ_Write(&net_message, packetBuffer.data, length);
-                               sock->receiveMessageLength = 0;
-
-                               ret = 1;
-                               break;
-                       }
-
-                       memcpy(sock->receiveMessage + sock->receiveMessageLength, packetBuffer.data, length);
-                       sock->receiveMessageLength += length;
-                       continue;
-               }
-       }
-
-       if (sock->sendNext)
-               SendMessageNext (sock);
-
-       return ret;
-}
-
-
-void PrintStats(qsocket_t *s)
-{
-       Con_Printf("canSend = %4u   \n", s->canSend);
-       Con_Printf("sendSeq = %4u   ", s->sendSequence);
-       Con_Printf("recvSeq = %4u   \n", s->receiveSequence);
-       Con_Printf("\n");
-}
-
-void NET_Stats_f (void)
-{
-       qsocket_t       *s;
-
-       if (Cmd_Argc () == 1)
-       {
-               Con_Printf("unreliable messages sent   = %i\n", unreliableMessagesSent);
-               Con_Printf("unreliable messages recv   = %i\n", unreliableMessagesReceived);
-               Con_Printf("reliable messages sent     = %i\n", messagesSent);
-               Con_Printf("reliable messages received = %i\n", messagesReceived);
-               Con_Printf("packetsSent                = %i\n", packetsSent);
-               Con_Printf("packetsReSent              = %i\n", packetsReSent);
-               Con_Printf("packetsReceived            = %i\n", packetsReceived);
-               Con_Printf("receivedDuplicateCount     = %i\n", receivedDuplicateCount);
-               Con_Printf("shortPacketCount           = %i\n", shortPacketCount);
-               Con_Printf("droppedDatagrams           = %i\n", droppedDatagrams);
-       }
-       else if (strcmp(Cmd_Argv(1), "*") == 0)
-       {
-               for (s = net_activeSockets; s; s = s->next)
-                       PrintStats(s);
-       }
-       else
-       {
-               for (s = net_activeSockets; s; s = s->next)
-                       if (strcasecmp(Cmd_Argv(1), s->address) == 0)
-                               break;
-               if (s == NULL)
-                       return;
-               PrintStats(s);
-       }
-}
-
-/*
-static qboolean testInProgress = false;
-static int             testPollCount;
-static int             testDriver;
-static int             testSocket;
-
-static void Test_Poll(void);
-PollProcedure  testPollProcedure = {NULL, 0.0, Test_Poll};
-
-static void Test_Poll(void)
-{
-       struct qsockaddr clientaddr;
-       int             control;
-       int             len;
-       char    name[32];
-       char    address[64];
-       int             colors;
-       int             frags;
-       int             connectTime;
-       qbyte   playerNumber;
-       int             c;
-
-       net_landriverlevel = testDriver;
-
-       while (1)
-       {
-               len = dfunc.Read (testSocket, net_message.data, net_message.maxsize, &clientaddr);
-               if (len < (int)sizeof(int))
-                       break;
-
-               net_message.cursize = len;
-
-               MSG_BeginReading ();
-               control = BigLong(*((int *)net_message.data));
-               MSG_ReadLong();
-               if (control == -1)
-                       break;
-               if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL)
-                       break;
-               if ((control & NETFLAG_LENGTH_MASK) != len)
-                       break;
-
-               c = MSG_ReadByte();
-               if (c != CCREP_PLAYER_INFO)
-                       Sys_Error("Unexpected repsonse to Player Info request\n");
-
-               playerNumber = MSG_ReadByte();
-               strcpy(name, MSG_ReadString());
-               colors = MSG_ReadLong();
-               frags = MSG_ReadLong();
-               connectTime = MSG_ReadLong();
-               strcpy(address, MSG_ReadString());
-
-               Con_Printf("%s\n  frags:%3i  colors:%u %u  time:%u\n  %s\n", name, frags, colors >> 4, colors & 0x0f, connectTime / 60, address);
-       }
-
-       testPollCount--;
-       if (testPollCount)
-       {
-               SchedulePollProcedure(&testPollProcedure, 0.1);
-       }
-       else
-       {
-               dfunc.CloseSocket(testSocket);
-               testInProgress = false;
-       }
-}
-
-static void Test_f (void)
-{
-       const char *host;
-       int n, max = MAX_SCOREBOARD;
-       struct qsockaddr sendaddr;
-
-       if (testInProgress)
-               return;
-
-       host = Cmd_Argv (1);
-
-       if (host && hostCacheCount)
-       {
-               for (n = 0; n < hostCacheCount; n++)
-                       if (strcasecmp (host, hostcache[n].name) == 0)
-                       {
-                               if (hostcache[n].driver != myDriverLevel)
-                                       continue;
-                               net_landriverlevel = hostcache[n].ldriver;
-                               max = hostcache[n].maxusers;
-                               memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr));
-                               break;
-                       }
-               if (n < hostCacheCount)
-                       goto JustDoIt;
-       }
-
-       for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
-       {
-               if (!net_landrivers[net_landriverlevel].initialized)
-                       continue;
-
-               // see if we can resolve the host name
-               if (dfunc.GetAddrFromName(host, &sendaddr) != -1)
-                       break;
-       }
-       if (net_landriverlevel == net_numlandrivers)
-               return;
-
-JustDoIt:
-       testSocket = dfunc.OpenSocket(0);
-       if (testSocket == -1)
-               return;
-
-       testInProgress = true;
-       testPollCount = 20;
-       testDriver = net_landriverlevel;
-
-       for (n = 0; n < max; n++)
-       {
-               SZ_Clear(&net_message);
-               // save space for the header, filled in later
-               MSG_WriteLong(&net_message, 0);
-               MSG_WriteByte(&net_message, CCREQ_PLAYER_INFO);
-               MSG_WriteByte(&net_message, n);
-               *((int *)net_message.data) = BigLong(NETFLAG_CTL |      (net_message.cursize & NETFLAG_LENGTH_MASK));
-               dfunc.Write (testSocket, net_message.data, net_message.cursize, &sendaddr);
-       }
-       SZ_Clear(&net_message);
-       SchedulePollProcedure(&testPollProcedure, 0.1);
-}
-
-
-static qboolean test2InProgress = false;
-static int             test2Driver;
-static int             test2Socket;
-
-static void Test2_Poll(void);
-PollProcedure  test2PollProcedure = {NULL, 0.0, Test2_Poll};
-
-static void Test2_Poll(void)
-{
-       struct qsockaddr clientaddr;
-       int             control;
-       int             len;
-       int             c;
-       char    name[256];
-       char    value[256];
-
-       net_landriverlevel = test2Driver;
-       name[0] = 0;
-
-       len = dfunc.Read (test2Socket, net_message.data, net_message.maxsize, &clientaddr);
-       if (len < (int)sizeof(int))
-               goto Reschedule;
-
-       net_message.cursize = len;
-
-       MSG_BeginReading ();
-       control = BigLong(*((int *)net_message.data));
-       MSG_ReadLong();
-       if (control == -1)
-               goto Error;
-       if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL)
-               goto Error;
-       if ((control & NETFLAG_LENGTH_MASK) != len)
-               goto Error;
-
-       c = MSG_ReadByte();
-       if (c != CCREP_RULE_INFO)
-               goto Error;
-
-       strcpy(name, MSG_ReadString());
-       if (name[0] == 0)
-               goto Done;
-       strcpy(value, MSG_ReadString());
-
-       Con_Printf("%-16.16s  %-16.16s\n", name, value);
-
-       SZ_Clear(&net_message);
-       // save space for the header, filled in later
-       MSG_WriteLong(&net_message, 0);
-       MSG_WriteByte(&net_message, CCREQ_RULE_INFO);
-       MSG_WriteString(&net_message, name);
-       *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-       dfunc.Write (test2Socket, net_message.data, net_message.cursize, &clientaddr);
-       SZ_Clear(&net_message);
-
-Reschedule:
-       SchedulePollProcedure(&test2PollProcedure, 0.05);
-       return;
-
-Error:
-       Con_Printf("Unexpected repsonse to Rule Info request\n");
-Done:
-       dfunc.CloseSocket(test2Socket);
-       test2InProgress = false;
-       return;
-}
-
-static void Test2_f (void)
-{
-       const char *host;
-       int n;
-       struct qsockaddr sendaddr;
-
-       if (test2InProgress)
-               return;
-
-       host = Cmd_Argv (1);
-
-       if (host && hostCacheCount)
-       {
-               for (n = 0; n < hostCacheCount; n++)
-                       if (strcasecmp (host, hostcache[n].name) == 0)
-                       {
-                               if (hostcache[n].driver != myDriverLevel)
-                                       continue;
-                               net_landriverlevel = hostcache[n].ldriver;
-                               memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr));
-                               break;
-                       }
-               if (n < hostCacheCount)
-                       goto JustDoIt;
-       }
-
-       for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
-       {
-               if (!net_landrivers[net_landriverlevel].initialized)
-                       continue;
-
-               // see if we can resolve the host name
-               if (dfunc.GetAddrFromName(host, &sendaddr) != -1)
-                       break;
-       }
-       if (net_landriverlevel == net_numlandrivers)
-               return;
-
-JustDoIt:
-       test2Socket = dfunc.OpenSocket(0);
-       if (test2Socket == -1)
-               return;
-
-       test2InProgress = true;
-       test2Driver = net_landriverlevel;
-
-       SZ_Clear(&net_message);
-       // save space for the header, filled in later
-       MSG_WriteLong(&net_message, 0);
-       MSG_WriteByte(&net_message, CCREQ_RULE_INFO);
-       MSG_WriteString(&net_message, "");
-       *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-       dfunc.Write (test2Socket, net_message.data, net_message.cursize, &sendaddr);
-       SZ_Clear(&net_message);
-       SchedulePollProcedure(&test2PollProcedure, 0.05);
-}
-*/
-
-int Datagram_Init (void)
-{
-       int i;
-       int csock;
-
-       myDriverLevel = net_driverlevel;
-       Cmd_AddCommand ("net_stats", NET_Stats_f);
-       Cvar_RegisterVariable (&cl_port);
-
-       if (COM_CheckParm("-nolan"))
-               return -1;
-
-       for (i = 0; i < net_numlandrivers; i++)
-               {
-               csock = net_landrivers[i].Init ();
-               if (csock == -1)
-                       continue;
-               net_landrivers[i].initialized = true;
-               net_landrivers[i].controlSock = csock;
-               }
-
-#ifdef BAN_TEST
-       Cmd_AddCommand ("ban", NET_Ban_f);
-#endif
-       //Cmd_AddCommand ("test", Test_f);
-       //Cmd_AddCommand ("test2", Test2_f);
-
-       return 0;
-}
-
-
-void Datagram_Shutdown (void)
-{
-       int i;
-
-//
-// shutdown the lan drivers
-//
-       for (i = 0; i < net_numlandrivers; i++)
-       {
-               if (net_landrivers[i].initialized)
-               {
-                       net_landrivers[i].Shutdown ();
-                       net_landrivers[i].initialized = false;
-               }
-       }
-}
-
-
-void Datagram_Close (qsocket_t *sock)
-{
-       sfunc.CloseSocket(sock->socket);
-}
-
-
-void Datagram_Listen (qboolean state)
-{
-       int i;
-
-       for (i = 0; i < net_numlandrivers; i++)
-               if (net_landrivers[i].initialized)
-                       net_landrivers[i].Listen (state);
-}
-
-
-static qsocket_t *_Datagram_CheckNewConnections (void)
-{
-       struct qsockaddr clientaddr;
-       struct qsockaddr newaddr;
-       int                     newsock;
-       int                     acceptsock;
-       qsocket_t       *sock;
-       qsocket_t       *s;
-       int                     len;
-       int                     command;
-       int                     control;
-       int                     ret;
-       int                     c;
-
-       acceptsock = dfunc.CheckNewConnections();
-       if (acceptsock == -1)
-               return NULL;
-
-       SZ_Clear(&net_message);
-
-       len = dfunc.Read (acceptsock, net_message.data, net_message.maxsize, &clientaddr);
-       if (len < (int)sizeof(int))
-               return NULL;
-       net_message.cursize = len;
-
-       MSG_BeginReading ();
-       control = BigLong(*((int *)net_message.data));
-       MSG_ReadLong();
-
-       // Messages starting by 0xFFFFFFFF are master server messages
-       if ((unsigned int)control == 0xFFFFFFFF)
-       {
-               int responsesize = Master_HandleMessage();
-               if (responsesize > 0)
-               {
-                       dfunc.Write(acceptsock, net_message.data, responsesize, &clientaddr);
-                       SZ_Clear(&net_message);
-               }
-               return NULL;
-       }
-       if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL)
-               return NULL;
-       if ((control & NETFLAG_LENGTH_MASK) != len)
-               return NULL;
-
-       command = MSG_ReadByte();
-       if (command == CCREQ_SERVER_INFO)
-       {
-               if (strcmp(MSG_ReadString(), "QUAKE") != 0)
-                       return NULL;
-
-               Con_DPrintf("Datagram_CheckNewConnections: received CCREQ_SERVERINFO, replying.\n");
-
-               SZ_Clear(&net_message);
-               // save space for the header, filled in later
-               MSG_WriteLong(&net_message, 0);
-               MSG_WriteByte(&net_message, CCREP_SERVER_INFO);
-               dfunc.GetSocketAddr(acceptsock, &newaddr);
-               MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr));
-               MSG_WriteString(&net_message, hostname.string);
-               MSG_WriteString(&net_message, sv.name);
-               MSG_WriteByte(&net_message, net_activeconnections);
-               MSG_WriteByte(&net_message, svs.maxclients);
-               MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
-               *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-               dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
-               SZ_Clear(&net_message);
-               return NULL;
-       }
-
-       if (command == CCREQ_PLAYER_INFO)
-       {
-               int                     playerNumber;
-               int                     activeNumber;
-               int                     clientNumber;
-               client_t        *client;
-
-               playerNumber = MSG_ReadByte();
-               activeNumber = -1;
-               for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++)
-               {
-                       if (client->active)
-                       {
-                               activeNumber++;
-                               if (activeNumber == playerNumber)
-                                       break;
-                       }
-               }
-               if (clientNumber == svs.maxclients)
-                       return NULL;
-
-               SZ_Clear(&net_message);
-               // save space for the header, filled in later
-               MSG_WriteLong(&net_message, 0);
-               MSG_WriteByte(&net_message, CCREP_PLAYER_INFO);
-               MSG_WriteByte(&net_message, playerNumber);
-               MSG_WriteString(&net_message, client->name);
-               MSG_WriteLong(&net_message, client->colors);
-               MSG_WriteLong(&net_message, (int)client->edict->v->frags);
-               MSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime));
-               MSG_WriteString(&net_message, client->netconnection->address);
-               *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-               dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
-               SZ_Clear(&net_message);
-
-               return NULL;
-       }
-
-       if (command == CCREQ_RULE_INFO)
-       {
-               char    *prevCvarName;
-               cvar_t  *var;
-
-               // find the search start location
-               prevCvarName = MSG_ReadString();
-               var = Cvar_FindVarAfter(prevCvarName, CVAR_NOTIFY);
-
-               // send the response
-
-               SZ_Clear(&net_message);
-               // save space for the header, filled in later
-               MSG_WriteLong(&net_message, 0);
-               MSG_WriteByte(&net_message, CCREP_RULE_INFO);
-               if (var)
-               {
-                       MSG_WriteString(&net_message, var->name);
-                       MSG_WriteString(&net_message, var->string);
-               }
-               *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-               dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
-               SZ_Clear(&net_message);
-
-               return NULL;
-       }
-
-       if (command != CCREQ_CONNECT)
-               return NULL;
-
-       if (strcmp(MSG_ReadString(), "QUAKE") != 0)
-               return NULL;
-
-       c = MSG_ReadByte();
-       if (c != NET_PROTOCOL_VERSION)
-       {
-               SZ_Clear(&net_message);
-               // save space for the header, filled in later
-               MSG_WriteLong(&net_message, 0);
-               MSG_WriteByte(&net_message, CCREP_REJECT);
-               MSG_WriteString(&net_message, "Incompatible version.\n");
-               *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-               dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
-               SZ_Clear(&net_message);
-               return NULL;
-       }
-
-#ifdef BAN_TEST
-       // check for a ban
-       if (clientaddr.sa_family == AF_INET)
-       {
-               unsigned long testAddr;
-               testAddr = ((struct sockaddr_in *)&clientaddr)->sin_addr.s_addr;
-               if ((testAddr & banMask) == banAddr)
-               {
-                       SZ_Clear(&net_message);
-                       // save space for the header, filled in later
-                       MSG_WriteLong(&net_message, 0);
-                       MSG_WriteByte(&net_message, CCREP_REJECT);
-                       MSG_WriteString(&net_message, "You have been banned.\n");
-                       *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-                       dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
-                       SZ_Clear(&net_message);
-                       return NULL;
-               }
-       }
-#endif
-
-       // see if this guy is already connected
-       for (s = net_activeSockets; s; s = s->next)
-       {
-               if (s->driver != net_driverlevel)
-                       continue;
-               ret = dfunc.AddrCompare(&clientaddr, &s->addr);
-               if (ret >= 0)
-               {
-                       // is this a duplicate connection request?
-                       if (ret == 0 && net_time - s->connecttime < 2.0)
-                       {
-                               // yes, so send a duplicate reply
-                               SZ_Clear(&net_message);
-                               // save space for the header, filled in later
-                               MSG_WriteLong(&net_message, 0);
-                               MSG_WriteByte(&net_message, CCREP_ACCEPT);
-                               dfunc.GetSocketAddr(s->socket, &newaddr);
-                               MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));
-                               *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-                               // LordHavoc: send from s->socket instead of acceptsock, this
-                               // way routers usually identify the connection correctly
-                               // (thanks to faded for provoking me to recite a lengthy
-                               // explanation of NAT nightmares, and realize this easy
-                               // workaround for quake)
-                               dfunc.Write (s->socket, net_message.data, net_message.cursize, &clientaddr);
-                               // LordHavoc: also send from acceptsock, for good measure
-                               dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
-                               SZ_Clear(&net_message);
-                               return NULL;
-                       }
-                       // it's somebody coming back in from a crash/disconnect
-                       // so close the old qsocket and let their retry get them back in
-                       NET_Close(s);
-                       return NULL;
-               }
-       }
-
-       // allocate a QSocket
-       sock = NET_NewQSocket ();
-       if (sock == NULL)
-       {
-               // no room; try to let him know
-               SZ_Clear(&net_message);
-               // save space for the header, filled in later
-               MSG_WriteLong(&net_message, 0);
-               MSG_WriteByte(&net_message, CCREP_REJECT);
-               MSG_WriteString(&net_message, "Server is full.\n");
-               *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-               dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
-               SZ_Clear(&net_message);
-               return NULL;
-       }
-
-       // allocate a network socket
-       newsock = dfunc.OpenSocket(0);
-       if (newsock == -1)
-       {
-               NET_FreeQSocket(sock);
-               return NULL;
-       }
-
-       // connect to the client
-       if (dfunc.Connect (newsock, &clientaddr) == -1)
-       {
-               dfunc.CloseSocket(newsock);
-               NET_FreeQSocket(sock);
-               return NULL;
-       }
-
-       // everything is allocated, just fill in the details
-       sock->socket = newsock;
-       sock->landriver = net_landriverlevel;
-       sock->addr = clientaddr;
-       strcpy(sock->address, dfunc.AddrToString(&clientaddr));
-
-       // send him back the info about the server connection he has been allocated
-       SZ_Clear(&net_message);
-       // save space for the header, filled in later
-       MSG_WriteLong(&net_message, 0);
-       MSG_WriteByte(&net_message, CCREP_ACCEPT);
-       dfunc.GetSocketAddr(newsock, &newaddr);
-       MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));
-       *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-       // LordHavoc: send from sock->socket instead of acceptsock, this way routers
-       // usually identify the connection correctly (thanks to faded for provoking
-       // me to recite a lengthy explanation of NAT nightmares, and realize this
-       // easy workaround for quake)
-       dfunc.Write (sock->socket, net_message.data, net_message.cursize, &clientaddr);
-       // LordHavoc: also send from acceptsock, for good measure
-       dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
-       SZ_Clear(&net_message);
-
-       return sock;
-}
-
-qsocket_t *Datagram_CheckNewConnections (void)
-{
-       qsocket_t *ret = NULL;
-
-       for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
-               if (net_landrivers[net_landriverlevel].initialized)
-                       if ((ret = _Datagram_CheckNewConnections ()) != NULL)
-                               break;
-       return ret;
-}
-
-
-static qboolean Datagram_HandleServerInfo (struct qsockaddr *readaddr)
-{
-       //struct qsockaddr myaddr;
-       int control;
-       int c, n;
-       char cname[256];
-
-       if (net_message.cursize < (int)sizeof(int))
-               return false;
-
-       // don't answer our own query
-       //dfunc.GetSocketAddr (dfunc.controlSock, &myaddr);
-       //if (dfunc.AddrCompare(readaddr, &myaddr) >= 0)
-       //      return false;
-
-       // is the cache full?
-       if (hostCacheCount == HOSTCACHESIZE)
-               return false;
-
-       MSG_BeginReading ();
-       control = BigLong(*((int *)net_message.data));
-       MSG_ReadLong();
-       if (control == -1)
-               return false;
-       if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL)
-               return false;
-       if ((control & NETFLAG_LENGTH_MASK) != net_message.cursize)
-               return false;
-
-       c = MSG_ReadByte();
-       if (c != CCREP_SERVER_INFO)
-               return false;
-
-       // LordHavoc: because the UDP driver reports 0.0.0.0:26000 as the address
-       // string we just ignore it and keep the real address
-       MSG_ReadString();
-       // hostcache only uses text addresses
-       strcpy(cname, dfunc.AddrToString(readaddr));
-       // search the cache for this server
-       for (n = 0; n < hostCacheCount; n++)
-               //if (dfunc.AddrCompare(readaddr, &hostcache[n].addr) == 0)
-               if (!strcmp(cname, hostcache[n].cname))
-                       return false;
-
-       // add it
-       hostCacheCount++;
-       strcpy(hostcache[n].name, MSG_ReadString());
-       strcpy(hostcache[n].map, MSG_ReadString());
-       hostcache[n].users = MSG_ReadByte();
-       hostcache[n].maxusers = MSG_ReadByte();
-       c = MSG_ReadByte();
-       if (c != NET_PROTOCOL_VERSION)
-       {
-               strncpy(hostcache[n].cname, hostcache[n].name, sizeof(hostcache[n].cname) - 1);
-               hostcache[n].cname[sizeof(hostcache[n].cname) - 1] = 0;
-               strcpy(hostcache[n].name, "*");
-               strncat(hostcache[n].name, hostcache[n].cname, sizeof(hostcache[n].name) - 1);
-               hostcache[n].name[sizeof(hostcache[n].name) - 1] = 0;
-       }
-       strcpy(hostcache[n].cname, cname);
-       //memcpy(&hostcache[n].addr, readaddr, sizeof(struct qsockaddr));
-       //hostcache[n].driver = net_driverlevel;
-       //hostcache[n].ldriver = net_landriverlevel;
-
-       /*
-       // check for a name conflict
-       for (i = 0; i < hostCacheCount; i++)
-       {
-               if (i == n)
-                       continue;
-               if (strcasecmp (hostcache[n].name, hostcache[i].name) == 0)
-               {
-                       i = strlen(hostcache[n].name);
-                       if (i < 15 && hostcache[n].name[i-1] > '8')
-                       {
-                               hostcache[n].name[i] = '0';
-                               hostcache[n].name[i+1] = 0;
-                       }
-                       else
-                               hostcache[n].name[i-1]++;
-                       i = -1;
-               }
-       }
-       */
-
-       return true;
-}
-
-
-static void _Datagram_SearchForHosts (qboolean xmit)
-{
-       int             ret;
-       struct qsockaddr readaddr;
-
-       if (xmit)
-       {
-               SZ_Clear(&net_message);
-               // save space for the header, filled in later
-               MSG_WriteLong(&net_message, 0);
-               MSG_WriteByte(&net_message, CCREQ_SERVER_INFO);
-               MSG_WriteString(&net_message, "QUAKE");
-               MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
-               *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-               dfunc.Broadcast(dfunc.controlSock, net_message.data, net_message.cursize);
-               SZ_Clear(&net_message);
-       }
-
-       while ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0)
-       {
-               net_message.cursize = ret;
-               Datagram_HandleServerInfo (&readaddr);
-       }
-}
-
-void Datagram_SearchForHosts (qboolean xmit)
-{
-       for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
-       {
-               if (hostCacheCount == HOSTCACHESIZE)
-                       break;
-               if (net_landrivers[net_landriverlevel].initialized)
-                       _Datagram_SearchForHosts (xmit);
-       }
-}
-
-
-static qboolean _Datagram_SearchForInetHosts (const char *master)
-{
-       qboolean result = false;
-       struct qsockaddr masteraddr;
-       struct qsockaddr readaddr;
-       int ret;
-
-       if (master)
-       {
-               if (dfunc.GetAddrFromName(master, &masteraddr) != -1)
-               {
-                       int portnum = 0;
-                       const char* port = strrchr (master, ':');
-                       if (port)
-                               portnum = atoi (port + 1);
-                       if (!portnum)
-                               portnum = MASTER_PORT;
-                       Con_DPrintf("Datagram_SearchForInetHosts: sending %d byte message to master %s port %i\n", net_message.cursize, master, portnum);
-                       dfunc.SetSocketPort (&masteraddr, portnum);
-                       dfunc.Write (dfunc.controlSock, net_message.data, net_message.cursize, &masteraddr);
-               }
-       }
-
-       while ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0)
-       {
-               net_message.cursize = ret;
-               Con_DPrintf("Datagram_SearchForInetHosts: Read received %d byte message\n", net_message.cursize);
-               if (Datagram_HandleServerInfo (&readaddr))
-                       result = true;
-               else
-                       Master_ParseServerList (&dfunc);
-       }
-
-       return result;
-}
-
-
-qboolean Datagram_SearchForInetHosts (const char *master)
-{
-       qboolean result = false;
-       for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
-       {
-               if (hostCacheCount == HOSTCACHESIZE)
-                       break;
-               if (net_landrivers[net_landriverlevel].initialized)
-                       if (_Datagram_SearchForInetHosts (master))
-                               result = true;
-       }
-
-       return result;
-}
-
-
-static qsocket_t *_Datagram_Connect (const char *host)
-{
-       struct qsockaddr sendaddr;
-       struct qsockaddr readaddr;
-       qsocket_t       *sock;
-       int                     newsock;
-       int                     ret;
-       int                     reps;
-       double          start_time;
-       int                     control;
-       char            *reason;
-
-       // see if we can resolve the host name
-       if (dfunc.GetAddrFromName(host, &sendaddr) == -1)
-               return NULL;
-
-       newsock = dfunc.OpenSocket (cl_port.integer);
-       if (newsock == -1)
-               return NULL;
-
-       sock = NET_NewQSocket ();
-       if (sock == NULL)
-               goto ErrorReturn2;
-       sock->socket = newsock;
-       sock->landriver = net_landriverlevel;
-
-       // connect to the host
-       if (dfunc.Connect (newsock, &sendaddr) == -1)
-               goto ErrorReturn;
-
-       // send the connection request
-       Con_Printf("trying...\n");CL_UpdateScreen();CL_UpdateScreen();
-       start_time = net_time;
-
-       for (reps = 0; reps < 3; reps++)
-       {
-               SZ_Clear(&net_message);
-               // save space for the header, filled in later
-               MSG_WriteLong(&net_message, 0);
-               MSG_WriteByte(&net_message, CCREQ_CONNECT);
-               MSG_WriteString(&net_message, "QUAKE");
-               MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
-               *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-               dfunc.Write (newsock, net_message.data, net_message.cursize, &sendaddr);
-               SZ_Clear(&net_message);
-               do
-               {
-                       ret = dfunc.Read (newsock, net_message.data, net_message.maxsize, &readaddr);
-                       // if we got something, validate it
-                       if (ret > 0)
-                       {
-                               // is it from the right place?
-                               // we don't care if the port matches (this adds support for
-                               // the NAT fix in the server inspired by faded)
-                               if (sfunc.AddrCompare(&readaddr, &sendaddr) < 0)
-                               {
-                                       char tempaddress1[64], tempaddress2[64];
-                                       dfunc.GetNameFromAddr (&sendaddr, tempaddress1);
-                                       dfunc.GetNameFromAddr (&readaddr, tempaddress2);
-                                       Con_Printf("wrong reply address (Expected: %s Received: %s)\n", tempaddress1, tempaddress2);
-                                       CL_UpdateScreen ();
-                                       CL_UpdateScreen ();
-                                       ret = 0;
-                                       continue;
-                               }
-
-                               if (ret < (int)sizeof(int))
-                               {
-                                       ret = 0;
-                                       continue;
-                               }
-
-                               net_message.cursize = ret;
-                               MSG_BeginReading ();
-
-                               control = BigLong(*((int *)net_message.data));
-                               MSG_ReadLong();
-                               if (control == -1)
-                               {
-                                       ret = 0;
-                                       continue;
-                               }
-                               if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL)
-                               {
-                                       ret = 0;
-                                       continue;
-                               }
-                               if ((control & NETFLAG_LENGTH_MASK) != ret)
-                               {
-                                       ret = 0;
-                                       continue;
-                               }
-                       }
-               }
-               while (ret == 0 && (SetNetTime() - start_time) < 2.5);
-               if (ret)
-                       break;
-               Con_Printf("still trying...\n");CL_UpdateScreen();CL_UpdateScreen();
-               start_time = SetNetTime();
-       }
-
-       if (ret == 0)
-       {
-               reason = "No Response";
-               Con_Printf("%s\n", reason);
-               strcpy(m_return_reason, reason);
-               goto ErrorReturn;
-       }
-
-       if (ret == -1)
-       {
-               reason = "Network Error";
-               Con_Printf("%s\n", reason);
-               strcpy(m_return_reason, reason);
-               goto ErrorReturn;
-       }
-
-       ret = MSG_ReadByte();
-       if (ret == CCREP_REJECT)
-       {
-               reason = MSG_ReadString();
-               Con_Printf("%s", reason);
-               strncpy(m_return_reason, reason, 31);
-               goto ErrorReturn;
-       }
-
-       if (ret == CCREP_ACCEPT)
-       {
-               memcpy(&sock->addr, &sendaddr, sizeof(struct qsockaddr));
-               dfunc.SetSocketPort (&sock->addr, MSG_ReadLong());
-       }
-       else
-       {
-               reason = "Bad Response";
-               Con_Printf("%s\n", reason);
-               strcpy(m_return_reason, reason);
-               goto ErrorReturn;
-       }
-
-       dfunc.GetNameFromAddr (&sendaddr, sock->address);
-
-       Con_Printf ("Connection accepted to %s\n", sock->address);
-       sock->lastMessageTime = SetNetTime();
-
-       // switch the connection to the specified address
-       if (dfunc.Connect (newsock, &sock->addr) == -1)
-       {
-               reason = "Connect to Game failed";
-               Con_Printf("%s\n", reason);
-               strcpy(m_return_reason, reason);
-               goto ErrorReturn;
-       }
-
-       m_return_onerror = false;
-       return sock;
-
-ErrorReturn:
-       NET_FreeQSocket(sock);
-ErrorReturn2:
-       dfunc.CloseSocket(newsock);
-       if (m_return_onerror)
-       {
-               key_dest = key_menu;
-               m_state = m_return_state;
-               m_return_onerror = false;
-       }
-       return NULL;
-}
-
-qsocket_t *Datagram_Connect (const char *host)
-{
-       qsocket_t *ret = NULL;
-
-       for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
-               if (net_landrivers[net_landriverlevel].initialized)
-                       if ((ret = _Datagram_Connect (host)) != NULL)
-                               break;
-       return ret;
-}
-
-static void _Datagram_Heartbeat (const char *master)
-{
-       struct qsockaddr masteraddr;
-       int portnum;
-       const char* port;
-
-       if (dfunc.GetAddrFromName(master, &masteraddr) == -1)
-               return;
-
-       portnum = 0;
-       port = strrchr (master, ':');
-       if (port)
-               portnum = atoi (port + 1);
-       if (!portnum)
-               portnum = MASTER_PORT;
-       dfunc.SetSocketPort (&masteraddr, portnum);
-
-       // FIXME: this is the only use of UDP_Send in the entire engine, add a dfunc.acceptSock to get rid of this function!
-       dfunc.Send (net_message.data, net_message.cursize, &masteraddr);
-}
-
-void Datagram_Heartbeat (const char *master)
-{
-       for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
-               if (net_landrivers[net_landriverlevel].initialized)
-                       _Datagram_Heartbeat (master);
-}