Netcode 1.25
Généralités
Le protocole réseau utilisé par T4C est du type non-connecté. Ce sont des datagrammes UDP.
Les données de ce datagramme comprennent un en-tête sur 12 octets, éventuellement suivis d'une clé de cryptage, d'une somme de contrôle ainsi que d'une chaîne de données cryptées (le pak).
Le cryptage est une série mathématique qui porte sur les octets 16 du datagramme et suivants, dont la clé est donnée à l'octet 12 sur 2 octets.
Le checksum (somme de contrôle) est donné sur 2 octets à l'octet 14 et porte sur les octets 16 du datagramme et suivants, avant encryption.
Les datagrammes de taille supérieure à 1024 octets sont systématiquement fragmentés (c'est-à-dire, envoyés en plusieurs parties de sorte que chaque partie envoyée ne fasse pas plus de 1024 octets).
Schéma canonique d'un datagramme du protocole 1.25 :
[HEADER][seed][checksum][DATA.........................]
[.......partie encryptée......]
ATTENTION: toutes les valeurs de l'en-tête, la clé de cryptage et la somme de contrôle sont en LITTLE ENDIAN (format de représentation des types de données Intel), mais les données du pak sont en BIG ENDIAN (format de représentation des types de données données Motorola). En lisant les données du pak sur un ordinateur de type x86, le programmeur doit penser à INVERSER l'ordre des octets. Les chaînes de caractères, étant considérées comme des tableaux d'octets, ne sont pas affectées.
Méthode de cryptage
Seules les données du pak sont cryptées, c'est-à-dire tout ce qui se situe au-delà du header, de la clé de cryptage et du checksum.
void Pak_ToggleEncryption_125 (pak_t *pak, unsigned short first_seed)
{
// this function toggles Vircom's encryption on/off on the pak data. Note that the checksum
// must be computed on the decrypted data, so it has to be done before calling this function.
unsigned short seed;
unsigned long index;
seed = first_seed;
// for each byte of data...
for (index = 0; index < pak->data_size; index++)
{
seed = seed * 145 + 1; // apply an infinite suite to seed
pak->data[index] ^= (char) seed; // use it to mask the data (XOR)
}
return; // finished
}
NOTE: La même fonction sert à la fois pour le cryptage et le décryptage.
Méthode de calcul de la somme de contrôle
La somme de contrôle est l'addition octet par octet des octets des données du pak, le résultat étant représenté sur deux octets non signés (dépassement de capacité compris).
signed short Pak_ComputeChecksum_125 (pak_t *pak)
{
// this function computes and returns the pak data's checksum
unsigned long index;
signed short sum;
sum = 0; // start at zero
// for each byte of data...
for (index = 0; index < pak->data_size; index++)
sum += ((unsigned char *) pak->data)[index]; // add its value to the checksum
return (sum); // return the checksum we found
}
Format des datagrammes UDP de T4C
Pak non fragmenté
Taille Type Description =============================================================================== 1 unsigned char 0 1 unsigned char Type de datagramme (tableau de bits) 2 unsigned short Longueur du datagramme 4 unsigned long ID du datagramme 4 unsigned long 0 2 unsigned short Clé de cryptage du pak 2 signed short Somme de contrôle des données du pak NON CRYPTEES (checksum) * char * Données du pak (cryptées), encodées en "big endian"
Pak fragmenté
Premier fragment de pak fragmenté
Taille Type Description =============================================================================== 1 unsigned char 0 1 unsigned char Type de datagramme (tableau de bits) 2 unsigned short Longueur du header + clé + checksum + données bout à bout 4 unsigned long ID du datagramme 4 unsigned long copie de l'ID du datagramme 2 unsigned short Clé de cryptage du pak 2 signed short Somme de contrôle des données du pak NON CRYPTEES (checksum) 1008 char * Données du pak (cryptées), encodées en "big endian"
Fragment de pak
Taille Type Description =============================================================================== 1 unsigned char Numéro du fragment 1 unsigned char Type de datagramme (tableau de bits) 2 unsigned short Longueur du header + clé + checksum + données bout à bout 4 unsigned long ID du datagramme 4 unsigned long ID du datagramme de référence (premier de la série) 1012 char * Données du pak (cryptées), encodées en "big endian"
Attention : 0 est une ID de datagramme valide !
Valeurs des différents champs
Tableau de bits du type de datagramme
Cet octet considéré comme un tableau de bits permet au datagramme de transporter jusqu'à huit flags différents. Voici ceux utilisés par le jeu :
- 00000000 (0x00): aucun flag, datagramme normal
- 00000001 (0x01): ce datagramme est l'accusé de réception d'un autre datagramme
- 00000010 (0x02): ce datagramme demande un accusé de réception
- 00000100 (0x04): ce datagramme contient un fragment de pak fragmenté
Ces valeurs peuvent bien entendu être combinées. Ainsi, un datagramme porteur des flags 00000110 sera un fragment de pak fragmenté qui demande un accusé de réception.
ID du datagramme
Il s'agit d'un numéro unique, normalement incrémentiel, mais qui peut parfaitement être aléatoire. Le premier datagramme envoyé par le client a toujours l'ID 0. Ensuite, le serveur renvoie un pak porteur de l'ID à partir de laquelle le client peut commencer son incrémentation.
Système d'accusé de réception
UDP étant un protocole non fiable, quand les données à envoyer sont importantes et nécessitent l'assurance que le destinataire (client ou serveur) les reçoit effectivement, les datagrammes envoyés portent le flag ACK REQUEST (deuxième bit le moins significatif dans l'octet du type de datagramme).
Quand l'un des hôtes reçoit un datagramme portant le flag ACK REQUEST, il doit aussitôt renvoyer un datagramme accusé de réception au format suivant (il s'agit d'une en-tête vide, portant seulement le flag ACK REPLY et l'ID du datagramme concerné).
Accusé de réception :
Taille Type Description =============================================================================== 1 unsigned char 0 1 unsigned char 1 2 unsigned short 0 4 unsigned long ID du datagramme faisant l'objet d'un accusé de réception 4 unsigned long 0
Ce système est implémenté au niveau DATAGRAMME, et non au niveau des paks assemblés. Ce qui signifie que si un pak fragmenté demande un accusé de réception, il le demande dans le header de chacun de ses fragments et il convient d'envoyer un accusé de réception à chaque fragment de pak reçu.
--Sorkvild 14 mars 2008 à 05:05 (MSK)