Ejemplo n.º 1
0
static void NET_QueryPrintCallback(net_addr_t *addr,
                                   net_querydata_t *data,
                                   unsigned int ping_time,
                                   void *user_data)
{
    // If this is the first server, print the header.

    if (!printed_header)
    {
        PrintHeader();
        printed_header = true;
    }

    formatted_printf(5, "%4i", ping_time);
    formatted_printf(18, "%s: ", NET_AddrToString(addr));
    formatted_printf(8, "%i/%i", data->num_players, 
                                 data->max_players);

    if (data->gamemode != indetermined)
    {
        printf("(%s) ", GameDescription(data->gamemode, 
                                        data->gamemission));
    }

    if (data->server_state)
    {
        printf("(game running) ");
    }

    NET_SafePuts(data->description);
}
Ejemplo n.º 2
0
static void NET_SV_SendWaitingData(net_client_t *client)
{
    net_waitdata_t wait_data;
    net_packet_t *packet;
    net_client_t *controller;
    int i;

    NET_SV_AssignPlayers();

    controller = NET_SV_Controller();

    wait_data.num_players = NET_SV_NumPlayers();
    wait_data.num_drones = NET_SV_NumDrones();
    wait_data.ready_players = NET_SV_NumReadyPlayers();
    wait_data.max_players = NET_SV_MaxPlayers();
    wait_data.is_controller = (client == controller);
    wait_data.consoleplayer = client->player_number;

    // Send the WAD and dehacked checksums of the controlling client.
    // If no controller found (?), send the details that the client
    // is expecting anyway.

    if (controller == NULL)
    {
        controller = client;
    }

    memcpy(&wait_data.wad_sha1sum, &controller->wad_sha1sum,
           sizeof(sha1_digest_t));
    memcpy(&wait_data.deh_sha1sum, &controller->deh_sha1sum,
           sizeof(sha1_digest_t));
    wait_data.is_freedoom = controller->is_freedoom;

    // set name and address of each player:

    for (i = 0; i < wait_data.num_players; ++i)
    {
        M_StringCopy(wait_data.player_names[i],
                     sv_players[i]->name,
                     MAXPLAYERNAME);
        M_StringCopy(wait_data.player_addrs[i],
                     NET_AddrToString(sv_players[i]->addr),
                     MAXPLAYERNAME);
    }

    // Construct packet:

    packet = NET_NewPacket(10);
    NET_WriteInt16(packet, NET_PACKET_TYPE_WAITING_DATA);
    NET_WriteWaitData(packet, &wait_data);

    // Send packet to client and free

    NET_Conn_SendPacket(&client->connection, packet);
    NET_FreePacket(packet);
}
Ejemplo n.º 3
0
void NET_SV_CheckDeadlock(net_client_t *client)
{
    int nowtime;
    int i;

    // Don't expect game data from clients.

    if (client->drone)
    {
        return;
    }

    nowtime = I_GetTimeMS();

    // If we haven't received anything for a long time, it may be a deadlock.

    if (nowtime - client->last_gamedata_time > 1000)
    {
        NET_Log("server: no gamedata from %s since %d - deadlock?",
                NET_AddrToString(client->addr),
                client->last_gamedata_time);

        // Search the receive window for the first tic we are expecting
        // from this player.

        for (i=0; i<BACKUPTICS; ++i)
        {
            if (!recvwindow[client->player_number][i].active)
            {
                NET_Log("server: deadlock: sending resend request for %d-%d",
                        recvwindow_start + i, recvwindow_start + i + 5);

                // Found a tic we haven't received.  Send a resend request.

                NET_SV_SendResendRequest(client,
                                         recvwindow_start + i,
                                         recvwindow_start + i + 5);

                client->last_gamedata_time = nowtime;
                break;
            }
        }

        // If we sent a resend request to break the deadlock, also trigger a
        // resend of any tics we have sitting in the send queue, in case the
        // client is blocked waiting on tics from us that have been lost.
        // This fixes deadlock with some older clients which do not send
        // resends to break deadlock.
        if (i < BACKUPTICS && client->sendseq > client->acknowledged)
        {
            NET_Log("server: also resending tics %d-%d to break deadlock",
                    client->acknowledged, client->sendseq - 1);
            NET_SV_SendTics(client, client->acknowledged, client->sendseq - 1);
        }
    }
}
Ejemplo n.º 4
0
	static void USED DoneDL_Handler( client_t *client )
	{
		// fix: set CS_PRIMED only when CS_CONNECTED is current state
		if ( client->state == CS_CONNECTED )
			client->state = CS_PRIMED;
		else
		{
			char tmpIP[NET_ADDRSTRMAXLEN] = {0};
			NET_AddrToString( tmpIP, sizeof( tmpIP ), &client->netchan.remoteAddress );
			G_SecurityLogPrintf( "Client %d (%s) probably tried \"donedl\" exploit when client->state(%d)!=CS_CONNECTED(%d) [IP: %s]\n", client->gentity->s.number, client->name, client->state, CS_CONNECTED, tmpIP );
		}
	}
