- case CCREQ_CONNECT:
- //if (developer.integer)
- 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 (developer.integer)
- 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)
- {
- // duplicate connection request
- if (realtime - client->connecttime < 2.0)
- {
- // client is still trying to connect,
- // so we send a duplicate reply
- if (developer.integer)
- 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
- {
- // 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)
- 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_ConnectClient(clientnum, conn);
- NetConn_Heartbeat(1);
- }
- else
- {
- //if (developer.integer)
- 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:
- if (developer.integer)
- Con_Printf("Datagram_ParseConnectionless: received CCREQ_SERVER_INFO from %s.\n", addressstring2);
- if (sv.active && !strcmp(MSG_ReadString(), "QUAKE"))
- {
- if (developer.integer)
- 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);
- *((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)
- Con_Printf("Datagram_ParseConnectionless: received CCREQ_PLAYER_INFO from %s.\n", addressstring2);
- if (sv.active)
+ // if the netconnection is loop, then this is the
+ // local player on a listen mode server, and it would
+ // result in duplicate printing to the console
+ // (not that the local player should be using rcon
+ // when they have the console)
+ if (host_client->netconnection && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
+ SV_ClientPrintf("%s", rcon_redirect_buffer);
+ }
+ else
+ {
+ // qw print command
+ dpsnprintf(response, sizeof(response), "\377\377\377\377n%s", rcon_redirect_buffer);
+ NetConn_WriteString(mysocket, response, peeraddress);
+ }
+ }
+ return true;
+ }
+ if (!strncmp(string, "ping", 4))
+ {
+ if (developer.integer >= 10)
+ Con_Printf("Received ping from %s, sending ack\n", addressstring2);
+ NetConn_WriteString(mysocket, "\377\377\377\377ack", peeraddress);
+ return true;
+ }
+ if (!strncmp(string, "ack", 3))
+ return true;
+ // we may not have liked the packet, but it was a command packet, so
+ // we're done processing this packet now
+ return true;
+ }
+ // 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;
+ int protocolnumber;
+ const char *protocolname;
+ data += 4;
+ length -= 4;
+ SZ_Clear(&net_message);
+ SZ_Write(&net_message, data, length);
+ MSG_BeginReading();
+ c = MSG_ReadByte();
+ switch (c)
+ {
+ case CCREQ_CONNECT:
+ if (developer.integer >= 10)
+ Con_Printf("Datagram_ParseConnectionless: received CCREQ_CONNECT from %s.\n", addressstring2);
+ if(!islocal && sv_public.integer <= -2)
+ break;
+
+ protocolname = MSG_ReadString();
+ protocolnumber = MSG_ReadByte();
+ if (strcmp(protocolname, "QUAKE") || protocolnumber != 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 (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 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 client is already spawned, re-send the
+ // serverinfo message as they'll need it to play
+ if (client->spawned)