//================ // SV_MMHeartbeat // Send matchmaker a heartbeat with status //================ void SV_MMHeartbeat( void ) { static qboolean canhost = qfalse; netadr_t address; socket_t *socket; if( !sv_public->integer ) return; // never go public when not acting as a game server if( sv.state > ss_game ) return; if( !SV_MM_Initialized() || SV_MM_IsLocked() ) return; svc.last_mmheartbeat -= svc.snapFrameTime; if( svc.last_mmheartbeat > 0 && canhost == SV_MM_CanHost() ) return; if ( !SV_MM_NetAddress( &address ) ) return; svc.last_mmheartbeat = MM_HEARTBEAT_SECONDS * 1000; canhost = SV_MM_CanHost(); socket = ( address.type == NA_IP6 ? &svs.socket_udp6 : &svs.socket_udp ); Netchan_OutOfBandPrint( socket, &address, "heartbeat %s %d %d %s", canhost ? "yes":"no", APP_PROTOCOL_VERSION, SV_MM_GetSlotCount(), SV_MM_Salt() ); Com_Printf( "Sending heartbeat to matchmaker\n" ); }
/* * 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 ); } } } } }