]> de.git.xonotic.org Git - voretournament/voretournament.git/blobdiff - misc/source/darkplaces-src/netconn.c
Update the engine
[voretournament/voretournament.git] / misc / source / darkplaces-src / netconn.c
index 65b64830067da60339105a1a36e91d4cacd5cd98..c5858c807155edf82ede94d42a7ec2768bf6e91b 100644 (file)
@@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 
 #include "quakedef.h"
+#include "thread.h"
 #include "lhnet.h"
 
 // for secure rcon authentication
@@ -62,14 +63,18 @@ static cvar_t sv_qwmasters [] =
        {0, "sv_qwmasterextra2", "asgaard.morphos-team.net:27000", "Global master server. (admin: unknown)"},
        {0, "sv_qwmasterextra3", "qwmaster.ocrana.de:27000", "German master server. (admin: unknown)"},
        {0, "sv_qwmasterextra4", "masterserver.exhale.de:27000", "German master server. (admin: unknown)"},
-       {0, "sv_qwmasterextra5", "kubus.rulez.pl:27000", "Poland master server. (admin: unknown)"},
+       {0, "sv_qwmasterextra5", "qwmaster.fodquake.net:27000", "Global master server. (admin: unknown)"},
        {0, NULL, NULL, NULL}
 };
 
 static double nextheartbeattime = 0;
 
-sizebuf_t net_message;
-static unsigned char net_message_buf[NET_MAXMESSAGE];
+sizebuf_t cl_message;
+sizebuf_t sv_message;
+static unsigned char cl_message_buf[NET_MAXMESSAGE];
+static unsigned char sv_message_buf[NET_MAXMESSAGE];
+char cl_readstring[MAX_INPUTLINE];
+char sv_readstring[MAX_INPUTLINE];
 
 cvar_t net_messagetimeout = {0, "net_messagetimeout","300", "drops players who have not sent any packets for this many seconds"};
 cvar_t net_connecttimeout = {0, "net_connecttimeout","15", "after requesting a connection, the client must reply within this many seconds or be dropped (cuts down on connect floods). Must be above 10 seconds."};
@@ -95,18 +100,6 @@ static cvar_t rcon_secure_maxdiff = {0, "rcon_secure_maxdiff", "5", "maximum tim
 extern cvar_t rcon_secure;
 extern cvar_t rcon_secure_challengetimeout;
 
-/* statistic counters */
-static int packetsSent = 0;
-static int packetsReSent = 0;
-static int packetsReceived = 0;
-static int receivedDuplicateCount = 0;
-static int droppedDatagrams = 0;
-
-static int unreliableMessagesSent = 0;
-static int unreliableMessagesReceived = 0;
-static int reliableMessagesSent = 0;
-static int reliableMessagesReceived = 0;
-
 double masterquerytime = -1000;
 int masterquerycount = 0;
 int masterreplycount = 0;
@@ -123,11 +116,6 @@ static qboolean serverlist_paused = false;
 /// flooding in (which would make a mess of the ping times)
 static double serverlist_querywaittime = 0;
 
-static unsigned char sendbuffer[NET_HEADERSIZE+NET_MAXMESSAGE];
-static unsigned char readbuffer[NET_HEADERSIZE+NET_MAXMESSAGE];
-static unsigned char cryptosendbuffer[NET_HEADERSIZE+NET_MAXMESSAGE+CRYPTO_HEADERSIZE];
-static unsigned char cryptoreadbuffer[NET_HEADERSIZE+NET_MAXMESSAGE+CRYPTO_HEADERSIZE];
-
 static int cl_numsockets;
 static lhnetsocket_t *cl_sockets[16];
 static int sv_numsockets;
@@ -135,6 +123,7 @@ static lhnetsocket_t *sv_sockets[16];
 
 netconn_t *netconn_list = NULL;
 mempool_t *netconn_mempool = NULL;
+void *netconn_mutex = NULL;
 
 cvar_t cl_netport = {0, "cl_port", "0", "forces client to use chosen port number if not 0"};
 cvar_t sv_netport = {0, "port", "26000", "server port for players to connect to"};
@@ -413,8 +402,8 @@ static void ServerList_ViewList_Insert( serverlist_entry_t *entry )
                !(
                           gameversion_min.integer >= 0 // min/max range set by user/mod?
                        && gameversion_max.integer >= 0
-                       && gameversion_min.integer >= entry->info.gameversion // version of server in min/max range?
-                       && gameversion_max.integer <= entry->info.gameversion
+                       && gameversion_min.integer <= entry->info.gameversion // version of server in min/max range?
+                       && gameversion_max.integer >= entry->info.gameversion
                 )
        )
                return;
@@ -597,8 +586,13 @@ void ServerList_QueryList(qboolean resetcache, qboolean querydp, qboolean queryq
 
 int NetConn_Read(lhnetsocket_t *mysocket, void *data, int maxlength, lhnetaddress_t *peeraddress)
 {
-       int length = LHNET_Read(mysocket, data, maxlength, peeraddress);
+       int length;
        int i;
+       if (mysocket->address.addresstype == LHNETADDRESSTYPE_LOOP && netconn_mutex)
+               Thread_LockMutex(netconn_mutex);
+       length = LHNET_Read(mysocket, data, maxlength, peeraddress);
+       if (mysocket->address.addresstype == LHNETADDRESSTYPE_LOOP && netconn_mutex)
+               Thread_UnlockMutex(netconn_mutex);
        if (length == 0)
                return 0;
        if (cl_netpacketloss_receive.integer)
@@ -629,7 +623,11 @@ int NetConn_Write(lhnetsocket_t *mysocket, const void *data, int length, const l
                for (i = 0;i < cl_numsockets;i++)
                        if (cl_sockets[i] == mysocket && (rand() % 100) < cl_netpacketloss_send.integer)
                                return length;
+       if (mysocket->address.addresstype == LHNETADDRESSTYPE_LOOP && netconn_mutex)
+               Thread_LockMutex(netconn_mutex);
        ret = LHNET_Write(mysocket, data, length, peeraddress);
+       if (mysocket->address.addresstype == LHNETADDRESSTYPE_LOOP && netconn_mutex)
+               Thread_UnlockMutex(netconn_mutex);
        if (developer_networking.integer)
        {
                char addressstring[128], addressstring2[128];
@@ -666,6 +664,8 @@ qboolean NetConn_CanSend(netconn_t *conn)
 int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolversion_t protocol, int rate, qboolean quakesignon_suppressreliables)
 {
        int totallen = 0;
+       unsigned char sendbuffer[NET_HEADERSIZE+NET_MAXMESSAGE];
+       unsigned char cryptosendbuffer[NET_HEADERSIZE+NET_MAXMESSAGE+CRYPTO_HEADERSIZE];
 
        // if this packet was supposedly choked, but we find ourselves sending one
        // anyway, make sure the size counting starts at zero
@@ -735,8 +735,8 @@ int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolvers
 
                NetConn_Write(conn->mysocket, (void *)&sendbuffer, packetLen, &conn->peeraddress);
 
-               packetsSent++;
-               unreliableMessagesSent++;
+               conn->packetsSent++;
+               conn->unreliableMessagesSent++;
 
                totallen += packetLen + 28;
        }
@@ -774,7 +774,7 @@ int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolvers
                        if (sendme && NetConn_Write(conn->mysocket, sendme, sendmelen, &conn->peeraddress) == (int)sendmelen)
                        {
                                conn->lastSendTime = realtime;
-                               packetsReSent++;
+                               conn->packetsReSent++;
                        }
 
                        totallen += sendmelen + 28;
@@ -826,8 +826,8 @@ int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolvers
                                NetConn_Write(conn->mysocket, sendme, sendmelen, &conn->peeraddress);
 
                        conn->lastSendTime = realtime;
-                       packetsSent++;
-                       reliableMessagesSent++;
+                       conn->packetsSent++;
+                       conn->reliableMessagesSent++;
 
                        totallen += sendmelen + 28;
                }
@@ -855,8 +855,8 @@ int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolvers
                        if(sendme)
                                NetConn_Write(conn->mysocket, sendme, sendmelen, &conn->peeraddress);
 
-                       packetsSent++;
-                       unreliableMessagesSent++;
+                       conn->packetsSent++;
+                       conn->unreliableMessagesSent++;
 
                        totallen += sendmelen + 28;
                }
@@ -889,7 +889,7 @@ void NetConn_CloseClientPorts(void)
                        LHNET_CloseSocket(cl_sockets[cl_numsockets - 1]);
 }
 
