void SV_NocPacket(netadr_t from, msg_t *msg) { //Not connected packet (Server is not running) char* s; char* c; if(msg->cursize >= 4) { if(*(int*)msg->data == -1) { #if 1 int CSteamServer_HandleIncomingPacket(const void* pData, int cbData, unsigned int srcIP, unsigned short srcPort); if(!CSteamServer_HandleIncomingPacket((const void*)msg->data, msg->cursize, from._ip, from.port)); #endif } else if(*(int*)msg->data == -2) { MSG_BeginReading(msg); MSG_ReadLong(msg); s = MSG_ReadStringLine(msg); Cmd_TokenizeString(s); c = Cmd_Argv(0); if(!Q_stricmp(c, "serverversionresponse")) { if(!NET_CompareBaseAdr(from, x_master)) return; } else if(!Q_stricmp(c, "clientversionresponse")) { if(!NET_CompareBaseAdr(from, x_master)) return; clientversion = atoi( Cmd_Argv(1) ); } } } }
/* * ================= * 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; } } }
/* ================= SV_ConnectionlessPacket A connectionless packet has four leading 0xff characters to distinguish it from a game channel. Clients that are in the game can still send connectionless packets. ================= */ static void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) { char *s; char *c; MSG_BeginReading( msg ); MSG_ReadLong( msg ); // skip the -1 marker s = MSG_ReadStringLine( msg ); Cmd_TokenizeString( s ); c = Cmd_Argv(0); Com_DPrintf ("SV packet %s : %s\n", NET_AdrToString(from), c); if (!strcmp(c,"getstatus")) { SVC_Status( from ); } else if (!strcmp(c,"getinfo")) { SVC_Info( from ); } else if (!strcmp(c,"connect")) { SV_DirectConnect( from ); } else if (!strcmp(c,"disconnect")) { // if a client starts up a local server, we may see some spurious // server disconnect messages when their new server sees our final // sequenced messages to the old client } else { Com_DPrintf ("bad connectionless packet from %s:\n%s\n" , NET_AdrToString (from), s); } }
void NQD_ReadPackets (void) { while (CL_GetNQDemoMessage()) { MSG_BeginReading (); CLNQ_ParseServerMessage(); } }
/* * SV_ProcessPacket */ static qboolean SV_ProcessPacket( netchan_t *netchan, msg_t *msg ) { int zerror; if( !Netchan_Process( netchan, msg ) ) return qfalse; // wasn't accepted for some reason // now if compressed, expand it MSG_BeginReading( msg ); MSG_ReadLong( msg ); // sequence MSG_ReadLong( msg ); // sequence_ack MSG_ReadShort( msg ); // game_port if( msg->compressed ) { zerror = Netchan_DecompressMessage( msg ); if( zerror < 0 ) { // compression error. Drop the packet Com_DPrintf( "SV_ProcessPacket: Compression error %i. Dropping packet\n", zerror ); return qfalse; } } return qtrue; }
/* ================= SV_ConnectionlessPacket A connectionless packet has four leading 0xff characters to distinguish it from a game channel. Clients that are in the game can still send connectionless packets. ================= */ void SV_ConnectionlessPacket(void) { const char * s; const char * c; MSG_BeginReading(&net_message); MSG_ReadLong(&net_message); // skip the -1 marker s = MSG_ReadStringLine(&net_message); Cmd_TokenizeString(s, false); c = Cmd_Argv(0); Com_DPrintf("Packet %s : %s\n", NET_AdrToString(net_from), c); if (!strcmp(c, "ping")) SVC_Ping(); else if (!strcmp(c, "ack")) SVC_Ack(); else if (!strcmp(c, "status")) SVC_Status(); else if (!strcmp(c, "info")) SVC_Info(); else if (!strcmp(c, "getchallenge")) SVC_GetChallenge(); else if (!strcmp(c, "connect")) SVC_DirectConnect(); else if (!strcmp(c, "rcon")) SVC_RemoteCommand(); else Com_Printf("bad connectionless packet from %s:\n%s\n", NET_AdrToString(net_from), s); }
/* * SV_ConnectionlessPacket * * A connectionless packet has four leading 0xff * characters to distinguish it from a game channel. * Clients that are in the game can still send * connectionless packets. */ void SV_ConnectionlessPacket( const socket_t *socket, const netadr_t *address, msg_t *msg ) { connectionless_cmd_t *cmd; char *s, *c; MSG_BeginReading( msg ); MSG_ReadLong( msg ); // skip the -1 marker s = MSG_ReadStringLine( msg ); Cmd_TokenizeString( s ); c = Cmd_Argv( 0 ); Com_DPrintf( "Packet %s : %s\n", NET_AddressToString( address ), c ); for( cmd = connectionless_cmds; cmd->name; cmd++ ) { if( !strcmp( c, cmd->name ) ) { cmd->func( socket, address ); return; } } Com_DPrintf( "Bad connectionless packet from %s:\n%s\n", NET_AddressToString( address ), s ); }
/* * TV_Downstream_UpstreamlessPacket */ void TV_Downstream_UpstreamlessPacket( const socket_t *socket, const netadr_t *address, msg_t *msg ) { upstreamless_cmd_t *cmd; char *s, *c; MSG_BeginReading( msg ); MSG_ReadLong( msg ); // skip the -1 marker s = MSG_ReadStringLine( msg ); if( TV_Downstream_SteamServerQuery( s, socket, address, msg ) ) return; Cmd_TokenizeString( s ); c = Cmd_Argv( 0 ); for( cmd = upstreamless_cmds; cmd->name; cmd++ ) { if( !strcmp( c, cmd->name ) ) { cmd->func( socket, address ); return; } } Com_DPrintf( "Bad downstream connectionless packet from %s:\n%s\n", NET_AddressToString( address ), s ); }
/* ================= SV_ReadPackets ================= */ void SV_PacketEvent( netadr_t from, msg_t *msg ) { int i; client_t *cl; int qport; // check for connectionless packet (0xffffffff) first if ( msg->cursize >= 4 && *(int *)msg->data == -1) { SV_ConnectionlessPacket( from, msg ); return; } // read the qport 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 qport = MSG_ReadShort( msg ) & 0xffff; // find which client the message is from for (i=0, cl=svs.clients ; i < 1 ; i++,cl++) { if (cl->state == CS_FREE) { continue; } if ( !NET_CompareBaseAdr( from, cl->netchan.remoteAddress ) ) { continue; } // it is possible to have multiple clients from a single IP // address, so they are differentiated by the qport variable if (cl->netchan.qport != qport) { continue; } // the IP port can't be used to differentiate them, because // some address translating routers periodically change UDP // port assignments if (cl->netchan.remoteAddress.port != from.port) { Com_Printf( "SV_ReadPackets: fixing up a translated port\n" ); cl->netchan.remoteAddress.port = from.port; } // make sure it is a valid, in sequence packet if (Netchan_Process(&cl->netchan, msg)) { // zombie clients stil neet to do the Netchan_Process // to make sure they don't need to retransmit the final // reliable message, but they don't do any other processing if (cl->state != CS_ZOMBIE) { cl->lastPacketTime = sv.time; // don't timeout cl->frames[ cl->netchan.incomingAcknowledged & PACKET_MASK ] .messageAcked = sv.time; SV_ExecuteClientMessage( cl, msg ); } } return; } // if we received a sequenced packet from an address we don't reckognize, // send an out of band disconnect packet to it NET_OutOfBandPrint( NS_SERVER, from, "disconnect" ); }
/* * ================= * SV_ConnectionlessPacket * * A connectionless packet has four leading 0xff * characters to distinguish it from a game channel. * Clients that are in the game can still send * connectionless packets. * ================= */ void SV_ConnectionlessPacket(void) { char *s; char *c; // r1ch fix: make sure we never talk to ourselves // if (NET_IsLocalAddress (net_from.ip[0] == 127) && !NET_IsLocalHost(net_from) && ShortSwap(net_from.port) == server_port) /* if ( (net_from.ip[0] == 127) && (net_from.type != NA_LOOPBACK) && (ShortSwap(net_from.port) == server_port) ) * { * Com_DPrintf ("dropped %d byte connectionless packet from self! (spoofing attack?)\n", net_message.cursize); * return; * }*/ MSG_BeginReading(&net_message); MSG_ReadLong(&net_message); // skip the -1 marker s = MSG_ReadStringLine(&net_message); Cmd_TokenizeString(s, false); c = Cmd_Argv(0); Com_DPrintf("Packet %s : %s\n", NET_AdrToString(net_from), c); if (!strcmp(c, "ping")) { SVC_Ping(); } else if (!strcmp(c, "ack")) { SVC_Ack(); } else if (!strcmp(c, "status")) { SVC_Status(); } else if (!strcmp(c, "info")) { SVC_Info(); } else if (!strcmp(c, "getchallenge")) { SVC_GetChallenge(); } else if (!strcmp(c, "connect")) { SVC_DirectConnect(); } else if (!strcmp(c, "rcon")) { SVC_RemoteCommand(); } else { Com_Printf("bad connectionless packet from %s:\n%s\n" , NET_AdrToString(net_from), s); } }
static void Test_Poll(void) { struct qsockaddr clientaddr; int control; int len; char name[32]; char address[64]; int colors; int frags; int connectTime; byte playerNumber; net_landriverlevel = testDriver; while (1) { len = dfunc.Read(testSocket, net_message.data, net_message.maxsize, &clientaddr); if (len < sizeof(int)) { break; } net_message.cursize = len; MSG_BeginReading(); control = BigLong(*((int *)net_message.data)); MSG_ReadLong(); if (control == -1) { break; } if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) { break; } if ((control & NETFLAG_LENGTH_MASK) != len) { break; } if (MSG_ReadByte() != CCREP_PLAYER_INFO) { Sys_Error("Unexpected repsonse to Player Info request\n"); } playerNumber = MSG_ReadByte(); Q_strcpy(name, MSG_ReadString()); colors = MSG_ReadLong(); frags = MSG_ReadLong(); connectTime = MSG_ReadLong(); Q_strcpy(address, MSG_ReadString()); Con_Printf("%s\n frags:%3i colors:%u %u time:%u\n %s\n", name, frags, colors >> 4, colors & 0x0f, connectTime / 60, address); } testPollCount--; if (testPollCount) { SchedulePollProcedure(&testPollProcedure, 0.1); } else { dfunc.CloseSocket(testSocket); testInProgress = false; } }
static void Test2_Poll(void) { struct qsockaddr clientaddr; int control; int len; char name[256]; char value[256]; net_landriverlevel = test2Driver; name[0] = 0; len = dfunc.Read (test2Socket, net_message.data, net_message.maxsize, &clientaddr); if (len < sizeof(int)) goto Reschedule; net_message.cursize = len; MSG_BeginReading (); control = BigLong(*((int *)net_message.data)); MSG_ReadLong(); if (control == -1) goto Error; if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) goto Error; if ((control & NETFLAG_LENGTH_MASK) != len) goto Error; if (MSG_ReadByte() != CCREP_RULE_INFO) goto Error; Q_strcpy(name, MSG_ReadString()); if (name[0] == 0) goto Done; Q_strcpy(value, MSG_ReadString()); Con_Printf("%-16.16s %-16.16s\n", name, value); SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREQ_RULE_INFO); MSG_WriteString(&net_message, name); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (test2Socket, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); Reschedule: SchedulePollProcedure(&test2PollProcedure, 0.05); return; Error: Con_Printf("Unexpected repsonse to Rule Info request\n"); Done: dfunc.CloseSocket(test2Socket); test2InProgress = false; return; }
unsigned char *W_ConvertWAD3TextureBGRA(sizebuf_t *sb) { unsigned char *in, *data, *out, *pal; int d, p; unsigned char name[16]; unsigned int mipoffset[4]; MSG_BeginReading(sb); MSG_ReadBytes(sb, 16, name); image_width = MSG_ReadLittleLong(sb); image_height = MSG_ReadLittleLong(sb); mipoffset[0] = MSG_ReadLittleLong(sb); mipoffset[1] = MSG_ReadLittleLong(sb); // should be mipoffset[0] + image_width*image_height mipoffset[2] = MSG_ReadLittleLong(sb); // should be mipoffset[1] + image_width*image_height/4 mipoffset[3] = MSG_ReadLittleLong(sb); // should be mipoffset[2] + image_width*image_height/16 pal = sb->data + mipoffset[3] + (image_width / 8 * image_height / 8) + 2; // bail if any data looks wrong if (image_width < 0 || image_width > 4096 || image_height < 0 || image_height > 4096 || mipoffset[0] != 40 || mipoffset[1] != mipoffset[0] + image_width * image_height || mipoffset[2] != mipoffset[1] + image_width / 2 * image_height / 2 || mipoffset[3] != mipoffset[2] + image_width / 4 * image_height / 4 || (unsigned int)sb->cursize < (mipoffset[3] + image_width / 8 * image_height / 8 + 2 + 768)) return NULL; in = (unsigned char *)sb->data + mipoffset[0]; data = out = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4); if (!data) return NULL; for (d = 0;d < image_width * image_height;d++) { p = *in++; if (name[0] == '{' && p == 255) out[0] = out[1] = out[2] = out[3] = 0; else { p *= 3; out[2] = pal[p]; out[1] = pal[p+1]; out[0] = pal[p+2]; out[3] = 255; } out += 4; } return data; }
/* ================= SV_ConnectionlessPacket A connectionless packet has four leading 0xff characters to distinguish it from a game channel. Clients that are in the game can still send connectionless packets. ================= */ static void SV_ConnectionlessPacket (void) { const char *s; const char *c; MSG_BeginReading (); MSG_ReadLong (); // skip the -1 marker s = MSG_ReadStringLine (); Cmd_TokenizeString (s); c = Cmd_Argv(0); if (!strcmp(c, "ping") || ( c[0] == A2A_PING && (c[1] == 0 || c[1] == '\n')) ) { SVC_Ping (); return; } if (c[0] == A2A_ACK && (c[1] == 0 || c[1] == '\n') ) { Con_Printf ("A2A_ACK from %s\n", NET_AdrToString (net_from)); return; } else if (c[0] == A2S_ECHO) { NET_SendPacket (net_message.cursize, net_message.data, net_from); return; } else if (!strcmp(c,"status")) { SVC_Status (); return; } else if (!strcmp(c,"log")) { SVC_Log (); return; } else if (!strcmp(c,"connect")) { SVC_DirectConnect (); return; } else if (!strcmp(c, "rcon")) SVC_RemoteCommand (); else Con_Printf ("bad connectionless packet from %s:\n%s\n", NET_AdrToString (net_from), s); }
/* <66786> ../engine/net_chan.c:1723 */ qboolean Netchan_CopyNormalFragments(netchan_t *chan) { fragbuf_t *p, *n; if (!chan->incomingready[FRAG_NORMAL_STREAM]) return FALSE; if (!chan->incomingbufs[FRAG_NORMAL_STREAM]) { Con_Printf("Netchan_CopyNormalFragments: Called with no fragments readied\n"); chan->incomingready[FRAG_NORMAL_STREAM] = FALSE; return FALSE; } p = chan->incomingbufs[FRAG_NORMAL_STREAM]; SZ_Clear(&net_message); MSG_BeginReading(); while (p) { n = p->next; SZ_Write(&net_message, p->frag_message.data, p->frag_message.cursize); Mem_Free(p); p = n; } if (*(uint32 *)net_message.data == MAKEID('B', 'Z', '2', '\0')) { char uncompressed[65536]; unsigned int uncompressedSize = 65536; BZ2_bzBuffToBuffDecompress(uncompressed, &uncompressedSize, (char*)net_message.data + 4, net_message.cursize - 4, 1, 0); Q_memcpy(net_message.data, uncompressed, uncompressedSize); net_message.cursize = uncompressedSize; } chan->incomingbufs[FRAG_NORMAL_STREAM] = NULL; chan->incomingready[FRAG_NORMAL_STREAM] = false; return TRUE; }
/* ================= SV_ConnectionlessPacket A connectionless packet has four leading 0xff characters to distinguish it from a game channel. Clients that are in the game can still send connectionless packets. ================= */ void SV_ConnectionlessPacket (void) { char *s; char *c; int s_token = 0; // r1ch fix: make sure we never talk to ourselves // if (NET_IsLocalAddress (net_from.ip[0] == 127) && !NET_IsLocalHost(net_from) && ShortSwap(net_from.port) == server_port) /* if ( (net_from.ip[0] == 127) && (net_from.type != NA_LOOPBACK) && (ShortSwap(net_from.port) == server_port) ) { Com_DPrintf ("dropped %d byte connectionless packet from self! (spoofing attack?)\n", net_message.cursize); return; }*/ MSG_BeginReading (&net_message); MSG_ReadLong (&net_message); // skip the -1 marker s = MSG_ReadStringLine (&net_message); Cmd_TokenizeString (s, false); c = Cmd_Argv(0); Com_DPrintf ("Packet %s : %s\n", NET_AdrToString(net_from), c); if ((s_token = Q_STLookup(&packet_stable, c)) != -1) { if (s_token == s_ping) SVC_Ping (); else if (s_token == s_ack) SVC_Ack (); else if (s_token == s_status) SVC_Status (); else if (s_token == s_info) SVC_Info (); else if (s_token == s_getchallenge) SVC_GetChallenge (); else if (s_token == s_connect) SVC_DirectConnect (); else if (s_token == s_rcon) SVC_RemoteCommand (); } else Com_Printf ("bad connectionless packet from %s:\n%s\n" , NET_AdrToString (net_from), s); }
/* * TV_Upstream_ConnectionlessPacket */ void TV_Upstream_ConnectionlessPacket( upstream_t *upstream, msg_t *msg ) { upstreamless_cmd_t *cmd; char *s, *c; MSG_BeginReading( msg ); MSG_ReadInt32( msg ); // skip the -1 marker s = MSG_ReadStringLine( msg ); Cmd_TokenizeString( s ); c = Cmd_Argv( 0 ); for( cmd = upstream_upstreamless_cmds; cmd->name; cmd++ ) { if( !strcmp( c, cmd->name ) ) { cmd->func( upstream, msg ); return; } } Com_DPrintf( "%s" S_COLOR_WHITE ": Bad upstream connectionless packet: %s\n", upstream->name, c ); }
/* Detecting the clientside protocol and process the 1st chunk of data if it is a http client */ tcpclientstate_t HTTPServer_AuthEvent(netadr_t* from, msg_t* msg, int *connectionId) { ftRequest_t* request; *connectionId = 0; char protocol[MAX_STRING_CHARS]; char* line; MSG_BeginReading(msg); line = MSG_ReadStringLine(msg, protocol, sizeof(protocol)); if (line != NULL) { if ( Q_strncmp(line, "GET", 3) && Q_strncmp(line, "POST", 4) && Q_strncmp(line, "HEAD", 4) ) { return TCP_AUTHNOTME; } if( strstr(line, "HTTP/1.0") == NULL && strstr(line, "HTTP/1.1") == NULL ) { /* Is not a HTTP client */ return TCP_AUTHNOTME; } } request = FT_CreateRequest(NULL, NULL); if(request == NULL) return TCP_AUTHBAD; *connectionId = (int)request; if (HTTPServer_Event(from, msg, *connectionId) == qtrue) { return TCP_AUTHBAD; } return TCP_AUTHSUCCESSFULL; }
static void demoPlayForwardFrame( demoPlay_t *play ) { int blockSize; msg_t msg; demoFrame_t *copyFrame; if (play->filePos + 4 > play->fileSize) { play->lastFrame = qtrue; return; } play->lastFrame = qfalse; play->filePos += 4; FS_Read( &blockSize, 4, play->fileHandle ); blockSize = LittleLong( blockSize ); FS_Read( demoBuffer, blockSize, play->fileHandle ); play->filePos += blockSize; MSG_Init( &msg, demoBuffer, sizeof(demoBuffer) ); MSG_BeginReading( &msg ); msg.cursize = blockSize; copyFrame = play->frame; play->frame = play->nextFrame; play->nextFrame = copyFrame; demoFrameUnpack( &msg, play->frame, play->nextFrame ); play->frameNumber++; }
static void qtv_connectionless_packet (void) { const char *cmd, *str; MSG_BeginReading (net_message); MSG_ReadLong (net_message); // skip the -1 marker str = MSG_ReadString (net_message); COM_TokenizeString (str, qtv_args); cmd_args = qtv_args; cmd = qtv_args->argv[0]->str; if (!strcmp (cmd, "ping")) { qtv_ping (); } else if (!strcmp (cmd, "status")) { qtv_status (); } else if (!strcmp (cmd, "getchallenge")) { Client_NewConnection (); } else if (cmd[0]) { switch (cmd[0]) { default: goto bad_packet; case A2C_PRINT: Sys_Printf ("%s", str + 1); break; case A2A_PING: qtv_ping (); break; } } else { bad_packet: Sys_Printf ("bad connectionless packet from %s:\n%s\n", NET_AdrToString (net_from), str); } }
/* * Netchan_Process * * Returns false if the message should not be processed due to being * out of order or a fragment. * * Msg must be large enough to hold MAX_MSGLEN, because if this is the * final fragment of a multi-part message, the entire thing will be * copied out. */ bool Netchan_Process( netchan_t *chan, msg_t *msg ) { int sequence, sequence_ack; int game_port = -1; int fragmentStart, fragmentLength; bool fragmented = false; int headerlength; bool compressed = false; bool lastfragment = false; // get sequence numbers MSG_BeginReading( msg ); sequence = MSG_ReadLong( msg ); sequence_ack = MSG_ReadLong( msg ); // wsw : jal : by now our header sends incoming ack too (q3 doesn't) // check for fragment information if( sequence & FRAGMENT_BIT ) { sequence &= ~FRAGMENT_BIT; fragmented = true; if( net_showfragments->integer ) Com_Printf( "Process fragmented packet (%s) (id:%i)\n", NET_SocketToString( chan->socket ), sequence ); } else { fragmented = false; } // wsw : jal : check for compressed information if( sequence_ack & FRAGMENT_BIT ) { sequence_ack &= ~FRAGMENT_BIT; compressed = true; if( !fragmented ) msg->compressed = true; } // read the game port if we are a server if( chan->socket->server ) game_port = MSG_ReadShort( msg ); // read the fragment information if( fragmented ) { fragmentStart = MSG_ReadShort( msg ); fragmentLength = MSG_ReadShort( msg ); if( fragmentLength & FRAGMENT_LAST ) { lastfragment = true; fragmentLength &= ~FRAGMENT_LAST; } } else { fragmentStart = 0; // stop warning message fragmentLength = 0; } if( showpackets->integer ) { if( fragmented ) { Com_Printf( "%s recv %4i : s=%i fragment=%i,%i\n", NET_SocketToString( chan->socket ), msg->cursize, sequence, fragmentStart, fragmentLength ); } else { Com_Printf( "%s recv %4i : s=%i\n", NET_SocketToString( chan->socket ), msg->cursize, sequence ); } } // // discard out of order or duplicated packets // if( sequence <= chan->incomingSequence ) { if( showdrop->integer || showpackets->integer ) { Com_Printf( "%s:Out of order packet %i at %i\n", NET_AddressToString( &chan->remoteAddress ), sequence, chan->incomingSequence ); } return false; } // // dropped packets don't keep the message from being used // chan->dropped = sequence - ( chan->incomingSequence+1 ); if( chan->dropped > 0 ) { if( showdrop->integer || showpackets->integer ) { Com_Printf( "%s:Dropped %i packets at %i\n", NET_AddressToString( &chan->remoteAddress ), chan->dropped, sequence ); } } // // if this is the final framgent of a reliable message, // bump incoming_reliable_sequence // if( fragmented ) { // TTimo // make sure we add the fragments in correct order // either a packet was dropped, or we received this one too soon // we don't reconstruct the fragments. we will wait till this fragment gets to us again // (NOTE: we could probably try to rebuild by out of order chunks if needed) if( sequence != chan->fragmentSequence ) { chan->fragmentSequence = sequence; chan->fragmentLength = 0; } // if we missed a fragment, dump the message if( fragmentStart != (int) chan->fragmentLength ) { if( showdrop->integer || showpackets->integer ) { Com_Printf( "%s:Dropped a message fragment\n", NET_AddressToString( &chan->remoteAddress ), sequence ); } // we can still keep the part that we have so far, // so we don't need to clear chan->fragmentLength return false; } // copy the fragment to the fragment buffer if( fragmentLength < 0 || msg->readcount + fragmentLength > msg->cursize || chan->fragmentLength + fragmentLength > sizeof( chan->fragmentBuffer ) ) { if( showdrop->integer || showpackets->integer ) { Com_Printf( "%s:illegal fragment length\n", NET_AddressToString( &chan->remoteAddress ) ); } return false; } memcpy( chan->fragmentBuffer + chan->fragmentLength, msg->data + msg->readcount, fragmentLength ); chan->fragmentLength += fragmentLength; // if this wasn't the last fragment, don't process anything if( !lastfragment ) { return false; } if( chan->fragmentLength > msg->maxsize ) { Com_Printf( "%s:fragmentLength %i > msg->maxsize\n", NET_AddressToString( &chan->remoteAddress ), chan->fragmentLength ); return false; } // wsw : jal : reconstruct the message MSG_Clear( msg ); MSG_WriteLong( msg, sequence ); MSG_WriteLong( msg, sequence_ack ); if( chan->socket->server ) MSG_WriteShort( msg, game_port ); msg->compressed = compressed; headerlength = msg->cursize; MSG_CopyData( msg, chan->fragmentBuffer, chan->fragmentLength ); msg->readcount = headerlength; // put read pointer after header again chan->fragmentLength = 0; //let it be finished as standard packets } // the message can now be read from the current message pointer chan->incomingSequence = sequence; // wsw : jal[start] : get the ack from the very first fragment chan->incoming_acknowledged = sequence_ack; // wsw : jal[end] return true; }
/* ================= SV_ConnectionlessPacket A connectionless packet has four leading 0xff characters to distinguish it from a game channel. Clients that are in the game can still send connectionless packets. ================= */ void SV_ConnectionlessPacket (void) { char *s; char *c; MSG_BeginReading (); MSG_ReadLong (); // skip the -1 marker s = MSG_ReadStringLine (); s[1023] = 0; Cmd_TokenizeString (s); c = Cmd_Argv(0); if (!strcmp(c, "ping") || ( c[0] == A2A_PING && (c[1] == 0 || c[1] == '\n')) ) { SVC_Ping (); return; } if (c[0] == A2A_ACK && (c[1] == 0 || c[1] == '\n') ) { Com_Printf ("A2A_ACK from %s\n", NET_AdrToString (net_from)); return; } else if (!strcmp(c,"status")) { SVC_Status (); return; } else if (!strcmp(c,"log")) { SVC_Log (); return; } else if (!strcmp(c,"connect")) { SVC_DirectConnect (); return; } #ifdef MAUTH else if (c[0] == M2S_AUTH_TOK && (c[1] == 0 || c[1] == '\n') ) { Com_Printf("MAUTH: Adding token from %s to auth queue\n", NET_AdrToString(net_from)); // Provisionally add auth record... if (SV_AuthListAdd(&authtokq)) { //SV_AuthListPrint(&authtokq); //SV_AuthListPrint(&authclientq); // Send S2M_AUTH_TOK_CHK as a spoofing check... Master_AuthTokChk(authtokq.start->name, authtokq.start->hash); } else { Com_Printf("MAUTH: Failure to add token from %s -- already added?\n", NET_AdrToString(net_from)); // FIXME Send S2M_AUTH_TOK_NACK } return; } else if (c[0] == M2S_AUTH_TOK_ACK && (c[1] == 0 || c[1] == '\n') ) { // The master is sending us the correct name and hash; // check that what we've got agrees with this. // FIXME do we trust this packet? char tok_ack = S2C_AUTH_TOK_ACK; authclient_t *newclient = NULL; qbool result; result = SV_AuthListValidate(&authtokq, &newclient); //SV_AuthListPrint(&authtokq); //SV_AuthListPrint(&authclientq); // Check the client is valid... if( !result ) { Com_Printf("MAUTH: Client is not valid!\n"); return; } // Tell client they can connect... Com_Printf("MAUTH: Telling client %s on %s to connect...\n", newclient->name, NET_AdrToString(newclient->client_addr)); NET_SendPacket (NS_SERVER, 1, &tok_ack, newclient->client_addr); return; } /*else if (c[0] == M2S_AUTH_TOK_NACK && (c[1] == 0 || c[1] == '\n') ) { // Master said this token not valid -- FIXME how can we trust this? // FIXME remove player details from auth queue. Com_Printf("MAUTH: Player invalid!\n"); }*/ #endif else if (!strcmp(c,"getchallenge")) { SVC_GetChallenge (); return; } else if (!strcmp(c, "rcon")) SVC_RemoteCommand (); else Com_Printf ("bad connectionless packet from %s:\n%s\n" , NET_AdrToString (net_from), s); }
static qsocket_t *_Datagram_Connect (char *host) { struct qsockaddr sendaddr; struct qsockaddr readaddr; qsocket_t *sock; int newsock; int ret; int reps; double start_time; int control; char *reason; // see if we can resolve the host name if (dfunc.GetAddrFromName(host, &sendaddr) == -1) return NULL; newsock = dfunc.OpenSocket (0); if (newsock == -1) return NULL; sock = NET_NewQSocket (); if (sock == NULL) goto ErrorReturn2; sock->socket = newsock; sock->landriver = net_landriverlevel; // connect to the host if (dfunc.Connect (newsock, &sendaddr) == -1) goto ErrorReturn; // send the connection request Con_Printf("trying...\n"); SCR_UpdateScreen (); start_time = net_time; for (reps = 0; reps < 3; reps++) { SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREQ_CONNECT); MSG_WriteString(&net_message, "QUAKE"); MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (newsock, net_message.data, net_message.cursize, &sendaddr); SZ_Clear(&net_message); do { ret = dfunc.Read (newsock, net_message.data, net_message.maxsize, &readaddr); // if we got something, validate it if (ret > 0) { // is it from the right place? if (sfunc.AddrCompare(&readaddr, &sendaddr) != 0) { #ifdef DEBUG Con_Printf("wrong reply address\n"); Con_Printf("Expected: %s\n", StrAddr (&sendaddr)); Con_Printf("Received: %s\n", StrAddr (&readaddr)); SCR_UpdateScreen (); #endif ret = 0; continue; } if (ret < sizeof(int)) { ret = 0; continue; } net_message.cursize = ret; MSG_BeginReading (); control = BigLong(*((int *)net_message.data)); MSG_ReadLong(); if (control == -1) { ret = 0; continue; } if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) { ret = 0; continue; } if ((control & NETFLAG_LENGTH_MASK) != ret) { ret = 0; continue; } } } while (ret == 0 && (SetNetTime() - start_time) < 2.5); if (ret) break; Con_Printf("still trying...\n"); SCR_UpdateScreen (); start_time = SetNetTime(); } if (ret == 0) { reason = "No Response"; Con_Printf("%s\n", reason); Q_strcpy(m_return_reason, reason); goto ErrorReturn; } if (ret == -1) { reason = "Network Error"; Con_Printf("%s\n", reason); Q_strcpy(m_return_reason, reason); goto ErrorReturn; } ret = MSG_ReadByte(); if (ret == CCREP_REJECT) { reason = MSG_ReadString(); Con_Printf(reason); Q_strncpy(m_return_reason, reason, 31); goto ErrorReturn; } if (ret == CCREP_ACCEPT) { Q_memcpy(&sock->addr, &sendaddr, sizeof(struct qsockaddr)); dfunc.SetSocketPort (&sock->addr, MSG_ReadLong()); } else { reason = "Bad Response"; Con_Printf("%s\n", reason); Q_strcpy(m_return_reason, reason); goto ErrorReturn; } dfunc.GetNameFromAddr (&sendaddr, sock->address); Con_Printf ("Connection accepted\n"); sock->lastMessageTime = SetNetTime(); // switch the connection to the specified address if (dfunc.Connect (newsock, &sock->addr) == -1) { reason = "Connect to Game failed"; Con_Printf("%s\n", reason); Q_strcpy(m_return_reason, reason); goto ErrorReturn; } m_return_onerror = false; return sock; ErrorReturn: NET_FreeQSocket(sock); ErrorReturn2: dfunc.CloseSocket(newsock); if (m_return_onerror) { key_dest = key_menu; m_state = m_return_state; m_return_onerror = false; } return NULL; }
/* ===================== CL_ParseServerMessage ===================== */ void CL_ParseServerMessage(void) { unsigned int bits; int i, cmd, prevcmd; int playernum, version, stylenum, signon, statnum; int stopsound, entitynum, channel; byte colors; player_info_t *player; lightstyle_t *style; const char *stylemap, *name; // // if recording demos, copy the message out // if (cl_shownet.value == 1) Con_Printf("%i ", net_message.cursize); else if (cl_shownet.value == 2) Con_Printf("------------------\n"); cl.onground = false; // unless the server says otherwise // // parse the message // prevcmd = svc_bad; MSG_BeginReading(); while (1) { if (msg_badread) Host_Error("%s: Bad server message", __func__); cmd = MSG_ReadByte(); if (cmd == -1) { SHOWNET("END OF MESSAGE"); return; // end of message } // if the high bit of the command byte is set, it is a fast update if (cmd & 128) { SHOWNET("fast update"); CL_ParseUpdate(cmd & 127); continue; } SHOWNET(svc_strings[cmd]); // other commands switch (cmd) { case svc_nop: break; case svc_time: cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = MSG_ReadFloat(); break; case svc_clientdata: CL_ParseClientdata(); break; case svc_version: version = MSG_ReadLong(); if (!Protocol_Known(version)) Host_Error("%s: Server returned unknown protocol version %i", __func__, version); cl.protocol = version; break; case svc_disconnect: Host_EndGame("Server disconnected\n"); case svc_print: Con_Printf("%s", MSG_ReadString()); break; case svc_centerprint: SCR_CenterPrint(MSG_ReadString()); break; case svc_stufftext: Cbuf_AddText("%s", MSG_ReadString()); break; case svc_damage: V_ParseDamage(); break; case svc_serverinfo: CL_ParseServerInfo(); vid.recalc_refdef = true; // leave intermission full screen break; case svc_setangle: for (i = 0; i < 3; i++) cl.viewangles[i] = MSG_ReadAngle(); break; case svc_setview: cl.viewentity = MSG_ReadShort(); break; case svc_lightstyle: stylenum = MSG_ReadByte(); if (stylenum >= MAX_LIGHTSTYLES) Sys_Error("svc_lightstyle > MAX_LIGHTSTYLES"); stylemap = MSG_ReadString(); style = cl_lightstyle + stylenum; snprintf(style->map, MAX_STYLESTRING, "%s", stylemap); style->length = strlen(style->map); break; case svc_sound: CL_ParseStartSoundPacket(); break; case svc_stopsound: stopsound = MSG_ReadShort(); /* 3-bit channel encoded in lsb */ entitynum = stopsound >> 3; channel = stopsound & 7; S_StopSound(entitynum, channel); break; case svc_updatename: Sbar_Changed(); playernum = MSG_ReadByte(); if (playernum >= cl.maxclients) Host_Error("%s: svc_updatename > MAX_SCOREBOARD", __func__); name = MSG_ReadString(); player = cl.players + playernum; snprintf(player->name, MAX_SCOREBOARDNAME, "%s", name); break; case svc_updatefrags: Sbar_Changed(); playernum = MSG_ReadByte(); if (playernum >= cl.maxclients) Host_Error("%s: svc_updatefrags > MAX_SCOREBOARD", __func__); player = cl.players + playernum; player->frags = MSG_ReadShort(); break; case svc_updatecolors: Sbar_Changed(); playernum = MSG_ReadByte(); if (playernum >= cl.maxclients) Host_Error("%s: svc_updatecolors > MAX_SCOREBOARD", __func__); colors = MSG_ReadByte(); player = cl.players + playernum; player->topcolor = (colors & 0xf0) >> 4; player->bottomcolor = colors & 0x0f; /* FIXME - is this the right check for current player? */ if (playernum == cl.viewentity) cl_color.value = colors; CL_NewTranslation(playernum); break; case svc_particle: R_ParseParticleEffect(); break; case svc_spawnbaseline: entitynum = MSG_ReadShort(); // must use CL_EntityNum() to force cl.num_entities up CL_ParseBaseline(CL_EntityNum(entitynum), 0); break; case svc_fitz_spawnbaseline2: /* FIXME - check here that protocol is FITZ? => Host_Error() */ entitynum = MSG_ReadShort(); bits = MSG_ReadByte(); // must use CL_EntityNum() to force cl.num_entities up CL_ParseBaseline(CL_EntityNum(entitynum), bits); break; case svc_spawnstatic: CL_ParseStatic(0); break; case svc_fitz_spawnstatic2: /* FIXME - check here that protocol is FITZ? => Host_Error() */ bits = MSG_ReadByte(); CL_ParseStatic(bits); break; case svc_temp_entity: CL_ParseTEnt(); break; case svc_setpause: cl.paused = MSG_ReadByte(); if (cl.paused) CDAudio_Pause(); else CDAudio_Resume(); break; case svc_signonnum: signon = MSG_ReadByte(); if (signon <= cls.signon) Host_Error("Received signon %d when at %d", signon, cls.signon); cls.signon = signon; CL_SignonReply(); break; case svc_killedmonster: cl.stats[STAT_MONSTERS]++; break; case svc_foundsecret: cl.stats[STAT_SECRETS]++; break; case svc_updatestat: statnum = MSG_ReadByte(); if (statnum < 0 || statnum >= MAX_CL_STATS) Sys_Error("svc_updatestat: %d is invalid", statnum); cl.stats[statnum] = MSG_ReadLong(); break; case svc_spawnstaticsound: CL_ParseStaticSound(); break; case svc_fitz_spawnstaticsound2: /* FIXME - check here that protocol is FITZ? => Host_Error() */ CL_ParseFitzStaticSound2(); break; case svc_cdtrack: cl.cdtrack = MSG_ReadByte(); cl.looptrack = MSG_ReadByte(); if ((cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1)) CDAudio_Play((byte)cls.forcetrack, true); else CDAudio_Play((byte)cl.cdtrack, true); break; case svc_intermission: cl.intermission = 1; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen break; case svc_finale: cl.intermission = 2; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen SCR_CenterPrint(MSG_ReadString()); break; case svc_cutscene: cl.intermission = 3; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen SCR_CenterPrint(MSG_ReadString()); break; case svc_sellscreen: Cmd_ExecuteString("help", src_command); break; /* Various FITZ protocol messages - FIXME - !protocol => Host_Error */ case svc_fitz_skybox: MSG_ReadString(); // FIXME - TODO break; case svc_fitz_bf: Cmd_ExecuteString("bf", src_command); break; case svc_fitz_fog: /* FIXME - TODO */ MSG_ReadByte(); // density MSG_ReadByte(); // red MSG_ReadByte(); // green MSG_ReadByte(); // blue MSG_ReadShort(); // time break; default: Host_Error("%s: Illegible server message. Previous was %s", __func__, svc_strings[prevcmd]); } prevcmd = cmd; } }
/* ================= 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); } } }
/* ================= Netchan_Process Returns qfalse if the message should not be processed due to being out of order or a fragment. Msg must be large enough to hold MAX_MSGLEN, because if this is the final fragment of a multi-part message, the entire thing will be copied out. ================= */ qboolean Netchan_Process( netchan_t *chan, msg_t *msg ) { int sequence; int fragmentStart, fragmentLength; qboolean fragmented; // get sequence numbers MSG_BeginReading( msg ); sequence = MSG_ReadLong( msg ); // check for fragment information if ( sequence & FRAGMENT_BIT ) { sequence &= ~FRAGMENT_BIT; fragmented = qtrue; } else { fragmented = qfalse; } // Pop off the qport if we are a server if ( chan->sock == NS_SERVER ) { MSG_ReadShort( msg ); } // read the fragment information if ( fragmented ) { fragmentStart = MSG_ReadLong( msg ); fragmentLength = MSG_ReadShort( msg ); } else { fragmentStart = 0; // stop warning message fragmentLength = 0; } if ( showpackets->boolean ) { if ( fragmented ) { Com_Printf( "%s recv %4i : s=%i fragment=%i,%i\n" , netsrcString[ chan->sock ] , msg->cursize , sequence , fragmentStart, fragmentLength ); } else { Com_Printf( "%s recv %4i : s=%i\n" , netsrcString[ chan->sock ] , msg->cursize , sequence ); } } // // discard out of order or duplicated packets // if ( sequence <= chan->incomingSequence ) { if ( showdrop->boolean || showpackets->boolean ) { Com_Printf( "%s:Out of order packet %i at %i\n" , NET_AdrToString( &chan->remoteAddress ) , sequence , chan->incomingSequence ); } return qfalse; } // // dropped packets don't keep the message from being used // chan->dropped = sequence - ( chan->incomingSequence + 1 ); if ( chan->dropped > 0 ) { if ( showdrop->boolean || showpackets->boolean ) { Com_Printf( "%s:Dropped %i packets at %i\n" , NET_AdrToString( &chan->remoteAddress ) , chan->dropped , sequence ); } } // // if this is the final framgent of a reliable message, // bump incoming_reliable_sequence // if ( fragmented ) { // TTimo // make sure we add the fragments in correct order // either a packet was dropped, or we received this one too soon // we don't reconstruct the fragments. we will wait till this fragment gets to us again // (NOTE: we could probably try to rebuild by out of order chunks if needed) if ( sequence != chan->fragmentSequence ) { chan->fragmentSequence = sequence; chan->fragmentLength = 0; } // if we missed a fragment, dump the message if ( fragmentStart != chan->fragmentLength ) { if ( showdrop->boolean || showpackets->boolean ) { Com_Printf( "%s:Dropped a message fragment seq: %d\n", NET_AdrToString( &chan->remoteAddress ), sequence ); } // we can still keep the part that we have so far, // so we don't need to clear chan->fragmentLength return qfalse; } // copy the fragment to the fragment buffer if ( fragmentLength < 0 || msg->readcount + fragmentLength > msg->cursize || chan->fragmentLength + fragmentLength > chan->fragmentBufferSize) { if ( showdrop->boolean || showpackets->boolean ) { Com_Printf( "%s:illegal fragment length: Current %i Fragment length %i Max %i\n", NET_AdrToString( &chan->remoteAddress ), chan->fragmentLength, fragmentLength, chan->fragmentBufferSize); } return qfalse; } memcpy( chan->fragmentBuffer + chan->fragmentLength, msg->data + msg->readcount, fragmentLength ); chan->fragmentLength += fragmentLength; // if this wasn't the last fragment, don't process anything if ( fragmentLength == FRAGMENT_SIZE ) { return qfalse; } if ( chan->fragmentLength > msg->maxsize ) { Com_Printf( "%s:fragmentLength %i > msg->maxsize\n", NET_AdrToString( &chan->remoteAddress ), chan->fragmentLength ); return qfalse; } // copy the full message over the partial fragment // make sure the sequence number is still there *(int *)msg->data = LittleLong( sequence ); memcpy( msg->data + 4, chan->fragmentBuffer, chan->fragmentLength ); msg->cursize = chan->fragmentLength + 4; chan->fragmentLength = 0; msg->readcount = 4; // past the sequence number msg->bit = 32; // past the sequence number // TTimo // clients were not acking fragmented messages chan->incomingSequence = sequence; return qtrue; } // // the message can now be read from the current message pointer // chan->incomingSequence = sequence; return qtrue; }
qboolean Netchan_Process (netchan_t *chan) { unsigned int reliable_ack, reliable_message, sequence, sequence_ack; if (!net_blocksend) if (!NET_CompareAdr (net_from, chan->remote_address)) return false; /// Get the sequence numbers. MSG_BeginReading (net_message); sequence = MSG_ReadLong (net_message); sequence_ack = MSG_ReadLong (net_message); /// Read the qport if appropriate (we are a server), but ignore it. if (chan->flags & NC_QPORT_READ) MSG_ReadShort (net_message); reliable_message = sequence >> 31; reliable_ack = sequence_ack >> 31; sequence &= ~(1 << 31); sequence_ack &= ~(1 << 31); if (showpackets->int_val & 2) Sys_Printf ("<-- s=%i(%i) a=%i(%i) %i\n", sequence, reliable_message, sequence_ack, reliable_ack, net_message->message->cursize); // get a rate estimation #if 0 // FIXME: Dead code if (chan->outgoing_sequence - sequence_ack < MAX_LATENT) { int i; double time, rate; i = sequence_ack & (MAX_LATENT - 1); time = *net_realtime - chan->outgoing_time[i]; time -= 0.1; // subtract 100 ms if (time <= 0) { // gotta be a digital link for <100 // ms ping if (chan->rate > 1.0 / 5000) chan->rate = 1.0 / 5000; } else { if (chan->outgoing_size[i] < 512) { // deal with only small // messages rate = chan->outgoing_size[i] / time; if (rate > 5000) rate = 5000; rate = 1.0 / rate; if (chan->rate > rate) chan->rate = rate; } } } #endif /// Discard stale or duplicated packets. if (sequence < (unsigned int) chan->incoming_sequence + 1) { if (showdrop->int_val) Sys_Printf ("%s:Out of order packet %i at %i\n", NET_AdrToString (chan->remote_address), sequence, chan->incoming_sequence); return false; } /// Dropped packets don't keep the message from being used. chan->net_drop = sequence - (chan->incoming_sequence + 1); if (chan->net_drop > 0) { chan->drop_count += 1; if (showdrop->int_val) Sys_Printf ("%s:Dropped %i packets at %i\n", NET_AdrToString (chan->remote_address), sequence - (chan->incoming_sequence + 1), sequence); } /// If the current outgoing reliable message has been acknowledged, /// clear the buffer to make way for the next. if (reliable_ack == (unsigned int) chan->reliable_sequence) chan->reliable_length = 0; // it has been received /// If this message contains a reliable message, bump /// incoming_reliable_sequence chan->incoming_sequence = sequence; chan->incoming_acknowledged = sequence_ack; chan->incoming_reliable_acknowledged = reliable_ack; if (reliable_message) chan->incoming_reliable_sequence ^= 1; // The message can now be read from the current message pointer. /// Update statistics counters. chan->frame_latency = chan->frame_latency * OLD_AVG + (chan->outgoing_sequence - sequence_ack) * (1.0 - OLD_AVG); chan->frame_rate = chan->frame_rate * OLD_AVG + (*net_realtime - chan->last_received) * (1.0 - OLD_AVG); chan->good_count += 1; chan->last_received = *net_realtime; return true; }
/* ==================== CL_ReadDemoMessage Handles playback of demos ==================== */ void CL_ReadDemoMessage(void) { int i; float f; if (!cls.demoplayback) return; // LordHavoc: pausedemo if (cls.demopaused) return; for (;;) { // decide if it is time to grab the next message // always grab until fully connected if (cls.signon == SIGNONS) { if (cls.timedemo) { cls.td_frames++; cls.td_onesecondframes++; // if this is the first official frame we can now grab the real // td_starttime so the bogus time on the first frame doesn't // count against the final report if (cls.td_frames == 0) { cls.td_starttime = realtime; cls.td_onesecondnexttime = cl.time + 1; cls.td_onesecondrealtime = realtime; cls.td_onesecondframes = 0; cls.td_onesecondminfps = 0; cls.td_onesecondmaxfps = 0; cls.td_onesecondavgfps = 0; cls.td_onesecondavgcount = 0; } if (cl.time >= cls.td_onesecondnexttime) { double fps = cls.td_onesecondframes / (realtime - cls.td_onesecondrealtime); if (cls.td_onesecondavgcount == 0) { cls.td_onesecondminfps = fps; cls.td_onesecondmaxfps = fps; } cls.td_onesecondrealtime = realtime; cls.td_onesecondminfps = min(cls.td_onesecondminfps, fps); cls.td_onesecondmaxfps = max(cls.td_onesecondmaxfps, fps); cls.td_onesecondavgfps += fps; cls.td_onesecondavgcount++; cls.td_onesecondframes = 0; cls.td_onesecondnexttime++; } } else if (cl.time <= cl.mtime[0]) { // don't need another message yet return; } } // get the next message FS_Read(cls.demofile, &cl_message.cursize, 4); cl_message.cursize = LittleLong(cl_message.cursize); if(cl_message.cursize & DEMOMSG_CLIENT_TO_SERVER) // This is a client->server message! Ignore for now! { // skip over demo packet FS_Seek(cls.demofile, 12 + (cl_message.cursize & (~DEMOMSG_CLIENT_TO_SERVER)), SEEK_CUR); continue; } if (cl_message.cursize > cl_message.maxsize) { Con_Printf("Demo message (%i) > cl_message.maxsize (%i)", cl_message.cursize, cl_message.maxsize); cl_message.cursize = 0; CL_Disconnect(); return; } VectorCopy(cl.mviewangles[0], cl.mviewangles[1]); for (i = 0;i < 3;i++) { FS_Read(cls.demofile, &f, 4); cl.mviewangles[0][i] = LittleFloat(f); } if (FS_Read(cls.demofile, cl_message.data, cl_message.cursize) == cl_message.cursize) { MSG_BeginReading(&cl_message); CL_ParseServerMessage(); if (cls.signon != SIGNONS) Cbuf_Execute(); // immediately execute svc_stufftext if in the demo before connect! // In case the demo contains a "svc_disconnect" message if (!cls.demoplayback) return; if (cls.timedemo) return; } else { CL_Disconnect(); return; } } }
/* * CL_ParseGetServersResponseMessage * Handle a reply from getservers message to master server */ static void CL_ParseGetServersResponseMessage( msg_t *msg, qboolean extended ) { const char *header; char adrString[64]; qbyte addr[16]; unsigned short port; netadr_t adr; MSG_BeginReading( msg ); MSG_ReadLong( msg ); // skip the -1 //jump over the command name header = ( extended ? "getserversExtResponse" : "getserversResponse" ); if( !MSG_SkipData( msg, strlen( header ) ) ) { Com_Printf( "Invalid master packet ( missing %s )\n", header ); return; } while( msg->readcount + 7 <= msg->cursize ) { char prefix = MSG_ReadChar( msg ); switch( prefix ) { case '\\': MSG_ReadData( msg, addr, 4 ); port = ShortSwap( MSG_ReadShort( msg ) ); // both endians need this swapped. Q_snprintfz( adrString, sizeof( adrString ), "%u.%u.%u.%u:%u", addr[0], addr[1], addr[2], addr[3], port ); break; case '/': if( extended ) { MSG_ReadData( msg, addr, 16 ); port = ShortSwap( MSG_ReadShort( msg ) ); // both endians need this swapped. Q_snprintfz( adrString, sizeof( adrString ), "[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%hu", addr[ 0], addr[ 1], addr[ 2], addr[ 3], addr[ 4], addr[ 5], addr[ 6], addr[ 7], addr[ 8], addr[ 9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15], port ); } else { Com_Printf( "Invalid master packet ( IPv6 prefix in a non-extended response )\n" ); return; } break; default: Com_Printf( "Invalid master packet ( missing separator )\n" ); return; } if( port == 0 ) // last server seen return; Com_DPrintf( "%s\n", adrString ); if( !NET_StringToAddress( adrString, &adr ) ) { Com_Printf( "Bad address: %s\n", adrString ); continue; } CL_AddServerToList( &masterList, adrString, 0 ); } }
static qsocket_t *_Datagram_CheckNewConnections (void) { struct qsockaddr clientaddr; struct qsockaddr newaddr; int newsock; int acceptsock; qsocket_t *sock; qsocket_t *s; int len; int command; int control; int ret; acceptsock = dfunc.CheckNewConnections(); if (acceptsock == -1) return NULL; SZ_Clear(&net_message); len = dfunc.Read (acceptsock, net_message.data, net_message.maxsize, &clientaddr); if (len < sizeof(int)) return NULL; net_message.cursize = len; MSG_BeginReading (); control = BigLong(*((int *)net_message.data)); MSG_ReadLong(); if (control == -1) return NULL; if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) return NULL; if ((control & NETFLAG_LENGTH_MASK) != len) return NULL; command = MSG_ReadByte(); if (command == CCREQ_SERVER_INFO) { if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0) return NULL; SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_SERVER_INFO); dfunc.GetSocketAddr(acceptsock, &newaddr); MSG_WriteString(&net_message, dfunc.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)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } if (command == CCREQ_PLAYER_INFO) { int playerNumber; int activeNumber; int clientNumber; client_t *client; playerNumber = MSG_ReadByte(); activeNumber = -1; for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++) { if (client->active) { activeNumber++; if (activeNumber == playerNumber) break; } } if (clientNumber == svs.maxclients) return NULL; SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_PLAYER_INFO); MSG_WriteByte(&net_message, playerNumber); MSG_WriteString(&net_message, client->name); MSG_WriteLong(&net_message, client->colors); MSG_WriteLong(&net_message, (int)client->edict->v.frags); MSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime)); MSG_WriteString(&net_message, client->netconnection->address); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } if (command == CCREQ_RULE_INFO) { char *prevCvarName; cvar_t *var; // find the search start location prevCvarName = MSG_ReadString(); if (*prevCvarName) { var = Cvar_FindVar (prevCvarName); if (!var) return NULL; var = var->next; } else var = cvar_vars; // search for the next server cvar while (var) { if (var->server) break; var = var->next; } // send the response SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_RULE_INFO); if (var) { MSG_WriteString(&net_message, var->name); MSG_WriteString(&net_message, var->string); } *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } if (command != CCREQ_CONNECT) return NULL; if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0) return NULL; if (MSG_ReadByte() != NET_PROTOCOL_VERSION) { 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)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } #ifdef BAN_TEST // check for a ban if (clientaddr.sa_family == AF_INET) { unsigned long testAddr; testAddr = ((struct sockaddr_in *)&clientaddr)->sin_addr.s_addr; if ((testAddr & banMask) == banAddr) { 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, "You have been banned.\n"); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } } #endif // see if this guy is already connected for (s = net_activeSockets; s; s = s->next) { if (s->driver != net_driverlevel) continue; ret = dfunc.AddrCompare(&clientaddr, &s->addr); if (ret >= 0) { // is this a duplicate connection reqeust? if (ret == 0 && net_time - s->connecttime < 2.0) { // yes, so send a duplicate reply SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_ACCEPT); dfunc.GetSocketAddr(s->socket, &newaddr); MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr)); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } // it's somebody coming back in from a crash/disconnect // so close the old qsocket and let their retry get them back in NET_Close(s); return NULL; } } // allocate a QSocket sock = NET_NewQSocket (); if (sock == NULL) { // no room; try to let him 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)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } // allocate a network socket newsock = dfunc.OpenSocket(0); if (newsock == -1) { NET_FreeQSocket(sock); return NULL; } // connect to the client if (dfunc.Connect (newsock, &clientaddr) == -1) { dfunc.CloseSocket(newsock); NET_FreeQSocket(sock); return NULL; } // everything is allocated, just fill in the details sock->socket = newsock; sock->landriver = net_landriverlevel; sock->addr = clientaddr; Q_strcpy(sock->address, dfunc.AddrToString(&clientaddr)); // send him back the info about the server connection he has been allocated SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_ACCEPT); dfunc.GetSocketAddr(newsock, &newaddr); MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr)); // MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr)); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return sock; }