== Zasady opisywania protokołów ==

Autor: Aleksy Schubert

=== Streszczenie ===

Niniejszy dokument opisuje strukturę i podstawowe wymagania dotyczące sposobu 
opisywania protokołów. 

Spodziewamy się, że każdy opis protokołu będzie miał następującą strukturę:
# Streszczenie
# Opis celów protokołu
# Opis założeń protokołu
# Opis formatu komunikatĂłw
# Opis wymienianych komunikatĂłw
# Opis stanĂłw
# Podsumowanie uĹźywanych numerĂłw
Przedstawione dokumenty nie muszą się ograniczać do tego kształtu. Mogą zawierać
dodatkowe sekcje, które objaśniają i precyzują inne istotne aspekty działania 
protokołu, np. bezpieczeństwo, odporność na awarie itp. Także konstrukcja
protokołu może wykraczać poza zakreślone tutaj ramy (można sobie wyobrazić, że
twórcy opracują jakiś system trybów lub poziomów działania protokołu, który
nie da się prosto ująć w ramach prostego wyliczenia stanów i komunikatów).

=== Cele ===

Opis protokołu powinien opisywać w sposób zrozumiały jego działanie. W obecnym 
dokumencie wyznaczamy pewien standard opisu protokołu, który powinien zmniejszyć
ilość niedomówień związanych z interpretacją.

W sekcji tej powinno być opisane, jakim celom ma służyć protokół, np. 
zapewnianiu przesyłania danych strumieniowych do komunikacji multimedialnej.

=== Założenia ===

Zakładamy, że opisy protokołów będą wykonywane w języku polskim i będą stanowiły
podstawę do tworzenia przez niezależne zespoły programistów implementacji.
Różne implementacje w założeniu mają ze sobą współdziałać. Zakładamy, że 
komunikacja między twórcą opisu protokołu a implementatorami jest ograniczona
(np. ze względu na brak czasu twórcy opisu). Zakładamy, że opisy mogą być
wykonane zarówno w formatach pozwalających na wstawianie rysunków, jak i
w czystym ASCII (być może wzbogaconym o możliwość wpisywania polskich znaków
diakrytycznych). Zakładamy, że opisy będą pozwalały na napisanie w języku C
(w wersji pod sysemy uniksowe) kodu źródłowego, który skompilowany na dwóch
maszynach o różnej architekturze będzie dawał mogące ze sobą współpracować 
programy.

W części tej m.in. powinny znaleźć się informacje o tym, z czego
opisywany protokół korzysta. W szczególności powinny znaleźć się tutaj 
informacje o tym:
* w jakiej warstwie działa protokół, 
* z jakich protokołów korzysta do transportu (UDP, TCP, RTP, itp.),
* z jakich protokołów usługowych bezpośrednio korzysta (np. DHCP, DNS itp.),
* z jakich funkcjonalności wspomnianych wyżej protokołów korzysta (np. numer 
  portu),
* z jakiego modelu komunikacji korzystamy (klient-serwer, P2P itp.).

=== Format komunikatĂłw ===

