sv_client.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. // sv_client.c -- server code for dealing with clients
  2. // leave this as first line for PCH reasons...
  3. //
  4. #include "../server/exe_headers.h"
  5. #include "server.h"
  6. /*
  7. ==================
  8. SV_DirectConnect
  9. A "connect" OOB command has been received
  10. ==================
  11. */
  12. void SV_DirectConnect( netadr_t from ) {
  13. char userinfo[MAX_INFO_STRING];
  14. int i;
  15. client_t *cl, *newcl;
  16. MAC_STATIC client_t temp;
  17. gentity_t *ent;
  18. int clientNum;
  19. int version;
  20. int qport;
  21. int challenge;
  22. char *denied;
  23. Com_DPrintf ("SVC_DirectConnect ()\n");
  24. Q_strncpyz( userinfo, Cmd_Argv(1), sizeof(userinfo) );
  25. version = atoi( Info_ValueForKey( userinfo, "protocol" ) );
  26. if ( version != PROTOCOL_VERSION ) {
  27. NET_OutOfBandPrint( NS_SERVER, from, "print\nServer uses protocol version %i.\n", PROTOCOL_VERSION );
  28. Com_DPrintf (" rejected connect from version %i\n", version);
  29. return;
  30. }
  31. qport = atoi( Info_ValueForKey( userinfo, "qport" ) );
  32. challenge = atoi( Info_ValueForKey( userinfo, "challenge" ) );
  33. // see if the challenge is valid (local clients don't need to challenge)
  34. if ( !NET_IsLocalAddress (from) ) {
  35. NET_OutOfBandPrint( NS_SERVER, from, "print\nNo challenge for address.\n" );
  36. return;
  37. } else {
  38. // force the "ip" info key to "localhost"
  39. Info_SetValueForKey( userinfo, "ip", "localhost" );
  40. }
  41. newcl = &temp;
  42. memset (newcl, 0, sizeof(client_t));
  43. // if there is already a slot for this ip, reuse it
  44. for (i=0,cl=svs.clients ; i < 1 ; i++,cl++)
  45. {
  46. if ( cl->state == CS_FREE ) {
  47. continue;
  48. }
  49. if ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress )
  50. && ( cl->netchan.qport == qport
  51. || from.port == cl->netchan.remoteAddress.port ) )
  52. {
  53. if (( sv.time - cl->lastConnectTime)
  54. < (sv_reconnectlimit->integer * 1000))
  55. {
  56. Com_DPrintf ("%s:reconnect rejected : too soon\n", NET_AdrToString (from));
  57. return;
  58. }
  59. Com_Printf ("%s:reconnect\n", NET_AdrToString (from));
  60. newcl = cl;
  61. goto gotnewcl;
  62. }
  63. }
  64. newcl = NULL;
  65. for ( i = 0; i < 1 ; i++ ) {
  66. cl = &svs.clients[i];
  67. if (cl->state == CS_FREE) {
  68. newcl = cl;
  69. break;
  70. }
  71. }
  72. if ( !newcl ) {
  73. NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is full.\n" );
  74. Com_DPrintf ("Rejected a connection.\n");
  75. return;
  76. }
  77. gotnewcl:
  78. // build a new connection
  79. // accept the new client
  80. // this is the only place a client_t is ever initialized
  81. *newcl = temp;
  82. clientNum = newcl - svs.clients;
  83. ent = SV_GentityNum( clientNum );
  84. newcl->gentity = ent;
  85. // save the address
  86. Netchan_Setup (NS_SERVER, &newcl->netchan , from, qport);
  87. // save the userinfo
  88. Q_strncpyz( newcl->userinfo, userinfo, sizeof(newcl->userinfo) );
  89. // get the game a chance to reject this connection or modify the userinfo
  90. denied = ge->ClientConnect( clientNum, qtrue, eSavedGameJustLoaded ); // firstTime = qtrue
  91. if ( denied ) {
  92. NET_OutOfBandPrint( NS_SERVER, from, "print\n%s\n", denied );
  93. Com_DPrintf ("Game rejected a connection: %s.\n", denied);
  94. return;
  95. }
  96. SV_UserinfoChanged( newcl );
  97. // send the connect packet to the client
  98. NET_OutOfBandPrint( NS_SERVER, from, "connectResponse" );
  99. newcl->state = CS_CONNECTED;
  100. newcl->nextSnapshotTime = sv.time;
  101. newcl->lastPacketTime = sv.time;
  102. newcl->lastConnectTime = sv.time;
  103. // when we receive the first packet from the client, we will
  104. // notice that it is from a different serverid and that the
  105. // gamestate message was not just sent, forcing a retransmit
  106. newcl->gamestateMessageNum = -1;
  107. }
  108. /*
  109. =====================
  110. SV_DropClient
  111. Called when the player is totally leaving the server, either willingly
  112. or unwillingly. This is NOT called if the entire server is quiting
  113. or crashing -- SV_FinalMessage() will handle that
  114. =====================
  115. */
  116. void SV_DropClient( client_t *drop, const char *reason ) {
  117. if ( drop->state == CS_ZOMBIE ) {
  118. return; // already dropped
  119. }
  120. drop->state = CS_ZOMBIE; // become free in a few seconds
  121. if (drop->download) {
  122. FS_FreeFile (drop->download);
  123. drop->download = NULL;
  124. }
  125. // call the prog function for removing a client
  126. // this will remove the body, among other things
  127. ge->ClientDisconnect( drop - svs.clients );
  128. // tell everyone why they got dropped
  129. SV_SendServerCommand( NULL, "print \"%s %s\n\"", drop->name, reason );
  130. // add the disconnect command
  131. SV_SendServerCommand( drop, "disconnect" );
  132. }
  133. /*
  134. ================
  135. SV_SendClientGameState
  136. Sends the first message from the server to a connected client.
  137. This will be sent on the initial connection and upon each new map load.
  138. It will be resent if the client acknowledges a later message but has
  139. the wrong gamestate.
  140. ================
  141. */
  142. void SV_SendClientGameState( client_t *client ) {
  143. int start;
  144. msg_t msg;
  145. byte msgBuffer[MAX_MSGLEN];
  146. Com_DPrintf ("SV_SendGameState() for %s\n", client->name);
  147. client->state = CS_PRIMED;
  148. // when we receive the first packet from the client, we will
  149. // notice that it is from a different serverid and that the
  150. // gamestate message was not just sent, forcing a retransmit
  151. client->gamestateMessageNum = client->netchan.outgoingSequence;
  152. // clear the reliable message list for this client
  153. client->reliableSequence = 0;
  154. client->reliableAcknowledge = 0;
  155. MSG_Init( &msg, msgBuffer, sizeof( msgBuffer ) );
  156. // send the gamestate
  157. MSG_WriteByte( &msg, svc_gamestate );
  158. MSG_WriteLong( &msg, client->reliableSequence );
  159. // write the configstrings
  160. for ( start = 0 ; start < MAX_CONFIGSTRINGS ; start++ ) {
  161. if (sv.configstrings[start][0]) {
  162. MSG_WriteByte( &msg, svc_configstring );
  163. MSG_WriteShort( &msg, start );
  164. MSG_WriteString( &msg, sv.configstrings[start] );
  165. }
  166. }
  167. MSG_WriteByte( &msg, 0 );
  168. // check for overflow
  169. if ( msg.overflowed ) {
  170. Com_Printf ("WARNING: GameState overflowed for %s\n", client->name);
  171. }
  172. // deliver this to the client
  173. SV_SendMessageToClient( &msg, client );
  174. }
  175. /*
  176. ==================
  177. SV_ClientEnterWorld
  178. ==================
  179. */
  180. void SV_ClientEnterWorld( client_t *client, usercmd_t *cmd, SavedGameJustLoaded_e eSavedGameJustLoaded ) {
  181. int clientNum;
  182. gentity_t *ent;
  183. Com_DPrintf ("SV_ClientEnterWorld() from %s\n", client->name);
  184. client->state = CS_ACTIVE;
  185. // set up the entity for the client
  186. clientNum = client - svs.clients;
  187. ent = SV_GentityNum( clientNum );
  188. ent->s.number = clientNum;
  189. client->gentity = ent;
  190. // normally I check 'qbFromSavedGame' to avoid overwriting loaded client data, but this stuff I want
  191. // to be reset so that client packet delta-ing bgins afresh, rather than based on your previous frame
  192. // (which didn't in fact happen now if we've just loaded from a saved game...)
  193. //
  194. client->deltaMessage = -1;
  195. client->cmdNum = 0;
  196. client->nextSnapshotTime = sv.time; // generate a snapshot immediately
  197. // call the game begin function
  198. ge->ClientBegin( client - svs.clients, cmd, eSavedGameJustLoaded );
  199. }
  200. /*
  201. ============================================================
  202. CLIENT COMMAND EXECUTION
  203. ============================================================
  204. */
  205. /*
  206. =================
  207. SV_Disconnect_f
  208. The client is going to disconnect, so remove the connection immediately FIXME: move to game?
  209. =================
  210. */
  211. static void SV_Disconnect_f( client_t *cl ) {
  212. SV_DropClient( cl, "disconnected" );
  213. }
  214. /*
  215. =================
  216. SV_UserinfoChanged
  217. Pull specific info from a newly changed userinfo string
  218. into a more C friendly form.
  219. =================
  220. */
  221. void SV_UserinfoChanged( client_t *cl ) {
  222. char *val;
  223. int i;
  224. // name for C code
  225. Q_strncpyz( cl->name, Info_ValueForKey (cl->userinfo, "name"), sizeof(cl->name) );
  226. // rate command
  227. // if the client is on the same subnet as the server and we aren't running an
  228. // internet public server, assume they don't need a rate choke
  229. cl->rate = 99999; // lans should not rate limit
  230. // snaps command
  231. val = Info_ValueForKey (cl->userinfo, "snaps");
  232. if (strlen(val)) {
  233. i = atoi(val);
  234. if ( i < 1 ) {
  235. i = 1;
  236. } else if ( i > 30 ) {
  237. i = 30;
  238. }
  239. cl->snapshotMsec = 1000/i;
  240. } else {
  241. cl->snapshotMsec = 50;
  242. }
  243. }
  244. /*
  245. ==================
  246. SV_UpdateUserinfo_f
  247. ==================
  248. */
  249. static void SV_UpdateUserinfo_f( client_t *cl ) {
  250. Q_strncpyz( cl->userinfo, Cmd_Argv(1), sizeof(cl->userinfo) );
  251. // call prog code to allow overrides
  252. ge->ClientUserinfoChanged( cl - svs.clients );
  253. SV_UserinfoChanged( cl );
  254. }
  255. typedef struct {
  256. char *name;
  257. void (*func)( client_t *cl );
  258. } ucmd_t;
  259. static ucmd_t ucmds[] = {
  260. {"userinfo", SV_UpdateUserinfo_f},
  261. {"disconnect", SV_Disconnect_f},
  262. {NULL, NULL}
  263. };
  264. /*
  265. ==================
  266. SV_ExecuteClientCommand
  267. ==================
  268. */
  269. void SV_ExecuteClientCommand( client_t *cl, const char *s ) {
  270. ucmd_t *u;
  271. Cmd_TokenizeString( s );
  272. // see if it is a server level command
  273. for (u=ucmds ; u->name ; u++) {
  274. if (!strcmp (Cmd_Argv(0), u->name) ) {
  275. u->func( cl );
  276. break;
  277. }
  278. }
  279. // pass unknown strings to the game
  280. if (!u->name && sv.state == SS_GAME) {
  281. ge->ClientCommand( cl - svs.clients );
  282. }
  283. }
  284. #define MAX_STRINGCMDS 8
  285. /*
  286. ===============
  287. SV_ClientCommand
  288. ===============
  289. */
  290. static void SV_ClientCommand( client_t *cl, msg_t *msg ) {
  291. int seq;
  292. const char *s;
  293. seq = MSG_ReadLong( msg );
  294. s = MSG_ReadString( msg );
  295. // see if we have already executed it
  296. if ( cl->lastClientCommand >= seq ) {
  297. return;
  298. }
  299. Com_DPrintf( "clientCommand: %s : %i : %s\n", cl->name, seq, s );
  300. // drop the connection if we have somehow lost commands
  301. if ( seq > cl->lastClientCommand + 1 ) {
  302. Com_Printf( "Client %s lost %i clientCommands\n", cl->name,
  303. seq - cl->lastClientCommand + 1 );
  304. }
  305. SV_ExecuteClientCommand( cl, s );
  306. cl->lastClientCommand = seq;
  307. }
  308. //==================================================================================
  309. /*
  310. ==================
  311. SV_ClientThink
  312. ==================
  313. */
  314. void SV_ClientThink (client_t *cl, usercmd_t *cmd) {
  315. cl->lastUsercmd = *cmd;
  316. if ( cl->state != CS_ACTIVE ) {
  317. return; // may have been kicked during the last usercmd
  318. }
  319. ge->ClientThink( cl - svs.clients, cmd );
  320. }
  321. /*
  322. ==================
  323. SV_UserMove
  324. The message usually contains all the movement commands
  325. that were in the last three packets, so that the information
  326. in dropped packets can be recovered.
  327. On very fast clients, there may be multiple usercmd packed into
  328. each of the backup packets.
  329. ==================
  330. */
  331. static void SV_UserMove( client_t *cl, msg_t *msg ) {
  332. int i, start;
  333. int cmdNum;
  334. int firstNum;
  335. int cmdCount;
  336. usercmd_t nullcmd;
  337. usercmd_t cmds[MAX_PACKET_USERCMDS];
  338. usercmd_t *cmd, *oldcmd;
  339. int clientTime;
  340. int serverId;
  341. cl->reliableAcknowledge = MSG_ReadLong( msg );
  342. serverId = MSG_ReadLong( msg );
  343. clientTime = MSG_ReadLong( msg );
  344. cl->deltaMessage = MSG_ReadLong( msg );
  345. // cmdNum is the command number of the most recent included usercmd
  346. cmdNum = MSG_ReadLong( msg );
  347. cmdCount = MSG_ReadByte( msg );
  348. if ( cmdCount < 1 ) {
  349. Com_Printf( "cmdCount < 1\n" );
  350. return;
  351. }
  352. if ( cmdCount > MAX_PACKET_USERCMDS ) {
  353. Com_Printf( "cmdCount > MAX_PACKET_USERCMDS\n" );
  354. return;
  355. }
  356. memset( &nullcmd, 0, sizeof(nullcmd) );
  357. oldcmd = &nullcmd;
  358. for ( i = 0 ; i < cmdCount ; i++ ) {
  359. cmd = &cmds[i];
  360. MSG_ReadDeltaUsercmd( msg, oldcmd, cmd );
  361. oldcmd = cmd;
  362. }
  363. // if this is a usercmd from a previous gamestate,
  364. // ignore it or retransmit the current gamestate
  365. if ( serverId != sv.serverId ) {
  366. // if we can tell that the client has dropped the last
  367. // gamestate we sent them, resend it
  368. if ( cl->netchan.incomingAcknowledged > cl->gamestateMessageNum ) {
  369. Com_DPrintf( "%s : dropped gamestate, resending\n", cl->name );
  370. SV_SendClientGameState( cl );
  371. }
  372. return;
  373. }
  374. // if this is the first usercmd we have received
  375. // this gamestate, put the client into the world
  376. if ( cl->state == CS_PRIMED ) {
  377. SV_ClientEnterWorld( cl, &cmds[0], eSavedGameJustLoaded );
  378. #ifndef _XBOX // No auto-saving for now?
  379. if ( sv_mapname->string[0]!='_' )
  380. {
  381. char savename[MAX_QPATH];
  382. if ( eSavedGameJustLoaded == eNO )
  383. {
  384. SG_WriteSavegame("auto",qtrue);
  385. if ( strnicmp(sv_mapname->string, "academy", 7) != 0)
  386. {
  387. Com_sprintf (savename, sizeof(savename), "auto_%s",sv_mapname->string);
  388. SG_WriteSavegame(savename,qtrue);//can't use va becuase it's nested
  389. }
  390. }
  391. else if ( qbLoadTransition == qtrue )
  392. {
  393. Com_sprintf (savename, sizeof(savename), "hub/%s", sv_mapname->string );
  394. SG_WriteSavegame( savename, qfalse );//save a full one
  395. SG_WriteSavegame( "auto", qfalse );//need a copy for auto, too
  396. }
  397. }
  398. #endif
  399. eSavedGameJustLoaded = eNO;
  400. // the moves can be processed normaly
  401. }
  402. if ( cl->state != CS_ACTIVE ) {
  403. cl->deltaMessage = -1;
  404. return;
  405. }
  406. // if there is a time gap from the last packet to this packet,
  407. // fill in with the first command in the packet
  408. // with a packetdup of 0, firstNum == cmdNum
  409. firstNum = cmdNum - ( cmdCount - 1 );
  410. if ( cl->cmdNum < firstNum - 1 ) {
  411. cl->droppedCommands = qtrue;
  412. if ( sv_showloss->integer ) {
  413. Com_Printf("Lost %i usercmds from %s\n", firstNum - 1 - cl->cmdNum,
  414. cl->name);
  415. }
  416. if ( cl->cmdNum < firstNum - 6 ) {
  417. cl->cmdNum = firstNum - 6; // don't generate too many
  418. }
  419. while ( cl->cmdNum < firstNum - 1 ) {
  420. cl->cmdNum++;
  421. SV_ClientThink( cl, &cmds[0] );
  422. }
  423. }
  424. // skip over any usercmd_t we have already executed
  425. start = cl->cmdNum - ( firstNum - 1 );
  426. for ( i = start ; i < cmdCount ; i++ ) {
  427. SV_ClientThink (cl, &cmds[ i ]);
  428. }
  429. cl->cmdNum = cmdNum;
  430. }
  431. /*
  432. ===========================================================================
  433. USER CMD EXECUTION
  434. ===========================================================================
  435. */
  436. /*
  437. ===================
  438. SV_ExecuteClientMessage
  439. Parse a client packet
  440. ===================
  441. */
  442. void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) {
  443. int c;
  444. while( 1 ) {
  445. if ( msg->readcount > msg->cursize ) {
  446. SV_DropClient (cl, "had a badread");
  447. return;
  448. }
  449. c = MSG_ReadByte( msg );
  450. if ( c == -1 ) {
  451. break;
  452. }
  453. switch( c ) {
  454. default:
  455. SV_DropClient( cl,"had an unknown command char" );
  456. return;
  457. case clc_nop:
  458. break;
  459. case clc_move:
  460. SV_UserMove( cl, msg );
  461. break;
  462. case clc_clientCommand:
  463. SV_ClientCommand( cl, msg );
  464. if (cl->state == CS_ZOMBIE) {
  465. return; // disconnect command
  466. }
  467. break;
  468. }
  469. }
  470. }
  471. void SV_FreeClient(client_t *client)
  472. {
  473. int i;
  474. if (!client) return;
  475. for(i=0; i<MAX_RELIABLE_COMMANDS; i++) {
  476. if ( client->reliableCommands[ i] ) {
  477. Z_Free( client->reliableCommands[ i] );
  478. client->reliableCommands[i] = NULL;
  479. client->reliableSequence = 0;
  480. }
  481. }
  482. }