Ejemplo n.º 5
0
static void NET_SV_SendReject(net_addr_t *addr, const char *msg)
{
    net_packet_t *packet;

    NET_Log("server: sending reject to %s", NET_AddrToString(addr));

    packet = NET_NewPacket(10);
    NET_WriteInt16(packet, NET_PACKET_TYPE_REJECTED);
    NET_WriteString(packet, msg);
    NET_SendPacket(addr, packet);
    NET_FreePacket(packet);
}
Ejemplo n.º 6
0
void NET_SV_SendQueryResponse(net_addr_t *addr)
{
    net_packet_t *reply;
    net_querydata_t querydata;
    int p;

    // Version

    querydata.version = PACKAGE_STRING;

    // Server state

    querydata.server_state = server_state;

    // Number of players/maximum players

    querydata.num_players = NET_SV_NumPlayers();
    querydata.max_players = NET_SV_MaxPlayers();

    // Game mode/mission

    querydata.gamemode = sv_gamemode;
    querydata.gamemission = sv_gamemission;

    //!
    // @category net
    // @arg <name>
    //
    // When starting a network server, specify a name for the server.
    //

    p = M_CheckParmWithArgs("-servername", 1);

    if (p > 0)
    {
        querydata.description = myargv[p + 1];
    }
    else
    {
        querydata.description = "Unnamed server";
    }

    // Send it and we're done.
    NET_Log("server: sending query response to %s", NET_AddrToString(addr));
    reply = NET_NewPacket(64);
    NET_WriteInt16(reply, NET_PACKET_TYPE_QUERY_RESPONSE);
    NET_WriteQueryData(reply, &querydata);
    NET_SendPacket(addr, reply);
    NET_FreePacket(reply);
}
Ejemplo n.º 7
0
static void QueryResponseCallback(net_addr_t *addr,
                                  net_querydata_t *querydata,
                                  unsigned int ping_time,
                                  TXT_UNCAST_ARG(results_table))
{
    TXT_CAST_ARG(txt_table_t, results_table);
    char ping_time_str[16];
    char description[47];

    // When we connect we'll have to negotiate a common protocol that we
    // can agree upon between the client and server. If we can't then we
    // won't be able to connect, so it's pointless to include it in the
    // results list. If protocol==NET_PROTOCOL_UNKNOWN then this may be
    // an old, pre-3.0 Chocolate Doom server that doesn't support the new
    // protocol negotiation mechanism, or it may be an incompatible fork.
    if (querydata->protocol == NET_PROTOCOL_UNKNOWN)
    {
        return;
    }

    M_snprintf(ping_time_str, sizeof(ping_time_str), "%ims", ping_time);

    // Build description from server name field. Because there is limited
    // space, we only include the player count if there are already players
    // connected to the server.
    if (querydata->num_players > 0)
    {
        M_snprintf(description, sizeof(description), "(%d/%d) ",
                   querydata->num_players, querydata->max_players);
    }
    else
    {
        M_StringCopy(description, "", sizeof(description));
    }

    M_StringConcat(description, querydata->description, sizeof(description));

    TXT_AddWidgets(results_table,
                   TXT_NewLabel(ping_time_str),
                   TXT_NewButton2(NET_AddrToString(addr),
                                  SelectQueryAddress, querydata),
                   TXT_NewLabel(description),
                   NULL);

    ++query_servers_found;
}
Ejemplo n.º 8
0
static void NET_SV_SendResendRequest(net_client_t *client, int start, int end)
{
    net_packet_t *packet;
    net_client_recv_t *recvobj;
    int i;
    unsigned int nowtime;
    int index;

    NET_Log("server: send resend to %s for tics %d-%d",
            NET_AddrToString(client->addr), start, end);

    packet = NET_NewPacket(20);

    NET_WriteInt16(packet, NET_PACKET_TYPE_GAMEDATA_RESEND);
    NET_WriteInt32(packet, start);
    NET_WriteInt8(packet, end - start + 1);

    NET_Conn_SendPacket(&client->connection, packet);
    NET_FreePacket(packet);

    // Store the time we send the resend request

    nowtime = I_GetTimeMS();

    for (i=start; i<=end; ++i)
    {
        index = i - recvwindow_start;

        if (index >= BACKUPTICS)
        {
            // Outside the range

            continue;
        }
        
        recvobj = &recvwindow[index][client->player_number];

        recvobj->resend_time = nowtime;
    }
}
Ejemplo n.º 9
0
static void QueryResponseCallback(net_addr_t *addr,
                                  net_querydata_t *querydata,
                                  unsigned int ping_time,
                                  TXT_UNCAST_ARG(results_table))
{
    TXT_CAST_ARG(txt_table_t, results_table);
    char ping_time_str[16];
    char description[47];

    M_snprintf(ping_time_str, sizeof(ping_time_str), "%ims", ping_time);
    M_StringCopy(description, querydata->description,
                 sizeof(description));

    TXT_AddWidgets(results_table,
                   TXT_NewLabel(ping_time_str),
                   TXT_NewButton2(NET_AddrToString(addr),
                                  SelectQueryAddress, querydata),
                   TXT_NewLabel(description),
                   NULL);

    ++query_servers_found;
}
Ejemplo n.º 10
0
static void NET_SV_InitNewClient(net_client_t *client, net_addr_t *addr,
                                 net_protocol_t protocol)
{
    client->active = true;
    client->connect_time = I_GetTimeMS();
    NET_Conn_InitServer(&client->connection, addr, protocol);
    client->addr = addr;
    NET_ReferenceAddress(addr);
    client->last_send_time = -1;

    // init the ticcmd send queue

    client->sendseq = 0;
    client->acknowledged = 0;
    client->drone = false;
    client->ready = false;

    client->last_gamedata_time = 0;

    memset(client->sendqueue, 0xff, sizeof(client->sendqueue));

    NET_Log("server: initialized new client from %s", NET_AddrToString(addr));
}
Ejemplo n.º 11
0
static void NET_SV_SendWaitingData(net_client_t *client)
{
    net_packet_t *packet;
    net_client_t *controller;
    int num_players;
    int i;

    NET_SV_AssignPlayers();

    controller = NET_SV_Controller();

    num_players = NET_SV_NumPlayers();

    // time to send the client another status packet

    packet = NET_NewPacket(10);
    NET_WriteInt16(packet, NET_PACKET_TYPE_WAITING_DATA);

    // include the number of players waiting

    NET_WriteInt8(packet, num_players);

    // send the number of drone clients

    NET_WriteInt8(packet, NET_SV_NumDrones());

    // indicate whether the client is the controller

    NET_WriteInt8(packet, client == controller);

    // send the player number of this client

    NET_WriteInt8(packet, client->player_number);

    // send the addresses of all players

    for (i=0; i<num_players; ++i)
    {
        char *addr;

        // name

        NET_WriteString(packet, sv_players[i]->name);

        // address

        addr = NET_AddrToString(sv_players[i]->addr);

        NET_WriteString(packet, addr);
    }

    // Send the WAD and dehacked checksums of the controlling client.

    if (controller != NULL)
    {
        NET_WriteMD5Sum(packet, controller->wad_md5sum);
        NET_WriteMD5Sum(packet, controller->deh_md5sum);
        NET_WriteInt8(packet, controller->is_freedoom);
    }
    else
    {
        NET_WriteMD5Sum(packet, client->wad_md5sum);
        NET_WriteMD5Sum(packet, client->deh_md5sum);
        NET_WriteInt8(packet, client->is_freedoom);
    }

    // send packet to client and free

    NET_Conn_SendPacket(&client->connection, packet);
    NET_FreePacket(packet);
}
Ejemplo n.º 12
0
boolean D_InitNetGame(net_connect_data_t *connect_data)
{
    boolean result = false;
    net_addr_t *addr = NULL;
    int i;

    // Call D_QuitNetGame on exit:

    I_AtExit(D_QuitNetGame, true);

    player_class = connect_data->player_class;

#ifdef FEATURE_MULTIPLAYER

    //!
    // @category net
    //
    // Start a multiplayer server, listening for connections.
    //

    if (M_CheckParm("-server") > 0
     || M_CheckParm("-privateserver") > 0)
    {
        NET_SV_Init();
        NET_SV_AddModule(&net_loop_server_module);
        NET_SV_AddModule(&net_sdl_module);
        NET_SV_RegisterWithMaster();

        net_loop_client_module.InitClient();
        addr = net_loop_client_module.ResolveAddress(NULL);
    }
    else
    {
        //!
        // @category net
        //
        // Automatically search the local LAN for a multiplayer
        // server and join it.
        //

        i = M_CheckParm("-autojoin");

        if (i > 0)
        {
            addr = NET_FindLANServer();

            if (addr == NULL)
            {
                I_Error("No server found on local LAN");
            }
        }

        //!
        // @arg <address>
        // @category net
        //
        // Connect to a multiplayer server running on the given
        // address.
        //

        i = M_CheckParmWithArgs("-connect", 1);

        if (i > 0)
        {
            net_sdl_module.InitClient();
            addr = net_sdl_module.ResolveAddress(myargv[i+1]);

            if (addr == NULL)
            {
                I_Error("Unable to resolve '%s'\n", myargv[i+1]);
            }
        }
    }

    if (addr != NULL)
    {
        if (M_CheckParm("-drone") > 0)
        {
            connect_data->drone = true;
        }

        if (!NET_CL_Connect(addr, connect_data))
        {
            I_Error("D_InitNetGame: Failed to connect to %s\n",
                    NET_AddrToString(addr));
        }

        printf("D_InitNetGame: Connected to %s\n", NET_AddrToString(addr));

        // Wait for launch message received from server.

        NET_WaitForLaunch();

        result = true;
    }
#endif

    return result;
}
Ejemplo n.º 13
0
static void NET_SV_RunClient(net_client_t *client)
{
    // Run common code

    NET_Conn_Run(&client->connection);

    if (client->connection.state == NET_CONN_STATE_DISCONNECTED
     && client->connection.disconnect_reason == NET_DISCONNECT_TIMEOUT)
    {
        NET_Log("server: client at %s timed out",
                NET_AddrToString(client->addr));
        NET_SV_BroadcastMessage("Client '%s' timed out and disconnected",
                                client->name);
    }

    // Is this client disconnected?

    if (client->connection.state == NET_CONN_STATE_DISCONNECTED)
    {
        client->active = false;

        // If we were about to start a game, any player disconnecting
        // should cause an abort.

        if (server_state == SERVER_WAITING_START && !client->drone)
        {
            NET_SV_BroadcastMessage("Game startup aborted because "
                                    "player '%s' disconnected.",
                                    client->name);
            NET_SV_GameEnded();
        }

        free(client->name);
        NET_ReleaseAddress(client->addr);

        // Are there any clients left connected?  If not, return the
        // server to the waiting-for-players state.
        //
	// Disconnect any drones still connected.

        if (NET_SV_NumPlayers() <= 0)
        {
            NET_Log("server: no player clients left, game ended");
            NET_SV_GameEnded();
        }
    }

    if (!ClientConnected(client))
    {
        // client has not yet finished connecting

        return;
    }

    if (server_state == SERVER_WAITING_LAUNCH)
    {
        // Waiting for the game to start

        // Send information once every second

        if (client->last_send_time < 0 
         || I_GetTimeMS() - client->last_send_time > 1000)
        {
            NET_SV_SendWaitingData(client);
            client->last_send_time = I_GetTimeMS();
        }
    }

    if (server_state == SERVER_IN_GAME)
    {
        NET_SV_PumpSendQueue(client);
        NET_SV_CheckDeadlock(client);
    }
}
Ejemplo n.º 14
0
static void NET_SV_PumpSendQueue(net_client_t *client)
{
    net_full_ticcmd_t cmd;
    int recv_index;
    int num_players;
    int i;
    int starttic, endtic;

    // If a client has not sent any acknowledgments for a while,
    // wait until they catch up.

    if (client->sendseq - NET_SV_LatestAcknowledged() > 40)
    {
        return;
    }
    
    // Work out the index into the receive window
   
    recv_index = client->sendseq - recvwindow_start;

    if (recv_index < 0 || recv_index >= BACKUPTICS)
    {
        return;
    }

    // Check if we can generate a new entry for the send queue
    // using the data in recvwindow.

    num_players = 0;

    for (i=0; i<NET_MAXPLAYERS; ++i)
    {
        if (sv_players[i] == client)
        {
            // Client does not rely on itself for data

            continue;
        }

        if (sv_players[i] == NULL || !ClientConnected(sv_players[i]))
        {
            continue;
        }

        if (!recvwindow[recv_index][i].active)
        {
            // We do not have this player's ticcmd, so we cannot
            // generate a complete command yet.

            return;
        }

        ++num_players;
    }

    // If this is a game with only a single player in it, we might
    // be sending a ticcmd set containing 0 ticcmds. This is fine;
    // however, there's nothing to stop the game running on ahead
    // and never stopping. Don't let the server get too far ahead
    // of the client.

    if (num_players == 0 && client->sendseq > recvwindow_start + 10)
    {
        return;
    }

    // We have all data we need to generate a command for this tic.
    
    cmd.seq = client->sendseq;

    // Add ticcmds from all players

    cmd.latency = 0;

    for (i=0; i<NET_MAXPLAYERS; ++i)
    {
        net_client_recv_t *recvobj;

        if (sv_players[i] == client)
        {
            // Not the player we are sending to

            cmd.playeringame[i] = false;
            continue;
        }
        
        if (sv_players[i] == NULL || !recvwindow[recv_index][i].active)
        {
            cmd.playeringame[i] = false;
            continue;
        }

        cmd.playeringame[i] = true;

        recvobj = &recvwindow[recv_index][i];

        cmd.cmds[i] = recvobj->diff;

        if (recvobj->latency > cmd.latency)
            cmd.latency = recvobj->latency;
    }

    //printf("SV: %i: latency %i\n", client->player_number, cmd.latency);

    // Add into the queue

    client->sendqueue[client->sendseq % BACKUPTICS] = cmd;

    // Transmit the new tic to the client

    starttic = client->sendseq - sv_settings.extratics;
    endtic = client->sendseq;

    if (starttic < 0)
        starttic = 0;

    NET_Log("server: send tics %d-%d to %s", starttic, endtic,
            NET_AddrToString(client->addr));
    NET_SV_SendTics(client, starttic, endtic);

    ++client->sendseq;
}
Ejemplo n.º 15
0
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;
        }
    }
}
Ejemplo n.º 16
0
static void NET_SV_CheckResends(net_client_t *client)
{
    int i;
    int player;
    int resend_start, resend_end;
    unsigned int nowtime;

    nowtime = I_GetTimeMS();

    player = client->player_number;
    resend_start = -1;
    resend_end = -1;

    for (i=0; i<BACKUPTICS; ++i)
    {
        net_client_recv_t *recvobj;
        boolean need_resend;

        recvobj = &recvwindow[i][player];

        // if need_resend is true, this tic needs another retransmit
        // request (300ms timeout)

        need_resend = !recvobj->active
                   && recvobj->resend_time != 0
                   && nowtime > recvobj->resend_time + 300;

        if (need_resend)
        {
            // Start a new run of resend tics?
            if (resend_start < 0)
            {
                resend_start = i;
            }
            resend_end = i;
        }
        else if (resend_start >= 0)
        {
            // End of a run of resend tics
            NET_Log("server: resend request to %s timed out for %d-%d (%d)",
                    NET_AddrToString(client->addr),
                    recvwindow_start + resend_start,
                    recvwindow_start + resend_end,
                    &recvwindow[resend_start][player].resend_time);
            NET_SV_SendResendRequest(client, 
                                     recvwindow_start + resend_start,
                                     recvwindow_start + resend_end);

            resend_start = -1;
        }
    }

    if (resend_start >= 0)
    {
        NET_Log("server: resend request to %s timed out for %d-%d (%d)",
                NET_AddrToString(client->addr),
                recvwindow_start + resend_start,
                recvwindow_start + resend_end,
                &recvwindow[resend_start][player].resend_time);
        NET_SV_SendResendRequest(client,
                                 recvwindow_start + resend_start,
                                 recvwindow_start + resend_end);
    }
}