X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=netconn.c;h=6ad1e7e337a920f427c98acc06a508e2ba5d75b0;hb=43a1c02fbd58d42355728f7aa2b0b21286d1f783;hp=a37505ca0128ca366eca08c410d3d56cf9e6831b;hpb=58be2a1de5339cae1240076267f0c50663e80843;p=xonotic%2Fdarkplaces.git diff --git a/netconn.c b/netconn.c index a37505ca..6ad1e7e3 100755 --- a/netconn.c +++ b/netconn.c @@ -846,6 +846,8 @@ static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int len if (length < 8) return 0; + // TODO: add netgraph stuff rather than just packetloss counting... + if (protocol == PROTOCOL_QUAKEWORLD) { int sequence, sequence_ack; @@ -876,15 +878,22 @@ static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int len sequence_ack &= ~(1<<31); if (sequence <= conn->qw.incoming_sequence) { - Con_DPrint("Got a stale datagram\n"); + //Con_DPrint("Got a stale datagram\n"); return 0; } count = sequence - (conn->qw.incoming_sequence + 1); if (count > 0) { droppedDatagrams += count; - Con_DPrintf("Dropped %u datagram(s)\n", count); + //Con_DPrintf("Dropped %u datagram(s)\n", count); + while (count--) + { + conn->packetlost[conn->packetlostcounter] = true; + conn->packetlostcounter = (conn->packetlostcounter + 1) % 100; + } } + conn->packetlost[conn->packetlostcounter] = false; + conn->packetlostcounter = (conn->packetlostcounter + 1) % 100; if (reliable_ack == conn->qw.reliable_sequence) { // received, now we will be able to send another reliable message @@ -931,8 +940,15 @@ static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int len { count = sequence - conn->nq.unreliableReceiveSequence; droppedDatagrams += count; - Con_DPrintf("Dropped %u datagram(s)\n", count); + //Con_DPrintf("Dropped %u datagram(s)\n", count); + while (count--) + { + conn->packetlost[conn->packetlostcounter] = true; + conn->packetlostcounter = (conn->packetlostcounter + 1) % 100; + } } + conn->packetlost[conn->packetlostcounter] = false; + conn->packetlostcounter = (conn->packetlostcounter + 1) % 100; conn->nq.unreliableReceiveSequence = sequence + 1; conn->lastMessageTime = realtime; conn->timeout = realtime + net_messagetimeout.value; @@ -945,8 +961,8 @@ static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int len return 2; } } - else - Con_DPrint("Got a stale datagram\n"); + //else + // Con_DPrint("Got a stale datagram\n"); return 1; } else if (flags & NETFLAG_ACK) @@ -999,11 +1015,11 @@ static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int len else conn->sendMessageLength = 0; } - else - Con_DPrint("Duplicate ACK received\n"); + //else + // Con_DPrint("Duplicate ACK received\n"); } - else - Con_DPrint("Stale ACK received\n"); + //else + // Con_DPrint("Stale ACK received\n"); return 1; } else if (flags & NETFLAG_DATA) @@ -1930,210 +1946,212 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat // we're done processing this packet now return true; } - // LordHavoc: disabled netquake control packet support in server -#if 0 + // netquake control packets, supported for compatibility only, and only + // when running game protocols that are normally served via this connection + // protocol + // (this protects more modern protocols against being used for + // Quake packet flood Denial Of Service attacks) + if (length >= 5 && (i = BigLong(*((int *)data))) && (i & (~NETFLAG_LENGTH_MASK)) == (int)NETFLAG_CTL && (i & NETFLAG_LENGTH_MASK) == length && (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)) { - int c, control; - // netquake control packets, supported for compatibility only - if (length >= 5 && (control = BigLong(*((int *)data))) && (control & (~NETFLAG_LENGTH_MASK)) == (int)NETFLAG_CTL && (control & NETFLAG_LENGTH_MASK) == length) + int c = data[4]; + data += 5; + length -= 5; + switch (c) { - c = data[4]; - data += 5; - length -= 5; - switch (c) + 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) { - 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 (memcmp(data, "QUAKE", strlen("QUAKE") + 1) != 0 || (int)data[strlen("QUAKE") + 1] != NET_PROTOCOL_VERSION) { - 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); + } + 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) { - 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); + // 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 { - // see if this is a duplicate connection request + // this is a new client, find a slot for (clientnum = 0, client = svs.clients;clientnum < svs.maxclients;clientnum++, client++) - if (client->netconnection && LHNETADDRESS_Compare(peeraddress, &client->netconnection->peeraddress) == 0) + if (!client->active) break; - if (clientnum < svs.maxclients) + if (clientnum < svs.maxclients && (client->netconnection = conn = NetConn_Open(mysocket, peeraddress)) != NULL) { - // 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 + // 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 { - // 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); - } + 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; -#if 0 - case CCREQ_SERVER_INFO: + } + break; + case CCREQ_SERVER_INFO: + if (developer.integer >= 10) + Con_Printf("Datagram_ParseConnectionless: received CCREQ_SERVER_INFO from %s.\n", addressstring2); + if (sv.active && !strcmp(MSG_ReadString(), "QUAKE")) + { + int numclients; + char myaddressstring[128]; if (developer.integer >= 10) - Con_Printf("Datagram_ParseConnectionless: received CCREQ_SERVER_INFO from %s.\n", addressstring2); - if (sv.active && !strcmp(MSG_ReadString(), "QUAKE")) + Con_Printf("Datagram_ParseConnectionless: sending CCREP_SERVER_INFO 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_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); + // 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); + *((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_PLAYER_INFO: + if (developer.integer >= 10) + Con_Printf("Datagram_ParseConnectionless: received CCREQ_PLAYER_INFO from %s.\n", addressstring2); + if (sv.active) + { + int playerNumber, activeNumber, clientNumber; + client_t *client; + + playerNumber = MSG_ReadByte(); + activeNumber = -1; + for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++) + if (client->active && ++activeNumber == playerNumber) + break; + if (clientNumber != svs.maxclients) { - if (developer.integer >= 10) - Con_Printf("Datagram_ParseConnectionless: sending CCREP_SERVER_INFO 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_SERVER_INFO); - UDP_GetSocketAddr(UDP_acceptSock, &newaddr); - MSG_WriteString(&net_message, UDP_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); + 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->fields.server->frags); + MSG_WriteLong(&net_message, (int)(realtime - client->connecttime)); + MSG_WriteString(&net_message, client->netconnection ? client->netconnection->address : "botclient"); *((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_PLAYER_INFO: - if (developer.integer >= 10) - Con_Printf("Datagram_ParseConnectionless: received CCREQ_PLAYER_INFO from %s.\n", addressstring2); - if (sv.active) - { - int playerNumber, activeNumber, clientNumber; - client_t *client; - - playerNumber = MSG_ReadByte(); - 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); - // 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->fields.server->frags); - MSG_WriteLong(&net_message, (int)(realtime - client->connecttime)); - MSG_WriteString(&net_message, client->netconnection ? client->netconnection->address : "botclient"); - *((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_RULE_INFO: - if (developer.integer >= 10) - Con_Printf("Datagram_ParseConnectionless: received CCREQ_RULE_INFO from %s.\n", addressstring2); - if (sv.active) - { - char *prevCvarName; - cvar_t *var; + } + break; + case CCREQ_RULE_INFO: + if (developer.integer >= 10) + Con_Printf("Datagram_ParseConnectionless: received CCREQ_RULE_INFO from %s.\n", addressstring2); + if (sv.active) + { + char *prevCvarName; + cvar_t *var; - // find the search start location - prevCvarName = MSG_ReadString(); - var = Cvar_FindVarAfter(prevCvarName, CVAR_NOTIFY); + // 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)); - NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress); - SZ_Clear(&net_message); + // 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); } - break; -#endif - default: - break; + *((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); } - // we may not have liked the packet, but it was a valid control - // packet, so we're done processing this packet now - return true; + break; + default: + break; } + // we may not have liked the packet, but it was a valid control + // packet, so we're done processing this packet now + return true; } -#endif if (host_client) { if ((ret = NetConn_ReceivedMessage(host_client->netconnection, data, length, sv.protocol)) == 2)