#define MASTER_PORT 27950
// note this defaults on for dedicated servers, off for listen servers
-cvar_t sv_public = {0, "sv_public", "0"};
-static cvar_t sv_heartbeatperiod = {CVAR_SAVE, "sv_heartbeatperiod", "120"};
+cvar_t sv_public = {0, "sv_public", "0", "advertises this server on the master server (so that players can find it in the server browser)"};
+static cvar_t sv_heartbeatperiod = {CVAR_SAVE, "sv_heartbeatperiod", "120", "how often to send heartbeat in seconds (only used if sv_public is 1)"};
// FIXME: resolve DNS on masters whenever their value changes and cache it (to avoid major delays in active servers when they heartbeat)
static cvar_t sv_masters [] =
{
- {CVAR_SAVE, "sv_master1", ""},
- {CVAR_SAVE, "sv_master2", ""},
- {CVAR_SAVE, "sv_master3", ""},
- {CVAR_SAVE, "sv_master4", ""},
- {0, "sv_masterextra1", "ghdigital.com"}, //69.59.212.88
- {0, "sv_masterextra2", "dpmaster.deathmask.net"}, //64.253.41.49
- {0, "sv_masterextra3", "12.166.196.192"}, //blaze.mindphukd.org (doesn't resolve currently but works as an ip)
- {0, NULL, NULL}
+ {CVAR_SAVE, "sv_master1", "", "user-chosen master server 1"},
+ {CVAR_SAVE, "sv_master2", "", "user-chosen master server 2"},
+ {CVAR_SAVE, "sv_master3", "", "user-chosen master server 3"},
+ {CVAR_SAVE, "sv_master4", "", "user-chosen master server 4"},
+ {0, "sv_masterextra1", "ghdigital.com", "default master server 1 (admin: LordHavoc)"}, // admin: LordHavoc
+ {0, "sv_masterextra2", "dpmaster.deathmask.net", "default master server 2 (admin: Willis)"}, // admin: Willis
+ {0, "sv_masterextra3", "12.166.196.192", "default master server 3 (admin: Venim)"}, // admin: Venim
+ {0, "sv_masterextra4", "excalibur.nvg.ntnu.no", "default master server 4 (admin: tChr)"}, // admin: tChr
+ {0, NULL, NULL, NULL}
};
static double nextheartbeattime = 0;
sizebuf_t net_message;
static unsigned char net_message_buf[NET_MAXMESSAGE];
-cvar_t net_messagetimeout = {0, "net_messagetimeout","300"};
-cvar_t net_messagerejointimeout = {0, "net_messagerejointimeout","10"};
-cvar_t net_connecttimeout = {0, "net_connecttimeout","10"};
-cvar_t hostname = {CVAR_SAVE, "hostname", "UNNAMED"};
-cvar_t developer_networking = {0, "developer_networking", "0"};
+cvar_t net_messagetimeout = {0, "net_messagetimeout","300", "drops players who have not sent any packets for this many seconds"};
+cvar_t net_messagerejointimeout = {0, "net_messagerejointimeout","10", "give a player this much time in seconds to rejoin and continue playing (not losing frags and such)"};
+cvar_t net_connecttimeout = {0, "net_connecttimeout","10", "after requesting a connection, the client must reply within this many seconds or be dropped (cuts down on connect floods)"};
+cvar_t hostname = {CVAR_SAVE, "hostname", "UNNAMED", "server message to show in server browser"};
+cvar_t developer_networking = {0, "developer_networking", "0", "prints all received and sent packets (recommended only for debugging)"};
-cvar_t cl_netlocalping = {0, "cl_netlocalping","0"};
-static cvar_t cl_netpacketloss = {0, "cl_netpacketloss","0"};
-static cvar_t net_slist_queriespersecond = {0, "net_slist_queriespersecond", "20"};
-static cvar_t net_slist_queriesperframe = {0, "net_slist_queriesperframe", "4"};
-static cvar_t net_slist_timeout = {0, "net_slist_timeout", "4"};
-static cvar_t net_slist_maxtries = {0, "net_slist_maxtries", "3"};
+cvar_t cl_netlocalping = {0, "cl_netlocalping","0", "lags local loopback connection by this much ping time (useful to play more fairly on your own server with people with higher pings)"};
+static cvar_t cl_netpacketloss = {0, "cl_netpacketloss","0", "drops this percentage of packets (incoming and outgoing), useful for testing network protocol robustness (effects failing to start, sounds failing to play, etc)"};
+static cvar_t net_slist_queriespersecond = {0, "net_slist_queriespersecond", "20", "how many server information requests to send per second"};
+static cvar_t net_slist_queriesperframe = {0, "net_slist_queriesperframe", "4", "maximum number of server information requests to send each rendered frame (guards against low framerates causing problems)"};
+static cvar_t net_slist_timeout = {0, "net_slist_timeout", "4", "how long to listen for a server information response before giving up"};
+static cvar_t net_slist_maxtries = {0, "net_slist_maxtries", "3", "how many times to ask the same server for information (more times gives better ping reports but takes longer)"};
/* statistic counters */
static int packetsSent = 0;
netconn_t *netconn_list = NULL;
mempool_t *netconn_mempool = NULL;
-cvar_t cl_netport = {0, "cl_port", "0"};
-cvar_t sv_netport = {0, "port", "26000"};
-cvar_t net_address = {0, "net_address", "0.0.0.0"};
-//cvar_t net_netaddress_ipv6 = {0, "net_address_ipv6", "[0:0:0:0:0:0:0:0]"};
+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"};
+cvar_t net_address = {0, "net_address", "0.0.0.0", "network address to open ports on"};
+//cvar_t net_netaddress_ipv6 = {0, "net_address_ipv6", "[0:0:0:0:0:0:0:0]", "network address to open ipv6 ports on"};
// ServerList interface
serverlist_mask_t serverlist_andmasks[SERVERLIST_ANDMASKCOUNT];
for( i = 0 ; i < 1024 ; i++ ) {
memset( &serverlist_cache[serverlist_cachecount], 0, sizeof( serverlist_entry_t ) );
serverlist_cache[serverlist_cachecount].info.ping = 1000 + 1024 - i;
- dpsnprintf( serverlist_cache[serverlist_cachecount].info.name, 128, "Black's ServerList Test %i", i );
+ dpsnprintf( serverlist_cache[serverlist_cachecount].info.name, sizeof(serverlist_cache[serverlist_cachecount].info.name), "Black's ServerList Test %i", i );
serverlist_cache[serverlist_cachecount].finished = true;
sprintf( serverlist_cache[serverlist_cachecount].line1, "%i %s", serverlist_cache[serverlist_cachecount].info.ping, serverlist_cache[serverlist_cachecount].info.name );
ServerList_ViewList_Insert( &serverlist_cache[serverlist_cachecount] );
return NetConn_Write(mysocket, string, (int)strlen(string), peeraddress);
}
-int NetConn_SendReliableMessage(netconn_t *conn, sizebuf_t *data)
-{
- unsigned int packetLen;
- unsigned int dataLen;
- unsigned int eom;
- unsigned int *header;
-
-//#ifdef DEBUG
- if (data->cursize == 0)
- {
- Con_Printf ("Datagram_SendMessage: zero length message\n");
- return -1;
- }
-
- if (data->cursize > (int)sizeof(conn->sendMessage))
- {
- Con_Printf ("Datagram_SendMessage: message too big (%u > %u)\n", data->cursize, sizeof(conn->sendMessage));
- return -1;
- }
-
- if (conn->canSend == false)
- {
- Con_Printf ("SendMessage: called with canSend == false\n");
- return -1;
- }
-//#endif
-
- memcpy(conn->sendMessage, data->data, data->cursize);
- conn->sendMessageLength = data->cursize;
-
- if (conn->sendMessageLength <= MAX_PACKETFRAGMENT)
- {
- dataLen = conn->sendMessageLength;
- eom = NETFLAG_EOM;
- }
- else
- {
- dataLen = MAX_PACKETFRAGMENT;
- eom = 0;
- }
-
- packetLen = NET_HEADERSIZE + dataLen;
-
- header = (unsigned int *)sendbuffer;
- header[0] = BigLong(packetLen | (NETFLAG_DATA | eom));
- header[1] = BigLong(conn->sendSequence);
- memcpy(sendbuffer + NET_HEADERSIZE, conn->sendMessage, dataLen);
-
- conn->sendSequence++;
- conn->canSend = false;
-
- if (NetConn_Write(conn->mysocket, (void *)&sendbuffer, packetLen, &conn->peeraddress) != (int)packetLen)
- return -1;
-
- conn->lastSendTime = realtime;
- packetsSent++;
- reliableMessagesSent++;
- return 1;
-}
-
-static void NetConn_SendMessageNext(netconn_t *conn)
+int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data)
{
unsigned int packetLen;
unsigned int dataLen;
unsigned int eom;
unsigned int *header;
- if (conn->sendMessageLength && !conn->canSend && conn->sendNext)
+ // if a reliable message fragment has been lost, send it again
+ if (!conn->canSend && conn->sendMessageLength && (realtime - conn->lastSendTime) > 1.0)
{
if (conn->sendMessageLength <= MAX_PACKETFRAGMENT)
{
header = (unsigned int *)sendbuffer;
header[0] = BigLong(packetLen | (NETFLAG_DATA | eom));
- header[1] = BigLong(conn->sendSequence);
+ header[1] = BigLong(conn->sendSequence - 1);
memcpy(sendbuffer + NET_HEADERSIZE, conn->sendMessage, dataLen);
- conn->sendSequence++;
- conn->sendNext = false;
+ if (NetConn_Write(conn->mysocket, (void *)&sendbuffer, packetLen, &conn->peeraddress) == (int)packetLen)
+ {
+ conn->lastSendTime = realtime;
+ packetsReSent++;
+ }
+ }
- if (NetConn_Write(conn->mysocket, (void *)&sendbuffer, packetLen, &conn->peeraddress) != (int)packetLen)
- return;
+ // if we have a new reliable message to send, do so
+ if (conn->canSend && conn->message.cursize)
+ {
+ if (conn->message.cursize > (int)sizeof(conn->sendMessage))
+ {
+ Con_Printf("NetConn_SendUnreliableMessage: reliable message too big (%u > %u)\n", conn->message.cursize, sizeof(conn->sendMessage));
+ conn->message.overflowed = true;
+ return -1;
+ }
- conn->lastSendTime = realtime;
- packetsSent++;
- }
-}
+ if (developer_networking.integer && conn == cls.netcon)
+ {
+ Con_Print("client sending reliable message to server:\n");
+ SZ_HexDumpToConsole(&conn->message);
+ }
-static void NetConn_ReSendMessage(netconn_t *conn)
-{
- unsigned int packetLen;
- unsigned int dataLen;
- unsigned int eom;
- unsigned int *header;
+ memcpy(conn->sendMessage, conn->message.data, conn->message.cursize);
+ conn->sendMessageLength = conn->message.cursize;
+ SZ_Clear(&conn->message);
- if (conn->sendMessageLength && !conn->canSend && (realtime - conn->lastSendTime) > 1.0)
- {
if (conn->sendMessageLength <= MAX_PACKETFRAGMENT)
{
dataLen = conn->sendMessageLength;
header = (unsigned int *)sendbuffer;
header[0] = BigLong(packetLen | (NETFLAG_DATA | eom));
- header[1] = BigLong(conn->sendSequence - 1);
+ header[1] = BigLong(conn->sendSequence);
memcpy(sendbuffer + NET_HEADERSIZE, conn->sendMessage, dataLen);
- conn->sendNext = false;
+ conn->sendSequence++;
+ conn->canSend = false;
- if (NetConn_Write(conn->mysocket, (void *)&sendbuffer, packetLen, &conn->peeraddress) != (int)packetLen)
- return;
+ NetConn_Write(conn->mysocket, (void *)&sendbuffer, packetLen, &conn->peeraddress);
conn->lastSendTime = realtime;
- packetsReSent++;
+ packetsSent++;
+ reliableMessagesSent++;
}
-}
-
-qboolean NetConn_CanSendMessage(netconn_t *conn)
-{
- return conn->canSend;
-}
-
-int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data)
-{
- int packetLen;
- unsigned int *header;
- packetLen = NET_HEADERSIZE + data->cursize;
-
-//#ifdef DEBUG
- if (data->cursize == 0)
+ // if we have an unreliable message to send, do so
+ if (data->cursize)
{
- Con_Printf ("Datagram_SendUnreliableMessage: zero length message\n");
- return -1;
- }
+ packetLen = NET_HEADERSIZE + data->cursize;
- if (packetLen > (int)sizeof(sendbuffer))
- {
- Con_Printf ("Datagram_SendUnreliableMessage: message too big %u\n", data->cursize);
- return -1;
- }
-//#endif
+ if (packetLen > (int)sizeof(sendbuffer))
+ {
+ Con_Printf("NetConn_SendUnreliableMessage: message too big %u\n", data->cursize);
+ return -1;
+ }
- header = (unsigned int *)sendbuffer;
- header[0] = BigLong(packetLen | NETFLAG_UNRELIABLE);
- header[1] = BigLong(conn->unreliableSendSequence);
- memcpy(sendbuffer + NET_HEADERSIZE, data->data, data->cursize);
+ header = (unsigned int *)sendbuffer;
+ header[0] = BigLong(packetLen | NETFLAG_UNRELIABLE);
+ header[1] = BigLong(conn->unreliableSendSequence);
+ memcpy(sendbuffer + NET_HEADERSIZE, data->data, data->cursize);
- conn->unreliableSendSequence++;
+ conn->unreliableSendSequence++;
- if (NetConn_Write(conn->mysocket, (void *)&sendbuffer, packetLen, &conn->peeraddress) != (int)packetLen)
- return -1;
+ NetConn_Write(conn->mysocket, (void *)&sendbuffer, packetLen, &conn->peeraddress);
- packetsSent++;
- unreliableMessagesSent++;
- return 1;
+ packetsSent++;
+ unreliableMessagesSent++;
+ }
+ return 0;
}
void NetConn_CloseClientPorts(void)
}
}
-static void NetConn_UpdateServerStuff(void);
void NetConn_OpenServerPorts(int opennetports)
{
int port;
NetConn_CloseServerPorts();
- NetConn_UpdateServerStuff();
+ NetConn_UpdateSockets();
port = bound(0, sv_netport.integer, 65535);
if (port == 0)
port = 26000;
conn->peeraddress = *peeraddress;
conn->canSend = true;
conn->lastMessageTime = realtime;
+ conn->message.data = conn->messagedata;
+ conn->message.maxsize = sizeof(conn->messagedata);
+ conn->message.cursize = 0;
// LordHavoc: (inspired by ProQuake) use a short connect timeout to
// reduce effectiveness of connection request floods
conn->timeout = realtime + net_connecttimeout.value;
static int clientport = -1;
static int clientport2 = -1;
static int hostport = -1;
-static void NetConn_UpdateServerStuff(void)
+void NetConn_UpdateSockets(void)
{
if (cls.state != ca_dedicated)
{
}
}
-int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int length)
+static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int length)
{
unsigned int count;
unsigned int flags;
Con_DPrint("ack sequencing error\n");
conn->lastMessageTime = realtime;
conn->timeout = realtime + net_messagetimeout.value;
- conn->sendMessageLength -= MAX_PACKETFRAGMENT;
- if (conn->sendMessageLength > 0)
+ if (conn->sendMessageLength > MAX_PACKETFRAGMENT)
{
+ unsigned int packetLen;
+ unsigned int dataLen;
+ unsigned int eom;
+ unsigned int *header;
+
+ conn->sendMessageLength -= MAX_PACKETFRAGMENT;
memcpy(conn->sendMessage, conn->sendMessage+MAX_PACKETFRAGMENT, conn->sendMessageLength);
- conn->sendNext = true;
- NetConn_SendMessageNext(conn);
+
+ if (conn->sendMessageLength <= MAX_PACKETFRAGMENT)
+ {
+ dataLen = conn->sendMessageLength;
+ eom = NETFLAG_EOM;
+ }
+ else
+ {
+ dataLen = MAX_PACKETFRAGMENT;
+ eom = 0;
+ }
+
+ packetLen = NET_HEADERSIZE + dataLen;
+
+ header = (unsigned int *)sendbuffer;
+ header[0] = BigLong(packetLen | (NETFLAG_DATA | eom));
+ header[1] = BigLong(conn->sendSequence);
+ memcpy(sendbuffer + NET_HEADERSIZE, conn->sendMessage, dataLen);
+
+ conn->sendSequence++;
+
+ if (NetConn_Write(conn->mysocket, (void *)&sendbuffer, packetLen, &conn->peeraddress) == (int)packetLen)
+ {
+ conn->lastSendTime = realtime;
+ packetsSent++;
+ }
}
else
{
CL_Disconnect();
// if we're connecting to a remote server, shut down any local server
if (LHNETADDRESS_GetAddressType(peeraddress) != LHNETADDRESSTYPE_LOOP && sv.active)
- Host_ShutdownServer (false);
+ Host_ShutdownServer ();
// allocate a net connection to keep track of things
cls.netcon = NetConn_Open(mysocket, peeraddress);
Con_Printf("Connection accepted to %s\n", cls.netcon->address);
return false;
}
-int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *data, int length, lhnetaddress_t *peeraddress)
+static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *data, int length, lhnetaddress_t *peeraddress)
{
int ret, c, control;
const char *s;
if (length >= 13 && !memcmp(string, "infoResponse\x0A", 13))
{
serverlist_info_t *info;
- int i, n;
+ int n;
double pingtime;
string += 13;
// legacy/old stuff move it to the menu ASAP
// build description strings for the things users care about
- dpsnprintf(serverlist_cache[n].line1, sizeof(serverlist_cache[n].line1), "%5d%c%3u/%3u %-65.65s", (int)pingtime, info->protocol != NET_PROTOCOL_VERSION ? '*' : ' ', info->numplayers, info->maxplayers, info->name);
+ dpsnprintf(serverlist_cache[n].line1, sizeof(serverlist_cache[n].line1), "%c%c%5d%c%c%c%3u/%3u %-65.65s", STRING_COLOR_TAG, pingtime >= 300 ? '1' : (pingtime >= 200 ? '3' : '7'), (int)pingtime, STRING_COLOR_TAG, STRING_COLOR_DEFAULT + '0', info->protocol != NET_PROTOCOL_VERSION ? '*' : ' ', info->numplayers, info->maxplayers, info->name);
dpsnprintf(serverlist_cache[n].line2, sizeof(serverlist_cache[n].line2), "%-21.21s %-19.19s %-17.17s %-20.20s", info->cname, info->game, info->mod, info->map);
- // if ping is especially high, display it as such
- if (pingtime >= 300)
- {
- // orange numbers (lower block)
- for (i = 0;i < 5;i++)
- if (serverlist_cache[n].line1[i] != ' ')
- serverlist_cache[n].line1[i] += 128;
- }
- else if (pingtime >= 200)
- {
- // yellow numbers (in upper block)
- for (i = 0;i < 5;i++)
- if (serverlist_cache[n].line1[i] != ' ')
- serverlist_cache[n].line1[i] -= 30;
- }
if( serverlist_cache[n].query == SQS_QUERIED ) {
ServerList_ViewList_Remove( &serverlist_cache[n] );
}
{
int i, length;
lhnetaddress_t peeraddress;
- netconn_t *conn;
- NetConn_UpdateServerStuff();
+ NetConn_UpdateSockets();
if (cls.connect_trying && cls.connect_nextsendtime < realtime)
{
if (cls.connect_remainingtries == 0)
NetConn_Write(cls.connect_mysocket, net_message.data, net_message.cursize, &cls.connect_address);
SZ_Clear(&net_message);
}
- for (i = 0;i < cl_numsockets;i++) {
- while (cl_sockets[i] && (length = NetConn_Read(cl_sockets[i], readbuffer, sizeof(readbuffer), &peeraddress)) > 0) {
+ for (i = 0;i < cl_numsockets;i++)
+ while (cl_sockets[i] && (length = NetConn_Read(cl_sockets[i], readbuffer, sizeof(readbuffer), &peeraddress)) > 0)
NetConn_ClientParsePacket(cl_sockets[i], readbuffer, length, &peeraddress);
- }
- }
NetConn_QueryQueueFrame();
if (cls.netcon && realtime > cls.netcon->timeout)
{
Con_Print("Connection timed out\n");
CL_Disconnect();
- Host_ShutdownServer (false);
+ Host_ShutdownServer ();
}
- for (conn = netconn_list;conn;conn = conn->next)
- NetConn_ReSendMessage(conn);
}
#define MAX_CHALLENGES 128
}
extern void SV_SendServerinfo (client_t *client);
-int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *data, int length, lhnetaddress_t *peeraddress)
+static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *data, int length, lhnetaddress_t *peeraddress)
{
int i, ret, clientnum, best;
double besttime;
{
int i, length;
lhnetaddress_t peeraddress;
- netconn_t *conn;
- NetConn_UpdateServerStuff();
+ NetConn_UpdateSockets();
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);
SV_DropClient(false);
}
}
- for (conn = netconn_list;conn;conn = conn->next)
- NetConn_ReSendMessage(conn);
}
void NetConn_QueryMasters(void)
}
}
-int NetConn_SendToAll(sizebuf_t *data, double blocktime)
-{
- int i, count = 0;
- unsigned char sent[MAX_SCOREBOARD];
-
- memset(sent, 0, sizeof(sent));
-
- // simultaneously wait for the first CanSendMessage and send the message,
- // then wait for a second CanSendMessage (verifying it was received), or
- // the client drops and is no longer counted
- // the loop aborts when either it runs out of clients to send to, or a
- // timeout expires
- blocktime += Sys_DoubleTime();
- do
- {
- count = 0;
- NetConn_ClientFrame();
- NetConn_ServerFrame();
- for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
- {
- if (host_client->netconnection)
- {
- if (NetConn_CanSendMessage(host_client->netconnection))
- {
- if (!sent[i])
- NetConn_SendReliableMessage(host_client->netconnection, data);
- sent[i] = true;
- }
- if (!NetConn_CanSendMessage(host_client->netconnection))
- count++;
- }
- }
- }
- while (count && Sys_DoubleTime() < blocktime);
- return count;
-}
-
static void Net_Heartbeat_f(void)
{
if (sv.active)
int i;
lhnetaddress_t tempaddress;
netconn_mempool = Mem_AllocPool("network connections", 0, NULL);
- Cmd_AddCommand("net_stats", Net_Stats_f);
- Cmd_AddCommand("net_slist", Net_Slist_f);
- Cmd_AddCommand("heartbeat", Net_Heartbeat_f);
+ Cmd_AddCommand("net_stats", Net_Stats_f, "print network statistics");
+ Cmd_AddCommand("net_slist", Net_Slist_f, "query master series and print all server information");
+ Cmd_AddCommand("heartbeat", Net_Heartbeat_f, "send a heartbeat to the master server (updates your server information)");
Cvar_RegisterVariable(&net_slist_queriespersecond);
Cvar_RegisterVariable(&net_slist_queriesperframe);
Cvar_RegisterVariable(&net_slist_timeout);