sv_net_chan.c (6293B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 23 #include "../game/q_shared.h" 24 #include "../qcommon/qcommon.h" 25 #include "server.h" 26 27 /* 28 ============== 29 SV_Netchan_Encode 30 31 // first four bytes of the data are always: 32 long reliableAcknowledge; 33 34 ============== 35 */ 36 static void SV_Netchan_Encode( client_t *client, msg_t *msg ) { 37 long reliableAcknowledge, i, index; 38 byte key, *string; 39 int srdc, sbit, soob; 40 41 if ( msg->cursize < SV_ENCODE_START ) { 42 return; 43 } 44 45 srdc = msg->readcount; 46 sbit = msg->bit; 47 soob = msg->oob; 48 49 msg->bit = 0; 50 msg->readcount = 0; 51 msg->oob = 0; 52 53 reliableAcknowledge = MSG_ReadLong(msg); 54 55 msg->oob = soob; 56 msg->bit = sbit; 57 msg->readcount = srdc; 58 59 string = (byte *)client->lastClientCommandString; 60 index = 0; 61 // xor the client challenge with the netchan sequence number 62 key = client->challenge ^ client->netchan.outgoingSequence; 63 for (i = SV_ENCODE_START; i < msg->cursize; i++) { 64 // modify the key with the last received and with this message acknowledged client command 65 if (!string[index]) 66 index = 0; 67 if (string[index] > 127 || string[index] == '%') { 68 key ^= '.' << (i & 1); 69 } 70 else { 71 key ^= string[index] << (i & 1); 72 } 73 index++; 74 // encode the data with this key 75 *(msg->data + i) = *(msg->data + i) ^ key; 76 } 77 } 78 79 /* 80 ============== 81 SV_Netchan_Decode 82 83 // first 12 bytes of the data are always: 84 long serverId; 85 long messageAcknowledge; 86 long reliableAcknowledge; 87 88 ============== 89 */ 90 static void SV_Netchan_Decode( client_t *client, msg_t *msg ) { 91 int serverId, messageAcknowledge, reliableAcknowledge; 92 int i, index, srdc, sbit, soob; 93 byte key, *string; 94 95 srdc = msg->readcount; 96 sbit = msg->bit; 97 soob = msg->oob; 98 99 msg->oob = 0; 100 101 serverId = MSG_ReadLong(msg); 102 messageAcknowledge = MSG_ReadLong(msg); 103 reliableAcknowledge = MSG_ReadLong(msg); 104 105 msg->oob = soob; 106 msg->bit = sbit; 107 msg->readcount = srdc; 108 109 string = (byte *)client->reliableCommands[ reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ]; 110 index = 0; 111 // 112 key = client->challenge ^ serverId ^ messageAcknowledge; 113 for (i = msg->readcount + SV_DECODE_START; i < msg->cursize; i++) { 114 // modify the key with the last sent and acknowledged server command 115 if (!string[index]) 116 index = 0; 117 if (string[index] > 127 || string[index] == '%') { 118 key ^= '.' << (i & 1); 119 } 120 else { 121 key ^= string[index] << (i & 1); 122 } 123 index++; 124 // decode the data with this key 125 *(msg->data + i) = *(msg->data + i) ^ key; 126 } 127 } 128 129 /* 130 ================= 131 SV_Netchan_TransmitNextFragment 132 ================= 133 */ 134 void SV_Netchan_TransmitNextFragment( client_t *client ) { 135 Netchan_TransmitNextFragment( &client->netchan ); 136 if (!client->netchan.unsentFragments) 137 { 138 // make sure the netchan queue has been properly initialized (you never know) 139 if (!client->netchan_end_queue) { 140 Com_Error(ERR_DROP, "netchan queue is not properly initialized in SV_Netchan_TransmitNextFragment\n"); 141 } 142 // the last fragment was transmitted, check wether we have queued messages 143 if (client->netchan_start_queue) { 144 netchan_buffer_t *netbuf; 145 Com_DPrintf("#462 Netchan_TransmitNextFragment: popping a queued message for transmit\n"); 146 netbuf = client->netchan_start_queue; 147 SV_Netchan_Encode( client, &netbuf->msg ); 148 Netchan_Transmit( &client->netchan, netbuf->msg.cursize, netbuf->msg.data ); 149 // pop from queue 150 client->netchan_start_queue = netbuf->next; 151 if (!client->netchan_start_queue) { 152 Com_DPrintf("#462 Netchan_TransmitNextFragment: emptied queue\n"); 153 client->netchan_end_queue = &client->netchan_start_queue; 154 } 155 else 156 Com_DPrintf("#462 Netchan_TransmitNextFragment: remaining queued message\n"); 157 Z_Free(netbuf); 158 } 159 } 160 } 161 162 163 /* 164 =============== 165 SV_Netchan_Transmit 166 TTimo 167 https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=462 168 if there are some unsent fragments (which may happen if the snapshots 169 and the gamestate are fragmenting, and collide on send for instance) 170 then buffer them and make sure they get sent in correct order 171 ================ 172 */ 173 174 void SV_Netchan_Transmit( client_t *client, msg_t *msg) { //int length, const byte *data ) { 175 MSG_WriteByte( msg, svc_EOF ); 176 if (client->netchan.unsentFragments) { 177 netchan_buffer_t *netbuf; 178 Com_DPrintf("#462 SV_Netchan_Transmit: unsent fragments, stacked\n"); 179 netbuf = (netchan_buffer_t *)Z_Malloc(sizeof(netchan_buffer_t)); 180 // store the msg, we can't store it encoded, as the encoding depends on stuff we still have to finish sending 181 MSG_Copy(&netbuf->msg, netbuf->msgBuffer, sizeof( netbuf->msgBuffer ), msg); 182 netbuf->next = NULL; 183 // insert it in the queue, the message will be encoded and sent later 184 *client->netchan_end_queue = netbuf; 185 client->netchan_end_queue = &(*client->netchan_end_queue)->next; 186 // emit the next fragment of the current message for now 187 Netchan_TransmitNextFragment(&client->netchan); 188 } else { 189 SV_Netchan_Encode( client, msg ); 190 Netchan_Transmit( &client->netchan, msg->cursize, msg->data ); 191 } 192 } 193 194 /* 195 ================= 196 Netchan_SV_Process 197 ================= 198 */ 199 qboolean SV_Netchan_Process( client_t *client, msg_t *msg ) { 200 int ret; 201 ret = Netchan_Process( &client->netchan, msg ); 202 if (!ret) 203 return qfalse; 204 SV_Netchan_Decode( client, msg ); 205 return qtrue; 206 } 207