Przy opisie protokołu przeznaczonym do interpretacji bez udziału twórcy 
protokołu konieczne jest jednoznaczne opisanie binarnego formatu wymienianych
komunikatów. Ten format powinien uwzględniać takie elementy jak:
* porządek oktetów w liczbach (sieciowy, little endian, big endian itp.),
* sposób interpretacji znaków (w arytmetyce uzupełnień do 2, do 1, itp.),
* format liczb zmiennoprzecinkowych (np. IEEE 754),
* dopuszczalne uzupełnienia formatu (np. czy liczby dwuoktetowe są uzupełniane
  do czterech oktetĂłw i jakimi danymi (zerami, przez 0xFF, losowymi danymi 
  itp.),
* jakie pola występują w komunikacie i w jakiej kolejności.
Opisanie tego ostatniego elementu wymaga użycia jakiegoś formatu opisu
komunikatów. Przyjmujemy, że nasze opisy będą używać formatu przedstawionego 
poniżej. Zakładamy, że oktety określonej według poniższych zasad reprezentacji
są przesyłane przez sieć w ten sposób, że najpierw transmitowany jest pierwszy
oktet, potem drugi, itd. aĹź do ostatniego.

Uwaga: na zajęciach przyjmujemy, że przez sieć przesyłane są liczby w sieciowym 
porządku oktetów.

==== Typy podstawowe ====

Będziemy używali następujących typów podstawowych:
* octet,
* int,
* float.
Typ octet oznacza zawsze wielkość ośmiobitową bez określenia sposobu 
interpretacji jako liczby całkowitej. Typ ten przydaje się, gdy chcemy określić,
że w danym miejscu znajdują się dane, które są opisane w innej części dokumentu.
Potrzeba taka zachodzi na przykład, gdy najpierw opisujemy ogólny format
komunikatu, a następnie uszczegóławiamy go, opisując konkretne komunikaty.

W wypadku typów całkowitoliczbowych będziemy używali prefiksów określających 
znak oraz sufiksów określających wielkość reprezentacji. Będziemy stosowali
dwa rodzaje prefiksów: "u" oraz "s". Dozwolone są wszystkie sufiksy będące
wielokrotnościami liczby 8, czyli: 8, 16, 24, 32, 40, itd. Przykładowe typy
całkowitoliczbowe to: uint32, sint16 itp.

W wypadku typów zmiennoprzecinkowych będziemy używali tylko sufiksów 32 i 64
na oznaczenie wielkości liczby (32 bity, 64 bity). Przykłady: float32, float64.

==== Typy złożone ====

Oprócz typów podstawowych możemy też korzystać z typów złożonych. Pierwszy 
rodzaj typu złożonego to tablica. Tablice opisujemy według wzoru:
  TYP [WIELKOŚĆ] NAZWA;
gdzie TYP to jeden z typów podstawowych lub wcześniej zdefiniowanych, NAZWA
to nazwa pola, zaś WIELKOŚĆ to liczba elementów tablicy. Tablice są zawsze
indeksowane od 0 do WIELKOŚĆ-1. Wartość oznaczona tutaj jako WIELKOŚĆ musi 
być znana na etapie specyfikacji protokołu lub obliczalna na podstawie 
części komunikatu odebranej przed przetwarzaniem tablicy. Wartość WIELKOŚĆ może 
być opisana symbolicznie.

Format binarny tablicy opisanej jako
  TYP [WIELKOŚĆ] NAZWA;
jest następujący: po kolei umieszczane są oktety reprezentacji binarnej pola o 
indeksie 0, 1, itd. aż do pola o indeksie WIELKOŚĆ-1. Na przykład reprezentacja 
binarna tablicy:
  uint16 [3] ala;
zawierającej elementy ala[0]=34324, ala[1]=4534, ala[2]=233 wyglądałaby 
binarnie tak (zakładamy sieciową reprezentację uint16):

0x86 0x14 0x11 0xB6 0x00 0xE9

Opis
  uint16 [3] ala;
można też równoważnie przedstawić jako
  uint16 [ARRAY_LEN] ala;
przy czym należy wcześniej opisać (nie wprowadzamy tu specjalnej składni), że
symbol ARRAY_LEN ma wartość 3.

Oprócz tablic możemy używać struktur. Struktury opisujemy, korzystając z
następującego formatu:
    NAZWA_STRUKTURY {
        TYP1 NAZWA1;
        ...
        TYPN NAZWAN;
    }
Reprezentacja binarna takiej struktury wygląda w ten sposób, że najpierw 
umieszczane są oktety pola NAZWA1, potem NAZWA2 itd. według kolejności
tekstowego występowania aż do pola NAZWAN. NAZWA_STRUKTURY może być
wykorzystywana do opisywania innych typów. Określenie TYPi obejmuje także
opisaną powyżej specyfikację rodzaju i wielkości tablicy. Przykład struktury:
    PROTOCOL_MSG {
        uint8                  message_type;
        uint32                 total_length;
        uint32                 payload_length;
        octet [payload_length] payload;
        octet [padding_length] padding;
        uint32                 mac;
    }
gdzie padding_length= total_length - payload_length - 13. Warto zwrócić
uwagę, że liczba 13 odpowiada łącznej długości pól message_type, total_length,
payload_length i mac.

==== Opisy długości ====

Jeśli w komunikacie występuje pole opisujące długość jakiejś części komunikatu,
to przy opisie tego pola powinny być jawnie wymienione nazwy pól, jakie ta
długość obejmuje. W wypadku komunikatu PROTOCOL_MSG opisanego w poprzedniej
sekcji opis pola total_length powinien brzmieć w przybliżeniu tak:

total_length - pole zawierające długość całego pakietu, długość ta obejmuje 
               pola: message_type, total_length, payload_length, payload, 
               padding, mac.

Nie używamy natomiast skrótów myślowych takich jak w tym opisie:

total_length - pole zawierające długość całego pakietu.

gdyż mogą pojawić się wątpliwości interpretacyjne, czy chodzi o cały pakiet
rzeczywiście, czy o jego część za polem total_length, czy oktety pola 
total_length też wchodzą w skład tej wartości itp.

=== Opis komunikatĂłw ===

NiezaleĹźnie od opisu ogĂłlnego formatu komunikatĂłw koniecznie jest podanie
formatu wszystkich konkretnych komunikatĂłw wraz z celami, do jakich te
komunikaty mają służyć oraz z opisem przetwarzania, jakie mają one powodować.
Każdy komunikat powinien mieć określoną symboliczną nazwę. Nazwa ta powinna
zawierać napis MSG.

Czasami dogodnie jest wprowadzić grupy komunikatów. Każda wprowadzona grupa
komunikatów powinna wymieniać jednoznacznie komunikaty, które do niej należą.
Przy korzystaniu z grup komunikatów można używać notacji typu:
* NAZWA_GRUPY + KOMUNIKAT - na oznaczenie zbioru komunikatów zawierającego
  wszystkie komunikaty z grupy NAZWA_GRUPY oraz dodatkowo komunikat KOMUNIKAT,
* NAZWA_GRUPY - KOMUNIKAT - na oznaczenie zbioru komunikatów zawierającego
  wszystkie komunikaty z grupy NAZWA_GRUPY oprĂłcz komunikatu KOMUNIKAT,
* NAZWA_GRUPY1 + NAZWA_GRUPY2 - na oznaczenie zbioru komunikatów zawierającego
  wszystkie komunikaty z grupy NAZWA_GRUPY1 oraz wszystkie komunikaty grupy
  NAZWA_GRUPY2,
* NAZWA_GRUPY1 - NAZWA_GRUPY2 - na oznaczenie zbioru komunikatów zawierającego
  te komunikaty z grupy NAZWA_GRUPY1, które nie należą do grupy NAZWA_GRUPY2.
Każda symboliczna nazwa grupy powinna zawierać napis GRP.

=== Opis stanĂłw ===

Przy opisie protokołu często zdarza się, że w pewnych momentach sensownie mogą
być zinterpretowane tylko niektóre komunikaty. Naturalne w tym momencie staje
się wprowadzenie pojęcia stanu. Stan określony jest przez sposób reakcji na
komunikaty oraz na inne zdarzenia (np. przekroczenie czasu, reakcja uĹźytkownika,
reakcja systemu operacyjnego itp.). Opisy stanów powinny zawierać dokładne
wyszczegĂłlnienie 
* założeń 
* działań, jakie powinny być wykonywane w reakcji na zdarzenia.
W szczególności jasno powinno być określone:
* jakie rodzaje zdarzeń są dopuszczalne w danym stanie (oprócz przyjścia 
  komunikatu),
* jak wygląda reakcja na te zdarzenia,
* jak powinna wyglądać reakcja na wszystkie możliwe komunikaty (nie tylko
  zgodne z pozytywnym scenariuszem działania protokołu).
Jeśli protokół przewiduje utrzymywanie jakichś dodatkowych zmiennych, to
należy w każdym przejściu jawnie wskazywać, jakie zmiany tych zmiennych
mają nastąpić. Także, jeśli wykonanie jakiejś akcji zależy od wartości
zmiennej, to należy to jasno opisać.

Dobrze też, gdy opis protokołu zawiera rysunek przedstawiający wszystkie
stany w postaci automatu. Na rysunku tym stany powinny być oznaczone w postaci
zamkniętych obszarów (kół, prostokątów, owali itp.), zaś zdarzenia w postaci
strzałek między stanami. Zdarzenia inicjowane przez implementację (np. wysłanie 
komunikatu, wypisanie czegoś na terminal) powinny być dodatkowo oznaczane 
znakiem wykrzyknika (!), zaś zdarzenia odbierane przez implementację (np. 
odebranie komunikatu, wciśnięcie klawisza przez użytkownika) za pomocą
znaku zapytania (?). Przykład:
                              | USER_INITS?
                              | x:=0
                             \|/
                    ----------------------
                    | DISCONNECTED_STATE | /____________
                    ---------------------- \           |
                              |                        |
                              | USER_STARTS?           |
                              | x:=x+1                 |
                             \|/                       |
                  -------------------------            |
                  | INIT_CONNECTION_STATE |            |
                  -------------------------            |
                              |                        |
                              | CONNECT_MSG!           |
                             \|/                       |
                    ----------------------             |
                    | WAIT_CONNECT_STATE |             |
                    ----------------------             |
                   /           |\                      |
       TIMEOUT?   /            | \ TIMEOUT?            |
         x>3     /             |  \  x<=3              |
               |/_ CONNECT_MSG?|   \                   |
   --------------              |    \                  |
   |    ABORT   |              |     -------------------
   --------------             \|/
                    ---------------------
                    |  WORKING_STATE    |
                    ---------------------
                             ...

Każda symboliczna nazwa stanu powinna zawierać napis STATE.

=== Numery ===

W sekcji tej powinny być zgromadzone skrótowe opisy wszystkich użytych w
dokumencie wartości symbolicznych wraz z odpowiadającymi im rzeczywistymi 
liczbami. Jeśli na przykład wprowadziliśmy komunikat ALA_MSG, któremu 
przypisaliśmy liczbowy typ o wartości 3, to w tej sekcji powinien znaleźć się 
opis w stylu:

ALA_MSG=3 - typ komunikatu wysyłanego przez Alę.

=== Uwagi końcowe ===

Nie narzucamy żadnego formatu tworzenia diagramów automatów (w szczególności
nie narzucamy UML-a), szczegóły prezentacji automatów są do negocjacji z 
prowadzącymi. Prowadzący może wymagać, aby teksty były zapisane w takim 
formacie, w którym jednoznacznie są reprezentowane polskie znaki diakrytyczne.
Opis protokołu nie powinien być zbyt obszerny - nalezy dążyć do zwięzłego, ale
pełnego opisu.

Dla lepszego zrozumienia potrzeby istnienia tego dokumentu warto obejrzeć
następujące specyfikacje:
* http://www.xmlrpc.com/spec - specyfikacja XMLRPC
* http://www.gamers.org/dEngine/quake/Qdem/dem-1.0.2-5.html#ss5.3 - 
* http://wiki.theory.org/index.php/BitTorrentSpecification
* ftp://sunsite.icm.edu.pl/pub/doc/rfc/rfc1661.txt
* ftp://sunsite.icm.edu.pl/pub/doc/rfc/rfc2246.txt (sekcja 4)