-void NetConn_OpenClientPort(const char *addressstring, lhnetaddresstype_t addresstype, int defaultport)
+static void NetConn_OpenClientPort(const char *addressstring, lhnetaddresstype_t addresstype, int defaultport)
 {
        lhnetaddress_t address;
        lhnetsocket_t *s;
@@ -922,6 +922,11 @@ void NetConn_OpenClientPorts(void)
 {
        int port;
        NetConn_CloseClientPorts();
+
+       SV_LockThreadMutex(); // FIXME recursive?
+       Crypto_LoadKeys(); // client sockets
+       SV_UnlockThreadMutex();
+
        port = bound(0, cl_netport.integer, 65535);
        if (cl_netport.integer != port)
                Cvar_SetValueQuick(&cl_netport, port);
@@ -943,7 +948,7 @@ void NetConn_CloseServerPorts(void)
                        LHNET_CloseSocket(sv_sockets[sv_numsockets - 1]);
 }
 
-qboolean NetConn_OpenServerPort(const char *addressstring, lhnetaddresstype_t addresstype, int defaultport, int range)
+static qboolean NetConn_OpenServerPort(const char *addressstring, lhnetaddresstype_t addresstype, int defaultport, int range)
 {
        lhnetaddress_t address;
        lhnetsocket_t *s;
@@ -987,6 +992,11 @@ void NetConn_OpenServerPorts(int opennetports)
 {
        int port;
        NetConn_CloseServerPorts();
+
+       SV_LockThreadMutex(); // FIXME recursive?
+       Crypto_LoadKeys(); // server sockets
+       SV_UnlockThreadMutex();
+
        NetConn_UpdateSockets();
        port = bound(0, sv_netport.integer, 65535);
        if (port == 0)
@@ -1127,6 +1137,9 @@ void NetConn_UpdateSockets(void)
 static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, size_t length, protocolversion_t protocol, double newtimeout)
 {
        int originallength = length;
+       unsigned char sendbuffer[NET_HEADERSIZE+NET_MAXMESSAGE];
+       unsigned char cryptosendbuffer[NET_HEADERSIZE+NET_MAXMESSAGE+CRYPTO_HEADERSIZE];
+       unsigned char cryptoreadbuffer[NET_HEADERSIZE+NET_MAXMESSAGE+CRYPTO_HEADERSIZE];
        if (length < 8)
                return 0;
 
@@ -1153,7 +1166,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                        length -= 2;
                }
 
-               packetsReceived++;
+               conn->packetsReceived++;
                reliable_message = (sequence >> 31) & 1;
                reliable_ack = (sequence_ack >> 31) & 1;
                sequence &= ~(1<<31);
@@ -1166,7 +1179,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                count = sequence - (conn->qw.incoming_sequence + 1);
                if (count > 0)
                {
-                       droppedDatagrams += count;
+                       conn->droppedDatagrams += count;
                        //Con_DPrintf("Dropped %u datagram(s)\n", count);
                        while (count--)
                        {
@@ -1186,7 +1199,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                {
                        // received, now we will be able to send another reliable message
                        conn->sendMessageLength = 0;
-                       reliableMessagesReceived++;
+                       conn->reliableMessagesReceived++;
                }
                conn->qw.incoming_sequence = sequence;
                if (conn == cls.netcon)
@@ -1197,10 +1210,19 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                        conn->qw.incoming_reliable_sequence ^= 1;
                conn->lastMessageTime = realtime;
                conn->timeout = realtime + newtimeout;
-               unreliableMessagesReceived++;
-               SZ_Clear(&net_message);
-               SZ_Write(&net_message, data, length);
-               MSG_BeginReading();
+               conn->unreliableMessagesReceived++;
+               if (conn == cls.netcon)
+               {
+                       SZ_Clear(&cl_message);
+                       SZ_Write(&cl_message, data, length);
+                       MSG_BeginReading(&cl_message);
+               }
+               else
+               {
+                       SZ_Clear(&sv_message);
+                       SZ_Write(&sv_message, data, length);
+                       MSG_BeginReading(&sv_message);
+               }
                return 2;
        }
        else
@@ -1226,7 +1248,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                if (!(flags & NETFLAG_CTL) && qlength == length)
                {
                        sequence = BuffBigLong(data + 4);
-                       packetsReceived++;
+                       conn->packetsReceived++;
                        data += 8;
                        length -= 8;
                        if (flags & NETFLAG_UNRELIABLE)
@@ -1236,7 +1258,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                                        if (sequence > conn->nq.unreliableReceiveSequence)
                                        {
                                                count = sequence - conn->nq.unreliableReceiveSequence;
-                                               droppedDatagrams += count;
+                                               conn->droppedDatagrams += count;
                                                //Con_DPrintf("Dropped %u datagram(s)\n", count);
                                                while (count--)
                                                {
@@ -1255,12 +1277,21 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                                        conn->nq.unreliableReceiveSequence = sequence + 1;
                                        conn->lastMessageTime = realtime;
                                        conn->timeout = realtime + newtimeout;
-                                       unreliableMessagesReceived++;
+                                       conn->unreliableMessagesReceived++;
                                        if (length > 0)
                                        {
-                                               SZ_Clear(&net_message);
-                                               SZ_Write(&net_message, data, length);
-                                               MSG_BeginReading();
+                                               if (conn == cls.netcon)
+                                               {
+                                                       SZ_Clear(&cl_message);
+                                                       SZ_Write(&cl_message, data, length);
+                                                       MSG_BeginReading(&cl_message);
+                                               }
+                                               else
+                                               {
+                                                       SZ_Clear(&sv_message);
+                                                       SZ_Write(&sv_message, data, length);
+                                                       MSG_BeginReading(&sv_message);
+                                               }
                                                return 2;
                                        }
                                }
@@ -1312,7 +1343,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                                                        if (sendme && NetConn_Write(conn->mysocket, sendme, sendmelen, &conn->peeraddress) == (int)sendmelen)
                                                        {
                                                                conn->lastSendTime = realtime;
-                                                               packetsSent++;
+                                                               conn->packetsSent++;
                                                        }
                                                }
                                                else
@@ -1351,20 +1382,29 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                                        }
                                        if (flags & NETFLAG_EOM)
                                        {
-                                               reliableMessagesReceived++;
+                                               conn->reliableMessagesReceived++;
                                                length = conn->receiveMessageLength;
                                                conn->receiveMessageLength = 0;
                                                if (length > 0)
                                                {
-                                                       SZ_Clear(&net_message);
-                                                       SZ_Write(&net_message, conn->receiveMessage, length);
-                                                       MSG_BeginReading();
+                                                       if (conn == cls.netcon)
+                                                       {
+                                                               SZ_Clear(&cl_message);
+                                                               SZ_Write(&cl_message, conn->receiveMessage, length);
+                                                               MSG_BeginReading(&cl_message);
+                                                       }
+                                                       else
+                                                       {
+                                                               SZ_Clear(&sv_message);
+                                                               SZ_Write(&sv_message, conn->receiveMessage, length);
+                                                               MSG_BeginReading(&sv_message);
+                                                       }
                                                        return 2;
                                                }
                                        }
                                }
                                else
-                                       receivedDuplicateCount++;
+                                       conn->receivedDuplicateCount++;
                                return 1;
                        }
                }
@@ -1372,7 +1412,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
        return 0;
 }
 
