+++ /dev/null
-/*
-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);
-}