Author: Walerian Sokołowski (C) Copyright 2002 You a free to change it in every way you want. ----- (0) disclaimer ------------------------------ Opisuję tu protokół przesyłania plików w między klientami G*du-G*du. Informację czerpałem ze źródeł gglib w którejś z wersji oraz z doświadczeń przeprowadzanych własnoręcznie. W tym celu nic nie desasemblowałem i nie reingenerowałem. ----- 1) zamiast wstępu ------------------------------------------------------ Protokół jest pewną implementacją części powszechnie znanego DCC opisanego w którymś z RFC. Obowiązują naturalne dla GG ustalenia, a więc sizeof(int) = 4 oraz transmisja jest intel endian. ----- 2) nawiązanie połączenia ------------------------------------------------ Klient łącząc się z serwerem GG wysyła swój adres IP i port, na którym nasłuchuje (patrz opis gg_login). Gdy któryś z kontaktów staje się dostępny (właśnie się połączyliśmy lub on właśnie zmienił stan) otrzymujemu powiadomienie o tym w paczce typu GG_NOTIFY_REPLY, która zawiera jego adresek IP i port, na którym on nasłuchuje (patrz opis gg_notify_reply). Tak więc w najprostszej sytuacji, gdy nie dzielą nas żadne firewalle strona wysyłająca ma adres odbiorcy. Jeśli odbiorca znajduje się za firewallem, a nadawca nie, to nadawca może poprosić odbiorcę o nawiązanie połączenia wysyłając do niego komunikat typu 0x0010 (GG_CLASS_CTCP) o zawartości 0x02. W taki sposób na czas nawiązania połączenia nadawca i odbiorca zamieniają się rolami. I do końca punktu będę ich nazywać wg. pełnionych ról. A więc nadawca nawiązuje połączenie TCP z adresem odbiorcy i wysyła swój UIN i UIN odbiorcy: struct { int uin1; /* mój numerek */ int uin2; /* jego numerek */ }; Odbiorca potwierdzając nawiązanie połączenia z klientem GG wysyła 4 bajty: struct { char [] "UDAG"; }; Jeśli nadawca ma wysyłać plik, to wysyła 0x0002: #define GG_DCC_CATCH_FILE 0x0002 Jeśli to odbiorca ma wysyłać, to nadawca wysyła 0x0003: #define GG_DCC_WANT_FILE 0x0003 Po tym wszystkim uważa się połączenie za nawiązane. ----- 3) transmisja pliku: strona nadawcy ------------------------------------- Nadawca wysyła po kolei: #define GG_DCC_HAVE_FILE 0x0001 #define GG_DCC_HAVE_FILEINFO 0x0003 int dunno1; /* 0 */ int dunno2; /* 0 */ file_info_struct finfo; Podejrzewam, że dunno2:dunno1 jest pozycją w pliku, od której nadawca chce wysyłać plik, ale nie udało mi się zasymulować sytuacji, w której byłyby używane. struct file_info_struct { int mode; /* dwFileAttributes */ int ctime[2]; /* ftCreationTime */ int atime[2]; /* ftLastAccessTime */ int mtime[2]; /* ftLastWriteTime */ int size_hdw; /* górne 4 bajty długości pliku */ int size_ldw; /* dolne 4 bajty długości pliku */ int reserved1; /* 0 */ int reserved2; /* 0 */ char file_name[276]; /* tablica zaczynająca się od nazwy pliku, wypełniona zerami */ }; Dalej nadawca czeka na akceptację odbiorcy, czyli następującą strukturkę: struct { int type; /* 0x0006 GG_DCC_GIMME_FILE */ int start; /* od której pozycji zacząć przesyłanie */ int dunno; /* 0 */ }; Teraz możemy zacząć przesyłanie pliku. Plik przesyłamy w paczkach długości ustalonej przez nadawcę. Przed każdą paczką z danymi nadawca wysyła nagłówek paczki: struct { int type; /* 0x0003 GG_DCC_FILEHEADER, jeśli paczka nie jest ostatnia. 0x0002 GG_DCC_LAST_FILEHEADER wpp. */ int chunk_size; /* rozmiar paczki */ int dunno; /* 0 */ }; Po wysłaniu ostatniej paczki zamykamy połączenie. Plik został przesłany. ----- 4) transmisja pliku: strona odbiorcy ------------------------------------ Zachowanie odbiorcy jest symetryczne: 1. odbiera kolejno GG_DCC_HAVE_FILE GG_DCC_HAVE_FILEINFO int dunno1; int dunno2; file_info_struct finfo; 2. jeśli użytkownik zgodzi się odebrać plik, to wysyłamy struktrę jakiej odbiorca się spodziewa. 3. otrzymujemy nagłówek paczki i paczkę z danymi zadeklarowanej długości 4. jeśli nagłówek był typu GG_DCC_LAST_FILEHEADER to otrzymaliśmy całość, więc zamykamy połączenie. Jeśli nie, to wracamy do kroku 3. $Id: dcc-protocol.txt,v 1.3 2002/06/09 20:41:03 wojtekka Exp $