-void NetConn_ConnectionEstablished(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress, protocolversion_t initialprotocol)
+static void NetConn_ConnectionEstablished(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress, protocolversion_t initialprotocol)
 {
        crypto_t *crypto;
        cls.connect_trying = false;
@@ -1381,7 +1421,11 @@ void NetConn_ConnectionEstablished(lhnetsocket_t *mysocket, lhnetaddress_t *peer
        CL_Disconnect();
        // if we're connecting to a remote server, shut down any local server
        if (LHNETADDRESS_GetAddressType(peeraddress) != LHNETADDRESSTYPE_LOOP && sv.active)
+       {
+               SV_LockThreadMutex();
                Host_ShutdownServer ();
+               SV_UnlockThreadMutex();
+       }
        // allocate a net connection to keep track of things
        cls.netcon = NetConn_Open(mysocket, peeraddress);
        crypto = &cls.crypto;
@@ -1498,8 +1542,8 @@ static void NetConn_ClientParsePacket_ServerList_UpdateCache(int n)
                         !(
                                    gameversion_min.integer >= 0 // min/max range set by user/mod?
                                 && gameversion_max.integer >= 0
-                                && gameversion_min.integer >= info->gameversion // version of server in min/max range?
-                                && gameversion_max.integer <= info->gameversion
+                                && gameversion_min.integer <= info->gameversion // version of server in min/max range?
+                                && gameversion_max.integer >= info->gameversion
                          )
                        ) ? '1' : '4',
                        info->mod, info->map);
