X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=netconn.c;h=ba857902e35540817b143ccdcb4dce52c3bd4483;hb=a19dce25671ecfa28e4eb3861f8636750bf3ba68;hp=62dba98428e1999da933f73c26852af06a893e90;hpb=4e8af786c2089e92eb77d2626cb1e6077a71db1e;p=xonotic%2Fdarkplaces.git diff --git a/netconn.c b/netconn.c index 62dba984..ba857902 100755 --- a/netconn.c +++ b/netconn.c @@ -27,7 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define DPMASTER_PORT 27950 // note this defaults on for dedicated servers, off for listen servers -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)"}; +cvar_t sv_public = {0, "sv_public", "0", "1: advertises this server on the master server (so that players can find it in the server browser); 0: allow direct queries only; -1: do not respond to direct queries; -2: do not allow anyone to connect"}; static cvar_t sv_heartbeatperiod = {CVAR_SAVE, "sv_heartbeatperiod", "120", "how often to send heartbeat in seconds (only used if sv_public is 1)"}; static cvar_t sv_masters [] = @@ -71,8 +71,8 @@ sizebuf_t net_message; static unsigned char net_message_buf[NET_MAXMESSAGE]; 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 net_connectfloodblockingtimeout = {0, "net_connectfloodblockingtimeout", "5", "when a connection packet is received, it will block all future connect packets from that IP address for this many seconds (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)"}; @@ -126,6 +126,10 @@ 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"}; +char net_extresponse[NET_EXTRESPONSE_MAX][1400]; +int net_extresponse_count = 0; +int net_extresponse_last = 0; + // ServerList interface serverlist_mask_t serverlist_andmasks[SERVERLIST_ANDMASKCOUNT]; serverlist_mask_t serverlist_ormasks[SERVERLIST_ORMASKCOUNT]; @@ -576,7 +580,7 @@ int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolvers { 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)); + Con_Printf("NetConn_SendUnreliableMessage: reliable message too big (%u > %u)\n", conn->message.cursize, (int)sizeof(conn->sendMessage)); conn->message.overflowed = true; return -1; } @@ -787,10 +791,15 @@ netconn_t *NetConn_Open(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress) return conn; } +void NetConn_ClearConnectFlood(lhnetaddress_t *peeraddress); void NetConn_Close(netconn_t *conn) { netconn_t *c; // remove connection from list + + // allow the client to reconnect immediately + NetConn_ClearConnectFlood(&(conn->peeraddress)); + if (conn == netconn_list) netconn_list = conn->next; else @@ -841,7 +850,7 @@ void NetConn_UpdateSockets(void) } } -static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int length, protocolversion_t protocol) +static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int length, protocolversion_t protocol, double newtimeout) { if (length < 8) return 0; @@ -908,7 +917,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int len if (reliable_message) conn->qw.incoming_reliable_sequence ^= 1; conn->lastMessageTime = realtime; - conn->timeout = realtime + net_messagetimeout.value; + conn->timeout = realtime + newtimeout; unreliableMessagesReceived++; SZ_Clear(&net_message); SZ_Write(&net_message, data, length); @@ -951,7 +960,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int len conn->packetlostcounter = (conn->packetlostcounter + 1) % 100; conn->nq.unreliableReceiveSequence = sequence + 1; conn->lastMessageTime = realtime; - conn->timeout = realtime + net_messagetimeout.value; + conn->timeout = realtime + newtimeout; unreliableMessagesReceived++; if (length > 0) { @@ -975,7 +984,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int len if (conn->nq.ackSequence != conn->nq.sendSequence) Con_DPrint("ack sequencing error\n"); conn->lastMessageTime = realtime; - conn->timeout = realtime + net_messagetimeout.value; + conn->timeout = realtime + newtimeout; if (conn->sendMessageLength > MAX_PACKETFRAGMENT) { unsigned int packetLen; @@ -1031,7 +1040,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int len if (sequence == conn->nq.receiveSequence) { conn->lastMessageTime = realtime; - conn->timeout = realtime + net_messagetimeout.value; + conn->timeout = realtime + newtimeout; conn->nq.receiveSequence++; if( conn->receiveMessageLength + length <= (int)sizeof( conn->receiveMessage ) ) { memcpy(conn->receiveMessage + conn->receiveMessageLength, data, length); @@ -1087,14 +1096,14 @@ void NetConn_ConnectionEstablished(lhnetsocket_t *mysocket, lhnetaddress_t *peer Cmd_ForwardStringToServer("new"); if (cls.protocol == PROTOCOL_QUAKE) { - // write a keepalive (svc_nop) as it seems to greatly improve the + // write a keepalive (clc_nop) as it seems to greatly improve the // chances of connecting to a netquake server sizebuf_t msg; unsigned char buf[4]; memset(&msg, 0, sizeof(msg)); msg.data = buf; msg.maxsize = sizeof(buf); - MSG_WriteChar(&msg, svc_nop); + MSG_WriteChar(&msg, clc_nop); NetConn_SendUnreliableMessage(cls.netcon, &msg, cls.protocol); } } @@ -1338,6 +1347,15 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat serverlist_querywaittime = realtime + 3; return true; } + if (!strncmp(string, "extResponse ", 12)) + { + ++net_extresponse_count; + if(net_extresponse_count > NET_EXTRESPONSE_MAX) + net_extresponse_count = NET_EXTRESPONSE_MAX; + net_extresponse_last = (net_extresponse_last + 1) % NET_EXTRESPONSE_MAX; + dpsnprintf(net_extresponse[net_extresponse_last], sizeof(net_extresponse[net_extresponse_last]), "%s %s", addressstring2, string + 12); + return true; + } if (!strncmp(string, "ping", 4)) { if (developer.integer >= 10) @@ -1422,7 +1440,7 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat return true; } // quakeworld ingame packet - if (fromserver && cls.protocol == PROTOCOL_QUAKEWORLD && length >= 8 && (ret = NetConn_ReceivedMessage(cls.netcon, data, length, cls.protocol)) == 2) + if (fromserver && cls.protocol == PROTOCOL_QUAKEWORLD && length >= 8 && (ret = NetConn_ReceivedMessage(cls.netcon, data, length, cls.protocol, net_messagetimeout.value)) == 2) { ret = 0; CL_ParseServerMessage(); @@ -1506,7 +1524,7 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat return true; } ret = 0; - if (fromserver && length >= (int)NET_HEADERSIZE && (ret = NetConn_ReceivedMessage(cls.netcon, data, length, cls.protocol)) == 2) + if (fromserver && length >= (int)NET_HEADERSIZE && (ret = NetConn_ReceivedMessage(cls.netcon, data, length, cls.protocol, net_messagetimeout.value)) == 2) CL_ParseServerMessage(); return ret; } @@ -1695,7 +1713,7 @@ static qboolean NetConn_BuildStatusResponse(const char* challenge, char* out_msg client_t *cl = &svs.clients[i]; if (cl->active) { - int nameind, cleanind; + int nameind, cleanind, pingvalue; char curchar; char cleanname [sizeof(cl->name)]; @@ -1713,9 +1731,14 @@ static qboolean NetConn_BuildStatusResponse(const char* challenge, char* out_msg } } while (curchar != '\0'); + pingvalue = (int)(cl->ping * 1000.0f); + if(cl->netconnection) + pingvalue = bound(1, pingvalue, 9999); + else + pingvalue = 0; length = dpsnprintf(ptr, left, "%d %d \"%s\"\n", cl->frags, - (int)(cl->ping * 1000.0f), + pingvalue, cleanname); if(length < 0) return false; @@ -1728,13 +1751,72 @@ static qboolean NetConn_BuildStatusResponse(const char* challenge, char* out_msg return true; } +static qboolean NetConn_PreventConnectFlood(lhnetaddress_t *peeraddress) +{ + int floodslotnum, bestfloodslotnum; + double bestfloodtime; + lhnetaddress_t noportpeeraddress; + // see if this is a connect flood + noportpeeraddress = *peeraddress; + LHNETADDRESS_SetPort(&noportpeeraddress, 0); + bestfloodslotnum = 0; + bestfloodtime = sv.connectfloodaddresses[bestfloodslotnum].lasttime; + for (floodslotnum = 0;floodslotnum < MAX_CONNECTFLOODADDRESSES;floodslotnum++) + { + if (bestfloodtime >= sv.connectfloodaddresses[floodslotnum].lasttime) + { + bestfloodtime = sv.connectfloodaddresses[floodslotnum].lasttime; + bestfloodslotnum = floodslotnum; + } + if (sv.connectfloodaddresses[floodslotnum].lasttime && LHNETADDRESS_Compare(&noportpeeraddress, &sv.connectfloodaddresses[floodslotnum].address) == 0) + { + // this address matches an ongoing flood address + if (realtime < sv.connectfloodaddresses[floodslotnum].lasttime + net_connectfloodblockingtimeout.value) + { + // renew the ban on this address so it does not expire + // until the flood has subsided + sv.connectfloodaddresses[floodslotnum].lasttime = realtime; + //Con_Printf("Flood detected!\n"); + return true; + } + // the flood appears to have subsided, so allow this + bestfloodslotnum = floodslotnum; // reuse the same slot + break; + } + } + // begin a new timeout on this address + sv.connectfloodaddresses[bestfloodslotnum].address = noportpeeraddress; + sv.connectfloodaddresses[bestfloodslotnum].lasttime = realtime; + //Con_Printf("Flood detection initiated!\n"); + return false; +} + +void NetConn_ClearConnectFlood(lhnetaddress_t *peeraddress) +{ + int floodslotnum; + lhnetaddress_t noportpeeraddress; + // see if this is a connect flood + noportpeeraddress = *peeraddress; + LHNETADDRESS_SetPort(&noportpeeraddress, 0); + for (floodslotnum = 0;floodslotnum < MAX_CONNECTFLOODADDRESSES;floodslotnum++) + { + if (sv.connectfloodaddresses[floodslotnum].lasttime && LHNETADDRESS_Compare(&noportpeeraddress, &sv.connectfloodaddresses[floodslotnum].address) == 0) + { + // this address matches an ongoing flood address + // remove the ban + sv.connectfloodaddresses[floodslotnum].address.addresstype = LHNETADDRESSTYPE_NONE; + sv.connectfloodaddresses[floodslotnum].lasttime = 0; + //Con_Printf("Flood cleared!\n"); + } + } +} + 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; - netconn_t *conn; char *s, *string, response[1400], addressstring2[128], stringbuf[16384]; if (!sv.active) @@ -1769,7 +1851,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat Com_HexDumpToConsole(data, length); } - if (length >= 12 && !memcmp(string, "getchallenge", 12)) + if (length >= 12 && !memcmp(string, "getchallenge", 12) && sv_public.integer > -2) { for (i = 0, best = 0, besttime = realtime;i < MAX_CHALLENGES;i++) { @@ -1791,88 +1873,90 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat NetConn_WriteString(mysocket, va("\377\377\377\377challenge %s", challenge[i].string), peeraddress); return true; } - if (length > 8 && !memcmp(string, "connect\\", 8)) + if (length > 8 && !memcmp(string, "connect\\", 8) && sv_public.integer > -2) { string += 7; length -= 7; - if ((s = SearchInfostring(string, "challenge"))) + + if (!(s = SearchInfostring(string, "challenge"))) + return true; + // validate the challenge + for (i = 0;i < MAX_CHALLENGES;i++) + if (!LHNETADDRESS_Compare(peeraddress, &challenge[i].address) && !strcmp(challenge[i].string, s)) + break; + // if the challenge is not recognized, drop the packet + if (i == MAX_CHALLENGES) + return true; + + // check engine protocol + if (strcmp(SearchInfostring(string, "protocol"), "darkplaces 3")) { - // validate the challenge - for (i = 0;i < MAX_CHALLENGES;i++) - if (!LHNETADDRESS_Compare(peeraddress, &challenge[i].address) && !strcmp(challenge[i].string, s)) - break; - if (i < MAX_CHALLENGES) + if (developer.integer >= 10) + Con_Printf("Datagram_ParseConnectionless: sending \"reject Wrong game protocol.\" to %s.\n", addressstring2); + NetConn_WriteString(mysocket, "\377\377\377\377reject Wrong game protocol.", peeraddress); + return true; + } + + // see if this is a duplicate connection request or a disconnected + // client who is rejoining to the same client slot + for (clientnum = 0, client = svs.clients;clientnum < svs.maxclients;clientnum++, client++) + { + if (client->netconnection && LHNETADDRESS_Compare(peeraddress, &client->netconnection->peeraddress) == 0) { - // check engine protocol - if (strcmp(SearchInfostring(string, "protocol"), "darkplaces 3")) + // this is a known client... + if (client->spawned) { + // client crashed and is coming back, + // keep their stuff intact if (developer.integer >= 10) - Con_Printf("Datagram_ParseConnectionless: sending \"reject Wrong game protocol.\" to %s.\n", addressstring2); - NetConn_WriteString(mysocket, "\377\377\377\377reject Wrong game protocol.", peeraddress); + Con_Printf("Datagram_ParseConnectionless: sending \"accept\" to %s.\n", addressstring2); + NetConn_WriteString(mysocket, "\377\377\377\377accept", peeraddress); + SV_VM_Begin(); + SV_SendServerinfo(client); + SV_VM_End(); } else { - // see if this is a duplicate connection request - for (clientnum = 0, client = svs.clients;clientnum < svs.maxclients;clientnum++, client++) - if (client->netconnection && LHNETADDRESS_Compare(peeraddress, &client->netconnection->peeraddress) == 0) - break; - if (clientnum < svs.maxclients && realtime - client->connecttime < net_messagerejointimeout.value) - { - // client is still trying to connect, - // so we send a duplicate reply - if (developer.integer >= 10) - Con_Printf("Datagram_ParseConnectionless: sending duplicate accept to %s.\n", addressstring2); - NetConn_WriteString(mysocket, "\377\377\377\377accept", peeraddress); - } -#if 0 - else if (clientnum < svs.maxclients) - { - if (realtime - client->netconnection->lastMessageTime >= net_messagerejointimeout.value) - { - // client crashed and is coming back, keep their stuff intact - SV_SendServerinfo(client); - //host_client = client; - //SV_DropClient (true); - } - // else ignore them - } -#endif - else - { - // this is a new client, find a slot - for (clientnum = 0, client = svs.clients;clientnum < svs.maxclients;clientnum++, client++) - if (!client->active) - break; - if (clientnum < svs.maxclients) - { - // prepare the client struct - if ((conn = NetConn_Open(mysocket, peeraddress))) - { - // allocated connection - if (developer.integer >= 10) - Con_Printf("Datagram_ParseConnectionless: sending \"accept\" to %s.\n", conn->address); - NetConn_WriteString(mysocket, "\377\377\377\377accept", peeraddress); - // now set up the client - SV_VM_Begin(); - SV_ConnectClient(clientnum, conn); - SV_VM_End(); - NetConn_Heartbeat(1); - } - } - else - { - // server is full - if (developer.integer >= 10) - Con_Printf("Datagram_ParseConnectionless: sending \"reject Server is full.\" to %s.\n", addressstring2); - NetConn_WriteString(mysocket, "\377\377\377\377reject Server is full.", peeraddress); - } - } + // client is still trying to connect, + // so we send a duplicate reply + if (developer.integer >= 10) + Con_Printf("Datagram_ParseConnectionless: sending duplicate accept to %s.\n", addressstring2); + NetConn_WriteString(mysocket, "\377\377\377\377accept", peeraddress); } + return true; + } + } + + if (NetConn_PreventConnectFlood(peeraddress)) + return true; + + // find an empty client slot for this new client + for (clientnum = 0, client = svs.clients;clientnum < svs.maxclients;clientnum++, client++) + { + netconn_t *conn; + if (!client->active && (conn = NetConn_Open(mysocket, peeraddress))) + { + // allocated connection + if (developer.integer >= 10) + Con_Printf("Datagram_ParseConnectionless: sending \"accept\" to %s.\n", conn->address); + NetConn_WriteString(mysocket, "\377\377\377\377accept", peeraddress); + // now set up the client + SV_VM_Begin(); + SV_ConnectClient(clientnum, conn); + SV_VM_End(); + NetConn_Heartbeat(1); + return true; } } + + // no empty slots found - server is full + if (developer.integer >= 10) + Con_Printf("Datagram_ParseConnectionless: sending \"reject Server is full.\" to %s.\n", addressstring2); + NetConn_WriteString(mysocket, "\377\377\377\377reject Server is full.", peeraddress); + return true; } - if (length >= 7 && !memcmp(string, "getinfo", 7)) + if (length >= 7 && !memcmp(string, "getinfo", 7) && sv_public.integer > -1) { const char *challenge = NULL; @@ -1888,7 +1972,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat } return true; } - if (length >= 9 && !memcmp(string, "getstatus", 9)) + if (length >= 9 && !memcmp(string, "getstatus", 9) && sv_public.integer > -1) { const char *challenge = NULL; @@ -1972,106 +2056,109 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat case CCREQ_CONNECT: if (developer.integer >= 10) Con_Printf("Datagram_ParseConnectionless: received CCREQ_CONNECT from %s.\n", addressstring2); - if (length >= (int)strlen("QUAKE") + 1 + 1) + if (length < (int)strlen("QUAKE") + 1 + 1) + break; + if(sv_public.integer <= -2) + break; + + if (memcmp(data, "QUAKE", strlen("QUAKE") + 1) != 0 || (int)data[strlen("QUAKE") + 1] != NET_PROTOCOL_VERSION) + { + if (developer.integer >= 10) + Con_Printf("Datagram_ParseConnectionless: sending CCREP_REJECT \"Incompatible version.\" to %s.\n", addressstring2); + 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)); + NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress); + SZ_Clear(&net_message); + break; + } + + // see if this connect request comes from a known client + for (clientnum = 0, client = svs.clients;clientnum < svs.maxclients;clientnum++, client++) { - if (memcmp(data, "QUAKE", strlen("QUAKE") + 1) != 0 || (int)data[strlen("QUAKE") + 1] != NET_PROTOCOL_VERSION) + if (client->netconnection && LHNETADDRESS_Compare(peeraddress, &client->netconnection->peeraddress) == 0) { + // this is either a duplicate connection request + // or coming back from a timeout + // (if so, keep their stuff intact) + + // send a reply if (developer.integer >= 10) - Con_Printf("Datagram_ParseConnectionless: sending CCREP_REJECT \"Incompatible version.\" to %s.\n", addressstring2); + Con_Printf("Datagram_ParseConnectionless: sending duplicate CCREP_ACCEPT to %s.\n", addressstring2); 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"); + MSG_WriteByte(&net_message, CCREP_ACCEPT); + MSG_WriteLong(&net_message, LHNETADDRESS_GetPort(LHNET_AddressFromSocket(client->netconnection->mysocket))); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress); SZ_Clear(&net_message); - } - else - { - // see if this is a duplicate connection request - for (clientnum = 0, client = svs.clients;clientnum < svs.maxclients;clientnum++, client++) - if (client->netconnection && LHNETADDRESS_Compare(peeraddress, &client->netconnection->peeraddress) == 0) - break; - if (clientnum < svs.maxclients) - { - // duplicate connection request - if (realtime - client->connecttime < 2.0) - { - // client is still trying to connect, - // so we send a duplicate reply - if (developer.integer >= 10) - Con_Printf("Datagram_ParseConnectionless: sending duplicate CCREP_ACCEPT to %s.\n", addressstring2); - SZ_Clear(&net_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))); - *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); - NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress); - SZ_Clear(&net_message); - } -#if 0 - else if (realtime - client->netconnection->lastMessageTime >= net_messagerejointimeout.value) - { - SV_SendServerinfo(client); - // the old client hasn't sent us anything - // in quite a while, so kick off and let - // the retry take care of it... - //host_client = client; - //SV_DropClient (true); - } -#endif - } - else + + // if client is already spawned, re-send the + // serverinfo message as they'll need it to play + if (client->spawned) { - // this is a new client, find a slot - for (clientnum = 0, client = svs.clients;clientnum < svs.maxclients;clientnum++, client++) - if (!client->active) - break; - if (clientnum < svs.maxclients && (client->netconnection = conn = NetConn_Open(mysocket, peeraddress)) != NULL) - { - // connect to the client - // everything is allocated, just fill in the details - strlcpy (conn->address, addressstring2, sizeof (conn->address)); - if (developer.integer >= 10) - Con_Printf("Datagram_ParseConnectionless: sending CCREP_ACCEPT to %s.\n", addressstring2); - // send back the info about the server connection - SZ_Clear(&net_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))); - *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); - NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress); - SZ_Clear(&net_message); - // now set up the client struct - SV_VM_Begin(); - SV_ConnectClient(clientnum, conn); - SV_VM_End(); - NetConn_Heartbeat(1); - } - else - { - if (developer.integer >= 10) - Con_Printf("Datagram_ParseConnectionless: sending CCREP_REJECT \"Server is full.\" to %s.\n", addressstring2); - // no room; try to let player 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)); - NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress); - SZ_Clear(&net_message); - } + SV_VM_Begin(); + SV_SendServerinfo(client); + SV_VM_End(); } + return true; + } + } + + // this is a new client, check for connection flood + if (NetConn_PreventConnectFlood(peeraddress)) + break; + + // find a slot for the new client + for (clientnum = 0, client = svs.clients;clientnum < svs.maxclients;clientnum++, client++) + { + netconn_t *conn; + if (!client->active && (client->netconnection = conn = NetConn_Open(mysocket, peeraddress)) != NULL) + { + // connect to the client + // everything is allocated, just fill in the details + strlcpy (conn->address, addressstring2, sizeof (conn->address)); + if (developer.integer >= 10) + Con_Printf("Datagram_ParseConnectionless: sending CCREP_ACCEPT to %s.\n", addressstring2); + // send back the info about the server connection + SZ_Clear(&net_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))); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress); + SZ_Clear(&net_message); + // now set up the client struct + SV_VM_Begin(); + SV_ConnectClient(clientnum, conn); + SV_VM_End(); + NetConn_Heartbeat(1); + return true; } } + + if (developer.integer >= 10) + Con_Printf("Datagram_ParseConnectionless: sending CCREP_REJECT \"Server is full.\" to %s.\n", addressstring2); + // no room; try to let player 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)); + NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress); + SZ_Clear(&net_message); break; case CCREQ_SERVER_INFO: if (developer.integer >= 10) Con_Printf("Datagram_ParseConnectionless: received CCREQ_SERVER_INFO from %s.\n", addressstring2); + if(sv_public.integer <= -1) + break; if (sv.active && !strcmp(MSG_ReadString(), "QUAKE")) { int numclients; @@ -2101,6 +2188,8 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat case CCREQ_PLAYER_INFO: if (developer.integer >= 10) Con_Printf("Datagram_ParseConnectionless: received CCREQ_PLAYER_INFO from %s.\n", addressstring2); + if(sv_public.integer <= -1) + break; if (sv.active) { int playerNumber, activeNumber, clientNumber; @@ -2132,6 +2221,8 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat case CCREQ_RULE_INFO: if (developer.integer >= 10) Con_Printf("Datagram_ParseConnectionless: received CCREQ_RULE_INFO from %s.\n", addressstring2); + if(sv_public.integer <= -1) + break; if (sv.active) { char *prevCvarName; @@ -2165,7 +2256,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat } if (host_client) { - if ((ret = NetConn_ReceivedMessage(host_client->netconnection, data, length, sv.protocol)) == 2) + 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(); @@ -2309,7 +2400,7 @@ void NetConn_Heartbeat(int priority) // make advertising optional and don't advertise singleplayer games, and // only send a heartbeat as often as the admin wants - if (sv.active && sv_public.integer && svs.maxclients >= 2 && (priority > 1 || realtime > nextheartbeattime)) + if (sv.active && sv_public.integer > 0 && svs.maxclients >= 2 && (priority > 1 || realtime > nextheartbeattime)) { nextheartbeattime = realtime + sv_heartbeatperiod.value; for (masternum = 0;sv_masters[masternum].name;masternum++) @@ -2393,8 +2484,8 @@ void NetConn_Init(void) Cvar_RegisterVariable(&net_slist_timeout); Cvar_RegisterVariable(&net_slist_maxtries); Cvar_RegisterVariable(&net_messagetimeout); - Cvar_RegisterVariable(&net_messagerejointimeout); Cvar_RegisterVariable(&net_connecttimeout); + Cvar_RegisterVariable(&net_connectfloodblockingtimeout); Cvar_RegisterVariable(&cl_netlocalping); Cvar_RegisterVariable(&cl_netpacketloss); Cvar_RegisterVariable(&hostname); @@ -2413,7 +2504,7 @@ void NetConn_Init(void) { if (LHNETADDRESS_FromString(&tempaddress, com_argv[i + 1], 0) == 1) { - Con_Printf("-ip option used, setting net_address to \"%s\"\n"); + Con_Printf("-ip option used, setting net_address to \"%s\"\n", com_argv[i + 1]); Cvar_SetQuick(&net_address, com_argv[i + 1]); } else