Developers Brainstorming

Ideas for game server detection:

To know the ideal, universal way to detect the server for all games it'll be needed to have as much as possible examples on this page so we can figure it out.

Check for all connections of the process with netstat and then use tcpdump for UDP.
Example:
   netstat:
       udp        0      0 0.0.0.0:38397           0.0.0.0:*                           5939/mumble -> local port 38397
   tcpdump:
       22:55:18.216848 IP 192.168.1.6.38397 > 85.214.87.101.64738: UDP, length 101
       22:55:18.239391 IP 192.168.1.6.38397 > 85.214.87.101.64738: UDP, length 83

You exactly know which remote address it is!

Currently working games

In order to be able to determine if the server detection works and has a mature code we need test results. Below are the current test results and their state.

Working games:
Wolfenstein: Enemy Territory
Enemy Territory: Quake Wars
Quake Live

Non-working games:
Games running using Wine (WIP)

Wolfenstein: Enemy Territory

warren@warren-desktop:~$ netstat -tuanp | grep et.x86
(Tous les processus ne peuvent être identifiés, les infos sur les processus
non possédés ne seront pas affichées, vous devez être root pour les voir toutes.)
udp        0      0 0.0.0.0:27960           0.0.0.0:*                           6173/et.x86     
warren@warren-desktop:~$ 

warren@warren-desktop:~$ tcpdump -c 5 -f -n
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
09:07:28.790061 IP 88.197.174.175.27960 > 63.211.110.136.27960: UDP, length 28
09:07:28.845063 IP 88.197.174.175.27960 > 63.211.110.136.27960: UDP, length 28
09:07:28.873263 IP 63.211.110.136.27960 > 88.197.174.175.27960: UDP, length 984
09:07:28.900073 IP 88.197.174.175.27960 > 63.211.110.136.27960: UDP, length 28
09:07:28.955178 IP 88.197.174.175.27960 > 63.211.110.136.27960: UDP, length 28
5 packets captured
5 packets received by filter
0 packets dropped by kernel
warren@warren-desktop:~$ 

Problem case: Enemy Territory: Quake Wars

tcp        0      0 88.197.174.164:57278    69.87.248.250:3074      ESTABLISHED 26553/etqw-rthread.
tcp        0      0 88.197.174.164:38420    69.87.248.252:3074      CLOSE_WAIT  26553/etqw-rthread.
udp        0      0 0.0.0.0:44909           0.0.0.0:*                           26553/etqw-rthread.
udp        0      0 0.0.0.0:54398           0.0.0.0:*                           26553/etqw-rthread.
udp        0      0 0.0.0.0:3074            0.0.0.0:*                           26553/etqw-rthread.
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
14:36:52.504193 IP 88.197.174.164.44909 > 78.41.115.234.27733: UDP, length 37
14:36:52.521039 IP 88.197.174.164.44909 > 78.41.115.234.27733: UDP, length 37
14:36:52.554047 IP 88.197.174.164.44909 > 78.41.115.234.27733: UDP, length 37
14:36:52.558195 IP 78.41.115.234.27733 > 88.197.174.164.44909: UDP, length 210
14:36:52.586039 IP 88.197.174.164.44909 > 78.41.115.234.27733: UDP, length 37
5 packets captured
5 packets received by filter
0 packets dropped by kernel

Make gdb logging automatically:

#!/bin/bash

TIME=`date +%F-%H%M%S`
LOG="$HOME/Documents/Gfire/logs/pidgin-db-${TIME}.log"

exec gdb -batch-silent \
    -ex 'set logging overwrite on' \
    -ex "set logging file ${LOG}" \
    -ex 'set logging on' \
    -ex 'handle all pass nostop print' \
    -ex 'handle SIGCHLD pass nostop noprint' \
    -ex 'handle SIGSEGV pass stop print' \
    -ex 'set pagination 0' \
    -ex 'run' \
    -ex 'backtrace full' \
    -ex 'info registers' \
    -ex 'thread apply all backtrace' \
    -ex 'continue' \
    --args pidgin \
    < /dev/null

Edit the path where the log should be saved and you should start pidgin always this way to be sure that you don't miss any bug.

Idea for a coding convention

  • Using glib if possible. Mixing it with stdlib makes no sense.
  • Creating functions for accessing data types (compare with glib; get closer to OOP) like at least "gfire_data *gfire_data_create();" and "void gfire_data_free(gfire_data *p_data);"
  • Splitting the code in one header/source file combination per task/struct (gfire_data.c/h, gfire_buddy.c/h, purple_interface.c/h, chat.c/h, clan.c/h, game_detection.c/h, ...)
  • No warnings (i.e. means no "guint32 val = get_val(231);") :)
  • Using const whenever no change to the variable is needed
  • Using "//" for single line comments; "/**/" for multiline comments

Example header and source file

/* Copyright note */

#ifndef _HEADER_H
#define _HEADER_H

#include <include_file.h>

#define A "a"

typedef struct _i_am_a_struct
{
    gchar *data1; // short description of data1
    guint32 data2; // short description of data2
} i_am_a_struct;

// Required prototypes
void i_am_a_function(const guint32 p_name);

#endif // _HEADER_H

/* Copyright note */

#include <header.h>

// This function does actually nothing
void i_am_a_function(const guint32 p_name)
{
    guint32 game_id = 0;
    gchar *game_name = NULL;

    if(!p_name)
        return;

    game_name = g_strdup_printf("Game Name Num: %u", p_name);
    game_id = g_strlen(game_name);

    if(game_name)
        g_free(game_name);
}