@@ -1592,10 +1636,11 @@ static void NetConn_ClientParsePacket_ServerList_ParseDPList(lhnetaddress_t *sen
                        {
 #ifdef WHY_JUST_WHY
                                const char *ifname;
+                               char ifnamebuf[16];
 
                                /// \TODO: make some basic checks of the IP address (broadcast, ...)
 
-                               ifname = LHNETADDRESS_GetInterfaceName(senderaddress);
+                               ifname = LHNETADDRESS_GetInterfaceName(senderaddress, ifnamebuf, sizeof(ifnamebuf));
                                if (ifname != NULL)
                                {
                                        dpsnprintf (ipstring, sizeof (ipstring), "[%x:%x:%x:%x:%x:%x:%x:%x%%%s]:%hu",
@@ -1646,6 +1691,8 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
        char stringbuf[16384];
        char senddata[NET_HEADERSIZE+NET_MAXMESSAGE+CRYPTO_HEADERSIZE];
        size_t sendlength;
+       char infostringvalue[MAX_INPUTLINE];
+       char vabuf[1024];
 
        // quakeworld ingame packet
        fromserver = cls.netcon && mysocket == cls.netcon->mysocket && !LHNETADDRESS_Compare(&cls.netcon->peeraddress, peeraddress);
@@ -1758,7 +1805,7 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        // update the server IP in the userinfo (QW servers expect this, and it is used by the reconnect command)
                        InfoString_SetValue(cls.userinfo, sizeof(cls.userinfo), "*ip", addressstring2);
                        // TODO: add userinfo stuff here instead of using NQ commands?
-                       NetConn_WriteString(mysocket, va("\377\377\377\377connect\\protocol\\darkplaces 3\\protocols\\%s%s\\challenge\\%s", protocolnames, cls.connect_userinfo, string + 10), peeraddress);
+                       NetConn_WriteString(mysocket, va(vabuf, sizeof(vabuf), "\377\377\377\377connect\\protocol\\darkplaces 3\\protocols\\%s%s\\challenge\\%s", protocolnames, cls.connect_userinfo, string + 10), peeraddress);
                        return true;
                }
                if (length == 6 && !memcmp(string, "accept", 6) && cls.connect_trying)
@@ -1813,17 +1860,17 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        else
                                Con_Printf("statusResponse without players block?\n");
 
-                       if ((s = SearchInfostring(string, "gamename"     )) != NULL) strlcpy(info->game, s, sizeof (info->game));
-                       if ((s = SearchInfostring(string, "modname"      )) != NULL) strlcpy(info->mod , s, sizeof (info->mod ));
-                       if ((s = SearchInfostring(string, "mapname"      )) != NULL) strlcpy(info->map , s, sizeof (info->map ));
-                       if ((s = SearchInfostring(string, "hostname"     )) != NULL) strlcpy(info->name, s, sizeof (info->name));
-                       if ((s = SearchInfostring(string, "protocol"     )) != NULL) info->protocol = atoi(s);
-                       if ((s = SearchInfostring(string, "clients"      )) != NULL) info->numplayers = atoi(s);
-                       if ((s = SearchInfostring(string, "bots"         )) != NULL) info->numbots = atoi(s);
-                       if ((s = SearchInfostring(string, "sv_maxclients")) != NULL) info->maxplayers = atoi(s);
-                       if ((s = SearchInfostring(string, "gameversion"  )) != NULL) info->gameversion = atoi(s);
-                       if ((s = SearchInfostring(string, "qcstatus"     )) != NULL) strlcpy(info->qcstatus, s, sizeof(info->qcstatus));
-                       if (p                                               != NULL) strlcpy(info->players, p, sizeof(info->players));
+                       if ((s = InfoString_GetValue(string, "gamename"     , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->game, s, sizeof (info->game));
+                       if ((s = InfoString_GetValue(string, "modname"      , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->mod , s, sizeof (info->mod ));
+                       if ((s = InfoString_GetValue(string, "mapname"      , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->map , s, sizeof (info->map ));
+                       if ((s = InfoString_GetValue(string, "hostname"     , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->name, s, sizeof (info->name));
+                       if ((s = InfoString_GetValue(string, "protocol"     , infostringvalue, sizeof(infostringvalue))) != NULL) info->protocol = atoi(s);
+                       if ((s = InfoString_GetValue(string, "clients"      , infostringvalue, sizeof(infostringvalue))) != NULL) info->numplayers = atoi(s);
+                       if ((s = InfoString_GetValue(string, "bots"         , infostringvalue, sizeof(infostringvalue))) != NULL) info->numbots = atoi(s);
+                       if ((s = InfoString_GetValue(string, "sv_maxclients", infostringvalue, sizeof(infostringvalue))) != NULL) info->maxplayers = atoi(s);
+                       if ((s = InfoString_GetValue(string, "gameversion"  , infostringvalue, sizeof(infostringvalue))) != NULL) info->gameversion = atoi(s);
+                       if ((s = InfoString_GetValue(string, "qcstatus"     , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->qcstatus, s, sizeof(info->qcstatus));
+                       if (p                                                                                         != NULL) strlcpy(info->players, p, sizeof(info->players));
                        info->numhumans = info->numplayers - max(0, info->numbots);
                        info->freeslots = info->maxplayers - info->numplayers;
 
@@ -1855,16 +1902,16 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        info->maxplayers  = 0;
                        info->gameversion = 0;
 
-                       if ((s = SearchInfostring(string, "gamename"     )) != NULL) strlcpy(info->game, s, sizeof (info->game));
-                       if ((s = SearchInfostring(string, "modname"      )) != NULL) strlcpy(info->mod , s, sizeof (info->mod ));
-                       if ((s = SearchInfostring(string, "mapname"      )) != NULL) strlcpy(info->map , s, sizeof (info->map ));
-                       if ((s = SearchInfostring(string, "hostname"     )) != NULL) strlcpy(info->name, s, sizeof (info->name));
-                       if ((s = SearchInfostring(string, "protocol"     )) != NULL) info->protocol = atoi(s);
-                       if ((s = SearchInfostring(string, "clients"      )) != NULL) info->numplayers = atoi(s);
-                       if ((s = SearchInfostring(string, "bots"         )) != NULL) info->numbots = atoi(s);
-                       if ((s = SearchInfostring(string, "sv_maxclients")) != NULL) info->maxplayers = atoi(s);
-                       if ((s = SearchInfostring(string, "gameversion"  )) != NULL) info->gameversion = atoi(s);
-                       if ((s = SearchInfostring(string, "qcstatus"     )) != NULL) strlcpy(info->qcstatus, s, sizeof(info->qcstatus));
+                       if ((s = InfoString_GetValue(string, "gamename"     , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->game, s, sizeof (info->game));
+                       if ((s = InfoString_GetValue(string, "modname"      , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->mod , s, sizeof (info->mod ));
+                       if ((s = InfoString_GetValue(string, "mapname"      , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->map , s, sizeof (info->map ));
+                       if ((s = InfoString_GetValue(string, "hostname"     , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->name, s, sizeof (info->name));
+                       if ((s = InfoString_GetValue(string, "protocol"     , infostringvalue, sizeof(infostringvalue))) != NULL) info->protocol = atoi(s);
+                       if ((s = InfoString_GetValue(string, "clients"      , infostringvalue, sizeof(infostringvalue))) != NULL) info->numplayers = atoi(s);
+                       if ((s = InfoString_GetValue(string, "bots"         , infostringvalue, sizeof(infostringvalue))) != NULL) info->numbots = atoi(s);
+                       if ((s = InfoString_GetValue(string, "sv_maxclients", infostringvalue, sizeof(infostringvalue))) != NULL) info->maxplayers = atoi(s);
+                       if ((s = InfoString_GetValue(string, "gameversion"  , infostringvalue, sizeof(infostringvalue))) != NULL) info->gameversion = atoi(s);
+                       if ((s = InfoString_GetValue(string, "qcstatus"     , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->qcstatus, s, sizeof(info->qcstatus));
                        info->numhumans = info->numplayers - max(0, info->numbots);
                        info->freeslots = info->maxplayers - info->numplayers;
 
@@ -1942,7 +1989,7 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        cls.qw_qport = qport.integer;
                        // update the server IP in the userinfo (QW servers expect this, and it is used by the reconnect command)
                        InfoString_SetValue(cls.userinfo, sizeof(cls.userinfo), "*ip", addressstring2);
-                       NetConn_WriteString(mysocket, va("\377\377\377\377connect %i %i %i \"%s%s\"\n", 28, cls.qw_qport, atoi(string + 1), cls.userinfo, cls.connect_userinfo), peeraddress);
+                       NetConn_WriteString(mysocket, va(vabuf, sizeof(vabuf), "\377\377\377\377connect %i %i %i \"%s%s\"\n", 28, cls.qw_qport, atoi(string + 1), cls.userinfo, cls.connect_userinfo), peeraddress);
                        return true;
                }
                if (length >= 1 && string[0] == 'j' && cls.connect_trying)
@@ -1969,14 +2016,14 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
 
                        info = &serverlist_cache[n].info;
                        strlcpy(info->game, "QuakeWorld", sizeof(info->game));
-                       if ((s = SearchInfostring(string, "*gamedir"     )) != NULL) strlcpy(info->mod , s, sizeof (info->mod ));else info->mod[0]  = 0;
-                       if ((s = SearchInfostring(string, "map"          )) != NULL) strlcpy(info->map , s, sizeof (info->map ));else info->map[0]  = 0;
-                       if ((s = SearchInfostring(string, "hostname"     )) != NULL) strlcpy(info->name, s, sizeof (info->name));else info->name[0] = 0;
+                       if ((s = InfoString_GetValue(string, "*gamedir"     , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->mod , s, sizeof (info->mod ));else info->mod[0]  = 0;
+                       if ((s = InfoString_GetValue(string, "map"          , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->map , s, sizeof (info->map ));else info->map[0]  = 0;
+                       if ((s = InfoString_GetValue(string, "hostname"     , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->name, s, sizeof (info->name));else info->name[0] = 0;
                        info->protocol = 0;
                        info->numplayers = 0; // updated below
                        info->numhumans = 0; // updated below
-                       if ((s = SearchInfostring(string, "maxclients"   )) != NULL) info->maxplayers = atoi(s);else info->maxplayers  = 0;
-                       if ((s = SearchInfostring(string, "gameversion"  )) != NULL) info->gameversion = atoi(s);else info->gameversion = 0;
+                       if ((s = InfoString_GetValue(string, "maxclients"   , infostringvalue, sizeof(infostringvalue))) != NULL) info->maxplayers = atoi(s);else info->maxplayers  = 0;
+                       if ((s = InfoString_GetValue(string, "gameversion"  , infostringvalue, sizeof(infostringvalue))) != NULL) info->gameversion = atoi(s);else info->gameversion = 0;
 
                        // count active players on server
                        // (we could gather more info, but we're just after the number)
@@ -2024,10 +2071,10 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
 
                data += 4;
                length -= 4;
-               SZ_Clear(&net_message);
-               SZ_Write(&net_message, data, length);
-               MSG_BeginReading();
-               c = MSG_ReadByte();
+               SZ_Clear(&cl_message);
+               SZ_Write(&cl_message, data, length);
+               MSG_BeginReading(&cl_message);
+               c = MSG_ReadByte(&cl_message);
                switch (c)
                {
                case CCREP_ACCEPT:
@@ -2037,18 +2084,18 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        {
                                lhnetaddress_t clientportaddress;
                                clientportaddress = *peeraddress;
-                               LHNETADDRESS_SetPort(&clientportaddress, MSG_ReadLong());
+                               LHNETADDRESS_SetPort(&clientportaddress, MSG_ReadLong(&cl_message));
                                // extra ProQuake stuff
                                if (length >= 6)
-                                       cls.proquake_servermod = MSG_ReadByte(); // MOD_PROQUAKE
+                                       cls.proquake_servermod = MSG_ReadByte(&cl_message); // MOD_PROQUAKE
                                else
                                        cls.proquake_servermod = 0;
                                if (length >= 7)
-                                       cls.proquake_serverversion = MSG_ReadByte(); // version * 10
+                                       cls.proquake_serverversion = MSG_ReadByte(&cl_message); // version * 10
                                else
                                        cls.proquake_serverversion = 0;
                                if (length >= 8)
-                                       cls.proquake_serverflags = MSG_ReadByte(); // flags (mainly PQF_CHEATFREE)
+                                       cls.proquake_serverflags = MSG_ReadByte(&cl_message); // flags (mainly PQF_CHEATFREE)
                                else
                                        cls.proquake_serverflags = 0;
                                if (cls.proquake_servermod == 1)
@@ -2063,14 +2110,14 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        if (developer_extra.integer)
                                Con_DPrintf("Datagram_ParseConnectionless: received CCREP_REJECT from %s.\n", addressstring2);
                        cls.connect_trying = false;
-                       M_Update_Return_Reason((char *)MSG_ReadString());
+                       M_Update_Return_Reason((char *)MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));
                        break;
                case CCREP_SERVER_INFO:
                        if (developer_extra.integer)
                                Con_DPrintf("Datagram_ParseConnectionless: received CCREP_SERVER_INFO from %s.\n", addressstring2);
                        // LordHavoc: because the quake server may report weird addresses
                        // we just ignore it and keep the real address
-                       MSG_ReadString();
+                       MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
                        // search the cache for this server and update it
                        n = NetConn_ClientParsePacket_ServerList_ProcessReply(addressstring2);
                        if (n < 0)
@@ -2079,11 +2126,11 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        info = &serverlist_cache[n].info;
                        strlcpy(info->game, "Quake", sizeof(info->game));
                        strlcpy(info->mod , "", sizeof(info->mod)); // mod name is not specified
-                       strlcpy(info->name, MSG_ReadString(), sizeof(info->name));
-                       strlcpy(info->map , MSG_ReadString(), sizeof(info->map));
-                       info->numplayers = MSG_ReadByte();
-                       info->maxplayers = MSG_ReadByte();
-                       info->protocol = MSG_ReadByte();
+                       strlcpy(info->name, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof(info->name));
+                       strlcpy(info->map , MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof(info->map));
+                       info->numplayers = MSG_ReadByte(&cl_message);
+                       info->maxplayers = MSG_ReadByte(&cl_message);
+                       info->protocol = MSG_ReadByte(&cl_message);
 
                        NetConn_ClientParsePacket_ServerList_UpdateCache(n);
 
@@ -2092,7 +2139,7 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        if (developer_extra.integer)
                                Con_DPrintf("Datagram_ParseConnectionless: received CCREP_RCON from %s.\n", addressstring2);
 
-                       Con_Printf("%s\n", MSG_ReadString());
+                       Con_Printf("%s\n", MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));
                        break;
                case CCREP_PLAYER_INFO:
                        // we got a CCREP_PLAYER_INFO??
@@ -2107,7 +2154,7 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                default:
                        break;
                }
-               SZ_Clear(&net_message);
+               SZ_Clear(&cl_message);
                // we may not have liked the packet, but it was a valid control
                // packet, so we're done processing this packet now
                return true;
@@ -2211,6 +2258,7 @@ void NetConn_ClientFrame(void)
 {
        int i, length;
        lhnetaddress_t peeraddress;
+       unsigned char readbuffer[NET_HEADERSIZE+NET_MAXMESSAGE];
        NetConn_UpdateSockets();
        if (cls.connect_trying && cls.connect_nextsendtime < realtime)
        {
@@ -2227,24 +2275,24 @@ void NetConn_ClientFrame(void)
                // try challenge first (newer DP server or QW)
                NetConn_WriteString(cls.connect_mysocket, "\377\377\377\377getchallenge", &cls.connect_address);
                // then try netquake as a fallback (old server, or netquake)
-               SZ_Clear(&net_message);
+               SZ_Clear(&cl_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);
+               MSG_WriteLong(&cl_message, 0);
+               MSG_WriteByte(&cl_message, CCREQ_CONNECT);
+               MSG_WriteString(&cl_message, "QUAKE");
+               MSG_WriteByte(&cl_message, NET_PROTOCOL_VERSION);
                // extended proquake stuff
-               MSG_WriteByte(&net_message, 1); // mod = MOD_PROQUAKE
+               MSG_WriteByte(&cl_message, 1); // mod = MOD_PROQUAKE
                // this version matches ProQuake 3.40, the first version to support
                // the NAT fix, and it only supports the NAT fix for ProQuake 3.40 or
                // higher clients, so we pretend we are that version...
-               MSG_WriteByte(&net_message, 34); // version * 10
-               MSG_WriteByte(&net_message, 0); // flags
-               MSG_WriteLong(&net_message, 0); // password
+               MSG_WriteByte(&cl_message, 34); // version * 10
+               MSG_WriteByte(&cl_message, 0); // flags
+               MSG_WriteLong(&cl_message, 0); // password
                // write the packetsize now...
-               StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-               NetConn_Write(cls.connect_mysocket, net_message.data, net_message.cursize, &cls.connect_address);
-               SZ_Clear(&net_message);
+               StoreBigLong(cl_message.data, NETFLAG_CTL | (cl_message.cursize & NETFLAG_LENGTH_MASK));
+               NetConn_Write(cls.connect_mysocket, cl_message.data, cl_message.cursize, &cls.connect_address);
+               SZ_Clear(&cl_message);
        }
        for (i = 0;i < cl_numsockets;i++)
        {
@@ -2260,7 +2308,9 @@ void NetConn_ClientFrame(void)
        {
                Con_Print("Connection timed out\n");
                CL_Disconnect();
+               SV_LockThreadMutex();
                Host_ShutdownServer ();
+               SV_UnlockThreadMutex();
        }
 }
 
@@ -2282,6 +2332,7 @@ static void NetConn_BuildChallengeString(char *buffer, int bufferlength)
 /// (div0) build the full response only if possible; better a getinfo response than no response at all if getstatus won't fit
 static qboolean NetConn_BuildStatusResponse(const char* challenge, char* out_msg, size_t out_size, qboolean fullstatus)
 {
+       prvm_prog_t *prog = SVVM_prog;
        char qcstatus[256];
        unsigned int nb_clients = 0, nb_bots = 0, i;
        int length;
@@ -2289,8 +2340,6 @@ static qboolean NetConn_BuildStatusResponse(const char* challenge, char* out_msg
        const char *crypto_idstring;
        const char *str;
 
-       SV_VM_Begin();
-
        // How many clients are there?
        for (i = 0;i < (unsigned int)svs.maxclients;i++)
        {
@@ -2303,13 +2352,13 @@ static qboolean NetConn_BuildStatusResponse(const char* challenge, char* out_msg
        }
 
        *qcstatus = 0;
-       str = PRVM_GetString(PRVM_serverglobalstring(worldstatus));
+       str = PRVM_GetString(prog, PRVM_serverglobalstring(worldstatus));
        if(str && *str)
        {
                char *p;
                const char *q;
                p = qcstatus;
-               for(q = str; *q && p - qcstatus < (ptrdiff_t)(sizeof(qcstatus)) - 1; ++q)
+               for(q = str; *q && (size_t)(p - qcstatus) < (sizeof(qcstatus) - 1); ++q)
                        if(*q != '\\' && *q != '\n')
                                *p++ = *q;
                *p = 0;
@@ -2382,7 +2431,7 @@ static qboolean NetConn_BuildStatusResponse(const char* challenge, char* out_msg
 
                                *qcstatus = 0;
                                ed = PRVM_EDICT_NUM(i + 1);
-                               str = PRVM_GetString(PRVM_serveredictstring(ed, clientstatus));
+                               str = PRVM_GetString(prog, PRVM_serveredictstring(ed, clientstatus));
                                if(str && *str)
                                {
                                        char *p;
@@ -2441,11 +2490,9 @@ static qboolean NetConn_BuildStatusResponse(const char* challenge, char* out_msg
                }
        }
 
-       SV_VM_End();
        return true;
 
 bad:
-       SV_VM_End();
        return false;
 }
 
@@ -2511,7 +2558,7 @@ void NetConn_ClearConnectFlood(lhnetaddress_t *peeraddress)
 
 typedef qboolean (*rcon_matchfunc_t) (lhnetaddress_t *peeraddress, const char *password, const char *hash, const char *s, int slen);
 
-qboolean hmac_mdfour_time_matching(lhnetaddress_t *peeraddress, const char *password, const char *hash, const char *s, int slen)
+static qboolean hmac_mdfour_time_matching(lhnetaddress_t *peeraddress, const char *password, const char *hash, const char *s, int slen)
 {
        char mdfourbuf[16];
        long t1, t2;
@@ -2527,7 +2574,7 @@ qboolean hmac_mdfour_time_matching(lhnetaddress_t *peeraddress, const char *pass
        return !memcmp(mdfourbuf, hash, 16);
 }
 
-qboolean hmac_mdfour_challenge_matching(lhnetaddress_t *peeraddress, const char *password, const char *hash, const char *s, int slen)
+static qboolean hmac_mdfour_challenge_matching(lhnetaddress_t *peeraddress, const char *password, const char *hash, const char *s, int slen)
 {
        char mdfourbuf[16];
        int i;
@@ -2556,19 +2603,20 @@ qboolean hmac_mdfour_challenge_matching(lhnetaddress_t *peeraddress, const char
        return true;
 }
 
-qboolean plaintext_matching(lhnetaddress_t *peeraddress, const char *password, const char *hash, const char *s, int slen)
+static qboolean plaintext_matching(lhnetaddress_t *peeraddress, const char *password, const char *hash, const char *s, int slen)
 {
        return !strcmp(password, hash);
 }
 
 /// returns a string describing the user level, or NULL for auth failure
-const char *RCon_Authenticate(lhnetaddress_t *peeraddress, const char *password, const char *s, const char *endpos, rcon_matchfunc_t comparator, const char *cs, int cslen)
+static const char *RCon_Authenticate(lhnetaddress_t *peeraddress, const char *password, const char *s, const char *endpos, rcon_matchfunc_t comparator, const char *cs, int cslen)
 {
        const char *text, *userpass_start, *userpass_end, *userpass_startpass;
        static char buf[MAX_INPUTLINE];
        qboolean hasquotes;
        qboolean restricted = false;
        qboolean have_usernames = false;
+       char vabuf[1024];
 
        userpass_start = rcon_password.string;
        while((userpass_end = strchr(userpass_start, ' ')))
@@ -2640,7 +2688,7 @@ check:
                                {
                                        if(!strcmp(com_token, s))
                                                goto match;
-                                       if(!memcmp(va("%s ", com_token), s, strlen(com_token) + 1))
+                                       if(!memcmp(va(vabuf, sizeof(vabuf), "%s ", com_token), s, strlen(com_token) + 1))
                                                goto match;
                                }
                        }
@@ -2654,12 +2702,12 @@ match:
 allow:
        userpass_startpass = strchr(userpass_start, ':');
        if(have_usernames && userpass_startpass && userpass_startpass < userpass_end)
-               return va("%srcon (username %.*s)", restricted ? "restricted " : "", (int)(userpass_startpass-userpass_start), userpass_start);
+               return va(vabuf, sizeof(vabuf), "%srcon (username %.*s)", restricted ? "restricted " : "", (int)(userpass_startpass-userpass_start), userpass_start);
 
-       return va("%srcon", restricted ? "restricted " : "");
+       return va(vabuf, sizeof(vabuf), "%srcon", restricted ? "restricted " : "");
 }
 
-void RCon_Execute(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress, const char *addressstring2, const char *userlevel, const char *s, const char *endpos, qboolean proquakeprotocol)
+static void RCon_Execute(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress, const char *addressstring2, const char *userlevel, const char *s, const char *endpos, qboolean proquakeprotocol)
 {
        if(userlevel)
        {
@@ -2683,7 +2731,7 @@ void RCon_Execute(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress, const ch
                        if(l)
                        {
                                client_t *host_client_save = host_client;
-                               Cmd_ExecuteString(s, src_command);
+                               Cmd_ExecuteString(s, src_command, true);
                                host_client = host_client_save;
                                // in case it is a command that changes host_client (like restart)
                        }
@@ -2697,17 +2745,18 @@ void RCon_Execute(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress, const ch
        }
 }
 
-extern void SV_SendServerinfo (client_t *client);
 static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *data, int length, lhnetaddress_t *peeraddress)
 {
        int i, ret, clientnum, best;
        double besttime;
        client_t *client;
        char *s, *string, response[1400], addressstring2[128];
-       static char stringbuf[16384];
+       static char stringbuf[16384]; // server only
        qboolean islocal = (LHNETADDRESS_GetAddressType(peeraddress) == LHNETADDRESSTYPE_LOOP);
        char senddata[NET_HEADERSIZE+NET_MAXMESSAGE+CRYPTO_HEADERSIZE];
        size_t sendlength, response_len;
+       char infostringvalue[MAX_INPUTLINE];
+       char vabuf[1024];
 
        if (!sv.active)
                return false;
@@ -2817,7 +2866,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        }
                        else
                        {
-                               if ((s = SearchInfostring(string, "challenge")))
+                               if ((s = InfoString_GetValue(string, "challenge", infostringvalue, sizeof(infostringvalue))))
                                {
                                        // validate the challenge
                                        for (i = 0;i < MAX_CHALLENGES;i++)
@@ -2830,19 +2879,19 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                }
                        }
 
-                       if((s = SearchInfostring(string, "message")))
+                       if((s = InfoString_GetValue(string, "message", infostringvalue, sizeof(infostringvalue))))
                                Con_DPrintf("Connecting client %s sent us the message: %s\n", addressstring2, s);
 
                        if(!(islocal || sv_public.integer > -2))
                        {
                                if (developer_extra.integer)
                                        Con_Printf("Datagram_ParseConnectionless: sending \"reject %s\" to %s.\n", sv_public_rejectreason.string, addressstring2);
-                               NetConn_WriteString(mysocket, va("\377\377\377\377reject %s", sv_public_rejectreason.string), peeraddress);
+                               NetConn_WriteString(mysocket, va(vabuf, sizeof(vabuf), "\377\377\377\377reject %s", sv_public_rejectreason.string), peeraddress);
                                return true;
                        }
 
                        // check engine protocol
-                       if(!(s = SearchInfostring(string, "protocol")) || strcmp(s, "darkplaces 3"))
+                       if(!(s = InfoString_GetValue(string, "protocol", infostringvalue, sizeof(infostringvalue))) || strcmp(s, "darkplaces 3"))
                        {
                                if (developer_extra.integer)
                                        Con_Printf("Datagram_ParseConnectionless: sending \"reject Wrong game protocol.\" to %s.\n", addressstring2);
@@ -2899,9 +2948,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                                NetConn_WriteString(mysocket, "\377\377\377\377accept", peeraddress);
                                                if(crypto && crypto->authenticated)
                                                        Crypto_ServerFinishInstance(&client->netconnection->crypto, crypto);
-                                               SV_VM_Begin();
                                                SV_SendServerinfo(client);
-                                               SV_VM_End();
                                        }
                                        else
                                        {
@@ -2933,9 +2980,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                        // now set up the client
                                        if(crypto && crypto->authenticated)
                                                Crypto_ServerFinishInstance(&conn->crypto, crypto);
-                                       SV_VM_Begin();
                                        SV_ConnectClient(clientnum, conn);
-                                       SV_VM_End();
                                        NetConn_Heartbeat(1);
                                        return true;
                                }
@@ -3071,10 +3116,10 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                const char *protocolname;
                data += 4;
                length -= 4;
-               SZ_Clear(&net_message);
-               SZ_Write(&net_message, data, length);
-               MSG_BeginReading();
-               c = MSG_ReadByte();
+               SZ_Clear(&sv_message);
+               SZ_Write(&sv_message, data, length);
+               MSG_BeginReading(&sv_message);
+               c = MSG_ReadByte(&sv_message);
                switch (c)
                {
                case CCREQ_CONNECT:
@@ -3084,31 +3129,31 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        {
                                if (developer_extra.integer)
                                        Con_DPrintf("Datagram_ParseConnectionless: sending CCREP_REJECT \"%s\" to %s.\n", sv_public_rejectreason.string, addressstring2);
-                               SZ_Clear(&net_message);
+                               SZ_Clear(&sv_message);
                                // save space for the header, filled in later
-                               MSG_WriteLong(&net_message, 0);
-                               MSG_WriteByte(&net_message, CCREP_REJECT);
-                               MSG_WriteString(&net_message, va("%s\n", sv_public_rejectreason.string));
-                               StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-                               NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress);
-                               SZ_Clear(&net_message);
+                               MSG_WriteLong(&sv_message, 0);
+                               MSG_WriteByte(&sv_message, CCREP_REJECT);
+                               MSG_WriteString(&sv_message, va(vabuf, sizeof(vabuf), "%s\n", sv_public_rejectreason.string));
+                               StoreBigLong(sv_message.data, NETFLAG_CTL | (sv_message.cursize & NETFLAG_LENGTH_MASK));
+                               NetConn_Write(mysocket, sv_message.data, sv_message.cursize, peeraddress);
+                               SZ_Clear(&sv_message);
                                break;
                        }
 
-                       protocolname = MSG_ReadString();
-                       protocolnumber = MSG_ReadByte();
+                       protocolname = MSG_ReadString(&sv_message, sv_readstring, sizeof(sv_readstring));
+                       protocolnumber = MSG_ReadByte(&sv_message);
                        if (strcmp(protocolname, "QUAKE") || protocolnumber != NET_PROTOCOL_VERSION)
                        {
                                if (developer_extra.integer)
                                        Con_DPrintf("Datagram_ParseConnectionless: sending CCREP_REJECT \"Incompatible version.\" to %s.\n", addressstring2);
-                               SZ_Clear(&net_message);
+                               SZ_Clear(&sv_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");
-                               StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-                               NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress);
-                               SZ_Clear(&net_message);
+                               MSG_WriteLong(&sv_message, 0);
+                               MSG_WriteByte(&sv_message, CCREP_REJECT);
+                               MSG_WriteString(&sv_message, "Incompatible version.\n");
+                               StoreBigLong(sv_message.data, NETFLAG_CTL | (sv_message.cursize & NETFLAG_LENGTH_MASK));
+                               NetConn_Write(mysocket, sv_message.data, sv_message.cursize, peeraddress);
+                               SZ_Clear(&sv_message);
                                break;
                        }
 
@@ -3124,23 +3169,19 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                        // send a reply
                                        if (developer_extra.integer)
                                                Con_DPrintf("Datagram_ParseConnectionless: sending duplicate CCREP_ACCEPT to %s.\n", addressstring2);
-                                       SZ_Clear(&net_message);
+                                       SZ_Clear(&sv_message);
                                        // save space for the header, filled in later
-                                       MSG_WriteLong(&net_message, 0);
-                                       MSG_WriteByte(&net_message, CCREP_ACCEPT);
-                                       MSG_WriteLong(&net_message, LHNETADDRESS_GetPort(LHNET_AddressFromSocket(client->netconnection->mysocket)));
-                                       StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-                                       NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress);
-                                       SZ_Clear(&net_message);
+                                       MSG_WriteLong(&sv_message, 0);
+                                       MSG_WriteByte(&sv_message, CCREP_ACCEPT);
+                                       MSG_WriteLong(&sv_message, LHNETADDRESS_GetPort(LHNET_AddressFromSocket(client->netconnection->mysocket)));
+                                       StoreBigLong(sv_message.data, NETFLAG_CTL | (sv_message.cursize & NETFLAG_LENGTH_MASK));
+                                       NetConn_Write(mysocket, sv_message.data, sv_message.cursize, peeraddress);
+                                       SZ_Clear(&sv_message);
 
                                        // if client is already spawned, re-send the
                                        // serverinfo message as they'll need it to play
                                        if (client->spawned)
-                                       {
-                                               SV_VM_Begin();
                                                SV_SendServerinfo(client);
-                                               SV_VM_End();
-                                       }
                                        return true;
                                }
                        }
@@ -3161,18 +3202,16 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                        if (developer_extra.integer)
                                                Con_DPrintf("Datagram_ParseConnectionless: sending CCREP_ACCEPT to %s.\n", addressstring2);
                                        // send back the info about the server connection
-                                       SZ_Clear(&net_message);
+                                       SZ_Clear(&sv_message);
                                        // save space for the header, filled in later
-                                       MSG_WriteLong(&net_message, 0);
-                                       MSG_WriteByte(&net_message, CCREP_ACCEPT);
-                                       MSG_WriteLong(&net_message, LHNETADDRESS_GetPort(LHNET_AddressFromSocket(conn->mysocket)));
-                                       StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-                                       NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress);
-                                       SZ_Clear(&net_message);
+                                       MSG_WriteLong(&sv_message, 0);
+                                       MSG_WriteByte(&sv_message, CCREP_ACCEPT);
+                                       MSG_WriteLong(&sv_message, LHNETADDRESS_GetPort(LHNET_AddressFromSocket(conn->mysocket)));
+                                       StoreBigLong(sv_message.data, NETFLAG_CTL | (sv_message.cursize & NETFLAG_LENGTH_MASK));
+                                       NetConn_Write(mysocket, sv_message.data, sv_message.cursize, peeraddress);
+                                       SZ_Clear(&sv_message);
                                        // now set up the client struct
-                                       SV_VM_Begin();
                                        SV_ConnectClient(clientnum, conn);
-                                       SV_VM_End();
                                        NetConn_Heartbeat(1);
                                        return true;
                                }
@@ -3181,44 +3220,44 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        if (developer_extra.integer)
                                Con_DPrintf("Datagram_ParseConnectionless: sending CCREP_REJECT \"Server is full.\" to %s.\n", addressstring2);
                        // no room; try to let player know
-                       SZ_Clear(&net_message);
+                       SZ_Clear(&sv_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");
-                       StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-                       NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress);
-                       SZ_Clear(&net_message);
+                       MSG_WriteLong(&sv_message, 0);
+                       MSG_WriteByte(&sv_message, CCREP_REJECT);
+                       MSG_WriteString(&sv_message, "Server is full.\n");
+                       StoreBigLong(sv_message.data, NETFLAG_CTL | (sv_message.cursize & NETFLAG_LENGTH_MASK));
+                       NetConn_Write(mysocket, sv_message.data, sv_message.cursize, peeraddress);
+                       SZ_Clear(&sv_message);
                        break;
                case CCREQ_SERVER_INFO:
                        if (developer_extra.integer)
                                Con_DPrintf("Datagram_ParseConnectionless: received CCREQ_SERVER_INFO from %s.\n", addressstring2);
                        if(!(islocal || sv_public.integer > -1))
                                break;
-                       if (sv.active && !strcmp(MSG_ReadString(), "QUAKE"))
+                       if (sv.active && !strcmp(MSG_ReadString(&sv_message, sv_readstring, sizeof(sv_readstring)), "QUAKE"))
                        {
                                int numclients;
                                char myaddressstring[128];
                                if (developer_extra.integer)
                                        Con_DPrintf("Datagram_ParseConnectionless: sending CCREP_SERVER_INFO to %s.\n", addressstring2);
-                               SZ_Clear(&net_message);
+                               SZ_Clear(&sv_message);
                                // save space for the header, filled in later
-                               MSG_WriteLong(&net_message, 0);
-                               MSG_WriteByte(&net_message, CCREP_SERVER_INFO);
+                               MSG_WriteLong(&sv_message, 0);
+                               MSG_WriteByte(&sv_message, CCREP_SERVER_INFO);
                                LHNETADDRESS_ToString(LHNET_AddressFromSocket(mysocket), myaddressstring, sizeof(myaddressstring), true);
-                               MSG_WriteString(&net_message, myaddressstring);
-                               MSG_WriteString(&net_message, hostname.string);
-                               MSG_WriteString(&net_message, sv.name);
+                               MSG_WriteString(&sv_message, myaddressstring);
+                               MSG_WriteString(&sv_message, hostname.string);
+                               MSG_WriteString(&sv_message, sv.name);
                                // How many clients are there?
                                for (i = 0, numclients = 0;i < svs.maxclients;i++)
                                        if (svs.clients[i].active)
                                                numclients++;
-                               MSG_WriteByte(&net_message, numclients);
-                               MSG_WriteByte(&net_message, svs.maxclients);
-                               MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
-                               StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-                               NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress);
-                               SZ_Clear(&net_message);
+                               MSG_WriteByte(&sv_message, numclients);
+                               MSG_WriteByte(&sv_message, svs.maxclients);
+                               MSG_WriteByte(&sv_message, NET_PROTOCOL_VERSION);
+                               StoreBigLong(sv_message.data, NETFLAG_CTL | (sv_message.cursize & NETFLAG_LENGTH_MASK));
+                               NetConn_Write(mysocket, sv_message.data, sv_message.cursize, peeraddress);
+                               SZ_Clear(&sv_message);
                        }
                        break;
                case CCREQ_PLAYER_INFO:
@@ -3231,29 +3270,29 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                int playerNumber, activeNumber, clientNumber;
                                client_t *client;
 
-                               playerNumber = MSG_ReadByte();
+                               playerNumber = MSG_ReadByte(&sv_message);
                                activeNumber = -1;
                                for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++)
                                        if (client->active && ++activeNumber == playerNumber)
                                                break;
                                if (clientNumber != svs.maxclients)
                                {
-                                       SZ_Clear(&net_message);
+                                       SZ_Clear(&sv_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, client->frags);
-                                       MSG_WriteLong(&net_message, (int)(realtime - client->connecttime));
+                                       MSG_WriteLong(&sv_message, 0);
+                                       MSG_WriteByte(&sv_message, CCREP_PLAYER_INFO);
+                                       MSG_WriteByte(&sv_message, playerNumber);
+                                       MSG_WriteString(&sv_message, client->name);
+                                       MSG_WriteLong(&sv_message, client->colors);
+                                       MSG_WriteLong(&sv_message, client->frags);
+                                       MSG_WriteLong(&sv_message, (int)(realtime - client->connecttime));
                                        if(sv_status_privacy.integer)
-                                               MSG_WriteString(&net_message, client->netconnection ? "hidden" : "botclient");
+                                               MSG_WriteString(&sv_message, client->netconnection ? "hidden" : "botclient");
                                        else
-                                               MSG_WriteString(&net_message, client->netconnection ? client->netconnection->address : "botclient");
-                                       StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-                                       NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress);
-                                       SZ_Clear(&net_message);
+                                               MSG_WriteString(&sv_message, client->netconnection ? client->netconnection->address : "botclient");
+                                       StoreBigLong(sv_message.data, NETFLAG_CTL | (sv_message.cursize & NETFLAG_LENGTH_MASK));
+                                       NetConn_Write(mysocket, sv_message.data, sv_message.cursize, peeraddress);
+                                       SZ_Clear(&sv_message);
                                }
                        }
                        break;
@@ -3268,22 +3307,22 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                cvar_t *var;
 
                                // find the search start location
-                               prevCvarName = MSG_ReadString();
+                               prevCvarName = MSG_ReadString(&sv_message, sv_readstring, sizeof(sv_readstring));
                                var = Cvar_FindVarAfter(prevCvarName, CVAR_NOTIFY);
 
                                // send the response
-                               SZ_Clear(&net_message);
+                               SZ_Clear(&sv_message);
                                // save space for the header, filled in later
-                               MSG_WriteLong(&net_message, 0);
-                               MSG_WriteByte(&net_message, CCREP_RULE_INFO);
+                               MSG_WriteLong(&sv_message, 0);
+                               MSG_WriteByte(&sv_message, CCREP_RULE_INFO);
                                if (var)
                                {
-                                       MSG_WriteString(&net_message, var->name);
-                                       MSG_WriteString(&net_message, var->string);
+                                       MSG_WriteString(&sv_message, var->name);
+                                       MSG_WriteString(&sv_message, var->string);
                                }
-                               StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-                               NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress);
-                               SZ_Clear(&net_message);
+                               StoreBigLong(sv_message.data, NETFLAG_CTL | (sv_message.cursize & NETFLAG_LENGTH_MASK));
+                               NetConn_Write(mysocket, sv_message.data, sv_message.cursize, peeraddress);
+                               SZ_Clear(&sv_message);
                        }
                        break;
                case CCREQ_RCON:
@@ -3296,8 +3335,8 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                char *s;
                                char *endpos;
                                const char *userlevel;
-                               strlcpy(password, MSG_ReadString(), sizeof(password));
-                               strlcpy(cmd, MSG_ReadString(), sizeof(cmd));
+                               strlcpy(password, MSG_ReadString(&sv_message, sv_readstring, sizeof(sv_readstring)), sizeof(password));
+                               strlcpy(cmd, MSG_ReadString(&sv_message, sv_readstring, sizeof(sv_readstring)), sizeof(cmd));
                                s = cmd;
                                endpos = cmd + strlen(cmd) + 1; // one behind the NUL, so adding strlen+1 will eventually reach it
                                userlevel = RCon_Authenticate(peeraddress, password, s, endpos, plaintext_matching, NULL, 0);
@@ -3308,7 +3347,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                default:
                        break;
                }
-               SZ_Clear(&net_message);
+               SZ_Clear(&sv_message);
                // we may not have liked the packet, but it was a valid control
                // packet, so we're done processing this packet now
                return true;
@@ -3317,9 +3356,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
        {
                if ((ret = NetConn_ReceivedMessage(host_client->netconnection, data, length, sv.protocol, host_client->spawned ? net_messagetimeout.value : net_connecttimeout.value)) == 2)
                {
-                       SV_VM_Begin();
                        SV_ReadClientMessage();
-                       SV_VM_End();
                        return ret;
                }
        }
@@ -3330,6 +3367,7 @@ void NetConn_ServerFrame(void)
 {
        int i, length;
        lhnetaddress_t peeraddress;
+       unsigned char readbuffer[NET_HEADERSIZE+NET_MAXMESSAGE];
        for (i = 0;i < sv_numsockets;i++)
                while (sv_sockets[i] && (length = NetConn_Read(sv_sockets[i], readbuffer, sizeof(readbuffer), &peeraddress)) > 0)
                        NetConn_ServerParsePacket(sv_sockets[i], readbuffer, length, &peeraddress);
@@ -3339,9 +3377,7 @@ void NetConn_ServerFrame(void)
                if (host_client->netconnection && realtime > host_client->netconnection->timeout && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
                {
                        Con_Printf("Client \"%s\" connection timed out\n", host_client->name);
-                       SV_VM_Begin();
                        SV_DropClient(false);
-                       SV_VM_End();
                }
        }
 }
@@ -3379,15 +3415,15 @@ void NetConn_QueryMasters(qboolean querydp, qboolean queryqw)
                                if(LHNETADDRESS_GetAddressType(&broadcastaddress) == af)
                                {
                                        // search LAN for Quake servers
-                                       SZ_Clear(&net_message);
+                                       SZ_Clear(&cl_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);
-                                       StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-                                       NetConn_Write(cl_sockets[i], net_message.data, net_message.cursize, &broadcastaddress);
-                                       SZ_Clear(&net_message);
+                                       MSG_WriteLong(&cl_message, 0);
+                                       MSG_WriteByte(&cl_message, CCREQ_SERVER_INFO);
+                                       MSG_WriteString(&cl_message, "QUAKE");
+                                       MSG_WriteByte(&cl_message, NET_PROTOCOL_VERSION);
+                                       StoreBigLong(cl_message.data, NETFLAG_CTL | (cl_message.cursize & NETFLAG_LENGTH_MASK));
+                                       NetConn_Write(cl_sockets[i], cl_message.data, cl_message.cursize, &broadcastaddress);
+                                       SZ_Clear(&cl_message);
 
                                        // search LAN for DarkPlaces servers
                                        NetConn_WriteString(cl_sockets[i], "\377\377\377\377getstatus", &broadcastaddress);
@@ -3525,26 +3561,26 @@ static void Net_Heartbeat_f(void)
                Con_Print("No server running, can not heartbeat to master server.\n");
 }
 
-void PrintStats(netconn_t *conn)
+static void PrintStats(netconn_t *conn)
 {
        if ((cls.state == ca_connected && cls.protocol == PROTOCOL_QUAKEWORLD) || (sv.active && sv.protocol == PROTOCOL_QUAKEWORLD))
                Con_Printf("address=%21s canSend=%u sendSeq=%6u recvSeq=%6u\n", conn->address, !conn->sendMessageLength, conn->outgoing_unreliable_sequence, conn->qw.incoming_sequence);
        else
                Con_Printf("address=%21s canSend=%u sendSeq=%6u recvSeq=%6u\n", conn->address, !conn->sendMessageLength, conn->nq.sendSequence, conn->nq.receiveSequence);
+       Con_Printf("unreliable messages sent   = %i\n", conn->unreliableMessagesSent);
+       Con_Printf("unreliable messages recv   = %i\n", conn->unreliableMessagesReceived);
+       Con_Printf("reliable messages sent     = %i\n", conn->reliableMessagesSent);
+       Con_Printf("reliable messages received = %i\n", conn->reliableMessagesReceived);
+       Con_Printf("packetsSent                = %i\n", conn->packetsSent);
+       Con_Printf("packetsReSent              = %i\n", conn->packetsReSent);
+       Con_Printf("packetsReceived            = %i\n", conn->packetsReceived);
+       Con_Printf("receivedDuplicateCount     = %i\n", conn->receivedDuplicateCount);
+       Con_Printf("droppedDatagrams           = %i\n", conn->droppedDatagrams);
 }
 
 void Net_Stats_f(void)
 {
        netconn_t *conn;
-       Con_Printf("unreliable messages sent   = %i\n", unreliableMessagesSent);
-       Con_Printf("unreliable messages recv   = %i\n", unreliableMessagesReceived);
-       Con_Printf("reliable messages sent     = %i\n", reliableMessagesSent);
-       Con_Printf("reliable messages received = %i\n", reliableMessagesReceived);
-       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("droppedDatagrams           = %i\n", droppedDatagrams);
        Con_Print("connections                =\n");
        for (conn = netconn_list;conn;conn = conn->next)
                PrintStats(conn);
@@ -3651,10 +3687,15 @@ void NetConn_Init(void)
        }
        cl_numsockets = 0;
        sv_numsockets = 0;
-       net_message.data = net_message_buf;
-       net_message.maxsize = sizeof(net_message_buf);
-       net_message.cursize = 0;
+       cl_message.data = cl_message_buf;
+       cl_message.maxsize = sizeof(cl_message_buf);
+       cl_message.cursize = 0;
+       sv_message.data = sv_message_buf;
+       sv_message.maxsize = sizeof(sv_message_buf);
+       sv_message.cursize = 0;
        LHNET_Init();
+       if (Thread_HasThreads())
+               netconn_mutex = Thread_CreateMutex();
 }
 
 void NetConn_Shutdown(void)
@@ -3662,5 +3703,8 @@ void NetConn_Shutdown(void)
        NetConn_CloseClientPorts();
        NetConn_CloseServerPorts();
        LHNET_Shutdown();
+       if (netconn_mutex)
+               Thread_DestroyMutex(netconn_mutex);
+       netconn_mutex = NULL;
 }