void NET_Query_MasterResponse(net_packet_t *packet) { unsigned int packet_type; unsigned int result; if (!NET_ReadInt16(packet, &packet_type) || !NET_ReadInt16(packet, &result)) { return; } if (packet_type == NET_MASTER_PACKET_TYPE_ADD_RESPONSE) { if (result != 0) { // Only show the message once. if (!registered_with_master) { printf("Registered with master server at %s\n", MASTER_SERVER_ADDRESS); registered_with_master = true; } } else { // Always show rejections. printf("Failed to register with master server at %s\n", MASTER_SERVER_ADDRESS); } got_master_response = true; } }
static net_packet_t *BlockForPacket(net_addr_t *addr, unsigned int packet_type, unsigned int timeout_ms) { net_packet_t *packet; net_addr_t *packet_src; unsigned int read_packet_type; unsigned int start_time; start_time = I_GetTimeMS(); while (I_GetTimeMS() < start_time + timeout_ms) { if (!NET_RecvPacket(query_context, &packet_src, &packet)) { I_Sleep(20); continue; } if (packet_src == addr && NET_ReadInt16(packet, &read_packet_type) && packet_type == read_packet_type) { return packet; } NET_FreePacket(packet); } // Timeout - no response. return NULL; }
static void NET_SV_MasterPacket(net_packet_t *packet) { unsigned int packet_type; // Read the packet type if (!NET_ReadInt16(packet, &packet_type)) { NET_Log("server: error: no packet type in master server message"); return; } NET_Log("server: packet from master server; type %d", packet_type); NET_LogPacket(packet); switch (packet_type) { case NET_MASTER_PACKET_TYPE_ADD_RESPONSE: NET_Query_AddResponse(packet); break; case NET_MASTER_PACKET_TYPE_NAT_HOLE_PUNCH: NET_SV_ParseHolePunch(packet); break; } }
static void NET_CL_ParsePacket(net_packet_t *packet) { unsigned int packet_type; if (!NET_ReadInt16(packet, &packet_type)) { return; } if (NET_Conn_Packet(&client_connection, packet, &packet_type)) { // Packet eaten by the common connection code } else { switch (packet_type) { case NET_PACKET_TYPE_WAITING_DATA: NET_CL_ParseWaitingData(packet); break; case NET_PACKET_TYPE_LAUNCH: NET_CL_ParseLaunch(packet); break; case NET_PACKET_TYPE_GAMESTART: NET_CL_ParseGameStart(packet); break; case NET_PACKET_TYPE_GAMEDATA: NET_CL_ParseGameData(packet); break; case NET_PACKET_TYPE_GAMEDATA_RESEND: NET_CL_ParseResendRequest(packet); break; case NET_PACKET_TYPE_CONSOLE_MESSAGE: NET_CL_ParseConsoleMessage(packet); break; default: break; } } }
static void NET_Query_ParseMasterResponse(net_addr_t *master_addr, net_packet_t *packet) { unsigned int packet_type; query_target_t *target; char *addr_str; net_addr_t *addr; // Read the header. We are only interested in query responses. if (!NET_ReadInt16(packet, &packet_type) || packet_type != NET_MASTER_PACKET_TYPE_QUERY_RESPONSE) { return; } // Read a list of strings containing the addresses of servers // that the master knows about. for (;;) { addr_str = NET_ReadString(packet); if (addr_str == NULL) { break; } // Resolve address and add to targets list if it is not already // there. addr = NET_ResolveAddress(query_context, addr_str); if (addr != NULL) { GetTargetForAddr(addr, true); } } // Mark the master as having responded. target = GetTargetForAddr(master_addr, true); target->state = QUERY_TARGET_RESPONDED; }
static void NET_Query_ParseResponse(net_addr_t *addr, net_packet_t *packet, net_query_callback_t callback, void *user_data) { unsigned int packet_type; net_querydata_t querydata; query_target_t *target; // Read the header if (!NET_ReadInt16(packet, &packet_type) || packet_type != NET_PACKET_TYPE_QUERY_RESPONSE) { return; } // Read query data if (!NET_ReadQueryData(packet, &querydata)) { return; } // Find the target that responded. target = GetTargetForAddr(addr, false); // If the target is not found, it may be because we are doing // a LAN broadcast search, in which case we need to create a // target for the new responder. if (target == NULL) { query_target_t *broadcast_target; broadcast_target = GetTargetForAddr(NULL, false); // Not in broadcast mode, unexpected response that came out // of nowhere. Ignore. if (broadcast_target == NULL || broadcast_target->state != QUERY_TARGET_QUERIED) { return; } // Create new target. target = GetTargetForAddr(addr, true); target->state = QUERY_TARGET_QUERIED; target->query_time = broadcast_target->query_time; } if (target->state != QUERY_TARGET_RESPONDED) { target->state = QUERY_TARGET_RESPONDED; memcpy(&target->data, &querydata, sizeof(net_querydata_t)); // Calculate RTT. target->ping_time = I_GetTimeMS() - target->query_time; // Invoke callback to signal that we have a new address. callback(addr, &target->data, target->ping_time, user_data); } }
static void NET_SV_ParseSYN(net_packet_t *packet, net_client_t *client, net_addr_t *addr) { unsigned int magic; unsigned int cl_gamemode, cl_gamemission; unsigned int cl_recording_lowres; unsigned int cl_drone; unsigned int is_freedoom; md5_digest_t deh_md5sum, wad_md5sum; char *player_name; char *client_version; int i; // read the magic number if (!NET_ReadInt32(packet, &magic)) { return; } if (magic != NET_MAGIC_NUMBER) { // invalid magic number return; } // Check the client version is the same as the server client_version = NET_ReadString(packet); if (client_version == NULL) { return; } if (strcmp(client_version, PACKAGE_STRING) != 0) { //! // @category net // // When running a netgame server, ignore version mismatches between // the server and the client. Using this option may cause game // desyncs to occur, or differences in protocol may mean the netgame // will simply not function at all. // if (M_CheckParm("-ignoreversion") == 0) { NET_SV_SendReject(addr, "Version mismatch: server version is: " PACKAGE_STRING); return; } } // read the game mode and mission if (!NET_ReadInt16(packet, &cl_gamemode) || !NET_ReadInt16(packet, &cl_gamemission) || !NET_ReadInt8(packet, &cl_recording_lowres) || !NET_ReadInt8(packet, &cl_drone) || !NET_ReadMD5Sum(packet, wad_md5sum) || !NET_ReadMD5Sum(packet, deh_md5sum) || !NET_ReadInt8(packet, &is_freedoom)) { return; } if (!NET_ValidGameMode(cl_gamemode, cl_gamemission)) { return; } // read the player's name player_name = NET_ReadString(packet); if (player_name == NULL) { return; } // received a valid SYN // not accepting new connections? if (server_state != SERVER_WAITING_START) { NET_SV_SendReject(addr, "Server is not currently accepting connections"); return; } // allocate a client slot if there isn't one already if (client == NULL) { // find a slot, or return if none found for (i=0; i<MAXNETNODES; ++i) { if (!clients[i].active) { client = &clients[i]; break; } } if (client == NULL) { return; } } else { // If this is a recently-disconnected client, deactivate // to allow immediate reconnection if (client->connection.state == NET_CONN_STATE_DISCONNECTED) { client->active = false; } } // New client? if (!client->active) { int num_players; // Before accepting a new client, check that there is a slot // free NET_SV_AssignPlayers(); num_players = NET_SV_NumPlayers(); if ((!cl_drone && num_players >= MAXPLAYERS) || NET_SV_NumClients() >= MAXNETNODES) { NET_SV_SendReject(addr, "Server is full!"); return; } // TODO: Add server option to allow rejecting clients which // set lowres_turn. This is potentially desirable as the // presence of such clients affects turning resolution. // Adopt the game mode and mission of the first connecting client if (num_players == 0 && !cl_drone) { sv_gamemode = cl_gamemode; sv_gamemission = cl_gamemission; } // Save the MD5 checksums memcpy(client->wad_md5sum, wad_md5sum, sizeof(md5_digest_t)); memcpy(client->deh_md5sum, deh_md5sum, sizeof(md5_digest_t)); client->is_freedoom = is_freedoom; // Check the connecting client is playing the same game as all // the other clients if (cl_gamemode != sv_gamemode || cl_gamemission != sv_gamemission) { NET_SV_SendReject(addr, "You are playing the wrong game!"); return; } // Activate, initialize connection NET_SV_InitNewClient(client, addr, player_name); client->recording_lowres = cl_recording_lowres; client->drone = cl_drone; } if (client->connection.state == NET_CONN_STATE_WAITING_ACK) { // force an acknowledgement client->connection.last_send_time = -1; } }
static void NET_SV_Packet(net_packet_t *packet, net_addr_t *addr) { net_client_t *client; unsigned int packet_type; // Response from master server? if (addr != NULL && addr == master_server) { NET_Query_MasterResponse(packet); return; } // Find which client this packet came from client = NET_SV_FindClient(addr); // Read the packet type if (!NET_ReadInt16(packet, &packet_type)) { // no packet type return; } if (packet_type == NET_PACKET_TYPE_SYN) { NET_SV_ParseSYN(packet, client, addr); } else if (packet_type == NET_PACKET_TYPE_QUERY) { NET_SV_SendQueryResponse(addr); } else if (client == NULL) { // Must come from a valid client; ignore otherwise } else if (NET_Conn_Packet(&client->connection, packet, &packet_type)) { // Packet was eaten by the common connection code } else { //printf("SV: %s: %i\n", NET_AddrToString(addr), packet_type); switch (packet_type) { case NET_PACKET_TYPE_GAMESTART: NET_SV_ParseGameStart(packet, client); break; case NET_PACKET_TYPE_GAMEDATA: NET_SV_ParseGameData(packet, client); break; case NET_PACKET_TYPE_GAMEDATA_ACK: NET_SV_ParseGameDataACK(packet, client); break; case NET_PACKET_TYPE_GAMEDATA_RESEND: NET_SV_ParseResendRequest(packet, client); break; default: // unknown packet type break; } } // If this address is not in the list of clients, be sure to // free it back. if (NET_SV_FindClient(addr) == NULL) { NET_FreeAddress(addr); } }
static void NET_SV_Packet(net_packet_t *packet, net_addr_t *addr) { net_client_t *client; unsigned int packet_type; // Response from master server? if (addr != NULL && addr == master_server) { NET_SV_MasterPacket(packet); return; } // Find which client this packet came from client = NET_SV_FindClient(addr); // Read the packet type if (!NET_ReadInt16(packet, &packet_type)) { // no packet type return; } NET_Log("server: packet from %s; type %d", NET_AddrToString(addr), packet_type & ~NET_RELIABLE_PACKET); NET_LogPacket(packet); if (packet_type == NET_PACKET_TYPE_SYN) { NET_SV_ParseSYN(packet, client, addr); } else if (packet_type == NET_PACKET_TYPE_QUERY) { NET_SV_SendQueryResponse(addr); } else if (client == NULL) { // Must come from a valid client; ignore otherwise } else if (NET_Conn_Packet(&client->connection, packet, &packet_type)) { // Packet was eaten by the common connection code } else { //printf("SV: %s: %i\n", NET_AddrToString(addr), packet_type); switch (packet_type) { case NET_PACKET_TYPE_GAMESTART: NET_SV_ParseGameStart(packet, client); break; case NET_PACKET_TYPE_LAUNCH: NET_SV_ParseLaunch(packet, client); break; case NET_PACKET_TYPE_GAMEDATA: NET_SV_ParseGameData(packet, client); break; case NET_PACKET_TYPE_GAMEDATA_ACK: NET_SV_ParseGameDataACK(packet, client); break; case NET_PACKET_TYPE_GAMEDATA_RESEND: NET_SV_ParseResendRequest(packet, client); break; default: // unknown packet type break; } } }