Beispiel #1
0
/**
 * Compare two string.
 */
int string_compare(const string_t* cpstr_first, const string_t* cpstr_second)
{
    return string_compare_cstr(cpstr_first, string_c_str(cpstr_second));
}
static void login_trilogy_handle_op_server_list(LoginClient* client, ProtocolHandler* handler)
{
    Login* login;
    ServerList* list;
    ServerListing* data;
    PacketTrilogy* packet;
    Aligned write;
    Aligned* w  = &write;
    uint32_t count;
    uint32_t length;
    uint32_t n;
    uint32_t i;
    uint32_t ip;
    bool isLocal;
    char address[INET_ADDRSTRLEN];
    
    if (login_client_get_state(client) != LoginClientTrilogy_AcceptedCredentials)
        return;
    
    isLocal = login_client_is_local(client);
    login   = (Login*)protocol_handler_basic(handler);
    list    = login_server_list(login);
    count   = server_list_count(list);
    ip      = protocol_handler_ip_address(handler)->sin_addr.s_addr;
    
    snprintf(address, sizeof(address), "%u.%u.%u.%u", (ip >> 0) & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff);
    
    // Figure out how long the packet will be
    data    = server_list_data(list);
    length  = sizeof(LoginTrilogy_ServerListHeader) + sizeof(LoginTrilogy_ServerListFooter);
    n       = 0;
    
    for (i = 0; i < count; i++)
    {
        ServerListing* server = &data[i];
        
        if (!server_listing_name(server))
            continue;
        
        /*
            There are two different 'local address' cases to handle:
            
            1) Login, char-select and client are all local to each other; or
            2) Char-select and client are local to each other, but both are remote to login
            
            In the first case, both char-select and client will have been flagged as local (to the login server) and the
            client's address will not match the remote address for char-select.
            
            In the second case, neither char-select and client will have been flagged as local, but the client's address will
            (presumably, and typically) be the same as char-select's remote address.
        */
        if ((isLocal && server_listing_is_local(server)) || string_compare_cstr(server_listing_remote_address(server), address))
            length += string_length(server_listing_local_address(server)) + 1;
        else
            length += server_listing_remote_length(server);
        
        length += server_listing_name_length(server);
        length += sizeof(LoginTrilogy_ServerFooter);
        
        if (++n == SERVER_LIST_COUNT_MAX)
            break;
    }
    
    // Create and fill the packet
    packet = packet_trilogy_create(B(login), TrilogyOp_ServerList, length);
    aligned_init(B(login), w, packet_trilogy_data(packet), packet_trilogy_length(packet));
    
    /* ServerListHeader */
    // serverCount
    aligned_write_uint8(w, n);
    // unknown (2 bytes)
    aligned_write_zeroes(w, sizeof(uint8_t) * 2);
    // showNumPlayers
    aligned_write_uint8(w, 0xff); // Show actual numbers rather than just "Up"
    
    /* Server entries and footers */
    n = 0;
    
    for (i = 0; i < count; i++)
    {
        int playerCount;
        ServerListing* server = &data[i];
        
        if (!server_listing_name(server))
            continue;
        
        switch (server_listing_status(server))
        {
        case ServerStatus_Down:
            playerCount = SERVER_DOWN;
            break;
        
        case ServerStatus_Locked:
            playerCount = SERVER_LOCKED;
            break;
        
        default:
            playerCount = server_listing_player_count(server);
            break;
        }
        
        // server name
        aligned_write_string_null_terminated(w, server_listing_name(server));
        // ip address
        if ((isLocal && server_listing_is_local(server)) || string_compare_cstr(server_listing_remote_address(server), address))
            aligned_write_string_null_terminated(w, server_listing_local_address(server));
        else
            aligned_write_string_null_terminated(w, server_listing_remote_address(server));
        // isGreenName
        aligned_write_bool(w, (server_listing_rank(server) != ServerRank_Standard));
        // playerCount
        aligned_write_int32(w, playerCount);
        
        if (++n == SERVER_LIST_COUNT_MAX)
            break;
    }
    
    /* ServerListFooter */
    // admin
    aligned_write_uint8(w, 0);
    // zeroes A (8 bytes)
    aligned_write_zeroes(w, sizeof(uint8_t) * 8);
    // kunark
    aligned_write_uint8(w, 1);
    // velious
    aligned_write_uint8(w, 1);
    // zeroes B (12 bytes)
    aligned_write_zeroes(w, sizeof(uint8_t) * 12);
    
    login_trilogy_schedule_packet(handler, packet);
}