+ if (length >= 12 && !memcmp(string, "getchallenge", 12))
+ {
+ for (i = 0, best = 0, besttime = realtime;i < MAX_CHALLENGES;i++)
+ {
+ if (!LHNETADDRESS_Compare(peeraddress, &challenge[i].address))
+ break;
+ if (besttime > challenge[i].time)
+ besttime = challenge[best = i].time;
+ }
+ // if we did not find an exact match, choose the oldest and
+ // update address and string
+ if (i == MAX_CHALLENGES)
+ {
+ i = best;
+ challenge[i].address = *peeraddress;
+ NetConn_BuildChallengeString(challenge[i].string, sizeof(challenge[i].string));
+ }
+ challenge[i].time = realtime;
+ // send the challenge
+ NetConn_WriteString(mysocket, va("\377\377\377\377challenge %s", challenge[i].string), peeraddress);
+ return true;
+ }
+ if (length > 8 && !memcmp(string, "connect\\", 8))
+ {
+ string += 7;
+ length -= 7;
+ if ((s = SearchInfostring(string, "challenge")))
+ {
+ // 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)
+ {
+ // check engine protocol
+ if (strcmp(SearchInfostring(string, "protocol"), "darkplaces 3"))
+ {
+ if (developer.integer)
+ Con_Printf("Datagram_ParseConnectionless: sending \"reject Wrong game protocol.\" to %s.\n", addressstring2);
+ NetConn_WriteString(mysocket, "\377\377\377\377reject Wrong game protocol.", peeraddress);
+ }
+ 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->netconnection->connecttime < 2.0)
+ {
+ // client is still trying to connect,
+ // so we send a duplicate reply
+ if (developer.integer)
+ Con_Printf("Datagram_ParseConnectionless: sending duplicate accept to %s.\n", addressstring2);
+ NetConn_WriteString(mysocket, "\377\377\377\377accept", peeraddress);
+ }
+ // only kick if old connection seems dead
+ if (realtime - client->netconnection->lastMessageTime >= net_messagerejointimeout.value)
+ {
+ // kick off connection and await retry
+ client->deadsocket = true;
+ }
+ }
+ 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 ((client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_clients_mempool)))
+ {
+ if ((conn = NetConn_Open(mysocket, peeraddress)))
+ {
+ // allocated connection
+ LHNETADDRESS_ToString(peeraddress, conn->address, sizeof(conn->address), true);
+ if (developer.integer)
+ 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_ConnectClient(clientnum, conn);
+ NetConn_Heartbeat(1);
+ }
+ else
+ EntityFrame4_FreeDatabase(client->entitydatabase4);
+ }
+ }
+ else
+ {
+ // server is full
+ if (developer.integer)
+ 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;
+ }