/* * ================= * SV_ReadPackets * ================= */ void SV_ReadPackets(void) { int i; client_t *cl; int qport; while (NET_GetPacket(NS_SERVER, &net_from, &net_message)) { // check for connectionless packet (0xffffffff) first if (*(int *)net_message.data == -1) { SV_ConnectionlessPacket(); continue; } // read the qport out of the message so we can fix up // stupid address translating routers MSG_BeginReading(&net_message); MSG_ReadLong(&net_message); // sequence number MSG_ReadLong(&net_message); // sequence number qport = MSG_ReadShort(&net_message) & 0xffff; // check for packets from connected clients for (i = 0, cl = svs.clients; i < maxclients->value; i++, cl++) { if (cl->state == cs_free) { continue; } if (!NET_CompareBaseAdr(net_from, cl->netchan.remote_address)) { continue; } if (cl->netchan.qport != qport) { continue; } if (cl->netchan.remote_address.port != net_from.port) { Com_Printf("SV_ReadPackets: fixing up a translated port\n"); cl->netchan.remote_address.port = net_from.port; } if (Netchan_Process(&cl->netchan, &net_message)) { // this is a valid, sequenced packet, so process it if (cl->state != cs_zombie) { cl->lastmessage = svs.realtime; // don't timeout SV_ExecuteClientMessage(cl); } } break; } if (i != maxclients->value) { continue; } } }
void NET_Event(fd_set *fdr) { byte bufData[MAX_MSGLEN + 1]; netadr_t from; msg_t netmsg; while(1) { MSG_Init(&netmsg, bufData, sizeof(bufData)); if(NET_GetPacket(&from, &netmsg, fdr)) { if(net_dropsim->value > 0.0f && net_dropsim->value <= 100.0f) { // com_dropsim->value percent of incoming packets get dropped. if(rand() < (int) (((double) RAND_MAX) / 100.0 * (double) net_dropsim->value)) continue; // drop this packet } if(com_sv_running->integer) Com_RunAndTimeServerPacket(&from, &netmsg); else CL_PacketEvent(from, &netmsg); } else break; } }
/* ==================== CL_GetMessage Handles recording and playback of demos, on top of NET_ code ==================== */ static qboolean CL_GetMessage( byte *data, size_t *length ) { if( cls.demoplayback ) { return CL_DemoReadMessage( data, length ); } return NET_GetPacket( NS_CLIENT, &net_from, data, length ); }
void SV_ReadPackets() { guard(SV_ReadPackets); while (NET_GetPacket(NS_SERVER, &net_from, &net_message)) { // check for connectionless packet (0xffffffff) first if (*(int *)net_message.data == -1) { SV_ConnectionlessPacket(); continue; } // read the qport out of the message so we can fix up // stupid address translating routers net_message.BeginReading(); MSG_ReadLong(&net_message); // sequence number MSG_ReadLong(&net_message); // sequence number int qport = MSG_ReadShort(&net_message) & 0xFFFF; // check for packets from connected clients int i; client_t *cl; for (i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++) { if (cl->state == cs_free) continue; // compare address: ignore network port, but use qport if (!NET_CompareBaseAdr(&net_from, &cl->netchan.remote_address)) continue; if (cl->netchan.port != qport) continue; // found a client if (cl->netchan.remote_address.port != net_from.port) { appWPrintf("SV_ReadPackets: fixing up a translated port\n"); cl->netchan.remote_address.port = net_from.port; } if (cl->netchan.Process(&net_message)) { // this is a valid, sequenced packet, so process it if (cl->state != cs_zombie) { cl->lastmessage = svs.realtime; // don't timeout SV_ExecuteClientMessage(cl); } } break; } // if (i != sv_maxclients->integer) continue; } unguard; }
/* ==================== CL_GetMessage Handles recording and playback of demos, on top of NET_ code ==================== */ qboolean CL_GetMessage (void) { if (cls.demoplayback) return CL_GetDemoMessage (); if (!NET_GetPacket ()) return false; CL_WriteDemoMessage (&net_message); return true; }
/* ==================== CL_GetMessage Handles recording and playback of demos, on top of NET_ code ==================== */ int CL_GetMessage( byte *data, size_t *length ) { if( cls.demoplayback ) { if( CL_DemoReadMessage( data, length )) return true; return false; } if( NET_GetPacket( NS_CLIENT, &net_from, data, length )) return true; return false; }
static void qtv_read_packets (void) { connection_t *con; while (NET_GetPacket ()) { if ((con = Connection_Find (&net_from))) { con->handler (con, con->object); } else if (*(int *) net_message->message->data == -1) { qtv_connectionless_packet (); } } }
/* ================= SV_ReadPackets ================= */ static void SV_ReadPackets (void) { int i; client_t *cl; while (NET_GetPacket ()) { if (SV_FilterPacket ()) { SV_SendBan (); // tell them we aren't listening... continue; } // check for connectionless packet (0xffffffff) first if (*(int *)net_message.data == -1) { SV_ConnectionlessPacket (); continue; } // check for packets from connected clients for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) { if (cl->state == cs_free) continue; if (!NET_CompareAdr (net_from, cl->netchan.remote_address)) continue; if (Netchan_Process(&cl->netchan)) { // this is a valid, sequenced packet, so process it svs.stats.packets++; cl->send_message = true; // reply at end of frame if (cl->state != cs_zombie) SV_ExecuteClientMessage (cl); } break; } if (i != MAX_CLIENTS) continue; // packet is not from a known client // Con_Printf ("%s:sequenced packet without connection\n", NET_AdrToString(net_from)); } }
/* ================= SV_ReadPackets ================= */ void SV_ReadPackets (void) { int i; client_t *cl; int qport; // first deal with delayed packets from connected clients for (i = 0, cl=svs.clients; i < MAX_CLIENTS; i++, cl++) { if (cl->state == cs_free) continue; net_from = cl->netchan.remote_address; while (cl->packets && svs.realtime - cl->packets->time >= cl->delay) { SZ_Clear(&net_message); SZ_Write(&net_message, cl->packets->msg.data, cl->packets->msg.cursize); SV_ExecuteClientMessage(cl); SV_FreeHeadDelayedPacket(cl); } } // now deal with new packets while (NET_GetPacket(NS_SERVER)) { if (SV_FilterPacket ()) { SV_SendBan (); // tell them we aren't listening... continue; } // check for connectionless packet (0xffffffff) first if (*(int *)net_message.data == -1) { SV_ConnectionlessPacket (); continue; } // read the qport out of the message so we can fix up // stupid address translating routers MSG_BeginReading (); MSG_ReadLong (); // sequence number MSG_ReadLong (); // sequence number qport = MSG_ReadShort () & 0xffff; // check which client sent this packet for (i=0, cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++) { if (cl->state == cs_free) continue; if (!NET_CompareBaseAdr (net_from, cl->netchan.remote_address)) continue; if (cl->netchan.qport != qport) continue; if (cl->netchan.remote_address.port != net_from.port) { Com_DPrintf ("SV_ReadPackets: fixing up a translated port\n"); cl->netchan.remote_address.port = net_from.port; } break; } if (i == MAX_CLIENTS) continue; // ok, we know who sent this packet, but do we need to delay executing it? if (cl->delay > 0) { if (!svs.free_packets) // packet has to be dropped.. break; // insert at end of list if (!cl->packets) { cl->last_packet = cl->packets = svs.free_packets; } else { // this works because '=' associates from right to left cl->last_packet = cl->last_packet->next = svs.free_packets; } svs.free_packets = svs.free_packets->next; cl->last_packet->next = NULL; cl->last_packet->time = svs.realtime; SZ_Clear(&cl->last_packet->msg); SZ_Write(&cl->last_packet->msg, net_message.data, net_message.cursize); } else { SV_ExecuteClientMessage (cl); } } }
void G_Ticker (void) { int buf; gamestate_t oldgamestate; size_t i; // Run client tics; CL_RunTics (); // do player reborns if needed if(serverside) for (i = 0; i < players.size(); i++) if (players[i].ingame() && players[i].playerstate == PST_REBORN) G_DoReborn (players[i]); // do things to change the game state oldgamestate = gamestate; while (gameaction != ga_nothing) { switch (gameaction) { case ga_loadlevel: G_DoLoadLevel (-1); break; case ga_newgame: G_DoNewGame (); break; case ga_loadgame: gameaction = ga_nothing; break; case ga_savegame: gameaction = ga_nothing; break; case ga_playdemo: G_DoPlayDemo (); break; case ga_completed: G_DoCompleted (); break; case ga_victory: gameaction = ga_nothing; break; case ga_worlddone: G_DoWorldDone (); break; case ga_screenshot: I_ScreenShot(shotfile.c_str()); gameaction = ga_nothing; break; case ga_fullconsole: C_FullConsole (); gameaction = ga_nothing; break; case ga_nothing: break; } C_AdjustBottom (); } // get commands buf = gametic%BACKUPTICS; memcpy (&consoleplayer().cmd, &consoleplayer().netcmds[buf], sizeof(ticcmd_t)); static int realrate = 0; int packet_size; if (demoplayback) G_ReadDemoTiccmd(); // play all player commands if (demorecording) G_WriteDemoTiccmd(); // read in all player commands if (connected) { while ((packet_size = NET_GetPacket()) ) { // denis - don't accept candy from strangers if(!NET_CompareAdr(serveraddr, net_from)) break; realrate += packet_size; last_received = gametic; noservermsgs = false; CL_ReadPacketHeader(); CL_ParseCommands(); if (gameaction == ga_fullconsole) // Host_EndGame was called return; } if (!(gametic%TICRATE)) { netin = realrate; realrate = 0; } if (!noservermsgs) CL_SendCmd(); // send console commands to the server CL_SaveCmd(); // save console commands if (!(gametic%TICRATE)) { netout = outrate; outrate = 0; } if (gametic - last_received > 65) noservermsgs = true; } else if (NET_GetPacket() ) { // denis - don't accept candy from strangers if((gamestate == GS_DOWNLOAD || gamestate == GS_CONNECTING) && NET_CompareAdr(serveraddr, net_from)) { int type = MSG_ReadLong(); if(type == CHALLENGE) { CL_PrepareConnect(); } else if(type == 0) { if (!CL_Connect()) memset (&serveraddr, 0, sizeof(serveraddr)); connecttimeout = 0; } else { // we are already connected to this server, quit first MSG_WriteMarker(&net_buffer, clc_disconnect); NET_SendPacket(net_buffer, serveraddr); } } } // check for special buttons if(serverside && consoleplayer().ingame()) { player_t &player = consoleplayer(); if (player.cmd.ucmd.buttons & BT_SPECIAL) { switch (player.cmd.ucmd.buttons & BT_SPECIALMASK) { case BTS_PAUSE: paused ^= 1; if (paused) S_PauseSound (); else S_ResumeSound (); break; case BTS_SAVEGAME: if (!savedescription[0]) strcpy (savedescription, "NET GAME"); savegameslot = (player.cmd.ucmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT; gameaction = ga_savegame; break; } } }
/* ================= SV_ReadPackets ================= */ void SV_ReadPackets( void ) { sv_client_t *cl; int i, qport, curSize; while( NET_GetPacket( NS_SERVER, &net_from, net_message_buffer, &curSize )) { BF_Init( &net_message, "ClientPacket", net_message_buffer, curSize ); // check for connectionless packet (0xffffffff) first if( BF_GetMaxBytes( &net_message ) >= 4 && *(int *)net_message.pData == -1 ) { SV_ConnectionlessPacket( net_from, &net_message ); continue; } // read the qport out of the message so we can fix up // stupid address translating routers BF_Clear( &net_message ); BF_ReadLong( &net_message ); // sequence number BF_ReadLong( &net_message ); // sequence number qport = (int)BF_ReadShort( &net_message ) & 0xffff; // check for packets from connected clients for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) { if( cl->state == cs_free || cl->fakeclient ) continue; if( !NET_CompareBaseAdr( net_from, cl->netchan.remote_address )) continue; if( cl->netchan.qport != qport ) continue; if( cl->netchan.remote_address.port != net_from.port ) { MsgDev( D_INFO, "SV_ReadPackets: fixing up a translated port\n"); cl->netchan.remote_address.port = net_from.port; } if( Netchan_Process( &cl->netchan, &net_message )) { cl->send_message = true; // reply at end of frame // this is a valid, sequenced packet, so process it if( cl->state != cs_zombie ) { cl->lastmessage = host.realtime; // don't timeout SV_ExecuteClientMessage( cl, &net_message ); svgame.globals->frametime = host.frametime; svgame.globals->time = sv.time; } } // fragmentation/reassembly sending takes priority over all game messages, want this in the future? if( Netchan_IncomingReady( &cl->netchan )) { if( Netchan_CopyNormalFragments( &cl->netchan, &net_message )) { BF_Clear( &net_message ); SV_ExecuteClientMessage( cl, &net_message ); } if( Netchan_CopyFileFragments( &cl->netchan, &net_message )) { SV_ProcessFile( cl, cl->netchan.incomingfilename ); } } break; } if( i != sv_maxclients->integer ) continue; } }
/* * SV_ReadPackets */ static void SV_ReadPackets( void ) { int i, socketind, ret; client_t *cl; #ifdef TCP_SUPPORT socket_t newsocket; netadr_t mmserver; #endif int game_port; socket_t *socket; netadr_t address; static msg_t msg; static qbyte msgData[MAX_MSGLEN]; socket_t* sockets [] = { &svs.socket_loopback, &svs.socket_udp, &svs.socket_udp6, }; #ifdef TCP_SUPPORT if( SV_MM_Initialized() ) SV_MM_NetAddress( &mmserver ); if( svs.socket_tcp.open ) { while( qtrue ) { // find a free slot for( i = 0; i < MAX_INCOMING_CONNECTIONS; i++ ) { if( !svs.incoming[i].active ) break; } if( i == MAX_INCOMING_CONNECTIONS ) break; if( ( ret = NET_Accept( &svs.socket_tcp, &newsocket, &address ) ) == 0 ) break; if( ret == -1 ) { Com_Printf( "NET_Accept: Error: %s\n", NET_ErrorString() ); continue; } Com_Printf( "New TCP connection from %s\n", NET_AddressToString( &address ) ); svs.incoming[i].active = qtrue; svs.incoming[i].socket = newsocket; svs.incoming[i].address = address; svs.incoming[i].time = svs.realtime; } } for( i = 0; i < MAX_INCOMING_CONNECTIONS; i++ ) { if( !svs.incoming[i].active ) continue; ret = NET_GetPacket( &svs.incoming[i].socket, &address, &msg ); if( ret == -1 ) { Com_Printf( "NET_GetPacket: Error: %s\n", NET_ErrorString() ); NET_CloseSocket( &svs.incoming[i].socket ); svs.incoming[i].active = qfalse; } else if( ret == 1 ) { if( SV_MM_Initialized() && NET_CompareBaseAddress( &mmserver, &address ) ) { Com_DPrintf( "TCP packet from matchmaker\n" ); SV_MM_SetConnection( &svs.incoming[i] ); SV_MM_Packet( &msg ); SV_MM_SetConnection( NULL ); continue; } if( *(int *)msg.data != -1 ) { Com_Printf( "Sequence packet without connection\n" ); NET_CloseSocket( &svs.incoming[i].socket ); svs.incoming[i].active = qfalse; continue; } Com_Printf( "Connectionless TCP packet from: %s\n", NET_AddressToString( &address ) ); SV_ConnectionlessPacket( &svs.incoming[i].socket, &address, &msg ); } } #endif MSG_Init( &msg, msgData, sizeof( msgData ) ); for( socketind = 0; socketind < sizeof( sockets ) / sizeof( sockets[0] ); socketind++ ) { socket = sockets[socketind]; if( !socket->open ) continue; while( ( ret = NET_GetPacket( socket, &address, &msg ) ) != 0 ) { if( ret == -1 ) { Com_Printf( "NET_GetPacket: Error: %s\n", NET_ErrorString() ); continue; } // check for connectionless packet (0xffffffff) first if( *(int *)msg.data == -1 ) { SV_ConnectionlessPacket( socket, &address, &msg ); continue; } // read the game port out of the message so we can fix up // stupid address translating routers MSG_BeginReading( &msg ); MSG_ReadLong( &msg ); // sequence number MSG_ReadLong( &msg ); // sequence number game_port = MSG_ReadShort( &msg ) & 0xffff; // data follows // check for packets from connected clients for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) { unsigned short addr_port; if( cl->state == CS_FREE || cl->state == CS_ZOMBIE ) continue; if( cl->edict && ( cl->edict->r.svflags & SVF_FAKECLIENT ) ) continue; if( !NET_CompareBaseAddress( &address, &cl->netchan.remoteAddress ) ) continue; if( cl->netchan.game_port != game_port ) continue; addr_port = NET_GetAddressPort( &address ); if( NET_GetAddressPort( &cl->netchan.remoteAddress ) != addr_port ) { Com_Printf( "SV_ReadPackets: fixing up a translated port\n" ); NET_SetAddressPort( &cl->netchan.remoteAddress, addr_port ); } if( SV_ProcessPacket( &cl->netchan, &msg ) ) // this is a valid, sequenced packet, so process it { cl->lastPacketReceivedTime = svs.realtime; SV_ParseClientMessage( cl, &msg ); } break; } } } // handle clients with individual sockets for( i = 0; i < sv_maxclients->integer; i++ ) { cl = &svs.clients[i]; if( cl->state == CS_ZOMBIE || cl->state == CS_FREE ) continue; if( !cl->individual_socket ) continue; // not while, we only handle one packet per client at a time here if( ( ret = NET_GetPacket( cl->netchan.socket, &address, &msg ) ) != 0 ) { if( ret == -1 ) { Com_Printf( "Error receiving packet from %s: %s\n", NET_AddressToString( &cl->netchan.remoteAddress ), NET_ErrorString() ); if( cl->reliable ) SV_DropClient( cl, DROP_TYPE_GENERAL, "Error receiving packet: %s", NET_ErrorString() ); } else { if( SV_ProcessPacket( &cl->netchan, &msg ) ) { // this is a valid, sequenced packet, so process it cl->lastPacketReceivedTime = svs.realtime; SV_ParseClientMessage( cl, &msg ); } } } } }
static void FWD_network_update(void) { fd_set rfds; struct timeval tv; int retval; int i1; peer_t *p; FD_ZERO(&rfds); // select on main server socket FD_SET(net_socket, &rfds); i1 = net_socket + 1; for (p = peers; p; p = p->next) { // select on peers sockets FD_SET(p->s, &rfds); if (p->s >= i1) i1 = p->s + 1; } // if not DLL - read stdin #ifndef APP_DLL #ifndef _WIN32 // try read stdin only if connected to a terminal. if (isatty(STDIN) && isatty(STDOUT)) { FD_SET(STDIN, &rfds); if (STDIN >= i1) i1 = STDIN + 1; } #endif // _WIN32 #endif /* Sleep for some time, wake up immidiately if there input packet. */ tv.tv_sec = 0; tv.tv_usec = 100000; // 100 ms retval = select(i1, &rfds, (fd_set *)0, (fd_set *)0, &tv); // read console input. // NOTE: we do not do that if we are in DLL mode... Sys_ReadSTDIN(&ps, rfds); if (retval <= 0) return; // if we have input packet on main server/proxy socket, then read it if(FD_ISSET(net_socket, &rfds)) { qbool connectionless; int cnt; // read it for(;;) { if (!NET_GetPacket(net_socket, &net_message)) break; // check for bans. if (SV_IsBanned(&net_from)) continue; if (net_message.cursize == 1 && net_message.data[0] == A2A_ACK) { QRY_SV_PingReply(); continue; } MSG_BeginReading(); connectionless = (MSG_ReadLong() == -1); if (connectionless) { if (MSG_BadRead()) continue; if (!SV_ConnectionlessPacket()) continue; // seems we do not need forward it } // search in peers for (p = peers; p; p = p->next) { // we have this peer already, so forward/send packet to remote server if (NET_CompareAddress(&p->from, &net_from)) break; } // peer was not found if (!p) continue; // forward data to the server/proxy if (p->ps >= ps_connected) { cnt = 1; // one packet by default // check for "drop" aka client disconnect, // first 10 bytes for NON connectionless packet is netchan related shit in QW if (p->proto == pr_qw && !connectionless && net_message.cursize > 10 && net_message.data[10] == clc_stringcmd) { if (!strcmp((char*)net_message.data + 10 + 1, "drop")) { // Sys_Printf("peer drop detected\n"); p->ps = ps_drop; // drop peer ASAP cnt = 3; // send few packets due to possibile packet lost } } for ( ; cnt > 0; cnt--) NET_SendPacket(p->s, net_message.cursize, net_message.data, &p->to); } time(&p->last); } } // now lets check peers sockets, perhaps we have input packets too for (p = peers; p; p = p->next) { if(FD_ISSET(p->s, &rfds)) { // yeah, we have packet, read it then for (;;) { if (!NET_GetPacket(p->s, &net_message)) break; // check for bans. if (SV_IsBanned(&net_from)) continue; // we should check is this packet from remote server, this may be some evil packet from haxors... if (!NET_CompareAddress(&p->to, &net_from)) continue; MSG_BeginReading(); if (MSG_ReadLong() == -1) { if (MSG_BadRead()) continue; if (!CL_ConnectionlessPacket(p)) continue; // seems we do not need forward it NET_SendPacket(net_socket, net_message.cursize, net_message.data, &p->from); continue; } if (p->ps >= ps_connected) NET_SendPacket(net_socket, net_message.cursize, net_message.data, &p->from); // qqshka: commented out // time(&p->last); } // for (;;) } // if(FD_ISSET(p->s, &rfds)) if (p->ps == ps_challenge) { // send challenge time to time if (time(NULL) - p->connect > 2) { p->connect = time(NULL); Netchan_OutOfBandPrint(p->s, &p->to, "getchallenge%s", p->proto == pr_qw ? "\n" : ""); } } } // for (p = peers; p; p = p->next) }
/* * TV_Downstream_ReadPackets */ void TV_Downstream_ReadPackets( void ) { int i, socketind, ret, game_port; client_t *cl; #ifdef TCP_SUPPORT socket_t newsocket; #endif socket_t *socket; netadr_t address; msg_t msg; qbyte msgData[MAX_MSGLEN]; socket_t* sockets [] = { &tvs.socket_udp, &tvs.socket_udp6, }; #ifdef TCP_SUPPORT if( tvs.socket_tcp.open ) { while( qtrue ) { // find a free slot for( i = 0; i < MAX_INCOMING_CONNECTIONS; i++ ) { if( !tvs.incoming[i].active ) break; } if( i == MAX_INCOMING_CONNECTIONS ) break; if( ( ret = NET_Accept( &tvs.socket_tcp, &newsocket, &address ) ) == 0 ) break; if( ret == -1 ) { Com_Printf( "NET_Accept: Error: %s\n", NET_ErrorString() ); continue; } tvs.incoming[i].active = qtrue; tvs.incoming[i].socket = newsocket; tvs.incoming[i].address = address; tvs.incoming[i].time = tvs.realtime; } } for( i = 0; i < MAX_INCOMING_CONNECTIONS; i++ ) { if( !tvs.incoming[i].active ) continue; ret = NET_GetPacket( &tvs.incoming[i].socket, &address, &msg ); if( ret == -1 ) { NET_CloseSocket( &tvs.incoming[i].socket ); tvs.incoming[i].active = qfalse; } else if( ret == 1 ) { if( *(int *)msg.data != -1 ) { // sequence packet without upstreams NET_CloseSocket( &tvs.incoming[i].socket ); tvs.incoming[i].active = qfalse; continue; } TV_Downstream_UpstreamlessPacket( &tvs.incoming[i].socket, &address, &msg ); } } #endif MSG_Init( &msg, msgData, sizeof( msgData ) ); for( socketind = 0; socketind < sizeof( sockets ) / sizeof( sockets[0] ); socketind++ ) { socket = sockets[socketind]; while( socket->open && ( ret = NET_GetPacket( socket, &address, &msg ) ) != 0 ) { if( ret == -1 ) { Com_Printf( "NET_GetPacket: Error: %s\n", NET_ErrorString() ); continue; } // check for upstreamless packet (0xffffffff) first if( *(int *)msg.data == -1 ) { TV_Downstream_UpstreamlessPacket( socket, &address, &msg ); continue; } // read the game port out of the message so we can fix up // stupid address translating routers MSG_BeginReading( &msg ); MSG_ReadLong( &msg ); // sequence number MSG_ReadLong( &msg ); // sequence number game_port = MSG_ReadShort( &msg ) & 0xffff; // data follows // check for packets from connected clients for( i = 0, cl = tvs.clients; i < tv_maxclients->integer; i++, cl++ ) { unsigned short remoteaddr_port, addr_port; if( cl->state == CS_FREE || cl->state == CS_ZOMBIE ) continue; if( !NET_CompareBaseAddress( &address, &cl->netchan.remoteAddress ) ) continue; if( cl->netchan.game_port != game_port ) continue; remoteaddr_port = NET_GetAddressPort( &cl->netchan.remoteAddress ); addr_port = NET_GetAddressPort( &address ); if( remoteaddr_port != addr_port ) { Com_DPrintf( "%s" S_COLOR_WHITE ": Fixing up a translated port from %i to %i\n", cl->name, remoteaddr_port, addr_port ); NET_SetAddressPort( &cl->netchan.remoteAddress, addr_port ); } if( TV_Downstream_ProcessPacket( &cl->netchan, &msg ) ) { // this is a valid, sequenced packet, so process it cl->lastPacketReceivedTime = tvs.realtime; TV_Downstream_ParseClientMessage( cl, &msg ); } break; } } } // handle clients with individual sockets for( i = 0; i < tv_maxclients->integer; i++ ) { cl = &tvs.clients[i]; if( cl->state == CS_ZOMBIE || cl->state == CS_FREE ) continue; if( !cl->individual_socket ) continue; // not while, we only handle one packet per client at a time here if( ( ret = NET_GetPacket( cl->netchan.socket, &address, &msg ) ) != 0 ) { if( ret == -1 ) { Com_Printf( "%s" S_COLOR_WHITE ": Error receiving packet: %s\n", cl->name, NET_ErrorString() ); if( cl->reliable ) TV_Downstream_DropClient( cl, DROP_TYPE_GENERAL, "Error receiving packet: %s", NET_ErrorString() ); } else { if( *(int *)msg.data == -1 ) { TV_Downstream_UpstreamlessPacket( cl->netchan.socket, &address, &msg ); } else { if( TV_Downstream_ProcessPacket( &cl->netchan, &msg ) ) { cl->lastPacketReceivedTime = tvs.realtime; TV_Downstream_ParseClientMessage( cl, &msg ); } } } } } }