biblia tcp ip tom 3 - uzupelnienie.pdf

363
tTi i eh- fW*' * J V - ar, “S n Uzupełnienie W. Richard Stevens VV : / \ \ -/ja \ \ V

Upload: cryptologiconaudyt

Post on 30-Nov-2015

252 views

Category:

Documents


11 download

TRANSCRIPT

Page 1: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

tTi i eh-

fW*' *J V -

ar,

“Sn

U zupełn ien ie

W. Richard Stevens

VV:/ \ \

-/ja \ \

V

Page 2: Biblia TCP IP Tom 3 - Uzupelnienie.pdf
Page 3: Biblia TCP IP Tom 3 - Uzupelnienie.pdf
Page 4: Biblia TCP IP Tom 3 - Uzupelnienie.pdf
Page 5: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

tom 3

BIBLIA TCP/IPUzupełnienie

W. Richard Stevens

Page 6: Biblia TCP IP Tom 3 - Uzupelnienie.pdf
Page 7: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

tom 3

BIBLIA TCP/IPUzupełnienie

W. Richard Stevens

ATT

AddisonW esley

Page 8: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Biblia TCP/IP, tom III. UzupełnienieW. Richard Stevens

Tytuł oryginału amerykańskiego: TCP/IP lllustrated, Vol. III

Copyright © 1996 by Addison-Wesley Publishing Company Published by arrangement with Addison Wesley Longman, Inc.The BSD Daemon used on the cover of this book is reproduced with the permission of Marshall Kirk McKusick

Opracowanie wersji polskiej: Marcin Palacz

Copyright © for the Polish edition by Wydawnictwo RM Sp. z o.o.,Warszawa 1998

Wydawnictwo RM, 00-987 W arszaw a 4, skr. poczt. 144 e-mail: [email protected] W W W : http://www.rm .com.pl

Ali rights reserved. No part of this book may be reproduced ortransmitted in any form or by any means, electronic or m echanical, including photocopying, recording or by any information storage retrieval system , without prior permission in writing from the Publisher.

Żadna część tej pracy nie może być powielana i rozpowszechniana w jakiejkolwiek formie i w jakikolwiek sposób (elektroniczny, m echaniczny) włącznie z fotokopiowaniem, nagrywaniem na taśm y lub przy użyciu innych Systemów, bez wcześniejszej pisemnej zgody wydawcy.

W szystkie nazwy handlowe i towarów, występujące w niniejszej publikacji, s ą znakami towarowymi zastrzeżo­nymi lub nazwami zastrzeżonymi odpowiednich firm odnośnych właścicieli.

Printed in Poland.

Wydawnictwo RM dołożyło wszelkich starań, aby zapewnić najw yższą jakość tej książce . Jednakże nikomu nie udziela żadnej rękojmi ani gwarancji. Wydawnictwo RM nie jest w żadnym wypadku odpowiedzialne za jakiekolwiek szkody łącznie ze szkodami z tytułu utraty zysków związanych z prowadzeniem przedsiębiorstwa, przerw w działalności przedsiębiorstwa lub utraty informacji gospodarczej, będących następstwem korzystania z informacji zawartych w niniejszej publikacji RM, nawet jeżeli RM zostało zawiadomione o możliwości wystąpienia szkód.

ISBN 83-87216-26-7

Redaktor prowadzący: Beata Brzeg-Wieluńska Redakcja: Anna MarczakOpracowanie graficzne okładki: Grażyna Jędrzejec Skład: Marcin FabijańskiDruk i oprawa: Oficyna Wydawnicza READ ME - Drukarnia w Łodzi

Wydanie I

10 9 8 7 6 54 3 2 1

Page 9: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Moim nauczycielom, od których w ciągu minionych lat nauczyłem się tak wiele, a szczególnie

Jimowi Braultowi, Dave'owi Hansonowi, Bobowi Huntowi i Bńanowi Keńnghanowi

Page 10: Biblia TCP IP Tom 3 - Uzupelnienie.pdf
Page 11: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Spis treści

Przedmowa XV

Rozdział 1 Wprowadzenie do T/TCP 11.1 Wstęp 11.2 Klient-serwer UDP 11.3 Klient-serwer TCP 71.4 Klient-serwer T/TCP 161.5 Sieć testowa 191.6 Przykład pomiaru czasu 201.7 Aplikacje 221.8 Historia 241.9 Implementacje 261.10 Podsumowanie 28

Rozdział 2 Protokół T/TCP 312.1 Wstęp 312.2 Nowe opcje TCP związane z T/TCP 322.3 Zmienne implementacyjne T/TCP 352.4 Diagram zmiany stanów 362.5 Stany rozszerzone T/TCP 382.6 Podsumowanie 40

Rozdział 3 T/TCP - przykłady 433.1 Wstęp 433.2 Przeładowanie klienta 443.3 Normalna transakcja T/TCP 463.4 Serwer otrzymuje duplikat starego segmentu SYN 473.5 Przeładowanie serwera 483.6 Żądanie lub odpowiedź z długością większą niż MSS 493.7 Kompatybilność wstecz 543.8 Podsumowanie 56

Rozdział 4 Protokół T/TCP - kontynuacja 594.1 Wstęp 594.2 Numery portów i stan TIME_WAIT 594.3 Rola stanu TIME_WAIT 624.4 Skrócenie stanu TTME_WAIT 654.5 Unikanie potrójnego uzgodnienia przy pomocy TAO 69

Page 12: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

VIII Biblia TCP/IP-tom III Spis treści

Rozdział

Rozdział

Rozdział

Rozdział

Rozdział

4.6 Wartości CC z „zawiniętym" bitem znaku 724.7 Podsumowanie 75

5 Implementacja T/TCP: warstwa gniazd 775.1 Wstęp 775.2 Stałe 775.3 Funkcja sosend 785.4 Podsumowanie 79

6 implementacja T/TCP: tablica rutowania 816.1 Wstęp 816.2 Kod źródłowy - wprowadzenie 826.3 Struktura radix_node_head 836.4 Struktura rtentry 836.5 Struktura rt_metrics 836.6 Funkcja injnithead 846.7 Funkcja in_addroute 856.8 Funkcja in_matroute 866.9 Funkcja in_clsroute 876.10 Funkcja in_rtqtimo 886.11 Funkcja in_rtqkill 906.12 Podsumowanie 93

7 Implementacja T/TCP: bloki kontrolne protokołu 957.1 Wstęp 957.2 Funkcja in_pcbladdr 967.3 Funkcja in_pcbconnect 977.4 Podsumowanie 98

8 implementacja T/TCP: przegląd TCP 998.1 Wstęp 998.2 Kod źródłowy - wprowadzenie 998.3 Struktura TCP protosw 1008.4 Blok kontrolny TCP 1018.5 Funkcja tcp_init 1028.6 Funkcja tcp_slowtimo 1028.7 Podsumowanie 103

9 Implementacja T/TCP: wyjście TCP 1059.1 Wstęp 1059.2 Funkcja tcp_output 1059.3 Podsumowanie 112

Page 13: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

113113113114115

116120121123129131133

135135137138140144

151151152153155157

159159159160163165166166167

169169171173178

Biblia TCP/IP-tom III

10 Implementacja T/TCP: funkcje TCP10.1 Wstęp10.2 Funkcja tcp_newtcpcb10.3 Funkcja tcp_rtlookup10.4 Funkcja tcp_gettaocache10.5 Obliczenie czasu oczekiwania na powtórzenie

transmisji10.6 Funkcja tcp_close10.7 Funkcja tcp_msssend10.8 Funkcja tcp_mssrcvd10.9 Funkcja tcp_dooptions10.10 Funkcja tcp_reass10.11 Podsumowanie

11 Implementacja T/TCP: wejście TCP11.1 Wstęp11.2 Przetwarzanie wstępne11.3 Przewidywanie nagłówka11.4 Inicjacja pasywnego otwarcia11.5 Inicjacja aktywnego otwarcia11.6 Zabezpieczenie przed „zawiniętymi" numerami

sekwencyjnymi (PAWS)11.7 Przetwarzanie ACK11.8 Zakończenie pasywnych i jednoczesnych otwarć11.9 Przetwarzanie ACK (kontynuacja)11.10 Przetwarzanie flagi FIN11.11 Podsumowanie

12 Implementacja T/TCP: żądania użytkownika TCP12.1 Wstęp12.2 Żądanie PRU_CONNECT12.3 Funkcja tcp_connect12.4 Żądania PRU_SEND i PRU_SEND_EOF12.5 Funkcja tcp_usrclosed12.6 Funkcja tcp_sysctl12.7 Przyszłość T/TCP12.8 Podsumowanie

13 HTTP - protokół przesyłania hipertekstu13.1 Wstęp13.2 Wprowadzenie do HTTP i HTML13.3 Protokół HTT13.4 Przykład

Page 14: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

X Biblia TCP/IP -tom III Spis treści

13.5 Dane statystyczne HTTP 18113.6 Problemy związane z szybkością i sprawnością

działania 18313.7 Podsumowanie 185

Rozdział 14 Pakiety znalezione w serwerze HTTP 18714.1 Wstęp 18714.2 Jednoczesne serwery HTTP 19014.3 Czas pomiędzy otrzymaniem kolejnych segmentów

SYN 19114.4 Pomiary RTT 19614.5 Drugi argument funkcji listen 19814.6 Opcje w segmencie SYN klienta 20314.7 Powtórne wysłania SYN klienta 20614.8 Nazwy domen 20814.9 Ograniczenie czasu sondowania trwałości połączenia 20814.10 Symulacja rozmiaru tablicy rutowania T/TCP 21214.11 Współdziałanie z buforami mbuf 21414.12 Blok protokołu TCP i przewidywanie nagłówka 21514.13 Podsumowanie 218

Rozdział 15 NNTP - sieciowy protokół przesyłania informacji 22115.1 Wstęp 22115.2 Protokół NNTP 22315.3 Prosty klient informacji 22715.4 Bardziej skomplikowany klient informacji 22915.5 Statystyka NNTP 23015.6 Podsumowanie 231

Rozdział 16 Protokoły domeny unixowej: wprowadzenie 23316.1 Wstęp 23316.2 Zastosowania 23416.3 Szybkość działania 23516.4 Przykłady programów 23716.5 Podsumowanie 239

Rozdział 17 Protokoły domeny unixowej: implementacja 24117.1 Wstęp 24117.2 Wprowadzenie do kodu źródłowego 24117.3 Unbcowe struktury domain i protosw 24217.4 Struktura adresowa gniazda domeny unixowej 24417.5 Bloki kontrolne protokołu domeny unixowej 24517.6 Funkcja uipc_usrreq 24817.7 Żądanie PRU_ATTACH i funkcja unp_attach 249

Page 15: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Spis treści Biblia TCP/IP -tom III XI

17.8 Żądanie PRU_DETACH i funkcja unp_detach 25017.9 Żądanie P R U _ B I N D i funkcja unp_bind 25217.10 Żądanie PRU_CONNECT i funkcja unp_connect 25517.11 Żądanie PRU_CONNECT2 i funkcja unp_connect2 26017.12 Odwołanie systemowe socketpair 26417.13 Odwołanie systemowe pipę 26817.14 Żądanie PRU_ACCEPT 26917.15 Żądanie PRU_DISCONNECT i funkcja

unp_disconnect 26917.16 Żądanie PRU_SHUTDOWN i funkcja unp_shutdown 27217.17 Żądanie PRU_ABORT i funkcja unp_drop 27317.18 Różne żądania 27417.19 Podsumowanie 276

Rozdział 18 Protokoły domeny unixowej: l/O i przekazywaniedeskryptorów 277

18.1 Wstęp 27718.2 Żądania PRU_SEND i PRU_RCVD 27718.3 Przekazywanie deskryptorów 28218.4 Funkcja unp_intemalize 28818.5 Funkcja unp_extemalize 29018.6 Funkcja unp_discard 29118.7 Funkcja unp_dispose 29218.8 Funkcja unp_scan 29318.9 Funkcja unp_gc 29418.10 Funkcja unp_mark 30218.11 Szybkość działania (raz jeszcze) 30318.12 Podsumowanie 304

Dodatek A Pomiary czasu w sieci 305A .l Pomiary RTT z użyciem programu Ping 306A.2 Pomiary w stosie protokołu 308A.3 Czas propagacji a szerokość pasma 314

Dodatek B Programowanie aplikacji T/TCP 319

Bibliografia 323

Indeks 329

Page 16: Biblia TCP IP Tom 3 - Uzupelnienie.pdf
Page 17: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Przedmowa

Wstęp i układ książkiKsiążka, którą właśnie oddajemy do rąk Państwa, należy do serii „Biblia TC P/IP" (tom 1 Protokoły [Stevens 1994] i tom 2 Implementacje [Wright i Stevens 1995]). W książce tej często odwołujemy się do informacji zawartych w poprzednich tomach - używamy wtedy określeń „tom 1" i „tom 2", oraz do innych opracowań wymienionych w załączonej na końcu bibliografii - stosujemy wówczas odnośniki w nawiasach kwadratowych. Książka została podzielona na trzy części, z których każda omawia oddzielne zagadnienie:

Część I rozdziały 1-4Protokół TCP dla transakcji, powszechnie nazywany T/TCP. Jest to rozszerze­nie TCP zaprojektowane tak, by transakcje klient-serwer były szybsze, bardziej efektywne i niezawodne. Osiąga się to przez pominięcie potrójnego uzgodnie­nia przy inicjacji połączenia i przez skrócenie czasu TIME_WAIT po jego za­kończeniu. Zobaczymy, że T/TCP może zaoferować szybkość działania zbliżo­ną do UDP, a jednocześnie zapewnia znacznie większą niż UDP niezawodność i zdolność adaptacyjną. Transakcja jest zdefiniowana jako żądanie klienta skie­rowane do serwera, z następującą po żądaniu odpowiedzią serwera. (Uwaga: pojęcia transakcja nie używamy w znaczeniu transakcji pojawiającej się w kon­tekście baz danych: blokowanie, potwierdzenie dwufazowe i odtworzenie.)

Część II rozdziały 5-12Aplikacje TCP/IP, szczególnie HTTP (Hypertext Transfer Protocol, podstawa Światowej Pajęczyny - WWW) oraz NNTP (Network News Transfer Protocol, podstawa systemu Usenet News).

Część III rozdziały 13-18Protokoły domeny unixowej. Protokoły takie istnieją we wszystkich unixo- wych implementacjach TCP/IP i wielu implementacjach należących do innych systemów niż Unix. Określają sposób komunikacji między procesami (IPC) i używają tego samego interfejsu gniazd co TCP/IP. Jeśli klient i serwer działają w tym samym komputerze, protokoły domeny urtbcowej są często dwukrotnie szybsze niż TCP/IP.

Prezentacja T/TCP zawarta w części I podzielona jest na dwa działy. W rozdzia­łach 1-4 przedstawiony został protokół i zademonstrowane jego działanie na wielu przykładach. Ten materiał jest dużym rozszerzeniem krótkiej prezentacji T/TCP w rozdziale 24.7 tomu 1. Rozdziały 5-12 ukazują implementację T/TCP zawartą w kodzie sieciowym systemu 4.4BSD-Lite (jest to kod zaprezentowany w tomie 2). Ponieważ pierwsza implementacja T/TCP została udostępniona dopiero we wrześniu 1994 r., mniej więcej rok po opublikowaniu tomu 1 i dokładnie w okresie, gdy tom 2 był bliski ukończenia, szczegółowy opis T/TCP, z przykładami

Page 18: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

XIV Biblia TCP/IP-tom III Przedmowa

i szczegółami implementacji, musiał zaczekać do ukazania się następnego tomu serii.

Część II, aplikacje HTTP i NNTP, jest kontynuacją prezentacji aplikacji TCP/IP z rozdziałów 25-30 tomu 1. W ciągu dwóch lat od opublikowania tomu 1 popular­ność HTTP wraz z „eksplozją" Internetu wzrosła niewyobrażalnie. Liczba kompu­terów używających NNTP w ciągu ostatnich 10 lat rosła o około 75% rocznie. Typowy sposób użycia TCP przez HTTP to krótkie połączenia z niewielką ilością przesyłanych danych, gdzie czas połączenia jest często określony przez czas na­wiązania i zamknięcia połączenia. W związku z tym HTTP to doskonały przykład aplikaq'i, która powinna używać T/TCP. Fakt, że HTTP jest używany tak inten­sywnie przez tysiące rozmaitych klientów, stwarza też wyjątkową sposobność przeanalizowania pakietów docierających do serwera i wysyłanych przez niego (rozdział 14) oraz do przyjrzenia się wielu właściwościom TCP/IP omawianym w tomach 1 i 2.

Początkowo przewidywano, że protokoły domeny unixowej omawiane w części III zostaną przedstawione w tomie 2. Zamierzenie to zostało jednak zweryfikowa­ne, gdy objętość tomu 2 przekroczyła 1200 stron. Choć może wydawać się dziwne, że w serii zatytułowanej „Biblia TC P/IP" omawiane są protokoły inne niż TCP/IP, trzeba pamiętać, że protokoły domeny unixowej zostały zaimplementowane w 4.2BSD niemal 15 lat temu, jednocześnie z pierwszą implementacją TCP/IP w systemie BSD. Są;one dziś intensywnie używane przez jądra systemów wywo­dzących się z systemu Berkeley, ale ich użycie nie jest jawne i większość użytkow­ników nie zdaje sobie sprawy z ich istnienia. Stanowią one podstawę strumieni unixowych i są wykorzystywane przez X Windows System, jeśli klient i serwer pracują w tym samym komputerze (tzn. w typowej stacji roboczej). Gniazd dome­ny unixowej używa się również do przekazywania deskryptorów pomiędzy pro­cesami, co jest ważną techniką komunikacji miedzyprocesowej. Ponieważ interfej­sy API (application program interface - interfejs programów aplikacyjnych) gniazd używane w protokołach domeny unixowej są niemal identyczne z interfejsami API gniazd używanych w TCP/IP, protokoły domeny unixowej pozwalają zwię­kszyć szybkość lokalnych aplikacji przy bardzo niewielkich zmianach kodu.

Zwracamy uwagę, że każda z trzech części może być czytana niezależnie.

CzytelnicyPodobnie jak poprzednie dwa tomy serii, książka jest przeznaczona dla każdego, kto pragnie zrozumieć działanie protokołów TCP/IP: programistów piszących aplikacje sieciowe, administratorów systemów i sieci komputerowych używają­cych TC P/IP oraz użytkowników, którzy regularnie korzystają z aplikacji TCP/IP.

W części I i II zakładamy, że czytelnik rozumie podstawy funkcjonowania proto­kołów TCP/IP.'Czytelnicy nie znający TCP/IP powinni zajrzeć do tomu pierwsze­go [Stevens 1994] w poszukiwaniu szczegółowego opisu podstaw TCP/IP. Pierw­szy dział części I (rozdziały 1-4 - idee leżące u podstaw T/TCP oraz przykłady),

Page 19: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Przedmowa Biblia TCP/IP-tom III XV

może być czytany niezależnie od tomu 2, ale w następnych rozdziałach tej części (rozdziały 5-12 - implementacja T/TCP) zakładamy znajomość kodu sieciowego systemu 4 .4BSD-Lite przedstawionego w tomie 2.

Dla bardziej wnikliwych czytelników w tekście książki podajemy wiele odnośni­ków, zarówno do zagadnień omawianych w innych miejscach książki, jak i do odpowiednich rozdziałów tomów 1 i 2. Załączamy szczegółowy spis alfabetyczny terminów używanych w książce, a lista skrótów wraz z odpowiednimi terminami podanymi w pełnym brzmieniu znajduje się na wewnętrznej stronie okładki na początku książki. Natomiast na wewnętrznej stronie okładki na końcu książki znajduje się spis alfabetyczny wszystkich struktur, funkcji i makroinstrukcji przedstawionych w książce, wraz z numerem strony, na której zaczyna się odpo­wiedni opis. Spis ten zawiera również odnośniki do definicji w tomie 2, w przy­padku gdy odnośnik dotyczy obiektu tam wprowadzonego.

Prawa autorskie kodu źródłowegoK o d ź r ó d ł o w y z a w a r t y w książce, p o c h o d z ą c y z s y s t e m u 4.4BSD-Lite, z a w i e r a

n a s t ę p u j ą c e zastrzeżenie d o t y c z ą c e p r a w autorskich:

/** Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994* The Regents of the University of California. Ali rights reserved.** Redistribution and use in source and binary forms, with or without* modification, are permitted provided that the following conditions* are met:* 1. Redistributions of source code must retain the above copyright* notice, this list of conditions and the following disclaimer.* 2. Redistributions in binary form must reproduce the above copyright* notice, this list of conditions and the following disclaimer in the* documentati.on and/or other materials provided with the di stri buti o n .* 3. Ali advertising materials mentioning features or use of this software* must display the following acknowledgement:* This product includes software developed by the University of* California, Berkeley and its contributors.* 4. Neither the name of the University nor the names of its contributors* may be used to endorse or promote products derived from this software* without specific prior written permission.** THIS SOFTWARE 1S PR0VIDED BY THE REGENTS AND CONTRIBUTORS " A S I S " AND* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, E X EMPLARY, OR C0NSE0UENTIAL* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE G00DS* OR SERVICES; LOSS OF USE, DATA. OR PROFITS; OR BUSINESS INTERRUPTION)* H0WEVER CAUSED AND ON ANY THEORY OF LIABILITY. WHETHER IN CONTRACT, STRICT* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF* SUCH DAMAGE.

Page 20: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

XVI Biblia TCP/IP -tom III Przedmowa

K o d ź r ó d ł o w y tablicy r u t o w a n i a w rozdziale 6 z a w i e r a n a s t ę p u j ą c e zastrzeżenie:

/** Copyright 1994, 1995 Massachusetts Institute of Technology •k* Permission to use, copy, modify, and distribute this software and* its documentation for any purpose and without fee is hereby* granted, provided that both the above copyright notice and this* permission notice appear in all copies, that both the above* copyright notice and this permission notice appear in all* supporting documentation, and that the name of M.I.T. not be used* in advertising or publicity pertaining to distribution of the* software without specific, written prior permission. M.I.T. makes* no representations about the suitability of this software for any* purpose. It is provided "as is" without express or implied* warranty.** THIS SOFTWARE IS PR0VIDED BY M.I.T. " A S I S " . M.I.T. DISCLAIMS* ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,* INCLUDING. BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT* SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) H0WEVER CAUSED AND* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY.* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF* SUCH DAMAGE.*/

Konwencje typograficzneWe fragmentach, w których przedstawiamy tekst interakcyjnie wprowadzany z klawiatury i wyświetlany na ekranie, tekst z klawiatury jest przedstawiony pogru­bionym drukiem, a tekst wyświetlany przez komputer taką czci onką. Komentarze pisane są kursywą.

sun X telnet www.aw.com 80 połącz się z serwerem HTTPsunTrying 192.207.117.2... wydruk z TelnetuConnected to aw.com.

Znak zgłoszenia powłoki systemu zawiera zawsze nazwę komputera (na przykład sun). Żeby uniknąć zbyt częstych zmian czcionki, przyjęliśmy zasadę, że nazwy programów pojawiające się w tekście rozpoczynają się dużą literą (np. Telnet i Tcpdump).

Dodatkowe informacje, dotyczące kontekstu historycznego czy szczegółów implementa­cji, przedstawiamy mniejszym drukiem, w sposób taki jak tutaj.

PodziękowaniaPrzede wszystkim dziękuję mojej rodzinie, Sally, Bilłemu, Elen i Davidowi, którzy znieśli jeszcze jedną książkę, przy tak częstych moich podróżach w ciągu ostatnie­go roku. Tym razem jednak jest to naprawdę „mała" książka.

Dziękuję recenzentom, którzy czytali maszynopis dostosowując się do napiętego harmonogramu i dostarczyli wielu istotnych uwag, a są to: Sami Boulos, Alan Cox, Tony DeSimone, Pete Haverlock, Chris Heigham, Mukesh Kacker, Brian Kemig-

Page 21: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Przedmowa Biblia TCP/IP -tom III XVII

han, Art Mellor, Jeff Mogul, Mariannę Mueller, Andras Olah, Craig Partridge, Vem Paxson, Keith Sklower, łan Lance Taylor i Gary Wright. Szczególnie dziękuję redaktorowi Brianowi Kernighanowi za jego szybkie, dokładne i pomocne uwagi w czasie pisania książki, za ciągłe wsparcie oraz wyrazy zachęty.

Specjalne podziękowania należą się Vemowi Paxsonowi i Andrasowi Olahowi za nieprawdopodobnie dokładne przeczytanie kompletnego manuskryptu, za znale­zienie licznych błędów i wiele cennych technicznych sugestii. Vernowi Paxsonowi dziękuję również za udostępnienie jego programów do analizy wydruków z pro­gramu Tcpdump, a Andrasowi Olahowi za pomoc z T/TCP w ciągu ostatniego roku. Dziękuję też Bobowi Bardenowi, który zaprojektował T/TC P i dostarczył kod źródłowy implementacji, na której oparta jest I część książki.

Pomoc innych osób była również istotna - na wiele sposobów. Gary Wright i Jim Hogue udostępnili system, który pozwolił zebrać dane do rozdziału 14. Doug Schmidt dostarczył kopie powszechnie rozpowszechnianego programu TTCP, który używa gniazd domeny unixowej i który posłużył do zmierzenia zależności czasowych w rozdziale 16. Craig Partridge dostarczył kopie kodu źródłowego RDP. Mike Karels odpowiedział na liczne pytania.

Dziękuję jeszcze raz National Optical Astronomy Observatories ( NOAO), Sid- ney'owi Wolffowi, Richardowi Wolffowi i Steve'owi Grandiemu za udostępnienie sieci i komputerów.

Dziękuję także wszystkim pracownikom Addison-Wesley, którzy byli pomocni w ciągu ostatnich kilku lat, szczególnie dziękuję Johnowi Waitowi, redaktorowi moich książek.

Kompletny, gotowy do powielenia egzemplarz książki został jak zwykle przygo­towany przez autora - zagorzałego zwolennika systemu Troff - przy użyciu pakietu Groff napisanego przez Jamesa Clarka. Zachęcam Czytelników do podzie­lenia się ze mną, za pośrednictwem poczty elektronicznej, wszelkimi uwagami, sugestiami i informacjami o znalezionych błędach.

Tucsoti, Arizona Listopad 1995

W. Richard [email protected]

http://www.noao.edu/-rstevens

Page 22: Biblia TCP IP Tom 3 - Uzupelnienie.pdf
Page 23: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Wprowadzenie do T/TCP1

1.1 WstępW niniejszym rozdziale wprowadzamy pojęcie transakcji klient-serwer. Rozpo­czynamy od omówienia najprostszej z możliwych aplikacji - UDP. Następnie stworzymy programy pełniące rolę serwera i klienta używające protokołu TCP i przeanalizujemy pakiety TCP/IP wymieniane między dwoma hostami. W kolej­nym kroku przedstawimy analogiczne programy używające protokołu T/TCP. Zwrócimy uwagę na zmniejszenie liczby pakietów i pokażemy, że zmiany w ko­dzie źródłowym po obu stronach połączenia umożliwiające wykorzystanie zalet T/TCP są niewielkie.

Następnie opiszemy przykładową sieć, której będziemy używać do wykonania omawianych przykładów. Sporządzimy proste porównanie czasów potrzebnych do wykonania aplikacji typu klient-serwer używających UDP, TCP i T/TCP. Prze­analizujemy kilka typowych internetowych aplikacji wykorzystujących TCP i za­stanowimy się, co uległoby zmianie, jeśli aplikaqe po obu stronach połączenia potrafiłyby wykorzystać T/TCP. Na koniec, krótko przedstawimy historię proto­kołów transakcyjnych w ramach zestawu protokołów Internetu i opiszemy istnie­jące implementacje T/TCP.

W niniejszym tekście i ogólnie w literaturze poświęconej T/TCP określenie tran­sakcja oznacza żądanie wysłane przez klienta do serwera, wraz z następującą po żądaniu odpowiedzią serwera. Typowym internetowym przykładem transakcji jest żądanie klienta skierowane do systemu nazw domen (DNS - Domain Name System), w którym klient pyta o adres IP odpowiadający nazwie domeny, oraz następująca po pytaniu odpowiedź serwera. Podkreślamy, że terminu transakcja nie używamy w znaczeniu transakcji pojawiającej się w kontekście baz danych: blokowanie, potwierdzenie dwufazowe, odtworzenie, itd.

1.2 Klient-serwer UDPRozpoczynamy od pokazania prostego przykładu systemu klient-serwer. Kod źródłowy klienta prezentujemy na rysunku 1.1. Klient przesyła żądanie do serwe­ra, serwer przetwarza to żądanie i przesyła odpowiedź.

Page 24: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

2 Wprowadzenie do T/TCP Rozdział 1

------------------------------------------------------------------------------------------------- udpcli.c1 tfinclude "cliserv.h"

2 i nt3 maintint argc, char *argv[])4 { /* prosty klient UDP */5 struct sockaddr_in serv:6 char request[REQUEST], reply[REPLY];7 i nt sockfd, n;

8 if (argc != 2)9 err_quit("usage: udpcli <IP address of server>");

10 if ((sockfd = socket(PF_INET, S0CK_DGRAM, 0)) < 0)11 e r r_sys("socket error");

12 memset(&serv, 0, sizeof(serv));13 s e r v .sin_family = AF_IN E T :14 serv.sin_addr.s_addr = inet_addr(argv[l]);15 serv.sin_port = htons(UDP_SERV_PORT);

16 /* tworzymy żądanie request[] ... */

17 if (sendtotsockfd, request, REOUEST. 0,18 (SA) & s e r v . sizeof(serv)) != REOUEST)19 e r r_sys("sendto error");

20 if ((n = recvfrom(sockfd, reply. REPLY, 0,21 (SA) NULL, (int *) N ULL)) < 0)22 err_sys("recvfrom error");

23 /* przetwarzamy "n" bajtów odpowiedzi reply[] ... */

24 exi t (0);25 1

------------------------------------- — ------------ ----------- ----------------------------- udpcli.cRysunek 1.1 Prosty klient UDP

Sposób przedstawienia kodu źródłowego na rysunku 1.1 jest typowy dla całej książki. Każda niepusta linia jest oznaczona numerem. Odpowiedni fragment tekstu opisujący ukazany na rysunku kod źródłowy rozpoczyna się od liczb oznaczających pierwsząi ostatnią linię omawianego kodu źródłowego, tak jak to widać poniżej. Czasami taki akapit poprzedzony jest krótkim nagłówkiem zawierającym określenie opisywanego fragmentu kodu. Poziome linie na końcu i na początku fragmentu programu zakończone są nazwą pliku zawierającego przedstawiany kod źródłowy. Nazwy plików odnoszą się do plików dystrybucji 4.4BSD-Lite, którą omówimy w podrozdziale 1.9.

Omawiamy tu odpowiednie właściwości programu, ale nie opisujemy szczegóło­wo funkcji gniazd, zakładając, że są one zasadniczo znane czytelnikowi. Więcej informacji na temat tych funkcji można znaleźć w rozdziale 6 książki [Stevens 1990]. Nagłówek cl i serv . h pokazujemy na rysunku 1.2.

Utworzenie gniazda UDP10-11 Funkcja socket tworzy gniazdo UDP, zwracając nieujemny deskryptordo

procesu, z którego została wywołana. Funkcja obsługi błędu err_sys przedsta­wiona jest w dodatku B.2 książki [Stevens 1992]. Funkcja ta akceptuje dowolną liczbę argumentów, formatuje argumenty używając vspri ntf, drukuje systemo­

Page 25: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 1.2 Klient-serwer UDP 3

wą informację o błędzie odpowiadającą wartości e r rn o z odwołania systemowego i kończy proces.

Wpisanie adresu serwera12-15 Struktura adresowa gniazda internetowego jest najpierw zerowana przy

pomocy memset, a następnie wpisane zostają do niej adres IP i numer portu serwera. Dla uproszczenia wymagamy, by użytkownik podał adres IP w linii komendy uruchamiającej program (a rgv [ 1 ]). Numer portu serwera jest zdefinio­wany (#def i ne ) w nagłówku cl i serv . h i dołączany na początku wszystkich programów w tym rozdziale. W ten sposób unikamy komplikowania kodu odwo­łaniami do gethostbyname i getservbyname.

Utworzenie i wysłanie żądania do serwera16-19 Klient formułuje żądanie (które przedstawiamy jedynie jako komentarz)

i wysyłaje do serwera używając sendto. W ten sposób pojedynczy datagram UDP zostaje wysłany do serwera. Ponownie dla uproszczenia zakładamy, że żądanie i odpowiedź (REOUESTi RE PLY) mają ustaloną długość. Rzeczywista aplikacja zare­zerwowałaby miejsce na żądanie i odpowiedź o maksymalnym rozmiarze, ale faktyczna długość żądania i odpowiedzi byłaby zmienna, najczęściej mniejsza.

Odczytanie i przetworzenie odpowiedzi serwera20-23 Odwołanie do recvfrom blokuje proces (tzn. usypia go) do czasu, gdy

datagram dociera do klienta. Gdy to nastąpi, klient przetwarza odpowiedź (co pokazujemy jako komentarz) i kończy proces.

Przedstawiony program zawiesi się trwale, jeśli żądanie lub odpowiedź zaginie, ponie­waż brak jest limitu czasu dla odwołania do recvfrom . Taki brak odporności na błędy występujące w rzeczywistych warunkach jest jednym z zasadniczych mankamentów systemów klient-serwer opartych na UDP. Omawiamy to bardziej szczegółowo pod koniec tego podrozdziału.W nagłówku cl i serv . h definiujemy symbole (#define) SA jako struct sockaddr * , czyli jako wskaźnik do uniwersalnej struktury adresowej gniazda. Za każdym razem, gdy jedna z funkcji gniazda żąda wskaźnika do struktury adresowej gniazda, wskaźnik ten musi być zrzutowany na wskaźnik do uniwersalnej struktury adresowej gniazda. Dzieje się tak dlatego, gdyż funkcje gniazd powstały wcześniej niż standard ANSI C i typ wskaźnika void * nie był dostępny we wczesnych latach osiemdziesiątych, kiedy to funkq'e te zostały stworzone. Rzecz w tym, że wyrażenie „struct sockaddr * " ma 17 znaków i linia kodu zawierająca to wyrażenie często wychodzi poza prawą krawędź ekranu (lub strony - w przypadku książki), tak więc skróciliśmy to wyrażenie do S A . Ten skrót jest zapożyczony z kodu źrodłowego jądra BSD.

Na rysunku 1.2 przedstawiamy nagłówek cl i serv . h dołączany do wszystkich programów w niniejszym rozdziale.

Page 26: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

4 Wprowadzenie do T/TCP Rozdział 1

clisero.h1 /* Instrukcje include i define wspólne dla serwerów i klientów2 * UDP, TCP i T/TCP */

3 //include4 # i nc1ude5 ż/incl ude6 ż/incl ude7 //include8 //include9 //include

10 //include

<sys/types.h> <sys/socket,h> <netinet/in.h> <arpa/inet.h> <stdio.h><stdli b .h > <string.h> <unistd.h>

11 //define REOUEST 40012 y/de fi ne REPLY 400

13 //define UDP_SERV_PORT 777714 //define TCP_SERV_PORT 868815 //define TTCP_SERV_PORT 9999

/* maks. rozmiar żądania, bajty *//* maks. rozmiar odpowiedzi, bajty */

/* dobrze-znany port serwera UDP *//* dobrze-znany port serwera TCP *//* dobrze-znany port serwera T/TCP */

16 /* Skrót używany przy rzutowaniu wskaźników */17 //define SA struct sockaddr *

18 void err_quit(const char *,...);19 void err_sys(const char20 int read_stream(int, char *, int);

------------------------------------------------------------------------------------------------- ćlisew.hRysunek 1.2 Nagłówek cl i se rv .h dołączany do zoszystkichprogramów w tym rozdziale

Na rysunku 1.3 przedstawiamy kod źródłowy serwera UDP odpowiadający wcześniej przedstawionemu klientowi.------------------------------------------------------------------------------ ------------------- udpserv.c

1 //include "cliserv.h"

2 1 nt3 mai n ( )4 ( /* prosty serwer UDP */5 struct sockaddr_in serv, cli;6 char request[REQUEST], rep 1y [REP LY];7 int sockfd. n, cl i 1 e n ;

8 if (Csockfd = socket(PF_INET, S0CK_DGRAM, 0)) < 0)9 err_sys("socket error");

10 memset(&serv. 0, sizeof(serv)):11 serv.sin_family = AF_INET;12 serv.sin_addr.s_addr = htonl(1NADDR_ANY);13 serv.sin_port = htons(UDP_SERV_PORT);

14 if (bindtsockfd , (SA) &serv, sizeof(serv)) < 0)15 er r_sys("bind error");

16 for ( ; ;) {17 cl i 1 en = si zeof(cl i );18 if ((n = recvfrom(sockfd, request, REOUEST, 0,19 (SA) i c l i , &cli len)) < 0)20 err_sys(”recvfrom error");

21 /* przetwarzamy "n” bajtów żądania i tworzymy odpowiedź... */22 if (sendtotsockfd, reply, REPLY, 0,23 (SA) & c l i , si zeof(cl i )) != REPLY)24 err_sys("sendtb error");25 ]26 ]

Rysunek 1 3 Serwer UDP odpowiadający klientowi UDP z rysunku 1.1udpsero.c

Page 27: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 1.2 Klient-serwer UDP 5

Utworzenie gniazda UDP i powiązanie z lokalnym adresem8-15 Odwołanie do funkcji socket tworzy gniazdo UDP i lokalny adres serwera

jest wpisywany do internetowej struktury adresowej. Lokalny adres otrzymuje wartość wieloznaczną (I NADDR_ANY ), co oznacza, że serwer zaakceptuje datagram otrzymany z dowolnego lokalnego interfejsu (w przypadku, gdy host serwera posiada więcej niż jeden interfejs sieciowy). Numer portu jest równy dobrze-zna- nemu (well-known) numerowi portu serwera (UDP_SERV_PORT ), k tó ry -jak wspo­mnieliśmy wcześniej - został zdefiniowany w nagłówku cl i serv . h. Lokalny adres IP i dobrze-znany port zostają związane z gniazdem przez odwołanie do funkcji bind .

Przetwarzanie żądania klienta16-25 Serwer wchodzi w nieskończoną pętlę, w której czeka na żądanie klienta

(recvfrom ), przetwarza to żądanie (co pokazujemy jako komentarz) i wysyła odpowiedź (sendto ).

Pokazaliśmy najprostszą formę aplikacji typu klient-serwer używającej UDP. Po­wszechnie spotykanym w rzeczywistości przykładem jest system nazw domen Domain Name System (DNS). Klient DNS (resolver) jest zwykle częścią klienta-ap- likacji, która korzysta z DNS (na przykład Telnet, FT P, czy przeglądarka WWW). Resolver wysyła pojedynczy datagram do serwera DNS z żądaniem podania adresu IP odpowiadającego nazwie domeny. W odpowiedzi serwer wysyła zwy­kle pojedynczy datagram.

Jeśli prześledzimy pakiety wymieniane pomiędzy serwerem a klientem, otrzyma­my diagram czasowy przedstawiony na rysunku 1.4. Czas biegnie w kierunku od góry do dołu strony. Najpierw uruchamiany jest serwer, przedstawiony w prawej części rysunku, nieco później zaczyna działać klient.

Wprowadzamy rozróżnienie pomiędzy odwołaniem do funkcji wykonanym przez serwera lub przez klienta, a działaniem wykonanym przez odpowiednie jądro. Używamy dwóch strzałek narysowanych bezpośrednio jedna nad drugą, tak jak to widać w dwóch odwołaniach do funkcji s o c k e t , aby pokazać, że jądro wykonuje żądaną czynność i zwraca kontrolę do wywołującego procesu praktycz­nie natychmiast. W przypadku wywołania sendto, mimo że powrót do wywołu­jącego procesu następuje natychmiast, kernel wysyła datagram UDP. Dla uprosz­czenia zakładamy, że rozmiar datagramów utworzonych przez żądanie klienta i odpowiedź serwera jest mniejszy niż MTU (maximum tmnsmission unit - najwię­ksza jednostka transmisji) danej sieci, unikając w ten sposób dzielenia datagramu IP na części.

Na tym samym rysunku pokazujemy również, że dwa odwołania do recvfrom wprowadzają proces w stan uśpienia - aż do czasu, gdy nadejdzie oczekiwany datagram. Odpowiednie procedury jądra oznaczamy jako sl eep i wakeup (uśpie­nie i pobudka).

Page 28: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

6 Wprowadzenie do T/TCP Rozdział 1

Wreszcie pokazujemy również zależności czasowe związane z transakcją. W lewej części rysunku 1.4 pokazujemy czas transakcji mierzony przez klienta: czas upły­wający od sformułowania żądania do otrzymania odpowiedzi. Po prawej stronie rysunku zaznaczyliśmy wartości odpowiadające temu czasowi transakcji: RTT + SPT, gdzie RTT jest charakterystycznym dla danej sieci czasem przesłania datagra- mu w obie strony (round trip time), a SPT jest czasem obsługi żądania przez serwer (seruer processing time). Czas transakcji pomiędzy klientem i serwerem w protokole UDP, RTT + SPT jest najmniejszym możliwym czasem transakcji.

Założyliśmy, że czas konieczny na przesłanie datagramu od klienta do serwera wynosi RTT i że czas potrzebny na przesłanie datagramu w przeciwnym kierunku jest również

Vi RTT. Przeprowadzona analiza ponad 600 marszrut internetowych [Paxson 1995b] wykazała, że 30% z tych tras charakteryzowało się znaczącą asymetrią, to znaczy pakiety podróżujące w przeciwnych kierunkach przemieszczały się różnymi drogami.

Nasz system składający się z klienta i serwera używających UDP wydaje się mało skomplikowany (każdy z programów składa się tylko z około 30 linii kodu), ale programy te nie są wystarczająco odporne na błędy, z którymi aplikacje mogą zetknąć się w rzeczywistych warunkach. Ponieważ UDP jest zawodnym protoko­łem - datagramy mogą być zgubione lub powielone, może być zmieniona ich kolejność - aplikacja działająca w rzeczywistości musi być w stanie obsłużyć

Page 29: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 1.3 Klient-serwer TCP 7

wszystkie takie problematyczne sytuacje. Zwykle wprowadza się ograniczenie na czas oczekiwania przy odwołaniu klienta do recvfrom, tak by w przypadku zaginięcia datagramu żądanie mogło być wysłane ponownie. Jeśli ograniczenie czasu ma być wprowadzone, klient musi zmierzyć RTT i dynamicznie uaktual­niać zmierzoną wartość, ponieważ RTT w intemecie może mieć bardzo różne wartości i może ulegać dużym zmianom. Gdy zaginie odpowiedź, a nie żądanie, serwer obsłuży żądanie po raz drugi, co w przypadku niektórych usług może być powodem problemów. Serwer, by zapobiec takiej sytuacji, może zachować odpowiedź, zamiast przetwarzać żądanie po raz drugi. Dodajmy, że klient zwykle dołącza identyfikator do każdego żądania, a serwer powiela ten identyfikator, umożliwiając klientowi skojarzenie odpowiedzi z żądaniem. W rozdziale 8.4 książki [Stevens 1990] szczegółowo przedstawiono kod źródłowy konieczny do obsłużenia niektórych z wymienionych problemów dla układu klient-serwer z protokołem UDP - wymaga to jednak dodania około 500 linii kodu do każdego z programów.

O ile niezawodność wielu aplikacji UDP jest zwiększona przez dodanie tych dodatkowych elementów (ograniczenie czasu oczekiwania, pomiary RTT, iden­tyfikatory żądań, itd.), wszystkie te zabezpieczenia są od nowa wymyślane, za każdym razem, gdy powstaje nowa aplikacja. W pracy [Partridge 1990b] autor zauważa: „by stworzyć niezawodną aplikację UDP, konieczna jest informacjao stanie połączenia (numer porządkowy, liczniki retransmisji, oszacowanie czasu przesłania w obie strony). W zasadzie potrzebna jest niemal cała informacja za­warta w bloku połączenia TCP. Pisanie 'niezawodnych aplikacji UDP' jest więc w istocie równie trudne jak pisanie aplikacji TCP."

Niektóre aplikacje nie posiadają wszystkich wymaganych zabezpieczeń: na przy­kład uwzględniają ograniczenie czasu oczekiwania na datagram, ale nie mierzą lub nie uaktualniają dynamicznie RTT. Może to być przyczyną problemów, gdy aplikacja zostaje przeniesiona z jednego środowiska (na przykład LAN) do innego (na przykład WAN). Lepszym rozwiązaniem jest użycie TCP zamiast UDP i wyko­rzystanie całej niezawodności charakterystycznej dla TCP. To rozwiązanie zwię­ksza jednak czas transakcji z wartości odpowiadającej RTT + SPT do 2 x RTT + SPT, co będzie pokazane w następnym podrozdziale, oraz znacznie zwiększa liczbę pakietów wymienianych między obydwoma systemami. Środkiem zarad­czym dla tych nowych problemów jest użycie T/TCP zamiast TCP. Zajmiemy się tym zagadnieniem w rozdziale 1.4.

1.3 Klient-serwer TCPW naszym następnym przykładzie aplikacji transakcyjnej typu klient-serwer w y­korzystany jest protokół TCP. Kod źródłowy programu-klienta przedstawiony został na rysunku 1.5.

Page 30: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

8 Wprowadzenie do TfTCP Rozdział 1

------------------------------------------------------------------------------------------------- tcpcli.c1 #include "cliserv.h"

2 i nt3 main(int argc, char *argv[])4 I /* prosty klient TCP */5 struct sockaddr_in serv;6 char request[REQUEST], rep 1y [REPLY];7 int sockfd, n;

8 if (argc != 2)9 err_quit("usage: tcpcli <IP address of server>");

10 if ((sockfd = socket(PF_INET, S0CK_STREAM, 0)) < 0)11 err_sys("socket error");

12 memset(&serv, 0. sizeof(serv)):13 serv.sin_family = AF _ I N E T :14 serv.sin_addr.s_addr = inet_addr(argv[l]);15 s e r v .sin_port = htons(TCP_SERV_P0RT);

16 if (connect(sockfd. (SA) &serv, sizeof(s e r v )) < 0)17 err_sys("connect error");

18 /* tworzymy żądanie request[] . . . *1

19 if (write(sockfd, request, RE0UEST) != RE0UEST)20 err_sys(“write error”);21 if (shutdown(sockfd. 1) < 0)22 err_sys("shutdown error");

23 if (Cn = read_stream(sockfd, reply, R EPLY)) < 0)24 err_sys("read error");

25 /* przetwarzamy "n" bajtów odpowiedzi reply[] . . . *1

26 exit(0);27 1

------------------------------------------------------------------------------------------------- tcpcli.cRysunek 1.5 Klient transakcji TCP

Utworzenie gniazda TCP i połączenie z serwerem10-17 Gniazdo TCP jest tworzone przez wywołanie funkcji s o c k e t, a następnie do

internetowej struktury adresowej zostaje wpisany adres IP i numer portu serwera. Wywołanie funkcji connect powoduje potrójne uzgodnienie TCP, ustanawiając połączenie między klientem i serwerem. W podrozdziale 18.5 tomu 1 przedstawia­my dodatkowe szczegóły procedury wymiany pakietów, gdy połączenia TCP są nawiązywane i zakańczane.

Wysłanie żądania i połowiczne zamknięcie połączenia19-22 Żądanie jest wysyłane przez klienta do serwera przy pomocy funkcji w r i te.

Klient wywołuje wtedy funkcję shutdown z drugim argumentem równym 1, za­mykając tym samym połowę połączenia - przesyłanie danych w kierunku od klienta do serwera. W ten sposób serwer otrzymuje informaqę, że klient zakończył już przesyłanie danych: przesłany zostaje od klienta do serwera znak końca pliku. Segment TCP zawierający flagę FIN jest wysłany do serwera. Klient może w dal­szym ciągu otrzymywać dane - zakończone jest przesyłanie danych w jednym

Page 31: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 1.3 Klient-serwer TCP 9

kierunku. Taki stan nazywamy połowicznym zamknięciem TCP. (Dodatkowe szczegóły zostały przedstawione w rozdziale 18.5 tomu 1.)

Odczytanie odpowiedzi23-24 Odpowiedź jest czytana przy pomocy naszej funkcji read_stream, przed­

stawionej na rysunku 1.6. Ponieważ TCP jest protokołem przesyłającym strumień bajtów, bez jakiejkolwiek struktury rekordów, odpowiedź serwera może być prze­słana w jednym lub kilku segmentach TCP. Segmenty te są odczytywane przez klienta przy pomocy jednego lub kilku odwołań do funkcji read. Wiemy, że serwer po wysłaniu kompletnej odpowiedzi zamyka połączenie przez wysłanie segmentu FIN do klienta. Segment ten, przy wczytaniu funkcją read przez proces klienta, powoduje otrzymanie informacji o końcu pliku (wartość zwracana przez read jest równa 0). Funkcja read_stream jest więc wywoływana tyle razy, ile jest to konieczne, aż do momentu gdy bufor wejściowy jest pełny, lub znak końca pliku zostanie zwrócony przez read. Wartość zwracana przez tę funkcję równa jest liczbie wczytanych bajtów.

------------------------------------------------------------------------------------------------- readstream.c1 tfinclude "cliserv.h"

2 i nt3 read_stream(int fd. char *ptr, int maxbytes)4 (5 int nleft, nread;

6 nleft = ma x b y t e s ;7 while (nleft > 0) (8 if ((nread = read(fd, ptr, nleft)) < 0)9 return (nread); /* błąd, wartość zwracana < 0 */

10 else if (nread == 0)11 break; /* EOF, zwracamy liczbę przeczytanych bajtów

*/12 nleft -= nread;13 ptr += nread;14 )15 return (maxbytes - nleft); /* return >= 0 */16 )

-------------------------------------------------------------------------------------------------readstream.cRysunek 1.6 Funkcja read_stream

Istnieją również inne sposoby zaznaczenia rekordów, gdy używany jest protokół strumie­niowy, taki jak na przykład TCP. Wiele aplikacji internetowych (FTP, SMTP, HTTP, NNTP) zakańcza każdy rekord znakami karetki i nowej linii. Inne (DNS, RFC) poprze­dzają każdy rekord informacją o długości rekordu, zapisaną w polu o ustalonej długości.W naszym przykładzie używamy flagi końca pliku protokołu TCP (FIN), ponieważ wysyłamy tylko jedno żądanie od klienta do serwera i jedną odpowiedź na to żądanie. Protokół FTP - by poinformować maszynę po drugiej stronie połączenia o końcu pliku - również używa tej techniki w swoich połączeniach transferu danych.

Page 32: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

10 Wprowadzenie do T/TCP Rozdział 1

Na rysunku 1.7 przedstawiony jest serwer używający protokołu TCP.

------------------------------------------------------------------------------------------------- tcpseru.c1 #include "cliserv.h"

2 i nt3 m a i n ( )4 ( /* prosty serwer TCP */5 struct sockaddr_in serv, cli;6 char request[REQUEST], reply[REPLY];7 int listenfd, sockfd, n. clilen;

8 if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)9 e r r_sys("socket error");

10 memset(&serv, 0, sizeof(serv));11 s e r v . si n_fami ly = A F _ I N E T ;12 s e r v .sin_a ddr.s_addr = hton1( INADDR_ANY);13 serv.sin_port = htons(TCP_SERV_PORT):

14 if (binddistenfd, (SA) &serv, si zeof (serv)) < 0)15 err_sys("bind error");

16 if (1 i stent 1 i stenfd , S0MAXC0NN) < 0)17 err_sys("listen error");

18 for (;;) (19 cl 1 len = si zeof(cl i );20 if ((sockfd = acceptt1 istenfd, (SA) &cli, &cli 1 e n )) < 0)21 e r r_sys("accept error");

22 if ((n = read_stream(sockfd, request, REOUEST)) < 0)23 err_sys("read error");

24 /* przetwarzamy "n" bajtów żądania i tworzymy odpowiedź... */

25 if (wri te(sockfd, reply, REPLY) != REPLY)26 e r r_sys("write error");

27 close(sockfd);28 )29 I

Rysunek 1.7 Serwer transakcji TCPtcpserv.c

Utworzenie gniazda odbiorczego TCP8 -1 7 Gniazdo TCP jest utworzone i dobrze-znany port serwera zostaje przypisa­

ny do tego gniazda. Tak jak w przypadku TCP serwer interpretuje wartość wielo­znaczną jako własny lokalny adres. Wywołanie funkcji 1 i sten wprowadza gniaz­do w tryb odbioru, tworząc gniazdo odbiorcze, w którym akceptowane będą przychodzące połączenia. Drugi argument funkcji 1 i sten, S0MAXC0NN, przekazuje do jądra maksymalną dopuszczalną liczbę połączeń oczekujących w kolejce do danego gniazda.

Parametr S0MAXC0NN jest zdefiniowany w nagłówku < s y s / s o c k e t . h>. Tradycyjna war­tość tego parametru wynosi 5, choć niektóre nowe systemy używają wartości 10. Należy jednak pamiętać, że silnie aktywne serwery (np. systemy udostępniające strony W W W - World Wide Web, Światowa Pajęczyna) muszą często stosować wyższe wartości, na przy­kład 256 lub 1024. (Omawiamy to zagadnienie w podrozdziale 14.5.)

Page 33: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 1.3 Klient-serwer TCP 11

Akceptacja połączenia i przetworzenie żądania18-28 Serwer zatrzymuje się w funkcji accept aż do czasu, gdy połączenie zosta­

nie ustanowione w wyniku wywołania connect przez klienta, sockfd - nowy deskryptor gniazda zwrócony przez accept dotyczy połączenia z klientem. Żąda­nie klienta zostaje odczytane przez read_stream (rysunek 1.6) i następnie przy pomocy funkcji wr i te wysłana jest odpowiedź.

Przedstawiony serwer jest serwerem iteracyjnym: przetwarza on całkowicie każde żąda­nie klienta, zanim kolejny raz wywoła a c c e p t , by przyjąć od niego następne połączenie. Serwer współbieżny obsługuje wielu klientów jednocześnie. W celu stworzenia serwera współbieżnego na maszynie unixowej stosuje się technikę polegającą na tym, że serwer tworzy proces potomny po wywołaniu accept i pozostawia temu procesowi obsłużenie żądania klienta, a proces macierzysty może natychmiast przyjąć od klienta następne połączenie. Innym sposobem jest utworzenie przez serwera w celu obsłużenia każdego żądania nowego procesu wątkowego (łhread) zwanego czasem procesem błahym lub lekkim (lightweight proces). By uniknąć komplikowania przykładu odwołaniami do funk­cji kontrolujących równoległe procesy, nieistotnymi dla sieciowych aspektów zagadnie­nia, pokazujemy ha serwer iteracyjny. (W rozdziale 8 książki [Stevens 1992] omówiona jest funkcja fork. W rozdziale 4 książki [Stevens 1990] porównano serwery itericyjnei współbieżne.)Istnieje również trzecia możliwość: tzw. serwer wstępnie rozgałęziony (pre-forked seroer).W tym przypadku serwer na wstępie (przy uruchomieniu) ustaloną liczbę razy wywołuje funkcję fork i każdy proces potomny wywołuje accept dla tego samego deskryptora odbiorczego. W ten sposób unika się wywołania funkcji fork przy każdym żądaniu klienta, co może w istotny sposób przyspieszyć działanie programu w przypadku bardzo zajętego serwera. Tej techniki używają niektóre serwery HTTP.

Na rysunku 1.8 przedstawione zostały zależności czasowe dla przeprowadzonej z użyciem TCP transakcji klient-serwer. Zauważamy tu przede wszystkim zwię­kszoną w porównaniu z UDP (rysunek 1.4) liczbę pakietów sieciowych: dziewięć dla transakcji TCP, dwa - dla UDP. W przypadku użycia TCP czas transakcji mierzony po stronie klienta wynosi przynajmniej 2 x RTT + SPT. Zwykle trzy środkowe segmenty przesyłane od klienta do serwera - ACK wysłany w odpowie­dzi na SYN serwera, żądanie i FIN klienta - są wysyłane w niewielkich odstępach czasowych, podobnie jak ostatnie dwa segmenty wysyłane przez serwera do klienta - odpowiedź i FIN serwera. Dlatego też czas transakcji bywa bardziej zbliżony do 2 x RTT + SPT, niż wynikałoby to z rysunku 1.8.

Dodatkowy czas RTT w omawianym tu przykładzie związany jest z nawiązaniem połączenia TCP - odpowiada to przesłaniu dwóch pierwszych segmentów z ry­sunku 1.8. Jeśli TCP potrafiłoby połączyć nawiązanie połączenia z wysłaniem przez klienta danych i segmentu FIN, a następnie odpowiedź serwera zostałaby połączona z segmentem FIN wysłanym przez serwera, czas transakcji wyniósłby znowu RTT + SPT, czyli tyle samo ile mieliśmy w przypadku UDP. Taką mniej więcej technikę wykorzystuje w rzeczywistości protokół T/TCP.

Page 34: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

12 Wprowadzenie do T/TCP Rozdział 1

Rysunek 1.8 Diagram czasowy dla transakcji klient-serwer TCP

Page 35: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 1.3 Klient-serwer TCP 13

Stan oczekiwania TCPTCP wymaga, by uczestnik transakcji wysyłający pierwszy segment FIN, którym w naszym przypadku jest klient, pozostawał w stanie oczekiwania (TIME_WAIT) przez czas równy podwojonemu maksymalnemu czasowi życia segmentu (maxi- mum segment lifetime - MSL), po tym jak połączenie zostaje całkowicie zakończone przez obie strony. Zalecaną wartością MSL jest 120 sekund, z czego wynika wartość opóźnienia TIME_WAIT równa 4 minuty. W czasie gdy połączenie jest w stanie TIME_WAIT, to samo połączenie (tzn. ten sam adres IP i numer portu klienta oraz adres IP i numer portu serwera) nie może być otwarte ponownie. (Powiemy więcej o stanie TIME_WAIT w rozdziale 4.)

Wiele implementacji opartych na kodzie typu Berkeley pozostaje w stanie TIME_WAIT tylko przez 60 sekund, a nie przez 240 sekund, co byłoby zgodne z RFC 1122 [Braden 1989], We wszystkich prezentowanych tu oszacowaniach zakładamy, że cząs oczekiwa­nia jest poprawny i wynosi 240 sekund.

W naszym przykładzie pierwszy segment FIN wysłany jest przez klienta, co określa się jako aktywne zamknięcie (active close) i opóźnienie TIME_WAIT poja­wia się po stronie klienta. W czasie trwania stanu TIME_WAIT pewne informacjeo stanie połączenia są przechowywane przez TCP, tak by połączenie było w stanie obsłużyć segmenty, które mogły zostać opóźnione w sieci i ewentualnie dotrą po zamknięciu połączenia. Również w przypadku gdy segment z ostatecznym ACK zostanie zagubiony, serwer prześle ponownie segment FIN, co spowoduje ponow­ne przesłanie ostatecznego ACK przez klienta.

W innych aplikacjach - w szczególności w protokole HTTP używanym przez WWW - klient wysyła specjalną komendę oznaczającą, że zakończył już wysyła­nie żądania (zamiast połowicznie zamykać połączenie, tak jak to robimy w przy­padku naszego klienta), po czym serwer wysyła odpowiedź, a następnie segment FIN. W odpowiedzi klient wysyła segment FIN. Różnica polega na tym, że stan TIME_WAIT pojawia się teraz po stronie serwera, a nie klienta. W przypadku silnie aktywnego serwera, z którym kontaktują się liczni klienci, wymagana informac­ja o stanie połączenia może zajmować duży obszar w pamięci serwera. Dlatego też zagadnienie, po której stronie połączenia ma pojawiać się stan TIME_WAIT, musi być rozważone przy projektowaniu systemów transakcyjnych typu klient-serwer. W dalszej części książki pokażemy też, że T/TCP skraca czas trwania stanu TIME_WAIT z 240 sekund do około 12 sekund.

Zmniejszenie liczby segmentów wysyłanych przez TCPTCP może zmniejszyć liczbę segmentów w transakcji pokazanej na rysunku 1.8, łącząc dane z segmentami kontrolnymi, tak jak to prezentujemy na rysunku 1.9. Zauważmy, że pierwszy segment zawiera teraz SYN, dane i FIN, a nie tylko SYN, tak jak to było pokazane na rysunku 1.8. Podobnie odpowiedź serwera jest połączona z segmentem FIN. Mimo że taka sekwencja pakietów jest dopuszczalna w sensie reguł TCP, autor nie zna metody, która umożliwiłaby aplikacji spowodowanie, by protokół TCP wytworzył taką sekwencję segmentów używając interfejsu API gniazd

Page 36: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

14 Wprowadzenie do T/TCP Rozdział 1

(stąd na rysunku znak zapytania w miejscu funkcji jądra generującej pierwszy segment wysyłany przez klienta i drugi znak zapytania w miejscu funkcji generu­jącej ostatni segment wysyłany przez serwera). Autor nie zna również implemen­tacji, która w rzeczywistości generowałaby przedstawioną sekwencję segmentów.

Rysunek 1.9 Diagram czasowy dla minimalnej transakcji TCP

Page 37: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 1.3 Klient-serwer TCP 15

Warto zauważyć, że choć zmniejszyliśmy liczbę segmentów z dziewięciu do pię­ciu, czas transakcji z punktu widzenia klienta wynosi nadal 2 x RTT + SPT, ponieważ reguły TCP zabraniają protokołowi TCP serwera dostarczenia danych do serwera zanim potrójne uzgodnienie jest zakończone. (Rozdział 27.9 tomu 2 pokazuje, jak TCP umieszcza takie dane w kolejce - aż do czasu, gdy połączenie zostanie nawiązane.) Takie ograniczenie istnieje, ponieważ serwer musi mieć pew­ność, że SYN otrzymany od klienta jest „nowy", to znaczy że nie jest to opóźniony segment SYN pochodzący z poprzedniego połączenia. Stosuje się następującą procedurę: serwer potwierdza (ACK) otrzymanie segmentu SYN od serwera, w y­syła własny segment SYN i czeka aż klient potwierdzi (ACK) otrzymanie segmen­tu SYN. W momencie gdy potrójne uzgodnienie zostaje zakończone, obie strony transakcji wiedzą, że SYN wysłany przez drugą stronę jest nowy. Zmniejszenie liczby pakietów nie zmniejsza czasu transakcji mierzonego po stronie klienta, ponieważ serwer nie może rozpocząć przetwarzania żądania klienta, dopóki po­trójne uzgodnienie nie jest zakończone.

Następujący fragment pochodzi z dodatku zamieszczonego w specyfikacji RFC 1185 [Jacobsen, Braden i Zhang 1990]: „Uwaga: umożliwienie szybkiego ponownego użycia połączenia było jednym z ważnych zagadnień we wczesnym okresie rozwoju TCP. Ten wymóg był związany z nadzieją, że TCP będzie służył zarówno jako podstawa protoko­łów poziomu użytkownika, jak i protokołów zorientowanych na połączenia. Omawiano przykład segmentu Choinki »Bożo-Narodzeniowej« lub segmentu »Kamikaze«, które zawierały bity SYN i FIN oraz dane. Entuzjazm dla takiego rozwiązania zmalał, gdy zdano sobie sprawę, że potrójne uzgodnienie związane z flagą SYN i uzgodnienie zwią­zane z flagą FIN oznaczały, że pomiędzy serwerem i klientem musi być wymienionych przynajmniej 5 pakietów. Co więcej, opóźnienie związane ze stanem TIME_WAIT powo­duje, że to samo połączenie nie może być w istocie natychmiast otwarte ponownie. Pracy nad tym zagadnieniem nie kontynuowano, choć istniejące aplikacje (szczególnie SMTP) często tworzą bardzo krótkie sesje TCP. Problem ponownego użycia jest omijany przez użycie innej pary portów dla każdego połączenia."W specyfikacji RFC 1379 [Braden 1992b] zaznacza się, że „Wspomniane segmenty »Kami- kaze« nie były tworzone jako usługa; były one głównie używane do powodowania załamania innych eksperymentalnych elementów TCP!"

W charakterze eksperymentu autor napisał próbny program, który wysyła seg­ment SYN z danymi i flagą FIN. Jest to pierwszy segment na rysunku 1.9. Taki segment był wysyłany do standardowych serwerów echa (echo server - bliżej omówiony w rozdziale 1.12 tomu 1) działających na bazie ośmiu różnych odmian Unixa. Wynikłe wymiany pakietów były obserwowane przy pomocy Tcpdump. Siedem z ośmiu serwerów przetworzyło segmenty poprawnie (4.4 BSD, AIX, 3.2.2, BSD/OS 2.0, HP-UX 9.01, IRIX System V.3, SunOS 4.1.3 i System V Release 4.0), podczas gdy ósmy (Solaris 2.4) zignorował dane towarzyszące fladze SYN, co zmusiło klienta do ponownego wysłania danych.

Rzeczywista sekwencja segmentów zaobserwowana dla siedmiu systemów była inna od scenariusza pokazanego na rysunku 1.9. Po zakończeniu potrójnego uz­godnienia serwer natychmiast potwierdził (ACK) otrzymanie danych i flagi FIN. Również - ponieważ serwer echa nie miał żadnej możliwości łącznego wysłania odpowiedzi i flagi FIN (czwarty segment na rysunku 1.9) - wysłał on dwa segmen-

Page 38: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

16 Wprowadzenie do T/TCP Rozdział 1

ty: odpowiedź i segment FIN następujący natychmiast po odpowiedzi. Całkowita liczba przesłanych segmentów wyniosła więc 7, a nie 5, jak pokazano na rysunku 1.9. W rozdziale 3.7 poświęcamy więcej miejsca kompatybilności z implementa­cjami nie używającymi T/TCP oraz prezentujemy wydruk z programu Tcpdump.

Wiele systemów opartych na systemie Berkeley nie potrafi przetworzyć otrzymanego segmentu, jeśli segment ten zawiera SYN, FIN, a nie zawiera danych oraz ACK. Ten błąd powoduje utworzenie nowego gniazda, pozostającego w stanie CLOSE_WAIT aż do czasu, gdy host zostanie przeładowany. Wspomniany segment jest dopuszczalny z pun­ktu widzenia protokołu T/TCP: klient ustanawia połączenie, przesyła 0 bajtów danych i zamyka połączenie.

1.4 Klient-serwer T/TCPNasz kod źródłowy dla systemu klient-serwer wykorzystującego T/TC P różni się nieznacznie od kodu TCP z poprzedniego rozdziału, tak by możliwe było wyko­rzystanie zalet T/TCP. Na rysunku 1.10 przedstawiamy kod źródłowy klienta T/TCP.

------------------------------------------------------------------------------------------------- ttcpcli.c1 #include "cliserv.h"

2 int3 main(int argc, char *argvC])4 [ /* klient T/TCP */5 struct sockaddr_in serv;6 char request[REQUEST], reply[REPLY];7 int sockfd, n;

8 if (argc != 2)9 err_quit("u s a g e : ttcpcli <1P address of server>");

10 if ((sockfd = socket(PF_INET, S0CK_STREAM, 0)) < 0)11 err_sys("socket error");

12 memset(&serv, 0, sizeof(serv));13 s e r v .sin_family = A F_IN E T ;14 serv.sin_addr.s_addr = inet_addr(argv[l]);15 serv.sin_port = htons(TCP_SERV_PORT);

16 /* tworzymy żądanie request[]

17 if (sendtotsockfd, request, REOUEST, MSG_E0F,18 (SA) &serv, sizeof(serv)) != REOUEST)19 err_sys(”sendto error");

20 if ((n = read_stream(sockfd, reply, REPLY)) < 0)21 err_sys("read error");

22 /* przetwarzamy "n" bajtów odpowiedzi reply[] ... */

23 exi t (0);24 }

------------------------------------------------------------------------------------------------- ttcpcli.cRysunek 1.10 Klient transakcji T/TCP

Page 39: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 1.4 Klient-serwer T/TCP 17

Utworzenie gniazda TCP1 0- 15 Odwołanie do funkcji socket jest identyczne jak w przypadku klienta TCP

i internetowa struktura adresowa zostaje wypełniona adresem IP i numerem portu serwera.

Wysłanie żądania do serwera17-19 Klient używający T/TCP nie wywołuje funkcji connect. W zamian wołana

jest standardowa funkqa sendto, która wysyła żądanie do serwera oraz ustana­wia połączenie z serwerem. Dodatkowo-jako czwarty argument funkcji sendto - podajemy flagę MSG_E0F, która informuje jądro systemu, że właśnie zakończyli­śmy wysyłanie danych. Postępowanie to jest podobne do wywołania funkcji shutdown na rysunku 1.5. W rezultacie segment FIN zostaje wysłany przez klienta do serwera. Flaga M S G _ E0 F to nowy element wprowadzony w implementacjach używających T/TCP. Nie należy mylić tej flagi z istniejącą flagą M S G _ E0 R , która jest używana w protokołach zorientowanych na przesyłanie rekordów (jak na przykład warstwa transportowa protokołu OSI), by zaznaczyć koniec rekordu. W wyniku wywołania funkcji sendto wysłany zostaje przez klienta pojedynczy segment zawierający flagę SYN, żądanie i flagę FIN. Jedno odwołanie do sendto jest funkcjonalnie równoważne kolejnym odwołaniom do connect, writeishut- down.

Odczytanie odpowiedzi serwera20-21 Odpowiedź serwera jest odczytana przy pomocy odwołania do funkcji

read_stream , takiego samego jak w przypadku klienta TCP.

Na rysunku 1.11 pokazany został serwer T/TCP.

Ten program jest niemal identyczny z programem serwera TCP z rysunku 1.7: odwołania do socket, bi nd, 1 i sten, accept i read_stream są takie same. Jedyna różnica polega na tym, że serwer T/TCP wysyła odpowiedź przy pomocy send, a nie wri te. W ten sposób może być podana flaga M S G _ E0 F, co pozwala połączyć odpowiedź serwera z flagą FIN wysłaną przez serwera.

Diagram czasowy dla transakcji klient-serwer przeprowadzonej z użyciem T/TCP pokazany został na rysunku 1.12.

Czas transakcji z punktu widzenia klienta T/TCP jest niemal taki sam jak czas transakcji widziany przez klienta UDP (rysunek 1.4): RTT + SPT. Możemy się spodziewać, że czas transakcji T/TCP będzie nieznacznie większy niż czas tran­sakcji UDP, ponieważ protokół T/TCP wykonuje więcej czynności niż protokół UDP, a także dlatego, że po obu stronach połączenia konieczne są dwa wywołania read , by odczytać zarówno dane i znak końca pliku (w porównaniu do pojedyn­czego wywołania recvfrompo obu stronach w przypadku UDP). Dodatkowy czas przetwarzania w obu zaangażowanych hostach jest zwykle jednak znacznie mniejszy niż czas RTT. (Pewne porównanie czasów transakcji mierzonych dla naszych systemów klient-serwer wykorzystujących UDP, TCP i T /TCP prezentu­jemy w rozdziale 1.6). Wyciągamy więc wniosek, że transkacja T/TCP jest szybsza

Page 40: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

18 Wprowadzenie do T/TCP Rozdział 1

niż transakcja TCP o czas niemal równy RTT. W protokole T/TC P można za­oszczędzić czas odpowiadający wartości RTT dzięki wykorzystaniu procedury TAO (TCP accelerated open - przyspieszone otwarcie TCP), która omija potrójne uzgodnienie. W następnych dwóch rozdziałach opisujemy, jak jest to zrealizowa­ne, a w podrozdziale 4.5 wyjaśniamy, dlaczego taka procedura może działać po­prawnie.

------------------------------------------------------------------------------------------------- ttcpsew.c1 //include "cliserv.h"

2 int3 m a i n ( )4 ( /* serwer T/TCP */5 struct sockaddr_in serv. cli;6 char request[REQUEST], reply[REPLYJ:7 int listenfd. sockfd. n. clilen;

8 if ((listenfd = socket(PF_INET. SOCK_STREAM, 0)) < 0)9 err_sys("socket error");

10 memset(&serv, 0, sizeof(serv)):11 serv.sin_family = A F_IN E T ;12 serv.sin_addr.s_addr = htonl(INADDR_ANY);13 serv.sin_port = htons(TCP_SERV_PORT);

14 if (binddistenfd, (SA) &serv, sizeof(serv)) < 0)15 err_sys("bind error"):

16 if (listendistenfd. S0MAXC0NN) < 0)17 err_sys("listen error");

18 for (;;) (19 clilen - sizeoftcli):20 if ((sockfd = accept(listenfd, (SA) &cli, Sclilen)) < 0)21 err_sys(”accept error");

22 if ((n = read_stream(sockfd. request, REOUEST)) < 0)23 err_sys("read error");

24 /* przetwarzamy "n" bajtów żądania i tworzymy odpowiedź... */

25 if (sendtsockfd, reply. REPLY. MSG_E0F) != REPLY)26 err_sys("send error");

27 close(sockfd);28 )29 )

------------------------------------------------------------------------------------------------- ttcpseru.cRysunek 1.11 Serwer transakcji T /TC P

Przeprowadzenie transakcji w przypadku UDP wymaga przesłania przez sieć dwóch pakietów, T/TCP - trzech pakietów, a TCP - dziewięciu pakietów. (Zakła­damy, że żadne pakiety nie zostają zgubione.) T/TCP nie tylko skraca więc czas transakcji, ale również zmniejsza liczbę pakietów sieciowych. Zmniejszenie liczby pakietów sieciowych jest pożądane, ponieważ rutery ograniczają często liczbę przesyłanych pakietów - bez względu na rozmiar pojedynczego pakietu.

Page 41: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 1.5 Sieć testowa 19

Podsumowując, T/TCP zapewnia niezawodność i możlwość dostosowania do konkret­nych potrzeb - właściwości zasadnicze dla aplikacji sieciowych. Dzieje się to ko­sztem zwiększenia liczby wysyłanych pakietów o jeden, przy niewielkim zwię­kszeniu czasu transakcji.

1.5 Sieć testowaNa rysunku 1.13 przedstawiona jest sieć używana do testowania wszystkich przy­kładowych programów prezentowanych w tekście.

Page 42: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

20 Wprowadzenie do T/TCP Rozdział 1

Ethernet, 140.252.13.0

Rysunek 1.13 Sieć, w której wykonywane są wszystkie przykłady omawiane w tekście (wszystkie adresy IP zaczynają się. od 140.252.)

Większość przykładowych programów jest uruchamiana w dwóch komputerach używających protokołu T/TCP: laptopibsdi. Wszystkie adresy IP na rysunku są częścią sieci typu B: 140.252.0.0. Wszystkie nazwy hostów należą do domeny tuc.noao.edu. Akronim noao oznacza National Optical Astronomy Observato- ries (Narodowe Astronomiczne Obserwatoria Optyczne), a tuc pochodzi od na­zwy Tucson. Na rysunku 1.13 nad prostokątami odpowiadającym poszczególnym komputerom zaznaczyliśmy używany system operacyjny.

1.6 Przykład pomiaru czasuMożemy zmierzyć czas transakcji dla każdego z naszych trzech systemów klient-ser­wer i porównać wyniki. Zmodyfikujemy programy klienta w ten sposób:

• W kodzie klienta UDP z rysunku 1.1 dodamy wywołania funkcji odczytującej czas zegara bezpośrednio przed wywołaniem sendto oraz zaraz po odwołaniu do recvfrom. Różnica pomiędzy wartościami czasu otrzymanymi w tych dwóch punktach jest czasem transakcji mierzonym dla klienta.

Page 43: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 1.6 Przykład pomiaru czasu 21

• W przypadku klienta TCP z rysunku 1.5 odczytamy czas zegara bezpośrednio przed wywołaniem connecti bezpośrednio po funkcji read_stream.

• W kodzie klienta T/TCP z rysunku 1.10 czas zegara zostanie odczytany bez­pośrednio przed wywołaniem sendto oraz zaraz po wywołaniu funkcji read_stream.

Na rysunku 1.14 przedstawiamy wyniki porównania dla 14 różnych wielkości żądania i odpowiedzi. Klientem jest host bsdi z rysunku 1.13, serwerem zaś host 1 aptop . W dodatku A dokładniej omawiamy tego typu pomiary i czynniki wpły­wające na ich rezultaty.

Rysunek 1.14 Czas wykonania transakcji UDP, T/TCP i TCP

Czasy otrzymywane z użyciem protokołu T/TCP są zawsze o kilka milisekund większe niż czasy dla protokołu UDP. (Ponieważ różnice czasu są związane z opro­gramowaniem, różnice te będą z upływem lat maleć, jako że komputery stają się coraz szybsze.) Stos protokołu T/TCP wykonuje więcej czynności niż UDP (rysu­nek A.8 str. 315). Zauważyliśmy również, że klient i serwer T/TCP wykonują po dwa odwołania do funkcji read , zamiast pojedynczego odwołania do recvfrom.

Czasy otrzymane dla protokołu TCP są zawsze o około 20 ms większe niż odpo­wiednie czasy dla T/TCP. Częściowo jest to związane z potrójnym uzgodnieniem w trakcie nawiązywania połączenia. Długość dwóch segementów SYN wynosi 44 bajty (20-bajtowy nagłówek IP, standardowy 20-bajtowy nagłówek TCP i 4-bajto-

Page 44: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

22 Wprowadzenie do T/TCP Rozdział 1

wa opcja TCP - MSS). Odpowiada to 16 bajtom danych użytkownika wysłanym przy pomocy Ping; na rysunku A.3 (str. 309) widzimy, że RTT wynosi około 10 ms. Dodatkowe 10 ms różnicy jest prawdopodobnie zużytkowane na dodatkowe przetwarzanie sześciu dodatkowych segmentów TCP.

Możemy więc stwierdzić, że czas transakcji T/TCP będzie nieco większy (choć bliski) niż czas otrzymany dla UDP. Czas transakcji T/TCP będzie mniejszy od czasu TCP przynajmniej o wartość równą RTT dla 44-bajtowego segmentu.

Względny zysk wynikający z użycia T/TCP zamiast TCP zależy od relacji pomię­dzy czasem RTT a SPT. Na przykład w sieci lokalnej (LAN) z RTT równym 3 ms (rysunek A.2 str. 308), dla serwera ze średnim czasem przetwarzania 500 ms, czas transakcji TCP wyniesie około 506 ms (2 x RTT + SPT), a czas transakcji T/TCP około 503 ms. W przypadku sieci typu WAN, z czasem RTT około 200 ms (rozdział 14.4) i średnim czasem SPT około 100 ms, odpowiednie wartości wynoszą około 500 ms dla TCP i 300 ms dla T/TCP. Pokazaliśmy również, że T/TCP wykorzystu­je mniejszą liczbę pakietów sieciowych (3 w porównaniu do 9, rysunki 1.8 i 1.12). Tak więc niezależnie od zmierzonego zmniejszenia czasu, zawsze zmniejszeniu ulega liczba przesyłanych pakietów. Zmniejszenie liczby pakietów może zmniej­szyć prawdopodobieństwo zagubienia pakietu i - w kontekście Internetu widzia­nego jako całość - przyczynia się do zwiększenia ogólnej stabilności sieci.

W rozdziale A.3 (str. 316-319) omawiamy różnicę między czasem propagacji (latency), a pasmem przenoszenia. RTT zależy co prawda zarówno od czasu propagacji, jak i od pasma przenoszenia, ale wraz ze zwiększeniem się szybkości przesyłania danych w sieciach bardziej istotny staje się czas propagacji. Co więcej, czas propagacji to wielkość, na którą nie mamy wpływu, ponieważ jest on wyzna­czony przez prędkość światła i odległość pomiędzy klientem i serwerem. Dlatego też - wraz ze zwiększeniem szybkości sieci - zmniejszenie liczby pakietów przesy­łanych w obie strony staje się coraz bardziej pożądane i korzyści wynikające ze stosowania T/TCP rosną.

Ogólnie dostępne testy szybkości sieci od niedawna uwzględniają również T/TCP:http://www.cup.hp.com/netperf/NetperfPage.html.

1.7 AplikacjePierwszą zaletą korzystania z T/TCP, istotną dla każdej aplikacji TCP, jest poten­cjalna możliwość skrócenia stanu TIME_WAIT. Pozwala to na zmniejszenie liczby bloków kontrolnych, które implementacja musi przetwarzać regularnie. W roz­dziale 4.4 omawiamy tę właściwość protokołu bardziej szczegółowo. W tym miej­scu wspomnijmy tylko, że właściwość ta jest cenna dla wszystkich aplikacji, które wykorzystują krótkie (typowo: krótsze niż 2 minuty) połączenia TCP, jeśli tylko oba hosty potrafią używać T/TCP.

Największym, być może, pożytkiem wynikającym ze stosowania T/TC P jest omi­nięcie potrójnego uzgodnienia. Ponadto wszystkie aplikacje, które wymieniają niewielkie ilości danych, skorzystają na zmniejszeniu czasu oczekiwania. Przed-

Page 45: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 1.7 Aplikacje 23

stawimy kilka przykładów takich aplikacji. (W dodatku B omawiamy zmiany w programowaniu, konieczne do uniknięcia potrójnego uzgodnienia w T/TCP.)

Światowa pajęczyna: protokół HTTPWWW (World Wide Web), czyli Światowa Pajęczyna i stosowany przez nią protokół HTTP (Hyperłexł Transfer Protocol), który omawiamy w rozdziale 13, w dużym stopniu mogą wykorzystać zalety T/TCP. W pracy [Mogul 1995b] zauważono, że: „Głównym powodem opóźnień widocznych przy użyciu WWW jest komunikacja sieciowa... Skoro nie możemy zwiększyć prędkości światła, powinniśmy przynaj­mniej zmniejszyć liczbę pakietów przesyłanych w obie strony przy każdej czynno­ści. Protokół HTTP, w formie obecnie używanej w WWW, wykonuje o wiele więcej przesłań pakietów w obie strony, niż to jest niezbędnie konieczne."

Na przykład dla przypadkowo wybranej próbki 200 000 transferów z użyciem HTTP stwierdzono [Mogul 1995b], że najczęściej spotykaną długością odpowiedzi było 1770 bajtów. (Używa się często wartości najczęściej spotykanej - mediany, zamiast wartości średniej, ponieważ niewielka liczba dużych plików może spowo­dować znaczące przesunięcie wartości średniej.) Mogul podaje też inny przykład prawie półtora miliona transferów, dla których najczęściej spotykana długość odpowiedzi wynosiła 958 bajtów. Żądanie klienta jest często mniejsze: 100-300 bajtów.

Typowa transakcja HTTP typu klient-serwer jest podobna to transakcji przedsta­wionej na rysunku 1.8. Klient wykonuje aktywne otwarcie, wysyła niewielkie żądanie do serwera, serwer wysyła odpowiedź i zamyka połączenie. Tego rodzaju wymiana pakietów to idealny przykład połączenia, które mogłoby wykorzysty­wać T/TCP. Zastosowanie TCP pozwoliłoby uniknąć przesyłania pakietów w obie strony przy okazji potrójnego uzgodnienia - segment SYN wysłany przez klienta zostałby połączony z żądaniem klienta. Zmniejszeniu uległaby również liczba pakietów sieciowych, co - zwłaszcza w czasach gdy natężenie ruchu w sieci generowane przez Pajęczynę jest tak wielkie - byłoby bardzo istotne.

Połączenie typu transfer danych protokołu FTPKolejnym kandydatem jest połączenie transferu danych protokołu FTP. W opraco­waniu natężenia ruchu w Internecie przedstawionym w pracy [Paxson 1994b] pokazano, że średnio w jednym połączeniu FTP przesyła się 3000 bajtów. Na stronie 494 tomu 1 pokazujemy przykład połączenia transferu danych FTP, które jest podobne do połączenia z rysunku 1.12, choć dane przesyłane są tylko w jed­nym kierunku. Osiem segmentów ze wspomnianego rysunku zostałoby zastąpio­nych trzema segmentami w przypadku połączenia T/TCP.

System nazw domen (DNS)Klient w systemie DNS wys.yła zapytania do serwera używając UDP. Serwer odpowiada z użyciem UDP, ale jeśli odpowiedź jest dłuższa niż 512 bajtów, tylko pierwszych 512 bajtów zostaje przesłanych wraz z flagą informującą, że dalszy

Page 46: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

24 Wprowadzenie do T/TCP Rozdział 1

ciąg odpowiedzi oczekuje na przesłanie. W takim przypadku klient powtarza pytanie używając TCP, a serwer przesyła kompletną odpowiedź, również stosując protokół TCP.

Technika taka jest stosowana, ponieważ nie ma gwarancji, że host potrafi przyjąć datagram IP o długości przekraczającej 576 bajtów. (Rzeczywiście, wiele aplikacji UDP ogranicza długość danych użytkownika do 512 bajtów, po to by zmieścić się poniżej limitu 576 bajtów.) Ponieważ TCP jest protokołem przesyłającym strumień bajtów, rozmiar odpowiedzi nie stanowi problemu. Wysyłający host TCP dzieli odpowiedź na części o odpowiedniej długości - ograniczeniem jest maksymalny rozmiar segmentu (MSS) przekazany przez partnera w czasie nawiązywania połą­czenia. Odbierający host TCP przyjmuje segmenty i przekazuje do aplikacji dane, podzielone na dowolne fragmenty, zgodnie z wymaganiami funkcji czytającej używanej przez aplikację. Klient i serwer DNS mogłyby używać T/TCP, zacho­wując szybkość UDP i korzystając jednocześnie ze wszystkich zalet TCP.

Zdalne wywołanie procedur (RPC)Protokół RPC (Remote Procedure Calls - zdalne wywołanie procedur) jest wymie­niany niemal zawsze, gdy trzeba podać przykład protokołu transportowego zaprojektowanego z myślą o przeprowadzaniu transakcji. Działanie RPC opiera się na wysłaniu przez klienta do serwera żądania zawierającego nazwę procedury, która ma być wykonana przez komputer serwera, wraz z argumentami podanymi przez klienta. Odpowiedź serwera zawiera wartości zwrócone przez wywołaną procedurę. (W rozdziale 29.2 pracy [Stevens 1994] przedyskutowana jest imple­mentacja RPC działająca na komputerach Sun.)

Implementacje RPC charakteryzują się zwykle dużymi rozmiarami, w sensie dłu­gości kodu, ponieważ starają się one zapewnić niezawodność działania RPC - opierając się na zawodnym protokole, jakim jest UDP - unikając potrójnego uzgodnienia protokołu TCP. Zastosowanie T/TCP pozwoliłoby na zapewnienie RPC niezawodności właściwej dla TCP, bez konieczności potrójnego uzgodnienia.

Innymi kandydatami do stosowania T/TCP są wszystkie aplikacje oparte na RPC, jak na przykład Sieciowy System Plików ( NFS - Network File System).

1.8 HistoriaJednym z wczesnych dokumentów zajmujących się przetwarzaniem transakcji jest RFC 938 [Miller 1985]. Dokument ten definiuje IRTP (Internet Reliable Transaction Protocol - niezawodny internetowy protokół transakcyjny), który oferuje nieza­wodne, sekwencyjne dostarczanie pakietów z danymi. Wymieniony dokument RFC określa transakcję jako mały, kompletny komunikat. W założeniu IRTP defi­niuje się trwałe połączenie pomiędzy dwoma dowolnymi hostami (tzn. adresami IP), które zostaje zresynchronizowane, gdy którykolwiek z hostów zostaje przeła­dowany. IRTP jest nakładką na IP i definiuje swój własny 8-bajtowy nagłówek.

Page 47: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 1.8 Historia 25

Kolejny dokument - RFC 955 [Braden 1985], nie specyfikuje protokołu w sensie dosłownym, za to podaje pewne kryteria projektowania protokołów transakcyj­nych. W dokumencie tym zauważa się, że dwa dominujące protokoły transporto­we, UDP i TCP, oferują diametralnie różne usługi, a protokoły transakcyjne trafiają ze swoimi wymaganiami w obszar leżący pomiędzy UDP i TCP, nie obejmowany w istocie przez żaden z tych protokołów. RFC 955 definiuje transakcję jako prostą wymianę komunikatów: żądanie klienta skierowane do serwera, z następującą po nim odpowiedzią serwera. W tym RFC zauważa się też, że cechami wspólnymi wszystkich transakcji są: asymetria (na jednym końcu połączenia jest klient, na drugim serwer), jednokierunkowy przepływ danych (dane nigdy nie są przesyła­ne jednocześnie w obu kierunkach), krótki czas trwania (być może dziesiątki sekund, ale nigdy godziny), niewielkie opóźnienie, niewiele pakietów danych, operowanie komunikatami (nie strumieniem bajtów).

We wspomnianym RFC jako przykład analizowany jest DNS. Zauważa się, że konieczność wyboru pomiędzy TCP a UDP stwarza nieprzyjemny dylemat dla serwera. Optymalny protokół transakcyjny powinien umożliwić niezawodne do­starczenie danych, nie powinno być konieczne jawne nawiązanie połączenia, jaw­ne jego zerwanie, ani podział komunikatu na części, czy odtworzenie komunikatu z fragmentów (aplikacja nie powinna być zmuszona do zajmowania się magiczny­mi liczbami, jak na przykład 576), a stan bezczynności powinien trwać możliwie najkrócej na obu końcach połączenia. TCP posiada te wszystkie cechy - wyjątkiem jest konieczność nawiązania połączenia i jego zerwania.

Innym pokrewnym protokołem jest RDP (Reliable Data Protocol - niezawodny protokół danych), zdefiniowany w RFC 908 [Velten, Hinden i Skx 1984], uaktual­niony w RFC 1151 [Partridge i Hinden 1990]. Doświadczenia zebrane w trakcie implementowania tego protokołu można znaleźć w pracy [Partridge 1987], W pra­cy [Partridge 1990a] zawarty jest natomiast następujący komentarz o RDP: „Kiedy ludzie pytają o niezawodny protokół datagramowy (i zanim Jon Postel napadnie na mnie, tak Jon, wiem, że jest to oksymoron), to mają wtedy zwykle na myśli protokół transakcyjny - protokół, który umożliwia niezawodną wymianę danych z wieloma oddalonymi systemami. Rodzaj niezawodnej wersji UDP. RDP powi­nien być traktowany jako protokół TCP operujący rekordami. RDP używa połą­czeń i niezawodnie przesyła strumień nieliniowych danych. Nie jest to protokół transakcyjny." (RDP nie jest protokołem transakcyjnym, ponieważ stosuje potrój­ne uzgodnienie, tak samo jak TCP.)

RDP używa zwykłego interfejsu API gniazd i oferuje strumieniowy interfejs gniazd (SOCK_STREAM ), podobnie jak TCP. Dodatkowo RDP oferuje typy gniazd S0CK_RDM (reliably delivered message - niezawodnie dostarczony komunikat) i SOCK_SEQPACKET (sequenced packet - pakiet uszeregowany).

Protokół VMTP (Versatile Message Transaction Protocol - uniwersalny protokół transakcji komunikatów) został określony w RFC 1045 [Cheriton 1988]. Protokół ten był specjalnie zaprojektowany pod kątem obsługi transakcji reprezentowa­nych przez zdalne wywołania procedur. Podobnie jak IRTP i RDP, protokół

Page 48: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

26 Wprowadzenie do T/TCP Rozdział 1

VMTP tworzy warstwę transportową ulokowaną jako nakładka na IP. VMTP obsługuje jednak bezpośrednio przesyłanie grupowe (multicasting) - właściwości tej nie posiadają T/TCP ani inne protokoły wymienione w tym podrozdziale. (Podejście takie było krytykowane w pracy [Floyd i in. 1995], w której twierdzi się, że niezawodne przesyłanie grupowe powinno być obsługiwane w warstwie apli­kacyjnej, a nie w warstwie transportowej.)

Protokół VMTP oferuje aplikacjom inny interfejs API. Interfejs ten został opisany w dokumencie RFC 1045. Typ gniazda jest zdefiniowany jako S0CK_TRANSACT.

Choć wiele elementów T/TCP opisano w RFC 955, pierwsza specyfikacja tego protokołu pojawiła się dopiero w RFC 1379 [Braden 1992b]. Ten ostatni dokument definiuje protokół T/TCP. Uzupełnieniem RFC 955 był dokument RFC 1644 [Braden 1994], w którym sprecyzowano dodatkowe szczegóły definicji protokołui przedyskutowano niektóre zagadnienia implementacyjne.

Interesujące jest pokazane niżej porównanie liczby linii kodu źródłowego w C koniecznych, by zaimplementować różne protokoły warstwy transportu.

Protokół Liczba linii kodu

UDP (tom 2) 800

RDP 2 700

TCP (tom 2) 4 500

TCP z modyfikacjami T/TCP 5 700

VMTP 21 000

Rysunek 1.15 Liczba linii kodu potrzebna do implementacji różnych warstw transportu

Dodatkowy kod, konieczny by możliwa była obsługa T/TCP (około 1200 linii), jest półtora raza większy niż implementacja UDP. Obsługa przesłań grupowych doda­na do 4.4BSD wymagała około 2000 linii kodu (pomijając zmiany w programach obsługi urządzeń i obsługę grupowego nitowania).

Protokół VMTP jest dostępny pod adresem: f t p : / /gregori o .Stanford .edu/vmtp- i p. RDP nie jest ogólnie dostępny.

1.9 ImplementacjePierwsza implementacja T/TCP została napisana przez Boba Bradena i Liminga Wei w Information Sciences Institute Uniwersytetu Południowej Karoliny. Praca ta była częściowo finansowana przez National Science Foundation w ramach grantu numer NCR-8922231. Implementacja ta została wykonana dla systemu SunOS 4.1.3 (z jądrem wywodzącym się z systemu Berkeley) i została udostępnio­na za pośrednictwem FTP (f tp : / / f tp . i s i . e d u / p u b / b r a d e n / T T C P . t a r . Z ). Kod źródłowy jądra SunOS jest jednak potrzebny, by móc uruchomić udostępnione uzupełnienia.

Page 49: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 1.9 Implementacje 27

Wymieniona wyżej implementacja została zmodyfikowana przez Andrasa Olaha z Uniwersytetu Twente (Holandia) i została włączona do systemu FreeBSD 2.0 udostępnionego w marcu 1995 r. Kod obsługi sieci we FreeBSD 2.0 jest oparty na systemie 4.4BSD-Lite (opisany w tomie 2). Chronologię pojawiania się różnych wersji systemu BSD pokazujemy na rysunku 1.16. Cała praca związana z tablicą nitowania (patrz rozdział 6) została wykonana przez Garretta Wollmana z Massa­chusetts Institute of Technology. Informacje na temat dostępności implementacji zawartej we FreeBSD można uzyskać pod adresem http://www.freebsd.org.

4.2BSD (1983)pierwsza szeroko dostępna

wersja TCP/IP

14.3BSD (1986)

poprawa sprawnościdziałania TCP

IT

4.3BSD Tahoe (1988)___— — ' ~ powolny start, unikanie

przeciążenia,szybka retransmisja

BSD Networking Software IReleasel.O (1989): Net/1 ▼

4.3BSD Reno (1990)szybkie odtwarzanie połączenia,

_________ — - przewidywanie nagłówka,kompresja nagłówka SLIP,zmiany w tablicy rutowania

BSD Networking Software IRelease 2.0 (1991): Net/2 T

4.4BSD (1993)przesyłanie grupowe,

— -— modyfikacje długich,szerokich potoków

4.4BSD-Lite (1994) 'oznaczane w tekście książki jako Net/3

BSD/OS> FreeBSD

' ’NetBSD

4.4BSD-Llte2 (1995)

Rysunek 1.16 Różne wersje BSD i loażniejsze właściwości IP

Page 50: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

28 Wprowadzenie do T/TCP Rozdział 1

Autor niniejszej książki przeniósł implementację zawartą we FreeBSD do jądra systemu BSD/OS 2.0 (który jest również oparty na kodzie obsługi sieci z 4.4BSD- Lite). Ten kod używany jest w komputerach bsdi ilaptop (rysunek 1.13), które są używane do uruchamiania programów przedstawionych w tekście. Rozszerzenia systemu BSD/OS, umożliwiające obsługę T/TCP, są dostępne za pośrednictwem strony domowej autora: ht t p : / / w w w . noao . edu/~rstevens.

Rysunek 1.16 pokazuje kolejność pojawiania się różnych wersji BSD, z zaznaczo­nymi istotnymi właściwościami TCP/IP. Wersje pokazane w lewej części rysunku są wersjami z publicznie dostępnym kompletnym kodem źródłowym: protokoły, procedury interfejsu sieciowego zawarte w jądrze i wiele aplikacji oraz progra­mów użytkowych (jak na przykład Telnet i FTP).

Oficjalna nazwa oprogramowania używanego jako podstawa implementacji T/TCP zawartych w tekście książki brzmi 4.4BSD-Lite, będziemy jednak używać prostszej nazwy: Net/3. Należy też zauważyć, że ogólnie dostępna wersja Net /3 nie obejmuje modyfikacji związanych z T/TCP, które są przedstawione w książce. Gdy używamy terminu N e t/3, odnosimy się do ogólnie dostępnej wersji, która nie obejmuje T/TCP.

System 4.4BSD-Lite2 jest modyfikacją 4.4BSD-Lite udostępnioną w roku 1995. Z punktu widzenia obsługi sieci zmiany wprowadzone w Lite2, w porównaniu do Lite, ograniczają się do usunięcia błędów i niewielkich usprawnień (jak na przy­kład ograniczenie czasu oczekiwania na tzw. próbki trwałości - persist probes). Wymieniamy trzy systemy oparte na kodzie Lite: BSD/OS, FreeBSD i NetBSD. W czasie gdy powstaje ta książka, wszystkie trzy systemy oparte są na oryginalnym kodzie Lite. Następne wersje tych systemów powinny być już oparte na Lite2. CD-ROM zawierający kod Lite2 jest rozprowadzany przez firmę Walnut Creek CD-ROM, h t t p : / / www. c d r o m . com.

W tekście książki będziemy używać określenia implementacja oparta na systemie Berkeley w odniesieniu do takich implementacji jak SunOS, SVR4 (System V Rele- ase 4) i AIX, których oryginalny kod był stworzony na podstawie kodu źródłowego systemu Berkeley. Wszystkie te implementacje mają wiele cech wspólnych - łącznie z powieleniem tych samych błędów!

1.10 PodsumowanieW niniejszym rozdziale staraliśmy się przekonać Czytelnika, że protokół T/TCP oferuje rozwiązanie wielu rzeczywistych problemów związanych z aplikacjami sieciowymi. Porównaliśmy najpierw kody prostych systemów klient-serwer, napi­sanych z użyciem UDP, TCP i T/TCP. Dwa pakiety były wymieniane przez system oparty na UDP, dziewięć pakietów w przypadku TCP i trzy pakiety w przypadku T/TCP. Następnie pokazaliśmy, że czas transakcji z punktu widze­nia klienta jest niemal taki sam dla T/TCP jak dla UDP. Pomiary czasu zaprezen­towane na rysunku 1.14 potwierdzają nasze stwierdzenia. Poza zbliżoną do UDP

Page 51: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 1.10 Podsumowanie 29

szybkością działania, T/TCP oferuje niezawodność i możliwość przystosowania, co w obu przypadkach jest znaczącym ulepszeniem w porównaniu do UDP.

Wymienione zalety protokołu T/TCP są wynikiem rezygnacji z typowego dla TCP potrójnego uzgodnienia. Zmiany w kodzie klienta i serwera - konieczne by móc skorzystać z tych zalet T/TCP - są niewielkie; w zasadzie sprowadzają się do wywołania funkcji sendto zamiast c o n n e c t , wri te i shutdown po stronie klienta. W kolejnych trzech rozdziałach przeanalizujemy bliżej sposób działania protokołu na podstawie większej liczby przykładów.

Page 52: Biblia TCP IP Tom 3 - Uzupelnienie.pdf
Page 53: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Protokół T/TCP2

2.1 WstępNaszą dyskusję o protokole T/TCP podzielimy na dwie części (przedstawione w rozdziałach 2 i 4), tak by dogłębną prezentację protokołu (rozdział 4), móc poprzedzić kilkoma przykładami jego użycia (rozdział 3). Niniejszy rozdział jest wstępem do przedstawienia technik protokołu T/TCP i wymaganych zmiennych implementacyjnych. W następnym rozdziale zawarliśmy kilka przykładów T/TCP, a w rozdziale 4 pogłębimy prezentację protokołu.

Dwa problemy pojawiają się, gdy protokół TCP jest używany do transakqi typu klient-server, tak jak to było pokazane w rozdziale 1:

1. Potrójne uzgodnienie zwiększa czas transakcji mierzony po stronie klientao dodatkowy czas RTT. Widzieliśmy to na rysunku 1.8.

2. Ponieważ to klient wykonuje aktywne zamknięcie (tzn. wysyła pierwszą flagę FIN), klient - po odebraniu segmentu FIN wysłanego przez serwera - pozostaje w stanie TIME_WAIT przez 240 sekund. Połączenie stanu TIME_WAIT i 16-bi- towego numeru portu wprowadza ograniczenie na częstotliwość transakq'i pomiędzy dowolnymi dwoma hostami. Na przykład, jeśli pewien host-klient dokonuje transakcji w sposób ciągły z jednym hostem-serwerem, musi on albo czekać przez 240 sekund pomiędzy każdymi dwoma kolejnymi transakqami, albo musi używać innego portu do każdej kolejnej transakcji. Klient ma jednak do dyspozycji tylko 64 512 portów (65 535 minus 1023 dobrze-znane porty), dostępnych co 240 sekund każdy, co ogranicza liczbę transakcji do 268 na sekundę. W sieci LAN, w której RTT wynosi 1-3 ms, możliwe jest osiągnięcie tego limitu.

Nawet jeśli aplikacja mieści się poniżej wymienionego wyżej limitu, wykonując - powiedzmy - 50 000 transakcji na każde 240 sekund, gdy połączenie jest w stanie TIME_WAIT po stronie klienta, klient musi utworzyć blok kontrolny, po to by utrzymać połączenie w niezmienionym stanie. W implementacji BSD, omówionej w tomie 2, wymagane są: blok kontrolny protokołu Internetu (zaj­mujący 84 bajty), blok kontrolny TCP (140 bajtów) oraz wzorcowy nagłówek IP/TCP. Oznacza to zajęcie 13 200 000 bajtów pamięci jądra, co jest wielkością dużą, nawet biorąc pod uwagę fakt, że pamięci komputerów stają się coraz większe.

Protokół T/TCP rozwiązuje te dwa problemy omijając potrójne uzgodnieniei skracając czas TIME_WAIT z 240 sekund do około 12 sekund. Obie te modyfika­cje omówimy szczegółowo w rozdziale 4.

Page 54: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

32 Protokół T/TCP Rozdział 2

Podstawowy element T/TCP, który pozwala ominąć potrójne uzgodnienie, okre­ślany jest jako TAO ( TCP a c c e l e r a t e d oper) - przyspieszone otwarcie TCP). Protokół T/TCP przypisuje jednoznaczny identyfikator, zwany licznikiem połą­czenia (connection c o u n t - CC), każdemu połączeniu nawiązanemu przez host. Każdy host używający T/TCP pamięta przez pewien czas ostatnią wartość liczni­ka połączenia dla każdego partnera. Kiedy serwer otrzymuje flagę SYN od klienta T/TCP i segment SYN zawiera licznik połączenia, który jest większy od wartości ostatnio otrzymanej, oznacza to, że SYN jest nowy i można zezwolić, by odbierają­cy moduł TCP zaakceptował SYN bez potrójnego uzgodnienia. Taka procedura nazywana jest testem TAO. Jeśli wynik testu TAO jest negatywny, TCP powraca do potrójnego uzgodnienia, by sprawdzić, czy otrzymany SYN jest nowy.

2.2 Nowe opcje TCP związane z T7TCPTrzy nowe opcje TCP są używane w połączeniu T/TCP. Na rysunku 2.1 przedsta­wione zostały wszystkie obecnie używane opqe TCP. Pierwsze trzy pochodzą z oryginalnej specyfikacji TCP zawartej w RFC 793 [Postel 1981b]. Czynnik skalu­jący okna (windów s c a le factor) i znacznik czasu ( timestamp) zostały zdefinio­wane w RFC 1323 [Jacobson, Braden i Borman 1992]. Ostatnie trzy - CC, CCnewi CCecho - są nowe, związane z T/TCP i zdefiniowano je w RFC 1644 [Braden 1994]. Zasady stosowania trzech nowych opcji są następujące:

1. Opcja CC może być wysłana w inicjującym segmencie SYN, czyli w przypadku aktywnego otwarcia wykonanego przez klienta. Może być również wysłana w innych segmentach, ale tylko wtedy, gdy urządzenie na drugim końcu połą­czenia wysłało CC lub CCnew w swoim segmencie SYN.

2. Opcja CCnew może pojawić się tylko w inicjującym segmencie SYN. Protokół TCP klienta wysyła tę opcję zamiast opcji CC, jeśli klient chce wykonać zwykłe potrójne uzgodnienie.

3. Opcja CCecho może pojawić się tylko w drugim segmencie potrójnego uzgod­nienia (zwykle wysyłanym przez serwera) zawierającym flagi SYN i ACK. Potwierdzane jest w ten sposób otrzymanie opcji CC lub CCnew wysłanych przez klienta i klient jest informowany, że serwer rozumie protokół T/TCP.

W dalszej części tego rozdziału, i w następnych rozdziałach, podamy więcej infor­macji o trzech nowych opcjach, w miarę dyskutowania przykładów T/TCP.

Należy zauważyć, że każda z trzech nowych opcji zajmuje 6 bajtów. W niektórych systemach pożądane jest, by każda opcja zajmowała wielokrotność czterech baj­tów. Sześciobajtowe opcje są więc zwykle poprzedzone dwoma jednobajtowymi rozkazami pustymi (NOP).

Page 55: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 2.2 Nowe opcje TCP związane z T/TCP 33

Koniec [sty opcji (EOl)

Rozkaz pusty (NOP):

kind-0

1 bajt

kind-1

1 baji

£a:

Maksymalny rozmiar segmentu:

Czynnik skali okna:

Znacznik czasu:

CC:

CCnew:

CCecho:

kind»2 len*4maksymalny

rozmiar segmentu (MSS)

1 bajt 1 bajt 2 bajty

kind-3 len=3 wartośćprzesunięcia

1 bajt 1 bajt 1 bajt

kind *8 len-10 wartość znacznika czasu odpowiedź .echo' znacznika czasu

1 bajt 1 bajt 4 bajty 4 bajty

ldnd-11 len=6 Bez nfk połączenia

1 bajt 1 bajt 4 bajty

kind=12 len>6 nowa wartość licznika połączenia

1 bajt 1 bajt 4 bajty

kind-13 len-6 licznik połączenia - „echo’

1 bajt 1 bajt 4 bajty

Rysunek 2.1 Opcje TCP

Na rysunku 2.2 przedstawione zostały opcje TCP w iniq'ującym segmencie SYN wysłanym przez klienta do serwera, w przypadku gdy klient używa protokołu zgodnego z RFC 1323 i T/TCP. Na rysunku zaznaczono wartości kind i len dla każdej opcji, a pola NOP przedstawipno jako zacieniowane prostokąty z wartością kind równą jeden. Druga opcja (symbol „WS") to opcja skali okna (window sca 1 e). W przedstawionym przykładzie opcje TCP zajmują 28 bajtów, przy maksymalnej długości pola przeznaczonego na opcje równej 40 bajtów. Warto zauważyć, że rozkazy puste (NOP) tak uzupełniają pola zajmowane przez opcje, by długość każdej opcji była wielokrotnością 4 bajtów.

Page 56: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

34 Protokół T/TCP Rozdział 2

4 8 12 16 20 24 26

2 4 MSS 1 3 3 WS 1 i ; ł ; 8 10 znacznik czasu znacznik czasu

-echo 1 1 1 61 1

CC

Rysunek 2.2 Opcje TCP w inicjującym segmencie SYN wystanym przez klienta zgodnego z RFC 1323 i znającego T/TCP

Jeśli serwer nie używa protokołu zgodnego z RFC 1323 lub T/TCP, odpowiedź składająca się z SYN i ACK będzie zawierała tylko opcję MSS. Jeżeli natomiast protokół używany przez serwera jest zgodny zarówno z RFC 1323 jak i z T/TCP, odpowiedź będzie zawierała opcje przedstawione na rysunku 2.3.

4 8 12 16 20 24 28 32 36

2 4 MSS 1 3 3 WS

1 1 8 10 znacznik czasu znacznik czasu -echo .1 I l i ; 11 6 CC 13 6 CC echo

Rysunek 2.3 Opcje TCP w odpoiuiedzi serwera na segment zawierający opcje z rysunku 2.2

Ponieważ opcja CCecho jest zawsze wysyłana łącznie z opcją CC, protokół T/TCP powinien w zasadzie połączyć obie te opcje w jedną, oszczędzając w ten sposób 4 bajty cennej przestrzeni przeznaczonej na opcje TCP. Ewentualnie, jako że najgor­sza kombinacja opcji zdarza się tylko w przypadku SYN/ACK wysłanych przez serwera, co tak czy inaczej oznacza powolne przetwarzanie na wejściu TCP, moż­na by było pominąć rozkazy puste, oszczędzając w ten sposób 7 bajtów.

Ponieważ opcje MSS i opcja skali okna pojawiają się tylko w segmentach SYN, a opcja CCecho pojawia się tylko w segmencie SYN/ACK, wszystkie następne opcje tego połączenia zawierają tylko znacznik czasu i opcje CC. Przedstawiamy to na rysunku 2.4. Zakładamy tutaj, że po obu stronach połączenia używane są protokoły zgodne z RFC 1323 i T/TCP.

4 B 12 16

1: ■ił 8 10 znacznik czasu znacznik czasu -echo 1 i 11 6

o"

o

Rysunek 2.4 Opcje TCP w segmentach innych niż SYN, gdy oba hosty działają zgodnie z RFC 1323 i znają T/TCP

Zauważmy, że opcje znacznika czasu i CC zwiększają o 20 bajtów długość wszyst­kich segmentów TCP wysyłanych po nawiązaniu połączenia.

Mówiąc o T/TCP często używamy ogólnego określenia opcje CC (CC options), odnosząc się do wszystkich trzech opcji omówionych w obecnym podrozdziale.

Page 57: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 2.3 Zmienne implementacyjne T/TCP 35

0 ile zwiększa się objętość przesyłanych danych, gdy używane są opcje CC1 zriacznika czasu? Zakładając typowo, że MSS dla dwóch hostów w różnych sieciach wynosi 512 bajtów, plik o długości 1 miliona bajtów przesyłany jest w 1954 segmentach bez opcji, lub w 2033 segmentach, gdy opcje CC i znacznik czasu są używane. Oznacza to zwiększenie liczby segmentów o 4%. Jeżeli wartość MSS jest równa 1460 bajtów, liczba segmentów rośnie tylko o 1,5%.

2.3 Zmienne implementacyjne T/TCPProtokół T/TCP wymaga, by jądro systemu przechowywało pewne nowe infor­macje. W tym podrozdziale opisujemy, jakie są to informacje, a w następnym pokażemy, jak są one używane.

1. tcp_ccgen to 32-bitowa globalna zmienna całkowita zawierająca wartość CC, która ma być użyta przy następnym połączeniu. Zmienna ta jest zwiększanao 1 przy każdym połączeniu TCP nawiązanym przez hosta, aktywnie lub pa­sywnie -b e z względu na to, czy połączenie używa T/TCP, czy nie. Wartość tej zmiennej nigdy nie jest równa 0. Jeśli w wyniku inkrementacji zmienna miała­by osiągnąć wartość 0, ustawiana zostaje wartość 1.

2. Zespół zmiennych związanych z konkretnym hostem (tzw. pe r- ho st cache), zawierający trzy nowe zmienne: tao_cc , tao_ccsent i tao_mssopt. Ta grupa zmiennych nazywana jest również pamięcią TAO ( TAO cache). Zobaczymy, że dla każdego hosta nasza implementacja T/TCP tworzy wpis w tablicy rutowania. (Tablica rutowania jest jedynie wygodnym umiejscowieniem pamięci TAO. W za­sadzie do tego celu mogłaby być stworzona oddzielna tablica. T/TCP nie wymaga wprowadzenia żadnych modyfikacji funkcji rutowania IP.) W momencie gdy nowy wpis jest tworzony w pamięci TAO, t a o_c c i t a o_c c s en t muszą otrzymać początkową wartość równą 0, co oznacza, że zmienne te są niezdefiniowane.

t a o_c c zawiera ostatnią wartość CC otrzymaną od danego hosta w segmencie SYN, bez opcji ACK (aktywne otwarcie). Jeśli host T/TCP otrzymuje segment SYN z opcją CC i jeżeli wartość tej opcji jest większa niż t a o_c c, serwer wie, że jest to nowy SYN, a nie duplikat starego, i możliwe jest pominięcie potrójnego uzgodnienia (test TAO).

tao_ccsent zawiera ostatnią wartość CC wysłaną do danego hosta w segmen­cie SYN bez opcji ACK (aktywne otwarcie). Jeżeli zmienna ta jest niezdefinio­wana (0), to otrzymuje ona niezerową wartość, kiedy host-partner poinformuje, że potrafi używać T/TCP, przesyłając opcję CCecho.

t a o_m s s o p t zawiera ostatnią wartość MSS otrzymaną od danego hosta.

3. Trzy nowe zmienne zostały dodane do istniejącego bloku kontrolnego TCP: cc_send, cc_recv i t_durati on. Pierwsza z tych zmiennych zawiera wartość CC, która ma być wysłana w każdym segmencie danego połączenia. Druga zmienna zawiera wartość CC, która powinna być otrzymana od partnera w każdym segmencie. Ostatnia z tych zmiennych, t_duration, podaje czas

Page 58: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

36 Protokół TfTCP Rozdział 2

trwania połączenia (mierzone w impulsach zegara). W momencie gdy połącze­nie zostaje aktywnie zamknięte, jeśli ten licznik impulsów zegara ma wartość mniejszą niż MSL, czas trwania stanu TIME_WAIT ulega zmniejszeniu. Do­kładniej omawiamy to zagadnienie w rozdziale 4.4.

Wymienione zmienne możemy przedstawić tak, jak to zostało pokazane na rysunku 2.5. Zakładamy, że używana jest implementacja opisana w następnych rozdziałach.

tcp ccgen:

1 1

routo{} route{}

tao_cc tao_cc

tao_ccsent tao_ccsent

tao_mssopt tao_mssopt

> dla każdego hosta

tcpcbf) tcpcb(} tcpcb{)

cc_send cc_send cc_send

cc_recv cc_recv cc_recv

t_duration t duration t_duration

> dla każdego połączenia

Rysunek 2.5 Zmienne implementacyjne T/TCP

Na rysunku para nawiasów klamrowych {} oznacza strukturę. Pokazujemy blok kontrolny jako strukturę tcpcb. Dowolna implementacja TCP musi dla każdego połączenia posiadać blok kontrolny zawierający wszystkie przedstawione zmienne.

2.4 Diagram zmiany stanówDziałanie TCP może być przedstawione w formie diagramu zmiany stanów, tak jak to pokazano na rysunku 2.6. Na większości diagramów zmiany stanów (na przykład diagramy w tomie 1 i 2) na linii symbolizującej zmianę stanu zaznacza się nazwy przesyłanych segmentów. Na przykład zmiana stanu z CLOSED do SYN_SENT oznaczałaby wysłanie segmentu SYN. Na rysunku 2.6 rezygnujemy z tej notacji, w zamian w każdym prostokącie reprezentującym stan zaznaczamy typ segmentów wysyłanych w tym stanie. Na przykład w stanie SYN_RCVD wysyłany jest segment SYN wraz z potwierdzeniem otrzymanego SYN. W stanie CLOSE_WAIT wysyłane jest potwierdzenie otrzymanego segmentu FIN.

Page 59: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 2.4________________________ Diagram zmiany stanów_______________________________ 37

początek

f SYN RCVD "1 otrzym. SYN f SYN SENT•N

zamknięcie[ SYN, AĆK(SYN) otwarcie jednoczesne SYN lub przekr.

aplikacja: zamknięcie

FIN WAIT_1 FIN, ACK

otrzym.:

jednoczesne zamknięcie

ACK (FIN)

FIN WAIT_2ACK

otrzym.: FIN r CLOSING ' l ̂ FIN, ACK(FIN) J

otrzym.:

ACK (FIN)

otrzym.: FIN f TIME WAITACK (FIN)

upłynął czas 2MSL

otrzym.:ACK(FIN)

pasywne zamknięcie

aktywne zamknięcie

-------- ► zwykle zmiany stanu dla klienta-------- ► zwykle zmiany stanu dla serweraaplikacja: zmiany stanu, gdy aplikacja inicjuje operacjęotrzym.: zmiany stanu po odebraniu segmentu

Rysunek 2.6 Diagram zmiany stanóio TCP

Page 60: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

38 Protokół T/TCP Rozdział 2

Wprowadziliśmy tę modyfikację diagramu, ponieważ T/TC P często przetwarza segment, który powoduje więcej niż jedną zmianę stanu. Istotny jest więc ostatecz­ny stan połączenia po przetworzeniu danego segmentu - to ostateczny stan połą­czenia określa, jaka jest wysyłana odpowiedź. Bez T/TCP każdy otrzymany seg­ment powoduje co najwyżej jedną zmianę stanu. Wyjątek stanowi segment FIN/ACK, który opiszemy pokrótce niżej.

Jest kilka różnic pomiędzy rysunkiem 2.6, a diagramami TCP pokazanymi w RFC 793 [Postel 1981b].

• RFC 793 pokazuje zmianę stanu z LISTEN do SYN_SENT w momencie, gdy aplikacja wysyła dane. To ułatwienie jest rzadko udostępniane przez typowe interfejsy API.

• RFC 1122 [ Braden 1989] opisuje przejście bezpośrednio ze stanu FIN_WAIT_1 do TIME_WAIT, po otrzymaniu segmentu FIN i potwierdzeniu wysłanego segmentu FIN. Jednakże w przypadku otrzymania segmentu z takimi flagami (co jest typowe), flaga ACK jest przetwarzana najpierw, powodując przejście do stanu FIN_WAIT_2, a dopiero potem przetwarzana jest flaga FIN, powodu­jąca przejście do stanu TIME_WAIT. Widać więc, że taki segment na rysunku2.6 został opisany poprawnie. Jest to przykład pojedynczego segmentu powo­dującego dwie zmiany stanu.

• We wszystkich stanach, z wyjątkiem stanu SYN_SENT, wysyłana jest flaga ACK. Dzieje się tak dlatego, że przesłanie ACK nic nie kosztuje: w stan­dardowym nagłówku TCP jest zawsze miejsce na potwierdzenie. Dlatego TCP zawsze potwierdza najwyższy otrzymany numer sekwencyjny (plus jeden), z wyjątkiem potwierdzenia segmentu SYN odpowiadającego aktywnemu otwarciu (SYN_SENT) i z wyjątkiem potwierdzenia niektórych segmentów RST.

Kolejność przetwarzania danych wejściowych w TCPKolejność, w jakiej TCP musi przetwarzać poszczególne elementy informacji otrzymanej w danym segmencie (flagi SYN, FIN, ACK, URG i RST, ewentualnie dane i opcje), nie jest przypadkowa, lecz z góry ustalona i nie zależy od implemen­tacji. Kolejność ta określona została szczegółowo w RFC 793. Jest to również zwięźle zademonstrowane na rysunku 11.1, gdzie uwypuklono zmiany wprowa­dzone w T/TCP.

Na przykład, jeśli klient T/TCP otrzymuje segment z flagą SYN, danymi oraz flagami FIN i ACK, flaga SYN zostaje przetworzona najpierw (ponieważ gniazdo jest w stanie SYN_SENT), a następnie przetwarzane są: flaga ACK, dane i na końcu flaga FIN. Każda z tych trzech flag może spowodować zmianę stanu gniazda.

2.5 Stany rozszerzone T/TCPProtokół T/TC P definiuje siedem stanów określanych jako stany rozszerzone (extended states) , zwane również stanami z gwiazdką (s t a r r e d states). Są to:

Page 61: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 2.5 Stany rozszerzone T/TCP 39

SYN_SENT*, SYN_RCVD*, ESTABLISHED*, CLOSE_WAIT*, LAST_ACK*, FIN_WAIT_1* i CLOSING*. Na przykład na rysunku 1.12 klient wysyła inicjujący segment zawierający SYN, dane i FIN. Wysłanie tego segmentu jako części aktyw­nego otwarcia wprowadza klienta w stan SYN_SENT*, a nie w zwykły stan SYN_SENT, ponieważ flaga FIN musi być wysłana. Wielokrotne zmiany stanów zachodzą w momencie, gdy nadejdzie odpowiedź serwera zawierająca SYN, dane, FIN oraz flagę ACK potwierdzającą SYN, dane i FIN wysłane wcześniej przez klienta.

• Flaga ACK, potwierdzając SYN wysłany przez klienta, wprowadza połączenie w stan FIN_WAIT_1. Stan jest całkowicie pominięty, ponieważ klient wysłał już FIN.

• Flaga ACK potwierdzająca flagę FIN wysłaną przez klienta wprowadza połą­czenie w stan FIN_WAIT_2.

• Otrzymanie wysłanej przez serwera flagi FIN wprowadza połączenie w stan TIME_WAIT.

W RFC 1379 szczegółowo omówiony został diagram zmiany stanów, na którym uwzględniono wszystkie stany oznaczone gwiazdką. Diagram taki zawiera jednak wiele pokrywających się linii i jest dużo bardziej skomplikowany niż diagram przedstawiony na rysunku 2.6. Na szczęście związek między stanami z gwiazdką a stanami bez gwiazdki jest prosty.

• Dwa stany: SYN_SENT* i SYN_RCVD* są identyczne z odpowiednimi stanami bez gwiazdki, z dokładnością do tego, że flaga FIN musi być wysłana. To znaczy połączenie znajduje się w jednym z tych dwóch stanów, gdy zostaje utworzony aktywny punkt końcowy i aplikacja generuje komunikat MSG_EOF (wysyła FIN) zanim połączenie zostanie ustanowione. Normalnym stanem klienta w tym scenariuszu jest SYN_SENT*. Rzadko występujący stan SYN_RCVD* pojawia się, gdy następuje jednoczesne otwarcie, co omawiamy w szczegółach w rozdziale 18.8 tomu 1.

• Stany ESTABLISHED*, CLOSE_WAIT*, LAST_ACK*, FIN_WAIT_1* i CLO­SING* są identyczne z odpowiednimi stanami bez gwiazdki, z dokładnością do tego, że flaga SYN musi być wysłana. Połączenie w jednym z tych pięciu stanów określa się mianem połączenia połowicznie zsynchronizowanego {hal f - s y n - ch ron ized). Połączenie znajduje się w jednym z tych stanów, jeśli host wyko­nuje pasywne zamknięcie i otrzymuje segment SYN, który pomyślnie przecho­dzi test TAO. Wraz z tym segmentem opcjonalnie przesłane są dane i flaga FIN. (Test TAO opisany jest szczegółowo w rozdziale 4.5.) Używa się określenia połowicznie zsynchronizowane, ponieważ host otrzymujący SYN uważa, że połą­czenie jest ustanowione (skoro test TAO daje pozytywny wynik), mimo że zwykłe potrójne uzgodnienie zostało zrealizowane tylko w połowie.

Rysunek 2.7 przedstawia stany z gwiazdką oraz wszystkie pozostałe zwykłe sta­ny. Dla każdego stanu w tabeli podany został rodzaj wysyłanego segmentu.

Page 62: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

40 Protokół T/TCP Rozdział 2

Zwykły stan Określenie Wysyłane Stanz gwiazdką

Wysyłane

CLOSED połączenie zamknięte RST, ACK

LISTEN oczekiwanie na połączenie (pasywne otwarcie)

SYN_SENT wysłano SYN (aktywne otwarcie) SYN SYN_SENT’ SYN, FIN

SYN_RCVD wysłano i otrzymano SYN; oczekiwanie na ACK SYN, ACK SYN_RCVD* SYN, FIN, ACK

ESTABUSHED połączenie nawiązane (przesyłanie danych) ACK ESTABUSHED* SYN, ACK

CLOSE_WAIT otrzymano FIN, oczekiwanie na zamknięcie aplikacji ACK CLOSE_WAIT* SYN, ACK

FIN_WAIT_1 połączenie zostało zamknięte, wysłano FIN; oczekiwanie na ACK i FIN

FIN, ACK FIN_WAIT_1* SYN, FIN, ACK

CLOSING jednoczesne zamknięcie; oczekiwanie na ACK FIN, ACK CLOSING’ SYN, FIN, ACK

LAST_ACK otrzymany FIN zamknął połączenie; oczekiwanie na ACK

FIN, ACK LAST_ACK* SYN, FIN, ACK

FIN_WAIT_2 zamknięte połączenie; oczekiwanie na FIN ACK

TIME_WAIT oczekiwanie przez czas 2MSL po aktywnym zamknięciu

ACK

Rysunek 2.7 Flagi wysyłane przez TCP w zależności od aktualnego stanu (stany zwykłe i rozszerzone)

Zobaczymy, że stany z gwiazdką nie stwarzają trudności implementacyjnych. W związanym z każdym połączeniem bloku kontrolnym TCP, w uzupełnieniu informacji dotyczących stanów bez gwiazdek, umieszczane są dwie dodatkowe flagi:

• T F_S E N D F I N pokazuje, że FIN ma być wysłany (odpowiada SYN_SENT*i SYN_RCVDł)

• T F_S E N D S Y N pokazuje, że SYN ma być wysłany (odpowiada pięciu połowicz­nie zsynchronizowanym stanom z gwiazdką, rysunek 2.7)

Na rysunku 2.7 użyliśmy pogrubionej czcionki do zaznaczenia flag SYN i FIN ustawianych w stanach z gwiazdką przez dwie nowe flagi.

2.6 PodsumowanieNajważniejszy element T/TCP to TAO, czyli aktywne otwarcie TCP. Ten mecha­nizm pozwala serwerowi T/TCP stwierdzić, bez stosowania potrójnego uzgodnie­nia, że otrzymany segment SYN jest nowy. Jednoznaczny identyfikator - licznik połączenia - jest przypisany każdemu połączeniu, w którym uczestniczy dany host. Każdy host T/TCP przechowuje przez pewien czas liczniki ostatnio nawią­zanych połączeń z każdym partnerem. Test TAO daje pozytywny rezultat, gdy otrzymany segment SYN ma wartość licznika połączenia większą niż ostatnio użyta wartość tego licznika dla danego partnera.

T/TCP definiuje trzy nowe opcje: CC, CCnew i CCecho. Każda z tych opcji zawiera pole określające długość (podobnie jak wszystkie opcje zdefinowane przez RFC 1323), tak że implementacja, która danej opcji nie rozumie, może taką opcję pominąć. Jeśli dane połączenie używa T/TCP, to opcja CC obecna jest niemal

Page 63: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 2.6 Podsumowanie 41

w każdym przesyłanym segmencie. Jedynie czasami opcja CC zastąpiona zostaje opcją CCnew w segmencie SYN wysłanym przez klienta.

W związku z T/TCP dodane są: jedna globalna zmienna jądra systemu, trzy nowe zmienne w tzw. pamięci TAO tworzonej dla każdego hosta i trzy nowe zmienne w istniejącym dla każdego połączenia bloku TCP. Implementacja T/TCP, którą opisujemy w tym tekście, używa jako pamięci TAO istniejącej tablicy rutowania.

T /TCP dodaje 7 dodatkowych stanów do 10 istniejących w diagramie stanów TCP. Implementacja tych nowych stanów jest jednak prosta: dwie nowe flagi dla każdego połączenia określają, czy flagi SYN i FIN powinny być wysłane - i to wystarcza do zdefiniowania siedmiu nowych stanów, jako że są one tylko rozsze­rzeniami stanów istniejących.

Page 64: Biblia TCP IP Tom 3 - Uzupelnienie.pdf
Page 65: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

T/TCP - przykłady3

3.1 WstępPrześledzimy teraz kilka przykładów zastosowania T/TCP, po to by dokładniej przeanalizować użycie trzech nowych opcji. Przykłady pokażą, jak protokół T/TCP działa w następujących sytuacjach:

• przeładowanie klienta

• normalna transakcja T/TCP

• serwer otrzymuje duplikat starego segmentu SYN

• przeładowanie serwera

• przetwarzanie żądania lub odpowiedzi o długości większej niż MSS

• kompatybilność wstecz z systemami, które nie znają T/TCP

W następnym rozdziale rozważamy dwa dodatkowe przykłady: przypadek seg­mentów SYN nie będących duplikatami, ale przybywających do serwera w niepra­widłowej kolejności oraz przetwarzanie przez klienta zduplikowanych odpowie­dzi SYN /ACK wysłanych przez serwer.

W przedstawionych przykładach klientem T/TCP jest host bsdi (rysunek 1.13), a serwerem - host laptop. Używane są programy: klient z rysunku 1.10 i serwer z rysunku 1.11. Klient wysyła 300-bajtowe żądania, a odpowiedź serwera ma 400 bajtów.

Klient w omawianych przykładach działa z pominięciem rozszerzeń protokołu opisanych w RFC 1323. Zapobiega to wysyłaniu przez klienta opcji skali okna i znacznika czasu w inicjującym segmencie SYN. (Ponieważ klient nie wysyła tych opcji, odpowiedź serwera również nie będzie ich zawierała, nie ma więc znacze­nia, czy serwer stosuje się do RFC 1323, czy nie.) W ten sposób unikamy kompliko­wania przykładów czynnikami, które nie mają wpływu na naszą dyskusjęo T/TCP. W normalnych warunkach rozszerzenia opisane w RFC 1323 byłyby używane wraz z T/TCP, ponieważ opcja znacznika czasu daje dodatkową ochro­nę przed zinterpretowaniem starych zduplikowanych segmentów jako części ist­niejącego połączenia. Oznacza to, że nawet z użyciem T/TCP zabezpieczenie PAWS (protection against zorapped seąuence numbers - zabezpieczenie przed „zawi­niętymi" numerami sekwencyjnymi, patrz też rozdział 24.6 w tomie 1) jest nie­zbędne w przypadku szerokopasmowych połączeń, przez które przesyłane są duże ilości danych.

Page 66: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

44 T/TCP - przykłady Rozdział 3

3.2 Przeładowanie klientaRozpoczynamy naszą sekwencję transakcji klient-serwer bezpośrednio po przeła­dowaniu klienta. W momencie gdy aplikacja klienta wysyła sendto, pojawia się zapis w tablicy rutowania dotyczący serwera, z wartością tao _ccsen t ustawioną na 0 (niezdefiniowana). TCP wysyła więc opcję CCnew zamiast opcji CC. Serwer otrzymuje opcję CCnew i to powoduje, że protokół TCP serwera przeprowadza zwykłe potrójne uzgodnienie, tak jak to widać na wydruku z programu Tcpdump na rysunku 3.1. (Czytelnicy nie znający programu Tcpdump i wydruku z tego programu powinni zapoznać się z dodatkiem A tomu 1.) Analizując wydruk z programu Tcpdump, nie należy zapominać, że flagi SYN i FIN zużywają po jednym bajcie w polu numeru sekwencyjnego.

1 0.0 bsdi.1024 > laptop.8888: SFP 36858825:36859125(300)win 8568 <mss 1460,nop.nop.ccnew 1>

2 0.020542 (0.0205) laptop.8888 > bsdi.1024: S 76355292:76355292(0)ack 36858826 win 8712 <mss 1460.nop.nop,cc 18, nop.nop,ccecho 1>

3 0.021479 (0.0009) bsdi.1024 > laptop.8888: F 301:301(0)ack 1 win 8712 <nop,nop,cc 1>

0.029471 (0.0080) laptop.8888 > bsdi.1024:ack 302 win 8412 <nop,nop,cc 18>

5 0.042086 (0.0126) laptop.8888 > bsdi.1024: FP 1:401(400)ack 302 win 8712 <nop,nop,cc 18>

6 0.042969 (0.0009) bsdi.1024 > laptop.8888: .ack 402 win 8312 <nop.nop,cc 1>

Rysunek 3.1 Po przeładowaniu klient przeprowadza transakcję z senoerem

Opcja CCnew w linii 1 pokazuje, że tcp_ccgen wynosi 1. W linii 2 serwer powtarza otrzymaną wartość CCnew i wartość zmiennej tcp_ccgen serwera jest równa 18. Serwer potwierdza (ACK) otrzymanie od klienta flagi SYN, ale nie potwierdza otrzy­mania danych. Ponieważ serwer otrzymał flagę CCnew od klienta, musi on wykonać zwykłe potrójne uzgodnienie, nawet jeśli w pamięci TAO serwera znajduje się wpis dla danego klienta. Protokół TCP serwera nie może przesłać 300 bajtów danych do dalszego przetwarzania, dopóki potrójne uzgodnienie nie zostanie zakończone.

W linii 3 znajdujemy ostatni segment potrójnego uzgodnienia: potwierdzenie flagi SYN wysłanej przez serwera. Klient ponownie wysyła FIN, ale nie wysyła powtór­nie 300 bajtów danych. W momencie, gdy serwer otrzyma ten segment, natych­miast potwierdza otrzymanie danych i flagi FIN, co widać w linii 4. Flaga ACK wysyłana jest natychmiast, po to by uniknąć wyczerpania się czasu oczekiwania klienta na potwierdzenie wysłania danych w linii 1.

Linia 5 jest potwierdzeniem odpowiedzi serwera i jednocześnie otrzymanej przez klienta flagi FIN. W linii 6 klient potwierdza otrzymanie obu tych potwierdzeń. Zauważmy, że linie 3 ,4 ,5 i 6 zawierają opcję CC. Opcje CCnew i CCecho pojawiają się odpowiednio tylko w pierwszym i drugim segmencie.

Page 67: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 3.2 Przeładowanie klienta 45

Począwszy od tego miejsca nie będziemy jawnie wymieniać rozkazów pustych (NOP) w segmentach T/TC P, ponieważ flagi te nie są niezbędne i tylko komplikują naszą prezentację. Opcje, których długość nie jest wielokrotnością 4 bajtów, są uzupełnia­ne rozkazami NOP, tak by każda opcja zawierała się w naturalnych czterobajtowych granicach.Wnikliwy Czytelnik zauważy, że początkowy numer sekwencyjny (ISN) użyty przez klienta TCP bezpośrednio po przeładowaniu nie jest zgodny ze zwykłym wzorcem omawianym w ćwiczeniu 18.1 w tomie 1. Widzimy też, że początkowy numer sekwencyj­ny użyty przez serwera jest liczbą parzystą, co w normalnej sytuacji nigdy się nie zdarza w implementacjach opartych na systemie Berkeley. Mamy tu do czynienia z sytuacją, w której początkowy numer sekwencyjny jest liczbą wygenerowaną losowo. Podobnie losowo generowana jest wartość dodawana do ISN jądra po każdych 500 ms. Zwiększa to możliwość zabezpieczenia się przed próbami przechwycenia pakietów, tak jak to zostało opisane w pracy [Bellovin 1989]. Ta modyfikacja została wprowadzona do systemu BSD/OS 2.0 a następnie do systemu 4.4BSD-Lite2, po szeroko znanym internetowym włamaniu w grudniu 1994 r. [Shimomura 1995].

Diagramy zależności czasowychNa rysunku 3.2 przedstawiono diagram zależności czasowych odpowiadający wymianie segmentów z rysunku 3.1.

bsdi.1024 laptop1.8888

SYN_SENT* 1 —<mss 14bo, ccnew 1> — ►

SYN_RCVD

SYN 75355292:76355292(0) 2FIN_WAIT_1 ack 36856826, <mss 1460, ec 18 ccecho1>3 ---------- ™ ? o ta o i(o )

a< *T < c e 7 r -

ESTABLISHED,CLOSE_WAIT

ack302,<cc18> 4FIN_WAIT_2 -------------

FIN. PSH ------------------------- 5 LAST_ACK

TIME_WAIT

6

-------- - ack 302, <«1B>

CLOSEDack402, <ec1>

Rysunek 3.2 Zależności czasowe dla wymiany pakietów z rysunku 3.1

Dwa segmenty zawierające dane oznaczamy pogrubionymi liniami (segmenty 1 i 5). Zaznaczamy również zmianę stanu związaną z otrzymaniem każdego seg­mentu. Klient znajduje się początkowo w stanie SYN_SENT*. Wynika to z faktu,

Page 68: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

46 T/TCP - przykłady Rozdział 3

że klient wywołuje sendto z flagą MSG_E0F. Gdy serwer przetwarza segment 3, następują dwie zmiany stanu. Najpierw flaga ACK potwierdzająca otrzymanie flagi SYN wysłanej przez serwera wprowadza połączenie w stan ESTABLISHED. Następnie flaga FIN zmienia stan połączenia na CLOSE_WAIT. Kiedy serwer wysyła odpowiedź używając flagi MSG_EOF, połączenie po stronie serwera wchodzi w stan LAST_ACK. Zauważmy również, że klient po raz drugi wysyła flagę FIN w segmencie 3 (przypominamy rysunek 2.7).

3.3 Normalna transakcja T/TCPW następnym kroku inicjujemy kolejną transakcję pomiędzy klientem i serwerem. Tym razem klient znajduje niezerową wartość zmiennej tao_ccsent w pamięci TAO dla danego serwera. Wysyła więc opcję CC z następną wartością zmiennej t c p_c c ge n równą 2. (Jest to drugie od przeładowania połączenie T/TCP nawiąza­ne przez klienta.) Wymiana segmentów pokazana została na rysunku 3.3.

1 0.0 b s d i .1025 > laptop.8888: SFP 40203490:40203790(300)win 8712 <mss 1460,cc 2>

2 0.026469 (0.0265) laptop.8888 > bsdi.1025: SFP 79578838:79579238(400)ack 40203792 win 8712 <mss 1460,cc 19.ccecho 2>

3 0.027573 (0.0011) bsdi.1025 > laptop.8888: .ack 402 win 8312 <cc 2>

Rysunek 3.3 Normalna transakcja klient-serwer T/TCP

Jest to normalna, minimalna wymiana T/TCP, w ramach której przesłane są trzy segmenty. Na rysunku 3.4 przedstawiony został diagram czasowy tej wymiany, z zaznaczonymi zmianami stanów.

bsdi.1025 laptop,888B

SYN_SENT* 1wm MU, <mss 1460, c c 2> ------------- -- ESTABUSHED*,

CLOSE_WAIT*

FIN WAIT 1, FIN WAIT 2, TIME WAIT

3

* 3 i S w S « « *

----------- --------ggj[4Q2. win 6312 <cc2>

2 LAST_ACK*

LAST ACK, CLOSED

Rysunek 3 A Zależności czasowe dla wymiany segmentów z rysunku 3.3

Page 69: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 3.4 Serwer otrzymuje duplikat starego segmentu SYN 47

Klient wchodzi w stan SYN_SENT* w momencie, gdy wysyła SYN, dane i FIN. Gdy serwer otrzymuje ten segment i test TAO daje pozytywny wynik, serwer wchodzi w stan ESTABLISHED*. Dane są przetworzone i przesłane do procesu serwera. W dalszej kolejności, w czasie przetwarzania tego segmentu, napotkana zostaje flaga FIN, co powoduje zmianę stanu połączenia na CLOSE_WAIT*. Ser­wer znajduje się w stanie z gwiazdką, ponieważ flaga SYN ciągle jeszcze musi być wysłana. Kiedy serwer wysyła swoją odpowiedź i proces specyfikuje flagę MSG_E0F połączenie po stronie serwera wchodzi w stan LAST_ACK*. Tak jak pokazano na rysunku 2.7, segment wysłany w tym stanie zawiera flagi SYN, FIN i ACK.

Kiedy klient otrzymuje segment 2, potwierdzenie (ACK) wysłanej przez klienta flagi SYN wprowadza połączenie w stan FIN_WAIT_1. W dalszej kolejności w trakcie przetwarzania tego segmentu znalezione jest potwierdzenie flagi FIN wysłanej przez klienta, co zmienia stan połączenia na FIN_WAIT_2. Odpowiedź serwera zostaje przekazana do procesu klienta. Ostatnim etapem przetwarzania ciągle tego samego segmentu jest znalezienie flagi FIN i związana z tym zmiana stanu połączenia na TIME_WAIT. Klient wysyła odpowiedź zawierającą ACK.

Kiedy serwer otrzymuje segment 3, flaga ACK potwierdzająca SYN wysłany przez serwera wprowadza połączenie w stan CLOSED.

Przedstawiony przykład jasno pokazuje, że w trakcie przetwarzania jednego otrzymanego segmentu następują liczne kolejne zmiany stanu. Pokazaliśmy też, że proces może otrzymać dane w stanie innym niż ESTABLISHED. Zdarza się to, gdy klient otrzymuje dane w stanie FIN_WAIT_1 (segment 2), po połowicznym zamknięciu połączenia (segment 1).

3.4 Serwer otrzymuje duplikat starego segmentu SYNCo się dzieje, gdy serwer otrzymuje segment z wartością CC odpowiadającą wcześniejszemu połączeniu z klientem? Zmuszamy klienta do wysłania segmentu SYN z wartościa CC równą 1, która jest mniejsza od najnowszej wartości CC otrzymanej przez serwera od tego klienta (wartość 2, rysunek 3.3). Taka sytuacja może nastąpić, gdy segment z CC równym 1 pochodzi z wcześniejszego wcielenia tego samego połączenia i uległ pewnemu opóźnieniu w sieci, nie większemu jednak niż wartość MSL obowiązująca w momencie wysyłania segmentu.

Połączenie jest zdefiniowane przez parę gniazd czyli zespół czterech elementów: numer IP i numer portu klienta oraz numer IP i numer portu serwera. Nowe realizacje tego samego połączenia (te same cztery elementy) nazywane są wciele­niami (incamations) połączenia.

Na rysunku 3.5 widzimy, że gdy serwer otrzymuje SYN z wartością CC równą 1, wymusza on przeprowadzenie potrójnego uzgodnienia, ponieważ nie może stwierdzić, czy otrzymany segment jest duplikatem starego segmentu, czy też nie.

Page 70: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

48 T/TCP - przykłady Rozdział 3

1 0.0 bsdi.1027 > laptop.8888: SFP 80000000:80000300(300)win 4096 <mss 1460,cc 1>

2 0.018391 (0.0184) laptop.8888 > bsdi.1027: S 132492350:132492350(0)ack 80000001 win 8712 <mss 1460,cc 21,ccecho 1>

3 0.019266 (0.0009) bsdi.1027 > laptop.8888: R 80000001:80000001(0) win 0

Rysunek 3.5 Serwer T/TCP otrzymuje od klienta duplikat starego segmentu SYN

Ponieważ ma miejsce potrójne uzgodnienie (co poznajemy po tym, że tylko flaga SYN jest potwierdzona, dane zaś nie), TCP serwera nie może przekazać 300 bajtów danych do procesu serwera aż do czasu potrójnego zakończenia.

W naszym przykładzie segment 1 jest duplikatem starego segmentu (TCP klienta nie oczekuje w tym momencie odpowiedzi na ten segment SYN) - tak więc gdy klient otrzymuje od serwera flagi SYN i ACK w segmencie 2, klient odpowiada wysłaniem flagi RST (segment 3). To właśnie powinno się zdarzyć. Serwer po otrzymaniu RST kasuje 300 bajtów danych i nie zakańcza odwołania do funkcji a c c e p t , na co czeka proces serwera.

Segment 1 został wygenerowany przez specjalny program służący do testów. Nie jeste­śmy w stanie spowodować, by klient T /TC P wygenerował taki segment, chcemy nato­miast, by segment ten wyglądał jak duplikat starego segmentu. Autor próbował sztucznie ustawić wartość tcp_ccgen na 1, ale - jak widzimy to na rysunku 12.3 - jeśli wartość tcp_ccgen zawarta w jądrze jest mniejsza niż ostatnia wartość CC wysłana do danego hosta, TCP automatycznie wysyła opcję CCnew, zamiast opcji CC.

Na rysunku 3.6 przedstawiona została następna, normalna transakcja T/TCP. Zgodnie z oczekiwaniami transakcja ta obejmuje wymianę trzech segmentów.

1 0 .0 bsdi.1026 > laptop.8888: SFP 101619844:101620144(300)win 8712 <mss 1460,cc 3>

2 0.028214 (0.0282) laptop.8888 > bsdi.1026: SFP 140211128:140211528(400)ack 101620146 win 8712 <mss 1460,cc 22,ccecho 3>

i 0.029330 (0.0011) bsdi .1026 > laptop.8888: .ack 402 win 8312 <cc 3>

Rysunek 3.6 Normalna transakcja klient-serwer T/TCP

Serwer spodziewa się otrzymać opcję CC z wartością większą niż 2, tak więc otrzymany segment SYN przechodzi test TAO z wynikiem pozytywnym.

3.5 Przeładowanie serweraPrzeładowujemy teraz serwer i klient rozpoczyna transakcję zaraz po przeładowa­niu, bezpośrednio po ponownym uruchomieniu procesu odbierającego serwera. Wymianę segmentów pokazujemy na rysunku 3.7.

Page 71: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 3.6 Żądanie lub odpowiedź z długością większą niż M SS 49

1 0.0 bsdi .1027 > laptop.8888: SFP 146513089:146513389(300)win 8712 <mss 1460,cc 4>

2 0.025420 (0.0254) arp who-has bsdi tell laptop

3 0.025872 (0.0005) arp reply bsdi is-at 0:20:af:9c:ee:95

4 0.033731 (0.0079) laptop.8888 > bsdi.1027: S 27338882:27338882(0)ack 146513090 win 8712 <mss 1460,cc l.ccecho 4>

5 0.034697 (0.0010) bsdi .1027 > laptop.8888: F 301:301(0)ack 1 win 8712 <cc 4>

6 0.044284 (0.0096) laptop.8888 > bsdi.1027: .ack 302 win 8412 <cc 1>

7 0.066749 (0.0225) laptop.8888 > bsdi.1027: FP 1:401(400)ack 302 win 8712 <cc 1>

8 0.067613 (0.0009) bsdi.1027 > laptop.8888: .ack 402 win 8312 <cc 4>

Rysunek 3.7 Wymiana pakietów T/TCP po przeładowaniu serwera

Ponieważ klient nie wie, że serwer został przeładowany, wysyła on normalne żądanie T/TCP z wartością CC równą 4 (linia 1). Ze względu na to, że serwer stracił sprzętowy adres klienta w czasie przeładowywania, serwer wysyła żądanie A R P , na co klient reaguje wysłaniem odpowiedzi ARP. Serwer wymusza zwykłe potrójne uzgodnie­nie (linia 4), nie zna bowiem wartości CC ostatnio otrzymanej od tego klienta.

Podobnie do sytuacji z rysunku 3.1, klient kończy potrójne uzgodnienie potwier­dzeniem, które zawiera również flagę FEST - 300 bajtów danych nie zostaje wysła­nych ponownie. Dane klienta są retransmitowane dopiero po upływie czasu oczeki­wania klienta na retransmisję, co pokażemy na rysunku 3.11. Po otrzymaniu trzeciego segmentu serwer natychmiast potwierdza otrzymanie danych i segmentu FIN. Odpowiedź serwera (linia 7) zostaje potwierdzona przez klienta w linii 8.

Po wymianie segmentów przedstawionej na rysunku 3.7 spodziewamy się, że następna transakcja pomiędzy klientem i serwerem bedzie znowu wymianą tylko trzech segmentów, tak jak to pokazujemy na rysunku 3.8.

1 0.0 bsdi.1028 > laptop.8888: SFP 152213061:152213361(300)win 8712 <mss 1460,cc 5>

2 0.034851 (0.0349) laptop.8888 > bsdi.1028: SFP 32869470:32869870(400)ack 152213363 win 8712 <mss 1460,cc 2,ccecho 5>

3 0.035955 (0.0011) bsdi .1028 > laptop.8888: .ack 402 win 8312 <cc 5>

Rysunek 3.8 Normalna transakcja klient-serwer TCP

3.6 Żądanie lub odpowiedź z długością większą niż MSSWe wszystkich naszych dotychczasowych przykładach klient wysyłał dane o dłu­gości nie przekraczającej MSS, i odpowiedź serwera też była nie dłuższa niż MSS. Jeżeli aplikacja klienta wysyła więcej bajtów danych niż MSS i jeżeli TCP klienta

Page 72: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

50 T/TCP - przykłady Rozdział 3

wie, że partner (serwer) potrafi obsłużyć T/TCP, dane są wysyłane w kilku seg­mentach. Ponieważ wartość MSS partnera jest przechowywana w zmiennej tao_mssopt (rysunek 2.5), klient zna MSS serwera, ale nie zna wielkości okna odbiorczego (receive ivindow) procesu partnera. (W rozdziałach 18.4 i 20.4 tomu 1 omawiane są odpowiednio MSS i rozmiar okna.) W przeciwieństwie do MSS, które jest zwykle stałe dla danego hosta-partnera, rozmiar okna może być zmie­niony przez aplikację, jeśli aplikacja zmienia rozmiar bufora wejściowego związa­nego z konkretnym gniazdem. Co więcej, nawet jeśli partner powiadomi, że uży­wa dużego okna (powiedzmy 32 768 bajtów) i jeśli MSS wynosi 512 bajtów, mogą istnieć pośrednie rutery, kóre nie potrafią obsłużyć początkowej lawiny 64 seg­mentów wysłanych od klienta do serwera (tzn. powolny start nie powinien być pominięty). T/TCP potrafi poradzić sobie z opisanymi problemami, z uwzględ­nieniem następujących dwóch ograniczeń:

1. T/TCP zakłada, że początkowy rozmiar okna wynosi 4096 bajtów. W imple­mentacji N et/3 zmienną określającą, jak dużo danych TCP może wysłać za jednym razem, jest snd_wnd. Początkowy rozmiar okna równy 4096 bajtów ulegnie zmianie, gdy pierwszy segment z informacją o rozmiarze okna zostanie otrzymany od partnera.

2. T/TC P rozpoczyna połączenie w trybie powolnym - (slow start) powolny start tylko wtedy, gdy partner nie znajduje się w sieci lokalnej. Tryb powolny rozpo­częcia połączenia jest stosowany, gdy zmienna snd_cwnd ma wartość jeden, co oznacza jeden segment. Sposób sprawdzenia, czy partner znajduje się w sieci lokalnej przedstawiony został na rysunku 10.14 i opiera się na wykorzystaniu funkcji in_l ocal addr z jądra systemu. Partner jest uważany za partnera lokalnego, gdy: (a) znajduje się w tej samej sieci i podsieci co dany host, (b) znajduje się w innej podsieci tej samej sieci, ale zmienna jądra subnetsarelo- cal maniezerowąwartość.

Zwykle N et/3 rozpoczyna każde połączenie w trybie powolnym (powolny start strona 940 tomu 2), ale to uniemożliwia klientowi biorącemu udział w transakcji wysłanie więcej niż jednego segmentu jako początku transakcji. Wprowadza się więc kompromis polegający na dopuszczeniu wysłania wielu segmentów w przy­padku lokalnego partnera. Całkowity rozmiar danych w tym przypadku nie może przekroczyć 4096 bajtów.

Kiedykolwiek TCP otrzymuje polecenie wysłania danych, rozmiar wysyłanych danych (liczbabajtów) jest określony przez mniejszą z dwóch zmiennych snd_wnd i snd_cwnd. Początkowa wartość pierwszej z tych zmiennych jest równa maksy­

malnej wartości informacji TCP o rozmiarze okna - zakładamy, że wynosi ona 65 535. (W rzeczywistości wartość ta może wynosić 65 535x214, czyli niemal 1 GB, w przypadku gdy używana jest opcja skali okna.) Dla lokalnego partnera począt­kowa wartość snd_wnd wynosi 4096, a początkowa wartość snd_cwnd 65 535. TCP będzie wysyłać początkowo dane w porcjach po maksymalnie 4096 bajtów, aż do momentu, gdy informacja o wielkości okna zostanie otrzymana. Jeżeli partner poinformował, że wielkość okna wynosi 32 768, TCP będzie kontynuować wysyła­

Page 73: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 3.6 Żądanie lub odpowiedź z długością większą niż M SS 51

nie danych aż do wyczerpania tego nowego limitu (32 768 jest mniejszą z dwóch wartości: 65 535 i 32 768). Uniknięto w ten sposób startu w trybie powolnym i długość przesyłanych danych jest ograniczona przez wielkość okna zadeklaro­waną przez partnera.

Natomiast gdy partner nie jest hostem lokalnym, początkowa wartość snd_wnd będzie nadal wynosić 4096, ale początkowa wartość snd_cwnd wyniesie 1, co oznacza jeden segment (zakładamy, że wartość MSS zapamiętana dla tego partne­ra wynosi 512). TCP początkowo wyśle tylko jeden segment, a kiedy partner poinformuje o wielkości okna, wartość snd_cwnd zwiększona zostanie o jeden segment dla każdej otrzymanej flagi ACK. Mamy tu do czynienia z kontrolowa­nym powolnym startem i ilość przesyłanych danych jest ograniczona przez ewen­tualne przeciążenie sieci, chyba że zostanie przekroczony rozmiar okna partnera.

Jako przykład zmodyfikowaliśmy kod klienta i serwera T/TCP z rozdziału 1, tak by wysłane zostało żądanie o długości 3300 bajtów i odpowiedź o długości 3400 bajtów. Nastąpiła wymiana pakietów, którą prezentujemy na rysunku 3.9.

I 0.0 bsdi.1057 > laptop.8888

2 0.001556 (0.0016) b sdi.1057 > laptop.

3 0.002672 (0.0011) bsdi.1057 > laptop.

S 3846892142:3846893590(1448) win 8712 <mss 1460,cc 7>. 3846893591:3846895043(1452)win 8712 <cc 7>FP 3846895043:3846895443(400) win 8712 <cc 7>

4 0.138283 (0.1356) laptop

5 0.139273 (0.0010) bsdi.1057 > laptop.8888:

> bsdi.1057: S 3786170031:3786170031(0) ack 3846895444 win 8712 <mss 1460,cc 6,ccecho 7>

6 0.179615 (0.0403) laptop.8888 > bsdi.1057:

7 0.180558 (0.0009) bsdi.1057 > laptop.

8 0.209621 (0.0291) laptop.8888 > bsdi.1057:

9 0.210565 (0.0009) bsdi.1057 > laptop.

ack 1 win 8712 <cc 7>

. 1:1453(1452)ack 1 win 8712 <cc 6>

ack 1453 win 7260 <cc 7>

. 1453:2905(1452) ack 1 win 8712 <cc 6>

ack 2905 win 7260 <cc 7>

10 0.223822 (0.0133) laptop.8888 > bsdi.1057: FP 2905:3401(496)ack 1 win 8712 <cc 6>

11 0.224719 (0.0009) bsdi.1057 > laptop.8888: .ack 3402 win 8216 <cc 7>

Rysunek 3.9 Żądanie klienta o długości 3300 bajtów i 3400-bajtowa odpowiedź serwera

Przykład pokazuje błąd w programie Tcpdump, polegający na złym drukowaniu względ­nych numerów sekwencyjnych w przypadku wymiany kilku segmentów T/TC P. Po­twierdzenie w liniach 6, 8 i 10 powinno dotyczyć numeru 3302, a nie 1.

Ponieważ klient wie, że serwer potrafi obsłużyć T/TCP, klient może natychmiast wysłać maksymalnie do 4096 bajtów. Segmenty 1, 2 i 3 zostają wysłane w ciągu pierwszych 2.6 ms. Pierwszy segment zawiera flagę SYN, 1448 bajtów danych i 12 bajtów opcji TCP (opcje MSS i CC). Drugi segment nie zawiera żadnych flag, zawiera natomiast 1452 bajty danych i 8 bajtów opcji TCP. Trzeci segment zawiera

Page 74: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

52 T/TCP - przykłady Rozdział 3

flagi FIN i PSH, pozostałe 400 bajtów danych i 8 bajtów opcji TCP. Segment drugi jest szczególny w tym sensie, że nie zawiera żadnej z sześciu flag TCP, w tym flagi ACK. Zwykle flaga ACK jest obecna, z wyjątkiem aktywnego otwarcia wykony­wanego przez klienta, zawierającego flagę SYN. (Klient nigdy nie wysyła ACK zanim nie otrzyma segmentu od serwera.)

Segment 4 zawiera SYN serwera i również potwierdza wszystko, co klient dotych­czas wysłał: SYN, dane i FIN. Klient natychmiast potwierdza otrzymanie od serwera flagi SYN - segment 5.

Segment 6 dociera do klienta 40 ms później i zawiera pierwszą część odpowiedzi serwera. Segment ten jest natychmiast potwierdzony przez klienta. Ten sam scena­riusz zostaje powtórzony dla segmentów 8-11. Ostatni segment wysłany przez serwera (10) zawiera flagę FIN. Na końcu (segment 11) klient potwierdza ostatni fragment danych i flagę FIN.

Możemy zapytać, dlaczego klient natychmiast potwierdza dwa pierwsze z trzech segmentów odpowiedzi serwera, skoro są one odebrane w krótkim odstępie czasu (44 ms)? Odpowiedź jest zawarta w makroinstrukcji TCP_REASS (strona 947, tom 2), wywoływanej dla każdego segmentu danych otrzymanych przez klienta. Po­nieważ połączenie po stronie klienta po przetworzeniu segmentu 4 wchodzi w stan FIN_WAIT_2 , sprawdzenie w TCP_REASS czy połączenie jest w stanie ESTABLISHED daje wynik negatywny, powodując wysłanie natychmiastowego potwierdzenia, zamiast potwierdzenia opóźnionego. Ta właściwość nie jest szcze­gólną cechą T/TCP - tak zachowuje się kod N et/3 zawsze, gdy połączenie TCP zostaje połowicznie zamknięte z jednej strony i wchodzi w stan FIN_WAIT_1 lub FIN_WAIT_2. Od tego momentu każdy segment z danymi otrzymany od partnera jest natychmiast potwierdzany. Sprawdzenie, czy połączenie jest w stanie ESTAB­LISHED w makroinstrukcji TCP_REASS zapobiega przekazaniu danych do aplika­cji zanim potrójne uzgodnienie jest zakończone. Nie ma potrzeby natychmiasto­wego potwierdzania danych otrzymywanych sekwencyjnie, jeśli połączenie jest w stanie następującym po stanie ESTABLISHED (tzn. odpowiedni fragment TCP_REASS powinien zostać zmieniony).

Opcja gniazda TCP_NOPUSHJeszcze jedna zmiana w kodzie źródłowym klienta była niezbędna, by przeprowa­dzić opisany wyżej przykład. Opcja gniazda TCP_NOPUSH (nowa opcja wprowa­dzona z T/TCP) została włączona w następujący sposób:

i nt n ;

n = 1:if (setsockopt(sockfd, IPPR0T0_TCP, TCP_NOPUSH, (char *) & n , sizeof(n)) < 0)

err_sys("TCP_N0PUSH error");

Przedstawione linie kodu zostały dodane po odwołaniu do funkcji socket na rysunku 1.10. Opcja ta ma za zadanie poinformować TCP, że segment nie powi­nien być wysłany, jeżeli jedynym powodem wysłania segmentu jest opróżnienie buforu wysyłania.

Page 75: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 3.6 Żądanie lub odpowiedź z długością większą niż M SS 53

Żeby zrozumieć potrzebę uruchomienia tej opcji gniazd, musimy prześledzić kro­ki wykonywane przez jądro, po tym jak proces woła sendto z flagą MSG_E0Fw celu wysłania 3300-bajtowego żądania.

1. Funkcja jądra sosend (rozdział 16.7, tom 2) jest wywołana, by obsłużyć żąda­nie wysyłki. Funkcja ta umieszcza pierwsze 2048 bajtów w klastrze mbuf i wysyła żądanie P RU_S E ND do protokołu (TCP).

2. Funkcja tcp_output jest wywołana i - ponieważ może zostać wysłany seg­ment o pełnej wielkości - pierwszych 1448 bajtów znajdujących się w klastrze zostaje wysłanych wraz z flagą SYN. (W segmencie tym 12 bajtów zajętych jest przez opcje TCP.)

3. Ponieważ 600 bajtów wciąż pozostaje w klastrze mbuf, tcp_o utp ut jest woła­na jeszcze raz. Mogłoby się wydawać, że algorytm Nagle uniemożliwi wysła­nie następnego segmentu, ale zauważmy (strona 886 tomu 2), że przy pierw­szym wywołaniu tcp_output zmienna i dl e była równa 1. Zmienna ta nie zostaje obliczona ponownie po tym, jak wykonany jest skok do aga i n po wysłaniu 1448-bajtowego segmentu. Dlatego program ostatecznie przechodzi do fragmentu pokazanego na rysunku 9.3 (unikanie wysyłania głupich seg­mentów - sender silly window avoidance). Wartość i d 1 e jest 1 (czyli „prawda"), a wysłanie segmentu opróżniłoby wysyłkowy bufor gniazda, więc tym co de­cyduje o wysłaniu segmentu lub nie, jest aktualna wartość flagi TF_N0PUSH.

Przed wprowadzeniem tej flagi wraz z T/TCP, niepełny segment zostałby zawsze wysłany, jeśli tylko wysłanie nie byłoby zablokowane przez algorytm Nagle i jeśli segment ten opróżniłby bufor wysyłkowy gniazda. Jeżeli jednak aplikacja ustawi flagę TF_N0PUSH (przy pomocy nowej opcji gniazda TCP_NOPUSH), to TCP nie wyśle danych z bufora wysyłkowego tylko po to, by opróżnić bufor. TCP pozwoli, by dane istniejące w buforze zostały połączone z danymi wprowadzony­mi przy pomocy późniejszych operacji, tak by móc wysłać większy segment.

4. Jeśli flaga T F_N 0 P U S H jest ustawiona przez aplikację, segment nie zostaje wysła­ny, a tcp_output zwraca kontrolę do sosend.

5. Jeśli flaga TF_N0PUSH nie jest ustawiona przez aplikaq'ę, 600-bajtowy segment zostaje wysłany i ustawiona jest flaga PSH.

6. Funkcja sosend wprowadza pozostałe 1252 bajty do klastra mbuf i generuje żądanie P RU_S E N D_E0 F (rysunek 5.2), które znowu doprowadza do wywołania tcp_output. Jednak przed tym wywołaniem tcp_output zostaje wywołana funkcja t c p_u s r c 1 o s e d (rysunek 12.4), co powoduje zmianę stanu połączenia z SYN_SENTnaSYN_SENP (rysunek 12.5). Przy ustawionej fladze TF_N0PUSH 1852 bajty danych znajdują się w buforze wysyłkowym gniazda i - jak widzimy na rysunku 3.9 - kolejny segment o normalnej (pełnej) wielkości, zawierający 1452 bajty danych i 8 bajtów opcji TCP, zostaje wysłany. Segment ten zostaje wysłany, ponieważ jest to segment o normalnej długości (tzn. algorytm Nagle nie daje żadnego efektu). Mimo że wśród flag wysyłanych w stanie SYN_SENT* znajduje się flaga FIN (rysunek 2.7), flaga FIN jest wyłączona

Page 76: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

54 T/TCP - przykłady Rozdział 3

(strona 889, tom 2), ponieważ w dalszym ciągu dane znajdują się w buforze wysyłkowym.

7. Funkq'a tcp_output jest wykonywana kolejny raz w celu wysłania 400 bajtów pozostających w buforze wysyłkowym. Tym razem flaga FIN zostaje ustawio­na, ponieważ bufor wysyłkowy jest opróżniany. Mimo że algorytm Nagle zapobiega wysłaniu segmentu o niepełnej długości, 400-bajtowy segment zo­staje wysłany, bowiem ustawiona jest flaga FIN (strona 895, tom 2).

W przedstawionym przykładzie 3300-bajtowe żądanie w sieci Ethernet - z warto­ścią MSS równą 1460, przy ustawionej opcji gniazda - powoduje wysłanie trzech segmentów zawierających 1448,1452 i 400 bajtów. W przypadku gdy opcja nie jest ustawiona, wysłane są również trzy segmenty liczące 1448, 600 i 1252 bajty. Dla 3600-bajtowego żądania, w przypadku z opcją, zostaną wysłane trzy segmenty (1448,1452 i 700 bajtów). Bez opcji wysłane będą cztery segmenty (1448, 600,1452 i 100 bajtów).

Podsumowując, jeżeli klient wysyła żądanie przy pomocy pojedynczego sendto. powinien zwykle ustawić opcję gniazda TCP_NOPUSH by spowodować wysyłanie segmentów o normalnej, pełnej długości, jeżeli długość żądania przekracza limit określony przez MSS. W ten sposób może być zredukowana liczba wysyłanych segmentów, w zależności od rozmiaru wysyłanych danych.

3.7 Kompatybilność wsteczMusimy się również zastanowić, co się zdarzy, gdy klient T/TCP wyśle dane do hosta, który nie zna T/TCP.

Na rysunku 3.10 przedstawiamy wymianę pakietów - transakcję - pomiędzy klientem T/TCP (bsdi), a serwerem svr4. Host svr4 działa pod systemem System V Release 4, który nie obsługuje T/TCP.

2 0.0 bsdi.1031 > svr4.8888: SFP 2672114321:2672114621 (300)win 8568 <mss 1460,ccnew 10>

2 0.006265 (0.0063) svr4.8888 > bsdi.1031: S 879930881:879930881(0)ack 2672114322 win 4096 <mss 1024>

3 0.007108 (0.0008) bsdi .1031 > svr4.8888: F 301:301(0)ack 1 win 9216

4 0.012279 (0.0052) svr4.8888 > bsdi.1031: .ack 302 win 3796

5 0.071683 (0.0594) svr4.8888 > bsdi.1031: P 1:401(400)ack 302 win 4096

6 0.072451 (0.0008) bsdi.1031 > svr4.8888: .ack 401 win 8816

7 0.078373 (0.0059) svr4.8888 > bsdi.1031: F 401:401(0)ack 302 win 4096

8 0.079642 (0.0013) bsdi.1031 > svr4.8888: .ack 402 win 9216

Rysunek 3.10 Transakcja klienta T/TCP z serwerem TCP

Page 77: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 3.7 Kompatybilność wstecz 55

Klient jak zwykle wysyła pierwszy segment zawierający SYN, FIN i flagi PSH, wraz z 300 bajtami danych. Wysyłana jest opcja CCnew, ponieważ klient nie ma zachowanej wartości numeru połączenia dla tego serwera. Serwer odpowiada wysyłając normalny, drugi segment potrójnego uzgodnienia (linia 2), który to segment klient potwierdza w linii 3. Zauważmy, że dane są retransmitowane w linii 3.

Kiedy serwer otrzymuje segment z linii 3, natychmiast wysyła potwierdzenie 300 bajtów danych i flagi FIN. (Potwierdzenie flagi FIN nigdy nie jest opóźnione, jak to pokazano na stronie 1033 tomu 2.) TCP serwera umieściło dane w kolejce aż do czasu, gdy potrójne uzgodnienie zostanie zakończone.

Linia 5 jest odpowiedzią serwera (400 bajtów danych), którą klient natychmiast potwierdza w linii 6. Linia 7 zawiera flagę FIN serwera, którą klient znów natych­miast potwierdza. Zauważmy, że proces serwera nie ma żadnej możliwości połą­czenia danych z linii 5 z flagą FIN z linii 7.

Jeśli zainicjujemy kolejną transakcję pomiędzy tym samym klientem i serwerem, sekwencja przesyłanych segmentów będzie taka sama. Pierwszy segment wysłany przez klienta zawiera opcję CCnew z wartością 11, ponieważ klient nie może wysłać opcji CC do tego hosta, jako że serwer nie przesłał opcji CCecho (rysunek 3.10). Klient T/TCP zawsze wysyła opcję CCnew, wpis w pamięci TAO dla serwera nie znającego T/TCP nigdy bowiem nie jest uaktualniany - wartość tao_ccsent pozostaje zawsze 0 (niezdefiniowana).

W następnym przykładzie (rysunek 3.11) klient rozpoczyna transakcję z serwerem działającym pod systemem Solaris 2.4, który to system - choć oparty na SVR4 (tak jak serwer na rysunku 3.10) - ma zupełnie inną implementacje TCP/IP.

1 0.0 bsdi.1033 > sun.8880: SFP 2693814107:2693814407(300)win 8712 <mss 1460,ccnew 12>

2 0.002808 (0.0028) sun.8888 > bsdi.1033: S 3179040768:3179040768(0)ack 2693814108 win 8760 <mss 1460> (DF)

3 0.003679 (0.0009) bsdi.1033 > sun.8888: F 301:301(0)ack 1 win 8760

4 1.287379 (1.2837) bsdi.1033 > sun.8888: FP 1:301(300)ack 1 win 8760

5 1.289048 (0.0017) sun.8888 > bsdi.1033: .ack 302 win 8760 (DF)

6 1.291323 (0.0023) sun.8888 > bsdi.1033: P 1:401(400)ack 302 win 8760 (DF)

7 1.292101 (0.0008) bsdi.1033 > sun.8888: .ack 401 win 8360

8 1.292367 (0.0003) sun.8888 > bsdi.1033: F 401:401(0)ack 302 win 8760 (DF)

9 1.293151 (0.0008) bsdi.1033 > sun.8888: .ack 402 win 8360

Rysunek 3.11 Transakcja klienta T/TCP z serwerem TCP działającym w systemie Solaris 2.4

Page 78: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

56 T/TCP - przykłady Rozdział 3

Linie 1, 2 i 3 są takie same jak na rysunku 3.10: flagi SYN, FIN, PSH i 300-bajtowe żądanie klienta, następnie flagi SYN/ACK serwera, po których następuje flaga ACK wysłana przez klienta. Jest to zwykłe potrójne uzgodnienie. Tak jak wcześ­niej, klient wysyła opcję CCnew, ponieważ nie ma zachowanej wartości CC dla tego serwera.

Obecność flagi „nie dzielić na fragmenty" (DF - don't fragment) w każdym segmencie pochodzącym od hosta Solaris jest związana z wyznaczeniem MTU ścieżki (path disccruery, RFC 1191 [Mogul i Deering 1990]).

Niestety, w tym momencie natykamy się na błąd w implementacji systemu Solaris. Okazuje się, że TCP serwera ignoruje dane, które były wysłane w linii 1 (dane nie są potwierdzone w segmencie 2), co powoduje, że upływa czas oczekiwania klien­ta na potwierdzenie i klient ponownie wysyła dane w linii 4. Flaga FIN również wysłana jest ponownie. Serwer następnie potwierdza dane oraz FIN (linia 5) i serwer wysyła odpowiedź (linia 6). Klient potwierdza odpowiedź (linia 7), ser­wer wysyła flagę FIN (linia 8), którą klient ostatecznie potwierdza (linia 9).

Na stronie 30 opracowania RFC 793 [Postel 1981b] znajduje się stwierdzenie: „Choć w przedstawionych przykładach synchronizacja połączenia nie jest dokonywana za po­średnictwem segmentów przenoszących również dane, taki przypadek byłby całkowicie dopuszczalny, jeśli tylko odbierający protokół TCP nie dostarcza danych do procesu użytkownika zanim nie zostanie ustalone, że dane są poprawne (tzn. dane muszą być buforowane przez odbierający TCP aż do chwili, gdy połączenie znajdzie się w stanie ESTABLISHED)." Na stronie 66 tego samego dokumentu mówi się, że w czasie przetwa­rzania otrzymanej flagi SYN w stanie LISTEN „dowolne elementy kontrolne lub tekstowe powinny być umieszczane w kolejce w oczekiwaniu na późniejsze przetworzenie."Pewien recenzent utrzymuje, że nazwanie tego błędem jest niewłaściwe, ponieważ doku­menty RFC nie imjmagają, by serwer akceptował dane, które przychodzą wraz z flagą SYN. Niektórzy utrzymują również, że implementacja systemu Solaris zachowuje się popraw­nie, ponieważ serwer nie poinformował jeszcze klienta o rozmiarze okna i serwer może odrzucić dane, wykraczają one bowiem poza okno. Bez względu na to, jak zdecydujemy się nazywać opisaną właściwość (autor określa ją jako błąd Solaris, a Sun przypisał jej identyfikator błędu 1222490, tak więc powinna ona być usunięta w przyszłych wersjach), przetwarzanie w sytuacjach jak ta opisana powyżej wiąże się z Zasadą Odporności (Robu- stness Principle), pierwszy raz wymienioną w RFC 791 [Postel 1981a]: „Bądi liberalny w stosunku do tego, co akceptujesz, i zachowawczy w stosunku do tego, co wysyłasz."

3.8 PodsumowaniePrzykłady z obecnego rozdziału możemy podsumować następującymi stwierdze­niami:

1. Jeśli klient straci informacje o stanie serwera (np. klient zostaje przeładowany), wymusza potrójne uzgodnienie wysyłając opcję CCnew w ramach swojego aktywnego otwarcia.

2. Jeśli serwer straci informacje o stanie klienta, lub jeśli otrzyma segment SYN z wartością CC mniejszą od oczekiwanej wartości, wymusza potrójne uzgod­nienie wysyłając jedynie SYN/ACK w odpowiedzi na SYN klienta. W tym

Page 79: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 3.8 Podsumowanie 57

przypadku TCP serwera musi zaczekać z przekazaniem otrzymanych danych do procesu serwera, aż zakończone zostanie potrójne uzgodnienie.

3. Serwer - jeśli chce używać T/TCP w danym połączeniu - zawsze w odpowie­dzi na opcje CC lub CCnew wysyła opcje CCecho.

4. Jeśli klient i serwer posiadają informacje o stanie partnera, przeprowadzana jest minimalna transakcja T/TCP składająca się z trzech segmentów (zakładając, że zarówno żądanie, jak i odpowiedź są mniejsze niż MSS). Jest to najmniejsza możliwa liczba pakietów i transakcja taka charakteryzuje się najmniejszym możliwym czasem oczekiwania (RTT + SPT).

W przykładach pokazaliśmy również wielokrotne zmiany stanu zachodzące w transakcjach z T/TCP i pokazaliśmy zastosowanie nowych, rozszerzonych (z gwiazdką) stanów połączenia.

Jeśli klient wysyła segment zawierający SYN, dane i FIN do hosta, który nie rozumie T/TCP, systemy oparte na kodzie sieciowym systemu Berkeley (wśród nich SVR4, lecz nie Solaris) poprawnie umieszczają dane w kolejce, czekając na zakończenie potrójnego uzgodnienia. Możliwe jest jednak, że inne implementacje niepoprawnie zignorują dane otrzymane wraz z SYN, powodując - po upływie czasu oczekiwania na potwierdzenie - ponowne wysłanie danych przez klienta.

Page 80: Biblia TCP IP Tom 3 - Uzupelnienie.pdf
Page 81: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Protokół T/TCP - kontynuacja4

4.1 WstępW tym rozdziale kontynuujemy nasze rozważania na temat protokołu T/TCP. Rozpoczynamy od omówienia, w jaki sposób aplikacje typu klient powinny usta­lać numer portu dla swojego końca połączenia, w zależności od przewidywanego czasu połączenia (połączenie dłuższe lub krótsze od MSL), i pokazujemy jak to wpływa na stan TIME_WAIT protokołu TCP. Następnie zastanowimy się, dlacze­go TCP definiuje stan TIME_WAIT, ponieważ ta właściwość protokołu często nie jest poprawnie rozumiana. Jedną z zalet T/TCP jest możliwość skrócenia stanu TIME_WAIT z 240 sekund do mniej więcej 12 sekund, jeśli połączenie trwa krócej niż wartość MSL. Przedstawiamy, w jaki sposób to skrócenie jest realizowane i dlaczego mechanizm ten może działać poprawnie.

Naszą dyskusję o protokole T/TCP uzupełnimy przedstawieniem mechanizmu TAO (TCP accelerated open - przyspieszone otwarcie TCP), który umożliwia syste­mom klient-serwer uniknięcie potrójnego uzgodnienia i w ten sposób przy nawią­zywaniu połączenia zaoszczędza czas odpowiadający przesłaniu pakietu w obie strony, co jest największą zaletą T/TCP.

4.2 Numery portów i stan TIME.WAITPrzy pisaniu programów typu klient TCP nie ma zwykle potrzeby poświęcania uwagi numerom portów. Większość klientów TCP (Telnet, FTP, WWW, itd.) uży­wa efemerycznego numeru portu, pozwalając modułowi TCP hosta wybrać aktu­alnie nieużywany port. Systemy wywodzące się z systemu Berkeley zwykle w y­bierają efemeryczny numer portu z zakresu od 1024 do 5000 (rysunek 14.4), Solaris wybiera natomiast port o numerze od 32 768 do 65 535. W przypadku klienta T/TCP wybór numeru portu jest bardziej skomplikowany i zależy od częstotliwo­ści wymieniania pakietów i czasu trwania połączenia.

Zwykłe hosty TCP, zwykły klient TCPRysunek 4.1 przedstawia klienta TCP (takiego jak na przykład z rysunku 1.5) wykonującego w odstępach jednosekundowych trzy jednosekundowe transakcje z tym samym serwerem. Trzy połączenia rozpoczynają się odpowiednio w czasie0, 2 i 4 oraz kończą się w czasie 1, 3 i 5. Na osi x odłożony jest czas w sekundach, a trzy połączenia oznaczono pogrubionymi liniami.

Page 82: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

60 Protokół T/TCP - kontynuacja Rozdział 4

Do każdej transakcji użyte jest inne połączenie TCP. Zakładamy, że klient nie wiąże jawnie lokalnego portu z gniazdem, pozwalając modułowi TCP wybrać port efemeryczny, oraz że wartość MSL protokołu TCP klienta wynosi 120 sekund. Pierwsze połączenie pozostaje w stanie TIME_WAIT aż do 241 sekundy, drugie połączenie od 3 do 243 sekundy, trzecie od 5 do 245 sekundy.

Używamy symbolu CB (control błock) na oznaczenie kombinacji bloków kon­trolnych protokołu TCP używanych, gdy połączenie jest aktywne lub w stanie TIME_WAIT. Są to: internetowy blok PCB, blok kontrolny TCP i wzorzec nagłów­ka. Zaznaczyliśmy na początku rozdziału 2, że całkowity rozmiar tych trzech bloków wynosi 264 bajty w implementacji N et/3. TCP musi periodycznie prze­twarzać wszystkie bloki kontrolne (w przykładach przedstawionych w rozdzia­łach 25.4 i 25.5 tomu 2 wszystkie bloki kontrolne TCP były przetwarzane odpowiednio co 200 i 500 ms), co może być istotnym obciążeniem CPU.

Implementacja N et/3 przechowuje kopie nagłówków TCP i IP dla każdego połączenia jako tzw. wzorzec nagłówka (header template, rozdział 26.8 w tomie 2). Wzorzec zawiera wszystkie pola, które pozostają niezmienione dla danego połączenia. Przyspiesza to tworzenie wysyłanego pakietu, ponieważ program po prostu kopiuje wzorzec nagłówka, zamiast wypełniać kolejno poszczególne pola.

W przypadku użycia normalnego TCP nie ma sposobu uniknięcia sytuacji, w któ­rej połączenie pozostaje przez długi czas w stanie TTME_WAIT. Klient nie może więc użyć tego samego portu dla wszystkich trzech połączeń, nawet w przypadku wykorzystania opcji gniazda SO_REUSEADDR. (Na stronie 766 w tomie 2 pokazuje­my przykład, w którym klient usiłuje użyć tego samego portu.)

Hosty T/TCP, różne porty klienta dla każdej transakcjiNa rysunku 4.2 prezentujemy taką samą sekwencję trzech transakcji, ale teraz oba hosty używają T/TCP. Klient TCP jest ten sam co na rysunku 4.1. Zwracamy uwagę na istotne rozróżnienie: aplikaq'e klienta i serwera nie muszą wykorzysty­wać T/TCP, wymagamy jedynie, by hosty znały TCP (tzn. znały opcje CC).

Page 83: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 4.2 Numery portów i stan TIME_ WAIT 61

Rysunek 4.2 Klient TCP, gdy klinet i serwer znają T/TCP

Różnica pomiędzy rysunkami 4.2 i 4.1 polega na tym, że czas trwania stanu nM E_W AIT zmniejszył się, ponieważ oba hosty potrafią wykorzystać opcje CC. Zakładamy, że czas oczekiwania, po którym następuje retransmisja pakietu wyno­si 1,5 sekundy (wartość typowa dla N et/3 w sieci lokalnej [Brakmo i Peterson 1994]), i że wartość mnożnika T/TCP dla stanu TIME_WAIT wynosi 8, co daje skrócenie czasu TIME_WAIT z 240 do 12 sekund.

Protokół T/TCP umożliwia skrócenie stanu TIME_WAIT, jeśli oba hosty potrafią wykorzystać opcje CC i jeśli czas trwania połączenia jest krótszy niż MSL (120 sekund). Może tak być, ponieważ opcja CC daje dodatkowe zabezpieczenie przed dostarczeniem duplikatów starych segmentów do innego wcielenia danego połą­czenia, co pokażemy w rozdziale 4.4.

Hosty T/TCP, ten sam port klienta dla każdej transakcjiRysunek 4.3 pokazuje tę samą co na rysunku 4.2 sekwencję trzech transakcji, ale tym razem zakładamy, że klient za każdym razem używa tego samego portu. Aby to osiągnąć, klient musi użyć opcji gniazda SO_REUSEADDR i następnie związać się z konkretnym portem lokalnym, wywołując bind przed wywołaniem connect (w przypadku zwykłego klienta TCP) lub sendto (w przypadku klienta T/TCP). Podobnie jak dla rysunku 4.2 zakładamy, że oba hosty potrafią używać T/TCP.

Rysunek 4.3 Klient TCP ponownie wykorzystuje ten sam port; klient i serwer znają T/TCP

W momencie gdy połączenie ma być utworzone w sekundach 2 i 4, TCP znajduje blok kontrolny z tą samą parą gniazd w stanie TIME_WAIT. Ponieważ poprzednie wcielenie tego połączenia używało opcji CC i czas trwania połączenia był krótszy

Page 84: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

62 Protokół T/TCP - kontynuacja Rozdział 4

niż MSL, stan TIME_WAIT zostaje skrócony, blok kontrolny istniejącego połącze­nia skasowany i utworzony jest blok kontrolny nowego połączenia. (Ten sam blok kontrolny może być użyty dla nowego połączenia - czy tak się zdarzy, zależy jednak od implementacji. Istotne jest, że całkowita liczba używanych bloków kontrolnych nie zwiększa się.) Zauważmy też, że po zamknięciu trzeciego połą­czenia stan TIME_WAIT będzie trwał tylko przez 12 sekund, tak jak to pokazali­śmy na rysunku 4.2.

Podsumowując, pokazaliśmy w tym podrozdziale, że możliwe są dwa sposoby optymalizacji działania klientów uczestniczących w transakcjach:

1. Bez jakichkolwiek zmian w kodzie źródłowym, uwzględniając jedynie, że oba uczestniczące hosty znają protokół T/TCP, otrzymuje się skrócenie czasu trwa­nia stanu TIME_WAIT z 240 sekund do wartości równej czasowi retransmisji pomnożonemu przez 8.

2. Wprowadzając zmianę w kodzie klienta, tak że używa on tego samego portu dla kolejnych połączeń, otrzymujemy nie tylko skrócenie stanu TIME_WAIT do wartości odpowiadającej czasowi retransmisji pomnożonemu przez 8, ale stan TIME_WAIT przerywany jest jeszcze szybciej - w momencie, gdy utwo­rzone jest nowe wcielenie tego samego połączenia.

4.3 Rola stanu TIME_WAITStan TTME_WAIT protokołu TCP to element, którego rola bywa bardzo często źle rozumiana. Być może przyczyną takiego stanu rzeczy jest oryginalna specyfikacja zawarta w RFC 793, w której stan ten został opisany bardzo lapidarnie. Późniejsze źródła, jak na przykład RFC 1185, omawiają to zagadnienie bardziej szczegółowo. Stan TTME_WAIT spełnia dwie funkcje:

• pozwala przeprowadzić pełne dwustronne zamknięcie połączenia

• umożliwia odczekanie do czasu, po którym stare zduplikowane segmenty przestają istnieć.

Przyjrzyjmy się bardziej szczegółowo każdej z tych dwóch funkcji.

Dwustronne zamknięcie połączenia TCPNa rysunku 4.4 pokazana jest typowa wymiana segmentów przeprowadzana w momencie, gdy połączenie jest zamykane. Pokazujemy również zmiany stanów połączenia i wartość RTT zmierzoną dla serwera.

Lewa strona diagramu odnosi się do klienta, prawa do serwera, ale należy zauwa­żyć, że aktywne zamknięcie może wykonywać zarówno klient, jak i serwer. Naj­częściej jednak robi to klient.

Rozważmy też co się stanie, jeżeli ostatni segment zostanie zgubiony. Pokazujemy to na rysunku 4.5.

Page 85: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 4.3 Rola stanu TIME_WAIT 63

kli<

(aktywne zamknięcie) FIN_WAIT_1

FIN_WAIT_2

TIME_WAIT

;nt ser

ack ____________

-----------—— ____________________

wer

CLOSE_WAIT (pasywne zamknięcie)

LAST_ACK ^

> RTT

CLOSED '

Rysunek 4.4 Zwykła wymiana segmentów przy zamknięciu połączenia

kil

(aktywne zamknięcie) FIN_WAIT_1

FIN_WAIT_2

TIME_WAIT

TIME_WAIT (rozpoczęty powtórnie)

ant ser

' -—

___ acK M+1___ ____ — -

------------

wer

CLOSE_WAIT (pasywne zamknięcie)

LAST_ACK -x

> RTO

J

CLOSED

Rysunek 4.5 Zamknięcie TCP, gdy ostatni segment zostaje zagubiony

Ponieważ potwierdzenie nigdy nie dociera do serwera, po upływie czasu oczeki­wania serwer prześle ponownie ostatni segment FIN. Z premedytacją zaznaczyli­śmy tu, że RTO (retransmission timeout - czas oczekiwania przed powtórzeniem transmisji) jest większy niż RTT z rysunku 4.4, ponieważ wartość RTO równa się oszacowanej wartości RTT plus pewna wielokrotność wariancji RTT. (W rozdziale 25 tomu 2 omówiliśmy szczegółowo pomiar RTT i sposób obliczania RTO.) Scena­riusz jest taki sam, jeśli ostatni segment FIN zaginie - serwer po upływie czasu oczekiwania przesyła ponownie segment FIN.

Zaprezentowany przykład wyjaśnia, dlaczego stan TIME_WAIT pojawia się po tej stronie połączenia, po której wykonywane jest aktywne zamknięcie: host wykonu­jący aktywne zamknięcie wysyła ostatnie potwierdzenie i - jeśli to potwierdzenie

Page 86: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

64 Protokół T/TCP - kontynuacja Rozdział 4

zostało zagubione, lub jeśli zaginął ostatni segment FIN - host znajdujący się po przeciwnej stronie połączenia, po upływie czasu oczekiwania, retransmituje ostat­ni segment FIN. Ponieważ informacja o stanie połączenia jest wciąż zachowana po stronie wykonującej aktywne zamknięcie, możliwe jest ponowne przesłanie osta­tecznego ACK. Jeśli moduł TCP nie przechowywałby informaqi o stanie połącze­nia, nie byłoby możliwe wysłanie ostatecznego segmentu ACK, konieczne byłoby natomiast wysłanie segmentu RST w odpowiedzi na retransmitowany FIN, w wy­niku czego pojawiłyby się niepotrzebne komunikaty o błędzie.

Na rysunku 4.5 zaznaczamy również, że jeżeli retransmitowany segment FIN dociera do hosta w stanie TIME_WAIT, to nie tylko wysłany jest ostatni segment, ale również rozpoczęty jest ponownie stan TIME_WAIT. Oznacza to, że czas oczekiwania w stanie TIME_WAIT zostaje od nowa ustawiony na 2MSL.

Możemy postawić pytanie, jak długo host wykonujący aktywne zamknięcie powi­nien pozostawać w stanie TIME_WAIT, by scenariusz przedstawiony na rysunku 4.5 był możliwy? Zależy to od wartości RTO po przeciwnej stronie połączenia, a ta z kolei zależy od RTT. W RFC 1185 zaznacza się, że RTT większe niż 1 minuta jest bardzo mało prawdopodobne. Natomiast możliwa jest wartość RTO bliska jednej minuty. Może się to zdarzyć w sytuacjach przeciążenia w sieciach typu WAN, gdy wielokrotnie retransmitowane segmenty są gubione i algorytm postępowania w sytuacjach awaryjnych protokołu TCP wykładniczo ustawia (exponential bcickoff) coraz większe i większe wartości RTO.

Utrata ważności przez stare, zduplikowane segmentyDrugim powodem istnienia stanu TIME_WAIT jest stworzenie sytuacji, w której stare zduplikowane segmenty mogą utracić ważność. Podstawowym założeniem w działaniu TCP jest, że każdy datagram IP ma ograniczony czas istnienia w Inter­necie. Ten czas jest podany w polu TTL (time-to-live - czas życia) nagłówka IP. Każdy ruter przekazujący datagram IP musi zmniejszyć wartość TTL o jeden, lubo liczbę sekund odpowiadającą czasowi, przez który ruter przetrzymuje data­gram. W praktyce rzadko się zdarza, by ruter przetrzymywał pakiet dłużej niż przez sekundę, wartość TTL jest więc zwykle zmniejszana o jeden przez każdy ruter (rozdział5.3.1 opracowania RFC 1812 [Baker 1995]). Ponieważ TTL zajmuje 8 bitów w nagłówku, maksymalna liczba hopów dla dowolnego datagramu wynosi 255.

W RFC 793 definiuje się maksymalny czas życia segmentu (MSL - maximum segment lifełime) i określa się jego wartość na 2 minuty. Stwierdza się również, że wybór wartości MSL podyktowany jest względami praktycznymi i wartość ta może być zmieniona pod wpływem doświadczenia oraz że czas trwania stanu TIME_WAIT jest równy podwojonej wartości MSL.

Na rysunku 4.6 pokazaliśmy połączenie, które zostaje zamknięte, czeka w stanie TIME_WAIT przez okres 2MSL, a następnie inicjowane jest nowe wcielenie połą­czenia.

Page 87: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 4.4 Skrócenie stanu TIME_WAIT 65

Rysunek 4.6 Nowe wcielenie połączenia jest inicjowane po czasie 2MSL od poprzedniego wcielenia

Ponieważ nowe wcielenie połączenia nie może być zainicjowane wcześniej niż po czasie 2 MSL od zamknięcia poprzedniego wcielenia i ponieważ ewentualne du­plikaty starych segmentów z pierwszego wcielenia znikną w ciągu pierwszego MSL trwania stanu TIME_WAIT, mamy pewność, że stare duplikaty nie zostaną błędnie uznane za należące do drugiego wcielenia.

Zabicie stanu TIME_WAITW RFC 793 stwierdza się, że segment RST otrzymany w stanie TIME_WAIT zmienia stan połączenia na CLOSED. Używa się tu określenia zabicie (assassina- tion) stanu TIME_WAIT. W RFC 1337 [Braden 1992a] zaleca się, by nie dopuszczać do sytuacji, w której RST przedwcześnie kończy stan TIME_WAIT.

4.4 Skrócenie stanu TIME_WAITWidzieliśmy na rysunkach 4.2 i 4.3, że T/TCP może skrócić stan TIME_WAIT. Jeśli używany jest protokół T/TCP, czas trwania stanu TIME_WAIT może ulec skróce­niu do wartości równej wartości RTO (retransmission timeout) pomnożonej przez 8, zamiast 2MSL. W rozdziale 4.3 wymieniliśmy również dwie funkcje pełnione przez stan TIME_WAIT, usprawiedliwiające jego istnienie. Jak wpływa skrócenie TIME_WAIT na te funkcje?

Page 88: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

66 Protokół T/TCP - kontynuacja Rozdział 4

Dwustronne zamknięcie połączenia TCPPierwszą przyczyną istnienia stanu TIME_WAIT jest przechowanie informacjio stanie połączenia, po to by możliwe było przetworzenie retransmitowanego segmentu FIN. Jak widać na rysunku 4.5, czas trwania stanu TIME_WAIT powi­nien rzeczywiście zależeć od RTO, a nie od MSL. Czynnik 8 używany przez T/TCP pozwala hostowi na drugim końcu połączenia odczekać odpowiednio długo na potwierdzenie wysłania FIN i - przy braku takiego potwierdzenia - wysłać segment FIN ponownie. W ten sposób powstaje scenariusz przedstawiony na rysunku 4.2, w którym każde kończone połączenie pozostaje w stanie TI- ME_WAIT krócej niż to miałoby miejsce w TCP (12 sekund na rysunku 4.2).

Zastanówmy się, co się dzieje w przypadku przedstawionym na rysunku 4.3, gdy klient używa ponownie tej samej pary gniazd i skrócenie stanu TIME_WAIT następuje wcześniej niż po czasie równym 8 razy RTO. Odpowiedni przykład został przedstawiony na rysunku 4.7.

klient

dane i EOF dla klienta, początek TIME_WAIT

nawa aktywne otwarcie, skrócenie TIME_WAIT

(ignorowany)

serwer

CC,®

cvu

cd's.......

c \N,

FIH:cc=a

HTO

- niejawne ACK wcześniejszego wcielenia, zamknięcie starego wcielenia, otwarcie nowego wcielenia, przekazanie danych do procesu serwera

R ysunek 4 .7 Skrócenie TIME_WAIT, gdy ostatni segment ACK został zagubiony

Ostatnie potwierdzenie jest zgubione, ale klient inicjuje nowe wcielenie tego same­go połączenia zanim druga (retransmitowana) kopia ostatniego segmentu wysła­nego przez serwera zostanie odebrana. Kiedy serwer otrzymuje nowy segment SYN, ponieważ test TAO daje wynik pozytywny (8 jest większe niż 6), potwier­dzony zostaje również niejawnie zaległy segment wysłany wcześniej przez serwe­ra (drugi segment na rysunku). Stare połączenie zostaje zamknięte, a nowe zaini­cjowane. Ponieważ test TAO daje wynik pozytywny, dane zawarte w nowym segmencie SYN zostają przekazane do procesu serwera.

Page 89: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 4.4 Skrócenie stanu TIME_WAIT 67

Warto zauważyć, że skoro T /T C P definiuje czas trwania stanu TIME_WAIT w zależności od RTO po stronie wykonującej aktywne zamknięcie, istnieje niejawne założenie, że wartości RTO po obu stronach połączenia są „podobne" i zawierają się w pewnych granicach [ Olah 1995]. Jeśli host wykonujący aktywne zamknięcie kończy stan TIME_WAIT zanim partner z drugiego końca połączenia wyśle ponownie ostatni segment FIN, odpo­wiedzią na ostatni FIN będzie RST, a nie spodziewane retransmitowane potwierdzenie.Może się to zdarzyć, jeśli wartość RTT jest mała, trzeci segment (ACK) minimalnej trzysegmentowej wymiany T /T C P został zgubiony, a klient i serwer mają różne częstot­liwości zegarów programowych i różne minimalne wartości RTO. (W rozdziale 14.7 pokazane są rozmaite, dziwaczne wartości RTO używane niekiedy przez systemy pełnią­ce rolę klienta.) Klient może zmierzyć RTT o małej wartości, podczas gdy serwer nie może zmierzyć RTT w ogóle (ponieważ trzeci segment został zgubiony). Dla przykładu załóż­my, że klient mierzy RTT i otrzymuje wartość 10 ms, przy minimalnej wartości RTT dla tego hosta równej 100 ms. Klient zakończy stan TIME_WAIT 800 ms po otrzymaniu odpowiedzi serwera. Jeżeli natomiast kod serwera wywodzi się z systemu Berkeley, domyślna wartość RTO będzie równa 6 sekund (tak jak pokazano na rysunku 14.13). Serwer ponownie wyśle segment zawierający SY N /A C K /dan e/FIN po około 6 sekun­dach, klient odpowie wysyłając RST, co prawdopodobnie spowoduje wystąpienie niepo­trzebnego błędu aplikacji serwera.

Utrata ważności przez stare, zduplikowane segmentySkrócenie stanu TIME_WAIT staje się możliwe dzięki temu, że opcja CC stwarza zabezpieczenie przed dostarczeniem duplikatów starych segmentów do innego wcielenia tego samego połączenia, ale tylko wtedy, gdy czas trwania połączenia jest mniejszy niż MSL. Na rysunku 4.8 prezentujemy sytuację, w której licznik CC jest zwiększany (tcp_ccgen) z największą możliwą częstotliwością: 2 - 1 jedno­stek na 2MSL. Daje to maksymalną częstotliwość transakcji równą 4 294 967 295, czyli 18 milionów transakcji na sekundę!

Zakładając, że wartość tcp_ccgen wynosi 1 w czasie 0 i jest zwiększana z maksymalną częstotliwością, wartość ta będzie ponownie równa 1 po czasie 2MSL, 4MSL, itd. Rów­nież, ponieważ wartość 0 nigdy nie występuje, pokazana wartość 2 14 7 483 648 pojawi się w rzeczywistości chwilę przed czasem MSL, a nie - tak jak pokazujemy - dokładnie w czasie MSL.

Zakładamy, że połączenie zaczyna się w czasie 0 z wartością CC równą 1, i czas trwania połączenia wynosi 100 sekund. Stan TIME_WAIT zaczyna się w czasie 100 i trwa albo do czasu 112, albo do momentu, gdy nowe wcielenie połączenia jest zainicjowane - w zależności od tego, co zdarzy się najpierw. (Zakładamy wartość RTO równą 1,5 sekundy, dającą czas trwania stanu TIME_WAIT równy 12 se­kund.) Ponieważ czas trwania połączenia (100 sekund) jest mniejszy niż MSL (120 sekund), mamy pewność, że wszelkie duplikaty starych segmentów znikną po czasie 220. Założymy również, że licznik tcp_ccgen jest inkrementowany z naj­większą możliwą częstotliwością, to znaczy pomiędzy czasem 0 i czasem 240 host nawiązuje ponad 4 miliardy innych połączeń TCP.

Tak więc - jeśli tylko czas trwania połączenia jest krótszy niż MSL - można bezpiecznie skrócić czas trwania stanu TIME_WAIT, ponieważ wartości CC nie powtórzą się przed czasem, po którym wszystkie ewentualne duplikaty starych segmentów przestaną istnieć.

Page 90: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

68 Protokół T/TCP - kontynuacja Rozdział 4

1 - tcp_ccgen czas 0 - -

* połączenie z C C -1

100 -- ■<112-

23' =2147 483 648 = tcp_ccgen (MSL) 120 -MSL; wszystkie stare duplikaty z połączenia

* z CC-1 przestają istnieć

220- _ J

2M -1 = 4 294 967 295 * tcp ccgen1 - tcp ccgen (2MSL) 240 -2=tcp_ccgen

Rysunek 4.8 Połączenie trwające mniej niż MSL: skrócenie TIME_WAIT jest możliwe

Aby zobaczyć, dlaczego skrócenie stanu TTME_WArT może mieć miejsce tylko wtedy, jeśli czas trwania połączenia jest krótszy niż MSL, przeanalizujmy rysunek 4.9.

1 = tcp_ccgen czas° 1 - ^

> połączenie z CC=2

231 -2 147 483 648 • tcp_ccgen (MSL) 120 -

140- - '

220 - MSL; wszystkie stare duplikaty z połączenia— i z CC2 przestają istnieć

2k -1 m 4 294 967 295 = tcp_ccgen £1 = tcp ccgen (2MSL) 240 -2= tcp_ccgen §

260 - > J=qro3E

360 -

380 -- ’r

Rysunek 4.9 Połączenie trwające dłużej niż MSL: stan TIM EJNAIT nie może być skrócony

Page 91: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 4.5____________ Unikanie potrójnego uzgodnienia przy pomocy TAO 69

Zakładamy ponownie, że licznik tcp_ccgen jest zwiększany z największą możli­wą częstotliwością. Połączenie rozpoczyna się w czasie 0, z wartością CC równą 2, a czas trwania połączenia wynosi 140 sekund. Ponieważ czas trwania jest większy niż MSL, stan TTME_WAIT nie może być skrócony i para gniazd nie może być ponownie użyta - aż do czasu 380. (Dokładniej, ponieważ przyjmujemy, że tcp_ccgen równa się 1 w czasie 0, połączenie z wartością CC równą 2 pojawi się chwilę po czasie 0 i skończy się chwilę po czasie 140. Nie wpływa to na nasze rozważania.)

W czasie pomiędzy 240 a 260 wartość CC równa 2 może zostać ponownie użyta. Gdyby stan T1ME_WAIT został skrócony (powiedzmy, zakończony pomiędzy 140 a 152) i jeśli nowe wcielenie tego samego połączenia zostałoby utworzone w czasie pomiędzy 240 i 260, możliwe byłoby (błędne) dostarczenie do drugiego wcielenia starych duplikatów z pierwszego wcielenia. Zauważmy, że nie jest problemem użycie wartości CC równej 2 w czasie 240-260 dla innego połączenia (to znaczy dla innej pary gniazd), nie można jedynie użyć tej samej wartości CC dla tej samej pary gniazd, dla której ciągle jeszcze mogą istnieć w sieci duplikaty starych segmentów.

Z punktu widzenia aplikacji, skrócenie TIME_WAIT oznacza, że klient musi zde­cydować, czy używać tego samego lokalnego portu dla serii transakcji z tym samym serwerem, czy używać innego portu dla każdej transakcji. Jeśli czas trwa­nia połączenia jest krótszy niż MSL (co jest typowe dla połączeń zwanych trans­akcjami), to używanie tego samego portu oszczędza zasoby TCP (tzn. zmniejsza pamięć zajętą przez bloki kontrolne, tak jak to pokazano na rysunkach 4.2 i 4.3). Jeśli jednak klient usiłuje użyć tego samego portu, a poprzednie połączenie trwało dłużej niż MSL, wygenerowany zostaje komunikat o błędzie EADDRINUSE.

Tak jak pokazano na rysunku 4.2, bez względu na to, która strategia wyboru portu zostanie użyta - przy założeniu, że oba hosty znają T/TCP i czas trwania połącze­nia jest krótszy niż MSL - stan TIME_WAIT jest zawsze skracany od wartości 2MSL do 8RTO. Pozwala to zaoszczędzić zasoby (tzn. pamięć i czas CPU). Doty­czy to dowolnego połączenia TCP - FTP, SMTP, HTTP i podobnych - krótszego niż MSL, nawiązanego pomiędzy dwoma hostami używającymi T/TCP.

4.5 Unikanie potrójnego uzgodnienia przy pomocy TAOPodstawową zaletą T/TCP jest możliwość uniknięcia potrójnego uzgodnienia. Aby zrozumieć, dlaczego pominięcie potrójnego uzgodnienia jest możliwe, musi­my najpierw zastanowić się, jaką rolę spełnia potrójne uzgodnienie. W RFC 793 zwięźle stwierdza się: „Pierwszorzędną przyczyną przeprowadzania potrójnego uzgodnienia jest uniknięcie sytuacji, w której stare duplikaty inicjacji połączenia są powodem trudności. W celu rozwiązania tego problemu został wymyślony spe­cjalny komunikat kontrolny - reset."

W ramach potrójnego uzgodnienia każdy z partnerów wysyła segment SYN ze swoim początkowym numerem sekwencyjnym i segment taki musi zostać po­twierdzony. W ten sposób wykluczona jest potencjalna możliwość otrzymania przez którykolwiek z dwu hostów duplikatu starego segmentu SYN. Co więcej,

Page 92: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

70 Protokół T/TCP - kontynuacja Rozdział 4

zwykłe TCP nie przekaże żadnych danych (dane mogą być zawarte w segmencie SYN) aż do czasu, gdy połączenie znajdzie się w stanie ESTABLISHED.

T/TCP musi dać gwarancje, że otrzymany SYN nie jest duplikatem starego seg­mentu, bez przechodzenia przez potrójne uzgodnienie, stwarzając jednocześnie możliwość natychmiastowego przekazania danych do procesu użytkownika. Za­bezpieczenie przed duplikatami starych segmentów SYN zostaje zrealizowane przez podanie wartości CC w segmencie SYN wysłanym przez klienta, która to wartość jest porównana z wartością CC dla ostatniego połączenia z tym samym klientem, zapamiętaną przez serwera.

Rozważmy diagram czasowy przedstawiony na rysunku 4.10. Tak jak w przypad­ku rysunku 4.8, zakładamy, że licznik tcp_ccgen jest zwiększany z maksymalną częstotliwością równą 232 -1 jednostek na 2MSL.

1 ■tcp_ccgen 100« tcp_ccgen

231 = 2 147 403 648 - tcp_ccgen

2m -1 - 4 294 967 295 - tcp_ccgen 1 b tcp_ccgen

100 = tcp_ccgen

czas O t

(MSL) 120

(2MSL) 240

wszystkie SYN z CC=1 przestają istnieć wszystkie SYN z CC-100 przestają istnieć

-► połączenie, CC=1, serwer zapamiętuje CC=1 -► połączenie, CC=100, serwer zapamiętuje CC-100

Rysunek 4.10 Większa wartość CC w segmencie SYN gwarantuje, że SYN nie jest duplikatem starego segmentu

W czasie 0 tcp_ccgen jest równe 1, w chwilę później wynosi 100. Z uwagi na ograniczony czas ważności dowolnego datagramu IP mamy gwarancję, że po czasie 120 (czas równy wartości MSL) wszystkie segmenty SYN z wartością CC równą 1 przestaną istnieć, a chwilę później przestaną również istnieć wszystkie segmenty SYN z wartością CC równą 100.

Następnie, w czasie 240, nawiązane zostaje połączenie z wartością CC równą 1. Załóżmy, że serwer przeprowadza test TAO dla segmentu inicjującego to połącze­nie i test ten daje wynik pozytywny - wówczas dla tego klienta serwer zachowuje wartość CC równą 1. Chwilę później zostaje zainicjowane nowe połączenie z tym samym hostem. Ponieważ wartość CC otrzymana wraz z SYN (100) jest większa niż zachowana wcześniej wartość CC dla tego klienta (1) i skoro wiemy na pewno,

Page 93: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 4.5 Unikanie potrójnego uzgodnienia przy pomocy TAO 71

że stare segmenty SYN z wartością CC równą 100 przestały istnieć przynajmniej MSL sekund wcześniej, mamy gwarancję, iż otrzymany segment SYN nie jest duplikatem starego segmentu.

Rzeczywiście, test TAO został opisany w RFC 1644 w sposób następujący: „Jeśli inicjujący segment SYN (tzn. segment zawierający bit SYN, ale nie zawierający bitu ACK) wysłany przez pewnego hosta posiada wartość CC większą niż odpo­wiednia zapamiętana wartość, monotoniczna własność opcji CC gwarantuje, że segment SYN jest nowy i w związku z tym może być natychmiast zaakceptowa­ny." Monotoniczna własność CC oraz dwa założenia:

• wszystkie segmenty mają skończony czas istnienia równy MSL,• wartość tcp_ccgen jest inkrementowana nie szybciej niż 223 - 1 jednostek na

2MSL sekund, gwarantują, że segment SYN jest nowy i T/TCP może pominąć potrójne uzgodnienie.

Segmenty SYN w nieprawidłowej kolejnościNa rysunku 4.11 przedstawiono dwa hosty T/TCP i segment SYN, który dociera do serwera w nieprawidłowej kolejności w stosunku do innych segmentów. Seg­ment SYN nie jest duplikatem starego segmentu, jedynie kolejność otrzymywania pakietów została zmieniona.

Rysunek 4.11 Dwa hosty T/TCP i segment SYN docierający zv niepraimdłowej kolejności

Page 94: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

12 Protokół T/TCP - kontynuacja Rozdział 4

Wartość CC przechowywana przez serwera dla tego klienta równa jest 1. Segment 1 na rysunku, wysłany z portu klienta numer 1600, z wartością CC równą 15, zostaje jednak opóźniony w sieci. Segment 2 jest wysłany z portu klienta 1601, z wartością CC równą 5000, i kiedy serwer odbierze ten segment, test TAO da wynik pozytywny (5000 jest większe niż 1) - wartość CC przechowywana przez serwera zostaje zwiększona do 5000, a dane przekazane do procesu. Segmenty 3 i 4 zakańczają tę transakcję.

Test TAO dla segmentu 1, gdy segment ten dociera wreszcie do serwera, daje wynik negatywny (15 jest mniejsze niż 5000), tak więc serwer odpowiada wysyła­jąc SYN oraz potwierdzenie segmentu SYN wysłanego przez klienta, wymuszając w ten sposób potrójne uzgodnienie (3WHS - three-way handshake), które musi być przeprowadzone zanim dane będą mogły być przesłane do procesu serwera. Segment 6 zakańcza potrójne uzgodnienie i dane są przekazane do procesu. (Nie pokazujemy dalszego ciągu tej transakcji.) Wartość CC przechowywana przez serwera nie jest jednak uaktualniona, mimo że potrójne uzgodnienie zostało za­kończone pomyślnie, ponieważ segment SYN z wartością CC równą 15 nie jest duplikatem starego segmentu (jedynie został on odebrany w nieprawidłowej ko­lejności). Gdyby wartość CC została uaktualniona, zmieniłaby się ona z powrotem z 5000 na 15, stwarzając możliwość błędnego zaakceptowania przez serwera du­plikatu starego segmentu SYN pochodzącego od tego samego klienta, z wartością CC w przedziale od 15 do 5000.

4.6 Wartości CC z „zawiniętym” bitem znakuNa rysunku 4.11 pokazaliśmy, że gdy test TAO daje wynik negatywny, serwer wymusza potrójne uzgodnienie. Nawet jeśli to uzgodnienie kończy się pomyślnie, wartość CC przechowywana przez serwera nie jest uaktualniona. Jest to prawidło­we postępowanie z punktu widzenia protokołu, ale wprowadza pewną trudność.

Możliwe, że test TAO przeprowadzony przez serwera da wynik negatywny, po­nieważ wartości CC wygenerowane przez klienta „zawijają bit znaku" (zump) w stosunku do danego serwera. Przypominamy, że generowana jest jedna se­kwencja wartości CC dla wszystkich połączeń realizowanych przez danego klien­ta. (CC są 32-bitowymi liczbami całkowitymi bez znaku, podobnie jak numery sekwencyjne TCP. Przy wszystkich porównaniach CC używana jest modularna arytmetyka, tak jak to opisano na stronach 839-842 tomu 2. Kiedy mówimy, że wartość a licznika CC „zawija się" w stosunku do b, to mamy na myśli sytuację, w której zwiększona wartość nie jest już większa, lecz jest mniejsza niż b). Rozważmy rysunek 4.12.

Klient ustanawia połączenie z serwerem w czasie 0, z wartością CC równą 1. Test TAO przeprowadzony przez serwera daje wynik pozytywny i serwer zachowuje dla danego klienta tę wartość CC. Następnie klient nawiązuje 2 147 483 646 po­łączeń z innymi serwerami. W czasie 120 zostaje nawiązane połączenie z tym samym serwerem co w czasie 0. Wartość CC wynosi teraz 2147 483 648. Test TAO

Page 95: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 4.6__________________Wartości CC z „zawiniętym" bitem znaku________________________ 73

przeprowadzony przez serwera dla segmentu SYN z taką wartością CC daje wynik negatywny (2147 483 648 jest mniejsze niż jeden, jeśli używana jest modular­na arytmetyka - patrz rysunek 24.26 na stronie 842 w tomie 2), potrójne uzgodnie­nie przeprowadzone zostaje pomyślnie, segment SYN zaakceptowany, ale wartość CC przechowywana przez serwera dla tego klienta pozostaje 1.

1=tcp_ccgen czas 0 - - -4-----► połączenie, CC=1, serwer zapamiętuje CC=1

231- 2 147483 648 = tcp_ccgen (MSL) 120 -- -----► połączenie, CC=2 147 483 648, test TAO daje wyniknegatywny, serwer wymusza potrójne uzgodnienie

232-1 =2 294967295 = tcp ccgen1 = tcp ccgen (2MSL) 240 -

'F

Rysunek 4.12 Test TAO może zakończyć się. niepomyślnie, ponieważ bit znaku CC zostaje „zawinięty"

Oznacza to, że wszystkie następne segmenty SYN wysłane przed czasem 240 przez tego samego klienta do serwera spowodują potrójne uzgodnienie. Zakłada­my tu, że licznik tcp_ccgen jest ciągle zwiększany z maksymalną częstotliwością. Bardziej prawdopodobne natomiast, że częstotliwość inkrementacji licznika bę­dzie znacznie mniejsza, co oznacza, że czas, po którym wartość licznika zwiększy się od 2 147 483 648 do 4 294 967 295 będzie nie 120 sekund, a potrwa godziny, czy nawet dni. Dopóki jednak bit znaku licznika nie zostanie „zawinięty" po raz drugi, wszystkie połączenia pomiędzy tym klientem i tym serwerem będą wymagały potrójnego uzgodnienia.

Rozwiązanie przedstawionego powyżej problemu jest dwustopniowe. Po pierw­sze, nie tylko serwer przechowuje najnowszą wartość CC otrzymaną od klienta, ale również klient przechowuje ostatnią wartość CC wysłaną do każdego serwera. Odpowiednie dwie zmienne pokazane są na rysunku 2.5 jako t a o_c c i t a o_c c s e n t .

Po drugie, jeśli klient stwierdza, że wartość CC, którą ma właśnie wysłać, jest mniejsza niż ostatnio użyta wartość CC dla tego serwera, klient wysyła opcję CCnew zamiast CC. Opcja CCnew zmusza oba hosty do ponownego zsynchro­nizowania przechowywanych wartości CC.

Page 96: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

74 Protokół T/TCP - kontynuacja Rozdział 4

Jeśli serwer otrzymuje segment SYN z opcją CCnew, zmienna tcp_ccgen dla tego klienta otrzymuje wartość 0 (niezdefiniowana). Po pomyślnym przeprowadzeniu potrójnego uzgodnienia, jeśli przechowywana wartość CC jest niezdefiniowana, zostaje ona uaktualniona wartością właśnie otrzymaną.

Klient wysyła opcję CCnew zamiast CC w inicjującym segmencie SYN w dwóch sytuacjach: gdy klient nie ma zachowanej wartości CC dla danego serwera (na przykład po przeładowaniu komputera lub gdy wpis dla danego serwera został opróżniony) oraz gdy klient wykrywa, że wartość CC dla tego serwera została zawinięta.

Zduplikowane segmenty SYN/ACKDo tego momentu nasza dyskusja koncentrowała się na przypadku, gdy serwer miał pewność, że otrzymany segment SYN jest nowy, tzn. nie jest duplikatem starego segmentu. W takiej sytuacji serwer nie musi przeprowadzać potrójnego uzgodnienia. Zastanówmy się teraz, w jaki sposób klient może uzyskać pewność, że odpowiedź serwera (segment SYN/ACK) nie jest duplikatem starego segmentu.

Gdy używany jest zwykły protokół TCP, klient nie wysyła żadnych danych w seg­mencie SYN, tak więc serwer musi potwierdzić dokładnie jeden bajt: flagę SYN. Co więcej, implementacje oparte na systemie Berkeley zwiększają początkowy wysyłkowy numer sekwencyjny (ISS - initial send sequen.ce number) o 64 000 (T C P_I SSINC R podzielone przez 2) za każdym razem, gdy rozpoczynane jest nowe połączenie (strona 1055 tomu 2). Tak więc każdy kolejny segment SYN klienta ma wyższy numer sekwencyjny niż w przypadku poprzedniego połączenia. Bardzo mało prawdopodobne, by duplikat starego segmentu SYN/ACK zawierał pole potwierdzenia akceptowalne dla klienta.

W przypadku T/TCP segment SYN zawiera zwykle również dane, co zwiększa zakres akceptowalnych dla klienta flag ACK wysłanych przez serwera. Rysunek 7 w RFC 1379 [Braden 1992b] pokazuje przykład duplikatu starego segmentu SYN/ACK błędnie zaakceptowanego przez klienta. Wadą tego przykładu jest jednak to, że różnica początkowych numerów sekwencyjnych pomiędzy dwoma połączeniami wynosi tylko 100 i jest to wartość mniejsza niż ilość danych wysyła­nych w pierwszym segmencie SYN (300 bajtów). Jak powiedzieliśmy, implemen­tacje oparte na systemie Berkeley zwiększają ISS przynajmniej o 64 000 dla każde­go połączenia, a liczba 64 000 jest większa niż domyślna wielkość wysyłkowego okna w protokole T/TCP (zwykle 4096). Wyklucza to możliwość zaakceptowania przez klienta duplikatu starego segmentu SYN/ACK.

System 4.4BSD-Lite2 generuje losowo wartość ISS - tak jak to przedstawiliśmy w rozdzia­le 3.2. W tym przypadku wartość, o którą ISS jest zwiększana, została jednolicie losowo rozłożona w przedziale od 31 232 do 96 767, co daje średnią wartość równą 63 999. Liczba 31 232 jest wciąż większa niż domyślna wielkość okna wysyłkowego, a opcja CCecho, którą właśnie zamierzamy przedyskutować, powoduje, że problem staje się pozorny.

Tak czy inaczej, T/TCP zawiera niezawodne zabezpieczenie przed duplikatami starych segmentów SYN/ACK: opcję CCecho. Klient zna wartość CC, którą wysy-

Page 97: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 4.7 Podsumowanie 75

ła, i dokładnie ta wartość musi być zwrócona przez serwera w opcji CCecho. Odpowiedź serwera nie zawierająca spodziewanej wartości CCecho jest ignoro­wana przez klienta (rysunek 11.8). Właściwość monotonicznego zwiększania war­tości CC gwarantuje, że duplikat starego segmentu SYN/ACK nie zostanie za­akceptowany przez klienta. Przypominamy, że cykliczne powtórzenie wartości CC może nastąpić najwcześniej po czasie równym 2MSL sekund.

Zauważmy, że klient nie może wykonać testu TAO dla segmentu SYN /ACK otrzymanego od serwera: jest na to zbyt późno. Segment SYN klienta został już zaakceptowany przez serwera, dane przekazane do procesu serwera, a otrzymany segment SYN /ACK zawiera odpowiedź serwera. Jest więc zbyt późno, by klient mógł wymusić potrójne uzgodnienie.

Retransmitowane segmenty SYNW RFC 1644 oraz w naszej dyskusji w tym podrozdziale zignorowana została możliwość, że SYN klienta lub SYN serwera będzie wysłany powtórnie. Na rysun­ku 4.10 zakładamy na przykład, że wartość tcp_ccgen jest 1 w czasie 0 i wszystkie segmenty SYN z wartością CC równą 1 przestają istnieć po czasie' 120 (MSL). W rzeczywistości może się zdarzyć, że segment SYN z CC równym 1 jest retrans­mitowany w przedziale czasu od 0 do 75, tak więc wszystkie segmenty SYN z CC równym 1 giną po czasie 195, a nie 120. (Implementacje wywodzące się z systemu Berkeley ograniczają czas, w którym segment SYN klienta lub serwera może być retransmitowany, do 75 sekund. Zostało to omówione na stronie 859 w tomie 2.)

Nie zmienia to faktu, że test TAO jest poprawny, zmniejszona zostaje natomiast maksymalna częstotliwość inkrementacji licznika tcp_ccgen. Wcześniej podali­śmy, że maksymalna częstotliwość zmian tego licznika wynosi 232 -1 jednostek na 2MSL sekund, co daje maksymalną częstotliwość transakcji niemal 18 milionów na sekundę. Jeśli weźmie się pod uwagę powtórnie wysłane segmenty SYN, maksy­malna częstotliwość jest równa 232 - 1 zmian na 2MSL+ 2MRX sekund, gdzie MRX jest limitem czasu na retransmisje segmentów SYN (75 sekund dla N et/3). Otrzy­mujemy w ten sposób zmniejszoną maksymalną częstość transakcji: około 11 milionów na sekundę.

4.7 PodsumowanieStan TTMELWAIT protokołu TCP pełni dwie funkcje:

• pozwala przeprowadzić pełne dwustronne zamknięcie połączenia,

• umożliwia odczekanie do czasu, po którym stare zduplikowane segmenty przestają istnieć.

Jeśli czas trwania połączenia T/TCP jest mniejszy niż 120 sekund (1MSL), stan TIME_WAIT trwa przez czas równy 8 razy czas oczekiwania na retransmsję (8RTO), zamiast 240 sekund. Klient może również stworzyć nowe wcielenie połą­czenia, które znajduje się w stanie TIME_WAIT, jeszcze bardziej skracając ten stan.

Page 98: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

76 Protokół T/TCP - kontynuacja Rozdział 4

Wyjaśniliśmy, dlaczego jest to możliwe, i pokazaliśmy, że ograniczeniem jest jedynie maksymalna częstotliwość transakcji w protokule T/TCP (niemal 18 mi­lionów transakcji na sekundę). Jeśli klient T/TCP zamierza przeprowadzać wiele transakcji z tym samym serwerem, może on używać tego samego portu dla każde­go kolejnego połączenia, ograniczając w ten sposób liczbę bloków kontrolnych w stanie TIME_WAIT.

Test TAO (TCP accelemted open) pozwala ominąć potrójne uzgodnienie przy na­wiązywaniu połączenia T/TCP. Test ten daje wynik pozytywny, jeśli serwer otrzymuje od klienta wartość CC większą niż wartość przechowywana przez serwera dla tego klienta. Właśnie właściwość monotonicznego wzrostu wartości CC oraz dwa założenia, że:

• wszystkie segmenty mają skończony czas istnienia równy MSL sekund,

• wartość tcp_ccgen rośnie nie szybciej niż 232 - 1 jednostek na 2MSL sekund, gwarantują, że segment SYN wysłany przez klienta jest nowy i umożliwiają pominięcie potrójnego uzgodnienia w protokole T/TCP.

Page 99: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Implementacja T/TCP: warstwa gniazd5

5.1 WstępJest to pierwszy z kilku rozdziałów opisujących implementację T/TCP zawartą w kodzie sieciowym N et/3. Zachowujemy ten sam porządek i styl prezentacji co w tomie 2:

• Rozdział 5: warstwa gniazd• Rozdział 6: tablica rutowania• Rozdział 7: bloki kontrolne protokołu (PCB)• Rozdział 8: przegląd TCP• Rozdział 9: wyjście TCP• Rozdział 10: funkcje TCP• Rozdział 11: wejście TCP• Rozdział 12: żądania użytkownika w TCP.

We wszystkich tych rozdziałach zakładamy, że Czytelnik dysponuje egzempla­rzem tomu 2 lub kodem źródłowym opisanych tam programów. W ten sposób możemy ograniczyć prezentację do 1200 linii nowego kodu potrzebnego do imple­mentacji T/TCP i unikamy powtórzenia opisu 15 000 linii zawartego w tomie 2.

Zmiany w warstwie gniazd wymagane przez T/TCP są niewielkie: funkcja sosend musi uwzględniać flagę MSG_EOF i musi umożliwiać wywołanie sendto lub s e n d m s g, jeżeli protokół dopuszcza niejawne zamknięcie-otwarcie.

5.2 StałeT/TCP wymaga zdefiniowania trzech nowych stałych:

1. Flaga MSG_E0F, zdefiniowana w <sys /soc ket .h> . Jeśli flaga ta jest podana w odwołaniu do funkcji send, sendto lub sendmsg, oznacza to, że przesyłanie danych w danym połączeniu zostało zakończone. Połączone są w ten sposób funkcje odwołań dowriteishutdown. Flaga ta powinna być uwzględniona na rysunku 16.12 (strona 498) tomu 2.

2. Nowe żądanie protokołu, PRU_SEND_E0 F, zdefiniowane w <sys/protosw. h>. Żądanie powinno być uwzględnione na rysunku 15.17 w tomie 2. Jest ono generowane przez s o s e n d, jak pokażemy to później na rysunku 5.2.

3. Nowa flaga protokołu, PR_IMPLOPCL (implied open-close, czyli niejawne otwar- cie-zamknięcie), również zdefiniowana w<sys/proto sw.h>. Flaga ta oznacza dwie rzeczy: (a) protokół dopuszcza wywołanie sendto i sendmsg z podaniem

Page 100: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

78 Implementacja T/TCP: warstwa gniazd Rozdział 5

adresu partnera, bez wcześniejszego wywołania connect (niejawne otwarcie); (b) protokół rozumie znaczenie flagi MSG_E0F (niejawne zamknięcie). Zauważ­my, że flaga P R_IM P L0 P C L jest istotna tylko dla protokołów zorientowanych na połączenia (na przykład TCP), ponieważ protokoły bezpołączeniowe zawsze dopuszczają sendto i sendmsg bez poprzedzającego connect. Flaga ta powin­na być dodana do rysunku 7.9 (strona 197) w tomie 2.

Wpis odpowiadający TCP w inetsw[2] (linie 51-55 na rysunku 7.13, strona 200, tom 2) powinien zawierać PR_IMPLOPCL wśród wartości pr_fl ags.

5.3 Funkcja sosendWprowadzamy dwie zmiany w kodzie funkcji sosend. Rysunek 5.1 przedstawia kod zastępujący linie 314-321 na stronie 511 w tomie 2.

uipc_socket.c320 if ((so ->so_state & SS_ISCONNECTED) == 0) [321 /*322 * sendto i sendmsg są dopuszczalne dla gniazda zorientowanego323 * na połączenie, jedynie jezleli gniazdo obsługuje niejawne otwarcie324 (np. T/TCP).325 ★ Zwracamy ENOTCONN, jeżeli brak połączenia lub nie został podany326 * a dres.327 */328 if ((so->so_proto->pr_f 1ags & PR_C0NNREQUIRED) &&329 (so->so_proto->pr_flags & PR_IMPLOPCL) == 0) (330 if ((so->so_state & S S_ISC0N FI RM ING) == 0 &&331 !(resid == 0 && cl en != 0))332 snderrt ENOTCONN);333 ] else if (addr == 0)334 snderr(so->so proto->pr flags & PR CONNREQUIRED ?335 ENOTCONN : EDESTADDRREO);336 )

------------------------------------------------------------------------------------------------ uipc_socket.cRysunek 5.1 Funkcja sosend-sprawdzenie poprawności

Zauważmy, że nasz modyfikowany kod zaczyna się od linii 320, a nie od linii 314. Spowodowane jest to przez inne zmiany, niezwiązane z T /TC P, dokonane we wcześniej­szych fragmentach tego pliku. Ponadto - ponieważ zastępujemy siedemnastoma nowymi liniami osiem linii z tomu 2 - dalsze fragmenty kodu w tym samym pliku, które będziemy pokazywać później, będą również miały inne numery linii niż odpowiednie fragmenty z tomu 2. Przyjmujemy ogólną zasadę, że kiedy odnosimy się do fragmentów programów z tomu 2, wyszczególniamy numery linii dokładnie takie, jakie widoczne są w w tomie 2. Ponieważ programy uległy zmianie w stosunku do przedstawionych w tomie 2, numery linii w prezentowanych tu fragmentach zawierających modyfikacje będą zbliżone, ale nie identyczne.

3 20-336 Jeżeli flaga protokołu P R_ IMPLOPCL jest ustawiona (tak jak ma to miejsce dla TCP ze zmianami opisanymi w tym tekście) i adres przeznaczenia jest podany przez wołającą procedurę, ten fragment kodu dla gniazda zorientowanego na połączenia, umożliwia użycie sendto lub sendmsg. Jeśli adres przeznaczenia nie jest podany - w przypadku gniazda TCP zwracany jest komunikat ENOTCONN, a w przypadku gniazda UDP komunikat EDESTADDRREO.

Page 101: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 5.4 Podsumowanie 79

330-331 Ta instrukcja i f umożliwia wysłanie informacji kontrolnej bez danych, jeśli połączenie jest w stanie S S_I S CO N FI RM ING. Wymagane jest to przez protokół OSI TP4, nie przez TCP/IP.

Następna modyfikacja sendto, zastępująca linie 399-403 na stronie 516 w tomie 2, została pokazana na rysunku 5.2.

------------------------------------------------------------------------------------------------ uipc_socket.c415 s = splnett): /* XXX */416 /*417 * Jeżeli użytkownik podaje flagę MSG_E0F, a protokół rozumie418 * tę flagę (np. T/TCP), i żadne dane nie oczekują na wysłanie,419 * wówczas wygenerowane zostaje żądanie PRU_SEND_EOF zamiast420 * PRILSEND. MSG_00B ma jednak wyższy priorytet.421 */422 req = (flags & MSG_00B) ? PRILSENDOOB :423 ((flags & MSG_E0F) &&424 (so->so_proto->pr_flags & PR_IMPL0PCL) &&425 (resid <= 0)) ? PRU_SEND_E0F : PRU_SEND;426 error = (*so->so_proto->pr_usrreq) (so, req, top. addr. control);427 splx( s);

------------------------------------------------------------------------------------------------ uipc_socket.cRysunek5.2 Funkcja s os e n d - przekazanie do odpowiedniego protokołu

Po raz pierwszy spotykamy się tutaj z komentarzem XXX. Jest to ostrzeżenie dla czytelni­ka, że ten fragment programu jest niejasny, powoduje nieoczywiste efekty uboczne, lub jest szybkim rozwiązaniem bardziej złożonego problemu. W przedstawionym tu frag­mencie kodu priorytet procesora zostaje zwiększony przez s p 1 n e t po to by uniemożliwić przetwarzanie protokołu. Początkowy priorytet procesora jest przywrócony na końcu przedstawionego fragmentu przez wywołanie spl x. Rozdział 1.12 tomu 2 przedstawia różne poziomy priorytetu przerwań w kodzie N et/3.

416-427 Jeśli podana jest flaga MSG_00B, to wygenerowane zostaje także żądanie PRILSENDOOB. W przeciwnym razie, jeśli podana jest flaga MSG_E0F oraz protokół uznaje flagę P R_IM P L0 PC L i nie ma więcej danych, które powinny być wysłane do protokołu (resid jest mniejsze lub równe 0), utworzone zostaje żądanie PRU_SEND_E0F, zamiast normalnego żądania PRU_SEND.

Przypomnijmy nasz przykład z rozdziału 3.6. Aplikacja wywołuje sendto z flagą MSG_EOF, żeby przekazać 3300 bajtów. Przy pierwszym wykonaniu pętli (rysu­nek 5.2) program generuje żądanie PRU_SEND dla pierwszych 2048 bajtów danych (klaster mbuf). Przy drugim wykonaniu pętli w funkcji sos end żądanie PRU_SEND_E0F utworzone zostaje dla pozostałych 1252 bajtów danych (w kolej­nym klastrze mbuf).

5.4 PodsumowanieT/TCP uzupełnia TCP o możliwość wykonania niejawnego otwarcia i zamknięcia połączenia. Niejawne otwarcie oznacza, że zamiast wywoływać connect, aplika­cja może wywołać sendto lub sendmsg podając adres partnera. Niejawne zamk­nięcie pozwala aplikacji podać flagę MSG_E0F w odwołaniu do send, sendto lub sendmsg, łącząc wysłanie danych z zamknięciem, sendto na rysunku 1.10 łączy

Page 102: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

80 Implementacja T/TCP: warstwa gniazd Rozdział 5

otwarcie, wysłanie i zamknięcie w jednym odwołaniu do funkcji systemowej. Zmiany zaprezentowane w tym rozdziale rozszerzają warstwę gniazd kodu N et/3 o możliwość korzystania z niejawnego otwarcia i zamknięcia.

Page 103: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Implementacja T/TCP: tablica rutowania6

6.1 WstępProtokół T/TCP musi utworzyć w pamięci wpis dla każdego hosta, z którym się komunikuje, zawierający trzy zmienne: tao_cc, tao_ccsent i tao_mssopt, tak jak to pokazaliśmy na rysunku 2.5. Wygodne miejsce na umieszczenie takiego wpisu to istniejąca tablica rutowania. W kodzie Net /3 umieszczenie dodatkowych da­nych w tablicy rutowania jest łatwe - można to zrobić przy pomocy flagi „klono­wania", którą opisaliśmy w rozdziale 19 tomu 2.

W tomie 2 zobaczyliśmy, że protokoły Internetu (bez T/TCP) używają ogólnych funkcji obsługi tablicy rutowania udostępnianych przez N et/3. Rysunek 18.17 (strona 593) w tomie 2 pokazuje, że marszruty są dodawane przy pomocy funkcji rn_addroute, a kasowane przy pomocy rn_delete. Poszukiwanie marszruty odbywa się przy pomocy funkcji rn_match, a funkcja rn_wa 1 ktree umożliwia prześledzenie całego drzewa rutowania. (N et/3 przechowuje tablice rutowania w formie binarnego drzewa, zwanego drzewem podstawowym - mdix tree). Wymie­nione funkcje pozwalają na pełną obsługę tablic rutowania wymaganą przez TCP/IP. W przypadku T/TCP sytuacja jest jednak inna.

Ponieważ host w krótkim czasie może nawiązywać połączenia z tysiącami innych hostów (na przykład w ciągu kilku godzin, a w przypadku silnie aktywnego serwera WWW być może nawet w czasie krótszym niż godzina), potrzebny jest mechanizm dający możliwość automatycznego usuwania wpisów z tablicy ruto­wania po określonym czasie, by uniknąć niepotrzebnego zajmowania pamięci jądra systemu. W tym rozdziale przedstawiamy używane przez T/TCP funkcje, pozwalające dynamicznie tworzyć i kasować wpisy w tablicy rutowania protoko­łu IP.

W ćwiczeniu 19.2 w tomie 2 przedstawiliśmy prosty sposób tworzenia wpisu w tablicy nitowania dla każdego partnera, z którym komunikuje się nasz host. Mechanizm, który przedstawiamy tutaj, opiera się na podobnej zasadzie, ale działa automatycznie dla większości marszrut TCP/IP. Wpisy dla poszczególnych hostów utworzone w ćwiczeniu nigdy nie traciły ważności - istniały aż do przeładowania hosta lub do chwili, gdy zostały ręcznie skasowane przez administratora. Potrzebny jest lepszy, automatyczny sposób zarządzania wpisami w tablicy rutowania.Istnieją różne opinie na temat założenia, że istniejąca tablica rutowania jest odpowiednim miejscem do przechowywania wpisów protokołu T /T C P dla poszczególnych hostów. Alternatywą byłoby przechowywanie danych T/TCP dla poszczególnych hostów w po­staci oddzielnego, specjalnie w tym celu utworzonego drzewa podstawowego w jądrze. Technika oddzielnego drzewa jest prosta, jeśli korzysta się z istniejących ogólnych funkcji służących do obsługi takiego drzewa, i w rzeczywistości jest używana do montowania dysków NFS w kodzie N et/3.

Page 104: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

82 Implementacja T/TCP: tablica rutowania Rozdział 6

6.2 Kod źródłowy - wprowadzenieFunkcje dodane wraz z T/TCP w celu obsługi rutowania T/TCP zebrane są w jednym pliku: neti net / i n_rmx. c. Plik ten zawiera jedynie funkcje specyficzne dla Internetu, które opisujemy w tym rozdziale. Nie opisujemy tutaj wszystkich funkcji rutowania przedstawionych w rozdziałach 18,19 i 20 tomu 2.

Na rysunku 6.1 przedstawiliśmy zależność pomiędzy nowymi funkq'ami specy­ficznymi dla Internetu, opisywanymi w tym rodziale (zacieniowane elipsy z na­zwami funkcji zaczynającymi się od i n_), a ogólnymi funkcjami rutowania (o na­zwach najczęściej zaczynających się od rn_ lub r t ).

co 10

minut

________^ 7(^route_init^) tqtimo^)

RTM ADD

1(^rtable_init]) (^rń^walktree^i (^rtreguest^) ( ^ J t a l l o c l ^ ) ( ^ ^ r t f r e e ~ ^ )

rt refcnt = 0

RTM DELETE<^rn_lnithead^) <^rtrequest^) (^rrT^addroute^) (^rn_m a t ch^)

Rysunek 6.1 Zależności pomiędzy funkcjami rutowania specyficznymi dla Internetu

Zmienne globalneNowe zmienne globalne specyficzne dla Internetu przedstawione są na rysunku 6.2.

Zmienna Typ Określenie

r t q _ t i meout r t q _ t o o m a n y

r t q _ r e a l l y o l d

r t q _ m i n r e a l l y o l d

i n t

i n t

i n t

i n t

częstotliwość wykonywania i n _ r t q t i mo (domyślnie co 10 minut)

liczba marszrut, powyżej której rozpoczyna się dynamiczne kasowanie

czas, po którym marszruta zostaje uznana za naprawdę starą

minimalna wartość r t q _ r e a l l y o l d

Rysunek 6.2 Zmienne globalne specyficzne dla Internetu

System FreeBSD pozwala administratorowi zmodyfikować wartości trzech ostatnich zmiennych na rysunku 6.2 przy pomocy programu sysct l z przedrostkiem

Page 105: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 6.3 Struktura radix_node_head 83

n e t . i n e t . i p. Nie pokazujemy tu odpowiedniego fragmentu kodu, ponieważ jest to proste uzupełnienie funkcji i p_sysct l (rysunek 8.35 strona 253 tomu 2).

6.3 Struktura radix_node_headNowy wskaźnik dodany do struktury radix_node_head (rysunek 18.16, strona 592, tom 2) jest pusty, z wyjątkiem sytuaq'i, gdy wskazuje on na funkcję i n_cl s route, którą pokazujemy na rysunku 6.7.

Wskaźnik ten używany jest przez funkcję r t f ree. Pomiędzy liniami 108 i 109 na rysunku 19.5 w tomie 2 dodajemy następującą linię, deklarując i inicjalizując lokalną zmienną dynamiczną rnh :

struct radix_node_head *rnh = rt_tables[rt_key(rt)- >sa_family];

Pomiędzy liniami 112 i 113 zostają dodane następujące trzy linie:

i f (rnh->rnh_close && rt->rt_refcnt == 0) (rnh->rnh_close((struct radix_node *)rt, rnh):

}Jeśli wskaźnik funkcji jest niepusty i licznik odwołań ( r t _ r e f c n t ) osiąga wartość0, wywołana zostaje funkcja zamykająca rnh_cl ose.

6.4 Struktura rtentryT/TC P wymaga wprowadzenia dwóch nowych flag rutowania w strukturze r t e n t ry (strona 597, tom 2). Do tej struktury zostaje więc dodany nowy człon flag, r t _ p r f 1ags.

Innym możliwym rozwiązaniem jest zmiana typu rt_f 1 ags z krótkich na długie liczby całkowite. Rozwiązanie to być może będzie zastosowane w następnych wersjach N et/3 .

T/TC P wykorzystuje w rt_prf1 ags dwa bity flag:

• Flaga RTPRF_WASCLONED -ustaw ianaprzez r trequest (pomiędzy liniami335- 336 na stronie 629 tomu 2), gdy nowy wpis jest tworzony z wpisu z ustawioną flagą RTF_CLONING.

• Flaga RTPRF_OURS - ustawiana przez in_clsroute (rysunek 6.7), gdy ostatnie odwołanie do sklonowanej marszruty IP zostaje usunięte; w tym momencie uru­chamiany jest zegar, który po pewnym czasie spowoduje skasowanie marszruty.

6.5 Struktura rtjnetricsWszystkie zmiany w tablicy rutowania związane z T/TCP wykonowywane są w celu umieszczenia w tej tablicy dodatkowych informacji związanych z poszcze­gólnymi hostami. Informacje te zawarte są w zmiennych tao_cc , t ao_ ccsent i tao_mssopt. Przechowanie nowych informaqi umożliwia nowy człon w stru­kturze rt_met ri cs (strona 599, tom 2):u_long rmx_fi 11e r [ 4 ] ; /* metryki specyficzne dla rodziny protokołów */

Page 106: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

84 Implementacja T/TCP: tablica rutowania Rozdział 6

Umożliwia to przeznaczenie 16 bajtów na metryki specyficzne dla konkretnego protokołu, które wykorzystywane są przez T/TCP tak, jak to pokazujemy na rysunku 6.3.

------------------------------------------------------------------------------------------------- tcpjuar.h153 struct rmxp_tao (154 tcp_cc tao_cc; /* ostatnia wartość CC otrzymana od

* partnera w poprawnym segmencie SYN */155 tcp_cc tao_ccsent; /* ostatnia wartość CC wysłana do partnera */156 u_short tao_mssopt; /* ostatnia wartość MSS otrzymana od partnera */157 ) ;

158 #define rmx_taop(r) ((struct rmxp_tao * )(r ) .rmx_fi 11 er)

------------------------------------------------------------------------------------------------ tcpjuar.hRysunek 6.3 Struktura rmxp_tao używana przez T/TCP jako pamięć TAO

153-157 Liczniki połączeń zadeklarowane są przy użyciu typu tcp_cc. Typ ten został zdefiniowany (typedef) jako liczba całkowita bez znaku (podobnie jak numery sekwencyjne TCP). Wartość 0 zmiennej typu tcp_cc oznacza, że zmienna jest niezdefiniowana.

158 Makroinstrukcja rmx_taop, z podanym wskaźnikiem do struktury rtentry, zwraca wskaźnik do odpowiedniej struktury rmxp_tao.

6.6 Funkcja injnitheadNa stronie 602 w tomie 2 opisaliśmy szczegółowo kolejne kroki wykonywane przy inicjacji wszystkich tablic rutowania w kodzie N et/3. Pierwsza modyfikacja zwią­zana z T/TCP polega na tym, że wskaźnik dom_rtattach należący do struktury inetdomain (linie 78-81 na stronie 200 tomu 2) wskazuje teraz na funkcję i n_i ni thead, zamiast na funkcję rn_i ni thead. Funkcję i n_i ni thead pokazuje­my na rysunku 6.4.

------------------------------------------------------------------------------------------------ in_rmx.c218 int219 in_inithead(void **head, int off)220 [221 struct radix_node_head *rnh;

222 if (!rn_initheadthead, off))223 return (0);

224 if (head != (void **) & rt_tabies[A F _1NET])225 return (1); /* wykonujemy to tylko dla prawdziwej

* tabli cy rutowani a */

226 rnh = *head;227 rnh->rnh_addaddr = in_addroute;228 rnh->rnh_matchaddr = in_matroute;229 rnh->rnh_close = in_clsroute;230 in_rtqtimo(rnh); /* ki ck off timeout first time */231 return (1);232 ]------------------------------------------------------------------------------------------------ in_rmx.cRysunek 6.4 Funkcja in _in i thead

Page 107: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 6.7 Funkcja in_addroute 85

Inicjacja tablicy rutowania222-225 W kodzie N e t /3 rn_i ni thead alokuje i inicjuje jedną strukturę typu

radi x_node_head. Pozostała część funkcji jest nowa, wprowadzona dla potrzeb T/TCP i wykonywana tylko wtedy, gdy inicjuje się „prawdziwą" tablicę rutowa­nia. Funkcja ta jest również wywoływana przy inicjacji tablicy rutowania innego rodzaju - używanej w związku z punktami montowania NFS.

Zmiana wskaźników funkcji226 ■ 229 Dwa wskaźniki funkcji w strukturze radi x_n o d e_h e a d są zmienione w sto­

sunku do ich wartości domyślnych ustawionych przez rn_ini thead: rnh_ad- daddr oraz rnh_matchaddr. Zmienione zostają więc dwa z czterech wskaźników z rysunku 18.17, strona 593, tom 2. W ten sposób czynności specyficzne dla Internetu mogą być wykonane zanim zostaną wywołane uniwersalne funkcje wierzchołka podstawy (mdix node). Wskaźnik funkcji r n h_c 1 os e jest nowy, wpro­wadzony wraz z T/TCP.

Inicjacja ograniczenia czasu230 Funkcja ograniczenia czasu, i n_rtqti mo, wywołana zostaje po raz pierw­

szy. Każde wywołanie tej funkcji powoduje, że będzie ona ponownie wywołana w przyszłości.

6.7 Funkcja in_addrouteGdy funkcja rtrequest umieszcza nowy wpis w tablicy rutowania w wyniku wykonania polecenia RTM_ADD lub polecenia RTM_RESOLVE (które tworzy nowy wpis z istniejącego wpisu posiadającego ustawioną flagę klonowania - strony 629-630 w tomie 2), wołana jest funkqa rnh_addaddr. Odpowiednikiem tej funkcji dla protokołów internetowych jest - jak widzieliśmy - i n_addroute. Ta nowa funkcja pokazana została na rysunku 6.5.

------------------------------------------------------------------------------------------------- in_rmx.c47 static struct radix_node *48 in_addroute(void *v_arg, void *n_arg, struct radix_node_head *head,49 struct radix_node *treenodes)50 l51 struct rtentry *rt = (struct rtentry *) treenodes;

52 /*53 * Dla IP wszystkie marszruty jednostkowe, nie będące marszrutami

* do hosta, mają ustawione flagi klonowania54 */55 if (!(rt->rt_f1ags & (RTF_H0ST | RTF_CLONING))) (56 struct sockaddr in *sin = (struct sockaddr in *) rt key(rt):57 if (! IN MULTICAST(ntohl(sin->sin addr.s a d d r ) )) (58 rt->rt flags |= RTF CLONING:59 )60 }61 return (rn_addroute(v_arg, n_arg, head, treenodes));62 }

------------------------------------------------------------------------------------------------- in_rmx.cRysunek 6.5 Funkcja in_addroute

Page 108: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

86 Implementacja TfTCP: tablica rutowania Rozdział 6

52-61 Jeżeli dodawana marszruta nie jest marszrutą do konkretnego hosta i nie maustawionej flagi klonowania, analizowane jest słowo kluczowe tablicy rutowania (adres IP). Jeśli adres IP nie jest adresem grupowym (multicast), nowy wpis w tab­licy rutowania otrzymuje flagę klonowania. Funkcja rn_addroute dodaje wpis do tablicy rutowania.

Efekt wykonania tej funkcji to ustawienie flagi klonowania dla wszystkich marsz­rut do sieci, łącznie z marszrutą domyślną, z wyjątkiem marszrut przesyłania grupowego. Flaga klonowania powoduje, że powstaje nowa marszruta do hosta dla każdego adresu przeznaczenia poszukiwanego w tablicy rutowania, jeśli tylko pasujący wpis w tablicy nie jest adresem sieci przesyłania grupowego. Dzieje się tak również, jeśli pasujący wpis to adres domyślny. Nowa, sklonowana marszruta do hosta tworzona jest przy pierwszym przeszukiwaniu tablicy dla danego adresu przeznaczenia.

6.8 Funkcja in_matroutePodczas poszukiwania marszruty funkcja rtallocl (strona 622-623, tom 2) wywołuje funkcję wskazywaną przez wskaźnik rnh_matchaddr (tzn. funkcję i n_matroute pokazaną na rysunku 6.6).

------------------------------------------------------------------------------------------------ in_rmx.c68 static struct radix_node *69 in_matroute(void *v_arg, struct radix_node_head *head)70 (71 struct radix_node *rn = rn_match(v_arg, head);72 struct rtentry *rt = (struct rtentry *) rn;

73 if (rt && rt->rt_refcnt == 0) ( /* jest to pierwsze odwołanie */74 if (rt->rt_prflags & RTPRF_0URS) l75 rt->rt_prflags &= ~RTPRF_OURS;76 rt->rt_rmx.rmx_expire = 0:77 )78 179 return (rn);80 )

-------------------------------------------------------------------------------------------------in_rmx.cRysunek 6.6 Funkcja injmtroute

Wywołanie mjnatch w poszukiwaniu marszruty71 -78 rn_match poszukuje marszruty w tablicy rutowania. Jeżeli marszruta zosta­

je znaleziona i licznik rt_ref cnt ma wartość 0, jest to pierwsze odwołanie do tego wpisu w tablicy rutowania. Jeżeli odliczany jest czas pozostający do skasowania wpisu, tzn. gdy ustawiona jest flaga RTPRFJDURS, flaga ta zostaje wyłączona i ze­gar (licznik czasu) rmx_expi re otrzymuje wartość 0. Taka sytuacja ma miejsce, gdy marszruta została zamknięta, ale nastąpiło ponowne jej użycie, zanim uległa skasowaniu.

Page 109: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 6.9 Funkcja in_clsroute 87

6.9 Funkcja in_clsrouteWspomnieliśmy wcześniej, że nowy wskaźnik funkcji, rn h_c 1 o s e, zostaje dodany do struktury radi x_node_head wraz z T/TCP. Funkcja ta jest wywoływana przez r t f ree, gdy licznik odwołań osiąga wartość 0. To powoduje wywołanie funkq'i i n_cl s route, pokazanej na rysunku 6.7.

89 stati c void90 in_clsroute(struct radix_node *rn, struct radix node head *head)91 {92 struct rtentry *rt = (struct rtentry *) rn;

93 if (!(rt->rt_flags & RTF_UP))94 return;95 if ((rt->rt_flags & (RTF_LLINF0 | RTF_H0ST)) != RTF_H0ST)96 return;97 if (Crt->rt prflags & (RTPRF WASCL0NED 1 RTPRF 0URS))98 != RTPRF_WASCL0NED)99 r et ur n;

100 /*101 ★ Jeżeli rtq_reallyold jest 0, po prostu kasujemy tę marszrutę102 * nie czekając aż zostanie skasowana po wyczerpaniu się czasu

oczekiwania.103 */104 if (rtq reallyold != 0) (105 rt->rt_prf1ags |= RTPRF_0URS;106 rt->rt_rmx.rmx_expire = time.tv_sec + rtq_real1y o l d ;107 ) else {108 rtrequest(RTM_DELETE,109 (struct sockaddr *) rt_key(rt).110 rt->rt_gateway, rt_mask(rt),111 rt->rt_flags, 0);112 )113 )------------------------------------------------------------------------------------------------- in_rmx.cRysunek 6.7 Funkcja in_clsroute

Sprawdzenie flag93-99 Sprawdzone zostaje, czy: marszruta jest aktywna (up), flaga RTF_H0ST włą­

czona (tzn. czy nie jest to marszruta do sieci), flaga RTF_LLIN FO wyłączona (flagata jest włączona dla wpisów ARP), flaga RTPRF_WASCLONED włączona (wpis został sklonowany) i czy flaga RTPRF_0URS wyłączona (czas do skasowania wpisu nie jest aktualnie odliczany). Jeśli którykolwiek z powyższych warunków nie został spełniony, funkcja zwraca kontrolę do procedury wołającej.

Ustalenie czasu skasowania wpisu100-112 Najczęściej wartość rtq_real 1 yol d jest niezerowa, co powoduje ustawie­

nie flagi RTPRF_0URS i wpisanie do rmx_expi re wartości aktualnego czasu w se­kundach ( t i me. tv_sec ) powiększonego o r tq_real lyol d (zwykle 3600 sekund, czyli 1 godzina). Jeśli administrator ustawi przy pomocy programu sy sc t l ze­rową wartość r tq_real lyold, to marszruta jest natychmiast kasowana przez r trequest .

Page 110: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

88 Implementacja T/TCP: tablica rutowania Rozdziale

6.10 Funkcja in_rtqtimoPo raz pierwszy funkcja in_rtqtimo została wywołana przez i n_i ni thead na rysunku 6.4. Każde wywołanie funkcji i n_rtqti mo powoduje, że ustalony zostajeczas następnego wywołania tej funkcji - nastąpi to po czasie rtq_t i meout sekund(wartość domyślna wynosi 600 sekund, czyli 10 minut).

Funkcja i n_rtqtimo kolejno przegląda (używając uniwersalnej funkcji rn_wal k-tree) wszystkie wpisy w tablicy rutowania IP, wywołując i n_rtq ki 11 dla każdego wpisu. Funkcja in_rtqkill decyduje, czy skasować wpis, czy nie. Funkcje i n_rtqti mo i i n_rtqki 11 muszą przekazywać między sobą informaqe i robią to za pośrednictwem trzeciego argumentu funkcji rn_wal ktree. Argument ten jest wskaźnikiem przekazywanym przez rn_wal ktree do i n_rtqki 11 . Ponieważ ar­gument jest wskaźnikiem, informacja może być przekazywana w obie strony, od i n_rtqtimo do i n_rtqki 11 i vice versa.

Wspomniany wskaźnik przekazywany przez in_rtqtimo do rn_wal ktree jest wskaźnikiem do struktury rtq k_a rg pokazanej na rysunku 6.8.

in_rmx.c114 struct rtqk _arg (

t-H-_1 ULA,

115 struct radi x_node_head *rnh; /* początek tablicy rutowania */116 i nt f o u n d ; /*

■kliczba wpisów, dla których odliczany jest czas do skasowania */

117 i nt ki 11e d ; /* liczba wpisów skasowanych przez in_rtqki 11 */118 i nt updating; /*

*ustawiany, jeżeli kasujemy niepotrzebne wpi sy */

119 i nt draining; /* zwykle 0 */120121

time t) ;

next st op ; /* czas ponownego wykonania */

in_rmx.cRysunek 6.8 Struktura rtqk_arg-przekazyivanie informacji z i n _ r t q t i m o

do i n _ r t q k i 11 izpoiorotem

Przy okazji omawiania funkcji i n_rtqti mo pokazanej na rysunku 6.9 pokażemy, jak poszczególne człony tej struktury są używane.

------------------------------------------------------------------------------------------------- in_rmx.c159 static void160 in_rtqtimo(void *rock)161 {162 struct radix_node_head *rnh = rock:163 struct rtqk_arg a r g ;164 struct timeval atv;165 static time_t 1ast_adjusted_timeout = 0;166 int s;

167 a rg . rnh = r n h ;168 arg.found = arg.killed = arg.updating = arg.draining = 0;169 arg.nextstop = time.tv_sec + rtq_timeout;170 s = s pi n e t ();171 rnh->rnh_walktree(rnh, in_rtqkill, &arg):172 s pl x( s);

173 /*174 * Usiłujemy postępować "dynamicznie":

Page 111: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 6.10 Funkcja in_rtqtimo 89

175 * Jeżeli jest "zbyt wiele" marszrut zajmujących niepotrzebnie miejsce,176 * skracamy czas oczekiwania i sprawdzamy, czy możemy się pozbyć jakichś177 * dodatkowych marszrut. Nigdy jednak nie dokonujemy takiej modyfikacji178 * częściej niż raz na rtq_timeout sekund - nie chcemy, by sprawdzanie179 * odbywało się zbyt często.180 */181 if (Carg.found - arg.killed > rtq_toomany) &&182 (time.tv_sec - last_adjusted_timeout >= rtq_timeout) &&183 r t q _ r e a H y o l d > rtq_minreal lyold) {184 rtq_reallyold = 2 * rtq_reallyold / 3;185 if (rtq_reallyold < rtq_minreallyold)186 rtq_reallyold = rtq_minreallyold;

187 1ast_adjusted_timeout = time.tv_sec;188 1og(L0G_DEBUG, "in_rtqtimo: adjusted rtq_reallyold to *d\n",189 rtq_reallyold);190 arg.found = arg.killed = 0;191 arg.updating = 1:192 s = s p lnet();193 rnh->rnh_walktree(rnh, in_rtqkill, &arg):194 splx( s);195 )196 atv.tv_usec = 0;197 atv.tv_sec = arg.nextstop;198 timeout(in_rtqtimo, rock, hzto(4atv));199 )

---------------------------------------------------------------------------------- in_rmx.c

Rysunek 6.9 Funkcja in_rtqtimo

Inicjacja struktury rtqk_arg i wywołanie rn_walktree167-172 Struktura rtqk_arg jest zainicjowana przez przypisanie rnh wartości odpo­

wiadającej początkowi tablicy rutowania IP, liczniki found i killed otrzymują wartość O, flagi drainingiupdate ustawione są na O, a wartość nextstop ustalona zostaje na aktualny czas (w sekundach) plus rtq_timeout (600 sekund, czyli 10 minut). Funkcja rn_walktree przegląda całą tablicę rutowania IP, wołając i n_rtqki 11 (rysunek 6.10) dla każdego wpisu w tej tablicy.

Sprawdzenie liczby wpisów w tablicy rutowania173-189 Tablica rutowania zawiera zbyt wiele wpisów, jeżeli jednocześnie spełnione

są następujące trzy warunki:

• liczba wpisów ciągle pozostających we właśnie przeglądanej tablicy rutowania (found minus ki 1 i ed ) jest większa niż rtq_toomany (z wartością domyślną równą 128),

• liczba sekund od ostatniego wykonania tego sprawdzenia jest większa niż rtq_ti meout (600 sekund, czyli 10 minut),

• wartość r t q_re a 11 y o 1 d jest większa niż r t q_mi n re a 11 y o 1 d (wartość domyśl­na wynosi 10).

Jeżeli wszystkie trzy warunki są spełnione, to rtq_reallyold otrzymuje wartość równą dwóm-trzecim swojej aktualnej wartości (obliczone z dzielenia liczb całko­witych). Ponieważ początkowa wartość rtq_real lyol d jest równa 3600 sekund (60 minut), to kolejne możliwe wartości wynoszą: 3600,2400,1600,1066,710, itd. Nigdy jednak wartość tej zmiennej nie może stać się mniejsza niż rtq_minreal lyol d

Page 112: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

90 Implementacja T/TCP: tablica rutowania Rozdział 6

(wartość domyślna równa 10). Aktualny czas zostaje zachowany w statycznej zmiennej 1 ast_ad ju‘sted_ti meout i wysyłany jest komunikat (dla kontroli) do demona sysl ogd. (Rozdział 13.4.2 pracy [Stevens 1992] pokazuje, jak funkcja 1 og wysyła komunikaty do demona s y s 1 o g d .) Idea związana z tym fragmentem kodu i ze zmniejszającą się wartością rtq_rea11 yol d jest taka, by przeglądanie tablicy rutowania i kasowanie zdezaktualizowanych wpisów stawało się częstsze, w mia­rę jak tablica rutowania się wypełnia.

190-195 Liczniki found i killed w strukturze rtqk_arg są ponownie inicjowane wartościami 0, flaga updati ng otrzymuje tym razem wartość 1 i znów wołana jest funkcja rn_wal ktree.

196-198 Funkcja i n_rtqki 11 wpisuje do członu nextstop struktury rtqk_arg czas, w którym i n_rtqti mo ma być wywołana ponownie. Funkcja jądra ti meout po­woduje, że takie wywołanie w przyszłości nastąpi.

Jak duże dodatkowe obciążenie procesora spowodowane jest przeglądaniem całej tablicy rutowania co 10 minut? Zależy to oczywiście od liczby wpisów w tej tablicy. W rozdziale 14.10 stworzyliśmy tablicę rutowania odpowiadającą aktywnemu serwerowi WWW i stwierdziliśmy, że choć serwer kontaktuje się z ponad 5000 różnych klientów w ciągu 24 godzin, z czasem deaktualizacji wpisów w tablicy rutowania równym 1 godzinie, w tab­licy rutowania nigdy nie występuje więcej niż 550 pozycji. Niektóre podstawowe (back- bone) rutery w Internecie posiadają dziś dziesiątki tysięcy wpisów w tablicy rutowania, lecz są to rutery, a nie hosty. Nie należy się spodziewać, że taki podstawowy ruter będzie wykorzystywał T /T C P i będzie zmuszony regularnie przeglądać tak wielką tablicę ruto­wania, kasując stare wpisy.

6.11 Funkcja in_rtqkillJak już wiemy, funkcja i n_rtqki 11 jest wołana przez rn_wal ktree, która tofunkcja z kolei jest wołana przez i n_rtqti mo. Funkcja i n_rt q k i 11, którą pokazu­jemy na rysunku 6.10, ma za zadanie kasować wpisy w tablicy rutowania IP, gdy to jest konieczne.

------------------------------------------------------------------------------------------------ in_rmx.c127 static int128 in_rtqki 11 (struct raaix_node *rri, void *rock)129 (130131132133

134135

136137138

139140141142143144

struct rtqk_arg *ap = rock; struct radix_node_head * rnh = a p ->rnh ; struct rtentry *rt = (struct rtentry *) rn; int err;

if (rt->rt_prflags & RTPRF_0URS) 1 ap->found++:

if (ap->draining || rt->rt_rmx.rmx_expire <= time.tv_sec) ( if (rt->rt_refcnt > 0)

pani c ("rtqki11 route re a 11y not free");

err = rtrequest(RTM_DELETE,(struct sockaddr *) rt_key(rt), rt->rt_gateway, rt_mask(rt), rt->rt_f1a g s . 0);

if (err)log(L0G_WARNING, "in_rtqki11: error % d\n”, err);

Page 113: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 6.11 Funkcja in_rłqkill 91

145 else146 ap->ki1 led++:147 1 else (148 if (ap->updating &&149 (rt->rt_rmx.rmx_expire - time.tv_sec > rtq_reallyold)) {150 rt->rt_rmx.rmx_expire = time.tv_sec + rtq reallyold;151 )152 ap->nextstop = lmin(ap->nextstop, rt->rt_rmx.rmx_expire);153 ]154 ]155 return (0):156 )

------------------------------------------------------------------------------------------------ in_rmx.cRysunek 6.10 Funkcja in_rtqk i 17

Przetwarzanie tylko nieaktualnych wpisów134-135 Funkcja ta przetwarza tylko wpisy z ustawioną flagą RTPRF_0URS, to znaczy

wpisy, które zostały zamknięte przez i n_cl s route (ich liczniki odwołań osiągnę­ły wartość 0) i następnie, po pewnym czasie (zwykle 1 godzina), straciły ważność. Funkcja nie ma wpływu na aktualnie używane marszruty (ponieważ flaga RTPRF_0URS dla takich marszrut nie jest ustawiona).

136-146 Jeżeli flaga dra i ni n g jest ustawiona (co nigdy nie zdarza się w opisywanej tu implementaqi), lub skończył się okres ważności wpisu (wartość rmx_expi re jest mniejsza niż aktualny czas),marszruta zostaje skasowana przy pomocy r trequest . Człon found struktury rtqk_arg zlicza wpisy w tablicy rutowania z ustawioną flagą RTPRF_0URS, a człon ki 11 ed zlicza skasowane wpisy.

147-151 Klauzula el se zostaje wykonana, gdy przeglądany wpis jest ważny (tzn. nie skończył się okres ważności wpisu ). Jeżeli ustawiona została flaga updating (co się zdarza, gdy - jak widzimy na rysunku 6.9 - mamy wiele marszrut, dla których odliczany jest czas do skasowania i cała tablica jest przeglądana jeszcze raz) i jeżeli czas utraty ważności (który musi odpowiadać przyszłości, jeśli odejmo­wanie ma dać dodatnią wartość) jest zbyt odległy, to czas ten zostaje ustawiony na aktualny czas powiększony o wartość rtq_rea 1 lyold. Wyjaśniamy to dokładniej na rysunku 6.11.

1 okres ważności ustalony początkowo na 3600 sekund

różnica = 3100

okres ważności odliczany od nowa - ustalony na 2400 sekund

i i i »

100 600I

3000I ►

3700in _ c l s r o u t e in _ r tq t im o

in r t q k i . l l

Rysunek 6.11 Funkcja in_rtqk i 11 zmienia czas utraty ważności

Na osi x odłożyliśmy czas w sekundach. Marszruta zostaje zamknięta w czasie 100 (gdy liczba odwołań stała się równa 0), a początkowa wartość r tq_real lyol d wynosi 3600 (1 godzina). Czas utraty ważności dla tej marszruty wynosi więc

Page 114: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

92 Implementacja T/TCP: tablica rutowania Rozdział 6

3700. W czasie 600 wykonana jest funkcja i n_rtqti mo i marszruta nie jest skaso­wana (ponieważ traci ona ważność dopiero 3100 sekund później). W tablicy ruto­wania jest jednak zbyt wiele pozycji, funkcja i n_rtqti mo ustawia więc wartość rtq_real lyol d na 2400, zmienia wartość flagi updati ng na 1, a funkcja rn_wal k-tree ponownie przegląda tablicę rutowania. Tym razem i n_r t q ki 11 znajduje ustawio­ną flagę updati ng i czas utraty ważności marszruty jest określony na 3100. Ponie­waż 3100 jest większe niż 2400, czas utraty ważności jest zmieniony na 2400 sekund liczone od aktualnej chwili, czyli czas 3000 na rysunku 6.11. Czas utraty ważności maleje wraz ze zwiększeniem się liczby wpisów w tablicy rutowania.

Obliczenie następnego czasu timeout152-153 Ten fragment kodu jest wykonywany za każdym razem, gdy znaleziona

zostaje marszruta, dla której czas do utraty ważności jest odliczany, ale jeszcze nie upłynął. nextstop otrzymuje wartość równą mniejszej z dwóch wartości: aktual­na wartość nextstop i czas utraty ważności danego wpisu w tablicy rutowania. Przypominamy, że początkowa wartość next stop była ustalona przez i n_rtqti mo ibyła równa aktualnemu czasowi plus rtq_ti meout (tzn. 10 minut później).

Rozważmy przykład pokazany na rysunku 6.12. Na osi x odłożony jest czas w sekundach i duże kropki w czasie 0, 600, itd. oznaczają kolejne wywołaniai n_rtqti mo.

in c l s r o u t e

" 1 1100 300

I I I 1 i i i i

marszruty tracą ważność

1 13700 3900

1 1 1 it l i f0 600

t1200

t1800

t2400

t3000

t t t3600

t ►4500

Rysunek 6.12 Wykonanie in _rtq tim o ; utrata ważności marszrut

Marszruta IP jest tworzona przez i n_addroute i następnie zamykana w czasie 100 przez in_clsroute. Czas utraty ważności tej marszruty ustalono na 3700 (godzinę później). Inna marszruta zostaje utworzona i następnie zamknięta w czasie 300, czas utraty ważności tej marszruty wynosi więc 3900. Funkcja in_rtqtimo jest wykonywana co 10 minut, w czasie 0, 600,1200,1800, 2400, 3000 i 3600. Podczas każdego z tych wykonań w czasach od 0 do 3000 nextstop otrzymuje wartość równą aktualnemu czasowi powiększonemu o 600. Kiedy i n_rtq ki 11 jest wywo­łana dla każdej z dwóch marszrut w czasie 3000, nextstop otrzymuje wartość 3600, ponieważ 3600 jest mniejsze niż 3700 i mniejsze niż 3900. Kiedy natomiast i n_rtqki 11 jest wywołana w czasie 3600, nextstop otrzymuje wartość 3700, ponieważ 3700 jest mniejsze niż 3900 i mniejsze niż 4200. Oznacza to, że następ­nym razem i n_rtqki 11 będzie wywołana w czasie 3700, a nie 4200. Podobnie, kiedy in_rtqkill jest wywołana w czasie 3700, druga marszuta, która utraci ważność w czasie 3900, powoduje, żenextstop otrzymuje wartość 3900. Zakłada­

Page 115: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 6.12 Podsumowanie 93

jąc, że żadne inne marszruty IP nie tracą ważności, funkcja i n_rtqti mo po wyko­naniu w czasie 3900 zostanie ponownie wywołana w czasie 4500,5100, itd.

Zależności związane z czasem utraty ważnościIstnieje kilka subtelnych zależności dotyczących czasu utraty ważności wpisów do tablicy rutowania i członu rmx_expi re struktury rt_metri cs. Po pierwsze, ten sam człon jest również używany przez ARP, by określić utratę ważności wpisów ARP (rozdział 21, tom 2). Oznacza to, że wpis w tablicy rutowania odnoszący się do hosta w lokalnej podsieci (łącznie ze związaną z tym hostem informacją TAO) jest kasowany, kiedy kasowany jest wpis ARP dla tego hosta, co zwykle ma miejsce co 20 minut. Czas ten jest krótszy niż domyślny czas utraty ważności używany przez i n_rtqki 11 (1 godzina). Przypominamy, że funkcja i n_c1 s route jawnie ignorowała te wpisy ARP (rysunek 6.7), które miały ustawioną flagę RTM_LLINF0, oddając ARP kontrolę nad ważnością tych wpisów.

Po drugie, wykonanie programu route w celu odczytania i wydrukowania me­tryk i czasu utraty ważności dla sklonowanego wpisu T/TCP w tablicy rutowania ma efekt uboczny polegający na przywróceniu początkowej wartości czasu utraty ważności. Dzieje się to w sposób następujący. Załóżmy, że marszruta jest używa­na, a następnie zostaje zamknięta (liczba odwołań staje się równa 0). Czas utraty ważności zostaje ustalony na jedną godzinę od czasu zamknięcia marszruty. 59 minut później, jedną minutę przed upływem terminu ważności, program route jest użyty do wydrukowania metryk tej marszruty. W wyniku uruchomienia programu route wykonane zostają następujące funkcje jądra: route_output wy­wołuje rtal 1 ocl, która z kolei woła i n_matroute (wersja funkcji rnh_matchaddr specyficzna dla Internetu), co powoduje zwiększenie liczby odwołań od - powie­dzmy - 0 do 1. Na koniec, zakładając, że liczba odwołań zmienia się od 1 do 0, funcja r t f r e e wywołuje i n_c 1 s r o u t e, co powoduje ustawienie czasu utraty waż­ności ponownie na 1 godzinę.

6.12 PodsumowanieW związku z T/TCP do struktury rt_metrics dodajemy 16 bajtów. Dziesięć z tych bajtów jest używanych przez T/TCP jako pamięć TAO :

• tao_cc , ostatnia wartość CC otrzymana od partnera w poprawnym segmencie SYN

• tao_ccsent , ostatnia wartość CC wysłana do partnera• tao_ms sopt, ostatnia wartość MSS otrzymana od partnera.

Do struktury radix_node_head zostaje dodany jeden nowy wskaźnik funkcji - człon rnh_close, który (o ile został zdefiniowany) jest wykorzystywany, gdy liczba odwołań dla danej marszruty osiągnie 0.

Page 116: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

94 Implementacja T/TCP: tablica rutowania Rozdział 6

Zostają zdefiniowane cztery nowe funkcje specyficzne dla protokołów interneto­wych:

1. i n_i ni thead inicjuje internetową strukturę rad i x_node_head, ustawiając omawiane tu cztery wskaźniki funkcji,

2. i n_addroute jest wołana, gdy do tablicy rutowania IP dodana zostaje nowa marszruta. Funkcja ta włącza flagę klonowania dla każdej marszruty IP, z wyjątkiem marszrut do hostów i wpisów odpowiadających adresom grupo­wym,

3. i n_m a t r o u t e jest wołana za każdym razem, gdy poszukiwana jest marszruta IP. Jeśli marszruta oczekuje na skasowanie po wykonaniu i n_c1 s route, tzn. biegnie czas do utraty jej ważności, czas utraty ważności otrzymuje wartość 0, ponieważ marszruta ta jest znowu używana.

4. in_clsroute jest wołana, gdy ostatnie odwołanie do marszruty IP zostaje zamknięte. Funkcja ta ustala czas utraty ważności marszruty na 1 godzinę od aktualnej chwili. Zobaczyliśmy też, że czas ten może zostać skrócony, jeżeli tablica rutowania staje się zbyt duża.

Page 117: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Implementacja T/TCP: bloki kontrolne protokołu7

7.1 WstępT/TCP wymaga wprowadzenia jednej niewielkej zmiany w funkcjach PCB (roz­dział 22, tom 2). Funkcja i n_pcbconnect (rozdział 22.8, tom 2) zostaje teraz po­dzielona na dwie części: wewnętrzną procedurę zwaną i n_pcbl addr, która przy­pisuje adres lokalnego interfejsu, oraz funkcję i n_pcbconnect, która pełni tę samą rolę co wcześniej (i woła in_pcbl addr).

Dokonujemy takiego podziału funkcji na dwie części, ponieważ przy użyciu T/TCP możliwe jest wywołanie connect, gdy poprzednie wcielenie tego samego połączenia (ta sama para gniazd) pozostaje w stanie TIME_WAIT. Jeśli poprzednie wcielenie trwało krócej niż wartość MSL, i jeśli obie strony używają opcji CC, wtedy połączenie w stanie TIME_WArr zostaje zamknięte i może zostać utworzo­ne nowe połączenie (nowe wcielenie połączenia). Gdybyśmy nie wprowadzili zmiany i T/TCP użyłoby niezmodyfikowanej funkcji i n_pcbconnect, aplikaqa - po znalezieniu bloku PCB połączenia w stanie TIME_WAIT - otrzymałaby infor­macje o błędzie „address already in use" (zajęty adres).

Funkcja i n_pcbconnect jest wywoływana nie tylko z polecenia connect modułu TCP, ale również: gdy otrzymane zostaje nowe żądanie połączenia TCP, gdy wywoływane jest c o n n e c t protokołu UDP i przy wykonaniu funkcji sendto UDP. Rysunek 7.1 podsumowuje te odwołania N et/3 przed wprowadzeniem naszej modyfikacji.

UDP wejście TCP

Rysunek7.1 Podsumowanie odwołań Net/3 do funkcji i n_pcbcorw ect

Procedury wejściowe TCP oraz moduł protokołu UDP wywołują - tak jak poprzednio - i n_pcbconnect, ale funkcja connect TCP (żądanie PRU_CONNECT) wywołuje teraz nową funkcję tcp_connect (rysunki 12.2 i 12.3), która z kolei wywołuje nową funkq'ę i n_pcbl addr. Dodatkowo tcp_connect wywołuje rów­nież żądania PRU_SEND oraz PRU_SEND_EOF wygenerowane w rezultacie niejawne­go otwarcia połączenia przez klienta z użyciem sendto lub w wyniku użycia sendmsg. Demonstrujemy to na rysunku 7.2.

Page 118: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

96 Implementacja T/TCP: bloki kontrolne protokołu______________ Rozdział 7

UDP wejście TCP

Rysunek.7.2 Nowy układ, odwołań do i n_pcbconnect i in_pcbl addr

7.2 Funkcja in_pcbladdrPierwsza część funkcji i n_pcbl addr pokazana została na rysunku 7.3. Ten frag­ment zawiera jedynie argumenty funkcji i pierwsze dwie linie kodu, które sąidentyczne z liniami 138-139 na stronie 762 tomu 2.

------------------------------------------------------------------------------------------------ in_pcb.c136 int137 in_pcbladdr(i n p , nam, p1o ca1_s i n )138 struct inpcb *inp;139 struct mbuf *nam;140 struct sockaddr_in **plocal_sin;141 (142 struct in_ifaddr *ia;143 struct sockaddr_in *ifaddr;144 struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);

145 if (nam->m_len != sizeof(*sin))146 return (EINVAL);

------------------------------------------------------------------------------------------------ in_pcb.cRysunek 7.3 Funkcja i n_pcb 1 addr, część pierwsza

136-140 Pierwsze dwa argumenty są takie same jak argumenty in_pcbconnect,

trzeci argument jest wskaźnikiem do wskaźnika, za pośrednictwem którego zwró­cony zostaje lokalny adres.

Pozostała część tej funkcji jest taka sama jak na rysunkach 22.25, 22.26 i 22.27 w tomie 2, z wyjątkiem ostatnich dwóch linii na rysunku 22.27 (linie 225-226, strona 765), które zostają zastąpione kodem przedstawionym na rysunku 7.4.

232-236 Jeśli procedura wołająca poda adres wieloznaczny (w iłd c a r d ), w trzecim argumencie zostanie zwrócony wskaźnik do struktury sockaddr_in.

Działanie in_pcbladdr sprowadza się w zasadzie do przeprowadzenia najpierw pewnej kontroli błędów, następnie obsłużone zostają szczególne adresy 0.0.0.0 i 255.255.255.255, po czym następuje przypisanie lokalnego adresu IP (o ile proce­dura wołająca nie podała adresu). Pozostała część przetwarzania wymaganego przez connect wykonywana jest w i n_pcbconnect.

Page 119: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 7.3 Funkcja in_pcbconnect 97

------------------------------------------------------------------------------------------------ injpcb.c232 /*233 * Nie wywołujemy tu in_pcblookup. Interfejs zwracamy w234 * plocal_sin i przekazujemy kontrolę do wywołującej procedury,

* która wykona poszukiwanie.235 */236 *plocal_sin = &i a -> i a _ addr:

237 )238 return (0);239 }

------------------------------------------------------------------------------------------------ in_pcb.cRysunek 7.4 Funkcja in_pcb 1 addr, część końcowa

7.3 Funkcja in_pcbconnectFunkcja i n_pcbconnect pokazana została na rysunku 7.5. Funkcja ta wywołuje funkcję i n_pcb 1 addr przedstawioną w poprzednim rozdziale, a dalsza część ko­du źródłowego tej funkcji jest taka sama jak kod z rysunku 22.28, strona 765 w tomie 2.

------------------------------------------------------------------------------------------------- injpcb.c247 int248 in_pcbconnect(inp, nam)249 struct inpcb *inp;250 struct mbuf *nam:251 (252253254

255256257258259

260 261 262263264265266267268269270271272273274275 )----------------------------------------------------------------------------------- injpco.c

struct sockaddr_in *i f addr;struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); int error;

/** Wywołujemy wewnętrzną funkcję, by przypisać lokalny adres interfejsu */

if (error = in_pcbladdr(inp, nam, &i f addr)) return (error);

if (in_pcblookup(inp->inp_head, si n->sin_addr, sin->sin_port,

inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, inp->inp_lport,0))

return (EADDRINUSE); if (inp->inp_laddr.s_addr == INADDR_ANY) {

if (i n p -> i n p_lport == 0)(v o i d ) i n_pcbbi n d (i n p , (struct mbuf *) 0);

inp->inp_laddr = ifaddr--sin_addr;}inp->inp_faddr = sin->sin_addr; inp->inp_fport = sin->sin_port; return (0);

Rysunek 7.5 Funkcja in_pcbconnect

Page 120: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

98 Implementacja TfTCP: bloki kontrolne protokołu Rozdział 7

Przypisanie lokalnego adresu2 55-259 Lokalny adres IP jest wyznaczany przez i n_pcbl addr i zostaje zwrócony

we wskaźniku i faddr, chyba że procedura wołająca związała się wcześniej z gniazdem.

Sprawdzenie, czy para gniazd jest jednoznaczna260-266 Funkcja in_pcblookup sprawdza, czy para gniazd określona jest jedno­

znacznie. W zwykłym przypadku, gdy klinet TCP wykonuje connect (jeśli klient nie związał się z gniazdem lokalnego portu lub lokalnego adresu), numer lokalne­go portu równy jest 0. Tak więc funkcja i n_pcbl ookup zawsze zwraca wartość 0, ponieważ numer lokalnego portu równy 0 nie koliduje z żadnym istniejącym blokiem PCB.

Związanie lokalnego adresu portu i lokalnego portu267-271 Funkcja i n_pcbbi nd przypisuje lokalny adres i lokalny port, o ile lokalny

adres i lokalny port nie zostały jeszcze związane z gniazdem. Jeśli lokalny adres nie został jeszcze związany, ale numer lokalnego portu jest inny niż 0, do PCB zostaje wpisany adres lokalny zwrócony przez in_pcbl addr. Nie jest możliwe związanie lokalnego adresu, gdy numer lokalnego portu jest ciągle 0, ponieważ wywołanie in_pcbbind w celu związania lokalnego adresu powoduje również przypisanie do gniazda efemerycznego portu.

272-273 Do PCB zostają wpisane adres i port odległego systemu (argumenty i n_pcbconnect).

7.4 PodsumowanieFunkcja i n_pcbconnect została zmodyfikowana w związku z T/TC P w ten spo­sób, że fragment kodu, w którym wyznaczany jest lokalny adres, został usunięty i umieszczony w nowej oddzielnej funkcji i n_pcbl addr. Funkcja i n_pcbconnect najpierw wywołuje nową funkcję, a następnie kontynuuje działanie tak jak po­przednio. Taki funkcjonalny podział procedury i n_pcbconnect umożliwia wy­wołanie i n_pcbl addr w celu wyznaczenia lokalnego adresu w trakcie przetwa­rzania żądania klienta T/TCP (jawnego - z użyciem connect, lub niejawnego - z użyciem sendto). Przetwarzanie po stronie klienta T/TCP powiela następnie kroki pokazane na rysunku 7.5, a moduł T/TCP umożliwia akceptację żądania połączenia, nawet jeśli istnieje wcześniejsze wcielenie tego samego połączenia pozostające w stanie TIME_WAIT. Zwykłe TCP nie dopuściłoby do takiej sytuacji, funkcja i n_pcbconnect zwróciłaby komunikat o błędzie EADDRINUSE (rysu­nek 7.5).

Page 121: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Implementacja T/TCP: przegląd TCP8

8.1 WstępW tym rozdziale omawiamy globalne zmiany w strukturach danych i funkcjach TCP wprowadzone na potrzeby T/TCP. Dodane zostają dwie zmienne globalne: tcp_ccgen - globalny licznik CC oraz tcp_do_rfcl644 - flaga określająca, czy powinny być używane opcje CC. Wpis przełącznika protokołów (protocol switch entry) odpowiadający TCP jest zmodyfikowany, tak by możliwe było wykonanie niejawnego otwarcia-zamknięcia. Ponadto do bloku kontrolnego TCP zostają do­dane cztery nowe zmienne.

Funkqa tcp_s 1 owti mo, mierząca czas trwania połączenia, zostaje nieznaczniezmodyfikowana. W zależności od czasu trwania połączenia - jeżeli połączenie jest krótsze niż MSL - T/TCP skraca stan TIME_WAIT, tak jak to przedstawiliśmy na rysunku 4.4.

8.2 Kod źródłowy - wprowadzenieŻadne nowe pliki z kodem źródłowym nie zostają dodane w związku z T/TCP, wymagane jest natomiast wprowadzenie kilku nowych zmiennych.

Zmienne globalneNa rysunku 8.1 zebraliśmy nowe zmienne globalne związane z T/TCP.

Zmienna Typ Określenie

t c p _ c c g e n

t c p _ d o _ r f c l 6 4 4

tcp_cc

i nt

następna wartość CC do wysłania

jeśli prawda (wartość domyślna), wyślij opcje CC lub CCnew

Rysunek 8.1 Zmienne globalne dodane wraz z T/TCP

W rozdziale 3 przedstawiliśmy kilka przykładów użycia zmiennej tcp_ccgen. W rozdziale 6.5 wspomnieliśmy, że typ zmiennych tcp_cc jest zdefiniowany (typedef) jako unsigned long. Wartość 0 zmiennej typu tcp_cc oznacza, że zmienna ta jest niezdefiniowana. Sposób odwoływania się do zmiennej tcp_ccgen jest zawsze następujący:

tp->cc_send = C C_INC(tcp_ccgen):

gdzie cc_send to nowy człon bloku kontrolnego TCP (patrz rysunek 8.3). Makro­instrukcja CC_INC została zdefiniowana w <net i net / tcp_seq . h> jako

Page 122: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

100 Implementacja T/TCP: przegląd TCP Rozdział 8

#define CC_lNC(c) (++(c) == O ? ++(c) : (c))

Ponieważ wartość zmiennej jest zwiększana przed użyciem, tcp_ccgen zostaje zainicjowana wartością 0, a jej pierwsza wartość wynosi 1.

Zostają zdefiniowane cztery makroinstrukq'e, które - przy zastosowaniu modular­nej arytmetyki - służą do porównywania wartości CC: CC_LT, CC_LEQ, CC_G, i CC_GEQ. Makroinstrukcje te są identyczne z czterema makroinstrukcjami SEQ_xx przedstawionymi na stronie 839 tomu 2.

Zmienna tcp_do_rfcl644 jest podobna do zmiennej tcp_do_rfc 1323 wprowa­dzonej w tomie 2. Jeśli t c p_do_r f c 1644 jest równa 0, TCP nie będzie wysyłać opcji CC lub CCnew do partnera po drugiej stronie połączenia.

Zmienne statystyczneT/TC P wprowadza pięć nowych liczników, które pokazujemy na rysunku 8.2. Liczniki te zostają dodane do struktury t c p s t a t , którą przedstawiamy na stro­nach 826-827 w tomie 2. Program n e t s t a t musi zostać zmodyfikowany, tak by drukował również te nowe człony struktury.

Czton tcpstat Opis

t c p _ t a o o k

t cp s_ t a o f a i 1

t c p s _ b a d c c e c h o

tcps_i mpli e d ac k

t c p s _ c c d r o p

liczba otrzymanych segmentów SYN, dla których testTAO dał wynik pozytywny

liczba otrzymanych segmentów SYN z opcją CC, ale z negatywnym wynikiem TAO

liczba segmentów SYN/ACK z błędną opcją CCecho

liczba nowych SYN, które niejawnie potwierdzają poprzednie wcielenie

liczba segmentów odrzuconych ze względu na nieprawidłową opcję CC

Rysunek 8.2 Dodatkowe liczniki T/TCP w strukturze statystycznej tcps tat

8.3 Struktura TCP protoswW rozdziale 5 wspomnieliśmy, że wraz z wprowadzeniem T/TCP zmianie ulega człon pr_f 1 ags odpowiadającej TCP struktury protosw (która jest elementem tablicy inetsw[2]; strona 829 w tomie 2). Do istniejących już flag PR_CONNREQUIREDi PR_WANTRCVD musi być dodana nowa flaga warstwy gniazd - PR_IMPL0PCL. W funkcji sosend, jeśli procedura wołająca podaje adres przeznaczenia, flaga ta umożliwia wykonanie sendto dla nie połączonego gniazda. Umożliwia ona rów­nież wystawienie żądania P RU_S E N D_E 0 F zamiast P RU_S E N D, jeśli podana jest flaga MSG_E0F.

Zmianą pokrewną do modyfikacji struktury protosw, nie wymaganą przez T/TCP, jest dodanie definicji funkcji zwanej tcp_sysctl w charakterze członu struktury pr_sysctl. Umożliwia to administratorowi systemu modyfikowanie wartości niektórych zmiennych kontrolujących działanie TCP przy pomocy programu sysctl z przedrostkiem n e t . i n e t . tcp. (Kod N et/3 przedstawiony w tomie 2 umożliwia jedynie kontrolę niektórych zmiennych IP, ICMP i UDP przy pomocy

Page 123: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 8.4 Blok kontrolny TCP 101

programu sysctl. Kontrola ta jest realizowana poprzez funkcje ip_sysctl,

i cmp_sysctl i udp_sysctl .) Funkcję tcp_sysctl pokazujemy na rysunku 12.6.

8.4 Blok kontrolny TCPDo bloku kontrolnego TCP, czyli do struktury tcpcb pokazanej na rysunku 8.3, dodane zostają cztery nowe zmienne.

Zmienna Typ Opis

t _ d u r a t i on

t_m a x o p d

c c _ s e n d

c c _ r e c v

u _ lo n g

u _ s h o r t

t c p _ c c

t c p _ c c

czas trwania połączenia w jednostkach 500 milisekundowych

MSS plus długość zwykłych opcji

wartość CC, która będzie wysłana do partnera

warlość CC otrzymana od partnera

Rysunek 8.3 Nowe człony struktury tcpcb dodane z T/TCP

Zmienna t_durati on jest konieczna, by stwierdzić, czy T/TCP może skrócić stan TIME_WAIT, tak jak to omawialiśmy w rozdziale 4.4. Gdy powstaje blok kontrol­ny, zmienna ta otrzymuje wartość początkową równą 0 i następnie jest zwiększa­na co 500 ms przez funkcję tcp_sl owti mo (rozdział 8 .6).

Zmienna t_maxopd została stworzona dla wygody. Jest równa sumie wartości członu t_maxseg oraz liczby bajtów zajmowanych przez opcje TCP. t_maxseg to liczba bajtów danych w segmencie. Na przykład w sieci Ethernet z wartością MTU równą 1500 bajtów - jeśli znaczniki czasu oraz opcje T/TCP są używane - t_maxopd jest równa 1460, a wartość t_maxseg 1440. Różnica 20 bajtów pomiędzy tymi dwiema wartościami odpowiada 12 bajtom opcji znacznika czasu plus 8 bajtów opcji CC (rysunek 2.4). Zmienne t_maxopd i t_maxseg są wyznaczane i zapisywane przez funkcję tcp_mssrcvd.

Ostatnie dwie zmienne z rysunku 8.3 pochodzą z RFC 1644 i przykłady użycia tych zmiennych były pokazane w rozdziale 2. Jeśli połączenie zostało nawiązane z użyciem opcji CC przez oba hosty, wartość cc_recv będzie niezerowa.

Sześć nowych flag zostaje zdefiniowanych i umieszczonych w członie t_fl ags bloku kontrolnego TCP. Flagi te zostały pokazane na rysunku 8.4 i są uzupełnie­niem flag przedstawionych na rysunku 24.14 na stronie 834 w tomie 2.

t _ f 1 ag s Opis

TF_SENDSYN

TF_SENDF1 N

TF_SENDCCNEW

TF_N0PUSH

wysłać SYN (ukryta flaga stanu dla połączenia połowicznie zsynchronizowanego)

wysłać FIN (ukryta flaga stanu)

wysłać opcję CCnew zamiast CC dla aklywego otwarcia

nie wysyłać segmentu tylko w celu opróżnienia bufora wysyłkowego

TF_RC/D_CC

TF_RE0_CC

ustawiona, gdy partner przysyła opcję CC w segmencie SYN

opcja CC jest lub będzie żądana w segmencie SYN

Rysunek 8.4 Nowe flagi w członie t _ f l a g s - wprowadzone wraz z T/TCP

Page 124: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

102 Implementacja TłTCP: przegląd TCP Rozdział 8

Nie należy mylić flagi T/TCP TF_SENDFIN, która oznacza, że TCP ma wysłać segment FIN, z istniejącą flagą T F_S ENTFIN, która oznacza, że segment FIN został już wysłany.

Nazwy TF_SENDSYN i T F _ S EN DF IN pochodzą z implementacji T /T C P Boba Bradena.W implementacji FreeBSD nazwy te zostały zmienione na TF_NEEDSYN i TF_NEEDF1 N.. Wybraliśmy wcześniej wymienione wersje nazw, ponieważ nowe flagi oznaczają, że odpowiednie flagi kontrolne (SYN i FIN) muszą być wysłane, podczas gdy nazwy w wer­sji FreeBSD niepoprawnie implikują, że flaga SYN lub FIN powinna być otrzymana. Należy jednak pamiętać, że przy takim wyborze nazw, nazwy flagi T /T C P TF_SENDF INi istniejącej flagi TF_SENTFIN (która oznacza, że moduł TCP wysłał już FIN) różnią się tylko jednym znakiem.

Flagi TF_N0PUSH i TF_SENDCCNEW omawiamy w następnym rozdziale i przedstawiamy je odpowiednio na rysunkach 9.3 i 9.7.

8.5 Funkcja tcpjnitNie jest wymagana jawna inicjacja żadnej ze zmiennych T/TC P i funkcja tcp_i n i t pozostaje nie zmieniona. Zmienna globalna tcp_ccgen jest niezainicjo- wana zmienną zewnętrzną i otrzymuje wartość domyślną 0, zgodnie z regułami języka C. Jest to poprawne, ponieważ makroinstrukcja CC_INC, zdefiniowana w rozdziale 8.2, inkrementuje tę zmienną zanim zostanie ona użyta, tak że pierw­sza wartość tcp_ccgen po przeładowaniu komputera wynosi 1.

Protokół T/TC P wymaga również, by pamięć TAO została opróżniona w trakcie przeładowania. Warunek ten jest spełniony niejawnie - tablica rutowania IP zosta­je zainicjowana po przeładowaniu. Za każdym razem, gdy nowa struktura rtent ry dodawana jest do tablicy rutowania, funkcja rtrequest inicjuje strukturę warto­ścią domyślną równą 0. Oznacza to, że trzy zmienne TAO w strukturze rmxp_ta o (rysunek 6.3) otrzymują wartości domyślne 0. Wartość początkowa równa 0 jest wymagana przez T/TCP dla zmiennej tao _cc , gdy dla nowego hosta powstaje nowy wpis TAO.

8.6 Funkcja tcp_slowtimoDo każdej z dwóch funkcji obsługi czasu w TCP dodana zostaje jedna linia kodu. Przy każdym odwołaniu do funkcji t c p_s 1 owt i mo (pokazanej na stronach 852-853 tomu 2) wartość członu t_durati on w każdym bloku kontrolnym TCP zostaje zwiększona o 1. Odwołania takie następują co 500 ms. Pomiędzy liniami 94 i 95 na stronie 853 tomu 2. dodana zostaje następująca linia:

tp->t_duration++;

Zadaniem zmiennej t_durati on jest pomiar czasu trwania połączenia w jedno­stkach równych 500 ms. Jeśli połączenie jest krótsze niż MSL, stan TIME_WAIT może zostać skrócony, tak jak to pokazaliśmy w rozdziale 4.4.

Page 125: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 8.7 Podsumowanie 103

Również w związku z tym usprawnieniem do nagłówka <netinet/timer.h> zostaje dodana następująca stała:

#define TCPTV_TWTRUNC 8 /* Czynnik RTO używany do skrócenia TIME_WAIT */

Na rysunkach 11.17 i 11.19 zobaczymy, że gdy połączenie T/TCP zostaje aktyw­nie zamknięte i wartość t_duration jest mniejsza niż TCPTV_MSL (60 jednostek 500-milisekundowych, czyli 30 sekund), to czas trwania stanu TIME_WAIT jest równy czasowi oczekiwania przed powtórzeniem transmisji (RTO) pomnożone­mu przez TCPTV_TWTRUNC. W sieci LAN, gdzie RTO wynosi zwykle 3 zliczenia zegara, czyli 1,5 sekundy - stan TIME_WAIT zostaje skrócony do 12 sekund.

8.7 PodsumowanieProtokół T/TCP wprowadza dwie nowe zmienne globalne (tcp_ccgen

i tcp_do_rfcl644 ), dwa nowe człony w bloku kontrolnym TCP i pięć nowych liczników w strukturze statystycznej TCP.

Funkcja tcp_sl owtimo jest również zmodyfikowana, tak by wyznaczała czas trwania każdego połączenia TCP w jednostkach równych 500 ms. Wartość ta używana jest dla określenia, czy T/TCP może skrócić stan TIME_WAIT, gdy następuje aktywne zamknięcie.

Page 126: Biblia TCP IP Tom 3 - Uzupelnienie.pdf
Page 127: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Implementacja T/TCP: wyjście TCP9

9.1 WstępW tym rozdziale omawiamy zmiany w funkcji tcp_output wprowadzone w związku z T/TCP. Funkcja tcp_output jest wołana z wielu miejsc w TCP. Sprawdza ona, czy segment powinien być wysłany i wysyła ten segment - jeżeli jest to konieczne. Wraz z T/TCP zostają wprowadzone następujące zmiany:

• dwie ukryte flagi stanu mogą włączyć flagi TH_SY N i TH_F IN• T/TCP umożliwia wysłanie więcej niż jednego segmentu w stanie SYN_SENT,

ale tylko jeśli wiemy, że partner rozumie T/TCP• mechanizm unikania wysyłania głupich segmentów musi wziąć pod uwagę

nową flagę TF_N0 PUSH (omawiamy tę flagę w rozdziale 3.6)• mogą być wysyłane nowe opcje T/TCP - CC, CCnew i CCecho.

9.2 Funkcja tcp_output

Nowe dynamiczne zmienne lokalneW tcp_output zostają zadeklarowane dwie nowe dynamiczne zmienne lokalne:

struct rmxp_tao *taop; struct rmxp_tao tao_noncached;

Pierwsza jest wskaźnikiem do wpisu partnera w pamięci T A O . Jeśli nie istnieje odpo­wiedni wpis T A O (co nie powinno się zdarzyć), t a o p wskazuje na t a o_n oncached, a ta struktura jest zainiqowana wartością 0 (jej wartość tao_cc pozostaje więc niezdefiniowana).

Dodanie ukrytych flag stanu

Na początku tcp_output flagi TCP odpowiadające aktualnemu stanowi połącze­nia zostają wczytane z tablicy tc p_o ut f 1 a gs . Rysunek 2.7 pokazuje flagi obowią­zujące dla poszczególnych stanów połączenia. Kod przedstawiony na rysunku 9.1 dodaje do flag połączenia (w sensie logicznego OR) flagi TH_FIN i TH_SYN, jeżeli odpowiednia ukryta flaga stanu jest włączona. Ten fragment kodu znajduje się na stronach 886 i 888 w tomie 2.

Page 128: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

106 Implementacja T/TCP: wyjście TCP Rozdział 9

------------------------------------------------------------------------------------------------- tcp_output.c71 again:72 sendalot = 0;73 off = tp->snd_nxt - tp->snd_una:74 win = min(tp->snd_wnd, tp->snd_cwnd):

75 flags = tcp_outflags[tp->t_state];76 /*77 * Modyfikujemy standardowe flagi dodając SYN lub FIN - jeżeli78 * tego wymagają ukryte flagi stanu.79 */80 if (tp->t_flags & TF _SENDFIN)81 flags 1= T H _ F I N:82 if (tp->t_łlags & TF_SENDSYN )83 flags |= T H_ SY N :

--------------------------------------------------------------- tCp_OUtput.CRysunek 9.1 tcp_output - dodanie ukrytych flag stanu

tcp_output.c116 1 en = min(so->so_snd.sb_cc, win) - off;

117 if ((taop = tcp_gettaocache(tp->t_inpcb)) == NULL) (118 taop = &tao_noncached;119 bzeroCtaop, sizeof(*taop)):120 )121 /*122 * Zerujemy bit SYN, jeżeli SYN został już wysłany.123 * Segmentu SYN nie wysyłamy też, jeżeli segment zawiera dane124 * znajdujemy się w stanie SYN_SENT, a nie wiemy, czy partner125 * zna TAO.126 */127 if ((flags & TH SYN) && SEQ GT(tp->snd nxt. tp->snd una)) (128 flags &= ~ T H _ S Y N :129 off--. len++;130 if (len > 0 && tp->t_state == TCPS_SYN_SENT &&131 taop->tao_ccsent == 0)132 return (0);133 1134 if (len < 0) l

------------------------------------------------------------------------------------------------- tcp_output.cRysunek 9.2 tcp_ou tput-flaga SYN nie powinna być powtórnie wysłana

w stanie SYN_SENT

Flaga SYN nie powinna być powtórnie wysiana w stanie SYN_SENT

Kod przedstawiony na rysunku 9.2 odczytuje pamięć TAO dla partnera i spraw­dza, czy segment SYN został wysłany. Ten fragment kodu ulokowany jest na początku rysunku 26.3 na stronie 889 w tomie 2.

Odczytanie pamięci TAO117-119 Zawartość pamięci TAO dla danego partnera zostaje odczytana. Jeśli odpo­

wiedni wpis TAO nie istnieje, użyta zostaje lokalna zmienna dynamiczna tao_noncached. Jest ona zainicjowana wartością 0.

Nawet jeśli ten w pełni zerowy wpis jest używany, nie ulega on nigdy modyfikacji. Dlatego też - zamiast inicjacji za pomocą b zero - struktura t a o _ n o n c a c h e d mogłaby być alokowana statycznie i zainicjowana wartością 0.

Page 129: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 9.2 Funkcja tcp_oułput 107

Sprawdzenie, czy żądanie klienta jest większe niż MSS121 -133 Jeżeli dla danego stanu segment SYN powinien być wysłany i jeśli został już

wysłany, to flaga TH_SYN jest wyłączana. Taka sytuacja może się zdarzyć, gdy aplikacja T/TCP wysyła do partnera więcej bajtów danych niż wartość MSS (roz­dział 3.6). Jeśli partner zna T/TCP, możliwe jest wysłanie więcej niż jednego segmentu, ale tylko pierwszy z tych segmentów powinien zawierać flagę SYN. Jeśli nie wiemy, czy partner rozumie T/TCP (tao _ccsen t jest 0), to nie wysyłamy więcej niż jednego segmentu danych dopóty, dopóki potrójne uzgodnienie nie zostanie zakończone.

Unikanie wysyłania głupich segmentówRysunek 9.3 pokazuje dwie zmiany wprowadzone w kodzie implementującym mechanizmu unikania wysyłania głupich segmentów (strona 893, tom 2).

------------------------------------------------------------------------------------------------ tcp_output.c168 i f (1 en ) l169 if (len == tp->t_maxseg)170 goto send;171 if ((id1e || tp->t f 1ags & TF NODELAY) &&

(t p ->t_f 1 ags & TF_N0PUSH) == 0 &&172173 len + off >= so->so_snd.sb_cc)174 goto send:175 if (tp->t_force)176 goto send;177 if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0)178 goto send;179 if (SEQ_LT(tp->snd_nxt. tp->snd_max))180 goto send;181 )

------------------------------------------------------------------------------------------------- tcp_output.cRysunek 9.3 tcp_output-określenie, przy użyciu mechanizmu unikania wysyłania

głupich segmentów, czy należy wysłać segment

Wysłanie segmentu o normalnej wielkości169-170 Jeśli segment o normalnej (pełnej) wielkości może być wysłany, to zostaje on

wysłany.

Aplikacja może wyłączyć niejawne wypchnięcie171-174 Implementacje BSD zawsze wysyłały segment, jeżeli flaga ACK nie była

akurat spodziewana od partnera (zmienna i d 1 e miała wartość „prawda") lub jeśli algorytm Nagle był wyłączony (TF_NODELAY miała wartość „prawda") oraz moduł TCP opróżniał bufor wysyłkowy. Takie postępowanie bywa czasami nazywane niejawnym wypchnięciem (implied push), ponieważ każda próba wpisania danych do gniazda wykonana przez aplikację kończy się wysłaniem segmentu, chyba że jest to uniemożliwione przez algorytm Nagle. T/TCP udostępnia nową opcję gniazd, TCP_NOPUSH, która umożliwia wyłączenie niejawnego wypchnięcia. Opcji tej od­powiada flaga T F_N0 PU SH. Przykład zastosowania tej flagi omówiliśmy w rozdzia­le 3.6. Widzimy, że w omawianym tu fragmencie kodu segment zostaje wysłany tylko wtedy, jeśli spełnione są jednocześnie trzy następujące warunki:

Page 130: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

108 Implementacja TfTCP: wyjście TCP Rozdział 9

• flaga ACK nie jest spodziewana ( i d 1 e ma wartość „true") lub algorytm Nagle jest wyłączony,

• opcja gniazda TCP_NOPUSH nie jest włączona (sytuacja domyślna),

• TCP opróżnia bufor wysyłkowy (tzn. całe oczekujące dane mogą być wysłane w pojedynczym segmencie).

Sprawdzenie, czy okno odbiorcy jest przynajmniej połowicznie otwarte177-178 W zwykłym TCP cały ten fragment kodu nie jest wykonywany dla inicjują­

cego segmentu SYN, ponieważ 1 en wynosi 0. Przy użyciu T/TC P możliwe jest jednak wysłanie danych przed otrzymaniem flagi SYN od partnera. Oznacza to, że sprawdzenie, czy okno odbierającego hosta jest teraz połowicznie otwarte, musi być oparte na warunku, czy wartość max_sndwnd jest większa niż 0. Zmienna ta podaje maksymalny rozmiar okna partnera, ale wynosi ona 0, dopóki informacjao rozmiarze okna nie zostanie otrzymana od partnera (tzn. dopóki nie zostanie otrzymany segment SYN).

Wyślij, jeśli upłynął czas oczekiwania na powtórzenie transmisji179-180 Wartość snd_nxt jest mniejsza niż snd_max, jeśli upłynął czas oczekiwania

na powtórzenie transmisji.

Wymuszenie wysłania segmentu z flagą RST lub SYNKod w liniach 179-180 na stronie 895 w tomie 2 zawsze wysyła segment, jeżeli ustawiona była flaga SYN lub RST. Te dwie linie zostają zastąpione kodem przed­stawionym na rysunku 9.4.

------------------------------------------------------------------------------------------------ tcp_output.c207 if ((flags & T H_RST) II208 ((flags & TH_SYN) (tp->t_flags & TF SENDSYN) == 0))209 goto send;

------------------------------------------------------------------------------------------------ tcp_output.cRysunek 9.4 tcp_output - sprawdzenie, czy segment ma być wysłany

w zależności od wartości flag RST i SYN.

207-209 Segment zawsze zostaje wysłany, jeżeli ustawiona jest flaga RST. Jeśli jed­nak została ustawiona flaga SYN, segment może być wysłany tylko wtedy, gdy odpowiednia ukryta flaga jest wyłączona. Przyczynę tego ostatniego ograniczenia widzimy na rysunku 2.7. Flaga TF_SENDSYN jest włączona dla ostatnich pięciu, spośród siedmiu, stanów z gwiazdką (stany połowicznie zsynchronizowane), co powoduje włączenie flagi SYN przez kod przedstawiony na rysunku 9.1. Rolą tego testu w tcp_output jest wysłanie segmentu tylko w stanach SYN_SENT, SYN_RCVD, SYN_SENT* i SYN_RCVD*.

Wysłanie opcji MSSWprowadzamy drobną zmianę w kodzie przedstawionym na stronie 908 w tomie 2. Funkcja N et/3 tcp_mss (z dwoma argumentami) zostaje zastąpiona funkcją

Page 131: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 9.2 Funkcja tcp_output 109

t c p_m s s s e n d (z jednym tylko argumentem - 1 p). Dzieje się tak, ponieważ musimy rozróżnić pomiędzy obliczeniem wartości MSS, która ma być wysłana, a przetwa­rzaniem otrzymanej opcji MSS. Funkcja tcp_mss w kodzie N et/3 pełniła obie te role. Protokół T/TCP używa dwóch różnych funkcji - tcp_msssend i tcp_ms s rcvd. Funkcje te przedstawiamy w następnym rozdziale.

Wysłać opcję znacznika czasu?Na stronie 909 w tomie 2 widać, że opcja znacznika czasu zostaje wysłana, jeśli spełnione są następujące trzy warunki:

• konfiguracja TCP przewiduje żądanie opcji znacznika czasu,• tworzony segment nie zawiera flagi RST,• wykonujemy aktywne otwarcie lub moduł TCP otrzymał opcję znacznika cza­

su od hosta na drugim końcu połączenia (TF_RCVD_TSTMP).

Z aktywnym otwarciem mamy do czynienia, jeżeli flaga SYN jest włączona, a flaga ACK wyłączona. Kod T/TCP sprawdzający trzy wspomniane warunki przedsta­wiony został na rysunku 9.5.

------------------------------------------------------------------------------------------------ tcp_output.c283 /*284 * Wysyłamy znacznik czasu i odpowiedź "echo", jeżeli jest to SYN285 * i chcemy używać znaczników czasu (TF_REQ_TSTMP jest ustawiona)286 * lub zarówno my jak i nasz partner wysłaliśmy znaczniki287 * czasu w segmentach SYN.

*/288 if ((t p ->t_f1ags 4 (TF_REQ_TSTMP | TF_N00PT)) == TF_REQ_TSTMP 44289 (flags 4 T H_RST) = 0 44290 ((flags & TH_ACK) == 0 |I291 (tp ->t_f1ags & TF_RCVD_TSTMP))) {

------------------------------------------------------------------------------------------------ tcp_output.cRysunek 9.5 tcp_output - czy wystać opcję znacznika czasu?

283-291 Pierwsza połowa trzeciego testu ulega zmianie dla T/TCP, ponieważ chce­my wysyłać znaczniki czasu we wszystkich początkowych segmentach przesyła­nych od klienta do serwera (w przypadku wielosegmentowego żądania - patrz rysunek 3.9), a nie tylko w pierwszym segmencie zawierającym SYN. Nowym testem dla wszystkich tych początkowych segmentów jest sprawdzenie braku flagi ACK.

Wysłanie opcji CCPierwszym warunkiem wysłania jednej z trzech opcji CC jest to, by flaga TF_REQ_CC była włączona (flagę tę włącza tcp_newtcpcb, jeśli zmienna globalna tcp_do_rfcl644 jest różna od zera), flaga TF_N00PT wyłączona i by segment nie zawierał flagi RST. Która konkretnie opcja CC będzie wysłana, zależy to od usta­wienia w tworzonym segmencie flag SYN i ACK. Są cztery możliwe kombinacje, dwie z nich pokazujemy na rysunku 9.6. (Przedstawiony kod powinien być umie­szczony pomiędzy liniami 268-269 na stronie 909 tomu 2.)

Page 132: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

110 Implementacja T/TCP: wyjście TCP Rozdział 9

Flaga TF_N00PT jest kontrolowana przez opcję gniazda TCP_N00PT. Opcja ta pojawiła się w kodzie przedstawionym przez Thomasa Skibo w RFC 1323 (rozdział 12.7). Jak wspo­mniano w tomie 2, flaga TF_N00PT (ale nie opq'a gniazda) obecna była w kodzie Berkeley od czasów 4.2BSD, ale zwykle nie było sposobu, by flagę tę włączyć. Jeśli flaga ta jest ustawiona, TCP nie wysyła żadnych opqi w segmencie SYN. Opcja TCP_NOOPT została dodana po to, by umożliwić funkcjonowanie T /T C P w kontakcie z implementacjami TCP, które nie są zgodne ze specyfikacją i nie ignorują nieznanych opcji TCP ( RFC 1323 wprowadza dwie nowe opcje TCP).T /T C P nie zmienia kodu, który określa, czy opcja MSS powinna zostać wysłana (strona 908, tom 2). Ten kod nie wysyła opcji MSS, jeżeli flaga TF_N00PT jest ustawiona. Bob Braden stwierdza jednak w RFC 1323, że nie ma w istocie przyczyny, dla której opcja MSS nie powinna być wysyłana. Opcja MSS uwzględniona była w oryginalnej specyfikacji zawartej w RFC 793.

------------------------------------------------------------------------------------------------ tcp_output.c299 /*300 * Wysłana zostaje jedna z opcji CC, jeżeli chcemy używać opcji CC301 * (TF_REQ_CC), opcje są dozwolone (!TF_N00PT) i nie jest to RST.302 */303 if ((tp->t_f1ags i (TF_REQ_CC | TF_N00PT)) == TF_REQ_CC &&304 (flags & TH_RST) = 0) (305 switch (flags & (TH_SYN | T H_ACK)) (306 /*307 * Jest to normalne ACK (nie SYN);308 * wysyłamy CC, jeżeli otrzymaliśmy CC od partnera.309 */310 case TH_ACK:311 if (!(tp->t_flags & TF_RCVD_CC))312 break;313 /* na koniec bloku */

314 /*315 * Możemy tu dostać się tylko w stanie SYN_SENT* protokołu T/TCP,316 * gdy wysyłamy segment inny niż SYN bez czekania na ACK naszego317 * segmentu SYN. Wcześniej w tej funkcji sprawdziliśmy, że robimy318 * to tylko, jeżeli partner rozumie T/TCP.319 */320 case 0;321 opt[optlen++] = TCP0PT_N0P;322 opt[optlen++] = TCP0PT_N0P;323 opt[optlen++] = TCP0PT_CC;324 optfoptlen++] = TCP0LEN_CC;325 *(u_int32_t *) 4 opt[optlen] = htonl(tp->cc_send);326 optlen += 4;327 break;-------------------------------------------------------------------------------------------------tcp_output.cRysunek 9.6 tcp_output-wysłanie jednej z opcji CC, część pierwsza

Brak flagi SYN, flaga ACK ustawiona310-313 Jeśli flaga SYN jest wyłączona, a flaga ACK włączona, mamy do czynienia

z normalnym potwierdzeniem (tzn. połączenie jest nawiązane). Opcja CC zostaje wysłana tylko wtedy, jeśli partner przysłał opcję CC.

Brak flagi SYN, flaga ACK wyłączona314-320 Obie flagi mogą być wyłączone tylko w stanie SYN_SENT*, kiedy wysyła­

my segment bez flagi SYN, zanim połączenie zostanie nawiązane. Oznacza to, że klient wysyła więcej danych niż może się zmieścić w jednym segmencie (liczba bajtów danych większa niż MSS). Kod przedstawiony na rysunku 9.2 zapewnia, że

Page 133: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 9.2 Funkcja tcp_output 111

sytuacja taka może się zdarzyć tylko wtedy, jeżeli partner rozumie T/TCP. Skoro tak, to opcja CC zostaje wysłana.

Utworzenie opcji CC321 -327 Opcja CC zostaje utworzona. Poprzedzona jest ona dwoma rozkazami pu­

stymi (NOP). Wartość cc_send dla tego połączenia zostaje wysłana w opcji CC.

Klauzule case odpowiadające pozostałym dwóm kombinacjom flag SYN i ACK pokazane są na rysunku 9.7.

------------------------------------------------------------------------------------------------ tcp_output.c328 /*329 * Jest to nasz inicjujący SYN (czyli klient wykonuje aktywne330 * otwarcie). Sprawdzamy, czy wysłać CC. czy CCnew.331 */332 case T H _ S Y N :333 opt[optlen++] = TCPOPT_NOP;334 opt[optlen++] = TCP0PT_N0P;335 opt[optlen++] =336 (tp->t_f1ags & TF_SENDCCNEW) ? TCP0PT_CCNEW : TCP0PT_CC;337 opt[optlen++] = TCP0LEN_CC;338 *(u_int32_t *) & opttoptlen] = htonl(tp->cc_send);339 optlen += 4;340 break;

341 /*342 * Jest to segment z SYN i ACK (odpowiedź serwera na aktywne343 * otwarcie wykonane przez klienta). Wysyłamy CC i CCecho,

* jeżeli otrzymaliśmy od partnera if CC lub CCnew.344 */345 case (TH_SYN | TH _ A C K ) :346 if (tp->t_f1ags & TF_RCVD_CC) (347 opt[optlen++] = TCP0PT_N0P;348 opttoptlen++] = TCP0PT_N0P;349 opt[optlen++] = TCP0PT_CC;350 opt[optlen++] = TCP0LEN_CC;351 *(u_int32_t *) & opt[optlen] = htonl(tp->cc_send);352 optlen += 4;

353 opt[optlen++] = TCP0PT_N0P;354 opt[optlen++] = TCP0PT_N0P;355 opt[optlen++] = TCP0PT_CCECH0;356 opt[optlen++] = TCP0LEN_CC;357 *(u_int32_t *) & opt[optlen] = htonl(tp->cc_recv);358 optlen += 4;359 I360 break;361 }362 }363 hdrlen += optlen;

------------------------------------------------------------------------------------------------ łcp_output.cRysunek 9.7 tcp_output-wysłanie jednej z opcji CC, część druga

Flaga SYN włączona, brak flagi ACK (aktywne otwarcie wykonane przez klienta)328-340 Flaga SYN jest włączona i brak jest flagi ACK - klient wykonuje aktywne

otwarcie. Kod przedstawiony na rysunku 12.3 ustawia flagę T F_SENDCCNEW, jeśli powinna być wysłana opcja CCnew zamiast opcji CC, i również ustala wartość cc_send.

Page 134: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

112 Implementacja T/TCP: wyjście TCP Rozdział 9

Flagi SYN i ACK włączone (odpowiedź serwera na SYN klienta)341-360 Jeśli obie flagi, SYN i ACK, są włączone, mamy do czynienia z odpowiedzią

na aktywne otwarcie partnera. Jeżeli partner wysłał opcję CC lub CCnew (flaga TF_RCVD_CC jest ustawiona), wysyłamy wtedy opcję CC (cc_send) oraz opcję CCecho z wartością CC otrzymaną od partnera (cc_recv).

Korekta rozmiaru danych dla opcji TCP

t_maxopd to nowy człon struktury tcpcb. Określa on maksymalną długość da­nych oraz opcji w zwyłym segmencie TCP. Możliwa jest sytuacja, gdy opcje w seg­mencie SYN (rysunki 2.2 i 2.3) zajmują więcej miejsca niż opcje w segmencie innym niż SYN (rysunek 2.4), ponieważ opcja skali okna i opcje CC obecne są jednocześnie tylko w segmentach SYN. Kod przedstawiony na rysunku 9.8 kory­guje rozmiar danych przeznaczonych do wysłania, opierając się na rozmiarze opcji TCP. Przedstawiony kod zastępuje linie 270-277 na stronie 909 w tomie 2.

------------------------------------------------------------------------------------------------ tcp_output.c364 /*365 •k Korygujemy długość danych - umieszczenie opcji może zmienić366 ■k długość pakietu tak, że będzie on większy niż wynikający367 •k z t_maxopd. Zerujemy bit FIN, ponieważ obcinamy koniec368 * s egm e nt u.369 * /370 if (len + optlen > tp->t_maxopd) (371 / *372 * Nie zamykać połączenia, jeżeli pozostaje jeszcze coś do373 */374 flags &= ~T H _ F I N ;

375 len = tp->t_maxopd - optlen;376 sendalot = 1;377 )------------------------------------------------------------------------------------------------- tcp_output.cRysunek 9.8 tcp_output-korekta rozmiaru danych przeznaczonych

do wysłania w zależności od rozmiaru opcji TCP

364-377 Jeżeli rozmiar danych (1 en) plus rozmiar opcji jest większy niż t_maxopd, ilość danych do wysłania jest zmniejszana, flaga FIN wyłączana (jeśli była włączo­na), a flaga sendal ot zostaje włączona (co wymusza powtórzenie tcp_output po wysłaniu aktualnego segmentu).

Ten fragment kodu nie jest specyficzny dla T/TC P. Powinien być używany dla dowol­nych opqi TCP, które umieszczane są w segmentach zawierających dane (na przykład opq'a znacznika czasu opisana w RFC 1323).

9.3 PodsumowanieOkoło 100 linii kodu zostaje dodanych wraz z T/TCP do liczącej 500 linii funkcji tcp_output. Większa część wprowadzonych uzupełnień dotyczy wysyłania no­wych opcji T/TCP: CC, CCnew i CCecho. Dodatkowo funkcja tcp_output

z T/TCP umożliwia wysyłanie więcej niż jednego segmentu w stanie SYN_SENT, pod warunkiem, że partner rozumie T/TCP.

Page 135: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Implementacja T/TCP: funkcje TCP10

10.1 WstępW niniejszym rozdziale omawiamy kilka różnych funkcji TCP ulegających zmia­nom przy wprowadzeniu T/TCP. Zajmiemy się tu funkcjami, które nie są omó­wione w innych rozdziałach. W poprzednim rozdziale opisaliśmy zmiany w funk­cji tcp_output, w następnych dwóch przedstawimy funkcje tcp_input

i tcp_usrreq. W tym rozdziale definiujemy dwie nowe funkqe - tcp_rtl ookup i tcp_gettaocache, które przeszukują pamięć TAO.

Funkcja tcp _cl ose zostaje zmodyfikowana, tak by dla połączenia, które używało T/TCP, zachowane zostały w tablicy rutowania oszacowane wartości średniego czasu przesłania pakietu w obie strony oraz średniego odchylenia od tej średniej wartości. W normalnym przypadku wartości te są określone i zapamiętane jedynie wtedy, gdy przynajmniej 16 segmentów o pełnym rozmiarze było przesłanych w czasie połączenia. T/TCP zwykle przesyła jednak znacznie mniej danych, a mi­mo to wspomniane wartości powinny być oszacowane i zachowane na podstawie różnych połączeń z tym samym partnerem.

Opcja MSS jest również inaczej przetwarzana w T/TCP. Z jednej strony zmiany polegają na zastąpieniu jednej, zbyt uniwersalnej funkq'i kodu N et/ 3, t c p_ms s, dwie­ma oddzielnymi funkcjami. Jedna z tych funkcji (tcp_msssend) oblicza wartość MSS przeznaczoną do wysłania, druga funkcja (t c p_ms s r c vd) przetwarza otrzymaną opcję MSS. T/TCP zapisuje również ostatnio otrzymaną od partnera wartość MSS w pamięci TAO. W ten sposób wysyłana opcja MSS może zostać zainicjowana, gdy T/TC P wysyła dane w segmencie SYN, przed otrzymaniem SYN i MSS od serwera.

Funkcja tcp_doopti ons z kodu N et/3 zostaje zmieniona, tak by rozpoznawała trzy nowe opcje T/TCP: CC, CCnew i CCecho.

Funkcja ta jest wołana, gdy żądanie PRU_ATTACH tworzy nowe gniazdo. Pięć linii kodu na rysunku 10.1 zastępuje linie 177-178 na stronie 865 w tomie 2.

10.2 Funkcja tcp_newtcpcb

tcp_subr.c180 tp->t_maxseg = tp->t_maxopd = tcp_mssdflt:

181182183184

if (tcp_do_rfcl323)tp->t_f1ags = (TF_REQ_SCALE | TF_REQ_TSTMP);

if (tcp_do_rfcl644)tp->t_f1ags |= TF_REQ_CC:

tcp_snbr.cRysunek 10.1 Funkcja tcp_new tcpcb-zm iany związane z T/TCP

Page 136: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

114 Implementacja T/TCP: funkcje TCP Rozdział 10

180 Tak jak wspomnieliśmy przy okazji omawiania rysunku 8.3, t_maxopd jest równa maksymalnej liczbie bajtów danych i opcji TCP wysyłanych w każdym segmencie. Zmienna ta, podobnie jak t_maxseg, otrzymuje wartość domyślną równą 512 (tcp_mssdfl t). Z faktu, że obie zmienne są równe, wynika założenie, że żadne opcje TCP nie są wysyłane w segmencie. Na pokazanych dalej rysunkach 10.13 i 10.14 zobaczymy, że t_maxseg zostaje zmniejszona, jeśli opcja znacznika czasu lub opcja CC (lub obie te opcje) mają być wysłane w każdym segmencie.

183-184 Jeśli globalna zmienna tcp_do_rfcl644 jest niezerowa (wartość domyślna tej zmiennej wynosi 1), ustawiona zostaje flaga T F _ R E Q _ C C , co powoduje wysłanie przez funkcję tcp_output w segmencie SYN opcji CC lub też CCnew (rysunek 9.6).

10.3 Funkcja tcp.rtlookupPierwszą operacją wykonywaną przez tcp_ms s (strona 936, tom 2) jest wczytanie marszruty zachowanej dla aktualnego połączenia (przechowywanej w członie i np_route internetowego bloku PCB). Jeżeli marszruta dla tego połączenia nie została jeszcze znaleziona, wywołuje się funkcję r ta l lo c . Operacja wczytania marszruty jest teraz (po zmianach związanych z T/TCP) umieszczona w oddziel­nej funkcji tcp_rtl ookup pokazanej na rysunku 10.2. Dzieje się tak, ponieważ operacja ta jest wykonywana częściej w T/TCP - wpis w tablicy rutowania zawiera bowiem również informacje TAO.

438-452 Jeżeli marszruta dla danego połączenia nie jest jeszcze wyznaczona, mar­szrutę znajduje funkcja r t a 11 o c . Marszruta może jednak zostać wyznaczona tylko wtedy, jeżeli adres partnera w bloku PCB jest niezerowy. Dlatego przed wywoła­niem rtal 1 oc wypełniona zostaje struktura sockaddr_i n, należąca do struktury route.

Na rysunku 10.3 przedstawiamy strukturę r o u t e. W każdym internetowym bloku PCB zawarta jest jedna taka struktura. Rysunek 10.4 schematycznie ilustruje te struktury. Przyjęto, że adres partnera jest 128.32.33.5.

------------------------------------------------------------------------------------------------- tcp_subr.c432 struct rtentry *433 tcp_rtlookup(inp)434 struct inpcb *inp;435 (436437

438439440441442443444445446447448449

struct route *ro; struct rtentry *rt;

ro = &inp->inp_route; rt = ro->ro_rt; if (rt == NULL) I

/* Brak marszruty, próbujemy znaleźć marszrutę */ if (inp->inp_faddr.s_addr != INADDR_ANY) (

ro->ro_dst.sa_family = A F_INET: ro->ro_dst.sa_len = sizeof(ro->ro_dst);((struct sockaddr_in *) &ro->ro_dst)->sin_addr =

i np->i n p_faddr; rtalloc(ro); rt = ro->ro_rt;

)

Page 137: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 10.4 Funkcja tcp_gettaocache 115

450 )451 return (rt);452 )

------------------------------------------------------------------------------------------------- tcp_subr.cR ysunekl0.2 Funkcja tcp_rtlookup

------------------------------------------------------------------------------------------------- route.h46 struct route (47 struct rtentry *ro_rt; /* wskaźnik do struktury z informacjami */48 struct sockaddr ro_dst; /* adres przeznaczenia dla tej marszruty */49 J :

------------------------------------------------------------------------------------------------- route.hRysunek 10.3 Struktura route

inpcbO

Rysunek 10.4 Marszruta przechowywana w internetowym bloku PCB

10.4 Funkcja tcp_gettaocacheInformacja TAO dla danego hosta jest przechowywana we wpisie do tablicy rutowania dla tego hosta, a dokładniej w polu rmx_f i ller struktury rtjnetri cs (rozdział 6.5). Pokazana na rysunku 10.5 funkcja tcp_gettaocache zwraca wskaźnik do informacji TAO dla danego hosta.

Page 138: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

116 Implementacja T/TCP: funkcje TCP Rozdział 10

------------------------------------------------------------------------------- ------------------ tcp_subr.c458 struct rmxp_tao *459 tcp_gettaocache(inp)460 struct inpcb *inp;461 {462 struct rtentry *rt = tcp_rtlookup(inp);

463 /* Upewniamy się, że jest to aktywna marszruta do hosta. */464 if (rt == NULL ||465 (rt ->rt_f1ags & (RTFJJP | RTF_H0ST)) != (RTF_UP I RTF_H0ST))466 return (NULL);

467 return (rmx_taop(rt->rt_rmx));468 )

------------------------------------------------------------------------------------------------ tcp_subr.cRysunek 10.5 Funkcja tcp_gettaocache

460-468 Funkcja tcp_rtl ookup zwraca wskaźnik do odpowiadającej partnerowi struktury r t e n t ry . Jeśli funkcja tcp_rtlookup zostaje wykonana pomyślnie i jeśli flagi RTFJJP i RTF_H0ST są włączone, to makroinstrukcja rmx_taop (rysunek 6.3) zwraca wskaźnik do struktury rmxp_tao.

10.5 Obliczenie czasu oczekiwania na powtórzenie transmisjiTCP w N et/3 oblicza czas oczekiwania na powtórzenie transmisji (RTO) przez pomiar czasu przesłania segmentów danych w obie strony i przez śledzenie „wy­gładzonego" (smoothed) oszacowania RTT (srtł) i „wygładzonego" średniego od­chylenia (rttvar). Średnie odchylenie jest dobrą estymatą średniego odchylenia standardowego i jest łatwiejsze do obliczenia niż średnie odchylenie standardowe, ponieważ nie wymaga obliczania pierwiastka kwadratowego. W pracy [Jacobsen 1988] podane zostały dodatkowe szczegóły pomiarów RTT, co doprowadziło do sformułowania następujących równań:

delta = data - srtt

srtt«- srtt + g x delta

rttvar <— rttvar + h ( I delta I - rttvar)

RTO = srtt + 4 x rttvar

gdzie delta jest różnicą pomiędzy właśnie zmierzonym czasem przesłania w obie strony (data) i aktualną „wygładzoną" estymatą RTT (srtt), g - czynnikiem-wzmoc- nieniem dla RTT, równym 1 /8 , h - wzmocnieniem dla estymaty średniego odchy­lenia równym 1 /4 . Oba wzmocnienia i czynnik 4 użyty przy obliczeniu RTO nie bez przyczyny są (pod)wielokrotnościami 2 - mogą być obliczone przy zastosowa­niu operacji przesuwania, zamiast mnożenia lub dzielenia. W rozdziale 25 tomu 2 przedstawiono dokładniej, jak te wartości są wyznaczane i przechowywane przy użyciu stałopozycyjnych liczb całkowitych.

W zwykłym połączeniu TCP estymaty srtt i rttvar mogą być wyznaczone na podstawie wielu zmierzonych wartości RTT. W przypadku minimalnego połącze­nia TCP przedstawionego na rysunku 1.9, dysponujemy przynajmniej dwoma

Page 139: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 10.5 Obliczenie czasu oczekiwania na powtórzenie transmisji 117

wartościami RTT. Ponadto w pewnych okolicznościach N et/3 będzie przechowy­wać i wykorzystywać te dwie estymaty dla różnych połączeń pomiędzy tymi samymi hostami. Wartości te aktualizuje i zapisuje funkcja tcp_c1 ose, wołana, gdy połączenie zostaje zamknięte, jeżeli przynajmniej 16 segmentów zostało otrzy­manych w ramach tego połączenia i jeżeli wpis w tablicy rutowania dla partnera nie jest wpisem domyślnym. Estymaty zostają zapisane w członach rmx_rtt

i rmx_rttvar struktury rt_metrics znajdującej się w tablicy rutowania. Przy inicjacji nowego połączenia obie estymaty, srtt i rttvar, otrzymują wartości począt­kowe odczytane z wpisu w tablicy rutowania przy pomocy funkcji tcp_mss rcvd (rozdział 10.8).

W przypadku połączeń T/TCP problem polega na tym, że najkrótsze połączenie umożliwia zmierzenie tylko jednej wartości RTT, a ponieważ zwykle przesyła­nych jest mniej niż 16 segmentów, wartości estymat nie są przechowywane pomię­dzy różnymi połączeniami dla tych samych partnerów. Oznacza to, że T/TCP nigdy nie może określić dobrej estymaty RTO dla pierwszego wysyłanego seg­mentu. Rozdział 25.8 w tomie 2 pokazuje, w jaki sposób inicjacja dokonana przez tcp_newtcpcb powoduje, że pierwsza wartość RTO wynosi 6 sekund.

Spowodowanie, by funkcja tcp_cl ose przechowywała „wygładzone" estymaty dla połączeń T/TCP nie jest trudne - nawet gdy odebrano mniej niż 16 segmentów (odpowiednie modyfikacje pokażemy w rozdziale 10.6). Trudność polega na tym, że nie jest jasne jak, w spójny sposób dołączyć nowe estymaty do wartości estymat otrzymywanych metodą standardową. Niestety, problem ten nie został jeszcze rozwiązany [Paxson 1995a].

Przeanalizujmy rysunek 10.6, by poznać różne możliwości. Sto 400-bajtowych diagramów UDP zostało wysłanych przez Internet od jednego z hostów autora do serwera echa w innym komputerze. Próba została wykonana w godzinach popo­łudniowych w zwykłym dniu roboczym - jest to zwykle czas największego natę­żenia ruchu w Internecie. Zwrócone zostały 93 datagramy (7 zaginęło gdzieś w Internecie). Na rysunku 10.6 pokazujemy pierwszych 91 zwróconych datagra- mów. Próby wykonano w 30-minutowym przedziale czasu i odstępy czasu pomię­dzy wysłaniem poszczególnych datagramów były jednolicie przypadkowo rozło­żone w przedziale od 0 do 30 sekund. Wartości RTT zostały otrzymane przy pomocy programu Tcpdump uruchomionego w komputerze klienta. Kropki na rysunku przedstawiają zmierzone wartości RTT. Trzy linie ciągłe (RTO, srtt i rttvar, od górnej do dolnej) odpowiadają wartościom wyznaczonym przy pomo­cy wzorów przedstawionych na początku obecnego podrozdziału. Obliczenia zostały wykonane w arytmetyce zmiennoprzecinkowej, a nie przy pomocy stało- pozycyjnych liczb całkowitych używanych w N et/3. Każda wartość RTO pokaza­na na rysunku została obliczona przy użyciu wartości zmierzonej odpowiadającej danemu punktowi. To znaczy, wartość RTO pierwszego punktu (około 2200 ms) jest obliczona używając pierwszego punktu danych - ta wartość RTO zostałaby użyta dla następnego wysyłanego segmentu.

Page 140: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

118 Implementacja T/TCP: funkcje TCP Rozdział 10

Rysunek 10.6 Pomiar RTT i odpowiadające wartości RTO, srtt i rttvar

Choć zmierzone RTT wynosi średnio nieco mniej niż 800 ms (system pełniący rolę klienta jest połączony z Internetem przez telefoniczne łącze PPP, a serwer znajduje się na drugim krańcu USA), to w 26 pomiarze otrzymano wartość niemal 1400 ms, a kilka następnych wartości układa się w pobliżu 1000 ms. Jak zauważono w pracy [ Jacobson 1994], „jeśli istnieją połączenia jednocześnie używające tej samej ścieżki, chwilowe fluktuacje RTT rzędu podwojonej wartości minimalnej są zupełnie nor­malne (odpowiadają one nawiązywaniu lub odnawianiu innych połączeń po ich przerwaniu), tak więc wartość RTO nie powinna nigdy być mniejsza niż 2 x RTT."

W momencie gdy nowe wartości estymat mają być zapisane w tablicy rutowania, trzeba podjąć decyzję, jak duży ma być wpływ nowo otrzymanych wartości na wartości przechowywane. Używane są tu wzory:

savesrtt = g x savesrtt + (1-g) x srtt

saverttvar = g x saverttvar + (1-g) x rttvar

Wzory te mają charakter filtru dolno-przepustowego, ze stałą g wzmocnienia filtru zawartą w przedziale od 0 do 1, a savesrtt i saverttvar są wartościami wpisywanymi do tablicy rutowania. Gdy N et/3 uaktualnia wpis w tablicy rutowania używając tych wzorów (w momencie gdy połączenie zostaje zamknięte i przynajmniej 16 wartości RTT zostało zmierzonych), używane jest wzmocnienie równe 0,5: nowa wartość wpisana do tablicy rutowania równa się sumie połowy nowej wyznaczo­

Page 141: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 10.5__________Obliczenie czasu oczekiwania na powtórzenie transmisji 119

nej wartości i połowy wartości wcześniej przechowywanej. W kodzie T/TC P Boba Bradena używane jest natomiast wzmocnienie równe 0,75.

Na rysunku 10.7 przedstawione zostało porównanie wyników zwykłych obliczeń wykonywanych przez TCP (rysunek 10.6) i wartości otrzymanych przy użyciu wzmocnienia 0,75. Trzy kropkowane linie prezentują trzy zmienne z rysunku 10.6 (poczynając od góry: RTO, srtt i rttvar). Linie ciągłe przedstawiają trzy odpowied­nie zmienne obliczone przy założeniu, że każdy punkt danych jest oddzielnym połączeniem T/TCP (jeden pomiar RTT na połączenie) i że wartości wpisane do tablicy rutowania po każdym połączeniu obliczane są ze wzmocnieniem filtra równym 0,75. Zwróćmy uwagę na różnicę: przy liniach kropkowanych zakłada się pojedyncze połączenie TCP z 91 wartościami RTT zebranymi w ciągu 30 minut, podczas gdy przy linii ciągłej zakłada się 91 oddzielnych połączeń T/TCP, każde z pojedynczym pomiarem RTT, w ciągu tego samego 30-minutowego okresu. Przy liniach ciągłych zakładamy również, że obie estymaty są uaktualniane w tablicy rutowania po każdym z 91 połączeń.

Rysunek 10.7 Porównanie „wygładzania" estymat RTT w TCP i T/TCP

Linie ciągłe i kropkowane dla srtt różnią się nieznacznie. Duża jest natomiast różnica pomiędzy liniami dla rttvar. Linia ciągła dla rttvar (T/TCP) leży zwykle wyżej niż linia kropkowana (pojedyncze połączenie TCP), co oznacza większy czas oczekiwania na powtórzenie transmisji w przypadku T/TCP.

Page 142: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

120 Implementacja T/TCP: funkcje TCP Rozdział 10

Istnieją inne czynniki wpływające na pomiar RTT dokonywany przez T/TCP. Z punktu widzenia klienta zmierzona wartość RTT zwykle zawiera czas przetwa­rzania pakietu przez serwera. Może też pojawić się zwłoka związana z opóźnionym potwierdzeniem (dehyed-ACK timer) wysyłanym przez serwera. W kodzie N et/3 czas oczekiwania na wysłanie opóźnionego potwierdzenia upły­wa co 200 ms, a pomiary RTT wykonywane są w jednostkach 500 ms zliczeń zegara, tak więc związane z tym opóźnienie nie powinno być duże. Również przetwarzanie segmentów T/TCP odbywa się zwykle z wykorzystaniem powol­nej ścieżki przetwarzania wejścia TCP (slow TCP input processing patii), co może spowodować zwiększenie mierzonych wartości RTT. (Różnica pomiędzy powol­ną i szybką ścieżką przetwarzania jest jednak prawdopodobnie zaniedbywalna, w porównaniu z wpływem 200 ms opóźnionych odpowiedzi.) Wreszcie - w przy­padku, gdy wartości zachowane w tablicy rutowania są „stare" (były na przykład ostatni raz uaktualnione przed godziną) - wynik aktualnego pomiaru powinien być może po prostu zastąpić wartości w tablicy rutowania w momencie, gdy transakcja zostaje zakończona (zamiast uaktualniania tych wartości).

Tak jak napisano w RFC 1644, konieczne są dalsze badania efektów dynamicznych TCP, a szczególnie sposobu wyznaczania wartości RTT w połączeniach T/TCP.

10.6 Funkcja tcp_closeW kodzie funkcji tcp _cl ose wymagana jest tylko jedna zmiana: estymaty RTT dla transakcji T/TCP muszą być uaktualniane, nawet jeśli w trakcie połączenia wy­mieniono mniej niż 16 segmentów. Uzasadniliśmy konieczność wprowadzenia tej zmiany w poprzednim podrozdziale. Odpowiedni kod przedstawiony jest na rysunku 10.8.

-----------------—---------------- -— --------------------------------------------------— tcp_subr.c252 if (SEQ_LT(tp->iss + so->so_snd.sb_hiwat * 16, tp->snd_max) &&253 (rt = inp->inp_route.ro_rt) &&254 ((struct sockaddr_in *) rt_key(r t ))->sin_addr.s_addr != INADDR_ANY) (

/* strony 932, 934 w tomie 2 */

304 } else if (tp->cc_recv != 0 &&305 (rt = inp->inp_route.ro_rt) &&306 ((struct sockaddr_in *) rt_key(rt))->sin_addr.s_addr != 1N ADDR_ANY) {307 /*308 * Dla transakcji musimy przechowywać wartości srtt i rttvar309 * nawet, jeżeli nie mamy "wystarczających” danych.310 */

311 u_long i ;

312 if ((rt->rt_rmx.rmx_locks & RTV_RTT) = = 0 ) (313 i = tp->t_srtt *314 (RTM_RTTUNIT / (PR_SL0WHZ * TCP_RTT_SCALE));315 if (rt->rt_rmx.rmx„rtt && i)316 /*317 * Filtr aktualizacji: 3/4 starej wartości plus

Page 143: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 10.7 Funkcja tcp_msssend 121

318 * 1/4 nowej. Zmieniamy skalę.319 */320 rt->rt_rmx.rmx_rtt =321 (3 * rt->rt_rmx.rmx_rtt + i) / 4;322 else323 rt->rt_rmx.rmx_rtt = i;324 1325 if ((rt->rt_rmx.rmx_locks & RTV_RTTVAR) == 0) (326 i = tp->t_rttvar *327 (RTM_RTTUNIT / (PR_SL0WHZ * TCP_RTTVAR_SCALE));328 if (rt->rt_rmx.rmx_rttvar && i)329 rt->rt_rmx.rmx_rttvar =330 (3 * rt->rt_rmx.rmx_rttvar + i) / 4;331 else332 rt->rt_rmx.rmx_rttvar = i;333 ]334 )

------------------------------------------------------------------------------------------------ tcp_subr.cRysunek 10.8 Funkcja tcp_cl os e-aktualizacja estymat RTT dla transakcji T/TCP

Aktualizacja tylko dla transakcji T/TCP304-311 Wartości zapisane w tablicy rutowania zostają uaktualnione tylko wtedy

jeśli dla danego połączenia używany jest protokół T/TCP (cc_recv jest różna od zera), odpowiedni wpis w tablicy rutowania istnieje i marszruta nie jest marszrutą domyślną. Ponadto, obie estymaty RTT zostają zaktualizowane, tylko jeżeli nie są one zablokowane (locked) (bity RTV_RTT i RTV_RTTVAR).

Aktualizacja RTT312-324 Wartość t_s rtt oznacza liczbę 500 ms zliczeń zegara pomnożoną przez 8,

a rmx_rtt jest wyrażana w mikrosekundach. Dlatego t_s rtt zostaje pomnożona przez 1 000 000 (RTM_RTTU NIT) i podzielona przez 2 (zliczenia zegara na sekundę) razy 8. Jeżeli wartość rmx_rtt już istnieje, to nowa wartość jest równa 3 /4 starej wartości plus 1 /4 nowej. Jest to wspomniane w poprzednim podrozdziale wzmoc­nienie filtra 0,75. W przeciwnym przypadku, gdy brak jest wcześniejszej wartości rmx_rtt, zapisana zostaje aktualnie wyznaczona wartość.

Aktualizacja średniego odchylenia325-334 Ten sam algorytm zostaje użyty dla estymaty średniego odchylenia. W ar­

tość ta jest również wyrażana w mikrosekundach, co wymaga zamiany jednostek- wartość t_r 11 v a r wyrażana jest w jednostkach odpowiadających liczbie zliczeń zegara pomnożonej przez 4.

10.7 Funkcja tcpjnsssendW kodzie N et/3 istnieje jedna funkcja t c p_ms s (rozdział 27.5, tom 2) wołana przez tcp_i nput, gdy przetwarzana jest opcja MSS, oraz przez tcp_output, gdy opcja MSS ma być wysłana. W kodzie rozszerzonym o T/TCP, ta istniejąca wcześniej funkcja otrzymuje nową nazwę - tcp_mss rcvd i jest wywoływana z tcp_i nput po otrzymaniu segmentu SYN (niezależnie od tego, czy segment SYN zawiera opcję MSS, czy nie, jak pokazane zostanie później na rysunku 10.18). Funkcja ta jest

Page 144: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

122 Implementacja T/TCP: funkcje TCP Rozdział 10

również wywoływana dla żądań PRU_SEND i PRU_SEND_EOF (rysunek 12.4), gdy połączenie jest niejawnie otwierane lub zamykane. Nowa funkcja tcp_msssend, którą pokazujemy na rysunku 10.9, wywoływana jest wyłącznie przez tcp _ou t - put, gdy wysłana ma być opcja MSS.

-------------------------------------------------- —----- --------------------------------------- tcp_input.c1911 int1912 tcp_msssend(tp)1913 struct tcpcb *tp:1914 (1915 struct rtentry * r t ;1916 extern int tcp_mssdflt;

1917 rt = tcp rtlookup(tp->t inpcb);1918 if (rt == N U L L )1919 return (tcp_mssdflt);

1920 /*1921 * Jeżeli istnieje wartość MTU dla tej marszruty - używamy jej1922 * Jeżeli nie - używamy MTU wysyłającego interfejsu.1923 */1924 if (rt->rt_rmx.rmx_mtu)1925 return (rt->rt_rmx.rmx_mtu - sizeoftstruct tcpiphdr));

1926 return (rt->rt_ifp->if_mtu - sizeoftstruct tcpiphdr));1927 )

------------------------------------------------------------------------------------------------- tcp_input.cRysunek 10.9 Funkcja tcp_mss send-zwrócona zostaje ivartość MSS,

która ma być wysłana iv opcji MSS

Odnalezienie wpisu w tablicy rutowania1917-1919 Tablica rutowania jest przeglądana w poszukiwaniu wpisu odpowiadają­

cego partnerowi. Jeśli taki wpis nie może być znaleziony, zwracana jest wartość domyślna równa 512 (tcp_mssdf 11). Odpowiedni wpis w tablicy rutowania po­winien zawsze zostać odnaleziony, chyba że partner jest nieosiągalny.

Zwrócenie wartości MSS1920-1926 Jeżeli tablica rutowania zawiera odpowiednią wartość MTU (w członie

rmx_mtu struktury rt_metrics - wpisana przez administratora systemu przy pomocy programu route), to wartość ta zostaje zwrócona. W przeciwnym przy­padku zwracana wartość równa się wartości MTU dla interfejsu wyjściowego pomniejszonej o 40 (na przykład 1460 dla Ethernetu). Interfejs wyjściowy jest znany, ponieważ marszruta została wyznaczona przez tcp_rtl ookup.

Innym sposobem zapisania wartości MTU w tablicy rutowania jest tzw. wyznaczenie ścieżki MTU {path MTU discovery) (rozdział 24.2, tom 1). W kodzie N et/3 metoda ta nie jest jednak jeszcze dostępna.

Działanie przedstawionej funkcji różni się od normalnego działania BSD. Kod N et/3 (strona 938 tomu 2), dla nielokalnego partnera (według funkcji i n_l ocal addr) z metryką rmx_nitu równą zero, zawsze informuje, że MSS wynosi 512 (tcp_mssdf 11).

Zadaniem opcji MSS jest poinformowanie hosta na drugim końcu połączenia, jak duży segment jest w stanie zaakceptować host wysyłający opcję. W RFC 793

Page 145: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 10.8 Funkcja tcp_mssrcvd 123

stwierdza się, że opcja MSS „informuje, jaki jest maksymalny rozmiar otrzymane­go segmentu dla modułu TCP wysyłającego ten segment". W niektórych imple­mentacjach ograniczeniem może być maksymalny rozmiar datagramu IP, który host jest w stanie odtworzyć. W większości współczesnych systemów rozsądny limit wynika jednak z wartości MTU dla interfejsu wyjściowego, ponieważ szyb­kość działania TCP istotnie maleje w przypadku fragmentacji, gdy fragmenty zaczynają być gubione.

Następujące komentarze pochodzą ze zmian w kodzie źródłowym, wprowadzo­nych na potrzeby T/TCP przez Boba Bradena: „Używanie opcji TCP wymaga, niestety, wprowadzenia istotnych zmian w BSD, ponieważ obsługa opcji MSS w tym kodzie była niepoprawna. Kod BSD zawsze wysyłał opcję MSS i dla nielo­kalnej sieci opcja ta zawierała wartość 532. Takie zachowanie wynika z niezrozu­mienia roli opcji MSS, która powinna informować wysyłającego partnera o tym, co odbierający partner jest w stanie obsłużyć. Wysyłający host powinien więc zadecy­dować, jaka wartość MSS ma być używana, biorąc pod uwagę zarówno wartość MSS, którą otrzymał, jak i ścieżkę (pcith). Jeżeli stosujemy wyznaczanie MTU (MTU discovery), ścieżka będzie prawdopodobnie miała wartość MTU większą niż 536; w takim przypadku sposób użycia opcji przez BSD zmniejsza przepustowość. Stąd procedura ta jedynie wyznacza wartość MSS, która ma być WYSŁANA: wartość MTU dla lokalnego interfejsu minus 40." (Zamiast wartości 536 w powyż­szych komentarzach powinno być 512.)

W następnym podrozdziale (rysunek 10.12) zobaczymy, że to host odbierający opcję MSS ogranicza wartość MSS do 512 bajtów, jeżeli partner nie jest lokalny.

10.8 Funkcja tcp _mssrcvdFunkcja tcp_mssrcvd jest wołana przez tcp_input po otrzymaniu segmentu SYN, a także - przy połączeniu nawiązywanym niejawnie - dla żądań P RU_S E N D i PRU_SEND_E0F. Funkcja ta jest podobna do tcp_mss, różnice są jednak na tyle duże, że musimy zaprezentować kod źródłowy całej funkcji. Główne zadanie tej funkcji to ustalenie wartości dwóch zmiennych - t_maxseg (maksymalna ilość danych wysyłanych w jednym segmencie) i t_maxopd (maksymalna ilość danych plus rozmiar opcji wysyłanych w jednym segmencie). Pierwsza część kodu przed­stawiona została na rysunku 10.10.

------------------------------------------------------------------------------------------------- tcpjnput.c1755 void1756 tcp_mssrcvd(tp, offer)1757 struct tcpcb *tp;1758 int offer;1759 (1760 struct rtentry *rt:1761 struct i fnet *i f p ;1762 int rtt, mss;1763 u_long bufs i z e ;1764 struct inpcb *inp;1765 struct socket *so;1766 struct rmxp_tao *taop;

Page 146: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

124 Implementacja T/TCP: funkcje TCP Rozdział 10

1767 int origoffer = offer;1768 extern int tcp_mssdflt;1769 extern int tcp_do_rfcl323;1770 extern int tcp_do_rfcl644;

1771 inp = tp->t_inpcb;1772 if ((rt = tcp_rtlookup(inp)) == NULL) I1773 tp->t_maxopd = tp->t_maxseg = tcp_mssdflt;1774 return;1775 )1776 ifp = rt->rt_ifp;1777 so = inp->inp_socket;

1778 taop = rmx_taop(rt->rt_rmx);1779 /*1780 * Offer == -1 oznacza, że nie otrzymaliśmy jeszcze segmentu SYN;1781 * w takim przypadku używamy wartości zachowanej.1782 */1783 if (offer == -1)1784 offer = taop->tao_mssopt;1785 /*1786 * Offer == 0 oznacza, że w segmencie SYN nie było wartości MSS1787 * oraz brak wartości zachowanej w pamięci TAO. Używamy tcp_mssdflt.1788 */1789 if (offer == 0)1790 offer = tcp_mssdflt;1791 else1792 /*1793 * Sprawdzenie sensowności: maxopd musi być na tyle duże,1794 * by w segmencie mogły znajdować się jakieś dane - nawet jeżeli1795 * użyta jest cała przestrzeń przeznaczona na opcje (40 bajtów).1796 * Jeśli nie - w tcp_output mogą się dziać dziwne rzeczy.1797 */1798 offer = max(offer, 64);1799 taop->tao_mssopt = offer;

------------------------------------------------------------------------------------------------- tcpjnput.cRysunek 10.10 Fimkcja t cp_ms srcvd, część pierwsza

Odnalezienie marszruty i informacji TAO dla partnera1771-1777 Fimkcja tcp_rtl ookup znajduje marszrutę do partnera. Jeśli z jakichś

przyczyn to się nie udaje, zmienne t_maxseg i t_maxopd otrzymują obie wartość512 (tcp_mssdfl t).

1778-1799 taop wskazuje na informacje TAO dla danego partnera zawartą w tablicy rutowania. Jeśli tcp_mssrcvd jest wywołana, ponieważ proces wywołał sendto (niejawne otwarcie połączenia, jako część żądania PRU_SEND lub PRU_SEND_E0F), zmienna offer otrzymuje wartość odczytaną z pamięci TAO. Jeśli ta wartość z pamięci TAO wynosi 0, offer otrzymuje wartość 512. Wartość w pamięci TAO zostaje uaktualniona.

Następna część funkcji pokazana na rysunku 10.11 jest taka sama jak kod przedsta­wiony na stronie 937 w tomie 2.

------------------------------------------------------------------------------------------------- tcpjnput.c1800 /*1801 * Sprawdzamy, czy istnieje początkowa wartość rtt lub rttvar.1802 * Zamieniamy jednostki: z jednostek używanych w tablicy rutowania1003 * na wielokrotność okresu powolnego zegara.1804 */1805 if (tp->t_srtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) l1806 /*

Page 147: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 10.8 Funkcja tcp_mssrcvd 125

1807 * XXX bit blokowania (lock) dla RTT oznacza, że jest to również1808 * wartość minimalna. To zmienia się z czasem.1809 */1810 if (rt->rt_rmx.rmx_locks & RTV_RTT)1811 tp->t_rttmin = rtt / (RTM_RTTUNIT / PR_SL0WHZ);1812 tp->t_srtt = rtt / (RTM_RTTUNIT / (PR_SL0WHZ * T CP _R T T_SCALE));1813 if (rt->rt_rmx.rmx_rttvar)1814 tp->t_rttvar = rt->rt_rmx.rmx_rttvar /1815 (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE));1816 else1817 /* domyślny wariant jest +- 1 rtt */1818 tp->t_rttvar =1819 tp->t_srtt * TCP_RTTVAR_SCALE / T CP_RTT_SCALE;1820 TCPT_RANGESET(tp->t_rxtcur.1821 (( t p- >t _ s r t t » 2) + tp->t_rttvar) » 1,1822 tp->t_rttmi n , TCPTV_REXMTMAX):1823 )------------------------------------------------------------------------------------------------ tcp_input.cRysunek 10.11 Funkcja tcp_m ssrcvd- inicjacja zmiennych RTT

wartościami z tablicy rutozuania

1300-1823 Jeśli brak wcześniejszych pomiarów RTT dla danego połączenia (t_s rtt wynosi 0), a metryka rmx_rtt jest niezerowa, wtedy zmienne t_s rtt, t_rttva r i t_rxtcur zostają zainicjowane wartościami z tablicy rutowania.

1806-1811 Jeślibit RTV_RTT we fladze blokowania w tablicy rutowania (routing metric lock flag) jest ustawiony, oznacza to, że wartość rmx_rtt powinna być również używana do inicjacji wartości minimalnej RTT dla tego połączenia (t_rttmin). t_rttmi n otrzymuje wartość domyślną odpowiadającą dwóm zliczeniom zegara (tick). W ten sposób administrator systemu może zmienić wartość domyślną.

Następna część funkcji tcp_mssrcvd (rysunek 10.12) ustala wartość lokalnej zmiennej dynamicznej mss.

--------------------- -— ■— —--------------------------------------------------------------- tcp_input.c1824 /*1825 * Wykorzystujemy wartość MTU dla danej marszruty, jeżeli istnieje.1826 */1827 if (rt->rt_rmx.rmx_mtu)1828 mss = rt->rt_rmx.rmx_mtu - sizeof(struct tcpiphdr);1829 else (1830 mss = ifp->if_mtu - sizeoftstruct tcpiphdr);1831 if ( !in_localaddr(inp->inp_faddr))1832 mss = mintmss, tcp_mssdf1t );1833 }1834 mss = mintmss, offer);

1835 /*1836 * t_maxopd to maksymalna długość danych ORAZ opcji w segmencie.1837 * t_maxseg to ilość danych w normalnym segmencie.1838 * Musimy przechowywać t_maxopd w uzupełnieniu do t_maxseg,1839 * ponieważ teraz każdy segment może zawierać opcje.1840 * Dlatego mamy teraz zwykle nieco mniej danych w segmencie.1841 */1842 tp->t_maxopd = mss;

------------------------------------------------------------------------------------------------- tcp_input.cRysunek 10.12 Funkcja tcp_mssrcvd-obliczenie wartości zmiennej

Page 148: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

126 Implementacja T/TCP: funkcje TCP Rozdział 10

1824-1834 Jeżeli istnieje wartość MTU związana z daną marszrutą (metryka rmx_mtu), to ta wartość jest używana. W przeciwnym razie mss oblicza się jako wartość MTU interfejsu wyjściowego minus 40. Dodatkowo, jeśli partner znajduje się w innej sieci lub - być może - w innej podsieci (zgodnie z informacją z funkcji in_l ocal addr), to maksymalna wartość mss wynosi 512 (tcp_mssdf 11). Nie sprawdza się, czy połączenie jest lokalne, jeśli wartość MTU znajduje się we wpisie do tablicy rutowania.

Ustalenie wartości t_maxopd1835-1842 t_maxopd otrzymuje wartość równą mss, czyli maksymalny rozmiar seg­

mentu, łącznie dane i opcje.

Następny fragment kodu pokazany na rysunku 10.13 zmniejsza wartość ms s o roz­miar opcji, które pojawią się w każdym segmencie.

------------------------------------------------------------------------------------------------- tcp_inpuł.c1843 /*1844 * Korygujemy mss, tak by było miejsce na opcje. Wywołanie tej funkcji1845 * następuje z końca t cp_dooptions, możemy więc użyć flag1846 * REQ/RCVD, by sprawdzić, czy opcje będą używane.1847 */1848 /*1849 * Dla T/TCP, origoffer == -1 oznacza, że nie odebrano jeszcze żadnych1850 * segmentów (tzn. klient wywołał sendto). W tym przypadku po prostu1851 * zgadujemy, w przeciwnym razie robimy to, co przed T/TCP.1852 */1853 if ((tp->t_f1ags & (TF_REQ_TSTMP | TF_N00PT)) == TF_REQ_TSTMP &&1854 (origoffer == -1 I |1855 (tp->t flags & TF_RCVD_TSTMP) == TF_RCVD_TSTMP))1856 mss - = TCP0LEN_TSTAMP_APPA;

1857 if ((tp->t_f1ags & (TF_REQ_CC | TF_N00PT)) == TF_REQ_CC &&1858 (origoffer == -1 I|1859 (t p ->t_f1ags & TF_RCVD_CC) == TF_RCVD_CC))1860 mss -= TCPOLEN_CC_APPA;

1861 y/i f (MCLBYTES & (MCLBYTES - 1)) = = 01862 if (mss > MCLBYTES)1863 mss &= -(MCLBYTES - 1):1864 #else1865 if (mss > MCLBYTES)1866 mss = mss / MCLBYTES * MCLBYTES;1867 #endif

------------------------------------------------------------------------------------------------- tcp_input.cRysunekl0.13 Funkcja tcp_mssrcvd-zmniejszenie ms s w zależności od opcji

Zmniejszenie mss, jeżeli opcja znacznika czasu będzie używana1843-1856 Wartość mss zostaje zmniejszona przez rozmiar opqi znacznika czasu

(TC P0 LE N_TSTAM P_AP P A, czyli 12 bajtów), jeżeli spełniony jest któryś z poniższych warunków:

• nasz koniec połączenia zażąda opcji znacznika czasu (TF_REQ_TSTAMP), a nie otrzymaliśmy jeszcze opcji MSS od hosta na drugim końcu połączenia (origoffer jest równe -1),

Page 149: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 10.8 Funkcja tcp_mssrcvd 127

• otrzymaliśmy opcję znacznika czasu z drugiego końca połączenia.

Tak jak zaznacza komentarz w tekście programu, drugi z warunków jest popraw­ny, ponieważ t c p_m s s r c v d jest wołana na końcu t c p_d o o p t i o n s, po przetworze­niu wszystkich opcji.

Zmniejszenie mss, jeśli używana będzie opcja CC1857-1860 Podobny algorytm może zmniejszyć wartość mss o 8 bajtów (TCPO-

LEN_CC_APPA).

Symbol APPA w wymienionych powyżej dwóch nazwach pochodzi stąd, że dodatek A (Appendix A) w RFC 1323 zawierał sugestię, by opcja znacznika czasu była poprzedzona dwoma rozkazami pustymi (NOP), tak by poprawnie umieścić w czterobajtowych grani­cach czterobajtową wartość znacznika czasu. Choć RFC 1644 zawiera dodatek A, nie ma tam nic na temat rozmieszczania opcji w czterobajtowych granicach. Jednakże poprze­dzenie każdej z trzech opq'i CC dwoma rozkazami pustymi jest sensowne - pokazaliśmy to na rysunku 9.6.

Obcięcie MSS do wielokrotności MCLBYTES1861-1867 Wartość mss jest zaokrąglona w dół do wielokrotności MCLBYTES, czyli do

rozmiaru klastra mbuf wyrażonego w bajtach (najczęściej 1024 lub 2048).

W tym fragmencie kodu w zawikłany i nieelegancki sposób usiłuje się zoptymalizować działanie programu przez używanie operacji logicznych, zamiast mnożenia i dzielenia, jeśli MCLBYTES jest wielokrotnością 2. Fragment ten wywodzi się z N e t/l i powinien zostać przeredagowany.

Na rysunku 10.14 przedstawiona została ostatnia część tcp_mssrcvd, w której ustalony zostaje rozmiar buforów wysyłkowego i odbiorczego.

Modyfikacja rozmiaru bufora wysyłkowego gniazda1868-1883 Wartości metryk rmx_sendpipe i rmx_recvpipe mogą zostać ustalone

przez administratora systemu za pomocą programu route. Zmienna bufsize otrzymuje wartość równą wartości metryki rmx_sendpi pe (jeśli metryka taka została zdefiniowana), lub równa jest aktualnej wartości ograniczenia wypełnienia (high-water mark) bufora wysyłkowego gniazda. Jeśli wartość bufsize jest mniej­sza niż mss, to wartość mss zostaje zmniejszona do wartości bufsize. (Jest to metoda na wymuszenie dla danego adresu przeznaczenia mniejszej wartości MSS niż wartość domyślna.) W przeciwnym razie wartość bufsize jest zaokrąglana w górę do najbliższej wielokrotności mss. (Rozmiar bufora gniazda powinien być zawsze wielokrotnością rozmiaru segmentu.) Górnym ograniczeniem jest wartość sb_max, która w kodzie N et/3 wynosi 262 144. Ograniczenie wypełnienia bufora gniazda ustalone zostało przez sbreserve.

Ustalenie wartości t_maxseg1884 Zmiennej t_maxseg przypisana zostaje wartość równa rozmiarowi danych

(bez zwykłych opcji), które TCP będzie wysyłać do partnera.

Page 150: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

128 Implementacja T/TCP: funkcje TCP Rozdział 10

tcp_input.c1868 /*1869 * Jeżeli istnieje "pipesize”. przyjmujemy taki właśnie rozmiar bufoi1870 gniazda. Rozmiar buforów gniazda ma być całkowitą wielokrotności;1871 mss. Jeżeli mss jest większe niż rozmiar bufora gniazda,1872 * to zmniejszamy mss.1873 * /1874 if' ((bufsize = rt->rt_rmx.rmx_sendpipe) == 0)1875 bufsize = so->so_snd.sb_hiwat;1876 if Cbufsize < mss)1877 mss = bufsize;1878 el se l1879 bufsize = rounduptbufsize, mss);1880 if (bufsize > sb_max)1881 bufsize = sb_max;1882 (v o i d ) sbreserve(&so->so_snd, bufsize);1883 }1884 tp ->t_maxseg = m s s ;

1885 if ((bufsize = rt->rt_rmx.rmx_recvpipe) == 0)1886 bufsize = so->so_rcv.sb_hiwat;1887 if (bufsize > mss) (1888 bufsize = roundup(bufsize, mss);1889 if (bufsize > sb_max)1890 bufsize = sb_max;1891 (void) sbreserve(&so->so_rcv, bufsize);1892 }1893 /*1894 •k D o n’t force slow-start on local network.1895 ■k/1896 if ( !in_localaddr(inp->inp_faddr))1897 tp->snd_cwnd = mss;

1898 if (rt->rt_rmx.rmx_ssthresh) (1899 /*1900 * Istnieje jakieś ograniczenie na rozmiar bufora dla tej ścieżk1901 * Używamy go do określenia limitu powolnego startu, limit ten1902 * ustalamy jednak na wartość nie mniejszą niż 2*mss.1903 *

1904 */1905 tp->snd_ssthresh = max(2 * mss, rt->rt_rmx.rmx_ssthresh);1906 I1907 )

------------------------------------------------------------------------------------------------ tcpjnput.cRysunek 10.14 Funkcja tcp_m ssrcvd- ustalenie rozmiaru buforów

wysyłkowegoi odbiorczego

Modyfikacja rozmiaru bufora odbiorczego gniazda1885-1892 Podobny sposób postępowania zostaje zastosowany w przypadku ograni­

czenia wypełnienia bufora odbiorczego gniazda. Na przykład, dla lokalnego połą­czenia wykorzystującego Ethernet - przy założeniu, że używane są opcje znaczni­ka czasu oraz opcje CC - wartość t_maxopd wyniesie 1460, a wartość t_maxseg będzie równa 1440 (rysunek 2.4). Rozmiary buforów gniazda odbiorczego i wysył­kowego zostaną zaokrąglone w górę od wartości domyślnych równych 8192 (ry­sunek 16.4, strona 493, tom 2) do wartości 8640 (1440 x 6).

Start w trybie powolnym dla nielokalnego partnera1893-1897 Jeśli partner nie znajduje się w sieci lokalnej (i n_l ocal addr zwraca war­

tość „fałsz") zainicjowany zostaje powolny start. Rozmiar okna przeciążenia (eon- gestion window), snd_cwnd, ustalany jest na jeden segment.

Page 151: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 10.9 Funkcja tcp_dooptions 129

Wymuszanie powolnego startu tylko dla nielokalnego partnera jest zmianą wprowadzo­ną wraz z T/TCP. Umożliwia to klientowi lub serwerowi T /T C P wysłanie więcej niż jednego segmentu do lokalnego partnera, bez narażania się na dodatkowe opóźnienia związane z przesyłaniem segmentów w obie strony, co jest wymagane w trybie powolne­go startu (rozdział 3.6). W kodzie N et/3 zawsze wykonywany jest powolny start.

Ustalenie progu powolnego startu1898-1906 Jeśli metryka progu powolnego startu rmx_ssthresh (slow start threshold)

jest niezerowa, to zmiennej snd_ssthresh przypisana zostaje wartość tej metryki.

Zależność pomiędzy rozmiarem bufora odbiorczego z MSS a pamięcią TAO może­my prześledzić na rysunkach 3.1 i 3.3. Na pierwszym rysunku klient wykonuje niejawne otwarcie połączenia, żądanie PRU_SEND_EOF wywołuje funkcję tcp_mssrcvd z wartością of fer równą -1 i funkcja znajduje tao_mssopt równe 0 dla serwera (ponieważ klient właśnie został przeładowany). Użyta zostaje wartość domyślna 512. Ponieważ używana jest jedynie opcja CC (w przykładach w roz­dziale 2 wyłączyliśmy znaczniki czasu), wartość ta ulega zmniejszeniu o 8 bajtów (rozmiar opcji), co daje wartość 504. Zauważmy, że zaokrąglenie liczby 8192 w górę do wielokrotności 504 daje 8568, i to jest rozmiar okna podawany przez klienta w jego segmencie SYN. Jednakże serwer, wywoławszy tcp_mssrcvd,

otrzymał SYN klienta z wartością MSS równą 1460. Wartość ta zostaje zmniejszonao 8 bajtów (rozmiar opcji), dając 1452, a 8192 zaokrąglone w górę do wielokrotno­ści 1452 daje 8712. Taki też rozmiar okna serwer podaje w swoim segmencie SYN. Gdy klient przetwarza segment SYN serwera (trzeci segment na rysunku), funkcja tcp_mssrcvd zostaje wywołana ponownie, tym razem z wartością off er równą 1460. To zwiększa wartość t_maxopd klienta do 1460, wartość t_maxseg klienta równa jest 1452, a zaokrąglony w górę rozmiar bufora odbiorczego klienta wynosi 8712. Taki rozmiar okna klient podaje w potwierdzeniu segmentu SYN serwera.

Na rysunku 3.3, gdy klient wykonuje niejawne otwarcie połączenia, wartość tao_mssopt wynosi teraz 1460. Jest to ostatnia wartość otrzymana od partnera. Klient podaje rozmiar okna równy 8712, co jest wielokrotnością liczby 1452, wię­kszą niż 8192.

10.9 Funkcja tcp_dooptionsW kodzie N e t/l oraz N et/2 funkcja tcp_doopti ons rozpoznawała jedynie opcje NOP, EOL i MSS i miała trzy argumenty. W kodzie N et/3 wprowadzono opcje skali okna i znacznika czasu, co spowodowało, że liczba argumentów funkcji wzrosła do siedmiu (strona 972 w tomie 2). Trzy z tych argumentów związane były z opcją znacznika czasu. Wprowadzając teraz opcje CC, CCnew i CCecho zrezygnowano z dodawania kolejnych argumentów funkcji, przeciwnie - liczba argumentów została zmniejszona do 5 i zastosowano inną technikę zwracania informacji o tym, jakie opcje są obecne oraz jakie mają wartości.

Na rysunku 10.15 pokazano strukturę tcpopt. Struktura taka jest alokowana w tcp_i nput (jedyna funkcja wołająca tcp_doopti ons) i wskaźnik do tej struktu-

Page 152: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

130 Implementacja T/TCP: funkcje TCP Rozdział 10

ry jest przekazywany do funkcji tcp_dooptions, która wpisuje odpowiednie wartości w pola struktury. tcp_input używa wartości zawartych w strukturze w czasie przetwarzania otrzymanego segmentu.

------------------------------------------------------------------------------------------------ tcp_var.h138 struct tcpopt (139 u J ong to_f1 a g ; /* flagi T0F_xxx */140 u_long to_tsval; /* wartość znacznika czasu */141 u_long to_tsecr; /* odpowiedź "echo" znacznika czasu */142 tcp_cc t o _ c c ; /* wartość CC lub CCnew */143 tcp_cc to_ccecho; /* wartość CCecho */144 )

------------------------------------------------------------------------------------------------ tcp_var.hRysunek 10.15 Struktura tcpopt, wypełniana w funkcji tcp_doopti ons

Rysunek 10.16 pokazuje cztery wartości, które mogą być umieszczone w członie to _ f 1 ag.

t o _ f l a g Opis

T0F_CCT0F_CCNEM

T0F_CCECH0

T0F_TS

obecna jest opcja CC

obecna jest opcja CCnew

obecna jest opcja CCecho

obecna jest opcja znacznika czasu

Rysunek 10.16 Wartości to _ fla g

Na rysunku 10.17 przedstawiamy deklaraqę funkcji wraz z argumentami. Pierw­sze cztery argumenty są takie same jak w N et/3, natomiast ostatni argument zastępuje trzy ostatnie argumenty z kodu N et/3.

------------------------------------------------------------------------------------------------- tcp_input.c1520 void1521 tcp_dooptions(tp, cp, cnt, t i , to)1522 struct tcpcb *tp;1523 u_char *cp;1524 int cnt;1525 struct tcpiphdr *ti;1526 struct tcpopt *to:1527 I

------------------------------------------------------------------------------------------------ tcp_input.cRysunek 10.17 Funkcja tcp_doopti ons - argumenty

Nie będziemy omawiać tu przetwarzania opcji EOL, NOP, MSS, skali okna i zna­cznika czasu, ponieważ odpowiedni kod jest niemal taki sam jak na stronach 972-973 w tomie 2. (Różnice dotyczą nowego sposobu przekazywania argumen­tów, omawianego powyżej.) Na rysunku 10.18 przedstawiony jest końcowy frag­ment funkcji odpowiedzialny za przetwarzanie trzech nowych opcji T/TCP.

Page 153: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 10.10 Funkcja tcp je a ss 131

Sprawdzanie długości opcji i czy opcja ma być przetwarzana1580-1584 Sprawdzana jest długość opcji (musi być równa 6 dla wszystkich trzech

opcji CC). Otrzymana opcja CC będzie przetwarzana, gdy jesteśmy w trybie wysyłania opcji CC (flaga TF_REQ_CC jest ustawiona przez tcp_newtcpcb, jeżeli została ustawiona flaga jądra tcp_do_rf c l644) oraz gdy flaga TF_N00PT nie jest ustawiona. (Ta ostatnia flaga zapobiega wysyłaniu flag przez TCP w segmencie SYN.)

Ustaw odpowiednią flagę i skopiuj 4-bajtową wartość1585-1588 Odpowiednia flaga członu to_f 1 ag jest ustawiona. Czterobajtowa war­

tość opcji zostaje zapisana w członie to_cc struktury tcpopt i kolejność bajtów jest dostosowana do kolejności bajtów obowiązującej dla danego hosta.

1589 -1595 Jeśli jest to segment SYN, to dla danego połączenia zostaje ustawiona flaga TF_RCVD_CC, ponieważ otrzymaliśmy opcję CC.

Opcje CCnew i CCecho1 596-1623 Kolejne kroki przetwarzania opcji CCnew i CCecho są podobne do odpo­

wiednich kroków dla opcji CC. Wykonywane jest dodatkowe sprawdzenie, czy otrzymany segment zawiera flagę SYN, ponieważ opcje CCnew i CCecho mają prawo pojawić się tylko w segmencie SYN.

Choć flaga T0F_CCNEW jest poprawnie ustawiona, nigdy się jej nie sprawdza. Wynika to z tego, że kod przedstawiony na rysunku 11.6 usuwa zachowaną wartość CC (tzn. ustawia wartość 0), jeżeli opcja CC nie jest obecna. Jeśli obecna jest opcja CCnew, to wartość cc_recv jest w dalszym ciągu poprawna (zauważmy, że wartości opcji CC i CCnew są obie wpisywane do to _ cc na rysunku 10.18). Po przeprowadzeniu potrójnego uzgodnie­nia (rysunek 11.14) do tao_cc kopiowana jest wartość cc_recv.

Przetwarzanie otrzymanej opcji MSS1625-1626 Zmienna lokalna mss zawiera albo wartość opcji MSS (jeśli opcja ta

jest obecna), lub wynosi 0 (jeśli opcja jest nieobecna). W każdym przypadku, funkcja tcp_mss rcvd ustala wartości t_maxseg i t_maxopd. Funkcja ta musi zostać wywołana na końcu tcp_dooptions, ponieważ tcp_mssrcvd używa flag TF_RCVD_TSTMP i TF_RCVD_CC, tak jak pokazano to na rysunku 10.13.

10.10 Funkcja tcp_reassJeżeli serwer otrzymuje segment SYN zawierający dane, przy założeniu, że testTAO daje wynik negatywny lub segmentnie zawiera opcjiCC, funkcja tcp_i nputumieszcza dane w kolejce, czekając na zakończenie potrójnego uzgodnienia. Stan połączenia zostaje ustalony na SYN_RCVD (rysunek 11.6), przetwarzanie skiero­wane do trimthenstep6 do miejsca oznaczonego etykietą dodata (strona 1031, tom 2), makroinstrukcja TCP_REASS stwierdza, że połączenie nie jest w stanie ESTABLISHED, wywołuje więc tcp_ re as s ,by dodać segment do kolejki segmen­tów otrzymanych w nieprawidłowej kolejności w ramach danego połączenia.

Page 154: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

132 Implementacja T/TCP: funkcje TCP RozdziaHO

(Dane nie zostały w istocie otrzymane w nieprawidłowej kolejności, wyprzedziły one jedynie zakończenie potrójnego uzgodnienia. Mimo to dwa liczniki statystyczne tcps_rcvoopack i tcps_rcvoobyte - w dolnej części rysunku 27.19, strona 951 w tomie 2 - są błędnie zwiększane.)

tcpjnput.c1580 case T C P 0P T_ C C:1581 if (optlen != TCP0LEN_CC)1582 continue;1583 if ((tp->t_flags & (TF_REQ_CC | TF_N00PT)) != TF_REQ_CC)1584 continue; /* nie wysyłamy opcji CC */1585 to->to_flag |= T0F_CC;1586 bcopy((char *) cp + 2, (char *) &to->to_cc,1587 Sizeof(to->to_cc));1588 NTOHLt to->to_cc);1589 /*

1590 * Opcja CC lub CCnew otrzymana w segmencie SYN powoduje,1591 * że wysyłanie CC w następnych segmentach staje się poprawne.

1592 */1593 if (ti->ti_f1ags & TH_SYN)1594 tp->t_flags |= TF_RCVD_CC;1595 break;

1596 case TCP0PT_CCNEW:1597 if (optlen != TCP0LEN_CC)1598 continue;1599 if ((tp->t_f1ags & (TF_REQ_CC I TF_NOOPT)) != TF_REQ_CC)1600 continue; /* nie wysyłamy opcji CC */1601 if (!(t i ->ti_f1ags & TH _ S Y N ) )1602 continue;1603 to->to_flag = T0F_CCNEW;1604 bcopy((char cp + 2, (char *) &to->to_cc,1605 sizeof(to->to_cc));1606 NT0HL(to->to_cc);1607 /*

1608 * Opcja CC lub CCnew otrzymana w segmencie SYN powoduje,1609 * że wysyłanie CC w następnych segmentach staje się poprawne.

1610 */1611 tp ->t_f1ags |= T F _RCVD_CC;1612 break;

1613 case TCP0PT_CCECH0:1614 if (optlen != TCP0LEN_CC)1615 continue;1616 if (!(ti->ti_f1ags & T H _ S Y N ))1617 continue;1618 to->to_flag |= T0F_CCECH0;1619 bcopy((char *) cp + 2, (char *) & to ->to_ccecho,1620 size of (to->to_ccecho));1621 NT0HL(to->to_ccecho);1622 break:1623 11624 ]1625 if (ti->ti_f1ags & TH_SYN)1626 tcp_mssrcvd(tp, mss); /* ustawia t_maxseg */1627 1

Rysunek 10.18 Funkcja tcp_doop 11 ons - przetwarzanie nowych opcji T/TCPtcpjnput.c

Page 155: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 10.11 Podsumowanie 133

Gdy potwierdzenie segmentu SYN serwera zostaje później otrzymane (zwykle jako trzeci segment potrójnego uzgodnienia), wykonywana jest instrukcja caseTCPS_SYN_RECEIVED (stronie 1011 w tomie 2), która zmienia stan połączenia naESTABLISHED i woła funkcję tcp_reass z drugim argumentem równym 0, by przekazać dane z kolejki do procesu. Zobaczymy jednak (rysunek 11.14), że to wywołanie tcp_reass zostaje ominięte, jeżeli nowy segment zawiera dane lub jeśli flaga FIN jest ustawiona, ponieważ każdy z tych warunków powoduje wywo­łanie TCP_REASS w punkcie, gdzie znajduje się etykieta doda ta. Problem polega na tym, że to wywołanie TCP_REASS nie spowoduje przekazania danych do procesu, jeżeli nowy segment całkowicie przykryje (overlap) wcześniejszy segment.

Problem ten może zostać zlikwidowany przez prostą modyfikację tcp_reass: zastąpienie return w linii 106 na stronie 951 tomu 2 instrukcją skoku do etykietypresent.

10.11 PodsumowanieInformacja TAO dla danego hosta jest przechowywana we wpisie do tablicy rutowania. Funkcja tcp_gettaocache wczytuje przechowywane informacje dla danego hosta i woła tcp_rtl ookup w poszukiwaniu marszruty dla hosta, jeżeli odpowiednia marszruta nie znajduje się jeszcze w bloku PCB.

T/TCP modyfikuje funkcję tcp_cl ose, tak by dwie estymaty, srtt i rttvar, zapisy­wane były w tablicy rutowania dla połączeń T/TCP, nawet jeśli mniej niż 16 pełnowymiarowych segmentów było wysłanych w danym połączeniu. W ten sposób następne połączenie T/TCP z tym samym hostem może być zainicjowane używając wartości tych dwóch estymat (zakładając, że przed nawiązaniem następnego połączenia nie mija okres ważności wpisu w tablicy rutowania).

Funkcja tcp_mss z kodu Net/3 zostaje funkcjonalnie podzielona na dwie części zawarte w funkcjach tcp_mssrcvd i tcp_msssend. Pierwsza z tych funkcji jest wołana po otrzymaniu opcji MSS, druga - przy wysyłaniu MSS. Druga z tych funkcji działa inaczej niż zwykle w BSD: podaje wartość MSS równą wartości MTU interfejsu wyjściowego pomniejszonej o rozmiar nagłówków TCP i IP. Sy­stem BSD ustaliłby wartość MSS dla nielokalnego partnera na 512.

Przy wprowadzeniu T/TCP zostaje zmodyfikowana funkcja tcp_doopti ons

z kodu N et/3 . Zrezygnowano z licznych argumentów funkcji, umieszczając odpo­wiednie wartości w strukturze. W ten sposób funkcja może przetworzyć nowe opcje (takie jak trzy opcje wprowadzone wraz z T/TCP), bez zwiększania liczby argumentów.

Page 156: Biblia TCP IP Tom 3 - Uzupelnienie.pdf
Page 157: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Implementacja T/TCP: wejście TCP11

11.1 WstępWiększość zmian wymaganych przez T/TCP zlokalizowanych jest w funkq'i tcp_input. Zmianą, która dotyczy wielu fragmentów funkcji, są nowe argumenty i sposób przekazywania informacji przez funkcję tcp_doopti ons (rozdział 10.9). Nie pokazujemy tu wszystkich fragmentów kodu zmienionych w związku z tą modyfikacją tcp_dooptions.

Rysunek 11.1 jest powtórzeniem rysunku 28.1 ze stron 962-963 w tomie 2. Pogru­bionym drukiem zaznaczyliśmy zmiany związane z T/TCP.

v o i dt c p _ i n p u t ( )I

suma k o n t r o l n a n ag ł ów k a TCP i d a n y c h ; p o m i j a m y n a g ł ó w k i IP/TCP w mbuf :

f i n d p c b :o d n a j d ź PCB s e g m e n t u : i f Cnie o d n a l e z i o n y )

g o t o d r o p w i t h r e s e t ;

r e i n i c j a c j a z e g a r ó w : z e g a r b e z c z y n n o ś c i 0 , z e g a r p od trz y my wa ni a 2 g o d z i n y

p r z e t w a r z a n i e o p c j i , j e ż e l i n i e w s t a n i e LISTEN;

i f ( p a k i e t z g o dn y z p r z ew i d yw a n i e m n a g ł ó w k a ) { c a ł k o w i t e p r z e t w o r z e n i e o d e b r a n e g o s e g m e n t u ; r e t u r n ;

)

s w i t c h ( t p - > t _ s t a t e ) I c a s e TCPS_LISTEN:

j e ż e l i u s t a w i o n a f l a g a SYN, z a a k c e p t u j nowe p o ł ą c z e n i e ; wykonuj emy t e s t TAO g o t o t r i m t h e n s t e p S :

c a s e TCPS_SYN_SENT:sprawdzamy o p c j ę CCechoj e ż e l i ACK n a s z e g o SYN - p o ł ą c z e n i e g o t o w e ;

t r i m t h e n s t e p S :w y c i n a j d a n e n i e m i e s z c z ą c e s i ę w o k n i e : i f ( f l a g a ACK u s t a w i o n a )

g o t o p r o c e s s a c k : g o t o s t e p 6 ;

c a s e TCPS_LAST_ACK: c a s e TCPS_CL0SING: c a s e TCPS_TIME_WAIT:

c z y nowy syn j e s t n i e j awnym p o t w i e r d z e n i e m p o p r z e d n i e g o w c i e l e n i a ;)

Page 158: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

136 Implementacja T/TCP: wejście TCP Rozdział 11

p r z e t w a r z a n i e z n a c z n i k a c z a s u RFC 1323 ;

sprawdzamy o p c j ę CC;

s p r aw d ź , c z y wewnątrz okna o d b i o r c z e g o są j a k i e ś b a j t y d a n y c h ;

o b e t n i j s e gm e n t t a k , a b y z m i e ś c i ł s i ę w o k n i e ;

i f ( u s t a w i o n a f l a g a RST) lp r z e t w a r z a n i e z a l e ż n e od s t a n u ; g o t o d r o p ;

)

i f ( f l a g a ACK w y ł ą c z o n a )i f (SYN_RCVD | | p o ł o w i c z n i e z s y n c h r o n i z o w a n e )

g o t o s t e p 6 ;e l s e

g o t o d r o p p ;

i f ( u s t a w i o n a f l a g a ACK) { i f ( s t a n SYN_RCVD)

o t w a r c i e pas ywne l ub z a k o ń c z e n i e o t w a r c i a j e d n o c z e s n e g o ; i f ( p o w i e l o n e ACK)

a l g o r y t m s z y b k i e g o o d z y s k i w a n i a ;p r o c e s s a c k :

o d ś w i e ż e s t y m a t o r y RTT j e ż e l i b y ł s pr a wd z a n y c z a s ; i f ( ż a d n e d a n e n i e z o s t a ł y p o t w i e r d z o n e )

g o t o s t e p S ; o t w ó r z o k n o p r z e c i ą ż e n i a ; usuń p o t w i e r d z o n e d a n e z b u f o r a n a d a w c z e g o ; z mi eń s t a n , j e ż e l i t e r a z w FIN_MAIT_1, CLOSING, l ub LAST_ACK;

)

s t e p 6 :o d ś w i e ż i n f o r m a c j e o k n a ;

p r z e t w a r z a n i e f l a g i URG;

d o d a t a :p r z e t w a r z a n i e da ny ch z s e gm en tu , d o d a n i e do k o l e j k i o d t w a r z a n i a p a k i e t ó w ;

i f ( u s t a w i o n a f l a g a FIN)p r z e t w a r z a n i e z a l e ż n e o d s t a n u ;

i f ( o p c j a g n i a z d a SO_DEBUG) t c p _ t r a c e ( T A _ I N P J T ) ;

i f ( p o t r z e b n y o u t p u t | | p o t w i e r d ź t e r a z ) t c p _ o u t p u t ( ) ;

r e t u r n ;

d r o p a f t e r a c k ;t c p _ o u t p u t ( ) w c e l u wy ge ne ro wa n ia ACK; r e t u r n ;

d r o p w i t h r e s e t :t c p _ r e s p o n d ( ) w c e l u wyge ne ro wan i a RST; r e t u r n ;

d r o p :i f ( o p c j a g n i a z d a SO_DEBUG)

t cp_ t r a c e ( TA _DR OP) ; r e t u r n ;

)

Rysunek 11.1 Podsumoimnie przetwarzania na wejściu TCP. Zmiany wprowadzone z T/TCP zaznaczone są pogrubionym drukiem

Page 159: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 11.2 Przetwarzanie wstępne 137

Zmiany w tcp_i nput prezentujemy w takiej kolejności, w jakiej odbywa się prze­twarzanie.

11.2 Przetwarzanie wstępneZdefiniowane zostają trzy nowe dynamiczne zmienne lokalne. Jedną z nich jest struktura tcpopt używana przez tcp_doopti ons. Następujące linie zastępują linię 190 na stronie 964 w tomie 2:

struct tcpopt to; /* opcje w tym segmencie */struct rmxp_tao *taop; /* wskaźnik do wpisu TAO */struct rmxp_tao tao_noncached; /* gdy brak wpisu TAO */

bzero((char *)&to, sizeof(to)): tcpstat.tcps_rcvtotal++;

Inicjacja struktury tcpopt wartością 0 jest istotna: w ten sposób człon to_cc (odebra­na wartość CC) otrzymuje wartość 0, co oznacza, że zmienna ta jest niezdefiniowana.

W kodzie N e t/3 przetwarzanie powraca do etykiety f i n d p c b jedynie wtedy, gdy nowy segment SYN jest przetwarzany dla połączenia, które nadal znajduje się w stanie UME_WAIT (strona 998, tom 2). Mamy tu jednak do czynienia z błędem, ponieważ dwie linie kodu:

m->m_data += sizeof(struct tcpiphdr) + off - sizeof(struct tcphdr);m->m_len -+ sizeof(struct tcpiphdr) + off - sizeof (struct tcphdr);

które pojawiają się dwukrotnie po findpcb, wykonywane są po raz drugi poinstrukcji goto. (Te dwie linie kodu pojawiają się na stronie 979 i ponownie nastronie 980 tomu 2; tylko jeden z tych dwóch powtórzonych fragmentów zostaje wykonywany - zależnie od tego, czy segment jest zgodny z przewidywaniem nagłówka (header prediction), czy też nie.) Przed wprowadzeniem T/TC P błąd ten nie stwarzał problemów ponieważ segmenty SYN rzadko zawierały również da­ne, a błąd się uwidaczniał jeśli przychodził nowy SYN zawierający dane, przezna­czone dla połączenia pozostającego w stanie TIME_WAIT. Dla T/TC P pojawia się jednak drugie odgałęzienie przetwarzania powracające do findpcb (odpowie­dzialne za przetwarzanie niejawnego potwierdzenia z rysunku 4.7, patrz rysunek 11.11), a przetwarzany SYN będzie prawdopodobnie zawierał dane. Dlatego wspomniane dwie linie muszą być przeniesione przed etykietę findpcb, tak jak to pokazano na rysunku 11.2. Dwie linie, o których mowa, powinny być następnie usunięte z kodu na stronie 979 i 980 w tomie 2.

Page 160: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

138 Implementacja T/TCP: wejście TCP Rozdział 11

------------------------------------------------------------------------------------------------------ t c p jn p u t .c274 /*275 * Pomijamy nagłówki TCP i IP oraz opcje TCP w mbuf.276 * optp i ti nadal wskazują na nagłówek TCP header, ale to jest OK.277 */278 m->m_data += sizeoftstruct tcpiphdr) + off - sizeoftstruct tcphdr);279 m->m_len -= sizeoftstruct tcpiphdr) + off - sizeoftstruct tcphdr);

280 /*281 * Znajdujemy pcb dla segmentu.282 */283 findpcb:

------------------------------------------------------------------- tcpjnput.cRysunek 11.2 t cp_ i n p u t - modyfikacja wskaźnika i długości mbuf

odbywa się przed fin d p cb

Następna zmiana pojawia się w linii 327 na stronie 969 tomu 2 - utworzenie nowego gniazda, gdy przychodzi segment dla nasłuchującego gniazda (listening socket). Po przypisaniu t_state wartości T C PS_L ISTEN, dwie flagi, TF_N0PUSH i TF_N00PT, muszą zostać przeniesione z gniazda nasłuchującego do nowego gniazda:

tp->t_f1ags |= tpO->t_f1ags & (TF_N0PUSH|TF_N00PT);

gdzie tpO jest lokalną zmienną dynamiczną, która wskazuje na tcpcb dla odbie­rającego gniazda.

Wywołanie funkcji tcp_doopti ons w liniach 344-345 na stronie 971 w tomie 2 zostaje zmienione, tak by uwzględnić zmodyfikowany sposób przekazywania parametrów dla tej funkcji (rozdział 10.9);

if (optp && tp->t_state != TCPS_LISTEN) tcp_dooptions(tp. optp. optlen, ti. Sto);

11.3 Przewidywanie nagłówkaPoczątkowy test, czy przewidywanie nagłówka może być zastosowane (strona 975, tom 2), musi obejmować sprawdzenie, czy ukryte flagi stanu są wyłączone. Jeśli którakolwiek z tych flag jest włączona, może być konieczne jej wyłączenie przez powolną ścieżkę przetwarzania w tcp_input. Nowy test przedstawiony został na rysunku 11.3.

------------------------------------------------------------------------------------------------- tcpjnput.c398 if (tp ->t_s ta te == TCPS_ESTABLISHED &&399 (tiflags & (TH_SYN I TH_FIN | TH_RST | THJJRG | T H _ A C K ) ) == TH_ACK &&400 ((tp->t_f1ags & (TF_SENDSYN I TF___SEN DFIN)) == 0) &&401 ((to.to_flag i T0F_TS) == 0 ||402 TSTMP_GEQ(to.to_tsval, tp->ts_recent)) &&403 /*404 * Jeżeli zaczęliśmy używać opcji CC, to używanie jej staje się obowiązkowe:405 * segment jest OK, jeżeli nieużywanie T/TCP nie zostało406 * wynegocjowane lub jeżeli segment zawiera CC równe CCrecv.407 */408 ( (tp->t_f1ags & (TF_REQ_CC I TF_RCVD_CC)) != (TF_REQ_CC I TF_RCVD_CC) ||409 (t o .to_f1 ag & T0F_CC) != 0 && to.to_cc == tp->cc_recv) &&410 ti ->ti_seq == tp->rcv_nxt &&

Page 161: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 11.3 Przewidywanie nagłówka 139

411 tiwin && tiwin = tp->snd_wnd &&412 tp->snd_nxt == tp->snd_max) [

413 /*414 * Jeżeli ostatnie ACK zawiera się w ramach numerów sekwencyjnych415 * tego segmentu, to rejestrujemy znacznik czasu.416 * UWAGA: test został zmodyfikowany zgodnie z propozycją417 * z listy [email protected] (Braden 1993/04/26).418 */419 if ((t o .to_flag & T0F_TS) != 0 &&420 SEQ_LEQ(ti->ti_seq, tp->last_ack_sent)) (421 tp->ts_recent_age = tcp_now;422 tp->ts_recent = to.to_tsval;423 ]

------------------------------------------------------------------- tcp_input.cR y s u n e k ll .3 tc p _ i n p u t - czy przewidywanie nagłówka może być zastosowane?

Sprawdzenie, czy ukryte flagi stanu są wyłączone400 Pierwsza zmiana polega na sprawdzeniu, czy wyłączone są obie flagi,

TF_SENDSYN i TF_SENDFIN.

Sprawdzenie opcji znacznika czasu (jeśli jest obecna)401-402 Następna zmiana wiąże się z modyfikacjami funkcji tcp_dooptions: za­

miast sprawdzać ts_present , sprawdzany jest bit T0F_TS w to_f 1 ag. Jeśli znacz­nik czasu jest obecny, jego wartość znajduje się w t o _ t s v a l , zamiast w t s _ v a l .

Sprawdzenie CC, jeśli używany jest protokół T/TCP403-409 Ostatecznie, jeżeli użycie T/TCP nie zostało wynegocjowane (żądaliśmy

opcji CC, ale jej nie otrzymaliśmy od partnera, lub nawet nie zgłaszaliśmy takiego żądania), wykonywane są dalsze sprawdzenia i f. Jeżeli T/TCP jest używane, to otrzymany segment musi zawierać opcję CC i wartość CC musi być równa cc_recv. W przeciwnym razie dalsze testy i f nie są przeprowadzane.

Spodziewamy się, że przewidywanie nagłówka będzie rzadko wykorzystywane dla krótkich transakcji T/TCP. Dzieje się tak dlatego, ponieważ w najmniejszej wy­mianie T/TCP pierwsze dwa segmenty mają ustawione flagi kontrolne (SYN i FIN) i drugi test na rysunku 11.3 daje wynik negatywny. Te segmenty T/TCP są przetwa­rzane powolną ścieżką w tcp_i nput. Natomiast opcji CC będą używać dłuższe połączenia (na przykład przekaz dużych ilości danych) pomiędzy hostami znają­cymi T/TC P i takie połączenia mogą korzystać z przewidywania nagłówka.

Aktualizacja ts_recent na podstawie otrzymanego znacznika czasu413-423 Sprawdzenie, czy wartość t s _ r e c e n t powinna zostać uaktualniona, różni

się od sprawdzenia w liniach 371-372 na stronie 975 w tomie 2. Przyczyna wpro­wadzenia modyfikacji przedstawionych na rysunku 11.3 jest wyjaśniona szczegó­łowo na stronach 903-906 w tomie 2.

Page 162: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

140 Implementacja T/TCP: wejście TCP Rozdział 11

11.4 Inicjacja pasywnego otwarciaZastępujemy teraz cały kod przedstawiony na stronie 984 w tomie 2 - ostatnia część przetwarzania otrzymanego segmentu SYN dla gniazda w stanie LISTEN. Gdy serwer otrzymuje SYN od klienta, mamy do czynienia z inicjacją pasywnego otwarcia. (Nie przytaczamy tu po raz drugi kodu na stronie 982 w tomie 2, który wykonuje początkowe przetwarzanie w tym stanie.) Pierwszy fragment tego kodu pokazany jest na rysunku 11.4.

545 tp->t_templ ate = tcp_template(tp);546 if (tp->t_template == 0) l547 tp = tcp_drop(tp, ENOBUFS);548 dropsocket = 0; /* gniazdo zostało już usunięte */549 goto drop;550 )551 if ((taop = tcp_gettaocache(inp)) == NULL) I552 taop = &tao_noncached;553 bzero(taop, sizeo f(* ta o p) );554 )555 if (optp)556 tcp_dooptions(tp, optp, optlen, ti , &to);557 if (iss)558 t p -> iss = i s s ;559 else560 t p -> iss = tcp_i s s ;561 tcp_i SS += TCP_ISSINCR / 4;562 tp->irs = ti->ti_seq:563 tcp_sendseqinit(t p ) ;564 tcp_rcvseqinit(tp);565 /*566 * Inicjacja tcpcb dla transakcji:567 * set SND.WND = SEG.WND,568 * inicjacja CCsend i CCrecv.569 */570 tp->snd_wnd = tiwin; / * początkowe okno wysyłkowe */571 tp->cc_send = CC_INC(tcp_ccgen);572 tp->cc_recv = to.to_cc;

Rysunek 11.4 tcp_input-zuczytanie wpisu TAO, inicjacja bloku kontrolnego dla transakcji.

Odczytanie wpisu TAO dla klienta551 -554 tcp_gettaocache szuka wpisu TAO dla danego klienta. Jeśli wpis taki nie

zostaje znaleziony, użyta jest lokalna zmienna dynamiczna z wyzerowanymi wszystkimi wartościami.

Przetwarzanie opcji i inicjacja numerów sekwencyjnych555-564 tcp_dooptions przetwarza opcje (funkcja ta nie była wołana wcześniej,

ponieważ połączenie jest w stanie LISTEN). Początkowy wysyłkowy numer se­kwencyjny (initial send sequence number - iss) oraz początkowy odbiorczy numer

Page 163: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 11.4 Inicjacja pasywnego otwarcia 141

sekwencyjny (initio! receive sequence number - i r s) zostają zainicjowane. Wszystkie zmienne bloku kontrolnego zawierające numery sekwencyjne są inicjowane przeztcp_sendseqi ni t oraz tcp_rcvseqi ni t.

Aktualizacja okna wysyłkowego565-570 ti w i n jest rozmiarem okna przekazanym przez klienta w segmencie SYN

(strona 968 w tomie 2). Jest to początkowy rozmiar okna dla nowego gniazda. Zwykle okno wysyłkowe nie jest uaktualniane aż do odebrania segmentu z ACK (strona 1025, tom 2). T/TCP musi jednak użyć wartości z otrzymanego segmentu SYN, nawet gdy segment nie zawiera flagi ACK. Rozmiar okna określa, jak wiele danych serwer może natychmiast wysłać w odpowiedzi do klienta (drugi segment w najmniejszej, trzysegmentowej wymianie T/TCP).

Określenie wartości cc_send i cc_recv571-572 Wartość cc_send jest przepisywana z tcp_ccgen, a cc_recv otrzymuje

wartość równą wartości CC, jeśli opcja CC była obecna. Jeśli zaś opcja CC nie była obecna, to - ponieważ struktura to została zainicjowana na początku funkcji tcp_i nput wartością 0 - cc_recv otrzyma też wartość 0 (niezdefiniowana).

Na rysunku 11.5 przedstawiony jest test TAO dla otrzymanego segmentu.

Wykonanie testu TAO573-587 Test TAO zostaje przeprowadzony tylko wtedy, gdy segment zawiera opcje

CC. Test TAO daje wynik pozytywny, jeśli otrzymana wartość CC jest niezerowa i większa niż wartość przechowywana dla danego klienta (tao_cc).

Pozytywny test TAO - uaktualnienie pamięci TAO dla klienta588 - 594 Wartość przechowywana dla danego klienta zostaje uaktualniona i połącze­

nie wchodzi w stan ESTABLISHED*. (Ukryta flaga stanu zostaje ustawiona kilka linii niżej, co oznacza, że połączenie znajduje się w tym połowicznie zsynchronizo­wanym stanie z gwiazdką.)

Sprawdzenie, czy potwierdzenie ma być opóźnione595 - 606 Jeśli segment zawiera flagę FIN, lub jeśli segment zawiera dane, oznacza to,

że kod aplikacji uwzględnia użycie T/TCP (tzn. aplikacja wywołała sendto z flagą MSG_E0F i nie mogła wywołać connect, wri te i shutdown). W tym przypadku potwierdzenie zostaje opóźnione, tak by umożliwić serwerowi przesłanie po­twierdzenia nałożonego (piggyback acknowledgement) na segment SYN /ACK ser­wera.Jeśli flaga FIN nie jest ustawiona, a segment zawiera dane, to - ponieważ segment zawiera również flagę SYN - jest to najprawdopodobniej pierwszy z kilku segmen­tów z danymi wysyłanymi przez klienta. W tym przypadku, jeżeli klient nie jest w podsieci lokalnej (i n_l ocal addr zwraca 0), to potwierdzenie nie zostaje opóźnione, ponieważ klient wykonuje prawdopodobnie powolny start.

Page 164: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

142 Implementacja T/TCP: wejście TCP Rozdział 11

------------------------------------------------------------------------------------------------- tcpjnput.c573 /*574 * Przeprowadzamy test TAO dla ewnetualnie odebranej opcji CC

* (SEG.CC):575 * -Porównujemy SEG.CC z wartością CC zachowana dla tego hosta576 * (jeśli wartość taka istnieje).577 * -Jeżeli SEG.CC > wartość zachowana, SYN jest nowy i zostaje578 * natychmiast zaakceptowany: nowa wartość CC jest zachowana,579 * gniazdo oznaczone jako połączone, połączenie jest w stanie580 * ESTABLISHED, włączamy flagę powodującą wysłanie SYN581 * w następnym segmencie. Wirtualny rozmiar okna wpisany jest do582 * rcv_adv, by zainicjować zabezpieczenie SWS. Następnie583 * przeprowadzamy zwykłe przetwarzanie segmentu: pomijamy SYN,584 * przetwarzamy dane i FIN.

* -W przeciwym razie wykonujemy zwykłe potrójne uzgodnienie.585 */586 if (Cto.to_flag & T0F_CC) != 0) (587 if (taop->tao_cc != 0 && CC_GT(to.to_cc, ta op - >tao_cc)) (588 /*589 * W otrzymanym segmencie SYN była opcja CC i test590 * TAO dał wynik pozytywny.591 */592 tcpstat.tcps_taook++;593 taop->tao_cc = to.to_cc;594 tp->t_state = TCP S__E STAB LIS HE D :

595 /*596 * Jeżeli jest FIN lub jeśli są dane i połączenie jest597 * lokalne, opóźniamy S Y N ,A C K (S Y N ), mając nadzieję598 * że będziemy mogli je nałożyć na segment odpowiedzi.599 * W innym przypadku ACK musi być wysłane teraz -600 * partner może wykonywać powolny start.601 */602 if ((tiflags & TH_FIN) | I603 (ti ->ti_1en 1= 0 && in_l ocaladdr(inp->inp_faddr)))604 t p ->t_f1ags |= (TF_DELACK | T F _S E ND SY N) ;605 else606 tp->t_flags |= (TF_ACKN0W | TF_SE ND S YN );607 tp->rcv_adv += tp->rcv_wnd;608 tcpstat.tcps_connects++;609 soisconnected(so):610 tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;611 dropsocket = 0; /* związane z gniazdem */612 tcpstat.tcps_accepts++;613 goto trimthenstep6;614 ) else if (taop->tao_cc != 0)615 tc p s t a t .tcps_taofai1++:

------------------------------------------------------------------------------------------------ tcpjnput.cRysunek 11.5 tcp _ in p u t- test TAO dla otrzymanego segmentu

Ustalenie wartości rcv_adv607 Zmienna rcv_adv jest zdefiniowana jako najwyższy zgłoszony (advertised)

numer sekwencyjny plus 1 (rysunek 24.18, strona 838 w tomie 2). Makroinstrukcja tcp_rcvseqi ni t (rysunek 11.4) zainicjowała jednak tę zmienną wartością równą otrzymanemu numerowi sekwencyjnemu plus 1. Na tym etapie przetwarzania rcv_wnd będzie rozmiarem bufora odbiorczego gniazda (strona 980 w tomie 2). Dodanie rcv_wnd do rcv_adv spowoduje, że rcv_adv będzie wskazywać na pierwszy bajt poza aktualnym oknem odbiorczym. rcv_adv musi zostać zainicjo­wana tutaj, ponieważ zmienna ta jest używana przez mechanizm unikania wysy­łania głupich segmentów w tcp_output (strona 915, tom 2). Wartość rcv_adv jest ustawiana na końcu tcp_output zwykle wtedy, gdy ma być wysłany pierwszy

Page 165: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 11.4 Inicjacja pasywnego otwarcia 143

segment (w tym przypadku byłby to segment SYN/ ACK serwera wysyłany w odpowiedzi na SYN klienta). T /TCP wymaga jednak, by wartość rcv_adv była określona przy pierwszym przejściu przez funkcję tcp_output, ponieważ dane mogą być umieszczone w pierwszym wysyłanym segmencie.

Nawiązanie połączenia608-609 Zwiększenie tcps_connects i wywołanie soi sconnected następują zwy­

kle, gdy otrzymany jest trzeci segment potrójnego uzgodnienia (strona 1011, tom 2). W przypadku T/TCP obie te czynności są wykonywane teraz, ponieważ połą­czenie zostało właśnie nawiązane.

610-613 Z e g a r nawiązywania połączenia (connection-establishment timer) zostaje usta­wiony na 75 sekund, flaga dropsocket otrzymuje wartość 0 i wykonany jest skok do etykiety trimthenstep6.

Na rysunku 11.6 pokazana została pozostała część przetwarzania segmentu SYN otrzymanego w stanie LISTEN.

------------------------------------------------------------------------------------------------ tcpjnput.c616 ] else {617 /*618 * Brak opcji CC, może jednak jest CCnew:619 * kasujemy wartość przechowywaną.620 */621 taop->tao_cc = 0;622 ]

623 /*624 * Test TAO dał wynik negatywny, lub nie było opcji CC -625 * wykonujemy standardowe potrójne uzgodnienie.626 */627 t p ->t_f1ags ]= TF_ACKN0W;628 tp->t_state = TCPS_SYN_RECEIVED;629 t p -> t__t i me r[TC PT_KE E P] = TCPTV_KEEP_INIT;630 dropsocket = 0: /* związane z gniazdem */631 t c ps ta t.tcps_accepts++;632 goto trimthenstep6;633 )

------------------------------------------------------------------------------------------------ tcpjnput.cRysunek 11.6 t cp_ in p u t- przetwarzanie w stanie LISTEN. Brak opcji CC lub

negatywny wynik testu TAO

Brak opcji CC; przechowywana wartość CC staje się niezdefiniowana616-622 Klauzula else odpowiada sytuacji, gdy brak jest opcji CC (pierwsza instrukcja

i f na rysunku 11.5). Przechowywana wartość CC zostaje ustawiona na 0 (niezdefinio­wana). Jeśli okaże się, że segment zawiera opcję CCnew, wartość przechowywana zostaje uaktualniona po zakończeniu potrójnego uzgodnienia (rysunek 11.14).

Wymagane potrójne uzgodnienie623 - 633 Segment nie zawierał opcji CC, lub opcja CC była obecna, ale test TAO dał

wynik negatywny. W każdym z tych przypadków wymagane jest przeprowadze­nie potrójnego uzgodnienia. Pozostałe linie są takie same jak końcowa część rysunku 28.17, strona 984 w tomie 2: flaga TF_ACKN0W zostaje ustawiona i ustalony

Page 166: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

144 Implementacja T/TCP: wejście TCP Rozdział 11

jest stan SYN_RCVD, co spowoduje natychmiastowe wysłanie segmentu SYN/ACK.

11.5 Inicjacja aktywnego otwarciaNastępny przypadek (case) odpowiada sytuacji, gdy połączenie znajduje się w stanie SYN_SENT. Moduł TCP wysłał wcześniej segment SYN (aktywne otwarcie) i prze­

twarza teraz odpowiedź serwera. Rysunek 11.7 pokazuje pierwszą część związanego z tym kodu. Odpowiedni fragment kodu N et/3 zaczyna się na stronie 986 w tomie 2.

------------------------------------------------------------------------------------------------ tcpjnput.c634 / *635 * Jeżeli jesteśmy w stanie SYN_SENT:636 * jeżeli segment zawiera ACK, ale nie dla naszego SYN, odrzucamy

* otrzymane dane.637 * jeżeli segment zawiera RST. odrzucamy połączenie.638 * jeżeli segment nie zawiera SYN, odrzucamy ten segment.639 * W przeciwnym razie, jest to akceptowalny segment SYN640 * inicjujemy tp->rcv_nxt i tp->irs641 * jeżeli segment zawiera ack to zwiększamy tp->snd_una.642 * jeżeli SYN został potwierdzony zmieniamy stan na ESTABLISHED,

jeżeli nie - na SYN_RCVD643 * spodziewamy się, że segment zostanie potwierdzony644 * kontynuujemy przetwarzanie pozostałych danych/komunikatów

kontrolnych, poczynając od URG645 */646 case TCPS_SYN_SENT:647 if ((taop = tcp_gettaocache(inp)) == NULL) (648 taop = &tao_noncached;649 bzerottaop, sizeof(*taop));650 )651 if ((ti flags & TH_ACK) &&652 (SEQ_LEQ(ti->ti_ack, tp->iss) ||653 SEQ_GT(ti->ti_ack, tp->snd_max))) (654 /*655 * Jeżeli mamy CCsent dla oddalonego hosta, to znaczy,656 * że nie było przed chwilą przeładowania - nie wysyłamy RST.657 * Może to być retransmisja wykonana przez partnera, po658 * zagubieniu naszego wcześniejszego potwierdzenia.659 * Nasz nowy SYN, gdy dotrze, posłuży za wymagane660 * potwierdzenie.661 */662 if (taop->tao_ccsent != 0)663 goto drop;664 else665 goto dropwithreset;666 )667 if (tiflags & TH_RST) (668 if (tif1ags & TH_ACK)669 tp = tcp_drop(tp, ECONNREFUSED);670 goto drop;671 I672 if ((tiflags & T H _ S Y N ) == 0)673 goto drop;674 tp->snd_wnd = ti->ti_win; /* początkowe okno wysyłkowe */675 tp->cc_recv = to.to_cc; /* wartość CC partnera */

676 tp->irs = ti->ti_seq;677 tcp_rcvseqinit(tp);------------- ----------------------------------------------------------------------------------- tcpjnput.cRysunek 11.7 t cp_ i n p u t- początkowe przetwarzanie w stanie SYN_SENT

Page 167: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 11.5 Inicjacja aktywnego otwarcia 145

Pobranie wpisu TAO647-650 Informacja TAO dla serwera zostaje pobrana. Odpowiedni wpis powinien

istnieć, ponieważ niedawno wysłaliśmy segment SYN.

Obsługa niepoprawnego ACK651-666 Jeżeli segment zawiera ACK, ale pole potwierdzenia jest niepoprawne (opis

porównywanych pól przedstawiony został na rysunku 28.19 w tomie 2), nasza odpowiedź zależy od tego, czy mamy zachowaną wartość tao_ccsent dla tego hosta. Jeżeli wartość tao_ccsent jest niezerowa, po prostu odrzucamy ten seg­ment i nie wysyłamy RST. Jeżeli natomiast wartość tao_ccsent wynosi 0, odrzu­camy segment i wysyłamy RST, co w tym stanie jest normalną odpowiedzią TCP na niepoprawne potwierdzenie.

Sprawdzenie, czy flaga RST jest obecna667-671 Jeżeli otrzymany segment zawiera flagę RST, segment zostaje odrzucony.

Dodatkowo, jeżeli ustawiona jest flaga ACK, oznacza to, że serwer TCP aktywnie odmawia połączenia i komunikat o błędzie ECONNREFUSED zostaje zwrócony do wołającego procesu.

Flaga SYN musi być ustawiona672-673 Jeżeli flaga SYN nie jest ustawiona, segment zostaje odrzucony.

674-677 Początkowe okno wysyłkowe otrzymuje wartość równą wartości zgłoszo­nej w otrzymanym segmencie, a cc_recv otrzymuje wartość równą otrzymanej wartości CC (0, jeżeli opcja CC nie była obecna), i rś jest początkowym odbior­czym numerem sekwencyjnym, a makroinstrukcja tcp_rcvseqinit inicjuje zmienne odbiorcze w bloku kontrolnym.

Przetwarzanie odbywa się teraz różnymi ścieżkami, w zależności od tego, czy segment zawiera potwierdzenie naszego segmentu SYN (normalny przypadek), czy też flaga ACK nie jest ustawiona (jednoczesne otwarcie, przypadek rzadszy). Normalny przypadek przedstawiony jest na rysunku 11.8.

Flaga ACK jest włączona678 Jeżeli flaga ACK jest włączona, to z testu t i _a c k na rysunku 11.7 wiemy, że

ACK potwierdza nasz segment SYN.

Sprawdzenie wartości CCecho, jeśli opcja ta jest obecna679-693 Jeżeli segment zawiera opcję CCecho, ale wartość CCecho nie jest równa

wysłanej przez nas wartości CC, segment zostaje odrzucony. (To „nie powinno się nigdy zdarzyć", chyba że partner nie działa poprawnie, ponieważ flaga ACK potwierdza nasz segment SYN.) Jeśli w ogóle nie wysyłaliśmy opcji CC (tao_ccsent wynosi 0), to również zostaje wysłana flaga RST.

Page 168: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

146 Implementacja T/TCP: wejście TCP Rozdział 11

------------------------------------------------------------------------------------------------ tcpjnput678 if (ti flags 4 TH_ACK) (679 /*680 * Nasz SYN został potwierdzony. Jeżeli segment zawiera CCecho.681 * sprawdzamy tę opcję, by się jeszcze raz upewnić, że ten682 * segment rzeczywiście odpowiada naszemy segmentowi SYN.683 * Jeżeli nie - odrzucamy segment jako stary duplikat. Jeżeli684 * jednak kierujemy się starymi regułami, to wysyłamy RST.685 */686 if ((to.to_flag 4 T0F_CCECH0) 44687 tp->cc_send != t o .to_ccecho) (688 if (taop->tao_ccsent != 0) (689 tcpstat.tcps_badccecho++;690 goto drop;691 ] else692 goto dropwithreset;693 }694 tcpstat,tcps_connects++;695 soisconnected(so);

696 /* Czy wykonywać skalowanie okna dla tego połączenia? */697 if ((t p ->t_f1ags 4 (TF_RCVD_SCALE | TF_REQ_SCALE)) =698 (TF_RCVD_SCALE | TF_REQ_SCALE)) (699 tp->snd_scale = tp->requested_s_scale;700 tp->rcv_scale = tp->request_r_scale;701 )702 /* Segment jest akceptowalny - uaktualniamy pamięć TAO,

* jeżeli jest niezdefiniowana. */703 if (taop->tao_ccsent == 0)704 taop->tao_ccsent = to.to_ccecho;

705 tp->rcv_adv += tp->rcv_wnd;706 tp->snd_una++; /* SYN jest potwierdzony */

707 /*708 * Jeżeli są dane, opoźniamy ACK; jeżeli jest również FIN709 * flaga ACKNOW zostanie włączona później.710 */711 i f (ti->ti_1en != 0)712 t p ->t_f1ags 1= TF_DELACK;713 else714 tp->t_flags 1= TF_ACKN0W;715 /*716 * Received <SYN,ACK> in SY N__SE NT [*] State.717 * Transitions:718 * SYN_SENT --> ESTABLISHEO719 * SYN_SENT* --> FIN_WAIT_1720 */721 if (tp->t_f1ags & TF_SENDFIN) (722 tp->t_state = TCPS_FIN_WAIT_1;723 tp->t_f1ags 4= ~TF_SENDFIN;724 ti flags 4= ~ T H _ S Y N :725 ) else726 tp->t_state = TCPS_ESTABLISHED:

------------------------------------------------------------------------------------------------ tcpjnputRysunek 11.8 tcp_ input - przetwarzanie odpowiedzi na SYN/ACK w stanie

SYN_SENT

Oznaczenie gniazda jako połączonego i przetworzenie opcji skali okna694 - 701 Gniazdo zostaje oznaczone jako połączone i opcja skali okna jest przetwa­

rzana - jeśli jest obecna.

W implementacji T /TC P Boba Bradena te dwie linie kodu błędnie zostały umieszczone przed sprawdzeniem wartości CCecho.

Page 169: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 11.5 Inicjacja aktywnego otwarcia 147

Aktualizacja pamięci TAO, jeśli pamięć TAO jest niezdefiniowana702-704 Segment jest akceptowalny, więc jeśli wpis TAO dla danego serwera jest

niezdefiniowany (po przeładowaniu klienta i wysłaniu przez niego opcji CCnew), następuje jego uaktualnienie otrzymaną wartością CCecho (0, jeśli opcja CCecho nie jest obecna).

Ustalenie wartości rcv_adv705-706 Wartość rcv_adv zostaje uaktualniona, takjak to pokazano na rysunku 11.4.

Wartość snd_una (najstarszy niepotwierdzony numer sekwencyjny) zostaje zwię­kszona o 1, ponieważ nasz SYN został potwierdzony.

Czy ACK ma być opóźnione?707-714 Jeżeli serwer wysłał dane w swoim segmencie SYN, to opóźniamy potwier­

dzenie. W przeciwnym przypadku wysyłamy ACK natychmiast (jest to bowiem najprawdopodobniej drugi segment potrójnego uzgodnienia). Potwierdzenie zo­staje opóźnione, ponieważ - jeżeli segment SYN serwera zawiera dane - to serwer używa zapewne T/TCP i nie ma powodu, by wysyłać potwierdzenie natychmiast, skoro możemy oczekiwać kolejnych segmentów z dalszym ciągiem odpowiedzi. Jeżeli jednak okaże się, że segment zawiera również flagę FIN serwera (drugi segment minimalnej, trzysegmentowej wymiany T/TCP), kod na rysunku 11.18 włączy flagę TF_ACKN0W, by potwierdzenie zostało wysłane natychmiast.

715-726 W iem y,że t_state równa się TCPS_SYN_SENT,ale jeżeli ukrytaflaga stanuTF_SENDFIN jest również włączona, znajdujemy się w istocie w stanieSYN_SENT*. W tym przypadku przechodzimy do stanu FIN_WAIT_1. (Tak na­prawdę - zgodnie z diagramem zmiany stanów w RFC 1644 - jest to kombinacja dwóch zmian stanów. Otrzymanie flagi SYN w stanie SYN_SENT* zmienia stan na FIN_WAIT_1*, a potwierdzenie naszego segmentu SYN powoduje przejście do stanu FIN_WAIT_1.)

Klauzula el se odpowiadająca instrukcji i f na początku rysunku 11.8 pokazana została na rysunku 11.9. Klauzula ta odpowiada jednoczesnemu otwarciu: wysła­liśmy SYN i następnie otrzymaliśmy SYN bez flagi ACK. Ten fragment kodu zastępuje linie 581-582 na stronie 988 w tomie 2.

Natychmiastowe potwierdzenie i wyłączenie zegara retransmisji739-740 Potwierdzenie jest wysłane natychmiast i zegar retransmisji (retransmission

łimer) zostaje wyłączony. Nawet przy wyłączonym zegarze funkcja tcp_output będzie wy woływana na końcu tcp_input,ponieważ włączona jest flaga TF_ACKN0W. Zegar retransmisji ponownie uruchamia się w momencie, gdy potwierdzenie zo­staje wysłane, ponieważ brak jest potwierdzenia co najmniej jednego bajtu danych (SYN).

Page 170: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

148 Implementacja T/TCP: wejście TCP Rozdział 11

------------------------------------------------------------------------------------------------ tcp_input.c727 } else (728 /*729 * Jednoczesne otwarcie.730 * Otrzymaliśmy inicjujący SYN w stanie SYN-SENT[*].731 * Jeżeli segment zawiera opcję CC i istnieje zachowana wartość732 * CC, stosujemy test TAO. Jeżeli test daje pomyślny wynik,733 * połączenie jest połowicznie zsynchronizowane.734 * W przeciwnym razie wykonujemy potrójne uzgodnienie.735 * SYN-SENT -> SY N - RE C EIV ED736 * SYN-SENT* -> S Y N -RECEIVED*737 * Jeżeli nie było opcji CC - kasujemy zachowaną wartość CC.738 */739 t p ->t_f1ags |= T F _ACKN0W;740 tp->t_ti mer[TCPT_REXMT] = 0;741 if (to.to_flag & TOF_CC) l742 if (taop->tao_cc != 0 && CC_G T( t o.t o _ c c , t a o p->t a o_ cc )) (743 /*744 * uaktualniamy pamięć TAO i wykonujemy przejścia:745 * SYN-SENT -> ESTABLISHED*746 * SYN-SENT* -> FIN-WAIT-1*747 */748 tcpstat.tcps_taook++;749 taop->tao_cc =■- to.to_cc;750 if (tp->t_f1ags & TF_SENDFIN) (751 tp->t_state = T CP S_FIN_WAIT_1;752 t p ->t_f1ags &= ~TF_ SE ND F IN ;753 ) else754 tp->t_state = TCPS_ESTABLISHED:755 t p ->t_f1ags ]= TF__S EN D SY N;756 1 else {757 tp->t_state = TCPS_SYN_RECEIVED:758 if (taop->tao_cc != 0)759 t cp st at .tcps_taofai1++:760 )761 ) else (762 /* CCnew lub brak opcji => skasować pamięć TAO */763 taop->tao_cc = 0;764 tp->t_state = TCPS_SYN_RECEIVED;765 )766 }

-------------------- tcpjnput.cRysunek 11.9 tcp_ inpu t -jednoczesne otwarcie

Wykonanie testu TAO741 - 755 Jeśli otrzymany segment zawiera opcję CC, to wykonywany jest test TAO:

wartość zachowana (tao_cc) musi być niezerowa, a otrzymana wartość CC wię­ksza od wartości zachowanej. Jeśli test TAO daje wynik pozytywny, wtedy prze­chowywana wartość CC zostaje uaktualniona wartością otrzymaną i następuje przejście ze stanu SYN_SENT do ESTABLISHED* lub ze stanu SYN_SENT* do stanu FIN_WAIT_1*.

Negatywny test TAO lub brak opcji CC756-765 Jeśli test TAO daje wynik negatywny, nowym stanem jest SYN_RCVD.

Jeżeli brak było opcji C C , wartość C C w pamięci TAO ustalona zostaje na O (niezdefiniowana) i nowym stanem jest SYN_RCVD.

Page 171: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 11.5 Inicjacja aktywnego otwarcia 149

Na rysunku 11.10 widoczna jest etykieta trimthenstep6, do której wykonany został skok na końcu przetwarzania w stanie LISTEN (rysunek 11.5). Większa część kodu na tym rysunku jest skopiowana ze strony 990 w tomie 2.

------------------------------------------------------------------------------------------------ tcpjnput.c767 trimthenstep6:768 /*769 * Zwiększamy ti->ti_seq tak, by odpowiadał pierwszemy bajtowi770 * danych. Jeżeli są dane, korygujemy ich rozmiar, tak by zmieścić771 * się w oknie, odrzucając FIN, jeśli to konieczne.772 */773 ti->ti_seq++;774 if (ti->ti_len > tp->rcv_wnd) (775 todrop = ti->ti_len - tp->rcv_wnd;776 m_adj(m, -todrop);777 ti ->ti_1en = tp->rcv_wnd;778 tiflags &= —TH__F IN;779 t c ps ta t .tcps_rcvpackafterwi n++;780 tcpst at .tcps_rcvbyteafterwin += todrop;781 )782 tp->snd_wll = ti ->ti_seq - 1;783 tp->rcv_up = ti ->t i_seq;784 /*785 * Jesteśmy klientem transakcji - wysłaliśmy już SYN i dane.786 * Jeżeli partner użył T/TCP do weryfikacji SYN, nasze dane787 * zostaną potwierdzone - jeśli tak, to rozpoczynamy normalne788 * przetwarzanie segmentu danych (w środku step5) i przetwarzamy789 * potwierdzenie. W przeciwnym przypadku wykonujemy skok do step6.790 */791 if (tiflags & TH_ACK)792 goto processack;793 goto step6;

--------------------------------------------------------------- t c p j n p u t . cRysunek 11.10 tcp _i nput-etykieta trim thenstep6 osiągnięta po aktywnym

lub pasywnym otwarciu

ACK nie może być pominięte w przypadku klienta784 - 793 Jeżeli flaga ACK jest włączona, oznacza to, że jesteśmy klientem transakcji.

To znaczy, nasz segment SYN został potwierdzony i znaleźliśmy się tutaj po przejściu ze stanu SYN_SENT, a nie ze stanu LISTEN. W tym przypadku nie możemy wykonać skoku do s tep6, ponieważ spowodowałoby to ominięcie prze­twarzania potwierdzenia (patrz rysunek 11.1). Jeśli wysłaliśmy dane w naszym segmencie SYN, musimy przetworzyć ewentualne potwierdzenie tych danych. (Zwykłe TCP może pominąć przetwarzanie ACK w tym punkcie, ponieważ dane nigdy nie są wysyłane w segmencie SYN.)

Następny krok przetwarzania został wprowadzony wraz z T/TCP. Zwykle instrukcja s w i t c h (rozpoczynająca się na stronie 982 w tomie 2) zawiera tylko przypadki (case) dla stanów LISTEN i SYN_SENT (które właśnie opisaliśmy). T/TC P dodaje przypadki dla stanów LAST_ACK , CLOSING i TIME_WAIT (rysu n ek ll.il).

Page 172: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

150 Implementacja T/TCP: wejście TCP Rozdział 11

------------------------------------------------------------------------------------- ---------- tcpjnput.c794 /*795 * W stanie LAST_ACK, CLOSING lub TIME _W AI T :796 * jeżeli segment zawiera SYN i CC [nie CCnew]797 * i partner rozumie T/TCP (cc_recv != 0):798 * if state == TIME_WAIT i czas trwania połączenia > MSL,

799 * odrzucamy pakiet i wysyłamy RST800 *801 * jeżeli SEG.CC > CCrecv wtedy jest to nowy SYN i może802 * niejawnie potwierdzić FIN (i dane) w kolejce retransmisji.803 * Zamykamy i kasujemy TCPCB. Przetwarzamy segment804 * ponownie - może znajdziemy nowy TCPCB w stanie LISTEN;805 *806 * jeżeli nie - musi to być stary SYN; odrzucić.807 * jeżeli nie - wykonujemy normalne przetwarzanie.808 */809 case TCPS_LAST_ACK:810 case T CP S _CL0SING:811 case T CPS_TIME_WAIT:812 if ((tiflags & T H _ SY N) &&813 (to.to_flag & T0F_CC) && tp->cc_recv != 0) (814 if (tp->t_state == TCPS_TIME_WAIT &&815 tp->t_duration > TCPTV_MSL)816 goto dropwithreset;817 if (CC_GT(to.t o_cc, tp->cc_recv)) {818 tp = tcp_close(tp);819 t c ps ta t.tcps_impliedack++;820 goto findpcb;821 1 else822 goto drop;823 }824 break; /* kontynuujemy normalne przetwarzanie */825 }

------------------------------------------------------------------------------------------------- tcpjnput.cRysunek 11.11 t cp_ in p u t- początkowe przetwarzanie dla stanów LAST_ACK,

CLOSING i TIM EJNAIT

812-813 Następujące sprawdzenia zostają wykonane tylko wtedy, jeśli otrzymany segment zawiera flagę SYN i opcję CC oraz jeśli mamy zachowaną wartość CC dla tego hosta (cc_rec v jest różna od 0). Zauważmy też, że -b y znaleźć się w jednym z tych trzech stanów - moduł TCP musiał wysłać i otrzymać FIN (rysunek 2.6). TCP w stanach LAST_ACK i CLOSING czeka na potwierdzenie wysłanej flagi FIN. Sprawdzane jest więc, czy nowy SYN w stanie TIME_WAIT może bezpiecz­nie skrócić stan TIME_WAIT, albo czy nowy SYN w stanie LAST_ACK lub CLO­SING niejawnie potwierdza wysłaną flagę FIN.

Nie skracać TIME_WAIT, jeśli czas trwania > MSL814-816 Zwykle jest dopuszczalne przyjęcie nowego segmentu SYN w stanie TI-

ME_WAIT (strona 998, tom 2). Jest to niejawne skrócenie stanu TIME_WAIT możliwe w systemach wywodzących się z systemu Berkeley, przynajmniej od czasów Net/ l . (Rozwiązanie ćwiczenia 18.5 z tomu 1 mówi o tej właściwości.) W przypadku T/TCP skrócenie takie nie jest dopuszczalne, jeżeli czas trwania połączenia będącego w stanie TIME_WAIT jest większy niż MSL. Jeśli mamy do czynienia z taką właśnie sytuacją, to jest wysyłana flaga RST. (Mówiliśmy o tym ograniczeniu w rozdziale 4.4.)

Page 173: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 11.6 Zabezpieczenie przed „za winiętymi" numerami sekwencyjnymi (PA WSJ__________ 151_

Nowy SYN jest niejawnym potwierdzeniem istniejącego połączenia817-820 Jeśli otrzymana wartość CC jest większa niż przechowywana wartość CC,

wtedy test TAO daje wynik pozytywny (tzn. jest to nowy SYN). Istniejące połącze­nie zostaje zamknięte i następuje skok z powrotem do f i n d p c b w nadziei znalezie­nia gniazda w stanie LISTEN, by przetworzyć nowy SYN. Na rysunku 4.7 przed­stawiliśmy przykład gniazda serwera, które znajdowałoby się w stanie LAST_ACK, gdy przetwarzane jest niejawne ACK.

11.6 Zabezpieczenie przed „zawiniętymi” numerami sekwencyjnymi (PAWS)

Test PAWS (Protection Against Wrapped Sequence Numbers - zabezpieczenie przed „zawiniętymi" numerami sekwencyjnymi) pozostaje taki sam jak na stronie 991 w tomie 2 - jest to kod wykorzystujący opcję znacznika czasu. Test pokazany na rysunku 11.12 umieszczany jest po sprawdzeniach dotyczących znacznika czasu i sprawdza otrzymaną opcję CC.

------------------------------------------------------------------------------------------------- tcpjnput.c860 /*861 * Mechanizm T/TCP:862 * Jeśli wynegocjowano użycie T/TCP. a segment nie ma CC, lub863 * otrzymana opcja CC jest błędna, to segment należy odrzucić.864 * Segmenty RST nie muszą się do tego stosować.865 */866 if ((tp - >t_f 1 ags & (TF_REQ_CC | TF_RCVD_CC)) = (TF_REQ_CC | TF_RCVD.867 ((to.to flag & TOF CC) = = 0 1 1 tp->cc recv != to.to cc) &&868 (tiflags & T H _ R S T ) == 0) (869 tcpstat.tcps_ccdrop++;870 goto dropafterack;871 )

------------------------------------------------------------------------------------------------- tcpjnput.cRysunek 11.12 tcp_1 nput-sprawdzenie otrzymanej opcji CC

860-871 Jeżeli używany jest protokół T/TCP (flagi TF_REQ_CC i TF_RCVD_CC są włą­czone), wtedy otrzymany segment musi zawierać opcje CC i wartość CC musi być równa wartości użytej dla tego połączenia (cc_recv). W przeciwnym razie seg­ment zostaje odrzucony jako duplikat starego segmentu (ale jest potwierdzony, ponieważ potwierdzone zostają wszystkie duplikaty starych segmentów). Jeżeli segment zawiera flagę RST, to nie zostaje on odrzucony, ale jest przetwarzany przez odpowiedni fragment kodu w dalszej części funkqi.

11.7 Przetwarzanie ACKNa stronie 1006 w tomie 2 widać, że segment zostaje odrzucony po przetworzeniu RST, jeżeli flaga ACK nie jest ustawiona. To normalne zachowanie TCP zostaje zmodyfikowane w przypadku T/TCP - odpowiedni fragment kodu pokazujemy na rysunku 11.13.

Page 174: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

152 Implementacja T/TCP: wejście TCP Rozdział 11

------------------------------------------------------------------------------------------------ tcpjnput.c1024 /*1025 * Jeżeli bit ACK jest 0 to w stanie SYN-RECEIVED lub przy ustawionej1026 * fladze SENDSYN (połowiczna synchronizacja), dane umieszczamy1027 * w kolejce - zostaną przetworzone później. W innych przypadkach -

* odrzucamy segment.1028 */1029 if ((ti flags & TH_ACK) == 0) {1030 if (t p ->t_state == TCPS_SYN_RECEIVED ||1031 (t p ->t_f1ags & TF_SENDSYN))1032 goto step6;1033 else1034 goto drop;1035 )

------------------------------------------------------------------------------------------------- tcpjnput.cRysunek 11.13 tcp_i n p u t- obsługa segmentów bez flagi ACK

1024-1035 Jeżeli flaga ACK jest wyłączona, to w stanie SYN_RCVD lub przy włączo­nej fladze T F_S E N D S Y N (tzn. połowiczna synchronizacja), segment nie jest odrzuca­ny, lecz następuje skok do s t e p 6. W ten sposób obsługujemy przypadek segmentu danych, który przybywa bez flagi ACK przed ustanowieniem połączenia, ale po początkowym segmencie SYN (przykładami takich segmentów są segmenty 2 i 3 z rysunku 3.9).

11.8 Zakończenie pasywnych i jednoczesnych otwarćPrzetwarzanie ACK jest kontynuowane w kodzie opisanym w rozdziale 29 w to­mie 2. Większość kodu na stronie 1011 pozostaje bez zmian (linia 806 jest usunię­ta), a kod na rysunku 11.14 zastępuje linie 813-815. W tym miejscu jesteśmy w stanie SYN_RCVD i przetwarzamy ACK, które zakańcza potrójne uzgodnienie. Jest to normalne przetwarzanie po stronie serwera.

------------------------------------------------------------------------------- tcpjnput.cI*

* Po pomyślnym przeprowadzeni u potrójnego uzgodnienia uaktualniamy* pamięć TAO - jeżeli była niezdefiniowana. Przekazujemy dane z* kolejki do użytkownika i odpowiednio określamy stan połączenia.*/

if ((taop = tcp_gettaocache(inp)) != NULL && taop->tao_cc == 0) taop->tao_cc = tp->cc_recv;

/** Wykonujemy przejścia:* SYN-RECEIVED -> ESTABLISHED* SYN-RECEIVED* -> FIN-WAIT-1 */

if (tp->t_f1ags & TF_SENDFIN) ( tp->t_state = TCPS_FIN_WAIT_1; t p ->t_f1ags &= ~ T F_SENDFIN:

) el setp->t_state = TCPS_ESTABLISHED;

/** Jeżeli segment zawiera dane lub FIN, tcp_reass() wywołamy później;

* jeżeli nie - robimy to teraz, by przekazać dane z kolejki do użytkownika.*/

1057105810591060 1061 106210631064

1065106610671068106910701071107210731074

1075107610771078

Page 175: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 11.9 Przetwarzanie ACK (kontynuacja) 153

1079 if (t i ->ti_len == 0 && (tiflags & TH_FIN) == 0)1080 (void) tcp_reass(tp, (struct tcpiphdr *) 0,1081 (struct mbuf *) 0);1082 tp->snd_wll = t i ->ti_seq - 1;1083 /* wpadamy w ... */

------------------------------------------------------------------------------------------------ tcpjnput.cRysunek 11.14 tcp_ in p u t- zakończenie aktywnego lub pasywnego otzuarcia

Aktualizacja zachowanej wartości CC, jeśli wartość ta jest niezdefiniowana1057-1064 Wpis TAO dla danego partnera zostaje wczytany i - jeśli przechowywana

wartość CC wynosi 0 (niezdefiniowana) - zostaje ona uaktualniona otrzymaną wartością CC. Zwracamy uwagę, że zdarza się to tylko wtedy, jeżeli wartość przechowywana jest niezdefiniowana. Przypominamy, że na rysunku 11.6 zmien­na tao_cc jawnie otrzymała wartość 0, jeśli opcja CC była nieobecna (więc ta aktualizacja będzie miała miejsce, jeśli przeprowadzone zostało potrójne uzgod­nienie). Natomiast gdy test TAO dał wynik negatywny, wartość tao_cc pozostała nie zmieniona. W przypadku negatywnego wyniku testu TAO chodzi o to, by segment SYN - przybywający w nieprawidłowej kolejności - nie spowodował zmiany tao_cc, tak jak to przedstawiliśmy na rysunku 4.11.

Przejście do nowego stanu1065-1074 Stan SYN_RCVD przechodzi w stan ESTABLISHED i jest to normalna

zmiana stanów TCP dla serwera zakańczającego potrójne uzgodnienie. Stan SYN_RCVD* przechodzi w stan FIN_WAIT_1, ponieważ proces zamknął wysyła­jącą część połączenia przy pomocy flagi M S G _ E 0 F .

Sprawdzenie: dane lub FIN1075-1081 Jeśli segment zawiera dane lub flagę FIN, to - by przekazać dane do

procesu - w punkcie oznaczonym etykietą doda ta wywoływana jest makroinstruk­cja TCP_REASS (przypominamy rysunek 11.1). Na stronie 1031 w tomie 2 pokazano wywołanie tej makroinstrukcji w punkcie doda ta i ten kod nie zmienia się przy wprowadzeniu T/TCP. W przeciwnym przypadku - by przekazać do procesu dane znajdujące się w kolejce - tcp_reass jest wywoływana tutaj z drugim argumentem równym 0.

11.9 Przetwarzanie ACK (kontynuacja)Algorytm szybkiej retransmisji (fast retransmit) i algorytm szybkiego odtworzenia połączenia (fast recovery) (rozdział 29.4 w tomie 2) pozostają niezmienione. Kod przedstawiony na rysunku 11.15 powinien zostać umieszczony pomiędzy liniami 899 i 900 na stronie 1017 w tomie 2.

Page 176: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

154 Implementacja T/TCP: wejście TCP Rozdział 11

------------------------------------------------------------------------------------------------ tcpjnput.c1168 / *1169 * Jeżeli osiągnęliśmy ten punkt, ACK nie jest duplikatem,1170 * czyli coś potwierdza.1171 */1172 if (tp->t_f1ags & TF_SENDSYN) (1173 /*1174 * T/TCP: Połączenie było połowicznie zsynchronizowane i nasz1175 * SYN został potwierdzony (połączenie jest więc teraz1176 * w pełni zsynchronizowane). Wchodzimy w stan bez gwiazdki1177 * i zwiększamy snd_una dla ACK segmentu SYN.1178 */1179 t p ->t_f1ags &= ~TF_SENDSYN;1180 tp->snd_una++;1181 I1182 processack:

------------------------------------------------------------------------------------------------- tcpjnput.cRysunek 11.15 tcp_i n p u t- wyłączenie flagi TF_SENDSYN, jeśli jest ona włączona

Wyłączenie ukrytej flagi stanu TF_SENDSYN1168-1181 Jeśli ukryta flaga stanu T F _ S E N D S Y N była włączona, zostaje ona wyłączo­

na. Dzieje się tak dlatego, bo otrzymana flaga ACK potwierdza coś, co wcześniej wysłaliśmy, więc połączenie nie znajduje się już w trybie połowicznej synchroni- zaq'i. Wartość snd_una zostaje zwiększona o 1, ponieważ segment SYN został potwierdzony i SYN zajmuje 1 bajt w przestrzeni numerów sekwencyjnych.

Kod przedstawiony na rysunku 11.16 powinien zostać umieszczony pomiędzy liniami 926 i 927 na stronach 1018-1019 w tomie 2.

------------------------------------------------------------------------------------------------- tcpjnput.c1210 / *1211 * Jeżeli potwierdzony był tylko SYN (a nie dane),1212 * pomijamy resztę Drzetwarzania ACK.1213 */1214 if (acked == 0)1215 goto step6;

------------------------------------------------------------------------------------------------- tcpjnput.cRysunek 11.16 tcp_input -pominąć pozostałą część przetwarzania ACK,

jeżeli żadne dane nie zostały potwierdzone

Koniec przetwarzania ACK, jeżeli brak potwierdzenia danych1210-1215 Jeżeli nie nadeszło żadne potwierdzenie danych (jedynie potwierdzony

został nasz segment SYN), pozostała część przetwarzania ACK jest pomijana. Pominięty zostaje fragment kodu, który otwiera okno przeciążenia (congestion window) i usuwa potwierdzone dane z bufora wysyłkowego.

T o sprawdzenie i skok w y k o n y w a n e są niezależnie o d T / T C P . W ten sposób s k o r y g o w a ­

n y zostaje błąd o m a w i a n y w rozdziale 14.12, polegający na tym, że serwer rozpoczyna

p o w o l n y start wysyłając d w a j e dnakowe (back-to-back) segmenty zamiast jednego.

Następna zmiana pokazana została na rysunku 11.17, który zastępuje rysunek 29.12 ze strony 1023 w tomie 2. Jesteśmy w stanie CLOSING i przetwarzamy ACK, co powoduje zmianę stanu połączenia na TIME_WAIT. T/TCP może umożliwić skrócenie stanu TIME_WAIT (rozdział 4.4).

Page 177: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 11.10______________________ Przetwarzanie flagi FIN_______________________________155

------------------------------------------------------------------------------------------------ tcpjnput.c1266 /*1267 * W stanie CLOSING, w uzupełnieniu przetwarzania dla stanu1268 * ESTABLISHED, jeżeli ACK potwierdza nasz FIN,1269 * to wchodzimy w stan TIME-WAIT: w przeciwnym razie ignorujemy1270 * segment.1271 */1272 case T CP S _CLOSING:1273 if (ourfinisacked) (1274 tp->t_state = TCPS_TIME_WAIT;1275 tcp_canceltimers(tp):1276 /* Skrócenie TIME_WAIT [RFC 1644, str.28] */1277 if (tp->cc_recv != 0 U tp->t_duration < TCPTV_MSL)1278 tp->t_timer[TCPT_2MSL] = tp->t_rxtcur * TCPT V_ T WT RU NC ;1279 else1280 tp->t_ti mer[TCPT_2MSL] = 2 * TCPTV_MSL;1281 soisdisconnected(so):1282 )1283 break;

------------------------------------------------------------------------------------------------ tcpjnput.cRysunek 11.17 tcp_ i n p u t- potzuierdzenie otrzymane w stanie T1ME_WAIT;

ustalenie czasu trwania stanu TIME_WAIT

1276-1280 Jeśli otrzymaliśmy od partnera wartość CC i czas trwania połączenia był krótszy niż MSL, czas trwania stanu TIME_WAIT zostaje ustalony na T C P T V_T W T R U N C (8) razy aktualny czas oczekiwania na retransmisję.

11.10 Przetwarzanie flagi FINNastępne trzy sekcje przetwarzania na wejściu TCP - aktualizacja informacji okna, przetwarzanie w trybie nagłym i przetwarzanie otrzymanych danych - pozostają nie zmienione w protokole T/TCP (patrz rysunek 11.1). Przypominamy również (rozdział 29.9 w tomie 2), że jeżeli flaga FIN jest ustawiona, ale nie może być potwierdzona, ponieważ pojawiła się przerwa w ciągu numerów sekwencyjnych, kod w tej części tcp_i nput wyłącza flagę FIN. Dlatego na tym etapie przetwarza­nia wiemy, że flaga FIN powinna zostać potwierdzona.

Następna zmiana, którą pokazujemy na rysunku 11.18, pojawia się przy przetwa­rzaniu flagi FIN. Kod przedstawiony na tym rysunku zastępuje linię 1123 na stronie 1033 w tomie 2.

Decyzja o opóźnieniu ACK1414-1424 Jeśli połączenie jest połowicznie zsynchronizowane (czyli ukryta flaga

stanu TF_SENDSYN włączona), potwierdzenie zostaje opóźnione i nastąpi próba wysłania potwierdzenia w segmencie zawierającym dane (piggyback ACK). Jest to typowa sytuacja dla serwera T/TCP otrzymującego segment SYN w stanie LISTEN - powoduje to ustawienie flagi T F_S E N DS Y N przez kod z rysunku 11.5. Zauważmy, że flaga opóźnionego potwierdzenia została już ustawiona na rysun­ku 11.5, obecnie jednak TCP podejmuje decyzję na podstawie flagi FIN, która jest również ustawiona. Jeżeli flaga TF_SENDSYN nie jest włączona, potwierdzenie nie zostaje opóźnione.

Page 178: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

156 Implementacja T/TCP: wejście TCP Rozdzia łu

------------------------------------------------------------------------------------------------ tcpjnput.c1407 /*1408 * Jeżeli otrzymaliśmy FIN - potwierdzamy FIN i informujemy1409 * użytkownika, że połączenie jest zamykane.1410 */1411 if (ti flags & T H_FIN) (1412 if (TC PS_HAV ERCVDFIN(tp->t_s ta t e ) == 0) (1413 socantrcvmore(so);1414 /*1415 * Jeżeli połączenie jest połowicznie zsynchronizowane (tzn.1416 * włączona flaga TF_SENDSYN), to opóźniamy ACK - zostanie1417 * ono nałożone na wysyłany SYN.1418 * Jeżeli nie jest, skoro otrzymaliśmy FIN, nie otrzymamy nic1419 * więcej, więc wysyłamy ACK teraz.1420 */1421 if (t p ->t_f 1 ags & TF_SENDSYN)1422 t p ->t_f 1 ags |= TF_DELACK;1423 else1424 t p ->t_f 1 ags |= T F_ACKN0W;1425 tp->rcv_nxt++;1426 1

------------------------------------------------------------------------------------------------ tcpjnput.cRysunek 11.18 tcp_i nput-decyzja czy ACK ma być opóźnione

Normalnie przejście do stanu TIME_WAIT następuje ze stanu FIN_WAIT_2. To również musi być zmodyfikowane na potrzeby T/TCP, tak by możliwe było skrócenie stanu TIME_WAIT (rozdział 4.4). Jest to pokazane na rysunku 11.19. Kod zaprezentowany na tym rysunku zastępuje linie 1142-1152 ze strony 1035 w tomie 2.

tcpjnput.c1443 /*1444 * W stanie FIN_WAIT_2 wchodzimy w stan TIME_WAIT,1445 * rozpoczynając odliczanie czasu oczekiwania i wyłączając1446 * inne standardowe zegary.1447 */1448 case TCPS FIN WAIT 2:1449 tp->t_state = TCPS_TIME_WAIT;1450 tcp canceltimers(tp):1451 /* Skrócenie TIME_WAIT [RFC 1644, str.28] */1452 if (tp->cc recv != 0 && tp->t duration < TCPTV MSL) (1453 tp->t_timer[TCPT_2MSL] = tp->t_rxtcur * TCPTV_TWTRUNC;1454 /* Dla klienta transakcyjnego wymuszamy teraz ACK */1455 t p ->t_f1ags |= TF_ACKN0W;1456 1 else1457 tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;1458 soisdisconnected(so);1459 break;

------------------------------------------------------------------------------------------------- tcpjnput.cRysunek 11.19 tcp_ in p u t- przejście do stanu TIMEJNAIT, ewentualnie

skrócenie oczekiwania

Określenie czasu trwania TIME_WAIT1451-1453 Stan TIME_WAIT zostaje skrócony tylko wtedy, gdy otrzymaliśmy od

partnera opcję CC i czas trwania połączenia jest mniejszy niż MSL (podobnie jak na rysunku 11.17).

Page 179: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 11.11 Podsumowanie 157

Wymuszenie natychmiastowego potwierdzenia flagi FIN1454-1455 Ta zmiana stanu zachodzi zwykle w module klienta T/TCP, kiedy

odpowiedź serwera zawiera flagi SYN i FIN. Ponieważ oba końce połączenia wysłały flagi FIN, flaga FIN serwera powinna być potwierdzona natychmiast - nie ma powodu, by opóźniać potwierdzenie.

Są dwie sytuacje, w których czas trwania stanu TIME_WAIT zaczyna być liczony od nowa: otrzymanie ACK w stanie TIME_WAIT oraz otrzymanie flagi FIN w stanie TIME_WAIT (strony 1024 i 1035 w tomie 2). T /T C P nie wprowadza tu zmian. Oznacza to, że - nawet jeśli stan TIME_WAIT został skrócony i jeżeli zduplikowana flaga ACK lub FIN została otrzymana w tym stanie - czas trwania stanu zostaje ustawiony ponownie na 2MSL, a nie na zmniejszoną wartość. Informacja potrzebna do ustalenia skróconego czasu trwania stanu jest wciąż dostępna (tzn. blok kontrolny), ale ponieważ partner musiał powtórzyć transmisję, bezpieczniej jest zrezygnować ze skrócenia stanu TIME_WAIT.

11.11 PodsumowanieWiększość zmian związanych z T/TCP zlokalizowanych jest w tcp_i nput i doty­czy głównie otwierania nowego połączenia.

Jeżeli segment SYN zostaje odebrany w stanie LISTEN, to wykonujemy test TAO. Jeżeli segment przejdzie przez ten test z wynikiem pozytywnym, oznacza to, że nie jest to duplikat starego segmentu i potrójne uzgodnienie nie musi być przepro­wadzone. Jeżeli segment SYN odbieramy w stanie SYN_SENT, opcja CCecho (jeśli była użyta) pozwala stwierdzić, czy SYN nie jest duplikatem starego seg­mentu. Jeżeli segment SYN zostaje odebrany w stanie LAST_ACK, CLOSING lub TIME_WAIT, segment ten może być niejawnym potwierdzeniem, zamykającym ostatecznie istniejące wcielenie połączenia.

Jeżeli połączenie zostaje aktywnie zamknięte, stan TIME_WAIT zostaje skrócony, pod warunkiem że czas trwania połączenia był krótszy niż MSL.

Page 180: Biblia TCP IP Tom 3 - Uzupelnienie.pdf
Page 181: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Implementacja T/TCP: żądania użytkownika TCP12

12.1 WstępFunkcja tcp_ussreq obsługuje wszystkie żądania PRlLxxx warstwy gniazd. W obecnym rozdziale omówimy jedynie żądania PRU_CONNECT, PRU_SENDi PRU_SEND_EOF, ponieważ tylko one ulegają zmianom przy wprowadzeniu T / T C P . Omawiamy również funkcję tcp_us rcl osed, wywoływaną, kiedy proces kończy wysyłanie danych, oraz funkcję tcp_sysctl , która obsługuje nowe zmien­ne TCP.

Nie omawiamy zmian w kodzie funkcji tcp_ctl output (rozdział 30.6 tomu 2) potrzebnych do obsługi nowych opcji gniazd: TCP_N0PUSH i TCP_N00PT. Koniecz­ne zmiany są dość proste i jednoznacznie wynikają z samego kodu źródłowego.

12.2 Żądanie PRU_CONNECTPrzetwarzanie żądań PRU_C0NNECT przez funkcję tcp_usrreq wymagało około 25 linii kodu (strona 1055 w tomie 2). Wraz z wprowadzeniem T/TC P większość kodu zostaje przeniesiona do funkcji tcp_connect (którą pokazujemy w nastę­pnym podrozdziale), a pozostaje tylko fragment kodu przedstawiony na rysunku 12.1.

------------------------------------------------------------------------------------------------ tcp_usrreq.c137 case PRU.CONNECT:138 if ((error = tcp_connect(tp, nam)) != 0)139 break;140 error = tcp_output(tp);141 break;

------------------------------------------------------------------------------------------------- tcp_usrreq.cRysunekl2.1 Żądanie PRU_CONNECT

137-141 tcp_connect wykonuje kroki konieczne do nawiązania połączenia, a tcp_output wysyła segment SYN (aktywne otwarcie).

Nawet jeżeli oba hosty - lokalny i ten, z którym nawiązywane jest połączenie - znają T/TCP, gdy proces wywołuje connect, następuje normalne potrójne uzgod­nienie. Dzieje się tak, ponieważ nie jest możliwe przesłanie danych jednocześnie z wywołaniem funkcji connect i funkcja tcp_output wysyła tylko segment SYN. Aby pominąć potrójne uzgodnienie, aplikacja nie może wywoływać connect, powinna w zamian wywołać sendto lub sendmsg, podając dane i adres serwera.

Page 182: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

160 Implementacja T/TCP: żądanie użytkownika TCP Rozdział 12

12.3 Funkcja tcp_connectNowa funkcja t c p_c o n n e c t czyni kroki konieczne do przeprowadzenia aktywne­go otwarcia. Funkcja ta jest wywoływana, gdy proces wykonuje connect (żądanie PRU_CONNECT) lub gdy proces wywołuje sendto lub sendmsg, podając adres part­nera, z którym ma być nawiązane połączenie. Pierwsza część tcp_connect poka­zana została na rysunku 12.2.

------------------------------------------------------------------------------------------------ tcp_usrreq.c295 int296 tcp_connect(tp. nam)297 struct tcpcb *tp;298 struct mbuf *nam;299 [300 struct inpcb *inp = tp->t_inpcb. *oinp:301 struct socket *so = inp->inp_socket;302 struct tcpcb *otp;303 struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);304 struct sockaddr_in *ifaddr;305 int error;306 struct rmxp_tao *taop;307 struct rmxp_tao tao_noncached;

308 if (i np->inp_1port == 0) (309 error = in_pcbbind(inp. NULL);310 if (error)311 return (error);312 ]313 /*314 * Nie można po prostu wywołać in_pcbconnect, ponieważ może istnieć315 * wcześniejsze wcielenie tego samego połączenia, pozostające w stanie316 * TIME_WAIT - spowodowałoby to błąd A DDRINUSE.317 */318 error = in_pcbladdr(i n p , nam, &ifaddr);319 oinp = in_pcblookup(inp->inp_head,320 sin->sin_addr. sin->sin_port.321 inp->inp_laddr.s_addr != INADDR_ANY ?322 inp-> inp_laddr : ifaddr->sin_addr,323 inp->inp_lport, 0):

324 if (oinp) {325 if (oinp != inp && (otp = intotcpcb(oinp)) != NULL &&326 otp->t_state == TCPS_TIME_WAIT &&327 otp->t_duration < TCPTV_MSL &&328 (otp->t_f1ags & TF_RCVD_CC))329 otp = tcp_close(otp);330 else331 return (EADDRINUSE):332 ]333 if (inp->inp__1a d d r .s_addr == INADDR_ANY)334 inp->inp_laddr = ifaddr->sin_addr;335 inp->inp_faddr = sin->sin_addr;336 inp->inp_fport = sin->sin_port;

------------------------------------------------------------------------------------------------- tcp_usrreq.cRysunek 12.2 Funkcja tcp_connect, część pierwsza

Związanie lokalnego portu308-312 nam wskazuje na internetową strukturę adresową zawierającą adres IP i nu­

mer portu serwera, z którym ma być nawiązane połączenie. Jeżeli lokalny port nie

Page 183: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 12.3 Funkcja tcp_connect 161

został jeszcze przypisany do gniazda (zwykły przypadek), i n_pcbbi nd przypisuje numer takiego portu (strona 758 w tomie 2).

Przypisanie lokalnego adresu, sprawdzenie jednoznaczności pary gniazd313-323 i n_pcbl addr przypisuje lokalny adres, jeśli taki adres nie został jeszcze

związany z gniazdem (normalny przypadek). Funkcja i n_pcbl ookup szuka pasu­jącego bloku, zwracając niezerowy wskaźnik, jeżeli blok taki zostaje znaleziony. Pasujący blok powinien zostać znaleziony jedynie wtedy, gdy proces związał się z konkretnym lokalnym portem. Jeśli i n_pcbbi nd wybiera lokalny port - jest to port aktualnie nie używany. W przypadku T/TCP jest bardziej prawdopodobne, że klient zwiąże się z jednym lokalnym portem dla całego zestawu transakcji (rozdział 4.2).

Połączenie istnieje; sprawdzenie, czy TIME_WAIT może być skrócony324-332 Jeśli znaleziony został pasujący blok, wykonywane są następujące spraw­

dzenia:

- czy blok jest w stanie TIME_WAIT,

- czy czas trwania połączenia był krótszy niż MSL,

- czy połączenie używało T/TCP (to znaczy, czy opcja CC lub CCnew została otrzymana od partnera).

Jeśli wszystkie te warunki są spełnione, istniejący blok zostaje zamknięty przez tcp_cl ose. Jest to skrócenie stanu TIME_WAIT, gdy nowe połączenie używa tej samej pary gniazd i wykonuje aktywne otwarcie. Omawialiśmy ten przypadek w rozdziale 4.4.

Uzupełnienie pary gniazd w internetowym PCB333-336 Jeśli lokalny adres ma wciąż formę wieloznaczną (wildccird), wartość wyzna­

czona przez i n_pcb 1 addr zostaje zapisana w PCB. Zewnętrzny (foreign) adres i port również zostają zapisane w PCB.

Kolejne kroki na rysunku 12.2 są podobne do odpowiednich kroków w końcowej części rysunku 7.5. Końcowa część tcp_connect pokazana została na rysunku 12.3. Ten kod jest podobny do ostatniej części żądania PRU_CONNECT ze strony 1055 w tomie 2.

Inicjacja nagłówków IP i TCP337-341 tcp_templ a te alokuje mbuf dla kopii nagłówków IP i TCP oraz inicjuje oba

nagłówki, wpisując w nie wszystkie możliwe (aktualnie dostępne) informacje.

Obliczenie czynnika skali okna342 - 345 Zostaje wyznaczona wartość czynnika skali okna dla bufora odbiorczego .

Page 184: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

162 Implementacja T/TCP: żądanie użytkownika TCP Rozdział 12

------------------------------------------------------------------------------------------------- łcp_usrreq.c337 tp->t_template = tcp_template(tp);338 if (tp->t_template == 0) (339 in_pcbdisconnect(inp);340 return (ENOBUFS);341 )342 /* Obliczamy żądane skalowanie okna */343 while (tp->request_r_scale < TCP_MAX_WINSHIFT &&344 (TCP_MAXWIN << tp->request_r_sca1e ) < so->so_rcv,sb_hiwat)345 tp->request_r_scale++;

346 soisconnecting(so);347 tcpstat.tcps_connattempt++;348 tp->t_state = TCPS_SYN_SENT;349 tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;350 t p ->i ss = tcp_iss;351 t c p j s s += TCP_ISSINCR / 4;352 tcp_sendseqi ni t C t p ) ;

353 /*354 * Generujemy wartość CC dla tego połączenia i sprawdzamy, czy355 * należy użyć CC, czy też CCnew.356 */357 if ((taop = tcp_gettaocache(tp->t_inpcb)) == NULL) (358 taop = &tao_noncached;359 bzerottaop, sizeof(*taop)):360 )361 tp->cc_send = CC_INC(tcp_ccgen);362 if (taop->tao_ccsent != 0 &&363 CC_GEQ(tp->cc_send, taop->tao_ccsent)) (364 taop->tao_ccsent = tp->cc_send;365 ] else 1366 taop->tao_ccsent = 0;367 tp->t_f1ags 1= TF_SENDCCNEW;368 )

369 return (0);370 )

------------------------------------------------------------------------------------------------- tcp_usrreq.cRysunek 12.3 Funkcja tcp_connect, część druga

Ustalenie stanu gniazda i połączenia346-349 soi sconnecti ng ustawia odpowiednie bity w zmiennej stanu gniazda,

a stan połączenia T C P jest ustalony na SYN_SENT. (Zobaczymy wkrótce, że jeżeli proces wywołał sendto lub sendmsg z flagą MSG_E0F zamiast connect, to funkcja tcp_usrcl osed ustawia ukrytą flagę stanu TF_SENDSYN, wprowadzając połącze­nie w stan SYN_SENT*. Zegar nawiązywania połączenia zostaje zainicjowany wartością 75 sekund.)

Inicjacja numerów sekwencyjnych350-352 Początkowy wysyłkowy numer sekwencyjny zostaje skopiowany z global­

nej zmiennej tcp_iss i zmienna ta zostaje następnie zwiększona o wartość TCP_ ISSI NCR podzieloną przez4. Wysyłkowe numery sekwencyjne są inicjowane przez tcp_sendseqi ni t.

Przypisanie ISS losowej wartości, co omawialiśmy w rozdziale 3.2, odbywa się w makro- instrukqi TCP_ISSINCR.

Page 185: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 12.4 Żądania PRU_SEND i PRU_SEN D _EO F 163

Ustalenie wartości CC3 5 3 -3 6 1 Zawartość pamięci TAO dla danego partnera zostaje wczytana. Wartość

zmiennej globalnej tcp_ccgen jest zwiększana o CC_I NC (rozdział 8.2) i zapisuje się ją w zmiennej tcp_ccgen. Tak jak zauważyliśmy wcześniej, wartość t c p_c c g e n jest zwiększana dla każdego połączenia nawiązywanego przez hosta - bez względu na to, czy opcje CC są używane, czy nie.

Stwierdzenie, czy opcja CC lub CCnew ma być używana3 6 2 - 3 6 8 Jeżeli wpis w pamięci TAO dla danego hosta (tao_ccsent) jest niezerowy

(czyli to nie pierwsze połączenie z tym hostem) i wartość cc_send jest większa bądź równa tao_ccsent (wartość CC nie jest „zawinięta"), wtedy opcja CC zostaje wysła­na i do pamięci TAO wpisuje się nową wartość CC. W przeciwnym przypadku, wysłana jest opcja C C n ew i t a o_c c s e n t otrzymuje wartość 0 (niezdefiniowana).

Wróćmy do rysunku 4.12, by zobaczyć, w jaki sposób druga część instrukcji i f może otrzymać wartość „fałsz" - ostatnia wartość CC wysłana do tego hosta wynosi 1 (tao_ccsent), ale aktualna wartość tcp_ccgen (która staje się wartością cc_send dla tego połączenia) jest 2 147483 648. T/TCP musi wysłać opcję CCnew zamiast opcji CC, ponieważ - jeśli wyślemy opcję CC z wartością 2 147 483 648, a partner ciągle przechowuje naszą ostatnią wartość CC (1) - partner wymusi potrójne uzgodnienie, wartość CC jest bowiem „zawinięta". Host na drugim koń­cu połączenia nie może stwierdzić, czy SYN z wartością CC równą 2 147 483 648 jest duplikatem starego segmentu, czy nie. Również, jeżeli wyślemy opcję CC, nawet po pomyślnym przeprowadzeniu potrójnego uzgodnienia, partner nie uaktualni informacji TAO dla naszego hosta (przypominamy rysunek 4.12 raz jeszcze). Wysyłając opcję CCnew, klient wymusza potrójne uzgodnienie oraz po­woduje, że serwer po przeprowadzeniu potrójnego uzgodnienia, uaktualni zacho­waną wartość CC.

Implementacja T/TC P Boba Bradena sprawdza, czy należy wysłać opcję CC, czy też CCnew w funkcji tcp_output, a nie tutaj. Jest to przyczyną subtelnego błędu, który uwidacznia się w sposób opisany poniżej [Olah 1995]. Rozważmy sytuację przedstawioną na rysunku 4.11, ale załóżmy, że segment 1 zostaje skasowany przez jakiś pośredniczący ruter. Segmenty 2-4 pozostają bez zmian i to połączenie z portu 1601 klienta zakończone zostaje pomyślnie. Następnym segmentem jest przesłany ponownie segment 1. Zawiera on jednak teraz opcję CCnew z wartością 15. Jeżeli segment ten jest pomyślnie odebrany, wymusza on potrójne uzgodnienie ze strony serwera. Po przeprowadzeniu potrójnego uzgodnienia serwer wpisuje do pamięci TAO dla klienta wartość CC równą 15. Jeżeli sieć dostarczy teraz duplikat starego segmentu 2 z wartością CC 1500, segment ten zostanie zaakceptowany przez serwera. Sprawdzenie czy wysłać opcję CC, czy CCnew powinno więc odbywać się, gdy klient wykonuje aktywne otwarcie, a nie - gdy segment jest wysyłany przez t c p_o u t p u t.

12.4 Żądania PRU_SEND i PRU_SEND_EOFNa stronie 1058 w tomie 2 przetwarzanie żądania PRU_SEND sprowadza się do wywołania sbappend i następnie tcp_output. W przypadku T/TCP żądanie to jest przetwarzane dokładnie w ten sam sposób, jednak kod jest teraz połączony

Page 186: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

164 Implementacja TfTCP: żądanie użytkownika TCP Rozdział 12

z kodem odpowiedzialnym za przetwarzanie żądania PRU_SEND_EOF, co pokazu­jemy na rysunku 12.4. Widzieliśmy wcześniej, że żądanie PRU_SEND_EOF jest wygenerowane dla TCP przez sosend, gdy została podana flaga MSG_E0F (rysu­nek 5.2) i gdy do protokołu został wysłany ostatni bufor mbuf.

------------------------------------------------------------------------------------------------ tcpjusrrecj.c169 case PRU_SEND_E0F:190 case PRU_SEND:191 sbappend(&so->so_snd, m);192 if (nam && tp->t_state < TCPS_SYN_SENT) (193 /*194 * Jeżeli połączenie nie jest jeszcze nawiązane, wykonujemy195 * niejawne otwarcie, inicjujemy okno wartością domyślną i196 * inicjujemy maxseg/maxopd używając wartości MSS zachowanej197 * dla tego partnera.198 */199 error = tcp_connect(tp, nam);200 if (error)201 break;202 tp->snd_wnd = TTCP_CLIENT_SND_WND;203 tcp_mssrcvd(tp, -1);204 ]205 if (req == PRU_SEND_E0F) [206 / *207 * Zamknąć wysyłającą połowę połączenia, jeżeli dane208 * zostały wysłane.209 */210 socantsendmore(so);211 tp = tcp_usrclosed(tp);2 1 2 1

213 if (tp != NULL)214 error = tcp_output(tp);215 break;

------------------------------------------------------------------------------------------------- tcp_usrreq.cRysunek 12.4 Żądania PRU_SEND i PRU_SEND_EOF

Niejawne connect192-202 Jeśli argument n a m jest niepusty, oznacza to, że proces wywołał sendto lub

s en dms g i podał adres partnera. Jeśli połączenie jest w stanie CLOSED lub LISTEN, wtedy tcp_connect niejawnie nawiązuje połączenie. Początkowy rozmiar okna zostaje ustawiony na 4096 (TTC P_C LIE N T_S N D_W N D), ponieważ klient T/TC P może wysłać dane przed otrzymaniem od serwera informacji o rozmiarze okna (rozdział 3.6).

Ustalenie początkowej wartości MSS dla połączenia203-204 Wywołanie tcp_mssrcvd z drugim argumentem równym -1 oznacza, że

jeszcze nie otrzymaliśmy segmentu SYN, tak więc wartość przechowywana dla tego hosta (t a o_ms s opt) zostaje użyta jako początkowa wartość MSS. Po wykona­niu tcp_mssrcvd wartości zmiennych t_maxseg i t_maxopd są ustalane na pod­stawie przechowywanej wartości t a o_ms s opt lub na podstawie wartości dla kon­kretnego hosta wpisanej przez administratora systemu do tablicy rutowania (człon rmx_mtu struktury rt_metri cs). Funkcja tcp_mssrcvd zostanie wywołana ponownie przez tcp_doopt i ons, gdy serwer otrzyma segment SYN z opcją MSS. T/TCP musi jednak ustalić wartość MSS w bloku kontrolnym TCP teraz, przed

Page 187: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 12.5 Funkcja tcp_usrclosed 165

otrzymaniem segmentu SYN, ponieważ dane są wysyłane przed otrzymaniem opcji MSS od partnera.

Przetwarzanie flagi MSG.EOF205-212 Jeśli flaga MSG_E0F była podana przez proces, socantsendmore ustawia

flagę gniazda SS_CANTSENDM0RE. Funkcja tcp_usrcl osed zmienia wówczas stan połączenia ze stanu SYN_SENT (ustawionego przez tcp_connect) na stan SYN_SENT*.

Wysłanie pierwszego segmentu213-214 tcp_output sprawdza, czy segment powinien być wysłany. W przypadku

klienta T/TCP, który wywołuje sendto z flagą MSG_E0F (rysunek 1.10), wywołanie tcp_output powoduje wysłanie segmentu zawierającego SYN, dane i FIN.

12.5 Funkcja tcp_usrclosedW kodzie N et/3 funkcja ta była wołana przez tcp_di sconnect oraz gdy było przetwarzane żądanie PRU_SHUTD0WN. W T/TCP - jak widzieliśmy na rysunku12.4 - funkcja ta jest również wołana przez żądanie PRU_SEND_E0F. Na rysunku12.5 pokazana została funkcja zastępująca kod na stronie 1066 w tomie 2.

------------------------------------------------------------------------------------------------ tcp_usrreq.c533 struct tcpcb *534 tcp_usrclosed(tp)535 struct tcpcb *tp;535 [

537 switch (tp->t_state) I

538 case TCPS_CLOSED:539 case TCPS_LISTEN:540 tp->t_state = TCPS_CL0SED;541 tp = tcp_close(tp);542 break;

543 case TCPS_SYN_SENT:544 case TCPS_SYN_RECEIVED:545 tp->t_flags |= TF_SENDFIN;546 break;

547 case TCPS_ESTABLISHED:548 tp->t_state = TCPS_FIN_WAIT_1;549 break;

550 case TCPS_CL0SE_WAIT;551 tp->t_State = TCPS_LAST_ACK;552 break;553 ]554 if (tp && tp->t_state >= TCPS_FIN_WAIT_2)555 soisdisconnected(tp->t_inpcb->inp_socket);556 return (tp);557 )

------------------------------------------------------------------- tcp_usrreq.cRysunekl2.5 Funkcja t c p _ u s r c l osed

Page 188: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

166 Implementacja T/TCP: żądanie użytkownika TCP Rozdziaf 12

543-546 Dla połączenia T/TCP zainicjowane przez użytkownika zamknięcie w sta­nach SYN_SENT lub SYN_RCVD powoduje przejście do odpowiedniego stanu z gwiazdką przez ustawienie flagi TF_SENDFIN. Pozostałe zmiany stanów nie zo­stają zmodyfikowane przez T/TCP.

12.6 Funkcja tcp_sysctlWraz ze zmianami związanymi z T/TCP wprowadzono również możliwość mo­dyfikacji zmiennych TCP przy pomocy programu sysctl . Modyfikacja ta - choć nie związana ściśle z T/TCP - umożliwia łatwiejszą, w porównaniu z użyciem debugera, modyfikację niektórych zmiennych TCP. Zmienne TCP osiągane są z użyciem przedrostka net.inet.tcp. Wskaźnik do tej funkcji jest przechowywa­ny w członie pr_sysctl struktury TCP protosw (strona 829, tom 2). Funkcja ta pokazana została na rysunku 12.6.

------------------------------------------------------------------------------------------------- tcp_usrrecj.c561 int562 tcp_sysctlCname, namelen, oldp, oldlenp, newp, newlen)563 int *name;564 u_int namelen;565 void *oldp;566 size_t *oldlenp;567 void *newp:568 size_t newlen;569 (570 extern int tcp_do_rfcl323;571 extern int tcp_do_rfcl644;572 extern int tcp_mssdflt;

573 /* Wszystkie nazwy sysctl na tym poziomie są kończące */574 if (namelen != 1)575 return (ENOTDIR):

576 switch (name[0]) (577 case TCPCTL_D0_RFC1323:578 return (sysctl_int(o l d p , oldlenp, newp, newlen, 4tcp_do_r f cl 32 3));579 case TCPCTL_D0_RFC1644:580 return (sysctl_int(oldp, oldlenp, newp, newlen, &t c p_do_rfcl644));581 case TC PCTL_MSSDFLT:582 return (sysctl_int(oldp, oldlenp, newp, newlen, &t c p_ mssdflt));583 default:584 return (EN0PR0T00PT);585 )586 /* nie osiągany */587 1

------------------------------------------------------------------------------------------------- łcp_usrreq.cRysunek 12.6 Funkcja tcp_sysctl

570-572 Dostępne są na razie tylko trzy zmienne. Kolejne zmienne mogą być łatwo udostępnione.

12.7 Przyszłość T/TCPCiekawe może być prześledzenie, jak upowszechniały się zmiany TCP wprowa­dzone w RFC 1323, czyli opq'e skali okna i znacznika czasu. Przyczyną wprowa­

Page 189: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 12.8 Podsumowanie 167

dzenia tych zmian było zwiększenie szybkości sieci (linie telefoniczne T3 i FDDI) i możliwość używania ścieżek o dużym opóźnieniu (połączenia satelitarne). Jedna z pierwszych implementacji została wykonana przez Thomasa Skibo dla stacji roboczych SGI. Ten sam autor zmodyfikował następnie kod N et/2 systemu Berke­ley i publicznie udostępnił wprowadzone zmiany w maju 1992 roku. Mniej więcej rok później (kwiecień 1993) Bob Braden i Liming Wei udostępnili podobne, oparte na RFC 1323, zmiany kodu źródłowego dla SunOS 4.1.1. Zmiany wprowadzone przez Skibo zostały dodane do wersji 4.4BSD systemu Berkeley w sierpniu 1993 roku i udostępniono je publicznie wraz z systemem 4.4BSD-Lite w kwietniu 1994 roku. Do roku 1995 niektórzy komercyjni dostawcy uwzględnili RFC 1323 w ofe­rowanych systemach, inni poinformowali o takim zamiarze. RFC 1323 nie jest jednak stan-dardem, szczególnie jeśli chodzi o implementacje PC. (Rzeczywiście, w rozdziale 14.6 widzimy, że mniej niż 2% klientów kontaktujących się z konkret­nym serwerem WWW wysłało opcje skali okna i znacznika czasu.)

Upowszechnianie T/TCP będzie prawdopodobnie przebiegało podobnie. Pierw­sza implementacja z września 1994 roku (rozdział 1.9) zawierała zmiany kodu źródłowego dla SunOS 4.1.3 i była mało interesująca dla większości użytkowni­ków, chyba że dysponowali oni kodem źródłowym systemu SunOS. Jest to jednak podstawowa implementacja T/TCP napisana przez twórcę protokołu. Implemen­tacja FreeBSD (oparta na zmianach w kodzie źródłowym SunOS), udostępniona publicznie na początku roku 1995, przeznaczona na wszechobecną platformę sprzętową (80x86), powinna spowodować rozpowszechnienie T/TC P wśród wie­lu użytkowników.

Celem tej części książki było przedstawienie przykładów T/TCP, tak by jasne się stało, dlaczego T/TCP jest wartościowym rozszerzeniem TCP, a także szczegóło­we udokumentowanie i objaśnienie zmian w kodzie źródłowym. Podobnie jak w przypadku zmian opisanych w RFC 1323, implementacje T/TCP współpracują z implementacjami nie obsługującymi T/TCP i opcje CC są używane tylko wtedy, jeżeli oba końce połączenia potrafią te opcje przetworzyć.

12.8 PodsumowanieW raz z T/TCP wprowadzono nową funkcję - tcp_connect. Jest ona wywoływa­na przy jawnym wykonaniu connect i przy niejawnym nawiązaniu połączenia (sendto lub sendmsgz podaniem adresu przeznaczenia). Dopuszcza ona utworze­nie nowego wcielenia połączenia znajdującego się w stanie TIME_WAIT, jeżeli połączenie to wykorzystywało T/TCP i jeśli czas trwania tego połączenia był krótszy niż MSL.

Zostało też wprowadzone nowe żądanie - PRU_SEND_E0F. Żądanie to jest genero­wane przez warstwę gniazd, gdy pojawia się ostateczne wywołanie wyjścia proto­kołu i jeśli aplikacja podaje flagę MSG_E0F. To żądanie dopuszcza niejawne nawią­zanie połączenia i również wywołuje tcp_usrcl osed, jeżeli została podana flagaMSG_E0F.

Page 190: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

168 Implementacja T/TCP: żądanie użytkownika TCP Rozdział 12

W funkcji tcp_usrcl osea wprowadzona została jedna modyfikacja. Modyfikacja ta umożliwia procesowi zamknięcie połączenia znajdującego się wciąż w stanie SYN_SENT lub SYN_RCVD. Wykonanie takiego zamknięcia powoduje ustawie­nie ukrytej flagi TF_SENDFIN.

Page 191: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

HTTP - protokół przesyłania hipertekstu13

13.1 WstępHTTP - protokół przesyłania hipertekstu (Hypertext Transfer Protocol) jest podsta­wą WWW - Światowej Pajęczyny (World Wide Web). W tym rozdziale przedstawia­my ten protokół, a w następnym badamy działanie rzeczywistego serwera WWW, wracając do wielu zagadnień z tomów 1 i 2 w kontekście działania aplikacji w rzeczywistych warunkach. Należy na wstępie zaznaczyć, iż ten rozdział nie jest wprowadzeniem do Pajęczyny, ani nie zawiera omówienia przeglądarki WWW.

Dane statystyczne ze szkieletowej sieci NSFnet (rysunek 13.1) pokazują niepra­wdopodobny wzrost intensywności używania HTTP od stycznia 1994 do kwietnia 1995 roku.

Miesiąc HTTP NNTP R P(dane)

Telnet SMTP DNS Liczba pakietów x109

Styczeń 1994 1,5 8,8 21,4 15,4 7,4 5,8 55

Kwiecień 1994 2,8 9,0 20,0 13,2 8,4 5,0 71

Lipiec 1994 4,5 10,6 19,8 13,9 7,5 5,3 74

Październik 1994 7,0 9,8 19,7 12,6 8,1 5,3 100

Styczeń 1995 13,1 10,0 18,8 10,4 7,4 5,4 87

Kwiecień 1995 21,4 8,1 14,0 7,5 6,4 5,4 59

Rysunek 13.1 Liczba pakietóio (w procentach) dla różnych protokołów w szkieletowej sieci NSFnet

Przedstawione liczby dotyczą liczby pakietów, a nie liczby przesłanych bajtów. (Wszystkie te statystyki są dostępne w ftp: / / f t p . mer i t . edu/sta t i sti cs.) Wi­dzimy, że procentowy udział pakietów HTTP rośnie, maleje natomiast udział pakietów FTP i Telnetu. Zauważamy również, iż całkowita liczba pakietów rosła w roku 1994, by następnie zmaleć w roku 1995. Przyczyną spadku liczby pakietów jest fakt, że inne szkieletowe sieci zaczęły zastępować NSFnet w grudniu 1994 roku. Mimo to porównanie względnej liczby pakietów w dalszym ciągu zwraca uwagę i wskazuje na wzrost wykorzystania HTTP.

Zasada działania Pajęczyny została przedstawiona w uproszczony sposób na ry­sunku 13.2.

Page 192: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

170 HTTP - protokół przesyłania hipertekstu Rozdział 13

Rysunek 13.2 System klient-serwer w Światowej Pajęczynie

Klient WWW, często nazywany przeglądarką (browser) WWW nawiązuje kontakt z serwerem WWW, używając jednego lub więcej połączeń TCP. Dobrze-znanym portem (well-known port) serwera WWW jest port numer 80. Serwer i klient do komunikacji po połączeniu TCP używają protokołu zwanego HTTP (Hypertext Transfer Protocol - protokół przesyłania hipertekstu), omawianego w tym rozdzia­le. Pokazujemy również, jak dany serwer może „wskazywać na" inne serwery WWW przy pomocy linków hipertekstu (hypertext links). Linki te nie są ograniczone zresztą do wskazywania tylko na kolejne serwery WWW. Serwer WWW może także wskazywać na przykład na serwer FTP lub serwer Telnetu.

Choć protokół HTTP był używany od roku 1990, pierwsza dokumentacja tego protokołu pojawiła się dopiero w roku 1993 ([Bemers-Lee 1993], przybliżony opis wersji 1.0 HTTP). Był to dokument typu „szkicu internetowego" (Internet draft), który już dawno temu utracił ważność (i nie jest dostępny). W czasie gdy powstaje ta książka najnowszą dostępną wersją dokumentami jest opracowanie T. Bemersa-Lee i współpracowników [Bemers-Lee, Fielding i Nielsen 1995]), wciąż jeszcze w for­mie szkicu internetowego.

Specjalnym rodzajem dokumentu dostarczanego klientowi przez serwera WWW jest tekst w języku hipertekstoioego znakowania informacji - HTML (Hypertext Markup Language), opisanym w [Bemers-Lee i Connolly 1995]. Serwer dostarcza również dokumenty innego rodzaju (pliki graficzne, PostScript, prosty format tekstowy, itd.) - kilka przykładów pokażemy w dalszej części tego rozdziału.

W następnym podrozdziale przedstawimy krótkie wprowadzenie do protokołu HTTP i do dokumentów HTML, po czym przeanalizujemy protokół HTTP bardziej szczegółowo. Następnie przyjrzymy się, w jaki sposób popularna przeglądarka (Ne­tscape) używa tego protokołu, przedstawimy trochę danych statystycznych dotyczą­cych użycia TCP przez HTTP i omówimy pewne zagadnienia związane z szybkością działania HTTP. Wiele spotykanych na co dzień problemów związanych z funkcjo­nowaniem serwera WWW jest opisanych w pracy [Stein 1995].

Page 193: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 13.2 Wprowadzenie do HTTP i HTML 171

13.2 Wprowadzenie do HTTP i HTMLHTTP jest prostym protokołem. Klient nawiązuje połączenie TCP z serwerem, wysyła żądanie i odczytuje odpowiedź serwera. Serwer zaznacza koniec swojej odpowiedzi zamykając połączenie. Plik udostępniony przez serwera zwykle za­wiera wskaźniki (linki hipertekstu) do innych plików rozmieszczonych w innych serwerach. Prostota protokołu z punktu widzenia użytkownika polega na łatwości śledzenia linków pomiędzy różnymi serwerami.

To klient (przeglądarka) zapewnia tę prostotę dla użytkownika, korzystając z wyszukanego interfejsu graficznego. Serwery HTTP jedynie udostępniają dokumenty zażądane przez klienta. Serwer jest więc prostszy niż klient. Na przykład serwer NCSA wersji 1.3 dla systemów unixowych zawiera około 6500 linii kodu źródłowego w C, natomiast unbcowy klient, Mosaic 2.5, działający w systemie X Windows, ma około 80 000 linii kodu w C.

Podobnie jak przy wielu innych protokołach internetowych, najłatwiejszym spo­sobem przyjrzenia się działaniu protokołu jest uruchomienie klienta Telnetu i po­łączenie się z odpowiednim serwerem. W przypadku HTTP jest to możliwe, ponieważ klient wysyła do serwera komendy ASCII (zakańczane znakami karetkii nowej linii, oznaczanymi CR/LF), a odpowiedź serwera rozpoczyna się liniami ASCII. HTTP używa 8-bitowego zestawu znaków ISO Latin 1, będącego rozsze­rzeniem ASCII, uwzgędniającym znaki używane w językach zachodnio-europej­skich również ISO Latin 2 - znaki z języków środkowoeuropejskich, w tym polskie- przyp. tłum. (Informacja na temat różnych zestawów znaków dostępna jest w http: / / un i code. org.)

W przykładzie przedstawionym poniżej ściągamy stronę wywoławczą wydaw­nictwa Addison-Wesley.

sun % t e l n e t www.aw.com 80 połączenie z portem 80 serweraTrying 192.207.117.2... wydruk klienta TelnetuConnected to aw.com. wydruk klienta TelnetuEscape character is ’A] ’. wydruk klienta TelnetuGET / wpisujemy tylko tę linię<HTML> pierwsza lima wydruku serwera WWW<HEAD>< TIT L E> AW’s HomePage</TITLE></HEAD><B0DY>< C E N T E R X I M G SRC = "awplogob.gif" ALT=" ”>< B R X / C E N T E R >< P X C E N T E R X H l > A d d i son-Wesley Longman</Hl X/ C EN TE R>Welcome to our Web server.

pomijamy 33 linie wydruku < D D X I M G ALIGN=bottom SRC="bal 1 _whi .g i f " ALT=" ">Information Resource<A HREF = "http://www.ncsa.uiuc.edu/SDG/Software/Mosaic/MetaIndex.html">Meta- Index</A>

omijamy 4 linie xvydruku</B0DY></HTML>Connection cl osed by foreign host. wydruk klienta Telnetu

Wpisujemy jedynie linię GET / i serwer przesyła 51 linii zawierających 3611 bajtów. W ten sposób ściągnięta zostaje strona wywoławcza (home page) serwera z katalogu głównego serwera WWW. Ostatnia linia wydruku klienta Telnetu oznacza, że serwer zamyka połączenie po wypisaniu ostatniej linii.

Page 194: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

m HTTP - protokół przesyłania hipertekstu Rozdział 13

Kompletny dokument w HTML zaczyna się od <HTML> i kończy się na </HTML>. Większość komend HTML zgrupowanych jest w podobne pary. Dokument zawie­ra nagłówek (hecid), ograniczony przez <HEAD> i </ HEAD> oraz korpus (body), ograniczony przez <B0DY> i < / BODY>. Tytuł (<TITLE> ) jest zwykle wyświetlany przez klienta w górnej części okna. Język HTML został przedstawiony bardziej szczegółowo w opracowaniu [Raggett, Lam i Aleksander 1996].

Następna linia wyszczególnia plik graficzny (w tym przypadku logo korporacji).

< C E N T E R X I M G SRC = "awplogob.gif" A L T = " "> < B R X / C E N T E R >

Znacznik <CENTER> informuje klienta, że grafika ma być umieszczona pośrodku linii, a instrukcja <IMG> zawiera informacje o obrazie graficznym. SRC podaje nazwę pliku graficznego, który klient musi ściągnąć, a ALT zawiera ciąg znaków, który trzeba wyświetlić, jeśli klient nie ma możliwości wyświetlania grafiki (w tym przypadku jest to tylko spacja). < B R> oznacza koniec linii. Serwer nie wysyła pliku graficznego wraz ze stroną wywoławczą. Wysyłana jest tylko nazwa pliku zawie­rającego tę grafikę i klient musi otworzyć nowe połączenie TCP do serwera, by ściągnąć ten plik. (Zobaczymy w dalszej części tego rozdziału, że wymóg tworze­nia nowego połączenia dla każdego wskazywanego pliku graficznego zwiększa obciążenie serwera.)

Następna linia

< P X C E N T E R X H l X A d d i son-Wesley L o n g m a n X / H l X / C E N T E R >

rozpoczyna nowy akapit (<P> ), tekst powinien być umieszczony na środku linii1 jest to nagłówek pierwszego poziomu <H1> (istnieją też nagłówki poziomów od2 do 7), zwykle wyświetlany większą i pogrubioną czcionką.

Widzimy tu różnicę pomiędzy językiem znakowania informacji (markup language), a językiem formatowania tekstu (formatting language), takim jak na przykład Troff, TeX czy PostScript. HTML wywodzi się z SGML, standardowego uogólnionego języka znakowania informa­cji (Standard Generalized Markup Language). (Więcej informacji o SGML można znaleźć w h t t p : //www. sgml o pen. org .) HTML określa zawartość dokumentu i jego strukturę (na­główek pierwszego poziomu w przedstawionym przykładzie), ale nie określa, w jaki sposób przeglądarka powinna sformatować wyświetlany dokument.

Pomijamy dużą część strony wywoławczej następującą po przywitaniu „Welco- m e", aż do punktu, w którym znajdują się linie:

< D D X I M G ALIGN=bottom SRC="bal l_whi .gi f ” ALT=" ”>Information Resource<A HREF = "http://www.ncsa.uiuc.edu/SDG/Software/Mosaic/MetaIndex.html''>Meta-Index</A>

<DD> oznacza kolejną pozycję listy. Pozycja ta rozpoczyna się obrazem graficz­nym (biała kula - zuhite bali), po którym następuje tekst „Information Resource Meta-Index". Ostatnie słowo tekstu jest wskaźnikiem do linku hipertekstu (znacz­nik <A> ) z odnośnikiem zaczynającym się od tekstu h t t p : / /www. ncsa .uiuc.edu. Takie linki hipertekstu są zwykle przedstawiane przez przeglądarkę jako tekst podkreślony lub wyświetlane są w innym kolorze. Tak jak w przypadku obrazu graficznego, który napotkaliśmy wcześniej (logo korporacji), serwer nie wysyła

Page 195: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 13.3 Protokół HTTP 173

obrazu lub dokumentu HTML, wskazywanego przez link hipertekstu. Klient zwy­kle ściągnie grafikę natychmiast (by ją wyświetlić na stronie wywoławczej), ale nie zrobi nic z linkiem hipertekstu, chyba że użytkownik wybierze ten link (to znaczy przesunie wskaźnik graficzny na ekranie i wciśnie przycisk myszy). Gdy link zostanie wybrany przez użytkownika, klient otworzy połączenie HTTP do hosta www .ncsa.uiuc.edui wykona GET dla wyszczególnionego dokumentu.

http://www.ncsa.uiuc.edu/SDG/Software/Mosaic/MetaIndex.html jest przykła­dem tzw. URL jednolitego lokalizatorci zasobów - (Uniform Resource Locator). Określe­nie i znaczenie URL zostały podane w RFC 1738 [Berners-Lee, Masinter i McCahill 1994]. URL jest częścią większego schematu zwanego URI-jednolitego identyfikato­ra zasobóio (Uniform Resource Identifiers), w skład którego wchodzą również obiekty zwane URN (Universal Resource Names) - uniioersalne nazwy zasobów. URI zostały przedstawione w RFC 1630 [Berners-Lee 1994]. URN powinny być bardziej nieza­wodne niż URL, obiekty te nie są jednak jeszcze zdefiniowane.

Większość przeglądarek WWW oferuje również możliwość obejrzenia kodu źródłowego strony WWW. Na przykład, Netscape i Mosaic udostępniają funkcję „View Source".

13.3 Protokół HTTPPolecenie GET / użyte przez klienta w przykładzie z poprzedniego podrozdziału jest poleceniem HTTP w wersji 0.9. Większość serwerów akceptuje polecenia tej wersji (dla kompatybilności wstecz), jednak aktualną wersją jest 1.0 (w roku 1995, gdy książka była pisana - przyp. tłum.). Serwer zauważy różnicę pomiędzy wer­sjami, ponieważ poczynając od wersji 1.0 klient podaje numer wersji jako część linii żądania, na przykład:

GET / HTTP/1.0

W obecnym podrozdziale przyjrzymy się dokładniej protokołowi HTTP/1.0.

Rodzaje komunikatów: żądania i odpowiedziIstnieją dwa rodzaje komunikatów w HTTP/1.0: żądania i odpowiedzi. Format żądania HTTP/1.0 jest następujący:

linia-żądanie nagłówki (0 lub więcej)<linia pusta>korpus (tylko dla żądania POST)

Format linii-żądania jest natomiast taki: żądanie żędanie-URI wersja-HTTP

Dostępne są trzy różne żądania.

1. Żądanie GET, które zwraca dowolną informację określoną przez żędanie-URI.

2. Żądanie HEAD jest podobne do żądania GET, serwer zwraca jednak nagłówek, a nie zawartość (korpus) żądanego dokumentu. Ta forma żądania jest często

Page 196: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

174 HTTP - protokół przesyłania hipertekstu Rozdział 13

stosowana do sprawdzenia linku hipertekstu pod kątem aktualności, dostę­pności, czy wprowadzonych ostatnio modyfikacji.

3. Żądanie POST używane jest do nadawania poczty elektronicznej, wysyłania informacji sieciowych lub wysyłania formularzy, które mogą zostać interakcyj­nie wypełnione przez użytkownika. Jest to jedyna forma żądania, wraz z która wysyłany jest korpus komunikatu. Długość korpusu musi być poprawnie okre­ślona w polu nagłówka Content - Length (opisujemy to pole poniżej).

W próbce 500 000 żądań klientów odebranych przez silnie aktywnego serwera WWW, 99,68% żądań były to żądania G ET, 0,25% stanowiły żądania H E AD, a pozo­stałe 0,07% to żądania POST. Inaczej by to prawdopodobnie wyglądało w przypad­ku serwera umożliwiającego interakcyjne zamówienie pizzy.

Format odpowiedzi w HTTP/1.0 jest następujący:linia-stanunagłóiuki (0 lub więcej)<pusła linia> korpus

Format linii-stanu (status-lme) jest taki:

iversja-HTTP kod-odpowiedzi fraza-odpowiedzi

Niżej omówimy pokrótce poszczególne elementy odpowiedzi.

Pola nagłówkówW HTTP/1.0 tak żądanie jak i odpowiedz mogą zawierać dowolną liczbę pól nagłów­kowych. Pola nagłówków od korpusu oddziela pusta linia. Pole nagłówka składa się z nazwy pola (rysunek 13.3), po której umieszczony jest dwukropek, następnie jedna spacja i wartość pola. Duże i małe litery nie są rozróżniane w nazwie pola.

Można wyróżnić trzy rodzaje nagłówków: używane z żądaniami, używane z od­powiedziami i określające korpus. Niektóre nagłówki są używane zarówno z żą­daniami, jak i z odpowiedziami (na przykład Da te ). Nagłówki określające korpus mogą pojawić się w żądaniach POST i w dowolnych odpowiedziach. Rysunek 13.3 pokazuje 17 różnych nagłówków opisanych w opracowaniu [Bemers-Lee, Fiel­ding i Nielsen 1995]. Nieznane pola nagłówka powinny zostać zignorowane przez odbierającego hosta. Przyjrzymy się później niektórym często spotykanym na­główkom, ale najpierw przedyskutujemy kody odpowiedzi.

Kody odpowiedziPierwsza linia odpowiedzi serwera zwana jest linią stanu. Na początku tej linii znajduje się określenie wersji HTTP, następnie podana jest trzycyfrowa liczba określająca kod odpowiedzi, a na końcu czytelne dla użytkownika wyrażenie (fraza odpowiedzi). Znaczenie trzycyfrowych kodów odpowiedzi zostało przed­stawione na rysunku 13.4. Pierwsza z trzech cyfr przypisuje kod do jednej z trzech ogólnych kategorii.

Page 197: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 13.3 Protokół HTTP 175

Użycie trzycyfrowego kodu odpowiedzi nie jest przypadkowe. Zobaczymy później, że NNTP również używa kodów odpowiedzi tego rodzaju (rysunek 15.2), podobnie jak inne aplikacje internetowe, na przykład FTP i SMTP.

Nagłówek Żądanie? Odpowiedź? Korpus?

A l 1 ow •

A u t h o r i z a t i on •

C o n t e n t - E n c o d i ng •

C o n t e n t - L e n g t h •

C o n t e n t - T y p e •

D a te • •

E x p i r e s •

From •

I f - M o d i f i e d - S in c e •

L a s t - M o d i f i ed •

L o c a t i on •

M IM E - V e rs i on • •

Pragm a • •

R e f e r e r •

S e r v e r •

U s e r - A g e n t •

W W W -A uthenti c a t e •

Rysunek 13.3 Nazwy nagłówków HTTP

Kod odpowiedzi Opis

1yz Informacja. Aktualnie nie używany

Sukces.200 OK, żądanie przetworzone pomyślnie.201 OK, utworzone zostały nowe zasoby (polecenie PO ST)202 Żądanie zaakceptowane, ale przetwarzanie nie zakończone.204 OK, ale brak tekstu do przestania.

Przeadresowanie; dalsze czynności konieczne po stronie użytkownika.301 Żądany zasób otrzymał na stałe nowy URL.302 Żądany zasób chwilowo jest dostępny pod innym URL.304 Dokument nie był zmodyfikowany (warunkowe GET)

Błąd klienta400 Złe żądanie.401 Brak autoryzacji; żądanie wymaga sprawdzenia tożsamości użytkownika.403 Zabronione z nieokreślonego powodu.404 Nie znaleziono.

Błąd serwera.500 Wewnętrzny błąd serwera.501 Nie zaimplementowane.502 Zły gateway. Zła odpowiedź od gatewaya lub pośredniczącego serwera.503 Usługa chwilowo nie dostępna.

Rysunek 13.4 Trzycyfrowe kody odpowiedzi HTTP

Page 198: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

176 HTTP - protokół przesyłania hipertekstu Rozdział 13

Przykłady różnych nagłówkówJeżeli przy użyciu HTTP/1.0 ściągniemy obrazek logo (wymieniony na stronie odwoławczej w poprzednim podrozdziale) otrzymamy następujący dialog mię­dzy serwerem i klientem:

sun % telnet www.aw.com 80 Trying 192.207.117.2...Connected to aw.com.Escape character is 'A] ’.GET /awplogob.gif HTTP/1.0 wpisujemy tę UnięFrom: [email protected] i tę linię

następnie wpisujemy pustą linię, by zakończyć żądanie

HTTP/1.0 200 OK pierwsza linia odpowiedzi serweraDate: Saturday. 19-Aug-95 20:23:52 GMTServer: NCSA/l.3MIME-version: 1.0Content-type: image/gifLast-modified: Monday. 13-Mar-95 01:47:51 GMT Content-length: 2859

puste linie kończą nagłówki odpowiedzi serwera «- 2589-bajtowy plik GIF zostaje przesłany

Connection cl osed by foreign host. wydruk klienta Telnetu

• Zaznaczamy numer wersji w żądaniu GET.• Wysyłamy pojedynczy nagłówek From, który może zostać zarejestrowany (za­

pisany w „log file")• Linia stanu serwera wymienia numer wersji, kod odpowiedzi 200 i frazę odpo­

wiedzi „OK".• Nagłówek Date zawiera czas i datę według serwera, podane zawsze w czasie

uniwersalnym (GMT). Serwer z naszego przykładu wysyła datę w przestarza­łym formacie. Zalecanym formatem jest:

Date: Sat, 19 Aug 1995 20:23:52 GMT

z nazwą dnia tygodnia w formie skróconej, bez myślnika w dacie i rokiem wyrażonym jako liczba czterocyfrowa.

• Serwer podaje typ i wersję używanego programu: serwer NCSA wersja 1.3.• Używany jest format MIME w wersji 1.0. Informacje na temat MIME można

znaleźć w rozdziale 28.4 tomu 1 oraz w pracy [Rose 1993].• Typ danych zawartych w korpusie jest określony przez pola Content-Type i

Content-Encoding. Pierwsze z tych pól przedstawione jest jako typ, po którym następuje ukośnik, a następnie podtyp. W naszym przykładzie typem jest i mage, a podtypem gif . HTTP używa typów danych internetowych wyszczególnio­nych w ostatnim opracowaniu Assigned Numbers RFC (wersja aktualna w czasie, gdy powstawała ta książka: [Reynolds and Postel 1994]).Innymi typowymi wartościami są:

Content-Type: text/html Content-Type: text/plain Content-Type: appli cati on/postscript

Jeśli korpus jest zakodowany, pojawia się również nagłówek Content-Enco- di ng. Na przykład dla pliku PostScript skompresowanego za pomocą unixo-

Page 199: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 13,3 Protokół HTTP 177

wego programu compress (zwykle plik taki ma nazwę z rozszerzeniem . p s . Z) pojawiłyby się następujące dwa nagłówki.

Content-Type: appli cation/postscri pt Content-Encoding: x-compress

• Last-Modi fied określa czas ostatniej modyfikacji ściąganego pliku.• Wielkość pliku graficznego (2859 bajtów) podana jest w nagłówku Content-

Length.Po ostatnim nagłówku serwer wysyła pustą linię (znaki C R/LF) i bezpośrednio po tym plik graficzny. Przesyłanie danych binarnych przez połączenie TCP jest dopu­szczalne, ponieważ HTTP używa ośmiobitowych bajtów. Inaczej wygląda to w przypadku niektórych innych aplikacji internetowych. W szczególności proto­kół SMTP (rozdział 28, tom 1) przesyła 7-bitowe znaki ASCII przez połączenie TCP, jawnie ustawiając wartość najbardziej znaczącego bitu na 0 i uniemożliwiając tym samym wymianę danych binarnych.

Często spotykanym nagłówkiem klienta jest User-Agent identyfikujący program klienta. Typowymi przykładami są:

User-Agent: Mozilla/l.lN (Windows; I; 16bit)User-Agent: NCSA Mosaic/2.6bl (XI1;SunOS 5.4 sun4m) libwww/2.12 modified

Przykład: pamięć podręczna klientaWiele programów działających jako klient przechowuje dokumenty HTTP w pod­ręcznej pamięci na dysku wraz z czasem i datą, kiedy te dokumenty zostały ściągnięte. Jeżeli ściągany aktualnie dokument znajduje się w pamięci podręcznej klienta, może zostać wysłany przez klienta nagłówek If -Modi f i ed - Si nce i to pozwala uniknąć wysyłania przez serwera drugiej kopii tego samego dokumentu -jeśli dokument nie został zmieniony. Jest to tak zwane warunkowe żądanie GET.

sun 1 telnet www.aw.com 80 Tryi ng 192.207.117.2...Connected to aw.com.Escape character is ’A]'.GET /awplogob.gif HTTP/1.0If-Modified-Since: Saturday, 08-Aug-95 20:20:14 GMT

pusta linia kończy żędanie klientaHTTP/1.0 304 Not modified Date: Saturday, 19-Aug-95 20:25:26 GMT Server: NCSA/l.3 MIME-version: 1.0

pusta linia kończy nagłówki odpowiedzi serweraConnection closed by foreign host.

Tym razem kod odpowiedzi jest 304, co oznacza, że dokument nie był zmodyfiko­wany. Z punktu widzenia protokołu TCP, umożliwia to uniknięcie przesyłania od serwera do klienta korpusu dokumentu, czyli w tym przykładzie 2859 bajtów pliku w formacie GIF. W dalszym ciągu muszą być przesłane segmenty potrójnego uzgodnienia oraz cztery pakiety kończące połączenie, czyli muszą być wykonane typowe czynności administracyjne protokołu TCP.

Page 200: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

178 HTTP - protokół przesyłania hipertekstu Rozdział 13

Przykład: przeadresowanie wykonane przez serweraNastępny przykład pokazuje przeadresowanie wykonane przez serwera. Próbuje­my ściągnąć stronę wywoławczą autora, ale celowo opuszczamy końcowy ukoś­nik (jest on wymaganą częścią URL określającego katalog).

sun % telnet www.noao.edu 80 Trying 140.252.1.11...Connected to gemini.tuc.noao.edu Escape character is ’A] ’.GET / ~ r s t e v e n s H T T P /1 .0

pusta linia kończy żądanie klientaHTTP/1.0 302 FoundDate: Wed. 18 Oct 1995 16:37:23 GMTServer: NCSA/1.4Location: http://www.noao,edu/~rstevens/Content-type: text/html

pusta linia kończy nagłówki odpowiedzi serwera

< H E A D X T I T L E > D o c u m e n t m o v e d < / T I T L E X / H E A D >< B 0 D Y X H l > D o c u m e n t moved</Hl>This document has moved <A HREF="http://www.noao.edu/~rstevens/”>here</A>.<P> </B0DY>

Kod odpowiedzi jest 302, co oznacza, że żądany dokument zmienił swoją lokaliza­cję. Nagłówek Location określa nowy adres, zawierający tym razem końcowy ukośnik. Większość przeglądarek automatycznie ściąga dokument wskazywany przez nowy URL. Serwer wysyła również plik HTML, który może być wyświetlo­ny przez przeglądarkę, jeżeli przeglądarka nie chce automatycznie ściągać nowe­go URL.

13.4 PrzykładPrzeanalizujemy teraz szczegółowo jeden przykład używając popularnej przeglą­darki WWW (Netscape 1.1N) i zwrócimy szczególnie uwagę na sposób wykorzy­stania HTTP i TCP. Zaczniemy od strony wywoławczej wydawnictwa Addison-Wes- ley (http: / / w w w . a w . com) i użyjemy trzech linków umieszczonych na tej stronie (wszystkie do w w w . a w . com) dochodząc do strony zawierającej opis tomu 1. Nawią­zywanych jest 17 połączeń TCP, 3132 bajty przesyłane są od klienta do serwera, a serwer zwraca ogółem 47 483 bajty. Spośród 17 połączeń, cztery służą do przesła­nia dokumentów HTML (28 159 bajtów), a w 13 połączeniach przesyłane są pliki graficzne GIF (19 324 bajty). Pamięć podręczna na dysku klienta używana przez program Netscape została wcześniej wyczyszczona, zmuszając klienta do ściąga­nia od serwera wszystkich plików. Wszystkie segmenty - wysyłane lub odbierane- były rejestrowane przy pomocy programu Tcpdump uruchomionego w kompu­terze klienta.

Tak jak się spodziewamy, pierwsze połączenie TCP służy do przesłania strony wywoławczej (GET /), która zawiera odnośniki do siedmiu plików graficznych GIF. Gdy tylko klient otrzyma tę stronę, cztery połączenia TCP zostaną równolegle otwarte dla pierwszych czterech plików graficznych. Jest to właściwość klienta Netscape, która pozwala zredukować całkowity czas transmisji. (Większość klien-

Page 201: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 13.4 Przykład 179

tów WWW nie jest aż tak agresywnych i ściąga pliki pojedynczo.) Liczba symul­tanicznych połączeń może być zmieniona przez użytkownika - domyślnie liczba ta określana jest na 4. Gdy tylko któreś z tych połączeń zostaje zamknięte, otwiera­ne jest natychmiast nowe połączenie - by ściągnąć kolejny plik GIF. Procedura ta jest kontynuowana aż do momentu, gdy wszystkie siedem obrazów graficznych zostaje ściągniętych. Na rysunku 13.5 pokazujemy diagram czasowy dla tych 8 połączeń TCP.

Rysunek 13.5 Diagram czasowy dla 8 połączeń TCP użytych do ściągnięcia strony wywoławczej i siedmiu plików GIF

Wszystkich 8 połączeń jest zainicjowancych przez klienta i używają one kolejnych numerów portów - od 1114 do 1121. Wszystkie te połączenia zostają zamknięte przez serwera. Przyjmujemy, że połączenie zaczyna się, gdy klient wysyła począt­kowy segment SYN (connect klienta) i kończy się, gdy klient - po otrzymaniu segmentu FIN od serwera - wysyła swój segment FIN (cl ose klienta). Potrzeba około 12 sekund, by ściągnąć stronę wywoławczą i wszystkie 7 plików graficznych wymienionych na tej stronie.

Page 202: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

180 HTTP - protokół przesyłania hipertekstu Rozdział 13

W następnym rozdziale, na rysunku 14.22, prześledzimy wymianę pakietów odpowiadającą pierwszemu połączeniu zainicjowanemu iprzez klienta (port 1114).

Zauważmy, że połączenia używające portów 1115, 1116 i 1117 rozpoczynają się zanim pierwsze połączenie (port 1114) się skończy . Dzieje się tak, bo klient Netscape iniq'uje te trzy nieblokujące połączenia po tym, gdy odbierze znak końca pliku w pierwszym połączeniu, ale przed zamknięciem tego połączenia. Rzeczywiście, na rysunku 14.22 zauważamy opóźnienie nieco ponad pół sekundy pomiędzy otrzymaniem FIN, a wysła­niem FIN przez klienta.

Czy symultaniczne połączenia są korzystne dla klienta, czyli czy ta technika zmniejsza czas transakcji dla interakcyjnego użytkownika? Żeby to sprawdzić, użyty został klient Netscape z hosta sun (rysunek 1.13) do ściągnięcia strony wywoławczej Addison-Wesley. Ten host połączony został z Internetem przez modem i połączenie telefoniczne o szybkości 28 800 bitów na sekundę, co jest dziś typowe dla WWW. Liczba połączeń używanych przez klienta może zostać zmie­niona w pliku preferencji użytkownika i próbowano użyć wartości od 1 do 7. Pamięć podręczna na dysku była wyłączona. Klient wykonywał swoje funkcje trzy razy dla każdej wartości i otrzymane wyniki zostały uśrednione.

Liczbajednoczesnych połączeń w sekundach

Całkowity czas

1 14,5

2 11,4

3 10,5

4 10,2

5 10,2

6 10,2

7 10,2

Rysunek 13.6 Całkowity czas operacji zmierzony dla klienta WWW przy różnych liczbach jednoczesnych połączeń

Dodatkowe połączenia, aż do czterech równoczesnych, rzeczywiście zmniejszają całkowity czas operacji. Kiedy jednak wymiana pakietów została przeanalizowa­na przy pomocy Tcpdump, okazało się, że choć użytkownik mógł zezwolić na więcej niż 4 połączenia, program w rzeczywistości i tak ograniczał ich liczbę do 4. Bez względu na to, biorąc pod uwagę różnice czasów pomiędzy użyciem 1 , 2 , 3 i 4 połączeń, można sądzić, że zwiększenie liczby połączeń ponad 4 dałoby niewielki, jeśli w ogóle jakikolwiek, efekt.

Całkowity czas transakcji z rysunku 13.5 jest o 2 sekundy większy od najkrótszego czasu (10.2) pokazanego na rysunku 13.6. Przyczyna pojawienia się tych dodatkowych 2 sekund związana jest z różnicami sprzętowymi (wyświetlanie) pomiędzy dwoma klientami. Przykład z rysunku 13.6 był wykonany na stacji roboczej, podczas gdy przykład, którego dotyczy rysunek 13.5, wykonywany był na wolniejszym komputerze PC z wolniejszą kartą graficzną.

Page 203: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 13.5 Dane statystyczne HTTP 181

W opracowaniu [Padmanabhan 1995] zauważono dwa problemy związane z sy­multanicznymi połączeniami. Po pierwsze, takie zachowanie może być uciążliwe dla innych protokołów, takich jak FTP, które używają zawsze jednego połączenia (pomijając połączenie kontrolne). Po drugie, jeżeli jedno z symultanicznych połą­czeń natyka się na przeciążenie i postępuje zgodnie z algorytmem unikania prze­ciążenia (congestion avoidance) informacja algorytmu unikania przeciążenia (opisa­ny w rozdziale 21.6 w tomie 2), nie jest przekazywana do innych połączeń.

W praktyce jednak symultaniczne połączenia z jednym hostem prawdopodobnie używa­ją tej samej marszruty. Jeśli jedno połączenie zaczyna tracić pakiety na skutek przeciąże­nia, jest wysoce prawdopodobne, że inne połączenia spotkają się z tym samym efektem.

Innym problemem związanym z wykorzystywaniem równoczesnych połączeń jest to, że w przypadku użycia takich połączeń prawdopodobieństwo przepełnie­nia niekompletnej kolejki połączenia serwera jest większe, co może prowadzić do dużych opóźnień, gdy klient musi przesyłać ponownie swoje segmenty SYN. W rozdziale 14.5 omówimy w szczegółach to zagadnienie związane z umieszcza­niem danych w kolejkach połączeń - w odniesieniu do serwerów WWW.

13.5 Dane statystyczne HTTPW następnym rozdziale przyjrzymy się dokładniej niektórym właściwościom ze­stawu protokołów TCP/IP i przeanalizujemy sposób użycia tych protokołów (również niewłaściwego) w silnie obciążonym serwerze HTTP. W obecnym pod­rozdziale pragniemy sprawdzić jak wygląda typowe połączenie HTTP. Będziemy używać opisanego w następnym rozdziale zestawu danych zebranych w ciągu 24 godzin przez program Tcpdump.

Na rysunku 13.7 zebraliśmy dane statystyczne uzyskane dla około 130 000 od­dzielnych połączeń HTTP. W przypadkach gdy klient zakończył połączenie w sposób nienormalny, na przykład przerywając połączenie telefoniczne, możemy nie być w stanie określić z wydruku Tcpdump wartości jednego lub obu liczników bajtów. Średni czas połączenia również może być zafałszowany w stronę wię­kszych wartości, z powodu połączeń, które serwer zamknął po wyczerpaniu się czasu oczekiwania.

Mediana Wartość średnia

klienci bajty/połączenie 224 226

seiwer bajty/połączenie 3093 7900

czas trwania połączenia (sekundy) 3,4 22,3

Rysunek 13.7 Statystyka oddzielnych połączeń HTTP

Większość opracowań dotyczących statystyki połączeń HTTP podaje zarówno wartość najczęściej spotykaną (medianę), jak i wartość średnią, ponieważ mediana jest parametrem w wielu przypadkach lepiej określającym „normalne" połączenia.

Page 204: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

182 HTTP - protokół przesyłania hipertekstu Rozdział 13

Średnia często ma wartość wyższą, co spowodowane jest przez niewielką liczbę bardzo długich plików. W opracowaniu [Mogul 1995b] przeanalizowano 200 000 połączeń HTTP i stwierdzono, że liczba bajtów danych zwracanych przez serwera miała medianę równą 1770 bajtów i wartość średnią 12 925 bajtów. Inny pomiar (również [Mogul 1995b]), w którym uwzględniono niemal 1,5 miliona połączeń z innym serwerem, przyniósł medianę 958 bajtów i wartość średnią 2394 bajty. Dla serwera NCSA zmierzono medianę [Braun i Claffy 1994] równą około 3000 bajtów i średnią około 17 000 bajtów. Oczywistym wnioskiem jest, że wielkość odpowie­dzi serwera zależy od rodzaju plików udostępnianych przez tego serwera i może zmieniać się w bardzo szerokich granicach dla różnych serwerów.

Liczby dyskutowane do tej pory w tym podrozdziale dotyczyły pojedynczych połączeń HTTP używających TCP. Najczęściej użytkownicy przeglądarki WWW ściągają wiele plików z danego serwera w trakcie tzw. sesji HTTP. Pomiar wielko­ści charakteryzujących sesję jest trudniejszy, ponieważ jedyna informacja dotyczą­ca klienta dostępna w serwerze to numer IP klienta. Możliwa jest sytuacja, w której kilku użytkowników tego samego klienta łączy się jednocześnie z tym samym serwerem. Co więcej, wiele instytucji kieruje wszystkie żądania klientów HTTP przez kilka hostów-serwerów, co powoduje, że wielu użytkowników używa po­zornie jednego adresu IP (często jest to związane z istnieniem sieciowych ścian ogniowych). (Serwery takie zwane są często senuemmi proxy). Mimo tych trudności wykonano [Kwan, McGrath i Reed 1995] próby scharakteryzowania sesji dla ser­wera NCSA, definiując sesję jako zestaw połączeń odbywających się w czasie najwyżej 30 minut. W ciągu takich 30-minutowych sesji każdy klient wysłał śred­nio 6 żądań HTTP, powodując przesłanie przez serwera 95 000 bajtów.

Wszystkie wielkości statystyczne wymieniane w tym podrozdziale były mierzone po stronie serwera. Należy zaznaczyć, iż na wszystkie te wielkości ma wpływ rodzaj dokumentów HTTP udostępnianych przez danego serwera. Wartość śred­nia liczby bajtów wysyłanych przez serwera udostępniającego na przykład duże mapy pogody, będzie znacznie wyższa niż analogiczna wielkość dla serwera wysyłającego głównie informacje tekstowe. Lepsze dane statystyczne dotyczące WWW można by otrzymać śledząc żądania wielu różnych klientów wysyłane do wielu różnych serwerów. Tego typu pomiary zostały przedstawione w opracowa­niu [Cunha, Bestavros i Crovella 1995]. Przeanalizowano tam 4700 sesji HTTP, zainicjowanych przez 591 użytkowników, w ramach których przesłano ogółem 575 772 pliki. Otrzymano średnią wielkość pliku równą 11 500 bajtów. Autorzy podają również średnie wielkości dokumentów określonego typu (HTML, grafika, dźwięk, video, text, itd.). Podobnie jak w innych pomiarach, stwierdzono, że rozkład wielkości plików ma długi ogon odpowiadający dużym plikom, co powo­duje przesunięcie wartości średniej. Stwierdzono również, że najczęściej przesyła­ne są pliki małe.

Page 205: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 13.6_________ Problemy związane z szybkością i sprawnością działania 183

13.6 Problemy związane z szybkością i sprawnością działaniaBiorąc pod uwagę duży wzrost użycia HTTP (rysunek 13.1), wpływ tego protoko­łu na funkcjonowanie Internetu jest wyjątkowo interesujący. Ogólne wykresy natężenia ruchu dla serwera NCSA można znaleźć w pracy [Kwan, McGrath i Reed 1995]. Wykresy te sporządzone zostały na podstawie plików rejestrujących (log files) otrzymanych dla różnych tygodni w ciągu pięciu miesięcy 1994 roku. Zauważono na przykład, że 58% żądań pochodzi z komputerów osobistych, a licz­ba żądań rośnie o 11-14% miesięcznie. Przedstawione są również dane statystycz­ne liczby żądań w zależności od dnia tygodnia, średnie długości połączeń, itd. Inną analizę pracy serwera NCSA znajdziemy w pracy [Braun i Claffy 1994]. Przedstawiono tam również, jakie zyski w szybkości i sprawności działania serwe­ra można osiągnąć, gdy serwer HTTP dokumenty najczęściej wymieniane w od­nośnikach przechowuje w podręcznej pamięci na dysku.

Najistotniejszym czynnikiem wpływającym na czas odpowiedzi serwera mierzo­ny przez interaktywnego użytkownika jest sposób użycia połączeń TCP przez HTTP. Jak widzieliśmy, dla każdego dokumentu używane jest jedno oddzielne połączenie. To zagadnienie opisane jest w opracowaniu [Spero 1994a], zaczynają­cym się od słów „HTTP/1.0 źle współpracuje z TCP." Innymi istotnymi czynnika­mi są czas RTT pomiędzy klientem i serwerem oraz obciążenie serwera.

We wspomnianym opracowaniu ([Spero 1994a]) zauważa się również, że każde połączenie rozpoczyna się w trybie powolnym (slow start, opisąny w rozdziale 20.6 w tomie 1), co dodatkowo zwiększa opóźnienie. Wpływ powolnego trybu rozpo­czynania połączenia zależy od rozmiaru żądania klienta i wartości MSS ogłoszonej przez serwera (zwykle 512 lub 536 dla połączeń nawiązywanych przez Internet). Przy wartości MSS 512 bajtów, jeżeli żądanie klienta nie jest dłuższe niż 512 bajtów, powolny tryb rozpoczynania połączenia nie ma znaczenia. (Należy jednak pamiętać o często spotykanej w implementacjach wywodzących się z systemu Berkeley zależności od buforów mbuf - opisujemy ją w rozdziale 14.11 - która może spowodować start w trybie powolnym.) W przypadku gdy żądanie klienta jest większe niż MSS, powolny tryb nawiązywania połączenia zwiększa opóźnienie o dodatkowe wartości RTT. Rozmiar żądania klienta zależy od progra­mu przeglądarki. Klient Xmosaic we wspomnianym opracowaniu ([Spero 1994a]) wygenerował 1130-bajtowe żądanie, które było przesłane w trzech segmentach TCP. (Żądanie to zawierało 42 linie, z których 41 było nagłówkami Accept.) W przykładzie z rozdziału 13.4 klient Netscape 1.1N utworzył 17 żądań o rozmia­rze od 150 do 197 bajtów, tryb powolnego startu nie był więc używany. Mediana i wartość średnia rozmiaru żądania klienta na rysunku 13.7 pokazują, że wię­kszość żądań odbieranych przez tego serwera nie powoduje powolnego startu, natomiast taki powolny start powoduje większość odpowiedzi wysyłanych przez serwera.

Przed chwilą wspomnieliśmy, że klient Mosaic wysyła wiele nagłówków Accept, ale nagłówek ten nie jest wymieniony na rysunku 13.3 (ponieważ nie pojawia się on w opra­cowaniu [Beme-Lee, Fielding i Nielsen 1995]). Nagłówek Accept został pominięty w tym

Page 206: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

184 H T T P - protokół przesyłania hipertekstu Rozdział 13

szkicu internetowym ze względu na to, iż tylko nieliczne serwery robią cokolwiek z tym nagłówkiem. Przy jego pomocy klient informuje serwera, jakie formaty danych klient będzie akceptował (grafiki GIF, pliki PostScript, itd.). Niewiele jest jednak serwerów, które przechowują kopie tego samego dokumentu w różnych formatach, i nie ma zwykle możliwości uzgodnienia formatu danych przez klienta i serwera.

Istotne jest też, że połączenie zostaje zwykle zamknięte przez serwera HTTP, co powoduje wprowadzenie połączenia w stan oczekiwania TIME_WAIT po stronie serwera. Wynikiem tej sytuacji może być obecność w silnie zajętym serwerze dużej liczby bloków kontrolnych połączeń w tym stanie.

Zaproponowano [Padmanabhan 1995] i [Mogul 1995b], by serwer nie zamykał połączenia TCP po wysłaniu odpowiedzi i by takie połączenie między klientem i serwerem było zachowywane. Jest to możliwe, gdy serwer zna rozmiar swojej odpowiedzi (przypominamy nagłówek Content-Lengthz naszego wcześniejsze­go przykładu ze strony 177, w którym podany został rozmiar grafiki GIF). W prze­ciwnym przypadku serwer musi zamknąć połączenie, by poinformować klientao końcu połączenia. Taka modyfikacja protokołu wymaga wprowadzenia zmian zarówno w oprogramowaniu serwera, jak i klienta. By zapewnić kompatybilność wstecz, klient generuje nagłówek Pragma: hold-connection. Nagłówek ten po­zwala nowym klientom komunikującym się z nowymi serwerami zachować połą­czenie, kiedy tylko jest to możliwe, i jednocześnie umożliwia współpracę wszy­stkich istniejących serwerów i klientów. Serwer, który nie rozumie takiego na­główka Pragma:, ignoruje go i zamyka połączenie po przesłaniu dokumentu.

Trwałe połączenia zostaną prawdopodobnie uwzględnione w następnej wersji HTTP, choć szczegóły implementacji mogą być inne niż przedstawiono powyżej.Serwer może w is tocie użyć trzech różnych sposobów, by poinformować klienta o zakończe­niu odpowiedzi. Pierwszym zalecanym sposobem jest użycie nagłówka Content-length. Kolejną możliwością jest wysłanie nagłówka Content-Type z atrybutem boundary=. (Przykład użycia tego atrybutu można znaleźć w rozdziale 6.1.1 pracy [Rose 1993], Nie wszystkie implementaq'e klienta uwzględniają ten atrybut.) Najgorszym sposobem, choć najczęściej używanym, jest zamknięcie połączenia przez serwera.

Padmanabhan i Mogul proponują również wprowadzenie dwóch nowych żądań klienta umożliwiających łączenie kilku odpowiedzi serwera w jedną: G ETA L L (ser­wer wysyła w jednej odpowiedzi dokument HTML oraz wszystkie wbudowane - inline - grafiki) oraz GET LI ST (odpowiada wysłaniu przez klienta serii żądań GET). Żądanie G ETA L L byłoby używane, jeśli klient nie przechowuje w pamięci podręcz­nej żadnych plików pochodzących od tego serwera. Idea związana z drugim nowym żądaniem jest taka, by klient najpierw wykonywał GET dla dokumentu HTML, a następnie używał GET LI ST do ściągnięcia wszystkich wymienianych w tym dokumencie plików, o ile nie znajdują się one w pamięci podręcznej.

Podstawowym problemem związanym z HTTP jest niedopasowanie protokołu TCP - zorientowanego na przesyłanie strumienia bajtów, i usługi HTTP - zorien­towanej na przesyłanie komunikatów. Idealnym rozwiązaniem jest protokół war­stwy sesji oparty na TCP, tworzący interfejs pomiędzy klientem i serwerem HTTP, nastawiony na przesyłanie komunikatów w ramach jednego połączenia TCP.

Page 207: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 13.7 Podsumowanie 185

W opracowaniu [Spero 1994b] omawiane jest takie podejście. Zaproponowany protokół, nazwany HTTP-NG, używa jednego połączenia TCP, podzielonego na tzw. sesje. W ramach jednej sesji przesyłane są informacje kontrolne - żądania klienta i kody odpowiedzi serwera, a w innej sesji serwer przesyła żądane pliki. W ramach połączenia TCP przesyłany jest 8-bajtowy nagłówek (zawierający kilka bitów flag, identyfikator sesji oraz długość następujących po nagłówku danych) oraz dane odpowiadające danej sesji.

13.7 PodsumowanieProtokół HTTP jest prosty. Klient nawiązuje połączenie TCP z serwerem, wysyła żądanie i czyta odpowiedź serwera. Serwer zaznacza koniec odpowiedzi, zamyka­jąc połączenie. Plik przesłany przez serwera zawiera zwykle wskaźniki (linki hipertekstu) do innych plików, umieszczonych być może w innych serwerach. Prostota protokołu z punktu widzenia użytkownika polega na oczywistej łatwości śledzenia takich linków od serwera do serwera.

Żądania klienta mają formę zwykłych linii ASCII, a odpowiedzi serwera składają się z linii ASCII (nagłówki), po których następują dane (binarne lub ASCII). Opro­gramowanie klienta (przeglądarka) analizuje odpowiedź serwera, formatuje otrzymane informacje i zaznacza linki do innych dokumentów.

Ilość danych przesyłanych w połączeniu HTTP jest mała. Żądania klienta zawiera­ją zwykle po kilkaset bajtów, a odpowiedzi serwera typowo od kilkuset do 10 000 bajtów. Ponieważ niewielka liczba dużych plików może w istotny sposób zmienić wartość średnią rozmiaru plików, opracowania statystyczne dotyczące HTTP po­dają zwykle medianę rozkładu długości odpowiedzi serwera. Wiele różnych ana­liz pokazuje, że mediana ta ma wartość mniejszą niż 3000 bajtów.

Największym problemem rzutującym na wydajność użycia HTTP jest fakt, że protokół ten używa oddzielnego połączenia TCP dla każdego przesyłanego pliku. W przykładzie, który przedstawiliśmy w rozdziale 13.4, ściągnięcie jednej strony wywoławczej spowodowało, że klient utworzył 8 połączeń TCP. Jeżeli żądanie klienta jest większe niż wartość MSS zgłoszona przez serwera, to powolny tryb nawiązywania połączenia powoduje dodatkowe opóźnienie w każdym połącze­niu TCP. Innym problemem jest to, że zamknięcie połączenia przez serwera powo­duje pojawienie się po stronie serwera stanu TIME_WAIT związanego z tym połączeniem i że aktywny serwer może skumulować bardzo wiele takich zakań­czanych połączeń.

Można przeprowadzić pewne historyczne porównanie. Protokół Gopher powstał mniej więcej w tym samym czasie co HTTP. Protokół Gopher jest opisany w RFC 1436 [Anklesaria i in. 1993]. Biorąc pod uwagę działanie sieci, HTTP i Gopher są dość podobne. Klient otwiera połączenie z portem serwera (port numer 70 dla Gophera) i wysyła żądanie. Serwer wysyła odpowiedź i zamyka połączenie. Róż­nica dotyczy zawartości odpowiedzi serwera. Choć protokół Gopher dopuszcza przesyłanie nietekstowej informacji, większość klientów Gophera współpracuje

Page 208: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

186 HTTP - protokół przesyłania hipertekstu Rozdział 13

jedynie z terminalami ASCII. Dlatego też większość dokumentów przesyłanych przez serwery Gophera to pliki tekstowe. W czasie gdy powstaje ta książka, wiele węzłów internetowych likwiduje usługi Gophera, ponieważ HTTP zaczyna zdecy­dowanie dominować. Wiele przeglądarek WWW potrafi jednak użyć protokołu Gopher i komunikuje się z takimi serwerami, gdy URL ma formę g o p h e r : f /host- ncime.

Będą pojawiać się kolejne wersje HTTP zazwyczaj jako „szkic internetowy". Wprowadzone zostaną być może takie rozszerzenia jak weryfikacja tożsamości (iauthentication), trwałe połączenia TCP i ustalanie formatu zawartości dokumen­tów.

Page 209: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Pakiety znalezione w serwerze HTTP14

14.1 WstępW tym rozdziale prezentujemy inne spojrzenie na protokół HTTP i niektóre bar­dziej ogólne właściwości internetowego zestawu protokołów. Przeanalizujemy tutaj pakiety przetwarzane przez silnie obciążony serwer HTTP. W ten sposób możemy powiązać niektóre właściwości TCP/IP przedstawione w tomach 1 i 2, analizując je w warunkach rzeczywistego użytkowania. Obecny rozdział pokazuje też, jak różne (a czasami zupełnie dziwaczne) może być działanie protokołu TCP i jego implementacji. W tym rozdziale poruszamy wiele zagadnień - w kolejności odpowiadającej mniej więcej etapom czynności w połączeniu TCP: nawiązanie połączenia, przesłanie danych i zakończenie połączenia.

Dane użyte w rozdziale zostały zebrane w systemie będącym komercyjnym do­stawcą usług internetowych. System dostarcza usług HTTP dla 22 różnych insty­tucji. W systemie działają 22 kopie serwera NCSA httpd. (Zagadnienie urucha­miania wielu serwerów jednocześnie omówimy szerzej.) CPU systemu to procesor Intel Pentium i wykorzystywany jest system operacyjny BSD/OS V I.1.

Zebrane zostały trzy zestawy danych.

1. W okresie 5 dni program netst a t z opq'ą - s uruchamiany był raz na godzinę, by zebrać wartości wszystkich zmiennych statystycznych protokołów interne­towych. Są to zmienne omawiane w tomie 2, na przykład na stronach 216 (IP) i 827 (TCP).

2. Program Tcpdump (dodatek A tomu 1) był uruchomiony łącznie na 24 godziny w ciągu tych 5 dni i rejestrował każdy pakiet TCP odebrany lub wysłany przez port 80, zawierający flagę SYN, FIN lub RST. W ten sposób możemy szczegóło­wo przeanalizować statystykę połączeń HTTP. Tcpdump zarejestrował 686 755 pakietów w ciągu wspomnianego okresu, co sprowadziło się do 147 103 prób nawiązania połączenia.

3. Zarejestrowany został każdy pakiet otrzymany lub wysłany przez port 80 w ciągu 2,5 godziny po zakończeniu pięciodniowego okresu. Dzięki temu ze­stawowi danych możemy dokładniej przyjrzeć się kilku szczególnym przypad­kom, analizując segmenty inne niż te, które zawierają flagi SYN, FIN i RST. W ciągu tego okresu zarejestrowano 1 039 235 pakietów, co daje średnią około 115 pakietów na sekundę.

Do zebrania danych SYN /FIN /RST w okresie 24-godzinnym użyliśmy polecenia:

$ tcpdump -p -w data.out ’tcp and port 80 and t c p [13:1] & 0x7 !- 0'

Page 210: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

188 Pakiety znalezione w serwerze HTTP Rozdział 14

Flaga - p powoduje, że interfejs nie pracuje w tzw. trybie nasłuchu (promiscuous mode), tak więc zostają zarejestrowane tylko pakiety odebrane lub wysłane przez hosta, w którym został uruchomiony program Tcpdump - tylko takimi pakietami jesteśmy zainteresowani. Używając tej flagi zmniejszamy objętość danych zebra­nych z sieci lokalnej i zmniejszamy również prawdopodobieństwo zagubienia pakietów.

Flaga ta nie gwarantuje pracy w trybie nienasłuchowym. Interfejs mógł być przestawionyw tryb nasłuchu przez inny proces.W ciągu kilku różnych długich okresów działania Tcpdump zaobserwowaliśmy, że gu­biony jest jeden pakiet na 16 000-20 000 pakietów zarejestrowanych.

Flaga - w powoduje zbieranie danych w pliku binarnym - zamiast wyświetlania ich w postaci tekstowej na ekranie. Utworzony plik jest później konwertowany (z użyciem flagi - r) do formatu tekstowego.

Zbierane są tylko pakiety TCP odbierane lub wysyłane przez port 80. Ponadto logiczne AND pojedynczego bajtu na 13 pozycji względem początku nagłówka TCP i liczby 7 musi dawać wartość niezerową. W ten sposób sprawdzamy, czy flaga SYN, FIN lub RST jest ustawiona (strona 263 tomu 1). Zbierając tylko takie pakiety i następnie analizując numery sekwencyjne w segmentach SYN i FIN możemy określić, ile bajtów zostało przesłanych w obu kierunkach połączenia. Oprogramowanie tcpdump - reduce, napisane przez Verna Paxsona, zostało użyte do analizy danych produkowanych przez Tcpdump (http: //town .hall . o r g / A r - chi ves//pub/ ITA/).

Pierwszy z prezentowanych wykresów (rysunek 14.1) pokazuje całkowitą licz­bę prób połączeń, aktywnych i pasywnych, w ciągu pięciodniowego okresu. Przedstawione liczby odpowiadają dwóm zmiennym statystycznym TCP, tcps_connattempt i tcps_accepts ze strony 827 tomu 2. Pierwsza zmienna jest inkrementowana, gdy zostaje wysłany segment SYN w aktywnym otwarciu, a druga - gdy SYN zostaje otrzymany przez odbierające gniazdo. Zmienne te są uaktualniane dla wszystkich połączeń TCP w danym systemie, nie tylko dla połą­czeń HTTP. Spodziewamy się, że system, który przede wszystkim pełni rolę serwera WWW, będzie znacznie częściej odbierał połączenia niż je nawiązywał. (System pełni też inne funkcje, ale większość ruchu TCP/IP stanowią pakiety HTTP.)

Dwie linie przerywane w czasie zbliżonym do piątkowego i sobotniego południa ograniczają 24-godzinny okres, w którym segmenty SYN /FIN /R ST były zbierane. Biorąc pod uwagę tylko pasywne próby połączeń zauważamy, że każdego dnia w okresie od przedpołudnia do północy nachylenie wykresu jest większe, tak jak się tego zresztą spodziewamy. Zauważamy również, że nachylenie jest mniejsze w ciągu weekendu, poczynając od północy w piątek. Te dobowe periodyczne zmia­ny są lepiej widoczne na wykresie częstotliwości pasywnych prób połączeń poka­zanym na rysunku 14.2

Page 211: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 14.1 Wstęp 189

wtorek środa czwartek piątek sobota niedzielapołudnie południe południe południe południe południe

czas działania systemu od przeładowania (minuty)

Rysunek 14.1 Całkowita liczba aktywnych i pasywnych prób połączeń

wtorek środa czwartek piątek sobota niedzielapołudnie południe południe południe południe południe

czas działania systemu od przeładowania (minuty)

Rysunek 14.2 Jednocześnie działające serwery HTTP

Page 212: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

190 Pakiety znalezione w serwerze HTTP Rozdział 14

Jak można zdefiniować „silnie obciążonego" serwera? Badany system odbierał nieco ponad 150 000 połączeń TCP dziennie. Daje to średnią 1,74 połączenia na sekundę.W pracy [Braun i Claffy 1994] omówiono serwer NCSA, który otrzymywał średnio360 000 żądań klientów dziennie (we wrześniu 1994) i obciążenie podwajało się po każ­dych 6-8 tygodniach. Inny autor [Mogul 1995b] analizuje pracę dwóch serwerów, które określa jako „względnie obciążone". Jeden z tych serwerów przetwarzał milion, a drugi 40 000 żądań dziennie w okresie ponad 3 miesięcy. W „The Wall Street Journal" z 21 czerwca 1995 r. wyliczono 10 najbardziej obciążonych serwerów WWW, na podstawie pomiarów wykonanych w tygodniu od 1 do 7 maja 1995 r. Serwery te odbierały od 4,3 miliona połączeń na tydzień ( w w w . n etscape, c o m) do zaledwie 300 000 połączeń dzien­nie. Na podstawie danych przytoczonych powyżej widzimy, że wszelkie stwierdzenia dotyczące szybkości i sprawności działania serwerów W W W oraz odpowiednich danych statystycznych należy przyjmować z rezerwą. Jak zobaczymy w tym rozdziale, mogą istnieć wielkie różnice pomiędzy serwerami, dotyczące liczby prób połączeń na dzień, liczby nawiązanych połączeń, liczby klientów i liczby sesji. Innym czynnikiem, który powinien być wzięty pod uwagę, jest liczba hostów, na których działa serwer danej instytucji, co będziemy omawiać w następnym podrozdziale.

14.2 Jednoczesne serwery HTTPZ najprostszą sytuacją mamy do czynienia, gdy pojedynczy serwer HTTP jesturuchomiony w jednym komputerze. Choć wiele węzłów może być zorganizowa­nych właśnie w ten sposób, istnieją dwie inne często spotykane sytuacje.

1. Jeden host, wiele serwerów. Ta metoda była użyta w serwerze, który dostarczył danych analizowanych w tym rozdziale. Pojedynczy host świadczy usługi HTTP dla wielu instytucji. Nazwie domeny WWW każdej z tych instytucji (www . organ i za tion. com) odpowiada inny adres IP (wszystkie adresy należą do tej samej podsieci) i do wszystkich tych adresów IP zostaje przypisany jeden interfejs internetowy. (W rozdziale 6.6 tomu 2 opisaliśmy, w jaki sposób N et/3 dopuszcza wiele różnych adresów IP dla jednego interfejsu. Dodatkowe adresy IP przypisane do interfesju, oprócz podstawowego, nazywane są aliasami.) Każda z 22 kopii serwera h 11 p d obsługuje tylko jeden adres IP. Każdy z tych 22 serwerów wiąże jeden lokalny adres IP ze swoim odbierającym gniazdem, tak że odbiera on tylko połączenia przeznaczone dla tego adresu IP.

2. Kilka hostów udostępnia po jednej kopii serwera. Ta technika stosowana jest przez silnie obciążone instytucje w celu rozłożenia obciążenia na kilka hostów (load balancing - wyrównywanie obciążenia). Wiele różnych adresów IP zostaje przypisanych do domeny WWW danej instytucji, www. organi zat i on . com- jeden adres IP dla każdego hosta z uruchomionym serwerem HTTP (wielokrot­ne rekordy A w DNS, rozdział 14 w tomie 2). Serwer DNS instytucji musi potrafić dostarczać wielorakie adresy IP w różnej kolejności dla różnych żądań klienta DNS. W protokole DNS postępowanie takie nazywane jest przetioarzci- niem cyklicznym (round-robin) i zostaje udostępniane choćby przez aktualną wersję powszechnie spotykanego serwera DNS (BIND).

Page 213: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 14.3__________Czas pomiędzy otrzymaniem kolejnych segmentów SYN 191

Na przykład NCSA udostępnia dziewięć serwerów HTTP. Przy pierwszym zapytaniu skierowanym do serwera DNS tej instytucji otrzymujemy:

$ host -t a www.ncsa.uiuc.edu newton.ncsa.uiuc.eduServer: newton.ncsa.uiuc.edu A d d r e s s : 141.142.6.6 141.142.2.2

www.ncsa.uiuc.edu www.ncsa.uiuc.edu w w w . n c s a .ui u c .edu w w w .n c s a .ui u c .edu w w w .n c s a .ui u c .edu w w w . n c s a .ui uc.edu www.ncsa.uiuc.edu www.ncsa.uiuc.edu w w w . n c s a .ui uc.edu

A 141 142.3.129A 141 142.3.131A 141 142.3.132A 141 142.3.134A 141 142.3.76A 141 142.3.70A 141 142.3.74A 141 142.3.30A 141 142.3.130

(Program host został opisany w rozdziale 14 tomu 1.) Ostatni argument jest nazwą serwera DNS, NCSA, do którego skierowane jest zapytanie. Jeśli ten argument nie będzie podany, program skontaktuje się z lokalnym serwerem DNS, a ten będzie prawdopodobnie posiadał 9 rekordów A w swojej pamięci podręcznej i będzie je zwracał za każdym razem w tej samej kolejności.

Przy następnym uruchomieniu programu, kolejność rekordów jest inna:

$ host -t a www.ncsa.uiuc.edu newton.ncsa.uiuc.eduServer: newton.ncsa.uiuc.edu Address: 141.142.6.6 141.142.2.2

www.ncsa.uiuc.edu A 141.142.3.132www.ncsa.uiuc.edu A 141.142.3.134www.ncsa.uiuc.edu A 141.142.3.76www.ncsa.uiuc.edu A 141.142.3.70www.ncsa.uiuc.edu A 141.142.3.74www.ncsa.uiuc.edu A 141.142.3.30www.ncsa.uiuc.edu A 141.142.3.130www.ncsa.uiuc.edu A 141.142.3.129www.ncsa.uiuc.edu A 141.142.3.131

14.3 Czas pomiędzy otrzymaniem kolejnych segmentów SYNInteresujące może być przeanalizowanie odstępów czasu pomiędzy kolejnymi segmentami SYN. W ten sposób możemy stwierdzić, jaka jest różnica pomiędzy średnią częstotliwością żądań, a częstotliwością maksymalną. Serwer powinien być w stanie spełniać swoje funkcje w warunkach maksymalnego, a nie tylko średniego obciążenia.

Możemy zmierzyć czas pomiędzy segmentami SYN otrzymywanymi przez ser­wera w czasie 24-godzinnej rejestracji segmentów SYN/FIN/RST. W ciągu 24 godzin serwery HTTP odebrały 160 948 segmentów SYN. (Na początku tego rozdziału zauważyliśmy, że zarejestrowano 147103 próby nawiązania połączenia. Różnica związana jest z powtórnie przesyłanymi segmentami SYN. Zauważmy, iż niemal 10% segmentów SYN jest retransmitowanych.) Najmniejszy i największy odstęp czasu między segmentami SYN wynosi odpowiednio 0,1 ms i 44,5 sekundy.

Page 214: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

192 Pakiety znalezione w serwerze HTTP Rozdział 14

Wartość średnia wynosi 538 ms, mediana 222 ms. 91% odstępów czasu jest krót­szych niż 1,5 sekundy. (Rozkład odstępów czasu pokazujemy na rysunku 14.3.)

Przedstawiony histogram, choć interesujący, nie podaje jednak maksymalnej czę­stotliwości otrzymywania segmentów SYN. Żeby wyznaczyć częstotliwość m a­ksymalną, dzielimy 24-godzinny okres na przedziały 1-sekundowe i obliczamy liczbę segmentów SYN otrzymywanych w każdej sekundzie. (W rzeczywistości czas trwania pomiaru był o parę minut dłuższy niż 24 godziny i wynosił 86 622 sekundy.) Na rysunku 14.4 prezentujemy liczby przedziałów jednosekundowych, w których odebranych było 0,1,2,...20 segmentów. W drugiej kolumnie na rysunku przedstawiono całkowite liczby segmentów, w kolumnie trzeciej - liczby segmen­tów otrzymane po odrzuceniu segmentów przesyłanych powtórnie. Wartości widniejące w ostatniej kolumnie wykorzystamy na końcu tego podrozdziału.

Jeżeli weźmiemy pod uwagę wszystkie odbierane segmenty SYN, to stwierdzamy, że było 27 868 sekund (32% 24-godzinnego okresu), w których nie odebrano żadnego segmentu SYN, 22 471 sekund (26% okresu) z jednym odebranym seg­mentem SYN, itd. Maksymalnie w ciągu sekundy odebraliśmy 73 segmenty i były dwie takie sekundy w ciągu doby. Jeśli weźmiemy pod uwagę wszystkie sekundy, w których odebranych było 50 lub więcej segmentów SYN, stwierdzamy, że wszystkie takie sekundy pojawiają się w ciągu 3-minutowego okresu. Jest to poszukiwane maksimum obciążenia.

Page 215: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 14.3_________ Czas pomiędzy otrzymaniem kolejnych segmentów SYN 193

Liczba segmentów SYN otrzymywanych w ciągu 1 sekundy

Całkowita liczba przypadków

Liczba przypadków dla nowych SYN

0 27868 30565

1 22471 22695

2 13036 12374

3 7906 7316

4 5499 5125

5 3752 3441

6 2525 2197

7 1456 1240

8 823 693

9 536 437

10 323 266

11 163 130

12 90 66

13 50 32

14 22 18

15 14 10

16 12 9

17 4 3

18 5 2

19 2 1

20 3 0

86560 86620

Rysunek 14.4 Liczba segmentów SYN odbieranych w danej sekundzie

Na rysunku 14.6 przedstawiliśmy wykres dla godziny zawierającej maksimum obciążenia. Sumujemy 30 jednosekundowych liczników i tak określamy skalę na osi y, by odpowiadała ona liczbie otrzymywanych segmentów SYN na sekundę. Średnia częstotliwość otrzymywania SYN wynosi około 3,5 segmenta na sekundę, a więc przeć całą tę godzinę przychodzące segmenty SYN są przetwarzane z czę­stotliwością niemal dwukrotnie większą od częstotliwości średniej.

Na rysunku 14.7 przedstawiamy dokładniej owe trzy minuty z maksymalnym obciążeniem.

Zmiany częstotliwości w tym trzyminutowym okresie są sprzeczne z intuicją i sugerują patologiczne zachowanie jakiegoś klienta. Jeśli spojrzymy na wydruk Tcpdump dla tych trzech minut, widzimy, że problem związany jest rzeczywiście z jednym klientem. W ciągu 30 sekund obejmujących pierwsze (z lewej strony rysunku) maksimum na rysunku 14.7, klient ten wysyła 1024 segmenty SYN z dwóch różnych portów, co daje średnią około 30 segmentów SYN na sekundę. W kilku okresach jednosekundowych zaobserwowano po 60-65 segmentów, co w sumie z segmentami pochodzącymi od innych klientów dało maksimum na

Page 216: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

194 Pakiety znalezione w serwerze HTTP Rozdział 14

poziomie około 70 segmentów na sekundę. Środkowe maksimum na tym rysunku było również spowodowane przez tego samego klienta.

Na rysunku 14.5 pokazujemy związany z tym klientem fragment wydruku Tcpdump.

1 0.0 Client.1537 > server,80:

2 0.001650 (0.0016) server.80 > Client.1537:

3 0.020060 (0.0184) Client.1537 > server.80:

4 0.020332 (0.0003) server.80 > C l i e n t . 1537:

5 0.020702 (0.0004) server.80 > Client.1537:

6 1.938627 (1.9179) Client.1537 > server.80:

7 1.958848 (0.0202) Client.1537 > server.80:

8 1.959802 (0.0010) server.80 > Client.1537:

9 2.026194 (0.0664) client.1537 > server.80:

10 2.027382 (0.0012) server.80 > Client.1537:

11 2.027998 (0.0006) server.80 > Client.1537:

S 1317079:1317079(0) win 2048 <mss 1460>

S 2104019969:2104019969(0) ack 1317080 win 4096 <mss 512>

S 1317092:1317092(0) win 2048 <mss 1460>

R 2104019970:2104019970(0) ack 1317080 win 4096

R 0:0(0) ack 1317093 win 0

R 1317080:1317080(0) win 2048

S 1319042:1319042(0) win 2048 <mss 1460>

S 2105107969:2105107969(0) ack 1319043 win 4096 <mss 512>

S 1319083:1319083(0) win 2048 <mss 1460>

R 2105107970:2105107970(0) ack 1319043 win 4096

R 0:0(0) ack 1319084 win 0

Rysunek 14.5 Wcidliiuy klient wysyłający z dużą częstotliwością niepoprawne segmenty SYN - wydruk Tcpdump

liczba segmentów

SYN otrzymywanych w ciągu sekundy

czas (minuty)

Rysunek 14.6 Liczba otrzymywanych segmentów SYN na sekundę w 60-minutowym przedziale czasu

Page 217: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 14.3_________ Czas pomiędzy otrzymaniem kolejnych segmentów SYN 195

Rysunek 14.7 Liczba otrzymanych segmentów SYN na sekundę w 3-minutoivym przedziale czasu z maksimum obciążenia

W linii pierwszej widzimy SYN klienta, a w drugiej segment SYN /ACK serwera. W trzeciej znajdujemy natomiast inny segment SYN, z tego samego portu tego samego klienta, z początkowym numerem sekwencyjnym większym o 13 od nu­meru sekwencyjnego z linii pierwszej. Serwer wysyła RST w linii czwartej i następ­ne RST w linii piątej, a klient wysyła RST w linii szóstej. Scenariusz powtarza się, poczynając od linii siódmej.

Dlaczego serwer wysyła pod rząd dwa segmenty RST do klienta (linie czwarta i piąta)? Jest to prawdopodobnie spowodowane przez jakieś segmenty, które nie są tu pokazane, gdyż ten wydruk Tcpdump zawiera, niestety, jedynie segmenty z flagami SYN, FIN i RST. Mimo to widać wyraźnie, że klient działa wadliwie, wysyłając segmenty SYN z tak dużą częstotliwością z tego samego portu i z nie­znacznie zmieniającymi się numerami sekwencyjnymi pomiędzy kolejnymi seg­mentami SYN.

Obliczenia powtórzone bez retransmitowanych SYNMusimy jeszcze raz przeanalizować czas pomiędzy kolejnymi otrzymanymi seg­mentami, pomijając powtórnie przesyłane segmenty SYN, ponieważ - jak właśnie stwierdziliśmy - jeden wadliwy klient może znacząco zmienić wyniki. Tak jak wspomnieliśmy na początku tego rozdziału, odrzucamy w ten sposób około 10% segmentów SYN. Pomijając powtórzone segmenty SYN, analizujemy też częstotli­wość nawiązywania nowych połączeń z serwerem. Podczas gdy częstotliwość

Page 218: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

196 Pakiety znalezione w serwerze HTTP Rozdział 14

odbierania wszystkich segmentów SYN ma znaczenie dla przetwarzania protoko­łu TCP/IP (ponieważ każdy SYN jest przetwarzany przez program obsługi urzą­dzenia, wejście TCP i wreszcie wyjście TCP), to częstotliwość nawiązywania połą­czeń wiąże się z działaniem serwera HTTP (który obsługuje nowe żądanie dla każdego połączenia).

Przedstawiona na rysunku 14.3 wartość średnia wzrasta od 538 do 600 ms, a me­diana zwiększa się od 222 do 251 ms. Na rysunku 14.4 podane zostały wcześniej liczby segmentów otrzymywanych w ciągu sekundy. Piki, takie jak te przedsta­wione na rysunku 14.6, są teraz znacznie mniejsze. W ciągu trzech sekund z naj­większą w ciągu dnia liczbą segmentów SYN otrzymano 19, 21 i 33 takie segmen­ty. Odbieranych jest więc od 4 segmentów na sekundę (dla mediany rozkładu odstępu czasu między segmentami równej 251 ms) do maksymalnie 33 segmen­tów na sekundę, czyli częstotliwość otrzymywanych segmentów wzrasta o czyn­nik rzędu 8 w stosunku do wartości najczęściej spotykanej. Oznacza to, że przy projektowaniu serwera WWW powinniśmy przewidzieć maksimum częstotliwo­ści połączeń o podobnej wielkości w stosunku do wartości średniej. W rozdziale14.5 omówimy wpływ takich okresów o wyjątkowo dużej częstotliwości połączeń na kolejkę odbieranych żądań.

14.4 Pomiary RTTZajmiemy się teraz określeniem czasu przesłania pakietów w obie strony (RTT) pomiędzy serwerem i różnymi klientami. Niestety, nie jesteśmy w stanie wyzna­czyć RTT na podstawie zestawu danych zawierającego segmenty SYN/FIN/RST. Na rysunku 14.8 przedstawiliśmy potrójne uzgodnienie TCP oraz cztery segmenty kończące połączenie (z pierwszym segmentem FIN wysłanym przez serwera). Pogru­bione linie odpowiadają segmentom zarejestrowanym w zestawie SYN/FIN/RST.

Klient może wyznaczyć swoją wartość RTT jako różnicę pomiędzy czasem wysła­nia własnego SYN, a czasem otrzymania segmentu SYN od serwera, my jednak wykonujemy pomiary po stronie serwera. Możemy rozważać wyznaczenie RTT serwera jako czasu pomiędzy wysłaniem flagi FIN serwera, a otrzymaniem flagi FIN od klienta. Taki pomiar zawiera jednak zmienne opóźnienie po stronie klien­ta: czas pomiędzy otrzymaniem przez aplikację klienta znaku końca pliku, a za­mknięciem połączenia po stronie klienta.

Do pomiaru RTT serwera potrzebujemy zestawu danych zawierającego wszystkie pakiety. Użyjemy więc danych zebranych w okresie 2,5-godzinnym i wyznaczy­my czas pomiędzy wysłaniem SYN/ACK przez serwera, a otrzymaniem przez serwera flagi ACK klienta. Potwierdzenie przez klienta segmentu SYN serwera zwykle nie jest opóźnione (strona 988jtom 2), pomiar ten nie obejmuje więc (w zasadzie) opóźnionego ACK. Dobrze, by rozmiary segmentów były najmniejsze z możliwych (44 bajty dla segmentu SYN serwera zawierającego opcję MSS z warto­ścią MSS używaną przez serwera i 40-bajtowe potwierdzenie klienta) - segmenty te nie powinny być znacząco opóźnione w wolnych liniach SLIP lub PPP.

Page 219: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 14.4 Pomiary RTT 197

W czasie 2,5-godzinnego okresu wykonano 19 195 pomiarów RTT dla 810 klien­tów o różnych adresach IP. Najmniejsza wartość RTT wyniosła 0 (dla klienta w tym samym komputerze), największa 12,3 sekundy, wartość średnia była równa 445 ms, a mediana 187 ms. Rozkład RTT dla wartości nie większych niż 3 sekundy pokazany jest na rysunku 14.9. W tym przedziale mieści się 98,5% otrzymanych wartości. Widzimy z tych pomiarów, że przy teoretycznej wartości RTT dla najbar­dziej oddalonych klientów (wschodnie - zachodnie wybrzeże w USA - przyp. tłum.) równej około 60 ms, wartości otrzymane dla typowych klientów są przynaj­mniej trzykrotnie większe.

Dlaczego mediana (178 ms) jest aż o tyle większa od teoretycznej wartości dla najbardziej oddalonych klientów (60 ms)? Pierwszym możliwym wytłumaczeniem jest to, że wiele klientów używa linii telefonicznych, a każdy, nawet szybki modem (28 800 bps) dodaje 100-200 ms do każdej wartości RTT. Możliwe także, że niektóre implementacje klienta opóźniają jednak trzeci segment potrójnego uzgodnienia - potwierdzenie przez klienta segmentu SYN serwera.

Page 220: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

198 Pakiety znalezione w serwerze HTTP Rozdział 14

14.5 Drugi argument funkcji listenSerwer, by przygotować gniazdo do odbioru przychodzących połączeń, tradycyj­nie wykonuje

1isten(sockfd. 5);

Drugi argument funkcji 1 i sten zwany jest argumentem przepełnienia (backlog) w na­główku <sys/socket. h>. Jeżeli aplikacja podaje większą wartość, wartość ta zo­staje w istocie milcząco zredukowana do S0MAXC0NN. W nowszych jądrach wartość S0MAXC0NN została zwiększona na przykład do 10 z przyczyn, które za chwilę omówimy.

Dla gniazda argument przepełnienia (strony 470-471 w tomie 2). Gdy otrzymane zostaje żądanie połączenia TCP (SYN klienta), TCP wywołuje sonewconn i przepro­wadzone zostaje następujące sprawdzenie (linie 130-131 na stronie 477 w tomie 2):

if (head->so_qlen + head->so_q01en > 3 * h ea d->sp_qlimit / 2) return ((struct socket *)0):

Jak opisano w tomie 2, mnożenie przez czynnik 3 /2 dodaje margines bezpieczeństwa do Argumentu przepełnienia l i s t e n podanego przez aplikację - ogranicza w rzeczywistości liczbę oczekujących połączeń do 8, gdy wartość argumentu wynosi 5. Taki margines bezpieczeństwa istnieje tylko w implementacjach wywodzących się z systemu Berkeley (strony 299-301 w tomie 1).

Page 221: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 14.5 Drugi argument funkcji listen 199

Limit liczby połączeń w kolejce ogranicza w rzeczywistości sumę następujących wartości:

- liczba pozycji w kolejce niekompletnych połączeń (so_q01 en - połączenia, dla których nadszedł segment SYN, ale potrójne uzgodnienie jeszcze nie zostało zakończone),

- liczba pozycji w kolejce kompletnych połączeń (s o_q 1 en - potrójne uzgodnie­nie jest zakończone i jądro czeka aż proces wywoła accept).

Na stronie 476 w tomie 2 przedstawiono dokładnie kolejne kroki przetwarzania, gdy odebrane zostaje żądanie połączenia TCP.

Ograniczenie liczby połączeń umieszczanych w kolejce może zostać osiągnięte, gdy kolejka kompletnych połączeń zapełni się (tzn. proces serwera lub host serwe­ra są tak zajęte, że proces nie może wystarczająco szybko wywołać connect i usunąć połączenia z kolejki) lub gdy zapełni się kolejka niekompletnych połą­czeń. Ta druga sytuacja zdarza się w przypadku serwera HTTP, gdy czas przesła­nia pakietu w obie strony jest długi w porównaniu z częstotliwością otrzymywa­nia nowych żądań połączeń. Dzieje się tak dlatego, bo nowy segment SYN zajmuje miejsce w tej kolejce przez czas RTT. Przedstawione to zostało na rysunku 14.10.

Rysunek 14.10 Czas istnienia wpisu w kolejce niekompletnych połączeń

Program netstat został zmodyfikowany tak, by możliwe było sprawdzenie, czy wypełnia się kolejka niekompletnych połączeń (a nie połączeń kompletnych). Zmodyfikowany program wypisuje w sposób ciągły wartości dwóch zmiennych, so_q01 en i so_ql en, dla najbardziej zajętych odbierających serwerów HTTP. Pro­gram został uruchomiony na przeciąg dwóch godzin, w czasie których zebrano 379 076 wartości obu zmiennych, co daje jeden pomiar co 19 ms. Wyniki przedsta­wiono na rysunku 14.11.

Page 222: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

200 Pakiety znalezione w serwerze HTTP Rozdział 14

Długość kolejki Liczba przypadkówdla kolejki niekompletnychpołączeń

Liczba przypadków dla kolejki kompletnych połączeń

0 167123 379075

1 116175 1

2 42185

3 18 842

4 12871

5 14581

6 6 346

7 706

8 245

379076 379076

Rysunek 14.11 Rozkład długości kolejek połączeń dla silnie obciążonego senuera HTTP

Tak jak wspomnieliśmy wcześniej, wartość argumentu przepełnienia równa 5 dopuszcza maksymalnie 8 połączeń oczekujących w kolejce. Kolejka kompletnych połączeń jest niemal zawsze pusta, ponieważ gdy tylko coś pojawia się w tej kolejce, wywołanie accept w kodzie serwera zwraca kontrolę i serwer usuwa kompletne połączenie z kolejki.

Gdy kolejka przepełnia się, TCP ignoruje przychodzące żądania połączeń (strona 969 w tomie 2), zakładając, że klient po upływie czasu oczekiwania na retransmisję wyśle ponownie SYN, i być może po paru sekundach znajdzie miejsce w kolejce. Kod N et/3 nie zlicza jednak w żaden sposób takich zignorowanych segmentów SYN, administrator systemu nie ma więc żadnej możliwości sprawdzenia, jak często coś takiego się zdarza. W związku z tym wprowadziliśmy następującą modyfikację w kodzie serwera:

if (so->so_options & S0_ACCEPTC0NN) ( so = sonewconn(so, 0);i f (s o == 0) I

tcpstat.tcps_listendrop++; /* nowy licznik */ goto drop:

I

Dodaliśmy w ten sposób nowy licznik połączeń.

Na rysunku 14.12 pokazujemy wartości tego licznika rejestrowane raz na godzinę w ciągu pięciu dni. Co prawda licznik obejmuje wszystkie serwery w naszego hosta, ale - biorąc pod uwagę, że host ten głównie pełni rolę serwera WWW - możemy być pewni, że przepełnienia kolejki zdarzają się dla odbierających gniazd httpd. Średnio host ten ignoruje zaledwie trzy przychodzące połączenia na minu­tę (22 918 przepełnień podzielonych przez 7139 minut), widoczne są jednak wyraźne skoki, gdy liczba przepełnień jest znacząco większa. W czasie oznaczo­nym na rysunku jako 4500 (godz. 4.00 w piątek po południu) 1964 segmenty SYN zostały zignorowane w ciągu 1 godziny, co daje 32 zignorowane segmenty na minutę (jeden segment co 2 sekundy). Dwa inne znaczące skoki pojawiają się w czwartek po południu.

Page 223: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 14.5 Drugi argument funkcji listen 201

wtorekpołudnie

przepełnieniakolejki

odbiorczej

środapołudnie

czwartekpołudnie

piątekpołudnie

sobotapołudnie

niedzielapołudnie

czas działania systemu od przeładowania w minutach

Rysunek 14.12 Przepełnienie kolejki odbiorczej serwera

W jądrach systemów obsługujących silnie obciążone serwery wartość argumentu przepełnienia jest pod tym względem wadliwa, ponieważ w tej wersji liczba 5 jest bezpośrednio wpisana jako wartość drugiego argumentu funkcji 1 i sten:

listentsd. 5);

W wersji 1.4 wartość argumentu jest zwiększona do 35, ale nawet ta wartość może być zbyt mała dla silnie obciążonych serwerów.

W systemach pochodzących od różnych dostawców, stosowane są różne meto­dy zwiększania argumentu przepełnienia, na przykład globalna zmienna jądra somaxconn inicjowana jest wartością 16 i może być zwiększona przez administra­tora systemu. Solaris 2.4 umożliwia administratorowi zmianę wartości parametru TCP tcp_conn_req_max przy pomocy programu ndd. Wartość domyślna wynosi 5 i może być maksymalnie zwiększona do 32. W systemie Solaris 2.5 wartość domyślna jest zwiększona do 32, a wartość maksymalna wynosi 1024. Niestety, nie istnieje prosty sposób sprawdzenia przez aplikację, jaka jest aktualna wartość argumentu wywołania funkcji 1 i sten w jądrze. Najlepiej więc, by w aplikacji podana była duża wartość argumentu (wartość zbyt duża nie powoduje błędu funkcji listen), lub by użytkownik mógł podać tę wartość jako argument w linii polecenia. Zaproponowano również [Mogul 1995c], by argument przepełnienia był ignorowany, a jądro ustalało możliwie największą wartość limitu.

Page 224: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

202 Pakiety znalezione w serwerze HTTP Rozdział 14

Niektóre aplikaq'e z premedytacją podają niską wartość argumentu przepełnienia. Po­winna więc istnieć możliwość uniknięcia zwiększania tej wartości dla niektórych aplikacji.

Błąd SYN_RCVDPrzy okazji analizowania wydruku n e t s t a t zauważono, że jedno gniazdo pozo­stawało w stanie SYN_RCVD przez wiele minut. W kodzie N et/3 czas trwania tego stanu jest ograniczony przez zegar nawiązywania połączenia (connection-es- tablishment timer, strony 860 i 984 w tomie 2) do 75 sekund, więc zaobserwowana sytuacja nie była spodziewana. Na rysunku 14.13 przedstawiamy wydruk Tcpdump.

1 0.0 Client.4821 > server.80: S 32320000:32320000(0)win 61440 <mss 512>

2 0.001045 ( 0.0010) server.80 > Client.4821: S 365777409:365777409(0)ack 32320001 win 4096 <mss 512>

3 5.791575 ( 5.7905) server.80 > Client.4821: S 365777409:365777409(0)ack 32320001 win 4096 <mss 512>

4 5.827420 ( 0.0358) Client.4821 > server.80: S 32320000:32320000(0)win 61440 <mss 512>

5 5.827730 ( 0.0003) server.80 > Client.4821: S 365777409:365777409(0)ack 32320001 win 4096 <mss 512>

6 29.801493 (23.9738) server.80 > Client.4821: S 365777409:365777409(0)ack 32320001 win 4096 <mss 512>

7 29.828256 ( 0.0268) Client.4821 > server.80: S 32320000:32320000(0)win 61440 <mss 512>

8 29.828600 ( 0.0003) server\80 > Client.4821: S 365777409:365777409(0)ack 32320001 win 4096 <mss 512>

9 77.811791 (47.9832) server.80 > Client.4821: S 365777409:365777409(0)ack 32320001 win 4096 <mss 512>

10 141.821740 (64.0099) server.80 > Client.4821: S 365777409:365777409(0)ack 32320001 win 4096 <mss 512>

serwer ponawia przestanie SYN/ACK co 64 sekundy

18 654.197350 (64.1911) server.80 > Client.4821: S 365777409:365777409(0)ack 32320001 win 4096 <mss 512>

Rysunek 14.13 Gniazdo serwera pozostające ponad 11 minut w stanie SYN_RCVD

Flaga SYN klienta otrzymana zostaje w segmencie pierwszym, a drugi segment zawiera SYN/ACK serwera. Serwer ustawia zegar nawiązywania połączenia na 75 sekund i ustala czas oczekiwania na retransmisję na 6 sekund. Czas ten upływa w trzeciej linii i serwer wysyła powtórnie SYN/ACK. Jest to zgodne z oczekiwa­niami.

Klient odpowiada w linii czwartej, ale odpowiedź jest powtórzeniem oryginalne­go segmentu SYN z linii pierwszej, a nie oczekiwanym potwierdzeniem segmentu SYN serwera. Wydaje się, że klient działa wadliwie. Serwer poprawnie odpowiada powtórzonym segmentem SYN/ACK. Otrzymanie czwartego segmentu powodu­je, że wejście TCP ustawia zegar „podtrzymywania" połączenia (keepalive timer, strona 971 tomu 2) na 2 godziny. Zegary nawiązywania połączenia i podtrzymy-

Page 225: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 14.6 Opcje w segmencie SYN klienta 203

wania połączenia używają jednak tego samego licznika w bloku kontrolnym (ry­sunek 25.2, strona 849 w tomie 2), tak więc pozostające 69 sekund zegara nawiązy­wania połączenia zostaje zastąpione 2 godzinami. Zwykle klient zakańcza potrój­ne uzgodnienie potwierdzeniem segmentu SYN serwera. Kiedy to potwierdzenie jest przetworzone, zegar podtrzymywania połączenia otrzymuje wartość 2 godzin1 zegar oczekiwania na powtórzenie transmisji jest wyłączony.

Linie szósta, siódma i ósma są podobne. Czas oczekiwania serwera na powtórze­nie transmisji upływa po 24 sekundach, serwer wysyła ponownie SYN/ACK, ale klient błędnie wysyła swój oryginalny SYN jeszcze raz, tak więc serwer poprawnie powtarza wysłanie SYN/ACK. W linii dziewiątej czas oczekiwania serwera na powtórzenie transmisji upływa raz jeszcze po 48 sekundach i SYN /ACK jest ponownie wysłany. Zegar oczekiwania na powtórzenie transmisji osiąga następ­nie maksymalną wartość równą 64 sekundy i wykonanych zostaje 12 retransmisji (stała TC P_MAX RXTSHIFT, strony 874,875 tomu 2, ma wartość 12,) po czym połącze­nie zostaje odrzucone.

Błąd można poprawić unikając ustawienia zegara podtrzymywania połączenia na2 godziny, gdy połączenie nie jest nawiązane (strona 971 w tomie 2), jako że licznik TCPT_KEEP jest używany wspólnie przez zegar podtrzymywania połączenia i ze­gar nawiązywania połączenia. Wprowadzenie takiej modyfikacji wymaga jednak, by po nawiązaniu połączenia zegar podtrzymywania połączenia został ustawiony na 2 godziny.

14.6 Opcje w segmencie SYN klientaPonieważ w 24-godzinnym zestawie danych rejestrujemy wszystkie segmenty SYN, możemy przyjrzeć się wartościom różnych parametrów i opcjom zawartym w segmentach SYN.

Numery portów klientówSystemy wywodzące się z systemu Berkeley przypisują efemeryczne numery por­tów z zakresu od 1024 do 5000 (strona 758, tom 2). Tak jak się spodziewamy, 93,5% spośród 160 000 numerów portów klientów zawiera się w tym zakresie. Otrzyma­nych zostało 14 żądań klientów z numerem portu mniejszym niż 1024, czyli z zakresu odpowiadającego zarezerwowanym numerom portów w N et/3 , a po­zostałe 6,5% żądań miało numery portów pomiędzy 5001 i 65 535. Niektóre syste­my, w szczególności Solaris 2.x, przypisują numery portów poczynając od 32 768.

Rysunek 14.14 pokazuje rozkład numerów portów klientów. Numery te zgrupo­wane są w przedziałach o szerokości 1000. Zwracamy uwagę na logarytmiczną skalę osi y. Zauważmy, że nie tylko większość numerów portów zawiera się w przedziale od 1024 do 5000, ale dwie trzecie tych numerów ulokowanych jest pomiędzy 1024 i 2000.

Page 226: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

204 Pakiety znalezione w serwerze HTTP Rozdział 14

100000

50000 —

20 00 0 -

10000 -

5000 -

2000 -

1000 -

liczba przypadków ’(skala logarytmiczna) ^

100 -

50-

2 0 -

1 0 — |

5

2 — 1

100000

-50000

— 20000

- 10000

5000

— 2000

— 1000

500

— 200

100

50

- 2 0

— 10

- 5

— 21

5000 10000 15000 20000 25000 30000 35000 40000 45000 50000 55000 60000 65000 numer portu klienta

Rysunek 14.14 Rozkład numerów portu klientów

Maksymalny rozmiar segmentu (MSS)Zgłoszony maksymalny rozmiar segmentu (MSS) może wynikać z wartości MTU sieci (patrz nasza wcześniejsza dyskusja w związku z rysunkiem 10.9) lub mogą być używane pewne ustalone wartości (512 lub 536 dla nielokalnych partnerów, 1024 dla starszych systemów BSD, itd.). RFC 1191 [Mogul i Deering 1990] wylicza 16 różnych, typowych wartości MTU. Spodziewaliśmy się więc znaleźć kilkana­ście różnych wartości MSS zgłaszanych przez klientów WWW. Znaleźliśmy nato­miast 117 różnych wartości w zakresie od 128 do 17 520.

Na rysunku 14.15 pokazujemy trzynaście najczęściej spotykanych wartości MSS zgłoszonych przez klientów. Tych 5071 klientów stanowi 94% wszystkich 5386 klientów, które łączyły się z serwerami WWW. Określenie „brak" w pierwszej pozycji w tabeli oznacza, że segment SYN klienta nie zgłaszał wartości MSS.

Informacja o początkowym rozmiarze okna

Segmenty SYN klientów zawierają również informacje klienta o początkowym rozmiarze okna. Zanotowano 117 różnych wartości rozłożonych w całym dozwo­lonym zakresie od 0 do 65 535. Rysunek 14.16 pokazuje liczby zliczeń dla 14 najczęściej spotykanych wartości.

Page 227: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 14.6 Opcje w segmencie SYN klienta 205

MSS Liczba przypadków Komentarz

brak 703 RFC 1122 nakazuje przyjąć 536, jeżeli opcja nie jest użyta

212 53

216 47 256-40

256 516 połączenie SLIP lub PPP z MTU = 296

408 24

472 21 512-40

512 465 często spotykana wartość domyślna dla nielokalnego hosta

536 1097 często spotykana wartość domyślna dla nielokalnego hosta

966 123 ARPANET MTU (1006)-40

1024 31 wartość używana dawniej w BSD dla lokalnego hosta

1396 117

1440 248

1460 1626 MTU Ethernetu (1500)-40

5071

Rysunek 14.15 Rozkład najczęściej spotykanych wartości MSS zgłaszanych przez klientów

Rozmiar okna Liczba przypadków Komentarz

0 317

512 94

848 66

1024 67

2048 254

2920 296 2x1460

4096 2062 często spotykana wartość domyślna rozmiaru buforu odbiorczego

8192 683 rzadziej spotykana wartość domyślna

8760 179 6 x 1460 (wartość często spotykana dla Ethernetu)

16384 175

22099 486 7 x 7 x 1 1 x 4 1 ?

22792 128 7 x 8 x 1 1 x 3 7 ?

32768 94

61440 89 60x1024

4990

Rysunek 14.16 Rozkład początkowych rozmiarów okna zgłaszanych przez klientów

Wymieniona na rysunku suma 4990 stanowi 93% wszystkich informacji o rozmia­rze okna podanych przez 5386 różnych klientów. Niektóre wartości są sensowne, inne natomiast - jak na przykład 22099 - stanowią zagadkę.

Page 228: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

206 Pakiety znalezione w serwerze HTTP Rozdział 14

Najwidoczniej istnieją przeglądarki W W W w komputerach PC, które pozwalają użyt­kownikowi na podanie wartości takich jak MSS, czy informacja o początkowym rozmia­rze okna. Niektóre zaobserwowane dziwaczne wartości mogły więc zostać wprowadzone przez użytkowników, którzy nie rozumieli znaczenia ustawianych parametrów.Mimo że znaleźliśmy 117 różnych wartości MSS i 117 różnych początkowych rozmiarów okna, po zbadaniu 267 różnych kombinacji MSS i rozmiaru okna nie stwierdziliśmy żadnej oczywistej korelacji między tymi dwoma liczbami.

Opcje skali okna i znacznika czasuRFC 1323 określa opcje skali okna i znacznika czasu (rysunek 2.1). Spośród 5386 różnych klientów 78 wysyłało opcję skali okna, 23 obie opcje, natomiast żaden nie wysyłał tylko opcji znacznika czasu. Wszystkie opcje skali okna zawierały czynnik przesunięcia równy zero (co oznacza czynnik skalujący równy 1, czyli rozmiar okna równy zgłoszonemu rozmiarowi okna TCP).

Wysyłanie danych w segmencie SYNPięciu klientów wysłało dane w segmencie SYN, ale żaden z tych segmentów SYN nie zawierał nowych opcji T/TCP. Okazało się, że każde z połączeń zawierających takie segmenty SYN było zgodne z tym samym schematem. Klient wysyłał zwy­kły, nie zawierający danych segment SYN. Serwer odpowiadał trzecim segmen­tem potrójnego uzgodnienia. Okazywało się jednak, że segment ten był zagubio­ny. Klient wysyłał więc powtórnie SYN. Wysyłany powtórnie segment SYN za każdym razem zawierał również dane (200 do 300 bajtów, zwykłe żądanie HTTP).

Wyznaczanie MTU ścieżkiWyznaczanie MTU ścieżki jest opisane w RFC 1191 [Mogul i Deering 1990] i w rozdziale 24.2 tomu 1. Możemy sprawdzić, jak wielu klientów używa tej opcji sprawdzając, czy segmenty SYN mają ustawiony bit DF (don't fragment, nie dzielić na fragmenty). Okazuje się, że w naszym zestawie danych 679 klientów (12,6%) stosuje wyznaczanie MTU ścieżki.

Początkowe numery sekwencyjne klientaZdumiewająco duża liczba klientów (trochę ponad 10%) stosuje początkowy nu­mer sekwencyjny równy zero, co jest w jawnej sprzeczności ze specyfikacją TCP. Okazuje się, że te implementacje klientów TCP/IP używają wartości 0 dla wszyst­kich aktywnych połączeń. Wniosek ten wyciągamy z faktu, że obserwujemy wiele połączeń z różnych portów tego samego klienta w sekundowych odstępach czasu i każde z tych połączeń używa początkowego numeru sekwencyjnego równego 0. Rysunek 14.19 pokazuje jednego z takich klientów.

14.7 Powtórne wysłania SYN klientaSystemy wywodzące się z systemu Berkeley retransmitują segment SYN po 6 se­kundach od wysłania inicjującego SYN i następnie - jeżeli odpowiedź ciągle

Page 229: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 14.7 Powtórne wysłania SYN klienta 207

jeszcze nie jest otrzymana (strona 860, tom 2) - po 24 sekundach. W 24-godzinnym zestawie danych mamy wszystkie segmenty SYN (z wyjątkiem zagubionych w sieci i przez program Tcpdump), możemy więc sprawdzić, jak często segmenty SYN są wysyłane ponownie przez klientów i jakie są odstępy czasu pomiędzy kolejnymi powtórzeniami wysłania.

W 24-godzinnym zestawie danych znajduje się 160 948 przychodzących segmen­tów SYN (rozdział 14.3), z czego 17 680 segmentów (11%) stanowią segmenty, które uznajemy za duplikaty. (Liczba prawdziwych duplikatów jest mniejsza, ponieważ w niektórych przypadkach odstęp czasu pomiędzy kolejnymi segmen­tami SYN otrzymanymi z tego samego portu i hosta (adres IP) był dość duży, co oznacza, że drugi segment SYN nie był duplikatem, lecz inicjował nowe wcielenie tego samego połączenia. Nie usiłowaliśmy pominąć takich segmentów w analizie, ponieważ stanowiły one niewielką część wspomnianych 11%.)

Dla segmentów SYN, które były przesyłane ponownie tylko raz, czas od wysłania pierwszego segmentu SYN wynosił zwykle 3 ,4 lub 5 sekund. Jeżeli segmenty były retransmitowane wielokrotnie, używany był często algorytm BSD: pierwsza re­transmisja następowała po 6 sekundach, a następna 24 sekundy później. Oznaczy­my tę sekwencję jako {6,24}. Zaobserwowano też następujące sekwencje:

• (3; 6; 12; 24]• {5; 10; 20; 40; 60; 60}• (4; 4; 4; 4} (sprzeczne z wykładniczym algorytmem postępowania w sytuacjach

awaryjnych - exponential backoff-w ym aganym przez RFC 1122)• {0,7; 1,3} (zbyt agresywne powtarzanie transmisji przez hosta, który oddalony

jest w istocie o 20 hopów; znaleziono 20 połączeń od tego hosta z retransmito- wanymi segmentami SYN i we wszystkich tych połączeniach czas pomiędzy kolejnymi powtórzeniami transmisji był mniejszy niż 500 ms !)

• {3; 6,5; 13; 26; 3; 6,5; 13; 26; 3; 6,5; 13; 26) (ten host uruchamia od nowa wykład­niczy algorytm po każdych czterech powtórzeniach transmisji)

• (2,75; 5,5; 11; 22; 44}• (21; 17; 106}• (5; 0,1; 0,2; 0,4; 0,8; 1,4; 3,2; 6,4} (po pierwszym długim oczekiwaniu postępowa­

nie zdecydowanie zbyt agresywne)• {0,4; 0,9; 2; 4} (jeszcze jeden przesadnie agresywny klient oddalony o 19 hopów)• {3; 18; 168; 120; 120; 240}

Jak widzimy, pewne sekwencje są zdumiewające. Niektóre z wielokrotnie retrans- mitowanych segmentów SYN pochodzą prawdopodobnie od hostów z błędnie określonymi marszrutami: hosty te mogą wysyłać pakiety do serwera, ale nigdy nie otrzymują odpowiedzi. Istnieje również możliwość, że niektóre z powtórzeń są żądaniami utworzenia nowego wcielenia wcześniejszego połączenia (na stronie 998 w tomie 2 opisano, w jaki sposób serwer BSD zaakceptuje nowe żądanie połączenia dla połączenia w stanie TIME_WAIT, jeżeli numer sekwencyjny no­wego SYN jest większy niż ostatni numer sekwencyjny połączenia w stanie

Page 230: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

208 Pakiety znalezione w serwerze HTTP Rozdział 14

TIME_WAIT), lecz odstępy czasu (na przykład oczywiste wielokrotności 3 lub 6 sekund), czynią to mało prawdopodobnym.

14.8 Nazwy domenW ciągu okresu 24-godzinnego 5386 hostów o różnych adresach IP łączyło się z serwerami WWW. Ponieważ Tcpdump (z flagą -w) rejestruje jedynie nagłówek pakietu z adresem IP, odpowiadającą nazwę domeny musimy ustalić później.

W pierwszej próbie powiązania adresów IP z nazwami domen przy użyciu DNS znaleźliśmy nazwy tylko dla 4052 (75%) adresów. Dzień później spróbowaliśmy znaleźć nazwy dla pozostałych 1334 adresów używając DNS - udało się to w 62 przypadkach. Oznacza to, że 23,6% klientów nie posiada poprawnego odwrotne­go odwzorowania adresów IP na nazwy domen. (W rozdziale 14.5 w tomie 1 takie odwzorowania przedstawione są szerzej.) Mimo że wielu z tych klientów może znajdować się na końcu linii telefonicznych, które są wyłączone przez większość czasu, nazwy klientów powinny być udostępniane przez serwery nazw, podsta­wowe i alternatywne, połączone stale z Internetem.

Użyliśmy programu Ping, żeby sprawdzić, czy hosty bez poprawnego odwzoro­wania adresu na nazwę były chwilowo niedostępne. Program Ping był urucho­miony dla 1272 pozostających klientów natychmiast po tym, jak fiaskiem zakoń­czyło się poszukiwanie nazwy przez DNS. Ping osiągnął 520 hostów (41%).

Pośród poprawnie znalezionych nazw domen było 57 różnych domen najwyższe­go poziomu (top level). Pięćdziesiąt z nich to domeny o dwuliterowych nazwach odpowiadające innym krajom niż USA, co oznacza - nawiasem mówiąc - że przymiotnik „światowa" jest dla Pajęczyny właściwy.

14.9 Ograniczenie czasu sondowania trwałości połączeniaN et/3 nigdy nie przestaje sondować trwałości połączenia (persist probes). To zna­czy, gdy N et/3 otrzymuje od partnera informacje o rozmiarze okna równą 0, kod ten wysyła w nieskończoność próbki trwałości połączenia, bez względu na to, czy kiedykolwiek otrzymuje cokolwiek z drugiego końca połączenia. Stwarza to prob­lem, gdy partner znika kompletnie (na przykład przerwane zostaje telefoniczne połączenie SLIP lub PPP). Przypominamy (strona 944, tom 2), że nawet gdy jakiś pośredniczący ruter używając protokołu ICMP wysyła komunikat o błędzie infor­mujący, że host jest nieosiągalny, TCP ignoruje taki komunikat, jeśli połączenie zostało ustanowione.

Jeśli takie połączenia nie zostaną odrzucone, TCP będzie stale wysyłać próbki trwałości co 60 sekund do nieistniejącego hosta (niepotrzebnie obciążając sieć). Dodatkowo każde takie połączenie zajmuje pamięć hosta (TCP i odpowiednie bloki kontrolne).

Kod pozwalający zlikwidować ten problem, przedstawiony na rysunku 14.17, pojawia się w 4.4BSD-Lite2 i zastępuje kod na stronie 858 w tomie 2.

Page 231: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 14.9___________Ograniczenie czasu sondowania trwałości połączenia 209

------------------------------------------------------------------------------------------------- tcp_timer.ccase TC P T_ PERSIST:

t cp s ta t.tcps_persi sttimeo++;/** Uwaga: jeśli partner jest martwy/nieosiągalny, nie przerywamy* wysyłania, jeżeli okno zostaje zamknięte.* Po wykonaniu wszystkich czynności przewidzianych dla sytuacji awaryjnej,* połączenie zostaje odrzucone, gdy osiągnięty zostanie maksymalny* czas bezczynności (brak odpowiedzi na próbki).*/

if (tp->t_rxtshift == TCP_MAXRXTSH1FT &&(t p ->t_id1e >= tcp_maxpersistidle || tp->t_idle >= TCP_REXMTVAL(tp) * tcp_totbackoff)) {

t c p s t a t .tcps_persi stdrop++; tp = tcp_drop(tp, ETIMEDOUT); b r e a k ;

)tcp_setpersist(tp); tp->t_force = 1;(v o i d ) tcp_output(tp); tp->t_force = 0; b r e a k :

------------------------------------------------------------------------------------------------- tcpjimer.cRysunek 14.17 Poprawiony kod obsługi próbek trwałości, wprowadzający

ograniczenie czasu

Nowy kod zawiera się w instrukcji i f. Zmienna tcp_maxpersi sti dl e jest nowa i została zainicjowana wartością TCPTV_KEEP_IDLE (14 400 półsekundowych zli­czeń zegara, czyli 2 godziny). Zmienna tcp_totbackoff jest również nowa i ma wartość 511, co jest sumą wszystkich elementów w tablicy tcp_backoff (strona 868 w tomie 2). Wreszcie tcps_persi stdrop to także nowa zmienna w strukturze tcpstat (strony 826-827 w tomie 2), która zlicza porzucone połączenia.

Wartość TCP_MAXRXTSHIFT wynosi 12 i określa maksymalną liczbę retransmisji, gdy TCP czeka na ACK. Po 12 powtórzeniach transmisji połączenie zostaje odrzu­cone, jeśli nic nie zostało otrzymane w ciągu 2 godzin lub w czasie równym 511 razy aktualna wartość RTO dla danego partnera - w zależności od tego, która z tych dwóch wartości jest mniejsza. Na przykład, jeżeli RTO wynosi 2,5 sekundy (5 zliczeń zegara, co jest wartością rozsądną), druga część sprawdzenia OR powo­duje odrzucenie połączenia po 22 minutach (2640 zliczeń zegara), ponieważ 2640 jest większe niż 2555 (5 x 511).

Komentarz w kodzie na rysunku 14.17 nie jest konieczny. W RFC 1122 stwierdza się, że TCP musi utrzymywać połączenie w nieskończoność, nawet jeśli otrzymany rozmiar okna jest 0, „tak długo jak długo odbierający moduł TCP wysyła potwierdzenia w odpo­wiedzi na segmenty próbkujące". Odrzucenie połączenia po dłuższym okresie bez odpo­wiedzi na próbki jest poprawne.

Przedstawiony kod został dodany, żeby sprawdzić jak często opisana sytuacja ma miejsce. Na rysunku 14.18 pokazujemy, jak zmienia się wartość nowego licznika w okresie 5 dni. W badanym systemie pojawiało się 90 odrzuconych połączeń dziennie, czyli prawie 4 takie połączenia na godzinę.

Page 232: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

210 Pakiety znalezione w serwerze HTTP Rozdział 14

wtorekpołudnie

liczbaodrzuconych

środapołudnie

czwartekpołudnie

piątekpołudnie

sobotapołudnie

niedzielapołudnie

czas działania systemu od przeładowania w minutach

Rysunek 14.18 Liczba połączeń odrzuconych po czasie oczekiwania na potwierdzenie próbek trwałości

Przyjrzyjmy się dokładniej jednemu z tych połączeń. Na rysunku 14.19 przedsta­wiamy szczegółowy wydruk z programu Tcpdump.

1 0.02 0.001212 (0.0012)

3 0.364841 (0.3636)

4 0.481275 (0.1164)5 0.546304 (0.0650)6 0.546761 (0.0005)

7 1.393139 (0.8464)8 1.394103 (0.0010)9 1.394587 (0.0005)

10 1.582501 (0.1879)11 1.583139 (0.0006)12 1.583608 (0.0005)13 2.851548 (1.2679)14 2.852214 (0.0007)15 2.852672 (0.0005)

16 3.812675 (0.9600)17 5.257997 (1.4453)

18 10.024936 (4.7669)19 16.035379 (6.0104)20 28.055130 (12.0198)

Client.1464 > serv.80: sery.80 > client.1464:

Client.1464 serv.80:

Client.1464 > serv.80 serv.80 > client.1464 serv.80 > client.1464

client.1464 > serv.80 serv.80 > client.1464 serv.80 > client.1464

client.1464 > serv.80 serv.80 > client.1464 serv.80 > client.1464 client.1464 > serv.80 serv.80 > client.1464 serv.80 > client.1464

Client.1464 > serv.80 Client.1464 > serv.80

serv.80 > client.1464 serv.80 > client.1464 serv.80 > client.1464

S 0:0(0) win 4096 <mss 1396>S 323930113:323930113(0)

ack 1 win 4096 <mss 512>P ack 1 win 4096

P 1:183(182) ack 1 win 4096 . 1:513(512) ack 183 win 4096 P 513:1025(512) ack 183 win 4096

FP 183:183(0) ack 513 win 3584 . 1025:1537(512) ack 184 win 4096. 1537:2049(512) ack 184 win 4096

FP 183:183(0) ack 1025 win 3072 . 2049:2561(512) ack 184 win 4096. 2561:3073(512) ack 184 win 4096P ack 2049 win 2048 . 3073:3585(512) ack 184 win 4096. 3585:4097(512) ack 184 win 4096

P ack 3073 win 1024P ack 4097 win 0

. 4097:4098(1) ack 184 win 4096

. 4097:4098(1) ack 184 win 4096

. 4097:4098(1) ack 184 win 4096

Page 233: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 14.9___________ Ograniczenie czasu sondowania trwałości połączenia 211

21 52.086026 (24.0309) serv.80 > Client.1464: . 4097:4098(1) ack 184 win 409622 100.135380 (48.0494) serv.80 > client.1464: . 4097:4098(1) ack 184 win 409623 160.195529 (60.0601) serv.80 > client.1464: . 4097:4098(1) ack 184 win 409624 220.255059 (60.0595) serv.80 > client.1464: . 4097:4098(1) ack 184 win 4096

wysyłanie próbek trwałości jest kontynuowane

140 7187.603975 (60.0501) serv.80 > client.1464: . 4097:4098(1) ack 184 win 4096141 7247.643905 (60.0399) serv.80 > client.1464: R 4098:4098(0) ack 184 win 4096

Rysunek 14.19 Wydruk Tcpdump: oczekiwanie na potwierdzenie próbek trwałości

W liniach od pierwszej do trzeciej widzimy zwykłe potrójne uzgodnienie protoko­łu TCP. Pojawiają się jednak niepoprawny początkowy numer sekwencyjny (0) i dziwna wartość MSS. Klient wysyła 182-bajtowe żądanie w linii czwartej. Serwer potwierdza żądanie w linii piątej i segment ten zawiera również pierwsze 512 bajtów odpowiedzi. W linii szóstej znajduje się następne 512 bajtów odpowiedzi.

Klient wysyła FIN w linii siódmej, serwer potwierdza FIN i kontynuuje wysyłanie odpowiedzi - następne 1024 bajty - w liniach ósmej i dziewiątej. Klient potwierdza kolejne 512 bajtów odpowiedzi serwera i przesyła ponownie swoją flagę FIN w linii dziesiątej. Linie jedenasta i dwunasta zawierają następne 1024 bajty odpo­wiedzi serwera. Ten sam scenariusz powtarza się w liniach od trzynastej do piętnastej.

Zauważmy, że gdy serwer wysyła dane, informacja klienta o rozmiarze okna w liniach 7,10,13 i 16 zawiera coraz mniejsze wartości, aż w linii 17 osiąga wartość 0. Klient TCP otrzymał łącznie 4096 bajtów odpowiedzi serwera w linii siedemnastej, ale - ponieważ 4096-bajtowy bufor odbiorczy jest wypełniony - klient informuje, że rozmiar okna wynosi 0. Aplikacja klienta nie wczytała żadnych danych z bufora odbiorczego.

Linia osiemnasta jest pierwszą próbką trwałości połączenia, wysłaną przez serwe­ra po około 5 sekundach od zerowej informacji o rozmiarze okna. Próbki trwałości połączenia wysyłane są dalej zgodnie z typowym scenariuszem pokazanym na rysunku 25.14 w tomie 2. Wydaje się, że klient stracił połączenie z Internetem pomiędzy liniami siedemnastą i osiemnastą. Zostaje wysłanych łącznie 124 próbek trwałości w ciągu nieco ponad 2 godzin, po czym serwer w linii 141 rezygnuje i wysyła RST. (Flaga RST zostaje wysłana przez tcp_d rop, strona 930, tom 2.)

Dlaczego, biorąc pod uwagę przedstawione na początku tego podrozdziału wytłumacze­nie drugiej części warunku OR w kodzie źródłowym 4.4BSD-Lite2, próbki trwałości w omówionym przykładzie wysyłane są przez 2 godziny? Kod ograniczenia czasu sprawdzania trwałości połączenia w systemie BSD/OS V2.0, działający w monitorowa­nym komputerze, zawierał jedynie sprawdzenie czy t_idle jest większe lub równe tc p _m ax pe r si st id l e. Druga część warunku OR została w prow adzona dopiero w 4.4BSD-Lite2. W naszym przykładzie możemy zobaczyć, dlaczego dodano drugą część warunku OR: wysyłanie próbek przez 2 godziny nie ma sensu, skoro jest oczywiste, że drugi koniec połączenia zniknął.

Page 234: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

212 Pakiety znalezione w serwerze HTTP Rozdział 14

Powiedzieliśmy, że w systemie odrzucanych było 90 połączeń dziennie, po wy­czerpaniu się czasu oczekiwania na potwierdzenie próbek trwałości. Jeśli próbki takie byłyby wysyłane w nieskończoność, po czterech dniach mielibyśmy 360 takich „zawieszonych" połączeń, wysyłających około 6 niepotrzebnych segmen­tów TCP na sekundę. Dodatkowo - ponieważ serwer HTTP usiłuje przesłać dane w tych połączeniach - w kolejce wysyłkowej oczekują przeznaczone do wysłania bufory mbuf. W opracowaniu [Mogul 1995a] stwierdzono, że „gdy klient przed­wcześnie przerywa połączenia TCP, mogą się ujawnić błędy przyczajonych serwe­rów, które mogą istotnie zmniejszyć sprawność sieci".

W linii siódmej na rysunku 14.19 serwer otrzymuje segment FIN od klienta. N a skutek tego połączenie po stronie serwera zostaje wprowadzone w stan CLOSE_WAIT. Choć nie możemy tego stwierdzić na podstawie wydruku Tcpdump, wiemy, że serwer w pewnym momencie analizowanego okresu wywo­łał cl ose, wprowadzając połączenie w stan LAST_ACK. Rzeczywiście, większość zawieszonych połączeń wysyłających próbki trwałości jest w stanie LAST_ACK.

W czasie gdy opisany tu problem gniazd zawieszonych w stanie LAST_ACK był dyskutowany po raz pierwszy na początku 1995 roku w ramach listy dyskusyjnej Usenet, zaproponowano między innymi, by do wykrywania znikających klientów i zakańczania takich połączeń została wykorzystana opcja źródła SO_KEEPALI VE. (W rozdziale 23 w tomie 1 przedyskutowano, jak działa ta opcja, a w rozdziale 25.6 tomu 2 przedstawiono szczegóły implementacji tej opcji.) Niestety, w ten sposób problem nie zostaje rozwiązany. Na stronie 860 w tomie 2 opcja „keepalive" nie kończy połączenia w stanach FIN_WAIT_1, FIN_WAIT_2, CLOSING lub LAST_ACK. Niektórzy dostawcy systemów podobno zmienili tę właściwość opcji.

14.10 Symulacja rozmiaru tablicy rutowania T/TCPHost, dla którego zaimplementowano T/TCP, tworzy wpis w tablicy rutowania dla każdego hosta, z którym nawiązuje połączenie (rozdział 6). Większość hostów przechowuje obecnie w tablicy rutowania najczęściej tylko marszrutę domyślną i być może najwyżej kilka marszrut do konkretnych hostów, tak więc implementa­cja T/TC P może potencjalnie utworzyć tablicę rutowania znacznie większą od normalnej. Użyjemy danych z serwera HTTP, aby zasymulować tablicę rutowania T/TC P i sprawdzimy, jak rozmiar tej tablicy zmienia się w czasie.

Nasza symulacja jest prosta. Używamy danych zebranych w okresie 24-godzin- nym do stworzenia tablicy rutowania dla każdego z 5386 różnych adresów IP, odpowiadających hostom łączącym się serwerami WWW w danym komputerze. Każdy wpis pozostaje w tablicy rutowania przez określony czas po jego użyciu. Symulację wykonamy dla czasu utraty ważności wpisu równego 30 minut, 60 minut i 2 godziny. Tablica rutowania jest przeglądana co 10 minut i wszystkie wpisy starsze niż zadany okres ważności są kasowane (podobnie do działania funkcji in_rtqtimo w rozdziale 6.10) oraz zliczane są te wpisy, które pozostają

Page 235: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 14.10 Symulacja rozmiaru tablicy rutowania T/TCP 213

w tablicy rutowania. Liczba pozostających wpisów pokazana została na rysunku 14.20.

Rysunek 14.20 Symulacja tablicy rutowania T/TCP: liczba wpisów w funkcji czasu

W ćwiczeniu 18.2 w tomie 2 wspomnieliśmy, że każdy wpis w tablicy rutowania w kodzie N et/3 zajmuje 152 bajty. W przypadku T/TC P rozmiar wpisu zwiększa się do 168 bajtów, gdyż zostaje dodanych 16 bajtów struktury r t_metr i cs (roz- ’ dział 6.5) używanych przez pamięć TAO. W istocie zasady alokowania pamięci systemu BSD powodują, że zajętych zostaje 256 bajtów. Dla najdłuższego czasu utraty ważności równego 2 godziny liczba wpisów osiąga niemal 1000, co odpo­wiada prawie 256 000 bajtom. Zmniejszenie okresu ważności wpisu do połowy zmniejsza zajętą pamięć mniej więcej dwukrotnie.

Przy czasie utraty ważności równym 30 minut tablica rutowania zawiera maksy­malnie 300 wpisów, przy 5386 różnych hostach łączących się z tym serwerem. Jest to całkowicie akceptowalny rozmiar tablicy rutowania.

Ponowne użycie wpisu w tablicy rutowaniaRysunek 14.20 informuje nas, jak duża staje się tablica rutowania przy różnych czasach utraty ważności oraz pokazuje, jak często wpisy przechowywane w tabeli są ponownie używane. Nie ma sensu przecież przechowywać wpisów, które bardzo rzadko są ponownie używane.

Page 236: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

214 Pakiety znalezione w serwerze HTTP Rozdział 14

Przyglądamy się 686 755 pakietom w 24-godzinnym zbiorze danych i szukamy segmentów SYN klientów, które pojawiają się przynajmniej 10 minut po otrzyma­niu ostatniego pakietu od danego klienta. Na rysunku 14.21 pokazany jest wykres liczby hostów w funkcji czasu braku aktywności w minutach. Na przykład 683 hosty (spośród 5386 klientów) wysyłają nowy segment SYN po czasie braku aktywności równym 10 lub więcej minut. Ta liczba zmniejsza się do 669 hostów dla czasu braku aktywności 11 lub więcej minut i do 367 hostów dla czasu braku aktywności 120 lub więcej minut.

Rysunek 14.21 Liczba hostów wysyłających SYN po pewnym okresie braku aktywności

Jeżeli przyjrzymy się nazwom hostów odpowiadającym adresom IP pojawiającym się powtórnie po pewnym okresie braku aktywności, wiele z nich ma formę wwwproxyl, webgatel, proxy, gateway i podobne, co oznacza, że są to serwery pośredniczące (proxy) odpowiednich instytucji.

14.11 Współdziałanie z buforami mbufInteresujące spostrzeżenie zostało poczynione przy okazji obserwowania za po­mocą programu Tcpdump wymian pakietów HTTP. Jeżeli aplikacja wpisuje od 101 do 208 bajtów, 4.4BSD dzieli dane na dwa bufory mbuf - pierwszy zawiera 100 bajtów, drugi pozostałe 1-108 bajtów - co powoduje wysłanie dwóch segmentów TCP, nawet jeśli wartość MSS jest większa niż 208 (co zwykle ma miejsce). Przy­czyna tej anomalii zawarta jest w funkcji sosend (strony 514-516 tomu 2). Ponieważ TCP nie jest protokołem niepodzielnym (atomie protocol), za każdym

Page 237: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 14.12 Blok protokołu TCP i przewidywanie nagłówka 215

razem gdy bufor mbuf zostaje wypełniony, wywoływana jest funkcja wyjścia protokołu.

Co gorsza, ponieważ żądanie klienta zawarte jest teraz w więcej niż jednym segmencie, połączenie uruchamiane jest w trybie powolnym (powolny start). Klient zanim wyśle drugi segment - wymaga, by serwer potwierdził pierwszy segment. Całkowity czas przesłania żądania zostaje więc zwiększony o wartość RTT.

Bardzo wiele żądań HTTP ma rozmiar od 101 do 208 bajtów. Rzeczywiście, wszystkie żądania wysłane w przykładzie w rozdziale 13.4 miały wielkość od 152 do 197 bajtów. Dzieje się tak dlatego, że żądanie klienta ma w zasadzie ustalony format, w którym jedynie URL zmienia się pomiędzy poszczególnymi żądaniami.

Problem może być usunięty w łatwy sposób (jeżeli mamy kod źródłowy jądra systemu). Wartość stałej MINC LSI ZE (strona 41 w tomie 2) powinna zostać zmie­niona ze 101 na 208. Wprowadzenie tej zmiany usuwa też maksimum widoczne w punkcie odpowiadającym 200 bajtom na rysunku A.6 i A.7.

Klient z rysunku 14.22 zawiera tę zmianę. Bez tej zmiany pierwszy segment klienta zawierałby 100 bajtów danych, następnie klient czekałby przez czas równy RTT na potwierdzenie pierwszego segmentu (powolny start) i po otrzymaniu potwierdze­nia wysłałby pozostałe 52 bajty. Dopiero wtedy serwer wysłałby pierwszy seg­ment odpowiedzi.

Istnieją alternatywne sposoby usunięcia problemu. Po pierwsze, rozmiar mbuf mógłby zostać zwiększony ze 128 do 256 bajtów. W niektórych systemach wywodzących się z systemu Berkeley wprowadzono właśnie tę modyfikację (na przykład A I X ). Po drugie, można by zmodyfikować funkcję sosend, tak by wyjście TCP nie było uruchamiane wielokrotnie, kiedy używane są struktury mbuf (a nie klastry mbuf).

14.12 Blok protokołu TCP i przewidywanie nagłówkaGdy TCP w kodzie Net /3 otrzymuje segment, TCP zachowuje wskaźnik do odpo­wiedniego internetowego bloku (wskaźnik tcp_l ast_i npcb do struktury i npcb na stronie 967 w tomie 2) mając nadzieję, że następny otrzymany segment mo­że należeć do tego samego połączenia. W ten sposób omijane jest kosztowne przeszukiwanie powiązanej listy bloków protokołu TCP. Za każdym razem, gdy następny segment należy do innego połączenia, inkrementowany jest licznik tcps_pcbcachemi ss. W przykładowym zestawie danych statystycznych ze stro­ny 827 w tomie 2 niemal w 80% przypadków segment należał do tego samego połączenia. System, na którym zostały zebrane te dane, był jednak systemem ogólnego przeznaczenia wykonującym wiele funkcji jednocześnie, a nie serwerem HTTP.

Wejście TCP wykonuje również przewidywanie nagłówka (rozdział 28.4 w tomie 2), gdy kolejny otrzymany segment w danym połączeniu jest następnym spodziewa­nym potwierdzeniem (strona wysyłająca dane) lub następnym spodziewanym segmentem danych (strona odbierająca dane).

Page 238: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

216 Pakiety znalezione w serwerze HTTP Rozdział 14

server.80

0,0

0,441223 (0,4412) 0,442067 (0,0008) 0,579457 (0,1374)

1,101392 (0,5219)

1,241115(0,1397) 1,249376 (0,0083)

1,681472 (0,4321)

1,821249 (0,1398) 1,853057 (0,0318)

1,960825 (0,1078) 2,048981 (0,0882)

2,251285 (0,2023)

2,362975 (0,1117) 2,369026 (0,0061)

2,693247 (0,3242)

2,957395(0,2641)

3,220193 (0,2628)

FIN,

j c k 2049, win Mr.A

,0 4 9:2561(512) aę! l l 5 V ^ 09^

ack 2561, winSflcw

2̂561_̂ 3073̂ 12)_aęK_153i_wn_̂ 2B5—

PSH 3073^3420^347)_ackJ531_wl!Li555—

^ L ^ i l w i n S 0 3 2 ^

jd (3 4 2 1 , w in flia?

3421, win 8192

ack15V «in409 5_

13

14

18

Rysunek 14.22 Transakcje klient-serwer HTTP

Dla serwera HTTP omawianego w tym rozdziale stwierdzono, że:

• w 20% przypadków mógł być użyty przechowywany wskaźnik do (segment należał do tego samego połączenia) (18-20%)

• w 15% przypadków przewidywanie nagłówka było poprawne dla następnego potwierdzenia (14-15%)

• w 30% przypadków przewidywanie nagłówka było poprawne dla następnego segmentu danych (20-35%).

Page 239: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 14.12 Blok protokołu TCP i przewidywanie nagłówka 217

Wszystkie trzy wartości są niskie. Wartości te zmieniały się nieznacznie w pomia­rach wykonywanych co godzinę przez okres 2 dni. Minimalne i maksymalne wartości podano w nawiasach.

Pierwsza z podanych wartości jest niska, ale nie może to dziwić, biorąc pod uwagę dużą liczbę klientów używających jednocześnie TCP dla silnie zajętego serwera HTTP. Niska wartość „trafień" wynika z faktu, że HTTP to w istocie protokół transakcyjny, a pokazano [McKenney i Dove 1992], że efektywność wykorzystania przechowywanego wskaźnika w N et/3 dla protokołu transakcyjnego jest niska.

Serwer HTTP zwykle wysyła więcej danych niż otrzymuje. Na rysunku 14.22 przedstawione są zależności czasowe dla pierwszego żądania klienta z rysunku13.5 (port klienta 1114). Żądanie klienta jest wysłane w segmencie 4, a odpowiedź serwera w segmentach 5, 6, 8, 9, 11, 13 i 14. Istnieje tylko jedna potencjalna możliwość wykonania przewidywania „następne dane" dla serwera - segment 4. Przewidywanie serwera „następne potwierdzenie" jest potencjalnie możliwe dla segmentów 7, 10, 12, 15 i 16. (Połączenie nie jest nawiązane, gdy przychodzi segment 3, a flaga FIN w segmencie 17 wyklucza przewidywanie dla tego segmen­tu.) To, czy w istocie któryś z tych segmentów ACK kwalifikuje się do przewidy­wania nagłówka, zależy od zgłoszonej informaq'i o rozmiarze okna, co z kolei zależy od sposobu, w jaki klient HTTP czyta dane przesłane przez serwera i od tego, kiedy klient wysyła ACK. W segmencie 7, na przykład, TCP potwierdza 1024 bajty otrzymane przez serwera, ale aplikacja klienta HTTP przeczytała tylko 260 bajtów z buforu gniazda (1024 - 8192 + 7428).

To potwierdzenie z dziwną informaq'ą o rozmiarze okna jest opóźnionym potwierdze­niem, wysłanym gdy upływa 200-milisekundowy okres oczekiwania TCP. Różnica czasu między segmentami 7 i 12 - oba te segmenty są opóźnionymi potwierdzeniami - wynosi 799 ms, co odpowiada czterem 200-milisekundowym zegarowym przerwaniom TCP. Właśnie ta różnica czasu świadczy o tym, że oba segmenty są opóźnionymi potwierdze­niami wysłanymi w związku z przerwaniem zegarowym, a nie w wyniku odczytania innego fragmentu danych z bufora gniazda. Wydaje się, że segment 10 jest również opóźnionym potwierdzeniem, ponieważ czas pomiędzy segmentami 7 i 10 wynosi 603 ms.

Segment ACK z mniejszą wartością informacji o rozmiarze okna uniemożliwia przewidywanie nagłówka na drugim końcu połączenia, ponieważ przewidywa­nie nagłówka jest wykonywane, tylko jeżeli otrzymany rozmiar okna jest równy rozmiarowi aktualnego okna wysyłkowego.

Podsumowując, nie jesteśmy zdziwieni niską efektywnością kodu przewidywania nagłówka w serwerze HTTP. Przewidywanie nagłówka działa najlepiej dla połą­czeń TCP, w których wymieniane są duże ilości danych. Ponieważ statystyka przewidywania nagłówka jest obliczana wspólnie dla wszystkich połączeń TCP, możemy jedynie domniemywać, że większa procentowa efektywność przewidy­wań typu „następne dane" (porównując z przewidywaniami typu „następne po­twierdzenie") pochodzi od bardzo długich połączeń NNTP (rysunek 15.3), w ra­mach których otrzymywanych jest średnio 13 milionów bajtów na jedno połącze­nie TCP.

Page 240: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

218 Pakiety znalezione w serwerze HTTP R o zd z ia łu

Błąd w trybie powolnego startuZauważmy, że - wbrew oczekiwaniom - serwer na rysunku 14.22 wysyła odpowiedź bez powolnego startu. Spodziewalibyśmy się, że serwer wyśle pierw­szy 512-bajtowy segment, zaczeka na ACK od klienta i następnie wyśle kolejne dwa 512-bajtowe segmenty. Serwer jednak wysyła natychmiast dwa 512-bajtowe segmenty (segmenty 5 i 6), nie czekając na potwierdzenie. Rzeczywiście, ta anoma­lia pojawia się w większości systemów wywodzących się z systemu Berkeley. Jest ona rzadko zauważana, ponieważ w wielu aplikacjach większość danych wysyła klient do serwera. Nawet w przypadku ściągania pliku od serwera przy pomocy FTP, to serwer FTP otwiera połączenie transferu danych, stając się w rzeczywisto­ści klientem tego transferu. (Na stronie 494 w tomie 1 pokazany jest przykład takiej sytuacji.)

Błąd tkwi w funkcji tcp_i nput. Nowe połączenie rozpoczyna się z jednosegmen- towym oknem przeciążenia. Kiedy nawiązywanie połączenia zostaje zakończone po stronie klienta (strony 988-990 w tomie 2), wykonywany jest skok do etykiety step6, omijający przetwarzanie potwierdzenia. Gdy pierwszy segment danych był wysłany przez klienta, okno przeciążenia tego segmentu wynosi jeden seg­ment - i jest to poprawne. Kiedy jednak nawiązywanie połączenia zostaje zakoń­czone po stronie serwera (strona 1011 w tomie 2), kontrola jest przekazana do fragmentu kodu przetwarzającego ACK i okno przeciążenia - w związku z otrzy­manym ACK - zwiększa się o jeden segment (strona 1019, tom 2). Dlatego serwer rozpoczyna od wysłania dwóch podobnych segmentów. Błąd można skorygować włączając kod z rysunku 11.16, bez względu na to, czy implementacja obsługuje T/TCP, czy nie.

Kiedy serwer otrzymuje ACK w segmencie 7, okno przeciążenia serwera zwiększa się do trzech segmentów, ale serwer najwyraźniej wysyła tylko dwa segmenty (8 i 9). Na podstawie rysunku 14.22 nie możemy stwierdzić, czy segmenty 10 i 11 minęły się gdzieś w sieci pomiędzy klientem i serwerem, ponieważ rejestrowali­śmy segmenty tylko na jednym końcu połączenia (uruchamiając Tcpdump w komputerze klienta). Jeśli to się w rzeczywistości zdarzyło, to serwer miał trzyseg­mentowe okno przeciążenia, tak jak tego oczekiwaliśmy.

Na podstawie wartości RTT wyznaczanych dla różnych segmentów, możemy domyślać się, że segmenty rzeczywiście minęły się w sieci. Wartość RTT klienta zmierzona dla segmentów 1 i 2 wynosi 441 ms, dla segmentów 4 i 5 - 521 ms, a dla segmentów 7 i 8 - 432 ms. Wartości te są sensowne i używając programu Ping w komputerze klienta otrzymujemy RTT dla tego serwera równe 461 ms. Wartość RTT dla segmentów 10 i 11 wynosi jednak dużo mniej: 107 ms.

14.13 PodsumowanieSilnie obciążony serwer WWW stawia wysokie wymagania implementacji TCP/IP. Zobaczyliśmy, że często bardzo dziwne pakiety mogą być otrzymywane od wielu rozmaitych klientów w Internecie.

Page 241: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 14.13 Podsumowanie 219

W obecnym rozdziale przeanalizowaliśmy pakiety zarejestrowane w obciążonymserwerze WWW, zwracając uwagę na kilka różnych właściwości implementacji.Poczyniliśmy następujące spostrzeżenia:

• Maksymalna częstotliwość otrzymywania segmentów SYN od klientów może przekroczyć wartość średnią o czynnik 8 (pomijamy patologicznie zachowują­cych się klientów).

• Wartość średnia RTT pomiędzy klientem i serwerem wynosi 445 ms, a mediana rozkładu RTT jest równa 187 ms.

• Kolejka niekompletnych żądań połączeń może łatwo zostać przepełniona przy typowych wartościach limitu przepełnienia równych 5 lub 10. Problem polega nie na tym, że proces serwera jest zbyt zajęty, ale na tym, że segmenty SYN klientów pozostają w tej kolejce przez czas RTT. Wartości limitu przepełnienia dla obciążonych serwerów WWW muszą być więc dużo większe. Powinien również istnieć w jądrze systemu licznik przepełnień tej kolejki, tak by admini­strator systemu mógł stwierdzić, jak często kolejka ulega przepełnieniu.

• System musi mieć możliwość odrzucania połączeń zawieszonych w stanie LAST_ACK i wysyłających próbki trwałości połączenia. Takie zawieszone po­łączenia pojawiają się często.

• W wielu systemach wywodzących się z systemu Berkeley, żądania o rozmiarze od 101 do 208 bajtów źle współdziałają z buforami mbuf (jest to typowy rozmiar żądania dla wielu klientów).

• Zasada zachowywania wskaźnika do bloku stosowana w wielu systemach wywodzących się z systemu Berkeley oraz przewidywania nagłówka stosowa­ne w większości systemów nie mają większego znaczenia w przypadku obcią­żonego serwera WWW.

• Podobna analiza innego obciążonego serwera WWW przedstawiona została w opracowaniu [Mogul 1995d].

Page 242: Biblia TCP IP Tom 3 - Uzupelnienie.pdf
Page 243: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

NNTP - sieciowy protokół przesyłania informacji15

15.1 WstępNNTP (Network News Transfer Protocol), sieciowy protokół przesyłania informacji, rozprowadza w sieci artykuły informacyjne (news articles) zawierające różnego rodzaju wiadomości. (Żaden z możliwych polskich odpowiedników nie oddaje w pełni znaczenia angielskiego określenia „news", szczególnie w kontekście „news" przesyłanych w sieci Usenet. Przy braku ogólnie przyjętego odpowiednika zde­cydowaliśmy się na na użycie terminu „informacje", zdając sobie sprawę, że takie tłumaczenie może budzić kontrowersje - przyp. tłumacza.) NNTP jest protokołem aplikacyjnym, używającym TCP. Opisany został w RFC 977 [Kantor i Lapsley 1986]. Powszechnie zaimplementowane rozszerzenia protokołu są udokumen­towane w opracowaniu [Barber 1995]. RFC 1036 [Horton i Adams 1987] opisuje zawartość różnych pól nagłówków artykułów informacyjnych.

Informacje sieciowe (network news) zainicjowane zostały przez listy adresowe (mai- ling lists) w sieci ARP ANET, a następnie przekształciły się w system informacji Usenet. Listy adresowe są wciąż szeroko używane, ale biorąc pod uwagę ilość przesyłanych wiadomości, to przede wszystkim informacje sieciowe rozwinęły się znacznie w ciągu ostatniej dekady. Rysunek 13.1 pokazuje, że liczba pakietów przesyłanych przez protokół NNTP jest zbliżona od liczby pakietów poczty elek­tronicznej. W pracy [Paxson 1994a] zauważono, że od roku 1984 ruch w sieci związany z przesyłaniem informacji sieciowych rósł jednostajnie - około 75% rocznie.

Usenet nie jest siecią fizyczną, lecz logiczną, zaimplementowaną na bazie sieci fizycznych różnych typów. Kilka lat temu popularnym sposobem rozpowszech­niania informacji sieciowych było użycie linii telefonicznych (zwykle w godzinach popołudniowych i nocnych, gdy połączenia telefoniczne są tańsze). Obecnie pod­stawą rozpowszechniania informacji sieciowych jest Internet. (Historię Usenet szczegółowo przedstawiono w rozdziale 15 książki [Salus 1995].)

Na rysunku 15.1 schematycznie przedstawiliśmy typowy system rozpowszech­niania informacji sieciowych. Jeden host jest serwerem informacji dla danej insty­tucji i przechowuje wszystkie artykuły informacyjne na dysku. Serwer ten komu­nikuje się z innymi serwerami informacji w Internecie i różne serwery przekazują sobie wzajemnie artykuły informacyjne. Protokół NNTP jest używany do komuni­kacji pomiędzy serwerami. Istnieje wiele rozmaitych implementacji serwerów informacji. Popularnym serwerem unixowym jest INN (InterNetNews).

Page 244: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

222 NNTP - sieciowy protokół przesyłania informacji Rozdział 15

sieć wewnętrzna instytucji

Rysunek 15.1 Schemat typowego systemu informacji sieciowych

Hosty należące do tej samej instytucji kontaktują się z serwerem informaqi, by prze­czytać artykuły informacyjne oraz by nadać artykuły przeznaczone dla wybranych grup informacyjnych (newsgroups). Dla tych hostów używamy określenia „klient informaq'i". Klienci informacji kontaktują się z serwerem informaq'i używając proto­kołu NNTP. Programy pełniące role klienta informacji, kontaktujące się z serwerem informacji w tym samym komputerze, zwykle również używają protokołu NNTP.

Istnieją dziesiątki rozmaitych czytników informacji (klientów) - różnych dla róż­nych systemów operacyjnych używanych w komputerze klienta. Oryginalnym unixowym klientem był program Readnews. Jego następcą jest program Rn i wiele programów pochodnych: Rm to wersja działająca zdalnie, w sytuacji gdy klienti serwer znajdują się w różnych hostach; Tm oznacza „threaded news" (informacje wątkowe) i jest określeniem czytnika potrafiącego śledzić różne wątki dyskusji w ramach jednej grupy informacyjnej; Xm to wersja Rn dla systemu X-windows. GNUS jest popularnym czytnikiem działającym w środowisku edytora Emacs. Powszechne stało się również wyposażanie przeglądarek WWW, takich jak Nets­cape, w interfejs umożliwiający czytanie informacji sieciowych bez wychodzenia z przeglądarki, tak że posiadanie oddzielnego czytnika informacji przestaje być konieczne. Każdy klient informacji posiada inny interfejs użytkownika - przywo-

Page 245: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 15.2 Protokół NNTP 223

łajmy w tym miejscu mnogość różnych interfejsów użytkownika używanych przez rozmaite czytniki poczty elektronicznej.

Bez względu na program klienta, wspólną cechą wszystkich klientów, wiążącą programy klienta z serwerem, jest protokół NNTP i ten to protokół stanowi temat tego rozdziału.

15.2 Protokół NNTPNNTP używa TCP i dobrze-znany port dla serwera NNTP ma numer 119. NNTP jest podobny do innych aplikacji internetowych (HTTP, FTP, SMTP, itd.) - w tym sensie, że klient wysyła do serwera polecenia w formie ciągów znaków ASCII, a serwer odpowiada liczbowym kodem odpowiedzi, po którym opcjonalnie nastę­pują dane ASCII (w zależności od polecenia). Linie poleceń i odpowiedzi są zakończone znakami karetki i końca linii.

Najprostszym sposobem zbadania protokołu jest użycie klienta Telnet i połączenie się z portem NNTP hosta, w którym uruchomiony jest serwer NNTP. Zwykle musi­my jednak połączyć się z hosta-klienta znanego serwerowi, najczęściej znajdującego się w sieci tej samej instytucji. Dla przykładu, jeżeli połączymy się z serwerem przez Internet z hosta w innej sieci, otrzymamy następujący komunikat o błędzie:

vangogh.cs.berkeley.edu °L telnet noao.edu nntpTrying 140.252.1.54... wydruk klienta TelnetuConnected to noao.edu. wydruk klienta TelnetuEscape character is ’A]'. wydruk klienta Telnetu502 You have no permission to talk. Goodbye.Connection closed by foreign host. wydruk klienta Telnetu

Piąta linia na wydruku powyżej, z kodem odpowiedzi 502, pochodzi od serwera NNTP. Gdy połączenie TCP jest nawiązywane serwer NNTP otrzymuje adres IP klienta i porównuje ten adres z listą adresów uprawnionych klientów.

W następnym przykładzie łączymy się z „lokalnego" klienta.

sun.tuc.noao.edu % telnet noao.edu nntp Trying 140.252.1.54.. .Connected to noao.edu.Escape character is ’A] ’.200 noao InterNetNews NNRP server INN 1.4 22-Dec-93 ready (posting ok).

Tym razem kod odpowiedzi jest 200 (polecenie OK) i pozostała część linii zawiera informacje o serwerze. Na końcu tej informacji znajduje się określenie „posting ok", lub „no posting", w zależności od tego, czy klient jest upoważniony do nadawania artykułów, czy nie. (Jest to kontrolowane przez administratora syste­mu i zależy od adresu IP klienta.)

Zauważamy w linii odpowiedzi serwera, że jest to serwer NNRP (Network News Reading Protocol - protokół czytania informaq'i sieciowych), a nie serwer INND (InterNetNews daemon - demon InterNetNews). Okazuje się, że serwer INND akceptuje żądanie połączenia otrzymane od klienta i następnie sprawdza adres IP klienta. Jeżeli adres klienta zostaje zaakceptowany, ale klient nie jest jednym ze znanych dostarczycieli informacji (news feed), zamiast INND uruchamiany jest

Page 246: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

224 NNTP - sieciowy protokół przesyłania informacji_____________ Rozdział 15

serwer NNRP - zgodnie z założeniem, że klient chce czytać informacje, a nie dostarczać informacje do serwera. W ten sposób implementacja może oddzielić serwera dostarczania informacji (news feed server, około 10 000 linii kodu C) od serwera czytania informacji (news reading server; około 5000 linii kodu C).

Znaczenie pierwszej i drugiej cyfry numerycznego kodu odpowiedzi zostało przedstawione na rysunku 15.2. Znaczenie tych kodów jest podobne do znaczenia kodów używanych przez FTP (strona 488, tom 1).

Odpowiedź Opis

1yz Komunikat informacyjny.

2yz Polecenie poprawne.

3yz Polecenie poprawne, jak dotąd. Wyślij pozostałą część polecenia.

4yz Polecenie było poprawne, nie mogto być wykonane z jakiegoś powodu.

5yz Polecenie nie jest zaimplementowane, jest błędne, lub pojawił się poważny błąd w programie.

xOz Połączenie, konfiguracja i komunikaty różnego rodzaju.

x1z Wybór grupy informacyjnej

x2z Wybór artykułu.

x3z Funkcje dystrybucyjne.

x4z Nadawanie.

x8z Niestandardowe rozszerzenia.

x9z Kontrola poprawności i poszukiwanie błędów.

Rysunek 15.2 Znaczenie pierwszej i drugiej cyfry trzycyfrowego kodu odpowiedzi

Pierwszym naszym poleceniem wydanym serwerowi jest help, które powoduje wypisanie wszystkich poleceń znanych serwerowi.

hel p100 Legał commands kodem odpowiedzi jest 100

authinfo user Namelpass Password article [MessagelD|Number] body [MessagelD|Number] dategroup newsgroup head [MessageID|Number] hel p i have 1 astlist [active|newsgroups|distributions|schema]1 istgroup newsgroup mode readernewgroups yymmdd hhmmss ["GMT"] [<distributions>]newnews newsgroups yymmdd hhmmss ["GMT"] [<distributions>]nextpostslavestat [MessagelD|Number] xgtitle [group_pattern] xhdr header [rangę|MessagelD] xover [rangę]xpat header range|MessageID pat [morepat...] xpath xpath MessagelD

Report problems to < [email protected] zawierająca tylko kropkę kończy odpowiedź serwera

Page 247: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 15.2 Protokół NNTP 225

Ponieważ klient nie wie, ile linii będzie zawierała odpowiedź serwera, protokoł wymaga, by serwer zakończył odpowiedź linią zawierającą jedynie kropkę. Jeżeli jakaś linia odpowiedzi zaczyna się od kropki, serwer poprzedza kropkę jeszcze jedną kropką, a klient usuwa dodatkową kropkę po odebraniu linii.

Następne nasze polecenie to 1 i s t, które - jeśli jest wydane bez żadnych argumen­tów - wypisuje nazwy wszystkich grup informacyjnych wraz z numerem ostatnie­go artykułu w grupie, numerem pierwszego artykułu w grupie oraz symbolem „y" lub „m ", w zależności od tego, czy wysyłanie artykułów do danej grupy jest dozwolone i czy grupa jest moderowana.

list215 Newsgroups in form "group high Iow flags". kodem odpowiedzi jest 215 alt.activism 0000113976 13444 y alt.aquaria 0000050114 44782 y

opuszczamy wiele liniic o m p .proto c ol s.tcp-ip 0000043831 41289 y comp.security.announce 0000000141 00117 m

opuszczamy wiele liniirec.skiing.alpine 0000025451 03612 y rec.skiing.nordic 0000007541 01507 y

linia zawierająca tylko kropkę kończy odpowiedź serwera

Tak jak poprzednio, 215 jest kodem odpowiedzi, a nie liczbą grup informacyjnych. W tym przykładzie serwer wypisuje 4238 nazw grup informacyjnych i zostaje przy tym przesłanych 175 833 bajtów od serwera do klienta. Ominęliśmy niemal wszystkie (z wyjątkiem sześciu) linie z nazwami grup. Przesłana lista grup nie jest zwykle uporządkowana alfabetycznie.

ściąganie z serwera takiej listy przez powolną linię telefoniczną często może powodować znaczące opóźnienie przy uruchamianiu klienta informacji siecio­wych. Na przykład, zakładając szybkość przesyłania danych równą 28 800 bitów na sekundę, ściągnięcie listy z przedstawionego przykładu zajmie około 1 minuty. (W rzeczywistości czas zmierzony przy użyciu modemu o podanej szybkości, kompresującego również dane, wyniósł 50 sekund.) W Ethernecie zajmuje to mniej niż 1 sekundę.

Polecenie group powoduje, że wybrana grupa staje się grupą „aktualną" dla danego klienta. Polecenie przedstawione poniżej wybiera grupę c o m p .proto­col s . tcp - i p jako aktualną.

group comp.protocols.tcp-ip211 181 41289 43831 comp.protocols.tcp-ip

Serwer odpowiada kodem 211 (polecenie OK), po którym następuje przybliżona liczba artykułów w grupie (181), numer pierwszego artykułu w grupie (41289), numer ostatniego artykułu w grupie (43831) oraz nazwa grupy. Różnica pomiędzy numerem ostatniego i pierwszego artykułu (43831 - 41289 = 2542) jest często większa niż liczba artykułów (181). Jedną z przyczyn jest to, że niektóre artykuły, w szczególności grupy FAQ (Frequently Asked Questions - często zadawane pyta­nia) mają dłuższy okres ważności (na przykład 1 miesiąc) niż większość artykułów (często kilka dni, w zależności od pojemności dysku serwera). Artykuły mogą być

Page 248: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

226 NNTP - sieciowy protokół przesyłania informacji Rozdział 15

również kasowane wybiórczo, co oczywiście też zmienia liczbę artykułów w gru­pie.

Żądamy teraz, używając polecenia head, by serwer przesłał linie nagłówków jednego wybranego artykułu (o numerze 43814, w tym przykładzie).

head 43814221 43814 <[email protected]> head Path: noao!rstevensFrom: [email protected] (W. Richard Stevens)Ne wsgroups: c o m p .protocol s .tcp - i p Subject: Re: IP Mapper: Using RAW sockets?Date: 4 Aug 1995 19:14:54 GMTOrga ni z at io n: National Optical Astronomy Observatories. Tucson, AZ, USA Lines: 29Message-ID: <[email protected]>Re ferences: <[email protected]>NNTP-Posting-Host: gemini .tuc.noao.edu

Pierwsza linia odpowiedzi zaczyna się kodem 221 (polecenie OK), po której nastę­puje 10 linii nagłówka i linia zawierająca tylko kropkę.

Większość pól nagłówka nie wymaga wyjaśnień, ale zagadkowy wygląd mają identyfika­tory komunikatów. INN usiłuje wygenerować jednoznaczny identyfikator komunika tu w następującym formacie: aktualny czas, znak dolara, identyfikator procesu , znak „at" (tzw. małpa) i pełna nazwa lokalnego hosta. Czas i identyfikator procesu są wartościami liczbowymi zapisanymi w kodzie radix-32: wartość liczbowa jest zamieniona na 5-bitowy symbol i każdy taki symbol drukowany jest przy użyciu znaków alfabetu: 0...9a...v.

Następnie podajemy polecenie body z tym samym numerem artykułu, co powo­duje przesłanie treści artykułu.

body 43814222 43814 <3vtrje$o t e@ no a o.edu> body> My group is looking at implementing an IP address mapper on a UNIX

28 linii artykułu zostało opuszczonych

Linie nagłówka wraz z treścią artykułu mogą być ściągnięte przy pomocy jednej komendy, a rti cl e, ale większość klientów informacji ściąga najpierw nagłówki, dając użytkownikowi okazję do wybrania artykułów na podstawie ich tematów (subject), a następnie ściągnięta zostaje treść tylko tych artykułów, które zostały wybrane przez użytkownika.

Połączenie z serwerem zakańczamy przy pomocy polecenia qui t.

qui t205Connection closed by foreign host.

Odpowiedzią serwera jest kod liczbowy 205. Nasz klient Telnet informuje, że serwer zamknął połączenie.

Cały przedstawiony dialog między klientem i serwerem odbywał się przy użyciu jednego zainicjowanego przez klienta połączenia TCP. Większość danych przesy­łanych jest jednak od serwera do klienta. Czas trwania połączenia oraz ilość przesłanych danych zależy od tego, jak długo użytkownik czyta informacje.

Page 249: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 15.3 Prosty klient informacji 227

15.3 Prosty klient informacjiObserwujemy teraz wymianę poleceń NNTP i odpowiedzi w czasie krótkiej sesji, używając przy tym prostego klienta informacji - Rn. Rn to jeden z najstarszych czytników informacji. Wybraliśmy ten program, ponieważ jest on prosty do obser­wacji i ponieważ posiada opcję śledzenia działania programu - debug (opcja linii polecenia -Dl6 , zakładając że klient był skompilowany z opcją umożliwiającą śledzenie działania programu). Dzięki temu możemy obserwować wydane pole­cenia NNTP jednocześnie z odpowiedziami serwera. Polecenia klienta oznaczamy pogrubionym drukiem.

1. Pierwszym poleceniem jest l i s t , które - jak widzieliśmy w poprzednim pod­rozdziale - spowodowało wysłanie przez serwera około 175 000 bajtów; jedna linia dla każdej grupy informacyjnej.

Rn przechowuje w pliku .newsrc (w macierzystym katalogu użytkownika) spis grup informacyjnych, które użytkownik chce czytać, wraz z listą numerów przeczytanych artykułów. Na przykład jedna linia pliku .newsrc zawiera:

comp.protocols.tcp-i p: 1-43015

Porównując zapisany w pliku numer ostatniego artykułu z danej grupy z numerem ostatniego artykułu podanym przez polecenie list, klient stwier­dza, czy dana grupa zawiera nieczytane artykuły.

2. Następnie klient sprawdza, czy zostały stworzone jakieś nowe grupy informa­cyjne.

NEWSGROUPS 950803 192708 GMT231 New newsgroups fol Iow. 231 jest kodem odpowiedzi

W pliku . rnl ast w katalogu macierzystym użytkownika Rn zapisuje czas, w którym otrzymał ostatnią informację o nowej grupie informacyjnej. Ten czas zostaje podany jako argument polecenia newsgroups. (Warto zaznaczyć, że duże i małe litery nie są rozróżniane w poleceniach NNTP i w argumentach tych poleceń.) W naszym przykładzie w pliku . rnl ast zapisany był czas: August 3,1995,19:27:08 GMT. Odpowiedź serwera jest pusta (nie ma żadnych linii między linią z kodem odpowiedzi 231, a linią zawierającą jedynie kropkę), co oznacza, że nie ma nowych grup informacyjnych. Gdyby pojawiły się nowe grupy, klient mógłby zapytać użytkownika, czy należy się zapisać do grupy, czy nie.

3. Rn wyświetla następnie liczbę nieczytanych artykułów w pięciu pierwszych grupach i pyta, czy chcemy czytać artykuły z pierwszej grupy, comp.proto- cols.tcp-ip. Odpowiadamy znakiem równości, co powoduje wyświetlenie przez Rn jednoliniowego podsumowania wszystkich artykułów w grupie. Ma­my wtedy szansę wybrać artykuły, które chcemy przeczytać. (Możemy określić konfigurację Rn w pliku . rn i n i t, tak by w podsumowaniu wyświetlane były dowolnie wybrane informacje dla każdego artykułu. W konfiguracji przyjętej przez autora wyświetlane są: numer artykułu, temat, liczba linii w artykule

Page 250: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

228 NNTP - sieciowy protokół przesyłania informacji_____________Rozdział 15

i nadawca artykułu.) Rn wydaje polecenie group i grupa zostaje uznana za grupę aktualną.

GROUP comp.protocols.tcp-ip211 182 41289 43832 comp.protocols.tcp-ip

Zostają ściągnięte nagłówek i treść pierwszego nieczytanego artykułu:

ARTICLE 43815220 43815 <3vtq8o$5pl@newsf1a s h .co ncordia.ca> article

artykuł nie jest pokazany

Jednoliniowe podsumowanie pierwszego nieczytanego artykułu jest wyświet­lane na ekranie.

4. Zostaje wydane polecenie x h d r, a następnie h e a d dla każdego z 17 pozostałych nieczytanych artykułów w tej grupie informacyjnej. Na przykład:

XHDR subject 43816221 subject fields follow43816 Re: RIP-2 and messy sub-nets

HEAD 43816221 43816 <[email protected] head

14 linii nagłówków nie zostało pokazanych

Polecenie xhdr może zaakceptować nie tylko pojedynczy numer artykułu, ale również zakres numerów artykułów i dlatego odpowiedź serwera składa się ze zmiennej liczby linii i jest zakończona linią zawierającą tylko kropkę. Jednoli­niowe podsumowanie każdego artykułu wyświetlane jest na ekranie.

5. Wciskamy klawisz spacji, wybierając w ten sposób pierwszy nieczytany arty­kuł. Wydane zostaje polecenie head, po którym następuje polecenie a rti cl e. Artykuł zostaje wyświetlony na ekranie. Przy przechodzeniu do kolejnych artykułów powtarzana jest sekwencja tych dwóch poleceń.

6. Po zakończeniu czytania artykułów z aktualnej grupy i przejściu do następnej zostaje wysłane przez klienta kolejne polecenie group. Żądamy wyświetlenia jednoliniowego podsumowania wszystkich nieczytanych artykułów i opisana przed chwilą sekwencja poleceń zostaje powtórzona dla nowej grupy.

Pierwszą rzeczą, którą zauważamy jest .to, że klient Rn wydaje zbyt wiele poleceń. Na przykład, chcąc otrzymać jednoliniowe podsumowanie wszystkich nieczyta­nych artykułów, Rn wydaje polecenia xhd r - by ściągnąć temat artykułu, a następ­nie head - by ściągnąć cały nagłówek. Pierwsze z tych dwóch poleceń mogłoby być pominięte. Pewnym wytłumaczeniem takich nadliczbowych poleceń jest fakt, że klient ten został oryginalnie napisany z myślą o pracy w komputerze, który był jednocześnie serwerem informacji, bez potrzeby używania NNTP. Tak więc do­datkowe komendy były „szybkie", nie wymagały przesłania pakietów w obie strony. Możliwość zdalnej współpracy z serwerem przy użyciu NNTP została opracowana później.

Page 251: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 15.4 Bardziej skomplikowany klient informacji 229

15.4 Bardziej skomplikowany klient informacjiPrzyjrzyjmy się teraz bardziej skomplikowanemu klientowi informacji, przeglą­darce WWW Netscape w wersji 1.1N, która posiada wbudowany czytnik informa­cji. Ten klient nie ma opcji śledzenia działania programu, więc - by stwierdzić, jakie czynności są wykonywane - śledziliśmy pakiety TCP wymieniane pomiędzy przeglądarką a serwerem informacji.

1. Gdy uruchamiamy klienta i wybieramy funkcję czytania informacji siecio­wych, klient czyta nasz plik . n ew s r c i pyta serwera tylko o grupy informacyj­ne, które prenumerujemy. By określić początkowe i końcowe numery artyku­łów, dla każdej takiej grupy wydane zostaje polecenie group. Numery te są porównywane z numerem ostatniego czytanego artykułu w pliku .newsrc. W naszym przykładzie autor zaprenumerował tylko 77 spośród ponad 4000 grup informacyjnych, polecenie group wysłane jest więc do serwera 77 razy. Zajmuje to tylko 23 sekundy w połączeniu przez linię telefoniczną z PPP, co można porównać z 50 sekundami potrzebnymi na wykonanie polecenia l i s t używanego przez Rn.

Zmniejszenie liczby grup z 4000 do 77 powinno znacznie bardziej zredukować czas wykonania poleceń niż do 23 sekund. Rzeczywiście, wysłanie tych samych 77 poleceń g r o u p do serwera używając funkcji s o c k (dodatek C tomu 1) zajmu­je tylko 3 sekundy. Wydaje się, że przeglądarka jednocześnie z wysyłaniem tych 77 poleceń wykonuje inne czynności inicjujące.

2. Wybieramy jedną grupę zawierającą nieczytane artykuły, comp. p r o t o ­

col s . tcp - i p. Wydane zostają następujące dwa polecenia:

group comp.protocols.tcp-ip211 181 41289 43831 comp.protocols.tcp-ip xover 43815-43831224 data follows43815\tping works but netscape is f1aky\troot@PR0BLEM_WITH_INEWS_D0MAIN_FILE (root)\t4 Aug 1995 18:52:08 GMT\t<[email protected] .ca>\t\tl202\tl343816\tRe: help me to select a terminal server\t gv c ne [email protected] et.net (g v c n et )\t 5 Aug 1995 09:35:08 GMT\t<3vve0c$g q 5 @ s e r v .hi net . net>\t<cl_aude. 807 537 607@ba u v 111 \ 1 1503\123

jednoliniowe podsumowanie pozostałych artykułów

Pierwsze polecenie ustanawia aktualną grupę, drugie oznacza żądanie wy­świetlenia podsumowania wyszczególnionych artykułów. Pierwszym nieczy- tanym artykułem jest artykuł 43 815, a ostatnim artykułem w grupie jest 43 831. Jednoliniowe podsumowanie każdego artykułu składa się z: numeru artykułu, tematu, autora, czasu i daty, identyfikatora komunikatu, identyfikatorów ko­munikatów odpowiadających artykułom, do których odnosi się aktualny arty­kuł, liczby bajtów i liczby linii. (Zauważmy, że jednoliniowe podsumowanie każdego artykułu jest długie, przedstawiamy je więc w paru liniach. Zastąpili­śmy również przez symbol \ t znaki tabulacji, oddzielające poszczególne pola, po to by znaki te były widoczne.)

Page 252: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

230 NNTP - sieciowy protokół przesyłania informacji_____________ Rozdział 15

Klient Netscape porządkuje otrzymane podsumowania według tematów i przedstawia listę tematów nieczytanych artykułów wraz z nazwiskiem (na­zwą) autora i liczbą linii. Artykuły i odpowiedzi na te artykuły są zebrane razem, co nazywane jest uporządkowaniem wątkowym (threading), ponieważ ze­brane zostają artykuły omawiające jeden wątek dyskusji.

3. Dla każdego wybranego artykułu zostaje wydane polecenie article i artykuł zostaje wyświetlony.

Widać z tego krótkiego opisu, że klient informacji Netscape optymalizuje czytanie grup informacyjnych na dwa sposoby, zmniejszając czas oczekiwania użytkowni­ka na wyświetlenie żądanych informacji. Po pierwsze, Netscape ściąga tylko gru­py, do których użytkownik jest zapisany, zamiast wykonywać polecenie list. Po drugie, podsumowanie jest dostarczane przy pomocy polecenia xover, zamiast poleceń headixhdr wydawanych dla każdego artykułu w grupie.

15.5 Statystyka NNTPZbadaliśmy typowy sposób użycia NNTP, rejestrując w tym samym komputerze, którego działanie było analizowane w rozdziale 14, wszystkie segmenty SYN, FIN i RST używane przez NNTP. Host ten otrzymuje grupy informacyjne od jednego dostawcy informacji (istnieją zwykle serwery pełniące rolę alternatywnego do­stawcy, ale wszystkie zarejestrowane segmenty pochodziły z jednego źródła) i do­starcza informacje dziesięciu innym hostom. Tylko dwa spośród tych dziesięciu hostów używają NNTP, pozostałych 8 używa UUCP. Tak więc dane zebrane przy pomocy Tcpdumpt zawierają tylko segmenty wysyłane do dwóch hostów NNTP. Tylko niewielka część otrzymywanych informacji jest przekazywana do tych dwóch hostów. Wreszcie, ponieważ host pełni rolę dostawcy usług interneto­wych, wielu klientów czyta informacje traktując naszego hosta jako serwera NNTP. Wszyscy użytkownicy czytający informacje używają NNTP - dotyczy to zarówno procesów uruchamianych w tym samym komputerze, jak i czytników informacji w innych komputerach, zwykle podłączonych przez łącza PPP lub SLIP. Tcpdump uruchomiony został na okres 113 godzin (4,7 doby), podczas których zarejestrowanych zostało 1250 połączeń. Zebrane dane zostały podsumo­wane na rysunku 15.3.

Przede wszystkim zauważamy, że host otrzymuje około 186 milionów bajtów dziennie, co odpowiada 8 milionom bajtów na godzinę. Zauważamy też, że typo­we połączenie NNTP z podstawowym dostawcą informacji trwa przez długi czas- 100 minut, w trakcie których przesyłanych jest 13 milionów bajtów. Po okresie braku aktywności w połączeniu pomiędzy naszym hostem a dostawcą informacji połączenie zostaje zamknięte przez serwera informacji. Połączenie jest później nawiązywane ponownie, w miarę potrzeb.

Page 253: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 15.6 Podsumowanie 231

Przyjmowanie informacji (od jednego hosta)

Wysyłania informacji (do dwóch hostów)

Czytnikiinformacji

Suma

liczba połączeń 67 32 1 151 1 250

liczba odbieranych bajtów (łącznie) 875 345 619 4499 593 731 875 943 849

liczba wysyłanych bajtów (łącznie) 4 071 785 1 194 086 56488 715 61 754 586

całkowity czas trwania (minuty) 6 686 407 21 758 28 851

liczba odbieranych bajtów na jedno połączenie 13 064 860 141 516

liczba wysyłanych bajtów na jedno połączenie 60 773 37 315 49 078

średni czas trwania połączenia 100 13 19

Rysunek 15.3 Statystyka połączeń NNTP jednego hosta zebrana w ciągu 4,7 doby

Typowy czytnik informacji używa połączenia NNTP przez 19 minut, czytając około 50 000 bajtów informacji. Ruch w połączeniach NNTP jest przeważnie jednokierunkowy: od podstawowego dostawcy informacji do serwera i od serwe­ra do czytników informacji.

Różnice pomiędzy poszczególnymi instytucjami i węzłami rozpowszechniania informacji sieciowych - jeśli chodzi o objętość danych przesyłanych przez NNTP - są bardzo duże. Przedstawiona statystyka powinna być traktowana jako przykład- nie ma typowych wartości dla tego rodzaju danych.

15.6 PodsumowanieNNTP jest kolejnym przykładem prostego protokołu używającego TCP. Klient wydaje polecenia ASCII (serwer rozpoznaje około 20 różnych poleceń), a serwer przesyła liczbowy kod odpowiedzi, po którym następuje jedna lub więcej linii odpowiedzi zakończonych jedną linią zawierającą tylko kropkę (jeżeli odpowiedź może mieć zmienną długość). Podobnie jak wiele innych protokołów interneto­wych, protokół NNTP pozostaje niezmieniony od lat, ale klient obsługujący inter­akcyjnego użytkownika zmieniał się bardzo szybko.

Wiele różnic pomiędzy różnymi czytnikami informacji sieciowych związanych jest ze sposobem użycia protokołu przez aplikację. Widzieliśmy różnice pomiędzy klientami Rn i Netscape - czytniki te w inny sposób określają, które artykuły nie były czytane i inaczej ściągają nieczytane artykuły.

NNTP używa jednego połączenia TCP dla całej wymiany pakietów pomiędzy klientem i serwerem. Mamy tu do czynienia z inną sytuacją niż w przypadku HTTP, kiedy do przesłania każdego pliku używane było oddzielne połączenie TCP. Różnica ta wynika między innymi z faktu, że klient NNTP komunikuje się z jednym serwerem, podczas gdy klient HTTP łączy się z wieloma różnymi serwe­rami. Zobaczyliśmy również, że większość danych w połączeniu NNTP jest prze­syłanych jednokierunkowo.

Page 254: Biblia TCP IP Tom 3 - Uzupelnienie.pdf
Page 255: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Protokoły domeny unixowej: wprowadzenie16

16.1 WstępProtokoły domeny unixowej są formą komunikacji międzyprocesowej - IPC (inłer- process communication), dostępną przy pomocy tego samego interfejsu API gniazd co interfejs używany do komunikacji sieciowej. W lewej części rysunku 16.1 przed­stawiono programy klienta oraz serwera napisane z użyciem gniazd i komuniku­jące się w jednym komputerze za pośrednictwem protokołów internetowych. Programy klienta i serwera przedstawione w prawej części rysunku, używają gniazd i protokołów domeny unbcowej.

host host

Rysunek 16.1 Programy klienta oraz serwera używające protokołów internetowych i protokołów domeny unixowej

Gdy klient wysyła dane do serwera używając TCP, dane są najpierw przetwarzane przez wyjście TCP, następnie przez wyjście IP, program obsługi pętli zwrotnej (rozdział 5.4 w tomie 2), gdzie dane są umieszczane w kolejce wejściowej IP, następnie są przetwarzane przez wejście IP, wejście TCP i ostatecznie dochodzą do serwera. Procedura taka działa poprawnie i nie ma to znaczenia, że klient i serwer znajdują się w jednym komputerze. Pojawiające się przy opisanym postępowaniu intensywne przetwarzanie w stosie protokołu TCP/IP nie jest jednak niezbędne, gdyż dane nigdy nie opuszczają jednego komputera.

Page 256: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

234 Protokoły domeny unixowej: wprowadzenie Rozdział 16

Protokoły domeny unixowej wykonują mniej czynności (to znaczy są szybsze), ponieważ wiadomo, że dane nie opuszczają komputera. Nie ma konieczności obliczania sumy kontrolnej, nie istnieje możliwość, żeby dane zostały otrzymane w nieprawidłowej kolejności, kontrola przepływu danych jest uproszczona, ponie­waż jądro może kontrolować działanie obu procesów, itd. Choć inne formy IPC (kolejki komunikatów - message queues, pamięć wspólna - shared memory, potoki z nazwami - named pipes, itd.) mają podobne cechy, główną zaletą protokołów unbcowych jest to, że używają one tego samego co aplikacje sieciowe interfejsu gniazd: klient wywołuje connect, serwer wywołuje l i s t e n i a c c e p t , klient i ser­wer używają readiwrite, itd. Inne formy IPC używają zupełnie innych interfej­sów API, niektóre z tych interfejsów nie współdziałają dobrze z gniazdami i inny­mi formami I/O (na przykład nie możemy używać funkcji sel e c t z kolejkami komunikatów w Systemie V).

Niektóre implementacje TC P/IP usiłują poprawić sprawność działania przez w prow a­dzenie różnego rodzaju optymalizaji, takich jak ominięcie obliczania i sprawdzania sumy kontrolnej TCP, gdy pakiety przeznaczone są dla interfejsu pętli zwrotnej.

Protokoły domeny unixowej udostępniają zarówno gniazdo strumieniowe (stream socket - S O C K _ S T R E A M - podobne do strumienia bajtów w TCP), jak i gniazdo datagramów (datagram socket - SOCK _ D G R A M - podobne do datagramów UDP). Rodziną adresową (address family) dla gniazda domeny unixowej jest AF_U NIX. Nazwy używane do identyfikacji gniazd domeny unixowej mają formę nazw ścieżek w systemie plików. (Protokoły internetowe do identyfikacji gniazd TCP i UDP używają kombinacji adresu IP i numeru portu.)

W standardzie IEEE POSIX 1003.1 g , rozwijanym na potrzeby programowania sieciowych interfejsów API, uwzględniono obsługę protokołów domeny unixowej pod nazwą „local IPC". Rodziną adresową jest AF_L0CAL, rodziną protokołów jest PF_L0CAL. Termin „Unix" określający te protokoły może stracić aktualność.

Protokoły domeny unixowej mogą również stworzyć możliwości nie istniejące w IPC pomiędzy różnymi maszynami. Przykładem takiej możliwości jest przeka­zywanie deskryptorów pomiędzy niezwiązanymi procesami poprzez gniazdo do­meny unixowej, co opisujemy w rozdziale 18.

16.2 ZastosowaniaLista aplikacji używających protokołów domeny unixowej jest długa:

1. Potoki (pipes). W jądrach wywodzących się z systemu Berkeley potoki są zaim­plementowane przy pomocy strumieniowych gniazd domeny unixowej. W rozdziale 17.3 omawiamy implementację odwołania systemowego pi pe.

2. X Window System. Klient X II wybiera protokół w momencie, gdy łączy się z serwerem X II, w zależności od wartości zmiennej systemowej D ISPLAY lub wartości argumentu linii polecenia -display. Wartość ta ma formę hostna- me:display.screen, gdzie nazwa hosta (hostname) jest opcjonalna, wartość domy­

Page 257: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 16.3 Szybkość działania 235

ślna to aktualny, lokalny host, a użyty protokół to najbardziej efektywna forma komunikacji. Dla lokalnego klienta zwykle wybierany jest strumieniowy proto­kół domeny unixowej. Wartość un i x wymusza użycie protokołu domeny uni- xowej. Nazwa związana z gniazdem unixowym ma postać zbliżoną do/tmp/.Xll-unix/XO.

Ponieważ serwer X zwykle obsługuje jednocześnie klientów podłączonych przez sieć i klientów w tym samym komputerze, serwer oczekuje na żądania połączeń pojawiające się w gniazdach TCP oraz w unixowych gniazdach stru­mieniowych.

3. Programy odpowiedzialne za drukowanie (print spooler) w systemie BSD (klient 1 pr i serwer 1 pd, opisane szczegółowo w rozdziale 13 książki [Stevens 1990]) komunikują się w ramach jednego hosta używając gniazda domeny unbcowej zwanego /dev/lp. Podobnie jak serwer X, serwer lpd obsługuje połączenia z klientami w tym samym komputerze używając gniazda u rn o w e­go, a połączenia z klientami sieciowymi - używając gniazda TCP.

4. Programy rejestracji zdarzeń systemowych (system logger) - funkcja bibliotecz­na sysl og, która może być wywołana przez dowolną aplikację, oraz serwer sysl ogd - komunikują się lokalnie używając datagramowego gniazda domen unixowych o nazwie / dev/1 og. Klient wpisuje komunikat do tego gniazda, a serwer czyta i przetwarza ten komunikat. Serwer obsługuje również, używa­jąc gniazda UDP, komunikaty od klientów w innych hostach. Więcej szczegó­łów na ten temat można znaleźć w rozdziale 13.4.2 książki [Stevens 1992],

5. Demon InterNetNews (i nnd) tworzy unixowe gniazdo datagramowe, w któ­rym czyta komunikaty kontrolne, oraz unixowe gniazdo strumieniowe, w któ­rym czyta artykuły z lokalnego serwera informacji. Gniazda te zwane są cont roi oraz nntpi n i znajdują się zwykle w katalogu /va r/news/run.

Powyższa lista nie jest kompletna: istnieją inne aplikacje używające gniazd dome­ny unbcowej.

16.3 Szybkość działaniaInteresujące będzie porównanie szybkości działania gniazd domeny unbcowej i gniazd TCP. Jedna z wersji publicznie rozpowszechnianego programu ttcp zo­stała zmodyfikowana, tak by oprócz gniazd TCP i UDP było używane strumienio­we gniazdo domeny unbcowej. Przesyłamy 16 777 216 bajtów pomiędzy dwiema kopiami tego samego programu działającymi w jednym komputerze. Wyniki przedstawiamy na rysunku 16.2.

Page 258: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

236 Protokoły domeny unixowej: wprowadzenie Rozdział 16

Jądro TCP (najszybszy) (bajty/sek.)

Domena unixowa (bajty/sek.)

Względny wzrost szybkości TCP-»Unix (%)

DEC 0SF/1 V3.0 14980 000 32109000 114

SunOS 4.1.3 4877000 11 570000 137

BSD/OS V1.1 3459 000 7 626 000 120

Solaris 2.4 2 829 000 3 570000 26

AIX 3.2.2 1 592 000 3 948 000 148

Rysunek 16.2 Porćnmanie szybkości działania gniazda domeny unixowej i TCP

Przy porównaniu gniazda TCP i gniazda domeny unixowej istotny jest względny przyrost szybkości, a nie absolutna szybkość przesyłania danych. (Testy zostały przeprowadzone w pięciu różnych systemach, z procesorami o znacząco różnych szybkościach przetwarzania. Porównywanie szybkości wyszczególnionych w róż­nych rzędach tabeli jest więc pozbawione sensu.) Jądra wszystkich systemów, z wyjątkiem Solaris 2.4, wywodzą się z systemu Berkeley. Widzimy, że w syste­mach wywodzących sie z systemu Berkeley gniazda domen unixowych są dwu­krotnie szybsze niż gniazda TCP. Względna różnica jest mniejsza dla systemu Solaris.

Solaris i system SVR4, z którego wywodzi się Solaris, mają całkowicie inną implementację gniazd domeny unixowej. Rozdział 7.5 książki [Rago 1993] zawiera przegląd opartej na strumieniach implementacji gniazd domen unixowych w systemie SVR4.

W przedstawionych testach termin „najszybszy TCP" oznacza, że testy były wy­konane z rozmiarami buforów wysyłkowych i odbiorczych równymi 32 768 (co jest wartością większą niż domyślne rozmiary buforów w niektórych systemach), a adres interfejsu pętli zwrotnej był podany jawnie, zamiast własnego adresu IP hosta. We wcześniejszych implementacjach BSD - jeżeli podawany był własny adres IP hosta - pakiet był wysyłany do interfejsu pętli zwrotnej dopiero po wyko­naniu kodu ARP (strona 31 tomu 1). Zmniejszało to szybkość działania gniazda (i dlatego w testach podawano bezpośrednio adres interfejsu pętli zwrotnej). Takie hosty mają w tablicy rutowania wpis do lokalnej sieci, której interfejsem jest program obsługi sieci. Przykładem może być wpis dla sieci 140.252.13.22 w górnej części strony 133 w tomie 1 (SunOS 4.1.3). Nowsze jądra BSD mają jawnie podaną marszrutę do własnego adresu IP, a odpowiednim interfejsem jest program obsłu­gi pętli zwrotnej. Wpis dla 140.252.13.35 na rysunku 18.2, strona 576 w tomie 2, jest tu dobrym przykładem (BSD/OS V2.0).

Do tematu szybkości działania wrócimy w rozdziale 18.11, po przedstawieniu implementacji protokołów domeny unbcowej.

Page 259: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 16.4 Przykłady programów 237

16.4 Przykłady programówPokażemy jak niewielkie są różnice pomiędzy klientem-serwerem TCP, a klien- tem-serwerem domeny unixowej. W tym celu zmodyfikowaliśmy programy klien­ta i serwera przedstawione na rysunkach 1.5 i 1.7, tak by wykorzystywane były protokoły domeny unixowej. Na rysunku 16.3 przedstawiamy klienta domeny uni- xowej. Zmiany w stosunku do rysunku 1.5 zaznaczamy pogrubionym drukiem.

------------------------------------------------------------------------------------------------- unixcli.c1 #include "cliserv.h"2 #1nclude <sys/un.h>

3 int4 main(int argc, char *argv[])5 ( /* prosty klient domeny unixowej */6 struct sockaddr_un serv:7 char request[REQUEST], reply[REPLY];8 int sockfd, n:

9 if (argc != 2)10 err_quit("usage: unixcli <pathname of server>");

11 if ((sockfd = socket(PF_UNIX, S0CK_STREAM. 0)) < 0)12 err_s ys ("socket error");

13 memset(&serv, 0, sizeof(serv));14 serv.sun_family - AF_UNIX;IB strncpy(serv.sun_path, argv[l], sizeof(serv.sun_path));

16 if (connecttsockfd, (SA) &serv, sizeof(serv)) < 0)17 er r_sys("connect error");

18 /* utworzenie żądania request[] . . . * /

19 if (writetsockfd, request, REQUEST) != RE0UEST)20 er r_sys("write error");21 if (shutdowntsockfd, 1) < 0)22 er r_sys("shutdown error");

23 if ((n = read_stream(sockfd, reply, REPLY)) < 0)24 err_sys("read error");

25 /* przetworzenie "n” bajtów odpowiedzi reply[] . . . * /

26 exi t (0);27 (

------------------------------------------------------------------------------------------------- unixcli.cRysunek 16.3 Klient transakcji używający gniazda domeny unixowej

2-6 Dołączamy nagłówek <sys/un.h> i struktury adresowe gniazd są teraz typu sockaddr_un.

Page 260: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

239 Protokoły domeny unixowej: wprowadzenie Rozdział 16

11-15 Rodziną protokołów dla odwołania do socket jest P F_U NIX. Struktura adre­sowa gniazda zostaje wypełniana przy pomocy strncpy nazwą ścieżki związaną z serwerem (z argumentu linii polecenia).

W następnym rozdziale, przy omawianiu implementacji, pokażemy, jakie są po­wody wprowadzenia tych zmian.

Na rysunku 16.4 pokazany jest serwer domeny unixowej. Tak jak poprzednio, zmiany w stosunku do rysunku 1.7 zaznaczyliśmy pogrubionym drukiem.

umxserv.c1 //include "cliserv.h"2 #include <sys/un.h>

3 #define SERV_PATH "/tmp/tcpipiv3.serv"

4 int5 m a i n ( )6 ( /* prosty serwer domeny unixowej */7 struct sockaddr_un serv, cli;8 char request[REQUEST], reply[REPLY];9 int listenfd, sockfd, n, clilen;

10 if ((listenfd = socket(PF_UNIX, SOCk_STREAM, 0)) < 0)11 e r r_ s ys (“socket error");

12 memset(&serv, 0, sizeof(serv));13 serv.sun_family - AF_UNIX;14 strncpy(serv.sun_path, SERV_PATH. sizeof(serv.sun_path));

15 if (bind(listenfd, (SA) &serv, sizeof(serv)) < 0)16 err_sys("bind error");

17 if (listen(listenfd, S0MAXC0NN) < 0)18 e r r_ s ys ("1 i sten e rr or”);

19 for ( ; ; ) (20 clilen = s i zeof(cli);21 if ((sockfd = accept(1 istenfd, (SA) &cl1, &cli 1 e n )) < 0)22 err_sys(”accept error");

23 if ((n = read_stream(sockfd. request, REOUEST)) < 0)24 err_ s ys ("read error");

25 /* przetworzenie ”n" bajtów żądania request[] i utworzenie* odpowiedzi reply[] . . . * /

26 if (write(sockfd, reply, REPLY) != REPLY)27 err_ s ys ("write e rror”);

28 close(sockfd);29 ]30 )

Rysunek 16.4 Senuer transakcji używający gniazda domeny unixowejunixserv.c

Page 261: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 16.5 Podsumowanie 239

2- 7 Dołączamy nagłówek <sys / un . h> oraz definiujemy (#def i ne) nazwę ścież­ki związanej z tym serwerem. (Zwykle ścieżka byłaby zdefiniowana w nagłówku dołączanym przez klienta i serwera; dla uproszczenia definicję umieszczamy tu­taj.) Struktury adresowe gniazd są teraz typu sockaddr_un.

13-14 Struktura adresowa gniazda serwera jest wypełniana nazwą ścieżki przy użyciu strncpy.

16.5 PodsumowanieProtokoły domen unixowych udostępniają sposób komunikacji międzyproceso- wej używający tych samych interfejsów programowych (gniazd), co komunikacja sieciowa. Protokoły domeny unixowej udostępniają zarówno gniazdo strumienio­we, podobne do TCP, jak i gniazdo datagramowe, podobne do UDP. Używając domeny unixowej zyskujemy na szybkości: dla jąder systemu wywodzących się z systemu Berkeley protokoły domeny unixowej są dwukrotnie szybsze niż TCP/IP.

Najważniejszymi użytkownikami protokołów domeny unucowej są potoki i X Window System. Jeżeli serwer X stwierdza, że klient X działa w tym samym komputerze, używane jest strumieniowe połączenie domeny unixowej zamiast połączenia TCP. Różnice w kodzie systemów klient-serwer używających TCP i domen unixowych są minimalne.

W następnych dwóch rozdziałach przedstawimy implementację gniazd domeny unixowej w kodzie jądra N e t/3.

Page 262: Biblia TCP IP Tom 3 - Uzupelnienie.pdf
Page 263: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Protokoły domeny unixowej: implementacja17

17.1 WstępKod źródłowy implementacji protokołów domeny unixowej składa się z 16 funkcji zebranych w pliku ui pc_usrreq .c. W sumie ta implementacja liczy około 1000 linii kodu w C, co jest wielkością podobną do 800 linii koniecznych do implemen­tacji UDP (tom 2), jednocześnie jest to znacznie mniej niż 4500 linii implementacji TCP.

Naszą prezentację implementacji protokołów domeny unixowej podzielimy na dwa rozdziały. W tym rozdziale omawiamy wszystkie zagadnienia oprócz I/O i przekazywania deskryptorów, które zostaną przedstawione w rozdziale następ­nym.

17.2 Wprowadzenie do kodu źródłowegoBędziemy zajmować się 16 funkcjami w C umieszczonymi w jednym pliku, Ponadto w oddzielnym pliku C zebrane zostały rozmaite definicje. Wykorzysty­wane będą też dwa nagłówki. Używane pliki zebraliśmy na rysunku 17.1. W tym rozdziale omówimy również dwa odwołania systemowe używające funkcji dome­ny unixowej: pi pe i socketpai r.

Plik Opis

s y s / u n .h

s y s / u n p c b . h

Definicja struktury s o c k a d d r _ u n

Definicja struktury u npcb

k e r n / u i p c _ p r o t o . c

k e r n / u i p c _ u s r r e q . c

k e r n / u i p c _ s y s c a l 1 s . c

Definicje p ro to s w { ) i doma i n { ) domeny unixowej

Funkcje domeny unixowej

Systemowe odwołania p i p e i s o c k e t p a i r

Rysunek 17.1 Pliki omawiane w tym rozdziale

Zmienne globalneNa rysunku 17.2 pokazujemy zmienne globalne wprowadzone w tym i następnym rozdziale.

Page 264: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

242 Protokoły domeny unixowej: implementacja_______________ Rozdział 17

Zmienna Typ danych Opis

u n ix d o m a in

u n i x sw

s t r u c t d o m a in

s t r u c t p ro to s w

definicje domeny (rysunek 17.4)

definicje protokołu (rysunek 17.5)

su n _n o n a m eu n p _ d e f e r

u n p _ g c i ng

u n p _ i no

u n p _ r i g h t s

s t r u c t s o c k a d d r

i n t

i n t

i n o _ t

i n t

struktura adresowa gniazda zawierająca pustą nazwę ścieżki

licznik opóźnionych wpisów procedury zbierania niepotrzebnych danych

ustawiona, jeśli zbieranie niepotrzebnych danych jest właśnie wykonywane

następny fałszywy numer węzła i-node, który będzie przypisany

licznik deskryptorów plików, które są w locie

u n p d g _ r e c v s p a c e

u n p d g _ s e n d s p a c e

u n p s t _ r e c v s p a c e

u n p s t _ s e n d s p a c e

u _ lo n g

u J ong

u _ lo n g

u _ lo n g

domyślny rozmiar bufora odbiorczego gniazda datagramowego, 4096 bajtów

domyślny rozmiar bufora wysyłkowego gniazda datagramowe­go, 2048 bajtów

domyślny rozmiar bufora odbiorczego gniazda strumieniowego, 4096 bajtów

domyślny rozmiar bufora wysyłkowego gniazda strumieniowe­go, 4096 bajtów

Rysunek 172 Zmienne globalne wprowadzone w tym rozdziale

17.3 Unixowe struktury domain iprotoswNa rysunku 17.3 pokazane zostały trzy struktury doma i n istniejące zwykle w sy­stemie N et/3 , oraz odpowiadające im tablice protosw .

Historyczne przyczyny istnienia dwóch nie przetworzonych pozycji IP (raw) omówione są na stronie 199 w tomie 2.

Page 265: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 17.3 Unixowe struktury domain i protosw 243

Domeny internetowe i domeny rutowania były omówione w tomie 2. Rysunek 17.4 przedstawia pola struktury domai n (strona 195 w tomie 2) dla protokołów domeny unixowej.

Czton Wartość Opis

d o m _fam i l y PF_UNIX rodzina protokołów dla domeny

dom _nam e unix nazwa

d o m _i n i t 0 nie używany w domenie unixowej

d o m _ e x t e r n a l i ze unp_externa1 i ze uzewnętrznienie praw dostępu (rys. 18.12)

d om _d i s p o s e unp_dispose usunięcie wewnętrznych praw dostępu (rys. 18.14)

d o m _p ro to sw urixsw tablica stmktur przełączników protokołu (rys. 17.5)

dom _protosw N PRO TO SW wskaźnik poza koniec struktury przełącznika proto­kołu

d o m _n e x t wypełnianyprzezdomai n i n i t , str.202,tom 2

d o m _ r t a t t a c h 0 nie używany w domenie unixowej

d o m _ r t o f f s e t 0 nie używany w domenie unixowej

d o m _ m a x r tk e y 0 nie używany w domenie unixowej

Rysunek 17.4 Struktura un ixdoma in

Tylko domena unbcowa definiuje funkcje dom_external i ze i dom_di spose. Opi­szemy te funkcje w rozdziale 18 przy okazji omawiania przekazywania deskrypto- rów. Ostatnie trzy człony struktury nie są zdefiniowane, ponieważ domena unixo- wa nie używa tablicy rutowania.

Na rysunku 17.5 pokazujemy inicjację struktury unixsw. (Analogiczną strukturę dla protokołów internetowych pokazano na stronie 200 w tomie 2.)

uipc_proto.c41 struct protosw unixsw[] =

(4243 (SOCK STREAM, &uni xd o ma in , 0. PR C0NNRE0UIRED | PR _WANTRCVD | PR _ R I G H T S ,44 0, 0, 0. 0.45 uipc usrreq,46 0, 0, 0. 0.47 1 .48 (SOCK OGRAM, & un ixdomain, 0, PR AT0MIC 1 PR ADDR 1 PR_RIGHTS,49 0. 0, 0. 0.50 uipc usrreq,51 0, 0, 0, 0.52 ).53 (0, 0, 0, 0,54 raw_input. 0, raw_ctlinput, 0,55 r aw_ u sr re q,56 raw init, 0, 0, 0,57 1,58 ) ;

------------------------------------------------------------------------------------------------- uipc_proto.cRysunek 17.5 Inicjacja tablicy unixsw

Page 266: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

244 Protokoły domeny unixowej: implementacja Rozdział17

Zdefiniowane są trzy protokoły:

• protokół strumieniowy podobny do TCP• protokół datagramowy podobny do UDP• protokół danych nie przetworzonych (raw) podobny do protokołu danych nie

przetworzonych IP (rciw IP).

Protokoły domeny unixowej - strumieniowy i datagramowy - używają flagi PR_RIGHTS, ponieważ domena ta stosuje prawa dostępu (przekazywanie deskryp­torów, które omawiamy w następnym rozdziale). Dwie kolejne flagi protokołu strumieniowego, PR_CONNREOUIRED i PR_WANTRCVD, są identyczne z flagami TCP, a dwie następne flagi, P R_ATOM IC i P R_ADD R, są takie same jak flagi UDP. Zauważ­my, że jedynym wskaźnikiem funkcji zdefiniowanym dla protokołów strumienio­wego i datagramowego jest u i pc_u s r req, obsługujący wszystkie żądania.

Cztery wskaźniki w strukturze protosw protokołu danych nie przetworzonych (wszystkie z nazwami zaczynającymi się od r a w _ ) są tymi samymi wskaźnikami, które są używane w domenie PF_R0UTE, opisanymi w rozdziale 20 w tomie 2.

Autor nie zna żadnej aplikacji używającej protokołu danych nie przetworzonych domeny unixowej.

17.4 Struktura adresowa gniazda domeny unixowejNa rysunku 17.6 pokazana jest definicja struktury adresowej gniazda domeny unbcowej, sockaddr_un, zajmującej 106 bajtów.

------:------------------------------------------------------------------------------------------ un.h38 struct sockaddr_un (39 u_char sun_len; /* długość sockaddr łącznie z zerem */40 u_char sun_family; /* A F _ U N IX */41 char sun_path[104]; /* nazwa ścieżki (gag) */42 );

------------------------------------------------------------------------------------------------- un.hRysunek 17.6 Struktura adresowa gniazda domeny unixowej

Pierwsze dwa pola są takie same, jak we wszystkich strukturach adresowych gniazd: bajt długości, po którym następuje rodzina adresowa (AF_UNIX).

Komentarz „gag'" istnieje w tym miejscu od czasów 4.2BSD (zachowano oryginalną postać komentarza, można to przetłumaczyć jako „oszukaństwo" - przyp. tłum.). Może­my się domyślać, że autor tego fragmentu kodu nie był zwolennikiem używania nazw ścieżek do identyfikacji gniazd domen unixowych lub być może komentarz odnosi się do faktu, że w mbuf nie ma wystarczająco dużo miejsca na kompletną nazwę ścieżki (której maksymalna długość wynosi 1024 bajty).

Zobaczymy, że gniazda domen unixowych używają do identyfikacji gniazd nazw ścieżek systemu plików i nazwa ścieżki jest przechowywana w członie s un_pa t h. Człon ten ma 104 bajty długości, by możliwe było zmieszczenie struktury adreso­wej gniazda wraz z kończącym bajtem zerowym w 128-bajtowym mbuf. Pokazu­jemy to na rysunku 17.7.

Page 267: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 17.5 Bloki kontrolne protokołu domeny unixowej 245

m_type (MT_SONAME) sun_len,— sun_family (AF_UNIX)

nagłówekmbuf

sun_path[104]

20 bajtówm _hdr()

1 1sockaddr un(}

1 1

U----------------

*

mbuf () (128bajtów)

Rysunek 17.7 Struktura adresowa gniazda domeny unixowej umieszczona w mbuf

Pokazujemy pole m_type bufora mbuf z wartością MT_S0NAME, ponieważ jest to normalna wartość w sytuacji, gdy mbuf zawiera strukturę adresową gniazda. Choć okazuje się, że ostatnie 2 bajty nie są używane i że maksymalna długość nazwy ścieżki wynosi 104 bajty, zobaczymy, że funkcje unp_bi nd i unp_connect dopuszczają nazwy ścieżki o długości 105 bajtów, z bajtem zerowym umieszczo­nym po nazwie ścieżki.

Gniazda domeny unixowej muszą gdzieś znaleźć przestrzeń na przechowywanie nazw.Do tego celu zostały użyte nazwy ścieżek, ponieważ przestrzeń przeznaczona na nazwy ścieżek systemu plików już istniała. Dla przykładu, protokoły internetowe używają adre­sów IP i numerów portu jako przestrzeni nazw, a System V IPC (rozdział 14 książki [Stevens 1992]) używa 32-bitowych kluczy. Ponieważ nazwy ścieżek są używane przez klientów domeny unixowej do komunikowania się z serwerem, stosowane są zwykle bezwzględne nazwy ścieżek (zaczynające się od znaku / ) . Jeżeli użyte zostają względne nazwy ścieżek, klient i serwer muszą znajdować się w tym samym katalogu, w przeciw­nym razie nazwa ścieżki, z którą zwiąże się serwer, nie zostanie znaleziona przez funkcje c o n n e c t i s e n d to wywołane przez klienta.

17.5 Bloki kontrolne protokołu domeny unixowejGniazda w domenie unixowej posiadają odpowiedni blok kontrolny protokołu (PCB) - strukturę unpcb. Pokazujemy tę 36-bajtową strukturę na rysunku 17.8.

------------------------------------------------------------------ unpcb.h60616263646566 67 606970

struct unpcb (struct socket *unp_socket; struct vnode *unp_vnode; ino_t unp_ino; struct unpcb *unp_conn; struct unpcb *unp_refs: struct unpcb *unp_nextref; struct mbuf *unp_addr; int unp_cc;int unp_mbcnt;

/* powrotny wskaźnik do struktury gniazda */ /* niezerowy. jeśli związany z plikiem *//* fałszywy numer inode *//* blok kontrolny połączonego gniazda *//* odniesienie do powiązanej listy gniazda */ /* wiązanie w liście unp_refs *//* związany adres gniazda *//* kopia rcv.sb_cc *// * kopia rcv.sb_mbcnt */

71 #define sotounpcb(so) ((struct unpcb * )( (so)->so_pcb))

Rysunek 17.8 Blok kontrolny protokołu domeny unixowejunpcb.h

Page 268: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

246 Protokoły domeny unixowej: implementacja Rozdział 17

W przeciwieństwie do internetowych bloków kontrolnych i bloków kontrolnych używanych w domenie rutowania, alokowanych przez funkcję jądra M A L LOC (stro­ny 687 i 742 w tomie 2), struktury unpcb są przechowywane w buforach mbuf. Wynika to najprawdopodobniej ze względów historycznych.

Kolejna różnica polega na tym, że wszystkie inne bloki kontrolne, poza blokami kontrolnymi domeny unixowej, są przechowywane w postaci dwukierunkowej listy cyklicznej, która jest przeszukiwana, gdy przychodzą dane i gdy są one kierowane do odpowiedniego gniazda. W przypadku bloków kontrolnych dome­ny unbcowej, lista taka nie jest potrzebna, ponieważ równoważną operację - na przykład odszukanie bloku kontrolnego serwera, gdy klient wywołuje c o n n e c t - wykonują funkcje istniejące w jądrze, służące do przeszukiwania ścieżek nazw. Adres raz znalezionego bloku unpcb serwera jest przechowywany w bloku unpcb klienta, ponieważ klient i serwer znajdują się w jednym komputerze z gniazdami domen unixowych.

Na rysunku 17.9 pokazany został układ różnych struktur danych związanych z gniazdami domen unixowych. Prezentujemy dwa gniazda domeny unbcowej. Zakładamy, że serwer (prawa strona rysunku) związał nazwę ścieżki ze swoim gniazdem, a klient (lewa strona) połączył się z nazwą ścieżki serwera.

Człon unp_conn klienta wskazuje na serwera. unp_refs serwera wskazuje na pierwszego klienta, który połączył się z tym PCB. (W przeciwieństwie do gniazd strumieniowych, z pojedynczym serwerem może połączyć się więcej niż jeden klient datagramowy. Połączenia datagramowych gniazd domeny unbcowej anali­zujemy szczegółowo w rozdziale 17.11.)

Człon unp_vnode gniazda serwera wskazuje na człon vnode skojarzony z nazwą ścieżki związaną z gniazdem serwera, a człon v_socket struktury vnode wskazuje na s o c k e t serwera. Takie połączenie jest wymagane, by zlokalizować blok unpcb, związany z nazwą ścieżki. Na przykład, gdy serwer wiąże nazwę ścieżki z gniaz­dem domeny unbcowej, powstaje struktura vnode i wskaźnik do unpcb umiesz­czony zostaje w członie v_socket węzła v-node. Gdy klient łączy się z tym serwe­rem, kod poszukiwania nazwy ścieżki w jądrze znajduje węzeł v-node i następnie ze wskaźnika v_socket otrzymuje wskaźnik do unpcb serwera.

Nazwa, która była związana z gniazdem serwera, zawarta jest w strukturze sockaddr_un,ta struktura z kolei jest zawarta w strukturze mbu f , na którą wska­zuje człon unp_addr. Unbcowe węzły v-node nigdy nie zawierają nazwy ścieżki prowadzącej do tego węzła v-node, ponieważ w systemie plików Unixa plik (tzn. v-node) może być wskazywany przez wiele nazw (tzn. pozycji w katalogu).

Rysunek 17.9 pokazuje dwa połączone gniazda datagramowe. Zobaczymy później (rysunek 17.26), że analogiczny diagram dla gniazd strumieniowych wygląda nieco inaczej.

Page 269: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 17.5_______________ Bloki kontrolne protokołu domeny unixowej 247

Page 270: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

248 Protokoły domeny unixowej: implementacja R o zd z ia łu

17.6 Funkcja uipc_usrreqZobaczyliśmy na rysunku 17.5, że jedyną funkcją wymienianą w strukturze unixsw dla protokołów strumieniowych i datagramowych jest u i pc_usrreq. Ry­sunek 17.10 przedstawia główną część tej funkcji.

------------------------------------------------------------------------------------------------ uipc_usrrecj.c47 i nt48 uipc_usrreq(so. req, m, nam, cont ro l)49 struct socket *so;50 int req;51 struct mbuf *m, *nam. * c o nt r ol ;52 (53 struct unpcb *unp = sotounpcb(so);54 struct socket *so2;55 int error = 0;56 struct proc *p = curproc; /* XXX */

57 if (req == PRU_C0NTR0L)58 return (EOPNOTSUPP);59 if (req != PRU_SEND && control && control->m_len) [60 error = EOPNOTSUPP;61 goto release;62 )63 if (unp == 0 && req != PRU_ATTACH) {64 error = EINVAL;65 goto release;66 )67 switch (req) 1

/* instrukcje switch (omawi ane w następnych podrozdzi ałaęh ). */

246 default:247 panic("piusrreq");248 ]249 release;250 i f (control )251 m_freem(control );252 if (m)253 m_f r ee m( m) ;254 return (error);255 )

------------------------------------------------------------------------------------------------- uipcjusrreq.cRysunek 17.10 Główna część funkcji u ip c_u srreq

Żądanie PRU_CONTROL nie jest akceptowane57-58 Żądanie PRU_C0NTR0L pochodzi z systemowego odwołania i octl i nie jest

obsługiwane przez domenę unixową.

Informacje kontrolne dopuszczalne tylko dla PRU_SEND59-62 Jeżeli informacja kontrolna została przekazana przez proces (przy pomocy

systemowego odwołania sendmsg), żądanie musi być żądaniem PRU_SEND,

w przeciwnym przypadku zwracany jest komunikat o błędzie. Dla tego żądania - przy użyciu informacji kontrolnej - przekazywane są deskryptory (pokazujemy to w rozdziale 18.)

Page 271: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 17.7 Żądanie PRU_ATTACH i funkcja unp_attach 249

Gniazdo musi mieć blok kontrolny63 - 66 Jeżeli struktura socket nie wskazuje na blok kontrolny domeny unixowej,

to jedynym dopuszczalnym żądaniem jest PRU_ATTACH, w przeciwnym razie zwracany jest komunikat o błędzie.

6 7 - 2 4 8 Poszczególne instrukcje case z tej funkcji oraz różne wywoływane funkcje imp_xxx omawiamy w następnych podrozdziałach.

2 4 9 - 2 5 5 Zwalniane są wszystkie informacje kontrolne oraz dane buforów mbuf i funkcja zwraca kontrolę do wołającej procedury.

17.7 Żądanie PRU_ATTACH i funkcja unp_attachŻądanie PRU_ATTACH (pokazane na rysunku 17.11) tworzone jest przez systemowe odwołanie socket i przez funkcję sonewconn (strona 477, tom 2), gdy przychodzi żądanie połączenia dla odbierającego gniazda strumieniowego.

------------------------------------------------------------------------------------------------- uipc_usrreq.c68 case PRU_ATTACH:69 if (unp) (70 error = EISCONN;71 break;72 173 error = unp_a tt ach(s o ):74 break;

------------------------------------------------------------------------------------------------- uipć_usrreq.cRysunek 17.11 Żądanie PRU_A TT A CH

6 8 - 7 4 Cała obsługa tego żądania wykonywana jest przez funkcję unp_attach (rysunek 17.12). Alokacja i inicjacja struktury socket została już wykonana w war­stwie gniazda i zależy to teraz już tylko od warstwy protokołu, czy alokować i inicjować własny blok kontrolny protokołu - w tym przypadku strukturę unpcb.

Ustawienie znaku przepełnienia gniazda2 7 7 - 290 Jeżeli wysyłany znak przepełnienia (high-water mark) gniazda lub odbierany

znak przepełnienia gniazda jest 0, s o r e s e r v e ustawia wartości domyślne pokaza­ne na rysunku 17.2. Znaki przepełnienia ograniczają ilość danych w buforze od­biorczym lub wysyłkowym gniazda. Gdy funkcja unp_attach jest wołana po­przez odwołanie systemowe socket, oba te znaki przepełnienia są równe 0, nato­miast w przypadku wywołania poprzez sonewconn, znaki te mają wartości odpo­wiednie dla odbierającego gniazda.

Alokacja i inicjacja291 -2 9 6 m_getcl r otrzymuje mbuf dla struktury unpcb, zeruje mbuf i ustawia typ

na MT_PCB. Zauważmy, że wszystkie człony inicjowane są wartością 0. Struktury socket i unpcb powiązane są przez wskaźniki so_pcb i unp_socket.

Page 272: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

250 Protokoły domeny unixowej: implementacja R o zd z ia łu

------------------------------------------------------------------------------------------------- uipc_usrreq.c270 int271 unp_attach(so)272 struct socket *so;273 (274 struct mbuf *m;275 struct unpcb *unp;276 int error;

277 if (so->so_snd.sb_hiwat == 0 || s o->so_rcv.sb_hiwat == 0) (278 switch (so->so_type) (

279 case S0CK_STREAM:280 error = soreserve(so, unpst_sendspace, unpst_recvspace);281 break;

282 case S 0CK_DGRAM:283 error = soreserve(so, unpdg_sendspace, unpdg_recvspace);284 break;

285 default:286 panic("unp_attach");287 }288 if (error)289 return (error);290 )291 m = m_getclr(M_D0NTWAIT, MT_PCB);292 if (m == NULL)293 return (ENOBUFS);294 unp = mtodtm, struct unpcb *);295 so->so_pcb = (caddr_t) unp;296 unp->unp_socket = so;297 return (0);298 I

------------------------------------------------------------------------------------------------- uipc_usrreq.cRysunek 17.12 Funkcja unp_a t ta ch

17.8 Żądanie PRU_DETACH i funkcja unp_detachŻądanie PRILD ETACH (rysunku 17.13) jest tworzone przy zamykaniu gniazda (stro­na 488, tom 2) i następuje po żądaniu PRU_DISC0NNECT (generowanym tylko dla połączonych gniazd).

------------------------------------------------------------------------------------------------- uipc_usrreq.c75 case PRU_DETACH:76 unp_detach(unp);77 break;

--------------------------------------------------------- --------------------------------------- uipc_usrreq.cRysunek 17.13 Żędanie PRU_DETACH

75-77 Funkcja unp_detach (rysunek 17.14) wykonuje całą obsługę żądaniaPRUJDETACH.

Page 273: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 17.8 Żądanie PRU_DETACH i funkcja unp_detach 251

---------------------------------------------------------------------------------- uipc_nsrrecj.c299 void300 unp_detach(unp)301 struct unpcb *unp;302 (

303 if (u n p ->unp_vnode) (304 unp->unp_vnode->v_socket = 0;305 vrele(unp->unp_vnode);306 unp->unp_vnode = 0;307 ]308 if (unp->unp_conn)309 unp_disconnect(unp);310 while (unp->unp_refs)311 unp_drop(unp->unp_refs, ECONNRESET);312 soisdisconnected(unp->unp_socket);313 unp->unp_socket->so_pcb = 0;314 m_freem(unp->unp_addr);315 (void) m_free(dtom(unp));316 if (unp_rights) (317 /*318 * Zwykle bufor odbiorczy jest opróżniany później, w sofree,319 * jeśli jednak nasz bufor odbiorczy przechowuje odnośniki320 * do deskryptorów, które są teraz zbędne, pozbędziemy się tych321 * odnośników do deskryptorów po zebraniu ich przez funkcję322 * zbierającą bezużyteczne dane (powodując: "panie: closef: count < 0").323 */324 sorflush(unp->unp_socket);325 u n p_gc();326 )327 ]

----------------------------------------------------------------------------------- uipc_usrreq.c

R ysunekl7.14 Funkcja unp_detach

Zwolnienie v-node303-307 Jeśli gniazdo jest związane z węzłem v-node, wskaźnik do struktury tego

bloku otrzymuje wartość 0 i vrei e zwalnia v-node.

Rozłączenie, jeżeli zamykane gniazdo jest połączone3 08-309 Jeżeli zamykane gniazdo jest połączone z innym gniazdem, funkcja

unp_di sconnect rozłącza gniazda.

Rozłączenie gniazda połączonego z zamykanym gniazdem310-311 Jeżeli inne gniazda datagramowe połączone są z zamykanym gniazdem, to

połączenia te zostają odrzucone przez unp_drop i gniazda otrzymują komunikato błędzie ECONNRESET. Pętla while przechodzi przez powiązaną listę wszystkich struktur unpcb połączonych z unpcb zamykanego gniazda. Funkcja unp_drop wywołuje funkcję unp_di sconnect, która zmienia człon unp_refs bloku, tak że człon ten wskazuje na następną pozycję listy. Po przetworzeniu całej listy wskaźnik unp_ref s bloku będzie równy 0.

312-313 Zamykane gniazdo zostaje rozłączone przez soi sdi sconnected,

a wskaźnik struktury socket do bloku jest zerowany.

Page 274: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

252 Protokoły domeny unixowej: implementacja_______________ R o zd z ia łu

Zwolnienie adresu i buforów mbuf314-315 Jeżeli gniazdo związane zostało z adresem, bufor mbuf zawierający ten

adres jest zwalniany przez m_freem. Zauważmy, że kod nie sprawdza, czy wskaźnik unp_a dd r jest niezerowy, ponieważ sprawdzenie to wykonuje m_f reem. Struktura unpcb jest zwalniana przez m_f ree.

To odwołanie do m_free powinno być przeniesione na koniec funkcji, ponieważ wskaźnik unp może być użyty przez następny fragment kodu.

Sprawdzenie przekazywanych deskryptorów316-326 Jeżeli istnieją deskryptory aktualnie przekazywane przez dowolny proces

w jądrze, wartość unp_ri ghts jest niezerowa, co powoduje wywołanie sorf 1 ush i unp_gc (garbage collector - funkcja zbierająca bezużyteczne dane). (Przekazywa­nie deskryptorów omawiamy w rozdziale 18.)

17.9 Żądanie PRU_BIND i funkcja unp_bindGniazda strumieniowe i datagramowe w domenie unbcowej mogą być związane z nazwami ścieżek w systemie plików przy pomocy funkcji bind. Systemowe odwołanie bind tworzy żądanie P RU_B I ND, co pokazujemy na rysunku 17.15.

------------------------------------------------------------------------------------------------- uipc_usrreq.c78 case PRU_BIND:79 error = unp_bind(unp, nam, p);80 break:

------------------------------------------------------------------------------------------------- uipc_usrreq.cRysunek 17.15 Żądanie PRU_BIND

78-80 Całe przetwarzanie jest wykonywane przez funkcję un p_b i nd, pokazaną na rysunku 17.16.

------------------------------------------------------------------------------------------------- uipc_usrreq.c328 int329 unp_bind(unp, nam. p)330 struct unpcb *unp;331 struct mbuf *nam;332 struct proc *p;333 (334 struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);335 struct vnode *vp;336 struct vattr vattr;337 int error;338 struct nameidata nd;

339 NDINIT(&nd, CREATE, F0LL0W | LOCKPARENT, UI0_SYSSPACE. soun->sun_path, p);340 if (unp->unp_vnode != NULL)341 return (EINVAL);342 if (nam->m_len == MLEN) (343 if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)344 return (E I NVAL);345 ] else346 *(mtod(nam, caddr_t) + nam->m_len) = 0;347 /* POWINNA BYC MOŻLIWOŚĆ UŻYCIA ISTNIEJĄCYCH PLIKÓW I WYKONANIA w a k e u p O ,

* JAK DLA FIF0 */

Page 275: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 17.9 Żądanie PRU_BIND i funkcja unp_bind 253

348349350351352353354355356357358359360361362363364

if (error = n a me i(& n d ))return (error);

vp = nd.ni_vp;i f (vp != NULL) (

V0P_AB0RT0P(nd.n i _ d v p , & n d .n i _c n d); if (n d .ni_dvp == vp)

v re le (n d .n i_ d vp );else

vput(nd,ni_dvp);v re le ( vp );return (EADDRINUSE);

1V ATTR_NULL(&vattr); vattr.va_type = VSOCK; vattr .va_mode = ACCESSPERMS;if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr))

return (error);

365 vp = nd.ni_vp;366 vp->v_socket = unp->unp_socket;367 unp->unp_vnode = vp;368 unp->unp_addr = m_copy(nam, 0, (int) M_C0PYALL);369 V 0P _U NL0CK(vp, 0, p);370 return (0);371 }

uipc_usrreq.cRysunek 17.16 Funkcja unp_bind

Inicjacja struktury nameidata338-339 unp_bi nd alokuje strukturę typu namei data, która zawiera wszystkie argu­

menty funkcji namei, i inicjuje tę strukturę przy pomocy makroinstrukcji NDINIT. Argument CREATEoznacza, że utworzona będzie nazwa ścieżki, F0LL0W pozwala na śledzenie symbolicznych linków, a L0CKPARENT informuje, że macierzysty wę­zeł v-node musi być zablokowany przy wyjściu (by inny proces nie mógł zmody­fikować v-node, dopóki nasze przetwarzanie nie zostanie zakończone). Z kolei U10_S Y S S P AC E oznacza, że nazwa ścieżki znajduje się w jądrze (ponieważ prze­twarzanie odwołania systemowego bind kopiuje ją z przestrzeni użytkownika do mbuf). soun ->sun_path jest początkowym adresem nazwy ścieżki (przekazywa­nym do unp_bi nd jako argument nam). Wreszcie p jest wskaźnikiem do struktury proc dla procesu, który wykonał odwołanie systemowe bi nd. Ta struktura zawie­ra całą informację o procesie, którą jądro musi przechowywać w pamięci przez cały czas. Makroinstrukcja NDI NIT tylko iniquje strukturę, odwołanie do namei znajduje się dalej w tekście funkcji.

Historycznie, funkcja szukająca nazw ścieżek w systemie plików zwana była namei, co bierze się z określenia „name-to-inode". Funkcja ta przeszukiwała system plików w poszukiwaniu podanej nazwy i - jeśli nazwa została znaleziona - inicjowała strukturę i node w jądrze, zawierającą kopię informacji węzła i-node pliku z dysku. Choć węzły i-node zostały zastąpione przez węzły v-node, to nazwa namei pozostała.Po raz pierwszy stykamy się bliżej z systemem plików w jądrze BSD. Jądro obsługuje systemy plików różnych typów: standardowy dyskowy system plików (zwany czasem „szybkim systemem plików" - fast filesystem), sieciowy system plików (NFS - netioork

filesystem), system plików CD-ROM, system plików MS-DOS, system plików w pamięci (:memory based filesystem; dla katalogów takich jak /tm p), itd. [Kleiman 1986] opisuje w czesną implementację v-node. Funkcje z nazwami zaczynającymi się od V 0P_ są podstawowymi funkcjami wykonującymi operacje na węzłach v-node. Istnieje około 40

Page 276: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

254 Protokoły domeny unixowej: implementacja_______________ Rozdział 17

takich funkcji i każda z nich, gdy zostaje wywołana, uruchamia funkcję zdefiniowaną dla danego systemu plików do wykonania odpowiedniej operacji. Funkcje z nazwami zaczy­nającymi się od małej litery v są funkcjami jądra, które mogą wywołać jedną lub więcej funkcji V0P_. Na przykład vput wywołuje V0P_UNLOCK, a następnie vrel e. Funkcja vrel e zwalnia węzeł v-node: licznik odwołań do węzła v zostaje zmniejszony i jeśli osiągnie wartość 0, wywoływana jest funkcja V0P_I NACTIVE.

Sprawdzenie, czy gniazdo jest już związane340-341 Jeżeli człon unp_vnode bloku gniazda ma niezerową wartość, gniazdo zo­

stało już związane, co jest błędem.

Zero kończące nazwę ścieżki342-346 Jeżeli długość bufora mbuf zawierającego strukturę sockaddr_un wynosi

108 (ML EN) - która to wartość jest kopiowana z trzeciego argumentu systemowego odwołania bi nd - to ostatni bajt bufora mbuf musi być bajtem zerowym. Nazwa ścieżki musi być zakończona zerem - jest to wymagane przy poszukiwaniu nazw ścieżek w systemie plików. (Funkcja sockargs, strona 467 w tomie 2, gwarantuje, że długość struktury adresowej gniazda przekazanej przez proces nie jest większa niż 108.) Jeżeli długość mbuf jest mniejsza niż 108, bajt zerowy jest umieszczany na końcu nazwy ścieżki, na wypadek, gdyby proces nie zakończył nazwy ścieżki bajtem zerowym.

Poszukiwanie nazwy ścieżki w systemie plików347-349 n ame i poszukuje nazwy ścieżki w systemie plików i usiłuje utworzyć plik o

odpowiedniej nazwie w odpowiednim katalogu. Na przykład, jeżeli nazwa ścieżki wiązana z gniazdem jest /tmp/ .Xll-unix/XO, wtedy nazwa X0 musi być dodana do katalogu / tmp/ .Xll-unix. Katalog zawierający X0 zwany jest katalogiem macierzystym (parent directory). Jeżeli katalog / t m p / .X I I - unix nie istnieje, lub jeżeli istnieje i zawiera już plik X 0, zwracany jest komunikat o błędzie. Może też pojawić się błąd wynikający z tego, że proces nie ma uprawnień do utworzenia nowego pliku w katalogu macierzystym. Oczekujemy, że funkcja na me i zwróci wartość 0 i wskaźnik n d . n i _v p będzie wskaźnikiem zerowym (plik jeszcze nie istnieje). Jeżeli oba te warunki są spełnione, wtedy nd.ni_dvp zawiera nazwę katalogu macierzystego, w którym będzie utworzony nowy plik.

Komentarz o użyciu istniejącej nazwy ścieżki odnosi się do sytuacji, gdy bind zwraca błąd, ponieważ plik już istnieje. Dlatego aplikacje wykonujące bi nd dla gniazda domeny unixowej najczęściej poprzedzają bind odwołaniem do un 1 i nk, by usunąć nazwę ścieżki, jeśli już istnieje.

Plik istnieje350-359 Jeżeli wskaźnik nd.ni_vp jest niezerowy, oznacza to, że plik o podanej

nazwie już istnieje. Odwołania do v-node zostają usunięte i komunikat o błędzie EADDRINUSE zostaje zwrócony do procesu.

Page 277: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 17.10 Żądanie PRU_CONNECT i funkcja unp_connect 255

Utworzenie v-node360-365 Struktura vattr zainicjowana jest przez makroinstrukcję VATTR_NULL.

Ustalony zostaje typ VS0CK (gniazdo) i tryb dostępu otrzymuje oktalną wartość 777 (ACCESSPERMS ). Ustawionych jest wszystkich dziewięć bitów praw dostępu, dopuszczone jest więc pisanie, czytanie i wykonywanie przez właściciela, grupę i innych użytkowników. Plik zostaje utworzony w podanym katalogu przez funk­cję systemu plików, wy wołaną pośrednio przez funkcję V 0 P_C R E AT E. Argumenta­mi do funkcji tworzącej plik są: n d . n i _d vp (wskaźnik do węzła v-node macierzy­stego katalogu), nd.ni_cnd (dodatkowa informacja z funkcji namei, która musi być przekazana do funkcji V0P) oraz struktura vattr. Drugi argument, nd . ni_vp, przekazuje informację zwracaną przez funkcję, wskazując na nowo utworzony węzeł v-node (jeśli funkcja została wykonana pomyślnie).

Powiązanie struktur365-367 vnode i socket wskazują wzajemnie na siebie poprzez człony v_socket

i unp_vnode.

Zachowanie nazwy ścieżki368-371 Wykonana zostaje, przy pomocy m_copy, kopia bufora mbuf zawierającego

nazwę ścieżki związanej przed chwilą z gniazdem. Człon unp_addr bloku wska­zuje na nowy bufor mbuf. Węzeł v-node zostaje odblokowany.

17.10 Żądanie PRU_CONNECT i funkcja unp_connectNa rysunku 17.17przedstawione są żądania PRU_LI STEN i PRU_C0NNECT.

----------------------------------------------------------------------------------- uipc_usrreq.c81 case PRU_LISTEN:82 if (unp->unp_vnode = 0)83 error = EINVAL;84 break;

85 case PRU_C0NNECT:86 error = unp_connect(so, nam. p);87 break;

----------------------------------------------------------------------------------- uipc_usrreq.c

Rysunek 17.17 Żądania PRU_LISTENi PRU_CONNECT

Sprawdzenie, czy odbierające gniazdo jest związane81 -84 Odwołanie systemowe listen' może być wykonane tylko dla gniazda, któ­

re zostało związane z nazwą ścieżki. Dla TCP taki wymóg nie istnieje. Na stronie 1054 w tomie 2 widzieliśmy, że gdy dla niezwiązanego gniazda TCP wołane jest 1 i sten, TCP wybiera i przypisuje do gniazda efemeryczny port.

85 -8 7 Całą obsługę żądania PRU_C0NNECT wykonuje funkcja unp_connect.

(Pierwszą część tej funkcji przedstawiamy na rysunku 17.18.) Funkcja ta jest wy­woływana przez żądanie P RU_C ONNECT (zarówno dla gniazda strumieniowego, jak

Page 278: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

256 Protokoły domeny unixowej: implementacja R o zd z ia łu

i dla gniazda datagramowego) i również - przy tymczasowym łączeniu niepołą­czonego gniazda datagramowego - przez żądanie PRU_SEND.

------------------------------------------------------------------------------------------------- uipc_usrreq.c372 int373 unp_connect(so, nam, p)374 struct socket *so;375 struct mbuf *nam:376 struct proc *p;377 (378 struct sockaddr_un *soun = mtodtnam, struct sockaddr_un *);379 struct vnode *vp;380 struct socket *so2, *so3;381 struct unpcb *unp2, *unp3;382 int error;383 struct nameidata nd;

384 NDINIT(&nd. L00KUP, F0LL0W | LOCKLEAF, UI 0_ S VSSPACE, soun->s un _p a th , p);385 if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) ( /* XXX */386 if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)387 return (EMSGSIZE);388 ) else389 *(mtod(nam, caddr_t) + nam->m_len) = 0;390 if (error = namei(&nd))391 return (error);392 vp = n d. n i _ v p ;393 if (vp->v_type != VS0CK) (394 error = EN0TS0CK;395 goto bad;396 )397 if (error = V0 P_ AC CESS(vp, VWRITE, p->p_ucred, p))398 goto bad;399 so2 = vp->v_socket;400 if (so2 == 0) [401 error = EC0NNREFUSED;402 goto bad:403 ł404 if (so->so_type != so2->so_type) {405 error = EPR0T0TYPE;406 goto bad;407 )

----------------------------------------------------------------------------------- uipc_usrreq.c

Rysunek 17.18 Funkcja u np_connect, część pierwsza

Inicjacja struktury nameidata383-384 Makroinstrukcja NDI NIT inicjuje strukturę nameidata. Argument L00KUP

oznacza, że nazwa ścieżki ma być poszukiwana, F0LL0W dopuszcza śledzenie symbolicznych linków, a LOCKLEAF stwierdza, że węzeł v-node musi być zabloko­wany przy wyjściu (by inny proces nie mógł zmodyfikować węzła v-node, dopóki nasze przetwarzanie nie zostanie zakończone). U10_SYSSPACE stwierdza, że na­zwa ścieżki znajduje się w jądrze, a soun ->sun_path jest początkowym adresem nazwy ścieżki (przekazanym do unp_connect w argumencie nam), p to wskaźnik do struktury proc dla procesu, który wykonał systemowe odwołanie connect lub sendto.

Page 279: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 17.10 Żądanie PRU_CONNECT i funkcja unp_connect 257

Zakończenie nazwy ścieżki bajtem zerowym385-389 Jeżeli długość struktury adresowej gniazda wynosi 108 bajtów, to ostatni

bajt musi być równy 0. Jeśli nie, bajt zerowy zostaje umieszczony na końcu nazwy ścieżki.

Ten fragment kodu jest podobny do kodu z rysunku 17.16. Istnieją jednak istotne różnice.Nie tylko pierwsza instrukcja i f została zapisana inaczej, ale również komunikat o błę­dzie - zwracany, gdy ostatni bajt jest niezerowy - jest inny: EMSGSI ZE tutaj i E I N V A L na rysunku 17.16. Przedstawiony tu test spełnia też dodatkową rolę: sprawdza, czy dane nie są zawarte w klastrze. Ten efekt uboczny jest jednak prawdopodobnie przypadkowy, ponie­waż funkcja sockar gs nigdy nie umieszcza struktury adresowej gniazda w klastrze.

Poszukiwanie i sprawdzenie nazwy ścieżki390-398 namei szuka nazwy ścieżki w systemie plików. Jeśli poszukiwanie kończy

się pomyślnie, wskaźnik do struktur v n o d e jest zwracany wnd.ni_vp.Typ v-node musi być V S 0 C K i aktualny proces musi mieć prawo do pisania dla tego gniazda.

Sprawdzenie, czy gniazdo jest związane z nazwą ścieżki399-403 Gniazdo musi być aktualnie związane z nazwą ścieżki, to znaczy wskaźnik

v_socket musi być niepusty. W przeciwnym przypadku żądanie połączenia jest odrzucane. Może się to zdarzyć, jeżeli serwer nie działa w tym momencie, ale nazwa ścieżki pozostała w systemie plików od czasu, gdy serwer ostatnio działał.

Sprawdzenie typu gniazda404-407 Typ gniazda łączącego się klienta (so) musi być taki sam jak typ gniazda

serwera, z którym połączenie jest nawiązywane (s o 2). To znaczy gniazdo strumie­niowe nie może połączyć się z gniazdem datagramowym - lub na odwrót.

Rysunek 17.19 pokazuje pozostałą część funkcji unp_connect, w której najpierw obsługiwane są łączące się gniazda strumieniowe, a następnie wywoływana jest funkcja unp_connect2 -b y powiązać dwie struktury unpcb.

------------------------------------------------------------------------------------------------- uipcjusrrecj.c408 if (so->so_proto->pr_flags & PR_C0NNREQUIRED) {409 if ((so2->so_options & S0_ACCEPTC0NN) == 0 ||410 (so3 = sonewconn(so2. 0)) == 0) (411 error = ECONNREFUSED:412 goto bad;413 )414 unp2 = sotounpcb(so2);415 unp3 = sotounpcb(so3);416 if (unp2->unp_addr)417 unp3->unp_addr =418 m_copy(unp2->unp_addr, 0, (int) M_C0PYALL);419 so2 = So3;420 )421 error = unp_connect2(so, so2);422 bad:423 vput(vp);424 return (error);425 )------------------------------------------------------------------------------------------------- uipc_usrreq.cRysunek 17.19 Funkcja unp_connect część druga

Page 280: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

258 Protokoły domeny unixowej: implementacja_______________ Rozdział 17

Połączenie gniazd strumieniowych408-415 Gniazda strumieniowe są obsługiwane w specjalny sposób, ponieważ nowe

gniazdo musi być utworzone z odbierającego gniazda. Po pierwsze, gniazdo serwera ma być gniazdem odbierającym, czyli musi być ustawiona flaga S0_ACCEPTC0NN. (Robi to funkcja s o 1 i s t e n, strona 470-471 w tomie 2.) Następnie wywoływana jest funkcja sonewconn, by utworzyć nowe gniazdo z gniazda odbierającego. Funkcja sonewconn umieszcza również nowe gniazdo w kolejce niekompletnych połączeń odbierającego gniazda (so_q0).

Kopia nazwy związanej z odbierającym gniazdem416-418 Jeżeli odbierające gniazdo zawiera wskaźnik do bufora mbuf zawierającego

s oc ka dd r_un z nazwą związaną z gniazdem (co zawsze powinno być prawdą), to dla nowo utworzonego gniazda przy pomocy m_c o py kopiowany jest bufor mbuf.

Rysunek 17.20 pokazuje stan różnych struktur bezpośrednio przed przypisaniem so2 = so3. Wykonywane są następujące kroki:

• Struktury file, socket i unpcb, przedstawione po prawej stronie rysunku, są tworzone, gdy serwer wywołuje socket. Serwer następnie woła bi nd, co po­woduje utworzenie odnośnika do vnode i do odpowiedniego bufora mbuf zawierającego nazwę ścieżki. Serwer następnie wywołuje listen, umożliwia­jąc klientowi połączenie.

• Struktury file, socketi unpcb przedstawione w lewej części rysunku tworzo­ne są, gdy klient wywołuje socket. Klient następnie wywołuje funkcję connect, która woła unp_connect.

• Struktura socket przedstawiona pośrodku, którą nazywamy „połączonym gniazdem serwera", utworzona jest przez funkcję sonewconn, która tworzy następnie żądanie PRU_ATTACH, powodując utworzenie struktury unpcb.

• Funkcja sonewconn wywołuje również soqi nsque,by umieścić nowo utworzo­ne gniazdo w kolejce niekompletnych połączeń odbierającego gniazda (zakła­damy, że kolejka była dotąd pusta). Pokazujemy również pustą kolejkę kom­pletnych połączeń dla odbierającego gniazda (so_q i so_ql en). Człon so_head nowo utworzonej struktury socket wskazuje z powrotem na gniazdo odbierające.

• Funkcja unp_connect wywołuje m_copy, by utworzyć kopię bufora mbuf za­wierającego nazwę ścieżki związanej z odbierającym gniazdem. Na ten bufor mbuf wskazuje środkowa struktura unpcb. Zobaczymy, że kopia jest potrzebna dla odwołania systemowego getpeername.

• Zauważmy wreszcie, że nowo utworzona struktura socket nie jest jeszcze wskazywana przez strukturę f i 1 e (i rzeczywiście, zostało to zaznaczone przez ustawienie flagi SS_N0FDREF w sonewconn). Alokacja struktury file dla tej struktury soc ket, wraz z odpowiednim deskryptorem pliku, zostanie wykona­na, gdy odbierający proces serwera wywoła accept.

Wskaźnik do vnode nie jest kopiowany z gniazda odbierającego do połączonego gniazda serwera. Ta struktura vnode ma za zadanie jedynie umożliwienie klien­tom wywołującym connect znalezienie odpowiedniej struktury socket serwera, za pośrednictwem wskaźnika v_s o c k e t.

Page 281: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 17.10 Żądanie PRU_CONNECTi funkcja unp_connect 259

deskryptorklienta

soclcat{) j /

so head

so_qO

so_q01en

so_q

so_qlen

SO_J5Cb

N U L L

N U L L

0NULL

0

unpcb{}unp_socket

unp_vnode

unp_ino

unp_conn

unp_refs

unp_nextref

unp_addr

unp_cc

unp_mbcnt

mbuf {}

odbierającydeskryptorserwera

Ifile O file O

f_type f_typef_data f_data

so3socket{}

so head

so_qO

so q01en

so_q

so qlen

so_pcb

utworzona przez sonewconnunpcb{} ^ / unP3

so head

so_qO

so_q01en

so_q

so_qlen

so_pcb

MT_SONAME MT_SONAME

sockaddr_un{} zawiera nazwę

ścieżki związaną z odbierającym

gniazdem

sockaddr_un{}zawiera nazwę

ścieżki związaną z odbierającym

gniazdem

v socket

so2

N U L L

1

N U L L

0

unpcb{) / /unp2

unp_socket -► unp_socket

unp vnode unp vnode

unp_ino unp_ino

unp_conn unp_conn

unp_refs unp_refs

unp_nextref unp_nextref

unp_addr unp_addr

unp_cc unp_cc

-unp_mbcnt -unp_mbcnt

mbuf {> vnede{>

Rysunek 17.20 Różne struktury w czasie zoykonywania connect dla gniazda strumieniowego

Page 282: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

260 Protokoły domeny unixowej: implementacja Rozdział 17

Połączenie dwóch gniazd strumieniowych lub datagramowych421 Ostatnią czynnością w un p_con n ect jest wywołanie funkcji un p_co n nec 12

(pokazanej w następnym podrozdziale), co jest wykonywane zarówno dla gniazd strumieniowych, jak i datagramowych. W ten sposób powiązane zostaną ze sobą człony unp_conn środkowej i lewej struktury unpcb z rysunku 17.20 oraz nowo utworzona struktura socket zostanie przeniesiona z kolejki niekompletnych połą­czeń do kolejki kompletnych połączeń dla odbierającej struktury socket serwera. Pokażemy wynikające z tych operacji struktury danych w następnym podrozdzia­le (rysunek 17.26).

17.11 Żądanie PRU_CONNECT2 i funkcja unp_connect2Żądanie PRU_C0NNECT2, pokazane na rysunku 17.21, powstaje tylko w wyniku wykonania systemowego odwołania socketpa i r. To żądanie istnieje tylko w do­menie unixowej.

------------------------------------------------------------------------------------------------- uipc_usrrec\.c88 case PRU_C0NNECT2:89 error = unp_connect2(so, (struct socket *) nam);90 break;

------------------------------------------------------------------------------------------------- uvpc_usrreq.cRysunek 17.21 Żądanie PRU_C0NNECT2

88-90 Całe przetwarzanie tego żądania odbywa się w funkcji unp_connect2.

Funkcja ta jest również wywoływana z dwóch innych miejsc w jądrze, tak jak topokazujemy na rysunku 17.22.

Rysunek 17.22 Wywołania funkcji unp_connect2

Page 283: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 17.11___________Żądanie PRU_C0NNECT2 i funkcja unp_connect2 261

W rozdziale 17.12 opisujemy odwołanie systemowe socket pa i r i funkcję socon - nect2, a odwołanie systemowe pi pe - w rozdziale 17.13. Funkcja unp_connect2 przedstawiona jest na rysunku 17.23.

------------------------------------------------------------------------------------------------- uipc_usrreq.c426 int427 unp_connect2(so, so2)428 struct socket *so:429 struct socket *so2;430 {431 struct unpcb *unp = sotounpcb(so);432 struct unpcb *unp2;

433 if (so2->so type != so->so type)434 return (EPROTOTYPE);435 unp2 = sotounpcb(so2);436 unp->unp_conn = unp2:437 switch (so->so_type) (

438 case S 0CK_DGRAM:439 unp->unp_nextref = unp2->unp_refs440 unp2->unp_refs = unp;441 soisconnected(so);442 b r e a k ;

443 case S0CK_STREAM:444 unp2->unp_conn = unp;445 soisconnected(so);446 soisconnected(so2);447 b r e a k ;

448 default:449 p a n i c C u n p connect2");450 )451 return (0);452 )

------------------------------------------------------------------------------------------------- uipc_usrreq.cRysunek 17.23 Funkcja unp_connect2

Sprawdzenie typu gniazd426-434 Dwa argumenty funkcji są wskaźnikami do struktur socket - so łączy się

z so2. Najpierw sprawdzane jest, czy oba gniazda są tego samego typu: strumie­niowe lub datagramowe.

Połączenie pierwszego gniazda z drugim gniazdem435-436 Pierwszy blok unpcb zostaje połączony z drugim przez człon unp_conn.

Następne kroki dla gniazd datagramowych i strumieniowych są jednak różne.

Połączenie gniazd datagramowych438-442 Człony unp_nextref i unp_ref s bloku łączą gniazda datagramowe. Roz­

ważmy na przykład datagramowe gniazdo serwera związane z nazwą ścieżki /tmp/foo. Klient datagramowy łączy się z tą nazwą ścieżki. Rysunek 17.24 pokazuje odpowiednie struktury danych, po zakończeniu przetwarzania w unp_connect2. (Dla uproszczenia, nie pokazujemy odpowiednich struktur file czy socket, ani struktury vnode związanej z gniazdem pokazanym z prawej strony.) Pokazujemy dwa wskaźniki, unp i unp2, które używane są w unp_connect2.

Page 284: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

262 Protokoły domeny unixowej: implementacja_______________ Rozdział 17

Rysunek 17.24 Połączone gniazda datagramowe

Dla gniazda datagramowego, z którym nawiązano połączenie, człon unp_refs wskazuje na pierwszy blok w powiązanej liście wszystkich gniazd, które połączy­ły się z tym gniazdem. Po liście tej można się przemieszczać, śledząc wskaźnikiunp_nextref.

Rysunek 17.25 pokazuje stan trzech bloków po tym, jak trzecie gniazdo datagra­mowe (to po lewej stronie) połączyło się z tym samym serwerem / tmp/foo.

Rysunek 17.25 Kolejne gniazdo (po lewej) łączy się z gniazdem pokazanym po prawej stronie

Dwa pola bloku, unp_refs i unp_nextref, muszą być rozdzielone, ponieważ gniazdo po prawej stronie na rysunku 17.25 może samo połączyć się z innym gniazdem datagramowym.

Połączenie gniazd strumieniowych443-447 Połączenie gniazda strumieniowego różni się od połączenia gniazda datagra­

mowego, ponieważ z gniazdem strumieniowym (serwerem) może połączyć się tylko jedno gniazdo klienta. Człony u n p_c o n n obu bloków wskazują na blok partnera, tak jak pokazano na rysunku 17.26. Rysunek ten jest kontynuacją rysunku 17.20.

Page 285: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 17.11 Żądanie PRU_C0NNECT2 i funkcja unp_connect2 263

odbierającydeskryptor deskryptor

klienta serwera

fila O file O

f_type

f data

socketf >

so head

so_qO

so gOlen

so_q

so_qlen

so_pcb

unpcb{}

N U L L

N U L L

0N U L L

0

, unPUtworzona przez sonewconn

unpcb{) ^ unP2 unpcb{)

MT_SONAME MT_SONAME

sockaddr un{| sockaddr un{}zawiera nazwę zawiera nazwę

ścieżki związaną ścieżki związanąz odbierającym z odbierającym

gniazdem gniazdem

unp_socket

unp vnode

unp_ino

unp_conn

unp_refs

unp_nextref

- unp__addr

unp_cc

unp mbcnt

vnode{}

Rysunek 17.26 Połączone gniazda strumieniowe

Page 286: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

264 Protokoły domeny unixowej: implementacja Rozdział 17

Kolejną zmianą w tym schemacie jest fakt, że wywołanie soisconnectedz argu­mentem so2 przenosi gniazdo z kolejki niekompletnych połączeń odbierającego gniazda (so_qO na rysunku 17.20) do kolejki kompletnych połączeń (so_q). Z tej kolejki gniazdo zostanie pobrane przez accept (strona 474 w tomie 2). Zauważmy, że soi sconnected (strona 479, tom 2) ustawia również flagę SS_ISCONNECTED w so_state. soisconnected przenosi gniazdo z kolejki niekompletnych połą­czeń do kolejki kompletnych połączeń tylko wtedy, jeśli wskaźnik s o_h e a d gniaz­da jest niezerowy. (Jeśli wskaźnik so_head jest zerowy, to gniazdo nie znajduje się ani w jednej, ani w drugiej kolejce.) Dlatego pierwsze wywołanie soi sconnected na rysunku 17.23 z argumentem so zmienia tylko so_state.

17.12 Odwołanie systemowe socketpairOdwołanie systemowe socketpai r istnieje tylko w domenie unixowej. Odwoła­nie to tworzy i łączy dwa gniazda, zwracając dwa deskryptory wzajemnie połą­czone ze sobą. Na przykład proces użytkownika wykonuje

int fd[2];socketpai r( P F JJNIX, SOCK_STREAM, 0, fd);

by utworzyć parę dwukierunkowych (full-duplex) wzajemnie połączonych stru­mieniowych gniazd domeny unbcowej. Pierwszy deskryptor jest zwracany w f d [ 0 ], a drugi w f d Cl]. Jeżeli drugim argumentem jest S0CK_DGRAM, zostaje utworzona para połączonych gniazd datagramowych domeny unbcowej. socketpai r zwra­ca wartość 0, jeżeli gniazda zostały utworzone pomyślnie, lub -1, w przypadku błędu.

Na rysunku 17.27pokazano implementację odwołania systemowego socketpai r.

------------------------------------------------------------------------------------------------- uipc_syscałls.c229 struct socketpair_args (230 int domain;231 int t y p e ;232 i nt prot o co l:233 int *rsv;234 I;

235 socketpair(p, uap. retv a l)236 struct proc *p;237 struct socketpair_args *uap;238 int retva1[ ]:239 (240 struct filedesc *fdp = p - >p_fd:241 struct file *fpl, *fp2;242 struct socket *sol, *so2;243 int fd, error, s v [2 ] :

244 if (error = socreate(uap->domain, &sol, uap->type. uap->protocol))245 return (error);246 if (error = socreate(uap->doinain, &so2, u a p O t y p e , uap->protocol))247 goto freel;

248 if (error = falloc(p, &fpl. &fd))249 goto free2;250 sv[0] = fd;251 f p l ->f_f1 ag = FREAD I FWRI TE ;252 fpl->f_type = DTYPE_S0CKET;

Page 287: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 17.12 Odwołanie systemowe socketpair 265

253254

255256257258259260 261

262263264265266267268269270271272273274

275276277278279280281282283284285286 }

------------------------------------------------------------------------------------------------- uipc_syscalls.cRysunek 17.27 Odwołanie systemowe socketpa i r

Argumenty229-239 Cztery argumenty typu całkowitego, poczynając od domain po rsv, są

argumentami, które zostały użyte w przykładowym wywołaniu socketpa i r przez użytkownika na początku tego podrozdziału. Trzy argumenty pokazane w defini­cji funkcji socketpair (p, uap i retval) są argumentami przekazywanymi do odwołania systemowego przez jądro.

Utworzenie dwóch gniazd i dwóch deskryptorów244-261 Funkcja socreate jest wołana dwukrotnie, tworząc dwa gniazda. Pierwszy

z dwóch deskryptorów zostaje alokowany przez f a 11 oc. Wartość deskryptora jest zwracana w fd, a wskaźnik do odpowiadającej struktury f i 1 e - w f pl. Ustawione zostają flagi FREAD i FWRITE (ponieważ mamy do czynienia z gniazdem dwukie­runkowym - fuli duplex), ustalony jest typ pliku DTYPE_S0CKET, wskaźnik f_ops jest ustawiony tak, by wskazywać na tablicę pięciu wskaźników funkq'i (rysunek 15.13 na stronie 460 w tomie 2), a wskaźnik f_data na strukturę socket. Drugi deskryptor jest alokowany przez fal 1 oc i odpowiednia struktura file zostaje zainicjowana.

fpl->f_ops = Łsocketops; fpl->f_data = (caddr_t) sol;

if (error = fal 1o c ( p , &fp2, &fd)) goto free3;

fp2->f_flag = FREAD I FWRITE;■ fp2->f_type = DTYPE_S0CKET;

fp2->f_ops = Jsocketops; fp2->f_data = (caddr_t) so2; s v C1] = fd;

if (error = soconnect2(sol, so2)) goto free4;

if (uap->type == S0CK_DGRAM) I /** Połączenie gniazda datagramowego jest asymetryczne.*/

if (error = soconnect2(so2, sol)) goto free4;

]error = c op yout((c ad dr_t) sv, (caddr_t) uap->rsv. 2 * si zeof(int)); retval[0] = s v[0]; /* XXX ??? */retval[1] = sv [1]: /* XXX ??? */return (error);

f r e e 4 :f free(fp2);fdp->fd_ofiles[sv[l]] = 0;

f r e e 3 : ffre et f pl );fdp->fd_ofi1 e s [s v[0]] = 0;

f r e e 2 :(void) soclose(so2);

f r e e l :(void) soclose(sol); return (error);

Page 288: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

266 Protokoły domeny unixowej: implementacja_______________ Rozdział 17

Połączenie dwóch gniazd262-270 soconnect2 tworzy żądanie PRU_C0NNECT2, które istnieje tylko w domenie

unbcowej. Jeżeli odwołanie systemowe tworzy gniazda strumieniowe, to po wyko­naniu soconnect2 otrzymujemy układ struktur pokazany na rysunku 17.28.

Jeżeli tworzone są dwa gniazda datagramowe, wymagane są dwa wywołania soconnect2, przy czym każde wywołanie powoduje ustanowienie połączenia w jednym kierunku. Po drugim wywołaniu otrzymujemy układ struktur pokaza­ny na rysunku 17.29.

Page 289: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 17.12 Odwołanie systemowe socketpair 267

Kopiowanie dwóch deskryptorów z powrotem do procesu271 -274 copyout kopiuje dwa deskryptory z powrotem do procesu.

Dwie instrukcje z komentarzami XXX ? ? ? po raz pierwszy pojawiły się w systemie 4.3BSD Reno. Są one niepotrzebne, ponieważ dwa deskryptory są zwracane do procesu przez c o py o u t . Zobaczymy, że odwołanie systemowe pipę zwraca oba deskryptory ustawiając retval[0]iretval[l], gdzie retval jest trzecim argumentem odwołania systemowego. Asemblerowa procedura w jądrze, obsługująca odwołania systemowe, zawsza zwraca dwie wartości całkowite retval [0] i retval [1 ] w rejestrach procesora, jako część wyni­ku przetworzenia dowolnego odwołania systemowego. Procedura asemblerowa procesu użytkownika wywołująca odwołanie systemowe musi być odpowiednio zaprogram owa­na, tak by wykorzystywała wartości zawarte w rejestrach i zwracała je, tak jak tego oczekuje proces. Funkcja pi pe w bibliotece C rzeczywiście działa w taki sposób, w prze­ciwieństwie do funkcji socketpa i r.

Page 290: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

268 Protokoły domeny unixowej: implementacja Rozdział 17

Funkcja soconnect2

Funkcja ta (pokazana na rysunku 17.30) tworzy żądanie P RU_C0N N ECT2. Jest ona wywoływana jedynie przez odwołanie systemowe socketpai r .

------------------------------------------------------------------------------------------------- uipc_socket.c225 soconnectZtsol, so2)226 struct socket *sol;227 struct socket *so2;228 (229 i nt s = sp l net();230 int error;

231 error = (*sol->so_proto->pr_usrreq) (sol, PRU_C0NNECT2,232 (struct mbuf *) 0, (struct mbuf *) so2, (struct mbuf *) 0);233 spl x (s );234 return (error);235 )

------------------------------------------------------------------------------------------------- uipc_syscalls.cRysunek 17.30 Funkcja soconnectZ

17.13 Odwołanie systemowe pipęOdwołanie systemowe pipę, pokazane na rysunku 17.31, jest niemal identyczne z odwołaniem systemowym socketpair.

------------------------------------------------------------------------------------------------- uipc_syscalls.c645 pipe(p, uap, retval)646 struct proc *p;647 struct pipe_args *uap;648 int retval[];649 (650 struct filedesc *fdp = p->p_fd;651 struct file *rf, *wf;652 struct socket *rso, *wso;653 int fd, error;

654 if (error = socreate(AF_UNIX, &rso, S0CK_STREAM, 0))655 return (error);656 if (error = socreate(AF_UNIX, &wso, S 0C K _STREAM, 0))657 goto freel;658 if (error = falloc(p, &rf, & f d ))659 goto free2;660 retval[0] = fd;661 rf->f_flag = FREAD;662 rf->f_type = DTYPE_S0CKET;663 rf->f_ops = Ssocketops;664 rf->f_data = (caddr_t) rso;665 if (error = falloctp, &wf, & f d ))666 goto free3;667 wf->f_flag = FWRITE;668 wf->f_type = DTYPE_S0CKET;669 wf->f_ops = Łsocketops;670 wf->f_data = (caddr_t) wso;671 retval[1] = fd;672 if (error = unp_connect2(wso, rso))673 goto free4;674 return (0);675 free4:676 ffree(wf);677 fdp->fd_ofi 1es[retval[1]] = 0;678 free3:

Page 291: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 17.14 Żądanie PRU_ACCEPT 269

679 ffree(rf);680 fdp->fd_ofiles[retval[0]] = 0;681 f r e e 2 :682 (void) soclose(wso);683 freel:684 (void) soclosetrso);685 return (error);686 ]------------------------------------------------------------------------------------------------- uipc_syscalls.cRysunek 17.31 Odwołanie systemowe pipę

645-686 Wy wołania funkcji socreate tworzą dwa gniazda domeny unbcowej. Jedy­na różnica pomiędzy tym odwołaniem systemowym a odwołaniem systemowym pipę polega na tym, iż p i pe ustala, że pierwszy z dwóch deskryptorów może być tylko czytany (read-only), a drugi tylko zapisywany (write-only); oba deskryptory są zwracane przez argument ret val , a nie przez copyout. Ponadto pi pe wywołuje unp_connect2 bezpośrednio, a nie poprzez soconnect2.

Niektóre wersje Unixa, na przykład SVR4, tworzą potoki (pipes) z prawem zapisu i odczy­tu dla obu końców.

17.14 Żądanie PRU_ACCEPTWiększość czynności związanych z akceptacją nowego połączenia dla gniazda strumieniowego jest wykonywanych przez inne funkcje jądra: s on ewc on n tworzy nową strukturę socket i generuje żądanie PRU_ATTACH, a odwołanie systemowe accept usuwa gniazdo z kolejki kompletnych połączeń i wywołuje soaccept. Ta ostatnia funkcja (strona 475 w tomie 2) tworzy tylko żądanie PRU_ACCEPT, co dla domeny unixowej pokazujemy na rysunku 17.32.

------------------------------------------------------------------------------------------------- uipc_usrreq.c94 case PRU ACCEPT:95 /*96 * Nazwa połączonego gniazda zostaje przekazana z powrotem,97 * jeżeli gniazdo było związane i wciąż jesteśmy połączeni98 * (nasz partner mógł już zamknąć połączenie !).99 */

100 if (unp->unp_conn && unp->unp_conn->unp_addr) {101 nam->m_len = unp->unp_conn->unp_addr->m_len:102 bcopy(mtod(unp->unp_conn->unp_addr. ca d dr_t).103 mtod(nam, caddr_t), (unsigned) nam->m_len);104 1 else 1105 nam->m_len = sizeof(sun_noname);106 *(mtod(nam, struct sockaddr *)) = sun noname;107 )108 b r e a k ;

------------------------------------------------------------------------------------------------- uipc_usrreq.cRysunek 17.32 Żądanie PRU_ACCEPT

Zwrócenie nazwy ścieżki klienta94-108 Jeżeli klient wywołał funkcję bind i jeśli jest nadal połączony, żądanie

PRU_ACCEPT kopiuje strukturę sockaddr_un zawierającą nazwę ścieżki klienta do

Page 292: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

270 Protokoły domeny unixowej: implementacja_______________ Rozdział 17

bufora mbuf wskazywanego przez argument nam. W przeciwnym przypadku zostaje zwrócona pusta nazwa ścieżki (sun_noname).

17.15 Żądanie PRU_DISCONNECT i funkcja unp_disconnectJeżeli gniazdo jest połączone, odwołanie systemowe tworzy żądanie PRILDISCONNECT (rysunek 17.33).

------------------------------------------------------------------------------------------------- uipc_syscalls.c91 case PRU_DISCONNECT:92 unp_disconnect(u n p );93 break;

------------------------------------------------------------------------------------------------- uipc_syscolls.cRysunek 17.33 Żądanie PRU_DISCONNECT

91-93 Całe przetwarzanie jest wykonane w funkcji unp_di sconnect (rysunek 17.34.)

------------------------------------------------------------------------------------------------- uipcjusrreą.c453 void454 unp_disconnect(unp)455 struct unpcb *unp;456 {457

458459460461

462463464465466467468469470471472473474475476477478

479480481482483484485 )------------------------------------------------------------------------------------------------- uipcjusrrecj.cRysunek 17.34 Funkcja u n p _ d i s c o n n e c t

struct unpcb *unp2 = unp->unp_conn;

i f (unp2 == 0) r et ur n ;

unp->unp_conn = 0; switch (unp->unp_socket->so_type) (

case S 0 CK_DGRAM:if (unp2->unp_refs == unp)

unp2->unp_refs = unp->unp_nextref; else (

unp2 = unp2->unp_refs; for (;;) 1

if (unp2 == 0)panic("unp_disconnect'');

if (unp2->unp_nextref == unp) b r e a k ;

unp2 = unp2->unp_nextref;)unp2->unp_nextref = unp->unp_nextref;

)unp->unp_nextref = 0;unp->unp_socket->so_state &= ~SS_ISCONNECTED; b r e a k ;

case SOCK_STREAM;soi sdi sconnected(unp->unp_socket); unp2->unp_conn = 0; soi sdi sconnected(u np2->unp_socket); b r e a k ;

Page 293: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 17.15 Żądanie PRU_DISCONNECT i funkcja unp_disconnect 271

Sprawdzenie, czy gniazdo jest połączone458-460 Jeżeli to gniazdo nie jest połączone z innym gniazdem, funkcja zakańcza

przetwarzanie natychmiast. W przeciwnym razie człon unp_conn otrzymuje war­tość 0, by zaznaczyć, że to gniazdo nie jest połączone z innym.

Usunięcie zamykanego datagramowego PCB z powiązanej listy462-478 Ten fragment kodu usuwa blok PCB odpowiadający zamykanemu gniazdu

z powiązanej listy połączonych datagramowych bloków PCB. Na przykład, jeżeli zaczniemy od rysunku 17.25 i zamkniemy lewe gniazdo, otrzymamy struktury danych przedstawione na rysunku 17.35. Ponieważ wskaźnik unp2->unp_refs jest równy unp (zamykany PCB znajduje się na początku powiązanej listy), wskaźnik un p_next ref zamykanego, staje się początkiem powiązanej listy.

Jeżeli jeszcze raz zaczniemy od rysunku 17.25 i zamkniemy środkowe gniazdo, otrzymujemy struktury danych przedstawione na rysunku 17.36. Tym razem blok PCB odpowiadający zamykanemu gniazdu nie znajduje się na początku powiąza­nej listy. Wskaźnik unp2 otrzymuje początkową wartość odpowiadającą początko­wi listy i poszukiwany jest blok poprzedzający zamykany PCB. unp2 pozostawio­ny zostaje z wartością odpowiadającą temu blokowi (lewy blok na rysunku 17.36). Wskaźnik unp_nextref zamykanego PCB jest następnie kopiowany do pola unp_nextref poprzedzającego (unp).

Zakończenie rozłączania gniazda strumieniowego479-483 Ponieważ strumieniowe gniazdo domeny unixowej może być połączone

tylko z jednym partnerem, rozłączanie jest prostsze, bowiem powiązana lista nie jest używana. Wskaźnik unp_conn partnera otrzymuje wartość 0 i funkcja soi sdi sconnected wywoływana jest dla obu gniazd.

Page 294: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

272 Protokoły domeny unixowej: implementacja Rozdział 17

unp2 f unp zamknięte gniazdo \unpcb{) / unpcb{) \ unpcb{)

--------

unp_conn unp_conn NULL unp_conn NULLunp refs NULL unp_refs NULL ^ ----- -unp_refs

unp_nextref NULL unp_nextref NULL f unp_nextref NULL

connect("/tmp/foo") connect("/tmp/foo") J bind("/tmp/foo’)

V.

Rysunek 17.36 Struktury danych z rysunku 17.25 po zamknięciu środkowego gniazda

17.16 Żądanie PRU_SHUTDOWN i funkcja unp_shutdownŻądanie PRU_SHUTDOWN pokazane na rysunku 17.37 zostaje utworzone, gdy proces woła shutdown i zapobiega dalszemu wysyłaniu jakichkolwiek danych.

------------------------------------------------------------------------------------------------- uipcjusrreą.c109 case PRU_SHUTD0WN:110 socantsendmore(so):111 unp_shutdown(unp);112 break;------------------------------------------------------------------------------------------------- uipc_usrreq.cRysunek 1 7 3 7 Żądanie PRU_SHUTDOm

109-112 socantsendmore ustawia flagi gniazda, tak by wysyłanie jakichkolwiek dalszych danych było zablokowane. Następnie wołana jest funkcja unp_shutdown (pokazana na rysunku 17.38).

------------------------------------------------------------------------------------------------- uipc_usrrecj.c494 void495 unp_shutdown(unp)496 struct unpcb *unp;497 (498 struct socket *so;

499 if (unp->unp_socket->so_type == S0CK_STREAM && unp->unp_conn &&500 (so = unp->unp_conn->unp_socket))501 socantrcvmore(so):502 )------------------------------------------------------------------------------------------------- uipcjusrreą.cRysunek 17.38 Funkcja u n p _ s h u t d o w n

Powiadomienie partnera dla gniazda strumieniowego499-502 W przypadku gniazda datagramowego nie robi się nic. Jeżeli jednak gniaz­

do jest gniazdem strumieniowym ciągle połączonym z partnerem i partner ciągle posiada strukturę socket, dla gniazda partnera wołana jest funkcj asocantrcvmore.

Page 295: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 17.17 Żądanie PRU_ABO RT i funkcja unp_drop 273

17.17 Żądanie PRU_ABORT i funkcja unp_dropNa rysunku 17.39 pokazane jest żądanie PRU_AB0RT/ generowane przez socl ose, jeśli gniazdo jest gniazdem odbierającym, i połączenia ciągle oczekują w kolejce, socl ose generuje żądanie PRU_AB0RT dla każdego gniazda w kolejce niekomplet­nych połączeń oraz dla każdego gniazda w kolejce kompletnych połączeń (strona 488 w tomie 2).

------------------------------------------------------------------------------------------------ uipc_usrreq.c209 case PRU_AB0RT:210 unp_drop(unp, ECONNABORTED);211 break;

------------------------------------------------------------------------------------------------- uipc_usrreq.cRysunek 17.39 Żędanie PRU_AB0RT

209-211 Funkcja unp_drop (pokazana na rysunku 17.40) generuje błąd ECONNABORTED. Na rysunku 17.14 widzieliśmy, że unp_detach również wywołuje unp_drop z ar­gumentem ECONNRESET.

------------------------------------------------------------------------------------------------- uipc_usrreq.c503 void504 unp_drop(unp, errno)505 struct unpcb *unp;506 int errno;507 (508 struct socket *so = unp->unp_socket;

509 so->so_error = errno;510 unp_disconnecttunp);511 if (so->so_head) (512 so->so_pcb = (caddr_t) 0;513 m_freem(unp->unp_addr);514 (void) m_free(dtom(unp));515 sofree(so);516 }517 )

------------------------------------------------------------------------------------------------- uipc_usrreq.cRysunek 17.40 Funkcja u n p _ d r o p

Zachowanie symbolu błędu i rozłączenie gniazda509-510 Wartość so_error gniazda zostaje ustalona i jeżeli gniazdo jest połączone,

wywołana zostaje funkcja unp_di sconnect.

Usunięcie struktur danych w kolejce odbiorczej serwera511-516 Jeżeli wskaźnik gniazda s o_h e a d jest niepusty, oznacza to, że gniazdo znaj­

duje się aktualnie w kolejce niekompletnych połączeń lub w kolejce kompletnych połączeń gniazda odbierającego. Wskaźnik struktury od socket do unpcb otrzy­muje wartość 0. Wywołanie m_freem zwalnia bufor mbuf zawierający nazwę związaną z odbierającym gniazdem (przypominamy rysunek 17.20), a wywołanie m_f r e e zwalnia strukturę unpcb. sofree zwalnia strukturę socket. Gniazdo znaj­dujące się w którejś z dwóch kolejek odbiorczych serwera nie może mieć skojarzo­

Page 296: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

274 Protokoły domeny unixowej: implementacja_______________ Rozdział 17

nej struktury file, ponieważ struktura taka jest alokowana przez accept przy usuwaniu gniazda z kolejki kompletnych połączeń.

17.18 Różne żądaniaRysunek 17.41 pokazuje sześć pozostałych żądań.

------------------------------------------------------------------------------------------------- uipc_usrreq.c212 case PRU_SENSE:213 ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat214 if (so->so_type == S0CK_STREAM && unp->unp_conn != 0)215 so2 = unp->unp_conn->unp_socket:216 ((struct stat *) m)->st blksize += so2->so rcv.sb217 1218 ((struct stat *) m)->st_dev = N 0 0 E V :219 i f (unp->unp_ino == 0)220 unp->unp_ino = unp_ino++;221 ((struct stat *) m)->st_ino = unp->unp_ino;222 return (0);

223 case PRU RCVOOB:224 return (EOPNOTSUPP):

225 case PRILSENDOOB:226 error = EOPNOTSUPP;227 b r e a k ;

228 case PRU_SOCKADDR:229 if (unp->unp_addr) (230 nam->m_len = unp->unp_addr->m_len;231 bcopy(mtod(unp->unp_addr, caddr _ t),232 mtod(nam, caddr_t), (unsigned) nam->m_len);233 ) else234 nam->m_len = 0;235 break;

236 case PRU_PEERADDR:237 if (unp->unp_conn && unp->unp_conn->unp_addr) (238 nam->m_len - unp->unp_conn->unp_addr->m_len;239 bcopy(mtod(unp->unp_conn->unp_addr. cadd r_ t) ,240 mtodtnam, caddr_t), (unsigned) nam->m_len);241 1 else242 nam->m_len = 0;243 break;

244 case PRU_SL0WTIMO:245 b r e a k ;

------------------------------------------------------------------------------------------------- uipc_usrrecj.cRysunek 17.41 Różne żądania PRU_xxx

Żądanie PRLLSENSE212-217 To żądanie jest generowane przez odwołanie systemowe f stat. Aktualna

wartość znaku przepełnienia bufora wysyłkowego gniazda zostaje zwrócona jako człon st_bl ksi ze struktury stat. Dodatkowo, jeśli gniazdo jest gniazdem stru­mieniowym, do tej wartości dodana zostaje liczba bajtów znajdujących się w tym momencie w buforze odbiorczym gniazda partnera. Gdy będziemy omawiać żą­danie PRU_SEND w rozdziale 18.2, zobaczymy, że suma tych dwóch wartości jest prawdziwą pojemnością „łącznika" pomiędzy dwoma połączonymi gniazdami strumieniowymi.

Page 297: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 17.18 Różne żądania 275

218 Człon st_dev otrzymuje wartość N0DEV (wartość stała zawierająca wszyst­kie bity równe 1, reprezentująca nie istniejące urządzenie).

219 - 221 Węzły i-node identyfikują pliki w systemie plików. Wartość zwrócona jako numer i-node gniazda domeny unbcowej (człon st_ino struktury stat) jest po prostu jednoznaczną wartością otrzymaną ze zmiennej globalnej unp_i no. Jeżeli jeden z takich fałszywych numerów i-node nie został jeszcze przypisany do stru­ktury unpcb, wartość zmiennej globalnej un p_i no zostaje przypisana, a następnie zmienna ta jest inkrementowana. Używamy określenia „fałszywy", ponieważ nu­mery te nie odpowiadają plikom rzeczywiście istniejącym w systemie plików. Są one po prostu tworzone w miarę potrzeb z wartości globalnego licznika. Jeżeli gniazda domeny unixowej musiałyby być związane z nazwą ścieżki w systemie plików (co nie jest wymagane), żądanie PRU_SENSE mogłoby używać wartości st_dev oraz st_i no odpowiadających dowiązanej nazwie ścieżki.

Zmienna globalna unp_i no powinna być inkrementowana przed przypisaniem wartości, a nie po przypisaniu. Przy pierwszym wywołaniu f s t a t dla gniazda domeny unixowej po przeładowaniu jądra, wartość wpisana do bloku unpcb gniazda będzie równa 0. Jeśli jednak f s t a t wywołana zostanie jeszcze raz dla tego samego gniazda, ponieważ zacho­wana wartość jest 0, aktualna niezerowa wartość unp_i no będzie wpisana do PCB.

Żądania PRU_RCV00B i PRU.SENDOOB223 - 227 Dane przesyłane zwiększonym priorytetem (out-of-band) nie są obsługiwane

przez domenę rumową.

Żądanie PRU.SOCKADDR228-235 To żądanie zwraca adres protokołu (nazwę ścieżki w przypadku domeny

unixowej). Jeśli nazwa ścieżki została dowiązana do gniazda, unp_addr wskazuje na strukturę mbuf zawierającą sockaddr_un z tą nazwą. Argument nam funkcji uipc_usrreq wskazuje na bufor mbuf alokowany przez wołającą procedurę - w której przekazany będzie wynik. m_copy robi kopię struktury adresowej gniaz­da. Jeżeli ścieżka nie została dowiązana do gniazda, pole długości otrzymanego bufora mbuf otrzymuje wartość 0.

Żądanie PRU_PEERADDR236-243 To żądanie jest obsługiwane podobnie do poprzedniego żądania, z tym że

wymagana nazwa ścieżki to nazwa związana z gniazdem połączonym z wywołu­jącym gniazdem. Jeżeli wywołujące gniazdo zostało połączone z partnerem, war­tość unp_conn będzie niezerowa.

Obsługa przez te dwa żądania gniazda, które nie ma dowiązanej nazwy ścieżki jest inna niż w przypadku żądania PRILACCEPT (rysunek 17.32). Odwołania systemowe getsockname i getpeername zwracają wartość 0 w swoim trzecim argumencie, gdy brakuje nazwy. Natomiast funkcja a ccept w swoim trzecim argumencie zwraca wartość16 i nazwa ścieżki, zawarta w strukturze sockaddr_un zwróconej w drugim argumencie, zawiera tylko bajt zerowy. (Przypominamy, że sun_noname jest ogólną strukturą soc­kaddr i jej rozmiar wynosi 16 bajtów.)

Page 298: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

276 Protokoły domeny unixowej: implementacja_______________ Rozdział 17

Żądanie PRU_SLOWTIMO244-245 To żądanie nigdy nie powinno być wygenerowane, ponieważ protokoły

domeny unixowej nie używają żadnych zegarów (liczników czasu).

17.19 PodsumowanieImplementaqa protokołów domeny unbcowej, którą przedstawiliśmy w tym roz­dziale, jest nieskomplikowana i oczywista. Udostępnione są gniazda strumienio­we i datagramowe, przy czym gniazda strumieniowe podobne są do TCP, gniazda datagramowe zaś do UDP.

Do gniazd domeny unixowej mogą zostać dowiązane nazwy ścieżek. Serwer dowiązuje (bind) swoją dobrze-znaną nazwę ścieżki (well-known pathname), a klient łączy się (connect) z tą ścieżką. Gniazda datagramowe mogą również zostać połączone i - podobnie jak w przypadku UDP - więcej niż jeden klient może połączyć się z jednym serwerem. Nienazwane gniazda domeny unixowej również mogą być utworzone przy pomocy funkcji socketpa i r. Unixowe odwo­łanie systemowe pi pe tworzy dwa połączone wzajemnie gniazda domeny unixo- wej. Potoki w systemach wywodzących się z systemu Berkeley są w rzeczywisto­ści gniazdami strumieniowymi domeny unixowej.

Blokiem kontrolnym używanym z gniazdami domeny unixowej jest struktura unpcb. Te bloki - w przeciwieństwie do innych domen - nie są jednak przechowy­wane w postaci powiązanej listy. W zamian, gdy gniazdo domeny unbcowej musi znaleźć inne gniazdo domeny unbcowej (przy connect lub sendto), blok kontrol­ny u n p c b przeznaczenia zos taje znaleziony przez należącą do jądra funkcję poszu­kiwania nazwy ścieżki (namei). Funkcja ta znajduje strukturę vnode, a ta z kolei pozwala odszukać unpcb.

Page 299: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Protokoły domeny unixowej: 1/0 i przekazywanie deskryptorów

18

18.1 WstępW tym rozdziale kontynuujemy rozpoczętą w poprzednim rozdziale prezentację implementacji protokołów domeny unixowej. Najpierw omówimy operacje wej­ścia/wyjścia (I/O ) - żądania PRU_SEND i PRU_RCVD, a następnie zajmiemy się przekazywaniem deskryptorów.

18.2 Żądania PRU_SEND i PRU_RCVDŻądanie P RU_S E N D zostaje utworzone zawsze, gdy proces wpisuje dane lub infor­mację kontrolną do gniazda domeny unbcowej. Pierwsza część żądania, przetwa­rzająca informację kontrolną, a następnie gniazda datagramowe, jest pokazana na rysunku 18.1.

Przetworzenie informacji kontrolnej na format wewnętrzny141 -142 Jeżeli proces przekazał informację kontrolną używając sendmsg, to funkq'a

unp_i nternal i ze zamienia wbudowane deskryptory na wskaźniki file. Oma­wiamy tę funkqę w rozdziale 18.4.

Tymczasowe połączenie niepołączonego gniazda datagramowego146-153 Jeżeli proces przekazuje strukturę adresową gniazda zawierającą adres

przeznaczenia (tzn. argument n a m jest niepusty), gniazdo nie może być połączone. Gdy gniazdo jest połączone, zwracany jest komunikat o błędzie EI SC 0 N N . Niepołą­czone gniazdo zostaje połączone przez unp_connect. (To tymczasowe łączenie niepołączonego gniazda datagramowego przypomina kod UDP pokazany na stro­nie 788 w tomie 2.)

154-159 Jeżeli proces nie przekazał adresu przeznaczenia, zwrócony zostaje błąd ENOTCONN dla niepołączonego gniazda.

Przekazanie adresu nadawcy160-164 so2 wskazuje na strukturę socket gniazda przeznaczenia. Jeżeli wysyłające

gniazdo ma dowiązaną nazwę ścieżki, wskaźnik from wskazuje na strukturę sockaddr_un zawierającą nazwę ścieżki. W przeciwnym przypadku from wska­zuje na sun_noname, która jest strukturą sockaddr_un z zerowym pierwszym bajtem nazwy ścieżki.

Page 300: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

278 Protokoły domeny unixowej: 1/0 i przekazywanie deskryptorów_______ Rozdział 18

------------------------------------------------------------------------------------------------- uipc_usrrea.c140 case PRU_SEND:141 if (control && (error = unp_internalize(control, p)))142 break;143 switch (so->so_type) I

144 case S OCK_DGRAM;{145 struct sockaddr *from;

146 if (nam) (147 if (unp->unp_conn) {148 error = EISCO N N;149 break;150 1151 error = unp_connect(so. nam, p);152 if (error)153 break;154 } else (155 if (unp->unp_conn == 0) {156 error = EN0TC0NN;157 break;158 )159 )160 so2 = unp->unp_conn->unp_socket:161 if (unp->unp_addr)162 from = mtod(unp->unp_addr, struct sockaddr *);163 else164 from = &sun_noname;165 if (sbappendaddr(&so2->so_rcv, from, m, control)) (166 sorwakeup(so2);167 m = 0;168 control = 0;169 ] else170 error = ENOBUFS;171 if (nam)172 unp_disconnect(unp);173 break;174 )

Rysunek 18.1 Żądanie PRU_SEND dla gniazd datagramowychutpcjusrrecj.c

Jeżeli nadawca datagramu domeny unbcowej nie zwiąże nazwy ścieżki z gniazdem, odbior­ca datagramu nie może wysłać odpowiedzi, ponieważ nie zna adresu przeznaczenia (czyli nazwy ścieżki), który powinien być użyty w wywołaniu sendto. Inaczej jest w przypadku UDP, gdzie efemeryczny port zostaje automatycznie przypisany do niezwiązanego gniazda datagramowego, przy pierwszym przesłaniu datagramu do gniazda. UDP może automatycznie wybrać numer portu dla aplikacji między innymi dlatego, że odpowiednie numery portów używane są tylko przez UDP. Nazwy ścieżek nie są jednak zarezerwowane dla gniazd domen unixowych. Automatyczne wybranie nazwy ścieżki dla niezwiązanego gniazda domeny unixowej mogłoby prowadzić do konfliktów w późniejszym czasie. Odpowiedź może być wymagana lub nie, w zależności od aplikacji. Funkcja s y s 1 o g nie związuje ścieżki z datagramowym gniazdem domeny unixowej. Funkcja ta jedynie wysy­ła komunikat do lokalnego demona sy s 1 ogd i nie oczekuje odpowiedzi.

Dołączenie informacji kontrolnej, adresu i danych do kolejki odbiorczej gniazda165-170 sbappendaddr dołącza informację kontrolną (jeśli istnieje), adres nadawcy

i dane do kolejki odbiorczej odbierającego gniazda. Jeżeli zostaje to przeprowa­dzone pomyślnie, to funkcja sorwakeup „budzi" procesy oczekujące na odbiór danych i wskaźniki m oraz control otrzymują wartość 0, by zapobiec zwolnieniu tych wskaźników na końcu funkcji (rysunek 17.10). W przypadku błędu (prawdo­podobnie z powodu braku miejsca na dane, adres lub informację kontrolną w ko­lejce odbiorczej), zwrócony zostaje komunikat ENOBUFS.

Page 301: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 18.2 Żądania PRU_SEND i PRU_RCVD 279

Obsługa tego błędu jest inna niż dla UDP. W przypadku datagramowego gniazda dome­ny unbcowej nadawca otrzymuje komunikat o błędzie powstałym w wyniku własnej operacji wyjściowej zakończonej błędem spowodowanym brakiem miejsca w kolejce odbiorczej. W przypadku UDP nadawca uznaje, że operacja wyjścia zakończyła się po­myślnie, jeżeli nie brakuje miejsca w kolejce wyjściowej interfejsu. Jeżeli odbierający moduł UDP stwierdza, że brak jest miejsca w kolejce odbierającego gniazda, wysyła zwykle do nadawcy komunikat ICMP o nieosiągalnym porcie. Nadawca nie otrzyma jednak tego komunikatu, chyba, że połączy się z odbiorcą (tak jak to opisano na stronach 774-775 w tomie 2).Dlaczego nadawca w domenie unbcowej nie zostaje zablokowany, a zamiast tego otrzy­muje komunikat ENOBU FS? Gniazda datagramowe są tradycyjnie uważane za zawodne i nie dające gwarancji dostarczenia danych. W opracowaniu [Rago 1993] stwierdza się, że w SVR4 jest to zależne od dostawcy systemu, czy włączyć w trakcie kompilacji jądra kontrolę przepływu dla datagramowych gniazd domeny unbcowej, też czy nie.

Rozłączenie tymczasowo połączonego gniazda171-172 u n p_d isconnect rozłącza połączone gniazdo.

Na rysunku 18.2 przedstawione jest przetwarzanie żądania PRU_SEND dla gniazdstrumieniowych.

------------------------------------------------------------------------------------------------- uipc_usrreq.c175 case S0CK_STREAM:176 y/defi ne rcv (&so2->so_rcv)177 #defi ne snd (&so->so_snd)178 if (so->so_state & SS_CANTSENDM0RE) l179 error = EPIPE;180 b r e a k :181 )182 if (unp->unp_conn == 0)183 panicC"uipc 3");184 so2 = unp->unp conn->unp socket;185 /*186 * Wysłanie do odpowiedniego odbierającego portu.187 * Znak przepełnienia zostaje zmniejszony, by zachować

* odpowiednie "ciśnienie".188 * Obudzenie procesów czytających.189 */190 if (control) {191 if (sbappendcontrol(rcv, m, control))192 control = 0:193 ) else194 sbappendtrcv, m);195 snd->sb_mbmax -=196 rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt;197 unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt;198 snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc;199 unp->unp_conn->unp_cc = rcv->sb_cc;200 sorwakeup(so2);201 m = 0;202 #undef snd203 #undef rcv204 b r e a k ;

205 default:206 p a n i c C u i p c 4");207 )208 b r e a k ;

------------------------------------------------------------------------------------------------- uipcjusrrecj.cRysunek 18.2 Żądanie PRU_SEND dla gniazd strumieniowych

Page 302: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

280______________Protokoły domeny unixowej: 1/0 i przekazywanie deskryptorów_______Rozdział 18

Sprawdzenie stanu gniazda175-183 Jeżeli wysyłająca strona gniazda została zamknięta, to zostaje zwrócony

komunikat EPIPE. Gniazdo musi być połączone. Jeśli nie jest, wywołana zostaje funkq'a pani c, ponieważ sosend sprawdza, czy gniazdo żądające połączenia jest połączone (strona 511 w tomie 2).

Pierwszy z tych warunków prawdopodobnie jest pozostałością z wcześniejszych wersji.Sprawdzenie takie wykonuje wcześniej s osend (strona 511 w tomie 2).

Dołączenie struktur mbuf do bufora odbiorczego184-194 s o 2 wskazuje na strukturę socket dla odbierającego gniazda. Jeżeli proces

przekazał informację kontrolną używając sendmsg, bufory mbuf - kontrolne i za­wierające dane - zostają dołączone przez sbappendcontrol do bufora odbiorcze­go odbierającego gniazda. Jeżeli zaś informaq'a kontrolna nie była przekazana, sbappend dołącza bufory mbuf zawierające dane. Gdy wykonanie sbappendcontrol kończy się błędem, wskaźnik control otrzymuje wartość zero, by nie nastąpiło odwołanie do m_f reem na końcu funkcji (rysunek 17.10), funkcja sbappendcontrol zwolniła bowiem już mbuf.

Aktualizacja liczników nadawcy i odbiorcy195-199 Uaktualnione zostają dwie zmienne nadawcy, sb_mbmax (maksymalna do­

puszczalna liczba bajtów we wszystkich mbuf w buforze) oraz s b_h i wa t (maksy­malna dopuszczalna liczba bajtów danych znajdujących się aktualnie w buforze). W tomie 2 (strona 511) zaznaczyliśmy, że ograniczenie na liczbę bajtów w mbuf zapobiega zajmowaniu zbyt wielu buforów mbuf przez bardzo liczne małe komu­nikaty.

Dla strumieniowych gniazd domeny unixowej te dwa limity odnoszą się do sumy dwóch liczników w buforze wysyłkowym i odbiorczym. Na przykład początkowa wartość sb_hiwat jest 4096 zarówno dla bufora nadawczego, jak i dla bufora odbiorczego strumieniowego gniazda domeny unbcowej (rysunek 17.2). Jeżeli na­dawca wpisuje 1024 bajty do gniazda, nie tylko zmienna s b_c c odbiorcy (aktualna liczba bajtów w buforze gniazda) zmienia się z 0 na 1024 (tego się spodziewamy), ale również s b_h i wa t nadawcy zmienia się z 4096 na 3072 (czego się nie spodzie­waliśmy). W innych protokołach, takich jak TCP, wartość sb_hiwat nie zmienia się nigdy, chyba że zostanie jawnie ustawiona przez opcję gniazda. Podobnie zachowuje się sb_mbmax: zwiększenie wartości sb_mbcnt odbiorcy wiąże się ze zmniejszeniem sb_mbmax nadawcy.

Ta manipulacja limitem nadawcy i aktualną wartością licznika odbiorcy uzasad­niona jest faktem, że dane wysyłane przez strumieniowe gniazdo domeny unixo- wej nigdy nie są umieszczane w buforze wysyłkowym wysyłającego gniazda. Dane są dołączane natychmiast do bufora odbiorczego odbierającego gniazda. Nie ma powodu, żeby marnować czas na umieszczanie danych w kolejce wysyłkowej wysyłającego gniazda, a następnie - natychmiast lub później - przenosić dane do kolejki odbiorczej. Jeżeli w buforze odbiorczym nie ma miejsca, nadawca musi

Page 303: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 18.2 Żądania PRU_SEND i PRU_RCVD 281

zostać zablokowany. Jednakże, by funkcja sosend zablokowała nadawcę, ilość miejsca w buforze wysyłkowym musi odpowiadać ilości miejsca w buforze od­biorczym. Zamiast modyfikować liczniki bufora wysyłkowego, gdy brak jest da­nych w buforze wysyłkowym, łatwiej jest zmodyfikować ograniczenia dla bufora wysyłkowego, tak by zgodne były z ilością miejsca w odpowiednim buforze odbiorczym.

198-199 Zajmiemy się tylko manipulacją wartości sb_hiwat nadawcy i wartości unp_cc odbiorcy (manipulacje sb_mbmax i unp_mbcnt są niemal identyczne). W tym miejscu rcv - >sb_cc zawiera liczbę bajtów w buforze odbiorczym, ponie­waż dane zostały właśnie dołączone do bufora odbiorczego. Należy zaznaczyć, że u n p - > u n p_c onn->unp_ccjest poprzednią wartością r c v - > s b_c c, tak więc różnica tych dwóch zmiennych jest liczbą bajtów właśnie dołączonych do bufora odbior­czego (czyli liczbą wpisanych bajtów). snd->sb_hiwat zostaje zmniejszona o tę wartość. Aktualna liczba bajtów w buforze odbiorczym zostaje zachowana w unp->unp_conn ->unp_cc, tak więc przy następnym przejściu tego kodu możemy obliczyć, jak dużo danych zostało wpisanych.

Na przykład w momencie gdy gniazda zostają utworzone, wartość sb_hiwat wynosi 4096, a wartości sb_cc i unp_cc odbiorcy są obie równe 0. Jeżeli przekaza­ne zostają 1024 bajty, to sb_hiwat nadawcy ma wartość 3072, a zmienne sb_cc i unp_cc odbiorcy wynoszą obie 1024. Zobaczymy później (rysunek 18.3), że gdy odbierający proces czyta te 1024 bajty, wartość sb_hiwat zostaje zwiększona do 4096 bajtów, a sb_cc i unp_cc odbiorcy zostają zmniejszone do 0.

Obudzenie procesów czekających na dane200-201 sorwakeup budzi procesy oczekujące na dane. m otrzymuje wartość 0, by

m_f reem nie została wywołana na końcu funkcji, ponieważ bufor mbuf znajduje się teraz w kolejce odbiorczej.

Ostatnim fragmentem kodu I/O jest żądanie P RU_RC V D przedstawione na rysunku 18.3. To żądanie jest tworzone przez sorecei ve (strona 541 w tomie 2), gdy dane są czytane z gniazda i protokół ustawił flagę PR_WANTRCVD, określoną dla strumie­niowego protokołu domen unbcowych na rysunku 17.5. Zadaniem tego żądania jest umożliwienie przejęcia kontroli przez warstwę protokołu, gdy warstwa gniazd usuwa dane z bufora odbiorczego gniazda. Na przykład TCP używa tego żądania, by sprawdzić, czy powinna być wysłana do partnera informaqa o roz­miarze okna, ponieważ bufor odbiorczy gniazda ma teraz więcej miejsca. Strumie­niowy protokół domen unbcowych używa tego żądania do uaktualnienia buforo­wych liczników nadawcy i odbiorcy.

Page 304: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

282 Protokoły domeny unixowej: 1/0 i przekazywanie deskryptorów_______Rozdział 18

------------------------------------------------------------------------------------------------- utpc_usrreq.c113 case PRU_RC VD :114 switch (so->so_type) I

115 case S OCK_DGRAM:116 p a n i c C u i p c 1");117 /* NOTREACHED */

118 case S0CK_STREAM:119 #define rcv (&so->so_rcv)120 #define snd (&so2->so_snd)121 if (unp->unp_conn == 0)122 break;123 so2 = unp->unp_conn->unp_socket;124 /*125 * Korekcja ograniczeń po stronie nadawcy126 * i obudzenie piszących procesów127 */128 snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt;129 unp->unp_mbcnt = rcv->sb_mbcnt;130 snd->sb_hiwat += unp->unp_cc - rcv->sb_cc;131 unp->unp_cc = rcv->sb_cc;132 sowwakeup(so2);133 #undef snd134 #undef rcv135 break;

136 default:137 p a n i c C u i p c 2”):138 )139 break;

--------------------------------------- uipc_usrreq.cRysunek 18.3 Żądanie PRU_RCVD

Sprawdzenie, czy partner jeszcze istnieje121 -122 Jeżeli partner, który wpisał dane, zakończył już działanie, nie pozostaje nic

do zrobienia. Zauważmy, że dane odbiorcy nie zostają skasowane; liczniki bufora nadawcy nie mogą być jednak uaktualnione, ponieważ wysyłający proces zamk­nął swoje gniazdo. Nie trzeba uaktualniać liczników bufora, ponieważ nadawca nie będzie więcej wpisywał danych do gniazda.

Aktualizacja liczników buforowych123-131 so2 wskazuje na strukturę socket nadawcy. Wartości sb_mbmax i sb_hi wat

zostają uaktualnione odpowiednio do ilości przeczytanych danych. Na przykład unp->unp_cc minus rcv->sb_cc daje liczbę właśnie przeczytanych bajtów.

Obudzenie piszących procesów132 Gdy dane z kolejki odbiorczej są czytane, wartość sb_hi wat nadawcy jest

zwiększana. Procesy czekające (ewentualnie) na wpisanie danych zostają więc zbudzone, ponieważ - być może - pojawiło się teraz wolne miejsce w kolejce.

18.3 Przekazywanie deskryptorówPrzekazywanie deskryptorów (descriptorpassing) to technika komunikacji między- procesowej o dużych możliwościach. Rozdział 15 książki [Stevens 1992] przedsta­wia przykłady tej techniki w systemach 4.4BSD i SVR4. Choć odwołania systemo-

Page 305: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 18.3 Przekazywanie deskryptorów 283

we różnią się dla tych dwóch implementacji, przykłady te udostępniają funkcje biblioteczne, które mogą uczynić różnice systemowe niewidocznymi dla aplikacji.

Historycznie przekazywanie deskryptorów zwane było przekazywaniem praw dostępu (access rigths). Jedną z możliwości reprezentowanych przez deskryptory jest uprawnienie do wykonywania operacji wejścia/wyjścia na obiektach. (Jeśli nie mielibyśmy tego uprawnienia, jądro nie otworzyłoby dla nas deskryptora.) Takie uprawnienie do operacji wejścia/wyjścia ma jednak znaczenie tylko w odniesienu do procesu, w którym deskryptor jest otwarty. Na przykład proste przekazanie pomiędzy procesami deskryptora o numerze - powiedzmy - 4 nie przenosi uprawnień, ponieważ deskryptor 4 może nie być otwarty w odbierającym proce­sie, a nawet jeśli jest otwarty, prawdopodobnie odnosi się do innego pliku niż plik w procesie wysyłającym. Deskryptor jest po prostu identyfikatorem, który ma znaczenie tylko w danym procesie. Przekazywanie deskryptorów pomiędzy pro­cesami, wraz z uprawnieniami związanymi z deskryptorami, wymaga dodatko- wago wsparcia ze strony jądra. Jedynym typem uprawnień (praw dostępu), które mogą być przekazywane pomiędzy procesami, są deskryptory.

Rysunek 18.4 pokazuje struktury danych uczestniczące w przekazywaniu de­skryptorów pomiędzy procesami. Wykonywane są kroki wymienione poniżej.

proc{} £ile{) socket{} unpcb{}

Rysunek 18.4 Struktury danych uczestniczące w przekazywaniu deskryptorów

Page 306: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

284 Protokoły domeny unixowej: 1/0 i przekazywanie deskryptorów_______Rozdział 18

1. Zakładamy, że proces przedstawiony w górnej części rysunku to serwer ze strumieniowym gniazdem domeny unbcowej, w którym odbierane są połącze­nia. W dolnej części rysunku pokazany jest klient. Klient tworzy strumieniowe gniazdo domeny unbcowej i łączy to gniazdo z gniazdem serwera. Klient odwołu­je się do swojego gniazda jako do fdm, serwer odwołuje się do swojego gniazda jako do fdi. W tym przykładzie używamy gniazd strumieniowych. Zobaczymy jednak, że przekazywanie deskryptorów działa też w przypadku datagramowych gniazd domeny unbcowej. Zakładamy również, żefdi jest połączonym gniazdem serwera, zwróconym przez accept (tak jak to było pokazane w rozdziale 17.10). Dla uproszczenia nie pokazujemy struktur dla odbierającego gniazda serwera.

2. Serwer otwiera inny plik i odwołuje się do tego pliku jako do fdj. Może to być plik dowolnego typu, do którego serwer odwołuje się przez deskryptor: plik, urządzenie, gniazdo, itd. Pokazujemy to jako plik ze strukturą vnode. Licznik odwołań do pliku - człon f_count struktury fi 1 e - w chwili gdy plik zostaje otwarty po raz pierwszy równy jest 1.

3. Serwer wywołuje sendmsg dla fdi z informacją kontrolną zawierającą typSCM_RI GHTS i wartości ą/d;'. W ten sposób przez strumieniowe gniazdo domenyunbcowej „zostaje przekazany deskryptor" do odbiorcy, którym jest fdm w pro­cesie klienta. Licznik odwołań związany z fdj w strukturze f i l e zostaje zwię­kszony do 2.

4. Klient wywołuje recvmsg dla fdm, określając bufor kontrolny. Zwrócona infor­macja kontrolna ma typ SC M_R I GHTS i wartość fdn, czyli najmniejszy nieużywa­ny deskryptor klienta.

5. Po wykonaniu sendmsg w serwerze, serwer zwykle zamyka deskryptor, który właśnie przekazał (fdj). Powoduje to zmniejszenie licznika odwołań do wartości 1.

Mówimy, że deskryptor jest w locie (inflight) pomiędzy sendmsg i recvmsg.

Przy okazji omawiania przekazywania deskryptorów natkniemy się na 3 licznikiprzechowywane w jądrze.

1. f_c o unt jest członem struktury fi 1 e i zlicza aktualne odwołania do tej struktu­ry. Gdy wiele deskryptorów wykorzystuje tę samą strukturę f i l e , licznik ten zlicza liczbę deskryptorów. Na przykład - gdy proces otwiera plik - licznik f_count dla tego pliku otrzymuje wartość 1. Jeśli proces teraz wywoła fork, licznik f _c o u n t otrzymuje wartość 2, ponieważ struktura f i l e jest teraz wyko­rzystywana jednocześnie przez proces macierzysty i potomny. Każdy z dwóch procesów ma deskryptor, który wskazuje na tę samą strukturę f i l e . Gdy deskryptor zostaje zamknięty, wartość f_count zostaje zmniejszona o 1. Jeżeli f_count osiąga wartość 0, odpowiadający plik lub gniazdo zostają zamkniętei struktura f i l e może zostać użyta ponownie.

2. f_msgcount jest również członem'struktury f i l e , lecz człon ten ma wartość niezerową tylko w czasie przekazywania deskryptora. Gdy deskryptor jest przekazywany przez sendmsg, człon f_msgcount zostaje zwiększony o 1. Gdy deskryptor zostaje otrzymany przy pomocy recvmsg, wartość f_msgcount maleje

Page 307: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 18.3 Przekazywanie deskryptorów 285

o 1. f_msgcount zlicza odwołania do danej struktury file związane z de- skryptorami w kolejkach odbiorczych gniazda (to znaczy aktualnie w locie).

3. unp_rights jest zmienną globalną jądra, zliczającą aktualnie przekazywane deskryptory, czyli jest to całkowita liczba deskryptorów znajdujących się aktu­alnie w kolejkach odbiorczych gniazda.

Dla otwartego deskryptora, nie przekazywanego w danym momencie, wartość f_count jest większa niż 0. Na rysunku 18.5 pokazane są wartości trzech liczni­ków w trakcie przekazywania deskryptora. Przyjmujemy, że żadne inne deskryp­tory nie są w tym czasie przekazywane przez jądro.

f_co un t f _ m s g c o u n t unp_ri ghts

po o pen nadawcy 1 0 0

po se n d m s g nadawcy 2 1 1

w kolejce odbiorcy 2 1 1

po r e c vm sg odbiorcy 2 0 0

po cl ose nadawcy 1 0 0

Rysunek 18.5 Wartości zmiennych jądra w trakcie przekazywania deskryptorów

Zakładamy tutaj, że nadawca zamyka deskryptor po zakończeniu przetwarzania przez funkcję recvmsg odbiorcy. Nadawca może zamknąć też deskryptor w trak­cie jego przesyłania, przed wywołaniem recvmsg przez odbiorcę. Na rysunku 18.6 pokazujemy wartości trzech liczników w tym ostatnim przypadku. Okazuje się, że rezultat końcowy jest ten sam - niezależnie od tego, czy nadawca zamyka de­skryptor przed czy po wywołaniu recvmsg przez odbiorcę. Widzimy również na obu rysunkach, że sendmsg zwiększa wszystkie trzy liczniki, podczas gdy recvmsg zmniejsza tylko dwa ostatnie liczniki w tabeli.

f_ c ount f _ m s g c o u n t unp_ri ghts

po o pen nadawcy 1 0 0

po se n d m s g nadawcy 2 1 1

w kolejce odbiorcy 2 1 1

po cl ose nadawcy 1 1 1

w kolejce odbiorcy 1 1 1

p o r e c v m s g odbiorcy 1 0 0

Rysunek 18.6 Wartości zmiennych jądra w trakcie przekazywania deskryptorów

Kod jądra odpowiedzialny za przekazywanie deskryptorów jest pojęciowo nie­skomplikowany. Przekazywany deskryptor zostaje zamieniony na odpowiadają­cy wskaźnik f i l e i przekazany do drugiego końca gniazda domeny unixowej. Odbiorca zamienia wskaźnik f i l e na najniższy nieużywany deskryptor odbie­rającego procesu. Pojawiają się jednak problemy w przypadku wystąpienia błę­dów. Na przykład odbierający proces może zamknąć swoje gniazdo domeny unixowej w czasie, gdy deskryptor znajduje się w kolejce odbiorczej.

Page 308: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

286 Protokoły domeny unixowej: 1/0 i przekazywanie deskryptorów_______ Rozdział 18

Zamiana deskryptora na odpowiadający wskaźnik f i l e przez wysyłający proces zwana jest zamianą na format wewnętrzny (intemalizing), a zamiana wskaźnika f i 1 e na najniższy deskryptor odbierającego procesu zwana jest zamianą na for­mat zewnętrzny (exłernalizing). Funkcja unp_internalize była wywoływana przez żądanie P RU_S END (rysunek 18.1) - jeżeli proces przekazał informację kon­trolną. Funkcja unp_external i ze jest wywoływana przez soreceive - jeżeli bufor mbuf typu MT_C0NTR0 L jest czytany przez proces (strona 536 w tomie 2).

Na rysunku 18.7 pokazana została definiqa informacji kontrolnej przekazywanej przez proces do sendmsg przy przekazywaniu deskryptora. Struktura tego same­go typu jest wypełniana w recvmsg przy odbieraniu deskryptora. Przykładowo, na rysunku 18.8 pokazujemy format informacji kontrolnej w przypadku, gdy proces wysyła dwa deskryptory z wartościami 3 i 7. Pokazujemy również dwa pola w strukturze msghdr określające informację kontrolną.

------------------------------------------------------------------------------------------------- socket.h251 struct cmsghdr (252 u_int cmsg_len; /* licznik bajtów łącznie z nagłówkiem */253 int cmsg_level; /* protokół wysyłający */254 int cmsg_type: /* typ specyficzny dla protokołu */255 /* followed by u_char cmsg_data[]; */256 );

------------------------------------------------------------------------------------------------- socket.hRysunek 18.7 Struktura cmsghdr

msghdr { ) c m s g h d r O

msg_name

/

cmsg len 2 0SOL_SOCKETSCM_RIGHTS

37

msg_namelen cmsg_level

msg_iov cmsg_type

msg iovlen

msg_control

msg_controllen

msg__f lags

2 0

Rysunek 18.8 Przykład informacji kontrolnej przy przekazywaniu dwóch deskryptorów

Proces może w zasadzie wysłać dowolną liczbę deskryptorów przy pomocy jedne­go wywołania sendmsg, ale aplikacje przekazujące deskryptory zwykle przekazu­ją tylko jeden deskryptor. Istnieje wewnętrzne ograniczenie całkowitego rozmiaru informacji kontrolnej. Informacja ta musi się zmieścić w pojedynczym buforze mbuf (ograniczenie to jest wprowadzone przez funkcję sockargs, wywoływaną przez funkcję s end i t - patrz odpowiednio strony 467 i 504 w tomie 2), co ograni­cza liczbę deskryptorów przekazywanych przez dowolny proces do 24.

We wcześniejszych niż 4.3BSD Reno wersjach systemu człony m s g _ c o n t r o l

i m s g _ c o n t r o l len struktury msghdr nazwane były msg_accri ghts imsg_accri ghts len.Pole cmsg_l en - zawsze równe m s g _c o nt ro l 1 en - jest zbędne. Pole to ma umożliwiać pojawienie się więcej niż jednej informacji kontrolnej w pojedynczym buforze kontrol­

Page 309: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 18.3 Przekazywanie deskryptorów 287

nym. Zobaczymy jednak później, że kod nie wykorzystuje tej możliwości wymagając, by tylko jedna informaq'a kontrolna znajdowała się w jednym buforze kontrolnym.Jedynym rodzajem informacji kontrolnej dopuszczalnym w domenie internetowej jest zwrot adresu IP przeznaczenia dla datagramu UDP (strona 802 w tomie 2). Protokoły OSI obsługują cztery różne typy informacji kontrolnej używanej do celów specyficznych dla OSI.

Rysunek 18.9 podsumowuje funkcje wywoływane przy wysyłaniu i odbieraniu deskryptorów. (Funkcje zacieniowane omawiane są w tym tekście, pozostałe przedstawione zostały w tomie 2.)

Page 310: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

288 Protokoły domeny unixowej: 1/0 i przekazywanie deskryptorów_______Rozdział 18

Rysunek 18.10 podsumowuje czynności funkcji unp_i nternal i ze oraz unp_ex-ternal i ze dotyczące deskryptorów i wskaźników f i 1 e w buforze kontrolnym użytkownika oraz w buforze mbuf jądra.

| unp_internalizeV zastępuje deskryptory z wysyłającego procesu j odpowiednimi wskaźnikami file

proces wysyłający

....... H .........proces odbierający

sbappendcontroldołącza dane i kontrolne bufory mbuf do buforu odbiorczego odbierającego gniazda

f

jądro mbut{}

] unp_externalizev zastępuje wskaźniki file deskryptorami j właśnie alokowanymi w odbierającym procesie

R ysunek 18.10 Operacje wykonywane przez unp_i n t e r n a l 1 ze i unp_e xt e rn a 1 i ze

18.4 Funkcja unpjnternalizeFunkcja unp_i nternal i ze została pokazana na rysunku 18.11. Jak widzieliśmy na rysunku 18.1, funkcja ta jest wołana przez ui pc_us rreq, gdy utworzone zostaje żądanie P RU_S E N D i proces przekazuje deskryptory.

Page 311: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 18.4 Funkcja unpjnternalize 289

------------------------------------------------------------------------------------------------- uipc_usrreq.c553 int554 unp_internalize(control , p)555 struct mbuf * c o nt ro l ;556 struct proc *p;557 (558 struct filedesc *fdp = p->p_fd;559 struct cmsghdr *cm = m to d( control, struct cmsghdr *);560 struct file **rp;561 struct file *fp;562 i nt i , f d ;563 int oldfds;

564 if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != S0L_S0CKET ||565 cm->cmsg_len != control->m_len)566 return (EINVAL);567 oldfds = (cm->cmsg_len - sizeof(*cm)) / s i zeof( in t) :568 rp = (struct file **) (cm + 1);569 for (i = 0; i < oldfds: i++) <570 fd = *(int *) rp++;571 if ((unsigned) fd >= fdp->fd_nfil es ||572 fdp->fd_ofi1 e s [fd] = NULL)573 return (EBADF);574 ]575 rp = (struct file **) (cm + 1);576 for (i = 0; i < oldfds; i++) (577 fp = fdp->fd_ofiles[*(int *) rp];578 *rp++ = fp;579 fp->f_count++;580 fp->f_msgcount++;581 unp_rights++;582 )583 return (0) ;584 ]

------------------------------------------------------------------------------------------------- uipc_usrrec\.cRysunek 18.11 Funkcja unp_ in tern a l i ze

Sprawdzenie pól cmsghdr5 6 4 - 5 6 6 Struktura cmsghdr użytkownika musi podać typ S C M_R IGHTS, poziom

S0L_S0CKET. Pole długości tej struktury musi odpowiadać ilości danych w mbuf (pole to jest kopią członu msg_control len struktury msghdr przekazanej przez proces do funkcji sendmsg).

Sprawdzenie ważności przekazywanych deskryptorów5 6 7 - 5 7 4 ol dfds otrzymuje wartość równą liczbie przekazywanych deskryptorów,

a rp wskazuje na pierwszy deskryptor. Dla każdego przekazywanego deskryptora pętla for sprawdza, czy deskryptor jest nie większy niż maksymalny deskryptor aktualnie używany przez proces i czy wskaźnik jest niezerowy (czyli czy deskryp­tor jest otwarty).

Zastąpienie deskryptorów wskaźnikami file575 - 5 78 Wskaźnik r p zostaje ustawiony tak, by wskazywał na pierwszy deskryptor,

a pętla f o r zastępuje każdy deskryptor przez wskaźnik f p struktury file.

Page 312: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

290______________ Protokoły domeny unixowej: 1/0 i przekazywanie deskryptorów Rozdział 18

Aktualizacja wartości trzech liczników579-581 Wartości członów f _ c o u n t i f _ m s g c o u n t struktury f i 1 e zostają zwiększo-

zostaje zamknięty, drugi natomiast jest zmniejszany przez unp_ex terna! i ze. Do­datkowo zmienna globalna unp_ri ghts jest zwiększana przez unp_internal ize dla każdego przekazanego deskryptora. Zobaczymy, że wartość ta zostanie następnie zmniejszana przez unp_external i ze dla każdego otrzymanego de­skryptora. Wartość tej zmiennej zawsze równa się liczbie deskryptorów w locie.Na rysunku 17.14 zobaczyliśmy, że gdy gniazdo domeny unixowej jest zamykane i zmienna ta ma niezerową wartość, to następuje uruchamianie funkcji zbierającej niepotrzebne dane u n p_g c (garbage collection) - ponieważ zamykane gniazdo może zawierać deskryptory w locie w kolejce odbiorczej.

18.5 Funkcja unp_externalizePrzyjrzyjmy się funkcji unp_external i ze pokazanej na rysunku 18.12. Jest ona wywoływana jako dom_external i ze przez soreceive (strona 536 tomu 2), gdy bufor mbuf typu MT_C0NTR0L zostaje znaleziony w kolejce odbiorczej gniazda i jeśli proces jest przygotowany do przyjęcia informacji kontrolnej.

------------------------------------------------------------------------------------------------- uipc_usrreq.c523 int524 unp_externalize(rights)525 struct mbuf *rights;526 (527 struct proc *p = curproc; /* XXX */528 i nt i ;529 struct cmsghdr *cm = mtodtrights, struct cmsghdr *);530 struct file **rp = (struct file **) (cm + 1):531 struct fi 1e * f p ;532 i nt newfds = (cm->cmsg len - sizeof(*cm)) / sizeof(int)533 int f ;

534 i f (!fdavail(p, newfds)) (535 for (i = 0; i < newfds; i++) {536 fp = *rp;537 unp_discard(fp);538 *rp++ = 0;539 1540 return (EMSGSIZE);541 )542 for (i = 0 ; i < newfds; i++) (543 if (fda 11o c (p , 0, &f))544 pani c("unp_externalize");545 fp = * r p ;546 p->p_fd->fd_ofiles[f] = fp;547 fp'>f_msgcount--;548 unp_ri g h ts - -;549 * ( i nt *) rp++ = f ;550 )551 return (0);552 }

uipc_usrreq.cRysunek 18.12 Funkcja u n p _extern a 1 ize

Page 313: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 18.6 Funkcja unp_discard 291

Sprawdzenie, czy proces ma wystarczająco wiele dostępnych deskryptorów532-541 newfds jest licznikiem wskaźników f i 1 e w aktualnie przetwarzanym na

format zewnętrzny buforze mbuf. f da v a i 1 to funkcja jądra sprawdzająca, czy proces ma wystarczająco wiele dostępnych deskryptorów. Jeżeli brakuje deskryp­torów, to dla każdego deskryptora wołana jest funkcja unp_di scard (pokazana w następnym podrozdziale) i komunikat EMSGSIZE jest zwracany do procesu.

Zamiana wskaźników file na deskryptory542-546 Dla każdego przekazywanego wskaźnika fi 1 e alokowany jest przez naj­

niższy nieużywany deskryptor procesu f da 11 oc. Drugi, zerowy argument funkcji fdal 1 oc informuje, że struktura f i l e nie ma być alokowana, ponieważ w tym punkcie potrzebny jest wyłącznie deskryptor. Deskryptor zostaje zwrócony przez fdal 1 oc w f. Deskryptor w procesie wskazuje na wskaźnik f i l e .

Zmniejszenie dwóch liczników547-548 Dwa liczniki - f_msgcount i unp_ri ghts - zostają zmniejszone dla każdego

przekazanego deskryptora.

Zastąpienie wskaźników file deskryptorem549 Alokowany przed chwilą deskryptor zastępuje wskaźnik f i l e w buforze

mbuf. Jest to wartość zwracana do procesu jako informacja kontrolna.

Co się dzieje, jeżeli bufor przekazany przez proces do recvmsg nie jest wystarczająco duży, by pomieścić otrzymane deskryptory? u np _extern al i ze w dalszym ciągu alokuje w procesie żądaną liczbę deskryptorów i wszystkie deskryptory wskazują na właściwą strukturę f i l e . r e c v i t (strona 521 w tomie 2) zwraca jednak tylko informację kontrolną mieszczącą się w buforze alokowanym przez proces. Jeżeli powoduje to obcięcie informa­cji kontrolnej, w polu m sg_flags ustawiona zostaje flaga MSG_CTRUNC. Proces może sprawdzić wartość tej flagi przy zakończeniu przetwarzania przez recvms g.

18.6 Funkcja unp_discardFunkcja u np_di s c a r d , pokazana na rysunku 18.13, była wywoływana na rysunku 18.12 dla każdego przekazywanego deskryptora, gdy okazywało się, że odbierają­cy proces nie miał wystarczająco wielu dostępnych deskryptorów.

------------------------------------------------------------------------------------------------- uipc_usrreq.c726 void727 unp_discard(fp)728 struct file *fp:729 {

730 fp->f_msgcount--;731 unp_ri g ht s- -:732 (void) ciosef(f p . (struct proc *) NULL);733 ]------------------------------------------------------------------------------------------------- uipc_usrreq.cRysunek 18.13 Funkcja unp_discard

Page 314: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

292 Protokoły domeny unixowej: 1/0 i przekazywanie deskryptorów_______ Rozdział 18

Zmniejszenie dwóch liczników730-731 Liczniki f_msgcount i unp_ri ghts zostają zmniejszone.

Wywołanie closef732 Struktura f i l e zostaje zamknięta przez funkcję c lo sef , która zmniejsza

f_count i wywołuje funkcję fo_cl ose deskryptora (strona 487 w tomie 2), jeżeli f_count ma teraz wartość 0.

18.7 Funkcja unp_disposePrzypominamy (rysunek 17.14), że unp_detach woła sorfl ush przy zamykaniu gniazda domeny unixowej, jeśli zmienna globalna unp_rights jest niezerowa (tzn. deskryptory są w locie). Jedna z ostatnich czynności wykonywanych przez sorfl ush (strona 485 w tomie 2) to wywołanie funkcji domeny dom_di spose, jeżeli funkcja ta została zdefiniowana i jeżeli protokół ustawił flagę PR_RIGHTS (rysunek 17.5). To wywołanie jest wykonywane, ponieważ bufory mbuf, które mają właśnie być zwolnione, mogą zawierać deskryptory w locie. Ponieważ liczni­ki f_count i f_msgcount w strukturze fi 1 e oraz zmienna globalna unp_ri ghts były zwiększone przez unp_i nternal i ze, wszystkie te liczniki muszą być skory­gowane, tak by uwzględnione były deskryptory, które zostały przekazane, lecz nie zostały nigdy odebrane.

Funkcją dom_di spose dla domeny unbcowej jest unp_di spose (rysunek 17.4), którą pokazujemy na rysunku 18.14.

------------------------------------------------------------------------------------------------- uipc_usrreq.c682 void683 unp_dispose(m)684 struct mbuf *m;685 {

686 if (m)687 unp_scan(m, unp_discard);688 )-------------------------------------------------------------- 1---------------------------------- uipc_usrreq.cRysunek 18.14 Funkcja u n p _ d i s p o s e

Wywołanie unp_scan686-687 Całe przetwarzanie wykonywane jest przez funkcję u n p_s c a n (omawiamy

ją w następnym podrozdziale). Drugim argumentem w wywołaniu funkcji jest wskaźnik do funkcji unp_di scard, która - jak zobaczyliśmy w poprzednim pod­rozdziale - usuwa deskryptory znalezione przez unp_scan w buforach kontrol­nych kolejki odbiorczej gniazda.

Page 315: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 18.8 Funkcja unp_scan 293

18.8 Funkcja unp_scanunp_scan jest wywoływana z unp_di spose, z drugim argumentem unp_di scard, a później z unp_gc,zdrugim argumentem unp_mark. Funkcję unp_scan pokazuje­my na rysunku 18.15.

------------------------------------------------------------------------------------------------- uipc_usrreq.c689 void690 unp_scan(mO, op)691 struct mbuf *m0;692 void (*op) (struct file *);693 (694695696697698

699700701702703704705706707708709710711712713714715716 )

------------------------------------------------------------------------------------------------- uipc_usrreq.cRysunek 18.15 Funkcja unp_scan

Poszukiwanie kontrolnych buforów mbuf699-706 Funkcja ta przegląda łańcuch mbuf dla każdego pakietu w kolejce odbior­

czej gniazda (argument m0), szukając bufora mbuf typu MT_C0NTR0L. Jeżeli infor­macja kontrolna zostaje znaleziona, gdy aktualnym poziomem jest S0L_S0CKET, a typem SCM_RIGHTS, to mbuf zawiera nigdy nie odebrane deskryptory w locie.

Zwolnienie wskaźników file707-716 qf ds to liczba tablicowych wskaźników f i 1 e w komunikacie kontrolnym.

Dla każdego wskaźnika fi 1 e wołana jest funkcja op (unp_di scard lub unp_mark). Argumentem funkcji o p jest wskaźnik f i l e zawarty w komunikacie kontrolnym. Po przetworzeniu tego kontrolnego bufora mbuf, break powoduje przejście do następnego pakietu w buforze odbiorczym.

Komentarz XXX pojawia się, ponieważ b re ak zakłada (słusznie), że istnieje tylko jeden kontrolny bufor mbuf w łańcuchu mbuf.

struct mbuf *m; struct file **rp; struct cmsghdr *cm; i nt i ;int qfds;

while (mO) (for (m = mO; m; m = m->m_next)

if (m->m_type == MT_C0NTR0L U m->m_len >= sizeof(*cm)) ( cm = mtodtm, struct cmsghdr *); if (cm->cmsg_level != SOL_SOCKET |]

cm->cmsg_type != SCM_RIGHTS) continue;

qfds = (cm->cmsg_len - sizeof *cm)/ sizeoftstruct file *);

rp = (struct file **) (cm + 1); for (i = 0; i < qfds; i++)

(*op) (*rp++);break; /* XXX, ale daje oszczędność czasu */

)mO = m0->m_nextpkt;

)

Page 316: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

294 __________ Protokoły domeny unixowej: 1/0 i przekazywanie deskryptorów_______Rozdział 18

18.9 Funkcja unp_gcWidzieliśmy już jedną z form zbierania niepotrzebnych danych (garbage collection) dla deskryptorów w locie: w u n p_d e t a c h za każdym razem, gdy gniazdo domeny unixowej jest zamykane i deskryptory są w locie, sorfl ush zwalnia deskryptory w locie zawarte w kolejce odbiorczej zamykanego gniazda. Deskryptory przeka­zywane przez gniazda domeny unixowej mogą być jednak „zgubione" w innych okolicznościach. Może się to zdarzyć na trzy sposoby.

1. Gdy deskryptor jest przekazywany, bufor mbuf typu MT_C0NTR0L jest umiesz­czany przez sbappendcontrol w kolejce odbiorczej gniazda (rysunek 18.2). Jeśli jednak odbierający proces wywołuje recvmsg bez zaznaczenia, że chce odbierać informacje kontrolne, lub wywołuje jedną z innych funkcji wejścia, które nie mogą odbierać informacji kontrolnych, to sorecei ve woła MFREE, by usunąć i zwolnić mbuf typu MT_C0 N T RO L z buforu odbiorczego gniazda (strona 536 tom 2). Jeśli struktura f i l e , do którego odwoływał się ten bufor mbuf, zostaje zamknięta przez nadawcę, to liczniki f_count i f_msgcount struktury file mają wartość 1 (przypominamy rysunek 18.6), a zmienna globalna unp_rights w dalszym ciągu pokazuje, że deskryptor jest w locie. Jest to struktura f i 1 e, do której nie odwołuje się i nigdy nie będzie się odwoływał żaden deskryptor. Struktura ta znajduje się jednak w powiązanej liście aktyw­nych struktur f i l e .

Na stronie 305 książki [Leffler i inni 1989] zaznaczono, że problem polega na tym, iż jądro nie pozwala, by protokół miał dostęp do komunikatu po jego przekazaniu do warstwy gniazda w celu dostarczenia do adresu przeznaczenia. Ci sami autorzy zauważają też, że problem ten powinien być załatwiony przez specyficzną dla domeny funkq'ę wywoływa­ną, gdy bufor mbuf typu M T _ C O N T R O L jest zwalniany.

2. Gdy deskryptor jest przekazywany, a odbierające gniazdo nie ma miejsca na komunikat, deskryptor w locie zostaje usunięty bez śladu. Nie powinno się to nigdy zdarzyć dla strumieniowego gniazda domeny unbcowej, ponieważ - jak widzieliśmy w rozdziale 18.2 - znak przepełnienia nadawcy odzwierciedla ilość miejsca w buforze odbiorcy, co powoduje zablokowanie nadawcy aż do czasu, gdy w buforze odbiorczym znajdzie się wystarczająco dużo miejsca. Błąd może się jednak zdarzyć dla gniazda datagramowego. Jeśli brakuje miej­sca w buforze odbiorczym, funkcja sbappendaddr (wołana na rysunku 18.1) zwraca 0, e r r o r otrzymuje wartość E N 0 B U F S i kod oznaczony etykietą release (rysunek 17.10) kasuje bufor mbuf zawierający informację kontrolną. Prowadzi to do tej samej sytuacji, co poprzednio: pojawia się struktura f i l e , do której nie odwołuje się i nigdy nie będzie odwoływał się żaden deskryptor.

3. Gdy gniazdo domeny unbcowej fdi jest przekazywane do innego gniazda do­meny unixowej fdj, a fdj jest również przekazywane do fdi. Jeżeli oba gniazda domeny unixowej zostają następnie zamknięte bez odebrania przekazywanych deskryptorów, deskryptory mogą być zagubione. Zobaczymy, że problem ten jest jawnie obsługiwany w BSD (rysunek 18.18).

Page 317: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 18.9 Funkcja unp_qc 295

W pierwszych dwóch przypadkach kluczowe znaczenie ma fakt, że „zagubiona" struktura file ma wartość f_count równą f_msgcount (tzn. jedyne odwołania do tego deskryptora znajdują się w komunikatach kontrolnych) oraz że żadne infor­macje kontrolne znalezione w kolejkach odbiorczych gniazd domeny unixowej w jądrze nie odwołują się do tej struktury fi 1 e. Jeżeli wartość f_co un t struktury jest większa niż f_msgcount, to różnica jest liczbą deskryptorów w procesach, które odwołują się do tej struktury, a więc struktura nie została zagubiona. (W po­prawnie działającym systemie wartość f_count nigdy nie jest mniejsza niż f _m s g c o u n t .) Jeżeli wartość f _c o u n t ma wartość równą f _m s g c o u n t, ale do stru­ktury f i l e odwołuje się komunikat kontrolny w gnieździe domeny unixowej, to struktura nie została zagubiona, ponieważ jakiś proces może ciągle otrzymać deskryptor z tego gniazda.

Funkcja zbierania niepotrzebnych danych, unp_gc, znajduje takie zagubione stru­ktury f i l e i je odzyskuje. Struktura f i l e zostaje odzyskana przez wywołanie cl osef (pokazano to na rysunku 18.13), ponieważ cl osef zwraca nieużywaną strukturę f i l e do zasobnika wolnych struktur w jądrze (kemeYs free pool). Za­uważmy, że funkcja ta jest wołana tylko wtedy, gdy istnieją deskryptory w locie, to znaczy, gdy wartość unp_ri ghts jest niezerowa (rysunek 17.14) i gdy jakieś gniazdo domeny unixowej zostaje zamknięte. Dlatego też funkcja ta jest rzadko wykonywana i tylko pozornie stanowi źródło dodatkowego obciążenia komputera.

Do zbierania niepotrzebnych danych funkcja unp_gc używa algorytmu typu za- znaczanie-wymiatanie (mark-and-sweep). Pierwsza część funkcji - zaznaczanie - przegląda wszystkie struktury fil e w jądrze i zaznacza te, które są używane. Używana struktura f i 1 e, to taka, do której odwołuje się deskryptor w procesie lub komunikat kontrolny w kolejce odbiorczej gniazda domeny unixowej (tzn. stru­ktura odpowiada deskryptorowi w locie). Druga część funkcji - wymiatanie - odzyskuje niezaznaczone, czyli nieużywane struktury f i l e .

Pierwsza część funkcji unp_gc jest pokazana na rysunku 18.16.

uipcjusrrecj.c587 void588 u np _g c ()589 (590 struct file *fp, *nextfp;591 struct socket * s o ;592 struct file **extra_ref, **fpp;593 int nunref, i;

594595596597598599600 601 602603604605606

if (unp_gcing)r et u rn ;

unp_gci ng = 1; unp_defer = 0;for (fp = fi 1e h e a d .1h_fir st ; fp != 0; fp = fp->f_list.le_next)

fp->f_f1 ag &= -(FMARK | FDEF ER ) ;do (

for (fp = f i 1e h e a d .1h_fi r s t ; fp != 0; fp = fp->f_lis t .1e _ n e x t ) {if (fp->f_count == 0)

conti nue;if (fp ->f_flag & FDEFER) (

fp ->f_f1 ag &= -FDEFER; unp_defer--;

Page 318: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

296 Protokoły domeny unixowej: 1/0 i przekazywanie deskryptorów_______ Rozdział 18

607 ] else (608 if (fp->f_f1 ag & FMARK)609 continue:610 if (fp->f_count == fp->f_msgcount)611 continue;612 fp->f_f1 ag 1= FMARK;613 1

614 if (fp->f_type != DTYPE_SOCKET ||615 (so = (struct socket *) fp->r_data) == 0)616 continue;617 if (so->so_proto->pr_domain != &unixdomain |[618 (so->so_proto->pr_flags & PR _RIGHTS) “ 0)619 continue;620 unp_scan(so->so_rcv.sb_mb, unp_mark);621 ]622 } while (unp_defer);

------------------------------------------------------------------------------------------------- uipcjusrrecj.cRysunek 18.16 Pierwsza część funkcji unp_gc - zaznaczanie

Zabezpieczenie przed rekursywnym wywołaniem funkcji594-596 Zmienna globalna unp_gci ng zapobiega rekursywnemu wywołaniu funk­

cji: unp_gc może bowiem wywołać funkcję sorfl ush, która wywołuje unp_di - spose, a ta z kolei wywołuje unp_d i scard, która wywołuje unp_detach, która woła ponownie unp_gc.

Usunięcie flag FMARK i FDEFER598-599 Ta pierwsza pętla przechodzi przez wszystkie struktury file w jądrze

i usuwa flagi FMARK i FDEFER.

Powtarzanie aż unp_defer osiągnie 0600-622 Pętla do whi 1 e jest wykonywana do momentu, gdy zmienna unp_defer

staje się równa zero. Zobaczymy, że ta flaga zostaje ustawiona, gdy znajdujemy strukturę f i l e , którą wcześniej przetworzyliśmy i którą uznaliśmy za nieużywa­ną, choć struktura ta w rzeczy wistości jest używana. Gdy taka sytuacja ma miejsce, możemy być zmuszeni do ponownego przejścia przez struktury f i l e , ponieważ istnieje możliwość, że struktura, którą właśnie oznaczyliśmy jako zajętą, jest w rze­czywistości gniazdem domeny unixowej zawierającym odnośniki do f i 1 e w ko­lejce odbiorczej.

Pętla dla wszystkich struktur file601 - 603 W tej pętli analizowane są wszystkie struktury f i 1 e w jądrze. Struktury nie

używane (f_count równe 0) są pomijane.

Przetworzenie odłożonych struktur604-606 Jeżeli flaga FDEFER była ustawiona, jest ona wyłączana i wartość licznika

unp_defer zostaje zmniejszona. Gdy unp_mark ustawia flagę FDEFER, ustawiona zostaje również flaga FMARK. Wiemy więc, że ta struktura jest używana i na końcu polecenia i f sprawdzimy, czy jest to gniazdo domeny unixowej.

Page 319: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 18.9 Funkcja unp_gc 297

Struktury przetworzone wcześniej są pominięte607-609 Jeżeli flaga FMARK jest ustawiona, to struktura jest używana i była już anali­

zowana.

Nie zaznaczać zagubionych struktur610-611 Wartość f_count równa f_msgcount może świadczyć, że struktura jest

zagubiona. Struktura taka nie zostaje zaznaczona i jest pominięta. Ponieważ wy­daje się, że struktura nie jest używana, nie możemy sprawdzić, czy jest to gniazdo domeny unbcowej z deskryptorami w locie w kolejce odbiorczej.

Zaznaczenie używanych struktur612 W tym punkcie wiemy, że struktura jest używana, więc flaga FMARK zostaje

ustawiona.

Sprawdzenie, czy struktura jest związana z gniazdem domeny unixowej614-619 Ponieważ ta struktura jest używana, sprawdzamy, czy jest to gniazdo ze

strukturą socket. Następnie sprawdzamy, czy jest to gniazdo domeny unbcowej z ustawioną flagą PR_R I GHTS. Flaga ta jest włączona dla protokołów strumienio­wego i datagramowego domen unixowych. Jeśli którykolwiek z warunków nie jest spełniony, struktura zostaje pominięta.

Poszukiwanie deskryptorów w locie w kolejce odbiorczej gniazda domeny unixowej620 W tym punkcie struktura file odpowiada gnieździe domeny unbcowej.

Funkcja u n p_s c a n przegląda kolejkę odbiorczą gniazda w poszukiwaniu buforów mbuf typu MT_C0NTR0L zawierających deskryptory w locie. Jeżeli struktura taka zostanie znaleziona, wywołana jest funkcja un p_ma r k.

W tym miejscu powinna być również przetworzona kolejka kompletnych połączeń (so_q) dla gniazda domeny unixowej [McKusick i inni 1996], Możliwe, że klient przeka­zuje deskryptor do nowo utworzonego gniazda serwera, ciągle oczekującego na wykona­nie accept.

Na rysunku 18.17przedstawiony został przykład fazy zaznaczania funkcji unp_gc i zilustrowana jest potencjalna potrzeba kilkukrotnego przejrzenia listy struktur f i l e . Rysunek pokazuje stan struktur przy zakończeniu pierwszego przejścia listy w fazie zaznaczania, kiedy to zmienna unp_defer równa się 1, co oznacza konieczność ponownego przejrzenia wszystkich struktur file. Ma tu miejsce omówione niżej przetwarzanie dla każdej z czterech struktur - od lewej do prawej.

Page 320: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

298 Protokoły domeny unixowej: 1/0 i przekazywanie deskryptorów_______Rozdział 18

filo O

f_type

f_flag

f count

fjmagcount

-£ data

VNODEFMARK2

vnod«{)

f_type

f_flag

f count

f_msgcount

£ data

VNODEFMARKFDEFER1

vnoda{)

fil* O

f_type

f_flag

f count

f_msgcount

f data

SOCKETFMARK1

BOCk«t{)

mbuf<)MT CONTROL

cmsg lencmag_levelcmsg_type

_______

so rcv

- ■

fila o

f_type

f count

f_msgcount

f data

SOCKETFMARK21

socket{}

mbuf()

Rysunek 18.17 Struktury danych po zakończeniu pierwszego przeglądu listy w fazie zaznaczania

Page 321: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 18.9 Funkcja unp_qc 299

1. Ta struktura f i l e ma dwa deskryptory w procesie odwołujące się do niej (f_count równa się 2) i nie ma żadnych odwołań pochodzących od deskrypto­rów w locie (f_msgcount wynosi 0). Kod z rysunku 18.16 ustawia bit flagiFMARK w połu f_f 1 ag. Struktura ta wskazuje na vnode. (Pomijamy przedrostekDTYPE_ w wartości pokazanej dla pola f_type. Pokazujemy też tylko flagi FMARKi FDEFERwpolu f_fl ag ; inne flagi w tym polu mogą być także ustawio­ne.)

2. Wydaje się, że ta struktura nie jest używana, ponieważ f_count równa się f_msgcount. W fazie zaznaczania pole f_ f 1 ag pozostaje bez zmian.

3. Flaga FMARK tej struktury zostaje włączona, ponieważ do struktury tej odwołuje się jeden deskryptor w procesie. Co więcej, ponieważ struktura ta odpowiada gniazdu domeny unbcowej, funkcja u n p_s c a n przetwarza komunikaty kontrol­ne w kolejce odbiorczej gniazda. Pierwszy deskryptor w komunikacie kontrol­nym wskazuje na drugą strukturę f i l e , a ponieważ flaga FMARK nie była włączona w punkcie 2, unp_ma rk ustawia dwie flagi: FMARK i FDEFER. Zmienna unp_defer otrzymuje wartość 1, ponieważ struktura była już uznana za nie­używaną.

Drugi deskryptor w komunikacie kontrolnym wskazuje na czwartą strukturę f i l e - ponieważ flaga FMARK nie jest ustawiona (struktura ta nie była nawet jeszcze przetwarzana) - ustawione zostają flagi FMARK i FDEFER. Wartość unp_defer zostaje zwiększona do 2.

4. Ta struktura ma ustawioną flagę FDEFER. Kod z rysunku 18.16 wyłącza tę flagę i zmniejsza wartość unp_defer do 1. Choć do struktury tej odwołuje się rów­nież deskryptor w procesie, wartości f _c o u n t i f _m s g c o u n t nie są sprawdzane, ponieważ wiadomo już, że do struktury odwołuje się deskryptor w locie.

W tym miejscu wszystkie cztery struktury f i l e zostały przeanalizowane, ale wartość unp_defer wynosi 1, więc wszystkie struktury są przeglądane ponownie. Dzieje się tak, ponieważ druga struktura, uznana za nie używaną przy pierwszym przeglądzie, może być gniazdem domeny unbcowej z komunikatem kontrolnym w kolejce odbiorczej (w naszym przykładzie tak nie jest). Struktura ta musi być przeanalizowana ponownie - i jeśli rzeczywiście domniemanie jest prawdziwe - mogą zostać włączone flagi FMARK i FDEFER w jakiejś innej strukturze, z listy uznanej wcześniej za nieużywaną.

Na zakończenie fazy zaznaczania, która może obejmować wielokrotne przejrzenie powiązanej listy struktur f i 1 e w jądrze, mamy pewność, że niezaznaczone stru­ktury są na pewno nieużywane. Następna faza, wymiatanie (sweep), została poka­zana na rysunku 18.18.

Page 322: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

300 Protokoły domeny unixowej: 1/0 i przekazywanie deskryptorów_______ Rozdział 18

------------------------------------------------------------------------------------------------- uipc_usrreq.c623 /*624 * Uzyskujemy dodatkowy odnośnik dla każdego wpisu w tablicy625 * plików, który nie może być osiągnięty w inny sposób.626 * Następnie zwalniamy uprawnienia zawarte w komunikatach w takim wpisie.627 *628 * Błąd w oryginalnym kodzie wymaga wyjaśnienia. Wyjaśnienie takie629 * przedstawiam poniżej.630 *631 * Błędem jest f_msgcount-krotne użycie unp_discard dla każdego wpisu.632 * Rozważmy przypadek dwóch gniazd, A i B, zawierających wzajemne632 * odnośniki. Przy ostatnim zamknięciu jakiegoś innego gniazda633 * uruchamiana jest funkcja gc, ponieważ liczba pozostających uprawnień634 * (unp_rights) jest niezerowa. Jeśli w fazie wymiatania kod wykonuje635 * unp_discard, wykonujemy pełne zamknięcie (closef) dla deskryptora.

* Closef dla A powoduje:636 * Closef wywołuje soo_close, która wywołuje soclose. Soclose najpierw637 * (przez "switch" uipc_usrreq) wywołuje unp_detach, która ponownie638 * uruchamia unp_gc. Unp_gc od razu zwraca kontrolę, ponieważ przy639 * poprzednim wywołaniu została ustawiona flaga unp_gcing. i kontrola641 * zostaje przekazana aż do soclose. Soclose oznacza gniazdo przy pomocy642 * SS_N0 FDREF i następnie wywołuje sofree. Sofree woła sorflush, by643 * zwolnić uprawnienia czekające w kolejce, zawarte w komunikatach w644 * gnieździe A, to znaczy odniesienia w B. Sorflush woła (przez645 * dom_dispose) "switch" unp_dispose, który wykonuje unp_scan z646 * unp_discard. To drugie wykonanie unp_discard po prostu robi

* closef na B.647 *648 * Podobne przetwarzanie ma miejsce dla B, co powoduje sorflush na B649 * i następnie closef na A. Niestety, A jest już zamykane, a deskryptor650 * został już oznaczony przy pomocy S S J O F D R E F , co powoduje "panie”651 * w tym miejscu.652 *653 * Uzyskujemy tu najpierw dodatkowy odnośnik do każdego nieosiągalnego654 * deskryptora. Następnie sami wywołujemy sorflush, wiedząc teraz, że655 * jest to gniazdo domeny unixowej. Po usunięciu wszystkich praw656 * zawartych w komunikatach, wykonujemy ostatnie closef, by pozbyć się657 * naszego dodatkowego odnośnika. Jest to ostatnie zamknięcie i658 * unp_detach (itd.) wyłączy gniazdo.659 *660 * 91/09/19. [email protected] */

662 extra_ref = mai 1oc(nfi 1 es * sizeof(struct file *), M_FILE, M_WAIT0K);663 for (nunref = 0, fp = fi 1e h e a d .1h _f ir s t, fpp = extra_ref; fp != 0;664 fp = nextfp) [665 nextfp = fp->f_list.1e _ n e x t ;666 if (fp->f_count == 0)667 continue;668 if (fp->f_count == fp->f_msgcount && !(fp ->f_f1 ag & FMARK)) {669 *fpp++ = f p ;670 nunref++;671 fp->f_count++;672 )673 )674 for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp)675 if ((*fpp)->f_type == DTYPE_S0CKET)676 sorflush((struct socket *) (*fpp)->f_data);677 for (i = nunref. fpp = extra_ref; --i >= 0; ++fpp)678 closef(*fpp, (struct proc *) NULL);679 free((caddr_t) extra_ref, M_FILE);680 unp_gcing = 0;681 )-------------------------------------------------------------------------------------------------uipc_usrreq.cRysunek 18.18 Druga część funkcji unp_gc- wymiatanie

Page 323: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 18.9 Funkcja unp_gc 301

Komentarz o poprawieniu błędu623-661 Komentarz dotyczy błędu w systemie 4.3BSD Reno i w N et/2. Błąd został

skorygowany w 4 .4BSD przez Bennet S. Yee. Stary kod, którego dotyczy komen­tarz, pokazany jest na rysunku 18.19.

Tymczasowa alokacja tablicy662 ma 11 o c alokuje miejsce na tablicę wskaźników do wszystkich struktur file

jądra, nf i 1 es to liczba aktualnie używanych struktur file. M_F ILE określa, w ja­kim celu ma być użyta pamięć. (Polecenie vmstat -m podaje informacje o wyko­rzystaniu pamięci przez jądro.) M_WAIT0K oznacza, że dopuszczalne jest uśpienie procesu, jeżeli pamięć nie jest natychmiast dostępna.

Pętla dla wszystkich struktur file663 -665 W tej pętli ponownie są badane wszystkie struktury f i 1 e w jądrze, po to by

znaleźć wszystkie struktury, do których nie ma odwołań (czyli zagubione).

Pominięcie nieużywanych struktur663 - 665 Jeżeli licznik f _c o u n t struktury wynosi 0, struktura jest pominięta.

Sprawdzenie, czy istnieją struktury bez odwołań668 Do struktury nie ma odwołań, gdy wartość f _c o u n t jest równa f_msgcount

(odwołania pochodzą tylko od deskryptorów w locie) i flaga FMARK nie była ustawiona w fazie zaznaczania (deskryptory w locie nie pojawiły się w żadnej kolejce odbiorczej gniazda domeny unbcowej).

Zachowanie wskaźnika do struktury bez odwołań669-671 Kopia f p wskaźnika do struktury fi 1 e jest zachowana w alokowanej przed

chwilą tablicy, licznik nunref zostaje zmniejszony, a licznik f_count zwiększony.

Wywołanie sorflush dla gniazd bez odwołań674-676 Dla każdego pliku (struktury file) bez odwołań wołana jest funkcja

sorfl ush. Funkcja ta (strona 485 w tomie 2) wywołuje z kolei funkcje domeny dom_di spose, w tym przypadku unp_di spose, która woła unp_scan, by skaso­wać deskryptory znajdujące się aktualnie w kolejce odbiorczej gniazda. Funkcja unp_discard zmniejsza wartości f_msgcount i unp_rights i wywołuje closef dla wszystkich struktur f i l e znalezionych w komunikatach kontrolnych w kolej­ce odbiorczej gniazda. Ponieważ mamy dodatkowe odwołanie do tej struktury file (wcześniej została zwiększena wartość f_count) i ponieważ struktury z licz­nikiem f _c o u n t równym zero są ignorowane w pętli, mamy pewność, że f _c o u n t ma wartość większą lub równą 2. Dlatego wywołanie c 1 o s e f (w wyniku wykona­nia sorflush) jedynie zmniejszy do niezerowej wartości f_c o u n t struktury. Stru­ktura ta nie zostanie całkowicie zamknięta. To jest przyczyną wprowadzenia wcześniej dodatkowego odwołania do tej struktury.

Page 324: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

302 Protokoły domeny unixowej: 1/0 i przekazywanie deskryptorów_______ Rozdział 18

Ostatnie zamknięcie677- 678 c 1 o s e f jest wywoływana dla struktur f i l e bez odwołań. Jest to ostateczne

wywołanie cl osef, tzn. f_count powinno zostać zmniejszone z 1 do 0, gniazdo wtedy zostaje zamknięte i struktura f i l e jest zwrócona do zasobnika wolnych struktur w jądrze.

Zwrócenie tymczasowej tablicy679-680 Tablica otrzymana wcześniej w wyniku użycia mai 1 oc zostaje zwrócona

i flaga u n p _ g ci ng zostaje usunięta.

Rysunek 18.19 pokazuje fazę wymiatania funkcji unp_gc w takiej formie, w jakiej funkcja ta pojawiła się w kodzie N et/2. Ten fragment kodu został zastąpiony przez kod z rysunku 18.18.

------------------------------------------------------------------------------------------------- itipc_usrreq.cfor (fp = filehead; fp; fp = f p ->f_fi 1e f ) I

i f (fp->f_count == 0) continue;

if (fp->f_count == fp->f_msgcount && (f p ->f_f1 ag & FMARK) == 0) while (fp->f_msgcount)

unp_discard(fp);}unp_gcing = 0;

I

-------------------------------------------------------------------------------------------------uipcjusrrecj.cRysunek 18.19 Błędny kod fazy tin/miałania funkcji unp_gc w Net/2

Do tego fragmentu kodu odnoszą się komentarze na początku rysunku 18.18.

Niestety, mimo wprowadzonych w N e t/3 poprawek modyfikujących kod z rysunku 18.19 i usunięcia błędu opisanego na początku rysunku 18.18, przedstawiony w tym podrozdziale kod nadal nie jest poprawny. Ciągle struktury f i l e mogą zostać zagubio­ne w dwóch pierwszych sytuacjach opisanych na początku tego podrozdziału.

18.10 Funkcja unpjnarkFunkcja ta jest wywoływana przez funkcję unp_scan uruchamianą z kolei przez unp_gc, by zaznaczyć struktury f i l e . Zaznaczanie jest wykonywane, gdy de­skryptory w locie zostają znalezione w kolejce odbiorczej gniazda. Funkcja ta przedstawiona została na rysunku 18.20.

------------------------------------------------------------------------------------------------- uipc_usrreq.c717 void718 unp_mark(fp)719 struct file *fp;720 (

721 if (fp->f_flag & FMARK)722 return;723 unp_defer++;724 fp->f_f1 ag = (FMARK | FDEFER);725 ]

------------------------------------------------------------------------------------------------- uipc_usrreq.cRysunek 18.20 Funkcja unp_mark

Page 325: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 18.11 Szybkość działania (raz jeszcze) 303

717-720 Argument fp jest wskaźnikiem do struktury f i l e znalezionej w kolejce odbiorczej gniazda domeny unbcowej.

Powrót, jeżeli struktura została już zaznaczona721-722 Jeżeli struktura f i l e została już zaznaczona, nie pozostaje nic więcej do

zrobienia. Wiadomo już, że struktura f i l e jest używana.

Ustawienie flag FMARK i FDEFER723-724 Licznik unp_defer zostaje zwiększony i flagi FMARK i FDEFER zostają włą­

czone. Jeżeli ta struktura f i l e znajduje się na liście jądra w pozycji wcześniejszej niż struktura f i l e gniazda domeny unixowej (tzn. była już przeanalizowana przez unp_gc, została uznana za strukturę nieużywaną i nie została zaznaczona), zwiększenie unp_def er spowoduje jeszcze jedno wykonanie pętli dla wszystkich struktur f i 1 e w fazie zaznaczania unp_gc.

18.11 Szybkość działania (raz jeszcze)Po przedstawieniu implementacji protokołów domeny unbcowej wracamy teraz do szybkości działania tych protokołów i wyjaśnimy, dlaczego są one dwukrotnie szybsze niż TCP (rysunek 16.2).

Wszytkie operacje wyjścia/wejścia wykonywane są za pośrednictwem sosend i sorecei ve, bez względu na stosowany protokół. Ma to swoje dobre i złe strony. Zaletą jest to, że te dwie funkcje spełniają wymagania wielu różnych protokołów - od protokołu TCP przesyłającego strumień bajtów, przez protokoły datagramowe (UDP), po protokoły przesyłające rekordy (OSI TP4). Uniwersalność funkcji zmniejsza jednak szybkość ich działania i komplikuje kod. Wersje tych funkcji zoptymalizowane dla różnych rodzajów protokołów działałyby sprawniej.

Porównując szybkość operacji wyjścia stwierdzamy, że ścieżka przetwarzania z funkcją sosenddla TCP jest niemal identyczna ze ścieżką dla protokołu domeny unixowej. Jeżeli aplikacja wypisuje dane dużymi porcjami (dla danych z rysunku 16.2 używane są bufory o długości 32 768 bajtów), to sosend dzieli dane na klastry mbuf i przekazuje każdy 2048-bajtowy klaster do protokołu, używając żądaniaPRU_SEND. Dlatego też TCP i domena unixowa będą przetwarzać tę samą liczbężądań PRU_SEND. Różnica w szybkości operacji wyjścia musi wynikać z prostoty żądania PRU_SEND (rysunek 18.2) w domenie unbcowej w porównaniu do operacji wyjścia protokołu TCP (który wywołuje procedury wyjścia IP, by dołączyć każdy segment do kolejki programu obsługi urządzenia pętli zwrotnej).

Jeśli chodzi o odbiór danych, jedyną zaangażowaną funkcją w przypadku gniazda domeny unbcowej jest soreceive, ponieważ żądanie P RU_S END umieszcza dane w buforze odbiorczym gniazda. W przypadku TCP program obsługi pętli zwrotnej umieszcza każdy segment w kolejce wejściowej IP, po czym następuje przetwarza­nie IP oraz przetwarzanie TCP, w którym segment kierowany jest do właściwego gniazda i umieszczany w kolejce odbiorczej gniazda.

Page 326: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

304______________Protokoły domeny unixowej: 1/0 i przekazywanie deskryptorów_______Rozdział 18

18.12 PodsumowanieDane wpisywane do gniazda domeny unixowej są natychmiast dołączane do bufora odbiorczego gniazda. Buforowanie danych w wysyłającym gnieździe nie jest konieczne. Procedura taka działa poprawnie dzięki temu, że P RU_S EN D

i PRU_RCVD manipulują znakiem przepełnienia bufora wysyłkowego, tak że znak ten zawsze odzwierciedla ilość miejsca w buforze odbiorczym partnera.

Gniazda domeny unbcowej udostępniają mechanizm przekazywania deskrypto­rów pomiędzy procesami. Jest to technika komunikacji międzyprocesowej o du­żych możliwościach. Przy przesyłaniu deskryptora między dwoma procesami deskryptor zostaje najpierw przedstawiony w formacie wewnętrznym - zamienio­ny na odpowiedni wskaźnik f i 1 e, i dopiero ten wskaźnik przekazywany jest do odbierającego gniazda. Kiedy odbierający proces czyta informację kontrolną, wskaźnik f i l e zostaje zamieniony na format zewnętrzny - staje się najniższym nieużywanym deskryptorem w odbierającym procesie. Ten deskryptor zostaje zwrócony do procesu.

Jeżeli gniazdo domeny unixowej zostaje zamknięte w czasie, gdy bufor odbiorczy zawiera komunikaty kontrolne z deskryptorami w locie, pojawia się błąd, który może być jednak łatwo obsłużony. Niestety, możliwe są dwie inne błędne sytuacje, stwarzające większe problemy: gdy odbierający proces nie żąda informacji kon­trolnej znajdującej się w buforze odbiorczym oraz gdy w buforze odbiorczym nie ma wystarczająco wiele miejsca na bufor kontrolny. W tych dwóch sytuacjach struktury f i l e zostają zagubione - to znaczy nie znajdują się w zasobniku wol­nych struktur w jądrze i nie są również używane. By odzyskać te struktury, potrzebna jest funkcja zbierająca niepotrzebne dane.

Funkcja zbierania niepotrzebnych danych ma fazę zaznaczania, w której wszyst­kie struktury f i 1 e w jądrze są przeglądane i zaznaczone zostają struktury używa­ne. Po fazie zaznaczania następuje faza wymiatania, w której wszystkie niezazna- czone struktury zostają odzyskane. Choć ta funkcja jest potrzebna, to jednak rzadko jej się używa.

Page 327: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Dodatek A Pomiary czasu w sieci

W wielu miejscach w tekście książki podajemy czas potrzebny do wymiany pakie­tów poprzez sieć. W tym dodatku przyjrzymy się dokładniej sposobom wyznacza­nia czasu i podamy kilka przykładów takich pomiarów. Przedstawimy pomiary RTT przy użyciu programu Ping, pomiary czasu przechodzenia przez stos proto­kołu i omówimy różnicę między czasem propagacji (latency) i szerokością pasma (bandwidth).

Programista sieciowy lub administrator systemu ma zwykle do swojej dyspozycji dwa sposoby wyznaczenia czasu potrzebnego aplikacji na przeprowadzenie transakcji.

1. Użycie zegara aplikacji. Na przykład w kodzie klienta UDP (rysunek 1.1), odczytujemy czas systemowy przed wywołaniem sendto i po wykonaniu recvf rom. Różnica tak odczytanych czasów pozwala określić czas (zmierzony przez aplikację) potrzebny na wysłanie żądania i odebranie odpowiedzi.

Jeżeli jądro udostępnia zegar o dużej dokładności (rzędu mikrosekund), tak wyznaczone wartości (kilka i więcej milisekund) są dość dokładne. W dodatku A w tomie 1 ten typ pomiarów został omówiony bardziej szczegółowo.

2. Użycie narzędzia programowego w rodzaju Tcpdump. Tcpdump śledzi prze­syłanie danych na poziomie warstwy danych, obserwuje wybrane pakiety i umożliwia obliczenie odpowiedniej różnicy czasu. Więcej szczegółów doty­czących tego typu narzędzi zawartych jest w dodatku A w tomie 1.

W tym tekście zakładamy, że śledzenie danych w warstwie danych odbywa się przy pomocy programu Tcpdump wykorzystującego BPF (BSD Packet Filter) filtr pakietów systemu BSD. Szczegóły implementacji BPF przedstawione zo­stały w rozdziale 31 w tomie 2. Na stronach 111 i 121 w tomie 2 przedstawiono umiejscowienie odwołań do BPF w typowym programie obsługi Ethernetu, a na stronie 159 tomu 2 znajdziemy odwołanie do BPF w programie obsługi pętli zwrotnej.

Najbardziej wiarygodnym sposobem pomiaru czasu jest dołączenie analizatora sieci do kabla sieciowego. Taka możliwość zwykle nie jest jednak dostępna.

Zaznaczamy, że oba systemy używane do przeprowadzenia omawianych tu przy­kładów (rysunek 1.13) - BSD/OS 2.0 działający w komputerze z procesorem 80386 oraz Solaris 2.4 uruchomiony w Sparcstation ELC - udostępniają zarówno zegaro dużej dokładności, jak i możliwość pomiaru czasu przy pomocy Tcpdump.

Page 328: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

306 Pomiary czasu w sieci Dodatek A

A.1 Pomiary RTT z użyciem programu PingWszechobecny program Ping (omówiony szczegółowo w rozdziale 7 tomu 1) używa zegara aplikacji do wyznaczenia RTT dla pakietu ICMP. Program wysyła do serwera żądanie odpowiedzi typu echo protokołu ICMP, a serwer zwraca do klienta pakiet echo ICMP. Klient zapisuje czas zegara w momencie wysłania pakietu jako opcjonalne dane w żądaniu echa, i te dane zostają zwrócone przez serwera. Aktualny czas zegara systemowego jest odczytany w momencie otrzy­mania odpowiedzi przez klienta i czas RTT zostaje obliczony i wyświetlony. Format pakietu programu Ping przestawiony jest na rysunku A.l.

nagłówek IP

20 bajtów

nagłówekICMP

8 bajtów

dane użytkownika (opcjonalne)

Rysunek A .l Pakiet programu Ping: żądanie echa lub odpowiedź typu echo protokołu ICMP

Program Ping pozwala określić ilość opcjonalnych danych użytkownika w pakie­cie, możemy więc badać wpływ rozmiaru pakietu na RTT. Ping może jednak wyznaczyć RTT tylko dla pakietów zawierających co najmniej 8 bajtów opcjonal­nych danych (ponieważ zapis czasu w pakiecie zajmuje 8 bajtów). Jeśli zażądamy wysłania mniej niż 8 bajtów, Ping będzie nadal działał, czas RTT nie będzie jednak obliczany i wypisywany.

Na rysunku A.2 przedstawione są typowe wartości RTT otrzymane za pomocą programu Ping dla hostów w trzech różnych lokalnych (LAN) sieciach Ethernet. Środkowa linia na rysunku odpowiada RTT pomiędzy komputerami s u n i b s d i

z rysunku 1.13.

Rysunek A.2 Wartości RTT otrzymane za pomocą programu Ping dla trzech hostów w lokalnych sieciach Ethernet

Page 329: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja A. 1 Pomiary R TT z użyciem programu Ping 307

Pomiary przeprowadzone były dla piętnastu różnych rozmiarów pakietów - 8 bajtów danych użytkownika oraz od 100 do 1400 bajtów danych użytkownika (co 100 bajtów). Łącznie z 20-bajtowym nagłówkiem IP oraz 8-bajtowym nagłówkiem ICMP, datagramy IP miały rozmiar od 36 do 1428 bajtów. Dla każdego rozmiaru pakietu przeprowadzono 10 pomiarów i na wykresie zaznaczona została naj­mniejsza z 10 wartości. Tak jak się spodziewamy, czas RTT jest większy dla większych pakietów. Różnice pomiędzy trzema liniami wynikają z różnic szybko­ści procesorów, kart interfejsów i systemów operacyjnych.

Na rysunku A.3 przedstawione zostały typowe wartości RTT otrzymane za pomo­cą Pinga dla różnych hostów w Internecie (czyli sieci WAN). Zwracamy uwagę na różnicę skali na osi y w porównaniu z rysunkiem A.2.

Rysunek A.3 Wartości RTT otrzymane za pomocą programu Ping dla hostów w Internecie (WAN)

Dla sieci WAN przeprowadzono pomiary tego samego typu co dla sieci LAN - 1 0 pomiarów dla każdego z 15 rozmiarów pakietu i zaznaczona zostaje najmniejsza z 10 zmierzonych wartości. Zaznaczamy również (w nawiasach) liczbę hopów dla każdej pary hostów.

Linia znajdująca się najwyżej (największa wartość RTT) odpowiada 25 hopom w Internecie pomiędzy dwoma hostami: jednym w Arizonie (noao. edu) i drugim w Holandii (utwente.nl). Druga od góry linia również odpowiada przejściu przez Atlantyk - pomiędzy Connecticut (conni x . com) i Londynem (ucl .ac.uk). Następne dwie linie są to połączenia przecinające USA: pomiędzy Connecticut

Page 330: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

308 Pomiary czasu w sieci Dodatek A

a Arizoną (conni x .com i noao .edu) oraz pomiędzy Kalifornią a Waszyngtonem (berke1ey.edu i uu.net). Kolejne dwie linie odpowiadają hostom zlokalizowa­nym geograficznie blisko siebie - conn i x . com w Connecticut i a w . com w Bostonie- lecz oddalonym w sensie liczby internetowych hopów (16).

Najniższe dwie linie na rysunku (najmniejsza wartość RTT) odpowiadają hostom sieci LAN autora (rysunek 1.13). Najniższa linia została skopiowana z rysunku A.2, dla porówniania typowych wartości RTT dla sieci LAN i WAN. Jeśli chodzio linię drugą od dołu, czyli połączenie pomiędzy bsdi i 1 aptop, to drugi z tych hostów posiada adapter Ethernetu dołączony do równoległego portu komputera. Choć komputer jest dołączony do Ethernetu, mniejsza szybkość przesyłania przez port równoległy powoduje, że otrzymane wartości zbliżone są do wartości otrzy­mywanych dla sieci WAN.

A.2 Pomiary w stosie protokołuProgramu Ping, wraz z Tcpdump, możemy również użyć do zmierzenia czasu potrzebnego na przejście przez stos protokołu. Na rysunku A.4 pokazujemy kolej­ne kroki przetwarzania, gdy uruchamiamy Ping i Tcpdump w pojedynczym kom­puterze, podając adres interfejsu pętli zwrotnej (zwykle 127.0.0.1).

Zakładając, że aplikacja uruchamia swój zegar bezpośrednio przed wysłaniem żądania echa do systemu operacyjnego i zatrzymuje zegar, gdy system operacyjny zwraca odpowiedź echo, różnica pomiędzy czasem zmierzonym przez aplikacje

Page 331: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja A.2 Pomiary w stosie protokołu 309

i czasem zmierzonym przy pomocy Tcpdump daje czas przetwarzania przez wyj­ście ICMP, wyjście IP, wejście IP i wejście ICMP.

Możemy przeprowadzić podobne pomiary dla dowolnej aplikacji typu klient-ser- wer. Na rysunku A.5 pokazane są kroki przetwarzania dla klienta i serwera UDP z rozdziału 1.2, w przypadku gdy klient i serwer znajdują się w tym samym komputerze.

Różnica pomiędzy klientem-serwerem UDP, a przykładem z programem Ping z rysunku A.4, polega na tym, że serwer UDP jest procesem użytkownika, podczas gdy serwer Ping jest częścią implementacji ICMP zawartej w jądrze (strona 329 tomu 2). Dlatego też w przypadku serwera UDP konieczne są dwa dodatkowe kopiowania danych klienta pomiędzy jądrem i procesem użytkownika: operacje wejścia i wyjścia serwera. Kopiowanie danych pomiędzy jądrem i procesem użyt­kownika jest zwykle czasochłonną operacją.

Na rysunku A.6 pokazane są wyniki różnych pomiarów wykonanych dla hosta bsdi. Porównujemy klienta-serwera Ping z klientem-serwerem UDP. Użyliśmy oznaczenia „zmierzony czas transakcji" dla osiy, ponieważ pojęcie RTT odnosi się zwykle do podawanego przez Ping czasu przesłania w sieci pakietu w obie strony (który, jak widzimy na rysunku A.8, jest możliwie najbardziej zbliżony do czasu sieci RTT). Dla naszych układów klient-serwer UDP, TCP i T/TCP mierzymy w rzeczywistości czas transakcji wykonywanej przez aplikację. W przypadku TCP i T/TCP transakcja może obejmować przesłanie wielu pakietów i czas transakcji może odpowiadać wielokrotności RTT.

Page 332: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

310 Pomiary czasu w sieci Dodatek A

zmierzony :zas transakcj

(ms)

dane użytkownika (bajty)

Rysunek A.6 Pomiary z użyciem Pinga i Tcpdump dla pojedynczego hosta (interfejs pętli zwrotnej)

Pomiary przedstawione na rysunku odpowiadają 23 różnym rozmiarom pakietów- od 100 do 2000 bajtów danych użytkownika (zwiększane co 100), dodatkowo trzy pomiary dla 8,1508 i 1509 bajtów danych użytkownika. Osiem bajtów jest to najmniejsza długość danych użytkownika, dla której Ping może wyznaczyć RTT. 1508 bajtów danych daje największy pakiet, dla którego nie zachodzi fragmentacja datagramu IP - wartość MTU dla BSD wynosi 1536 (1508 + 20 + 8). 1509 bajtów odpowiada najmniejszemu pakietowi przesyłanemu z fragmentacją.

Wyraźnie widoczny jest skok czasu w momencie, gdy pojawia się fragmentacja - przy długości danych użytkownika równej 1509 bajtów. Tego się spodziewamy. W przypadku fragmentacji, wywołania operacji wyjścia IP (lewa strona rysunków A.4 i A.5) powodują dwa odwołania do programu obsługi pętli zwrotnej, jedno odwołanie dla każdego fragmentu. Choć ilość danych użytkownika wzrasta tylkoo 1 bajt, z 1508 do 1509, czas transakcji mierzony przez aplikację wzrasta mniej więcej o 25%, co jest związane z dodatkowym przetwarzaniem dla każdego pakietu.

Wzrost czasu widoczny dla wszystkich czterech linii w punkcie odpowiadającym200 bajtom związany jest ze szczegółem implementaqi obsługi buforów mbuf w BSD (rozdział 2, tom 2). Przy najmniejszym rozmiarze pakietu (0 bajtów danych użytkownika dla klienta UDP i 8 bajtów danych użytkownika dla klienta Ping), dane i nagłówki mieszczą się w jednym buforze mbuf. W punkcie odpowiadają­cym 100 bajtom, potrzebny jest drugi bufor mbuf, a w punkcie 200 bajtów - trzeci

Page 333: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja A.2 Pomiary w stosie protokołu 311

bufor. W końcu przy 300 bajtach jądro decyduje się na użycie 2048-bajtowych klastrów mbuf, zamiast mniejszych buforów mbuf. Jak widać, biorąc pod uwagę czas przetwarzania, zmiana wielkości mbuf powinna nastąpić wcześniej (na przy­kład w punkcie odpowiadającym 100 bajtom). Jest to przykład klasycznego wybo­ru pomiędzy optymalizacją czasu przetwarzania i rozmiaru zajmowanej pamięci. Decyzja o zwiększeniu rozmiaru mbuf, gdy ilość danych przekracza 208 bajtów, została podjęta wiele lat temu, gdy pamięci były bardzo kosztowne.

Czasy przedstawione na rysunku 1.14 zostały zmierzone dla zmodyfikowanego jądra BSD/OS, z wartością M I N C L S I Z E (strony 41 i 514 w tomie 2) zmienioną z 208 na 101. Powoduje to alokację klastra mbuf w momencie, gdy rozmiar danych użytkownika przekracza 100 bajtów. Na rysunku 1.14 nie obserwujemy więc wzrostu RTT w punkcie odpowiadającym 200 bajtom.Omawialiśmy ten problem również w rozdziale 14.11, gdzie stwierdziliśmy, że wiele żądań klientów W W W zawiera się w przedziale od 100 do 200 bajtów.

Różnica pomiędzy dwiema liniami UDP na rysunku A.6 wynosi od 1,5 do 2 ms - do momentu, gdy pojawia się fragmentacja. Ponieważ różnica ta związana jest z operacjami wyjścia UDP i IP oraz wejścia IP i UDP (rysunek A.5) - jeżeli założy­my, że przetwarzanie na wejściu protokołu zajmuje mniej więcej tyle samo czasu, co przetwarzanie na wyjściu - możemy stwierdzić, że przesłanie pakietu od góry do dołu stosu protokołu zajmuje nieco mniej niż 1 ms i podobnie odbiór pakietu przechodzącego przez stos z góry do dołu zajmuje też nieco mniej niż 1 ms. Czasy te obejmują czasochłonne kopiowania danych z procesu do jądra - przy wysyłaniu danych, oraz z jądra do procesu - przy odbieraniu danych.

Ponieważ te same cztery kroki (wejście IP, wejście UDP, wyjście UDP i wyjście IP) obejmowane są przez pomiar przy użyciu Tcpdump (rysunek A.5), spodziewamy się, że wartości odpowiadające UDP z Tcpdump także zawarte będą w przedziale 1,5-2 ms (biorąc pod uwagę tylko punkty bez fragmentacji). Prawie wszystkie warto­ści na rysunku A.6, z wyjątkiem pierwszego punktu, układają się pomiędzy 1,5 i 2 ms.

Rozważając wartości z fragmentacją, różnica pomiędzy dwiema liniami UDP na rysunku A.6 wynosi 2,5-3 ms. Tak jak się spodziewamy, wartości UDP mierzone przy pomocy Tcpdump również zawierają się pomiędzy 2,5 i 3 ms.

Zauważmy wreszcie, że linia odpowiadająca pomiarowi Tcpdump dla programu Ping na rysunku A.6 jest niemal zupełnie pozioma, podczas gdy pomiar aplikacji w przypadku Ping daje linię o wyraźnym nachyleniu. Prawdopodobną przyczyną tej różnicy jest to, że pomiar aplikacji obejmuje dwa kopiowania danych pomiędzy procesem użytkownika i jądrem, pqdczas gdy takie kopiowania nie są objęte przez pomiar Tcpdump (serwer Ping jest częścią implementacji ICMP jądra). Również niewielkie nachylenie linii Tcpdump dla programu Ping jest prawdopodobnie spowodowane dwiema operacjami wykonywanymi w jądrze przez serwer Pinga dla każdego bajtu - sprawdzenie otrzymanej sumy kontrolnej ICMP i obliczenie wysyłanej sumy kontrolnej ICMP.

Możemy też zmodyfikować nasze programy klienta i serwera TCP oraz T/TCP, przedstawione w rozdziale 1.3 i 1.4, tak by mierzony był czas każdej transakcji

Page 334: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

312 Pomiary czasu w sieci Dodatek A

(opisaliśmy to w rozdziale 1.6), i możemy wykonać pomiary dla różnych rozmia­rów pakietów. Wyniki takich pomiarów pokazane są na rysunku A.7. (Ponieważ TCP unika fragmentacji, poczynając od tego miejsca przedstawiamy wyniki po­miarów dla pakietów o maksymalnym rozmiarze 1400 bajtów.)

Rysunek A .7 Pomiar czasu transakcji klient-serwer TCP i T/TCP w ramach jednego hosta (interfejs pętli zwrotnej)

W pomiarach przy użyciu Tcpdump czas był mierzony poczynając od pierwszego segmentu wysłanego przez klienta (SYN dla klienta TCP, kombinacja SYN, da­nych i FIN dla klienta T/TCP), kończąc na ostatnim segmencie otrzymanym od serwera (FIN dla klienta TCP, kombinacja danych i FIN dla klienta T/TCP). Różnica pomiędzy linią odpowiadającą pomiarowi aplikacji TCP i linią Tcpdump dla TCP jest więc czasem potrzebnym na przetworzenie przez stos protokołu wywołania connect i ostatniego segmentu FIN (wymianę pakietów przedstawia rysunek 1.8). Różnica pomiędzy linią aplikacji i linią Tcpdump dla klienta-serwera T/TCP jest czasem potrzebnym na przetworzenie w stosie protokołu wywołania sendto klienta, które obejmuje dane klienta i ostateczną flagę FIN (wymianę pakietów przedstawa rysunek 1.12). Widzimy, że różnica pomiędzy dwiema linia­mi T/TCP (około 4 ms) jest większa niż różnica pomiędzy dwiema liniami TCP (około 2,5 ms), co zrozumiałe, ponieważ stos protokołu wykonuje więcej czynno­ści w przypadku T/TCP (wysłanie SYN, danych i FIN w pierwszym segmencie) niż w przypadku TCP (tylko SYN w pierwszym segmencie).

Page 335: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja A.2 Pomiary w stosie protokołu 313

Wyjątkowo duży czas transakcji w punkcie odpowiadającym 200 bajtom raz jesz­cze pokazuje, że jądro powinno wcześniej decydować się na użycie klastra mbuf. Zauważmy, że wzrost wartości w punkcie 200 bajtów dla TCP i T /TC P jest znacznie większy niż widzieliśmy to na rysunku A.6 dla Pinga i UDP. W przypad­ku protokołów datagramowych (ICMP i UDP), nawet jeśli trzy bufory mbuf są używane do przesłania danych użytkownika, wykonywane jest tylko jedno odwo­łanie warstwy gniazd w jądrze do procedury wyjściowej protokołu. Jest to wywo­łanie funkcji sendto (rozdział 16.7 w tomie 2). Natomiast dla protokołu strumie­niowego (TCP) procedura operacji wyjścia TCP jest wołana dwukrotnie: pierwszy raz dla pierwszych 100 bajtów, drugi raz dla następnych 100 bajtów danych użytkownika. Rzeczywiście, Tcpdump potwierdza, że w tym przypadku przesyła­ne są dwa 100-bajtowe segmenty. Dodatkowe wywołanie procedury wyjściowej protokołu jest czasochłonne.

Różnica pomiędzy czasami aplikacji TCP i T/TCP, wynosząca około 4 ms dla wszystkich wielkości pakietów, pojawia się ponieważ T/TCP przetwarza mniej­szą liczbę segmentów. Na rysunkach 1.8 i 1.12 widzieliśmy 9 segmentów w przy­padku TCP i 3 segmenty w przypadku T/TCP. Jasne jest, że zmniejszenie liczby segmentów, zmniejsza czas przetwarzania przez hosty na obu końcach połączenia.

Na rysunku A.8 pokazane zostało podsumowanie pokazanych na rysunkach A.6 i A .7 pomiarów czasu aplikacji dla układów klient-serwer Ping, UDP, T/TCPi TCP. Pomijamy tu pomiary wykonane przy pomocy Tcpdump.

Rysunek A.8 Transakcje klient-serwer w pojedynczym komputerze (interfejs pętli zwrotnej) - Ping, UDP, T/TCP i TCP

Page 336: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

314 Pomiary czasu w sieci Dodatek A

Wyniki są takie, jak się spodziewaliśmy. Czasy dla programu Ping są najmniejsze,i nie ma już możliwości otrzymania krótszych czasów, Ping jest bowiem częścią jądra. Czasy transakcji UDP są nieco większe niż czasy dla Pinga, ponieważ dane są dodatkowo dwukrotnie kopiowane pomiędzy klientem i serwerem. Różnica pomiędzy Pingiem i UDP jest jednak niewielka, ze względu na ograniczone prze­twarzanie protokołu UDP. Czasy transakcji T/TCP są mniej więcej dwukrotnie większe niż czasy transakcji UDP, mimo że liczba pakietów pozostaje taka sama (nasz zegar aplikaq'i nie obejmuje ostatniego segmentu ACK z rysunku 1.12), co związane jest z bardziej rozbudowanym przetwarzaniem przez protokół. Czas transakcji dla TCP jest o około 50% większy niż czas T/TCP - przyczynia się do tego większa liczba pakietów przetwarzanych przez protokół. Różnice pomiędzy UDP, T/TCP i TCP na rysunku A.8 nie są takie same jak na rysunku 1.14, ponie­waż pomiary w rozdziale 1 zostały wykonane w prawdziwej sieci, podczas gdy czasy prezentowane w tym dodatku uzyskano dla interfejsu pętli zwrotnej.

A.3 Czas propagacji a szerokość pasmaW komunikacji sieciowej dwa czynniki określają czas potrzebny na przesłanie informacji: czas propagacji (lałency) i szerokość pasma (bandwidth) [Bellovin 1992]. Pomijamy tu czas przetwarzania przez serwera i obciążenie sieci, czyli kolejne dwa elementy, które oczywiście także wpływają na czas transakcji mierzony przez klienta.

Czas propagacji (zwany też propagation delay), czyli opóźnienie związane z czasem rozchodzenia się sygnału, to stały czas potrzebny na przeniesienie jednego bitu od klienta do serwera i z powrotem. Czas ten jest ograniczony przez prędkość światłai dlatego zależy od odległości, którą optyczne lub elektryczne sygnały muszą pokonać pomiędzy dwoma hostami. Dla transakcji pomiędzy wschodnim i za­chodnim wybrzeżem USA wartość RTT nigdy nie będzie mniejsza niż mniej więcej 60 ms, chyba że ktoś zdoła zwiększyć prędkość światła. Czas propagacji można zmniejszyć przenosząc komputery tak, by dystans między klientem i serwerem był mniejszy, lub unikając tras o dużym czasie propagacji (takich jak na przykład połączenia satelitarne).

Teoretycznie, czas przestania impulsu świetlnego przez catą szerokość USA powinien wynosić około 16 ms, co dawałoby RTT równe 32 ms. W rzeczywistości RTT wynosi 60 ms. Autor przeprowadził eksperyment, w którym uruchomił Traceroute dla hostów znajdujących się na przeciwległych krańcach USA i rejestrował tylko minimalne wartości RTT. Minimalna wartość RTT pomiędzy Kalifornią i Waszyngtonem wyniosła 58 ms, a pomiędzy Kalifornią i Bostonem - 80 ms.

Szerokość pasma (bandwidth) określa szybkość, z jaką bit może być umieszczony w sieci. Nadawca uszeregowuje dane w sieci z szybkością określoną przez szero­kość pasma. Zwiększenie pasma przenoszenia jest możliwe przez zakup szybszej sieci. Na przykład - jeżeli linia telefoniczna w standardzie Tl nie jest wystarczają­co szybka (około 1 544 000 bitów na sekundę) - można wydzierżawić linię T3 (około 45 000 000 bitów na sekundę).

Page 337: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja A.3 Czas propagacji a szerokość pasma 315

Wąż ogrodowy jest tu dobrą analogią (podziękowania dla łan Lance Taylor): czas propa- gaq'i to czas potrzebny na przemieszczenie wody od kurka do spryskiwacza, szerokość pasma przenoszenia jest natomiast objętością wody wydobywającej się ze spryskiwacza w każdej sekundzie.

Sieci stają się coraz szybsze (to znaczy zwiększa się pasmo przenoszenia), ale czas propagacji pozostaje niezmienny. Na przykład przesłanie 1 miliona bajtów przez całą szerokość USA (zakładamy czas propagacji w jednym kierunku równy 30 ms) przez linię telefoniczną typu T l, zajmuje 5,21 sekundy: 5,18 sekundy ma związek z szerokością pasma, a czas propagacji wynosi 0,03. W tym przypadku czynni­kiem dominującym jest pasmo przenoszenia. Przy użyciu linii telefonicznej T3 całkowity czas wynosi 208 ms: 178 ms wynika z pasma przenoszenia, a 30 ms to czas propagacji. W tym drugim przykładzie czas propagacji staje się zbliżony do opóźnienia związanego z pasmem przenoszenia, a w przypadku jeszcze szyb­szych sieci - czas propagacji zaczyna dominować.

Na rysunku A.3 czas propagacji w obie strony odpowiada z grubsza punktowi przecięcia się każdej linii z osią y. Górne dwie linie (z punktami przecięcia dla około 202 i 155 ms) odpowiadają przesyłaniu danych pomiędzy USA i Europą. Następne dwie linie (punkty przecięcia dla 98 i 80 ms) odpowiadają przesłaniu danych przez całą szerokość USA. Następna linia (przecięcie przy 30 ms) dotyczy dwóch hostów na wschodnim wybrzeżu USA.

Rosnące znaczenie czasu propagacji, wraz ze wzrostem szerokości pasma, zwię­ksza znaczenie T/TCP. T/TCP zmniejsza bowiem czas propagacji o przynajmniej jedną wartość RTT.

Opóźnienia uszeregowania a ruteryZałóżmy, że dzierżawimy łącze telefoniczne do dostawcy usług internetowych, przesyłamy dane do innego hosta połączonego z Internetem przy pomocy łącza Tli wszystkie pośrednie łącza są typu Tl lub szybsze. Zobaczymy, że pomiar czasów przesyłania daje wyniki inne od oczekiwanych na podstawie prostego oszacowa­nia.

Jeżeli na przykład przeanalizujemy linię rysunku A.3, rozpoczynającą się przy wartości 80 ms i kończącą się wartością około 193 ms, co odpowiada połączeniu pomiędzy hostami connix.com w Connecticut i noao.edu w Arizonie, to dla wartości RTT połączenia pomiędzy przeciwległymi krańcami USA punkt przecię­cia z osią y w okolicy 80 ms jest zrozumiały. (Program Traceroute informuje nas w istocie, że pakiety wędrują z Arizony do Kalifornii, następnie do Texasu, W a­szyngtonu i w końcu do Connecticut.) Jeżeli jednak obliczymy czas potrzebny na przesłanie 1400 bajtów przez telefoniczne łącze Tl, otrzymamy 7,5 ms, tak więc oszacowalibyśmy RTT dla pakietu 1400-bajtowego na około 95 ms, co jest warto­ścią znacznie różniącą się od wartości zmierzonej (193 ms).

Mamy tu do czynienia z opóźnieniem uszeregowania (serialization delay), które rośnie liniowo wraz z liczbą pośredniczących ruterów, ponieważ każdy ruter musi ode­brać cały datagram przed przekazaniem go do interfejsu wyjściowego. Rozważmy

Page 338: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

316 Pomiary czasu w sieci Dodatek A

przykład z rysunku A.9. Wysyłamy 1428-bajtowy pakiet z hosta po lewej stronie do hosta po prawej stronie, za pośrednictwem rutera (pośrodku). Zakładamy, że oba łącza są liniami telefonicznymi typu T l, w których wysłanie 1428 bajtów zajmuje około 7,5 ms. Czas na rysunku płynie od góry do dołu strony.

Pierwsza strzałka, od czasu 0 do czasu 1, reprezentuje przetwarzanie datagramu w komputerze nadawcy. Na podstawie pomiarów omówionych wcześniej w tym dodatku zakładamy, że czas tego przetwarzania wynosi 1 ms. Dane są następnie poddawane procesowi uszeregowania w sieci, od pierwszego do ostatniego bitu, co zajmuje 7,5 ms. Dodatkowo czas propagacji pomiędzy dwoma końcami łącza wynosi 5 ms, tak więc pierwszy bit dociera do rutera w czasie 6 ms, a ostatni bit w czasie 13,5 ms.

Dopiero po odebraniu ostatniego bitu ruter przekazuje pakiet dalej. Zakładamy, że to przekazywanie zajmuje 1 ms. Pierwszy bit zostaje więc wysłany przez rutera w czasie 14,5 ms i dociera do odbiorcy 1 ms później (czas propagacji dla drugiego

Page 339: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja A.3 Czas propagacji a szerokość pasma 317

łącza). Ostatni bit dociera do odbiorcy w czasie 23 ms. Zakładamy wreszcie, że przetwarzanie w komputerze odbiorcy zajmuje znowu 1 ms.

Rzeczywista szybkość przesyłania wynosi więc 1428 bajtów w ciągu 24 ms, czyli 476 000 bitów na sekundę. Jeżeli zignorujemy 3 ms zużyte na przetwarzanie przez hosty i ruter, otrzymujemy szybkość przesyłania danych równą 544 000 bitów na sekundę.

Tak jak wspomnieliśmy wcześniej, opóźnienie uszeregowania jest liniową funkcją liczby ruterów na drodze pakietu. Efekt ten zależy od szybkości łącza (pasmo przenoszenia), rozmiaru każdego pakietu i liczby pośredniczących hopów (liczby pośredniczących ruterów). Na przykład opóźnienie uszeregowania dla pakietu 552-bajtowego (typowy segment TCP zawierający 512 bajtów danych) wynosi niemal 80 ms przy szybkości łącza równej 56 000 bitów na sekundę, 2,86 ms w przypadku linii Tl i tylko 0,13 ms w linii T3. Dlatego 10 hopów Tl dodaje do całkowitego czasu 28,6 ms (co jest niemal równe czasowi propagacji w jedną stronę przez całe Stany Zjednoczone), podczas gdy 10 hopów T3 dodaje tylko 1 ms (co prawdopodobnie można pominąć w porównaniu z czasem propagacji).

Możemy ostatecznie powiedzieć, że opóźnienie uszeregowania jest efektem zwią­zanym z czasem propagacji, a nie z szerokością pasma. Na przykład na rysunkuA.9 host wysyłający, przedstawiony po lewej stronie, może zacząć wysyłać drugi pakiet w czasie 8,5, a nie czeka do czasu 24 z wysłaniem drugiego pakietu. Jeżeli host po lewej stronie wysyła 10 bezpośrednio po sobie następujących 1428-bajto- wych pakietów, ostatni bit ostatniego pakietu - zakładając brak czasu martwego pomiędzy pakietami - odebrany zostaje w czasie 91,5 (24 + 9 x 7,5). Daje to szybkość przesyłania danych równą 1 248 525 bitów na sekundę, co jest bliskie szybkości łącza T l . W odniesieniu do TCP wystarczy zwiększyć rozmiar okna, by skompensować opóźnienie uszeregowania.

Wracając do naszego przykładu, w którym dane były przesyłane pomiędzy connix.com i noao.edu - jeżeli określimy rzeczywistą marszrutę i znamy szyb­kość wszystkich łączy - musimy też wziąć pod uwagę opóźnienie uszeregowania w każdym z 12 ruterów pomiędzy naszymi dwoma hostami. Zakładając czas propagacji równy 80 ms i czas przetwarzania w każdym z pośredniczących rute­rów równy 0,5 ms, otrzymujemy wartość 187 ms. Jest ona znacznie bliższa warto­ści zmierzonej niż nasze wcześniejsze oszacowanie - 95 ms.

Page 340: Biblia TCP IP Tom 3 - Uzupelnienie.pdf
Page 341: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Dodatek B Programowanie aplikacji T/TCP

W części pierwszej określiliśmy dwie korzyści wynikające ze stosowania T/TCP:

• uniknięcie potrójnego uzgodnienia TCP

• skrócenie stanu TIME_WAIT, gdy czas trwania połączenia jest krótszy niż MSL

Jeżeli oba hosty zaangażowane w połączeniu TCP potrafią obsługiwać T/TCP, wówczas druga z tych zalet jest dostępna dla wszystkich aplikacji, bez żadnych zmian w kodzie źródłowym.

Uniknięcie potrójnego uzgodnienia jest możliwe jednak tylko wtedy, gdy w ko­dzie aplikacji znajdują się odwołania do sendto lub sendmsg, zamiast odwołań do connect i wri te. Połączenie flagi FIN z danymi jest możliwe, gdy aplikacja, zamiast wywoływania shutdown, w ostatnim wywołaniu send, sendto lub sendmsg podaje flagę MSG_E0F. Kody klienta i serwera w rozdziale 1 uwzględniają te zmiany.

Dla zachowania możliwie największej przenośności oprogramowania powinni­śmy programować aplikacje tak, by korzystały z zalet T/TCP, gdy:

• host, na którym program jest kompilowany, obsługuje T/TCP

• aplikacja została skompilowana tak, by wykorzystywać T/TCP.

Drugi warunek oznacza również, że musimy w trakcie wykonywania aplikacji sprawdzić, czy host, w którym działa program, obsługuje T/TCP, możliwe jest bowiem czasami, że program był kompilowany z inną wersją systemu operacyjne­go niż wersja wykorzystywana w trakcie działania programu.

Host, w którym program jest kompilowany, obsługuje T/TCP, jeżeli w nagłówku <s y s /socket. h> została zdefiniowana flaga MSG_E0F. Fakttenm oże zostać wyko­rzystany w instrukcji #i f def.

#ifdef MSG_E0F/* host obsługuje T/TCP */

Ile 1 se/* host nie obsługuje T/TCP */

#endi f

Drugi warunek oznacza, że aplikacja wykonuje niejawne otwarcie (sendto lub sendmsg z podaniem adresu przeznaczenia, bez wywołania connect), ale jedno­cześnie potrafi obsłużyć niepomyślne zakończenie takiego otwarcia, gdy host nie zna T/TCP. Wszystkie funkcje operacji wyjścia zwracają komunikat ENOTCONN, jeżeli zostaną wykonane dla gniazda zorientowanego na połączenie, które nie jest połączone, w komputerze, który nie obsługuje T/TCP (strona 511 w tomie 2). Odnosi się to zarówno do systemów wywodzących się z systemu Berkeley, jak i do

Page 342: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

320 Programowanie aplikacji TfTCP Dodatek B

biblioteki gniazd SVR4. Jeżeli aplikacja otrzymuje taki komunikat, na przykład z odwołania do sendto, musi wtedy wywołać connect.

Klient i serwer TCP lub T/TCPPrzedstawione przed chwilą idee możemy zaimplementować w programach, któ­re są prostymi modyfikacjami klientów i serwerów T/TCP oraz TCP z rozdziału 1. Podobnie jak w przypadku programów w C w rozdziale 1, nie omawiamy szcze­gółowo przedstawionych kodów, zakładając pewną znajomość interfejsu API gniazd. Najpierw prezentujemy kod funkcji ma i n klienta (rysunek B.l).

------------------------------------------------------------------------------------------------- client.c1 /Mnclude "cliserv.h"

2 int3 main(int argc, char *argv[])4 ( /* klient T/TCP lub TCP */5 struct sockaddr_in serv;6 char request[REQUEST], reply[REPLY];7 int sockfd, n;

8 if (argc != 3)9 err_quit("usage: Client <IP address of server> <port#>");

10 memset(&serv, 0, sizeof(serv));11 s e r v .sin_family = A F_IN E T ;12 serv.sin_addr.s_addr = inet_addr(argv[l]);13 s e r v .sin_port = htons(atoi(argv[2]));

14 /* utworzenie żądania request[] . . . */

15 if ((sockfd = send_request(request, REOUEST, 1,16 (SA) &serv, sizeof(serv))) < 0)17 er r _sys("send_request error %d", sockfd):

18 if ((n = read_stream(sockfd, reply, REPLY)) < 0)19 er r _sys("read error");

20 /* przetworzenie "n" bajtów odpowiedzi reply[] ... */

21 e x i t (0);22 }

------------------------------------------------------------------------------------------------- client.cRysunek B .l Funkcja ma i n dla TfTCP lub TCP

8-13 Internetowa strukura adresowa jest wypełniana adresem IP serwera i nu­merem portu. Obie te informacje są wzięte z linii polecenia.

15-17 Funkcja send_request wysyła żądanie do serwera. Zwraca ona deskryptor gniazda - jeżeli została wykonana pomyślnie, lub wartość ujemną - w przypadku błędu. Trzeci argument (1) informuje funkcję, że po wysłaniu żądania ma być wysłany znak końca pliku.

18-19 Funkcja read_stream pozostaje bez zmian w stosunku do rysunku 1.6.

Funkcja send_request jest pokazana na rysunku B.2.

Page 343: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Sekcja 321

----------------------------------------------------------------------------------------------- - sendrequest.c1 #include "cliserv.h"2 #include <errno.h>3 #include <netinet/tcp.h>

4 /* Żądanie transakcji zostaje wysłane do serwera używając T/TCP, jeżeli5 * jest to możliwe. Jeśli nie - użyty jest protokół TCP. W przypadku

* błędu zwracana jest wartość < 0. Przy pomyślnym wykonaniu zwracany* jest nieujemny deskryptor gniazda. */

6 i nt7 send_request(const void *request, size_t nbytes, int sendeof.8 const SA servptr, int servsize)9 (

10 int sockfd, n;

11 if ((sockfd = s o cket(PF_INET, S0CK_STREAM, 0)) < 0)12 return (-1);

13 #ifdef MSG_E0F /* kompilujący host zna T/TCP */

14 n = 1;15 if (setsockopt(sockfd, IPPR0T0_TCP, TCP_NOPUSH.16 (char *) &n, sizeof(n)) < 0) (17 if (errno == EN0PR0T00PT)18 goto doconnect;19 return (-2):20 ]21 if (sendtotsockfd, request, nbytes, sendeof ? MSG_E0F : 0.22 servptr, servsize) != nbytes) [23 if (errno == ENOTCONN)24 goto doconnect;25 return (-3);26 }27 return (sockfd); /* sukces */

28 doconnect: /* host wykonujący nie zna T/TCP */29 #endif

30 /*31 * Kod umieszczony poniżej jest potrzebny, nawet gdy kompilujący host zna32 * T/TCP. Kod ten jest wykorzystywany, gdy host wykonujący nie zna T/TCP.33 */

34 if (connect(sockfd, servptr, servsize) < 0)35 return (-4);36 if (write(sockfd, request, nbytes) != nbytes)37 return (-5)38 i f (sendeof &&39 return (-6)

40 return (sockfd)41 }

hutdowntsockfd, 1) < 0)

/* sukces */

----------------------------------------------------------------------------------- sendrequest.cRysunek B.2 Funkcja s e n d _ r e q u e s t : wysłanie żądania przy użyciu T/TCP i TCP

Próba sendto dla T/TCP13-29 Ten fragment kodu jest wykonywany, jeżeli kompilujący host obsługuje

T/TCP. Opcję gniazda TCP_N0PUSH omówiliśmy w rozdziale 3.6. Jeżeli host, w którym program jest wykonywany, nie rozumie T/TCP, to odwołanie do setsockopt zwraca EN0PR0T00PT i robimy skok do etykiety doconnect, gdzie wykonane zostanie zwykłe connect. Znak końca pliku zostaje wysłany po żąda­niu, jeżeli trzeci argument wywołania funkcji był niezerowy.

Page 344: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

322 Programowanie aplikacji TfTCP Dodatek B

Zwykłe odwołania TCP30-40 Jest to zwykły kod TCP: connect, wri te i opcjonalnie shutdown.

Zmiany w kodzie funkcji ma i n serwera (rysunek B.3) są minimalne.

--------------------------------------------------------------------------- :-------------------- seruer.c1 #include "cliserv.h"

2 int3 mainCint argc, char *argv[])4 { /* serwer T/TCP lub TCP */5 struct sockaddr_in serv, cli;6 char request[REQUEST], reply[REPLY];7 int listenfd, sockfd, n, clilen;

8 if (argc != 2)9 err_quit("usage; server <port#>");

10 if ((listenfd = socket(PF_I NET, S0 CK _STREAM, 0)) < 0)11 err_ sy s("socket e r ror”);

12 memset(&serv, 0, sizeof(serv));13 s e r v .sin_family = A F_IN E T ;14 serv.sin_addr.s_addr = htonl(INADDR_ANY);15 s e r v .sin_port = htons(atoi(argv[1]));

16 if ( b i n dd is t en fd , (SA) &serv, sizeof (serv)) < 0)17 err_ sy s ("bind error");

18 if (1isten(1 i s t en fd , S0MAXC0NN) < 0)19 err_sys(”listen error");

20 for ( ; ; ) {21 cl i len = si zeof(cl i );22 if ((sockfd = acceptt1iste nf d , (SA) &cli, Łclilen)) < 0)23 err_ s ys ("accept e rror”);

24 if ((n = read_stream(sockfd, request, REOUEST)) < 0)25 err_sys("read e r ro r”);

26 /* przetworzenie ”n“ bajtów żądania request[] i* utworzenie odpowiedzi reply[j . . . * /

27 #i fndef MSG_E0F28 //define MSG_E0F 0 /* s en d() z flags=0 jest identyczne z w r i t e O */29 #endif

30 if (sendtsockfd, reply, REPLY, MSG_E0F) != REPLY)31 err_sys("send error");

32 close(sockfd);33 )34 )

------------------------------------------------------------------------------------------------- semer.cRysunek B.3 Funkcja ma i n serwera

27-31 Jedyna zmiana polega na tym, że zawsze wywoływana jest funkcja send (w kodzie z rysunku 1.7 wołana była funkcja wri te), z trzecim argumentem rów­nym zero, jeżeli host nie obsługuje T/TCP. Nawet jeśli host kompilujący znał T/TCP, a host wykonujący program nie zna T/TCP (w tym przypadku wartość MSG_E0F ustalona w trakcie kompilacji nie zostanie zrozumiana przez jądro w trakcie wykonania), funkcja sosend w jądrach wywodzących się z systemu Berke­ley nie protestuje w przypadku użycia nieznanych flag.

Page 345: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Bibliografia

F. Anklesaria, M. McCahill, P. Lindner, D. Johnson, D. Torrey i B. Alberti, 1993, The Internet Gopher Protocol, RFC 1436 (marzec), 16 stron

F. Baker (red.), 1995, Requirements for IP Version 4 Routers, RFC 1812 (czerwiec), 175 stronOdpowiada RFC 1122 [Braden 1989] dla rutera. Zastępuje RFC 1009 i RFC 1716.

S. Barber, 1995, Common NNTP Extensions, Internet Draft (czerwiec), draft-barber-nntp-imp-01.txt

S. M. Bellovin, 1989, Security Problems in the TCP/IP Protocol Suitę „Computer Communication Review", tom 19, nr 2, str. 32-48 (kwiecień) ftp://ftp.research.att.com/di st/internet_security/ipext.ps . Z

S. M. Bellovin, 1992, „A Best-Case Network Performance Model", informacja pry­watna

T. Bem ers-Lee, 1993, Hypertext Transfer Protocol, Internet Draft, (listopad), 31 strondraft-ietf-i i ir-http-00.txt

Nieaktualny już dokument typu „Internet Draft", jest to jednak oryginalna specyfikacja HTTP wersja 1.0.

T. Bemers-Lee, 1994, Universal Resource Identifiers in WWW: A Unifying Syntax for the Expression of Names and Addresses of Objects on the Network as Used in the World-Wide Web, 28 stron, RFC 1630 (czerwiec) h t t p ://www .w 3.org/hypertext/WWW/Addressi ng/URL/URl_0vervi e w .html

T. Bemers-Lee i D. Connolly, 1995 Hypertext Markup Language - 2.0, Internet Draft (sierpień)d ra ft-ietf-html-spec-05.txt

T. Bemers-Lee, R. T. Fielding i H. F. Nielsen, 1995, Hypertext Transfer Protocol - HTTP/1.0, Internet Draft (sierpień), 45 strondraft-ietf-http-vl0-spec-02.ps

T. Bemers-Lee, L. Masinter i M. McCahill (red.), 1994, Uniform Resource Locators (URL), RFC 1738 (grudzień), 25 stron

R. T. Braden, 1985, Towards a Transport Seruicefor Transaction Processing Applica­tions, RFC 955 (wrzesień), 10 stron

R. T. Braden (red.), 1989, Requirements for Internet Hosts - Communication Layers, RFC 1122 (październik), 116 stronPierwsza część „Host Reąuirements RFC". W tej części omówione są: warstwa łącza, IP, TCP i UDP.

R. T. Braden, 1992a, TIME-WAIT Assassination Hazards in TCP, RFC 1337 (Maj), 11 stron

R. T. Braden, 1992b, Extending TCP for Transactions - Concepts, RFC 1379 (listopad), 38 stron

Page 346: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

324 Biblia TCP/IP - tom III Bibliografia

R. T. Braden, 1993, TCP Extensions for High Performance: An Update, Internet Draft (czerwiec), 10 stronh ttp ://w w w .noao,edu /~rstevens/tcplw -exten si ons. tx t Jest to aktualizacja RFC 1323 [Jacobson, Braden i Borman 1992],

R. T. Braden, 1994, T/TCP - TCP Extensions for Transactions, Functional Specification, RFC 1644 (lipiec), 38 stron

L. S. Brakmo i L. L. Peterson, 1994, „Performance Problems in BSD4.4 TCP"f tp ://cs .a riz o n a .e d u /x k e rn e l/P a p e rs /tcp _ p ro b le m s . ps

H-W. Braun i K. C. Claffy , 1994, Web Traffic Characterization: An Assessment ofthe Impact of Caching Documents from NCSA's Web Seruer, „Proceedings of the Se- cond World Wide Web Conference '94: Mosaic and the Web" (październik), Chicago, str. 1007-1027h ttp ://w w w .ncsa. u iu c . edu/SDG/IT94/Proceedi ngs/D D ay/claffy/m ain. html

D. P. Cheriton, 1988, VMTP: Versatile Message Transaction Protocol, RFC 1045 (luty), 123 strony

C. R. Cunha, A. Bestavros i M. E. Crovella, 1995, Characteristics of WWW Client-ba- sed Traces, BU-CS-95-010, Computer Science Department, Boston University (lipiec)f t p : / / c s - f t p .b u . edu/techreports/95-010-w w w -cl i e n t - t r a c e s . p s . Z

R. T. Fielding, 1995, Relative Uniform Resource Locators RFC 1808 (czerwiec), 16 stron

S. Floyd, V. Jacobson, S. McCanne, C.-G. Liu i L. Zhang, 1995, A Reliable Multicast Framework for Lightweight Sessions and Application Level Framing, „Computer Communication Review", tom 25 nr 4 (październik), strony 342-356f t p : / / f t p ,e e .1 b l . gov/pap ers/srm l. te c h . p s . Z

M. Horton i R. Adams, 1987, Standard for Interchange of USENET Messages, RFC 1036 (grudzień), 19 stron

V. Jacobson, 1988, Congestion Avoidance and Control, „Computer Communication Review", tom 18, nr 4, (sierpień), strony 314-329 f t p : / / f t p . e e . 1b l . gov/papers/congavoid . p s. Z

Opis procedury powolnego startu i algorytmów unikania przeciążenia dla TCP. Klasyka.

V. Jacobson, 1994, Problems ivith Arizona's Vegas, end2end-tf mailing list, 14 marca 1994h ttp ://w w w .n o ao ,ed u /-rstev en s/v an j. 94 m a rl4 .tx t

V. Jacobson, R. T. Braden i D. A. Borman, 1992, RFC 1323 TCP Extensions for High Performance, 37 stron (marzec)Opisuje opcje skali okna i znacznika czasu oraz algorytm PAWS. Omawia również powody, dla których te modyfikacje są potrzebne. Aktualniejsze informacje można znaleźć w pracy [Braden 1993],

V. Jacobson, R. T. Braden, L. Zhang, 1990, TCP Extensionsfor High-Speed Paths, RFC 1185,21 stron (październik)Mimo że aktualniejsze informacje podawane są w RFC 1323, dodatek na temat zabezpie­czenia przed starymi, zduplikowanymi segmentami w TCP jest wart przeczytania.

Page 347: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Bibliografia Biblia T C P IP - tom III 325

B. Kantor i P. Lapsley, 1986, Network News Transfer Protocol, III stron (luty), RFC 977

S. R. Kleiman, 1986, Vnodes: An Architecture for Multiple File System Types in Sun UNIX, „Proceedings of the 1986 Summer USENIX Conference", Atlanta, Ga. strony 238-247

T. T. Kwan, R. E. McGrath i D. A. Reed, 1995, „User Access Pattems to NCSA's World Wide Web Server"http://www-pablo.cs.uiuc.edu/Papers/WWW.ps. Z

S. J. Leffler, M. K. McKusick, M. J. Karels i J. S. Quarterman, 1989, „The Design and Implementation of the 4.3BSD UNIX Operating System", Addison-Wesley, Reading, Mass.W tej książce opisany jest system 4.3BSD Tahoe. Opis nowszej wersji BSD zawarty jest w książce [McKusick i inni 1996],

P. E. McKenney, i K. F. Dove, 1992, Ejficient Demultiplexing oflncoming TCP Packets, „Computer Communication Review", tom 22, nr 4 (październik), strony 269- 279

M. K. McKusick, K. Bostic, M. J. Karels i J. S. Quarterman, 1996, „The Design and Implementation of the 4.4BSD Operating System" Addison-Wesley, Reading, Mass.

T. Miller, 1985, Internet Reliable Transaction Protocol Functional and Interface Specifica- tion, RFC 938,16 stron (luty)

J. C. Mogul, 1995a, Operating Systems Support for Busy Internet Seruers, TN-49, Digital Western Research Laboratory (maj)http://www.research.di g i t a l . com/wrl/techreports/abstracts/TN-49.html

J. C. Mogul, 1995b, The Case for Persistent-Connection HTTP, „Computer Communi­cation Review", tom 25, nr 4, strony 299-313 (październik)http: //www.research.di gital.com/wrl/techreports/abstracts/95.4 . html

J. C. Mogul, 1995c, informacja prywatna

J. C. Mogul, 1995d, Network Behavior of a Busy Web Sewer and its Clients, Raport WRL Research 9 5 /5 , Digital Western Research Laboratory (październik)http://www.research.d i g i tal.com/wrl/techreports/abstracts/95.5 . html

J. C. Mogul i S. E. Deering, 1990, Path M TU Discovery, RFC 1191,19 stron (kwiecień)

A. Olah, 1995, informacja prywatna

V. N. Padmanabhan, 1995, Improving World Wide Web Latency, UCB/CSD-95-875, Computer Science Division, University of California, Berkeley (maj)http://www.cs.berkeley. edu/~padmanab/papers/masters-tr.ps

C. Partridge, 1987, Implementing the Reliable Data Protocol (RDP), „Proceedings of the 1987 Summer USENIX Conference", Phoenix, Ariz., strony 367-379

C. Partridge, 1990a, Re: Reliable Datagram Protocol, Message-ID <[email protected]>, Usenet, grupa comp.protocols.tcp-ip (październik)

Page 348: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

326 Biblia TCP/IP-łom III Bibliografia

C. Partridge, 1990b, Re: Reliable ??? Datagram Protocols, Message-ID <6034tM3baBBN.COM>, Usenet, grupa comp.protocols.tcp-ip (październik)

C. Partridge i R. Hinden, 1990, Version 2 of the Reliable Data Protocol (RDP), RFC 1151,4 strony (kwiecień)

V. Paxson, 1994a, Growth Trends in Wide-Area TCP Connections, „IEEE Network", tom 8, nr 4 (lipiec/sierpień), strony 8-17ftp: / / f tp .ee. lbl . gov/papers/WAN-TCP-growth-trends.ps. Z

V. Paxson, 1994b, Empirically-Derived Analytic Models of Wide-Area TCP Connections, „IEEE/ACM Transactions on Networking", tom 2, nr 4, strony 316-336 (sier­pień)ftp: / / f tp.ee .1bl.gov/papers/WAN-TCP-models. ps.1

V. Paxson, 1995a, informaq'a prywatna

V. Paxson, 1995b, Re: Traceroute and TTL, Message-ID <[email protected]>, Usenet, grupa comp.protocols.tcp-ip (wrzesień)http://www.noao.edu/~rstevens/paxson.95sep29.txt

J. B. Postel, red., 1981a, Internet Protocol, RFC 791,45 stron (wrzesień)

J. B. Postel, red., 1981b, Transmission Control Protocol, RFC 793, 85 stron (wrzesień)

D. Raggett, J. Lam i I. Alexander, 1996, „The Definitive Guide to HTML 3.0: Electronic Publishing on the World Wide Web", Addison-Wesley, Reading, M as s .

S. A. Rago, 1993, „UNIX System V Network Programming", Addison-Wesley Reading, Mass

J. K. Reynolds i J. B. Postel, 1994, Assigned Numbers, RFC 1700, 230 stron (październik)Ten dokument RFC, jest regularnie uaktualniany. Aktualny numer można odszukać w spisie RFC.

M. T. Rose, 1993, „The Internet Message: Closing the Book with Electronic Mail", Prentice-Hall, Upper Saddle River, N.J

P. H. Salus, 1995, „Casting the Net: From ARP ANET to Internet and Beyond", Addison-Wesley, Reading, Mass.

Tsutomu Shimomura, 1995, Technical details of the attack described by Markoffin NYT, Message-ID <3g5gkl$5jl@ariel. sdsc.edu>, Usenet, grupa comp.protocols.tcp-ip, (styczeń)http://www.noao.edu/~rstevens/shimomura.9 5j an2 5 .txtSzczegółowy opis techniczny włamania internetowego z grudnia 1994, wraz z odpowied­nimi zaleceniami CERT.

S. E. Spero, 1994a, „Analysis of HTTP Performance Problems"http://sunsite.unc.edu/mdma-release/http-prob.html

S. E. Spero, 1994b, „Progress on HTTP-NG",http://www.w3.org/hypertext/WWW/Proto co 1s/HTTP-NG/http-ng-status. html

L. D. Stein, 1995a, „How to Set Up and Maintain a World Wide Web Site: The Guide for Information Providers" Addison-Wesley, Reading, Mass.

Page 349: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Bibliografia Biblia TCPIP - łom III 327

W. R. Stevens, 1990, „UNIX Network Prograiruning", Prentice-Hall, Upper Saddle River, N .J.

W. R. Stevens, 1992, „Advanced Programming in the UNIX Environment" Addi­son-Wesley Reading, Mass.

W. R. Stevens, 1994, „TCP/IP Illustrated, tom 1: The Protocols", Addison-Wesley Reading, Mass.Pierwsza z trzech książek w niniejszej serii. Zawiera wyczerpujące wprowadzenie do protokołów internetowych.

D. Velten, R. Hinden i J. Sax, 1984, Reliable Data Protocol, RFC 908,57 stron (lipiec)

G. R. Wright i W. R. Stevens, 1995, TCP/IP Illustrated, tom 2: The Implementation, Addison-Wesley Reading, Mass.Druga książka z niniejszej serii. Jest to opis implementacji protokołów internetowych w systemie 4.4BSD-Lite.

Page 350: Biblia TCP IP Tom 3 - Uzupelnienie.pdf
Page 351: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Indeks

!

#define 3, 239 #ifdef 319 -D16227 -display 234 -p 188 -r 188 -s 187 -w 188, 208 .newsrc 227, 229 .ps.Z 177 .minit 227 .miast 227 / 245/dev/log 235 /dev/lp 235 /tmp/.Xll-unix 254 / tmp/ .XI l-unix/X0 235,254 /tmp/foo 261-262 / var/news/ run 235 fd 264,267 argv 3,264, 267 inetsw 78,100 3WHS 714.2BSD XVI, 27,110,2444.3BSD Reno 27,267 286,3014.3BSDTahoe274.4BSD-Lite 274.4BSD-Lite2 274.4BSD-Lite2, kod źródłowy 28</BODY> 172</HEAD> 172</HTML> 172<A> 173<BODY> 172<BR> 172<CENTER> 172<DD> 173<H1> 172<HEAD> 172<HTML> 172<IMG> 172<netinet/tcp_seq.h> 99

<netinet/timer.h> 103 <P> 172<sys/protosw.h> 77 <sys/socket.h> 10,77,198,319 <sys/un.h> 237,239 <TITLE> 172

Aaccept 11,17,48,183,199,234,258,264, 269,

274-275,284, 297 ACCESSPERMS 255 ACCESSPERMS, stała 255 Adams R. 221adres interfejsu pętli zwrotnej 236,308AF_LOCAL 234AF_LOCAL, stała 234AF_UNIX 234,244AF_UNIX, stała 234,244again 53agresywne zachowanie 207AIX15,28,215,235aktywne otwarcie 144-145,147,149aktywne zamknięcie 13,31,37,62-64,67,103Alberti B. 323Alexander J. 326algorytm unikania przeciążenia 181alias adresu IP 190Allow 175ALT 172ANSI3API 13, XVI, 25-26,38,233-234,320 APPA 127argument przepełnienia 198argument przepełnienia, funkcja listen 198ARP 49,87, 93,236ARP ANET 205,221,326article 226,228,230ASCII 223,231Authorization 175aw.com 308

Page 352: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

330 Indeks

BBaker F. 6 4 ,3 2 3 Barber S. 221, 323 BellovinS. M .4 5 , 3 1 4 ,3 2 3 - berkeley.edu 308 Berners-Lee T. 323 Bestavros A . 324 bibliografia 323 bind 5 ,1 7 , 6 1 ,2 5 2 -2 5 4 ,2 5 8 ,2 7 6 blok kontrolny TCP 31, 3 5 ,1 0 1 blok PCB 6 0 ,1 3 7 ,1 6 1 ,2 1 5 -2 1 7 ,2 1 9 ,2 4 5 -2 4 6 ,

249,251-252 ,254-255 ,261-262 ,271 ,275-276 bloki PCB T /T C P 95 błąd pow olnego startu 154 błąd SYN_RCVD 202 błąd Tcpdum p 51 body 226Borm an D. A. 32, 324 Bostic K. 325 Boulos S. E. XVI bou nd ary= 184 B P F 305Braden R. T. 1 3 ,1 5 , 25-26, 32, 38, 65, 7 4 ,1 0 2 ,

1 1 0 ,1 1 9 ,1 2 3 ,1 4 6 ,1 6 3 ,1 6 7 ,3 2 3 -3 2 4 Brakm o L. S. 61, 324 Braun H -W . 190 ,3 2 4 break 293 BSD 27BSD /O S 15, 28, 4 5 ,1 8 7 ,2 1 1 ,2 3 5 -2 3 6 , 305, 311 bsdi 2 0 -2 1 ,2 8 ,4 3 ,5 4 ,3 0 6 ,3 0 8 -3 0 9 bufsize 127 bzero 106

ccase 1 1 1 ,1 4 4 ,1 4 9 , 249case TCPS_SYN_RECEIVED 133CC_G EQ 100CC_GT 100C C JN C 9 9 ,1 0 2 ,1 6 3CC_LEQ 100CC _LEQ , m akroinstrukcja 100 CC_LT 100CC_LT, makroinstrukcja 100 cc_recv 3 5 ,1 0 1 ,1 1 2 ,1 2 1 ,1 3 1 ,1 3 9 ,1 4 1 ,1 4 5 ,

150-151cc_send 35, 9 9 ,1 0 1 ,1 1 1 -1 1 2 ,1 4 1 ,1 6 3 CCnew 163 CERT 326Cheriton D. P. 25, 324 cin_clsroute 94 Claffy K. C. 190, 324

Clark J .J . XVIIcliserv 3cliserv.h 3-5close 179 ,285close, funkcja 2 1 2 ,2 6 9 , 285CLOSE_W AIT, stan 1 6 ,3 6 ,4 6 ,2 1 2CLOSE_W AIT*, stan 3 9 ,4 7CLOSED, stan 3 6 ,4 7 , 6 5 ,1 6 4closef 2 9 2 ,2 9 5 ,3 0 1 -3 0 2CLOSING 1 4 9 -1 5 0 ,1 5 4 ,1 5 7 ,2 1 2CLOSING* 39cm sg_data, człon 286cm sg_len 286cmsg_len, człon 286cmsg_level, człon 2 8 6 ,2 9 0 ,2 9 3cm sg_type, człon 286cm sghdr 2 8 6 ,2 8 9cm sghdr, struktura 2 86 ,288-289cm sghdr{} 288com p.protocols.tcp-ip 2 2 5 ,2 2 7 ,2 2 9 com pCC_IN C, m akroinstrukcja 9 9 ,1 0 2 ,1 6 3 com press 177connect 8 ,1 1 ,1 7 ,2 1 ,2 9 ,6 1 ,7 8 -7 9 , 95-96, 98,

1 4 1 ,1 5 9 -1 6 0 ,1 6 2 ,1 6 4 ,1 6 7 ,1 7 9 ,1 9 9 ,2 3 4 , 2 4 5 -2 4 6 ,2 5 6 ,2 5 8 -2 5 9 ,2 7 6 , 312, 319-322

connix.com 307-308, 315, 317 Conolly D. 323 Content-Encoding 175-176 Content-Length 1 7 5 ,1 7 7 ,1 8 4 Content-Type 175-176 ,184 control 2 3 5 ,2 7 8 ,2 8 0 copyout 267, 269 Cox A. XVI CREATE 253 CREATE, stała 253 Crovella M. E. 324 Cunha C. R. 324czas propagacji 22, 305, 314-315, 317 czas trw ania połączenia 36, 59, 61, 67-69, 75,

9 9 ,1 0 1 -1 0 3 ,1 5 0 ,1 5 5 -1 5 7 ,1 6 1 ,1 6 7 ,2 2 6 ,3 1 9

Ddane statystyczne T /T C P 100 Date 174-176Deering S. E. 5 6 ,2 0 4 ,2 0 6 ,3 2 5 DeSimone A. XVIdeskryptor 2 ,1 1 , XVI, 234, 241, 243-244, 248,

252, 258, 264-265, 267, 269, 277-278, 280, 282-302, 304, 320

deskryptor dow olnego typu 283 deskryptor w locie 242-243, 284 DF, flaga 56, 206

Page 353: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Indeks 331

diagram y zależności czasow ych 45 DISPLAY 234DISPLAY, zm ienna system ow a 234 długi szeroki potok 27 DNS 1 ,5do m _rtattach 243 do while 296 dobrze-znany portu 5 dobrze znana nazw a ścieżki 276 doconnect 321 dodata 1 3 1 ,1 3 3 ,1 5 3 dodata, etykieta 137 dom _dispose 2 4 3 ,2 9 2 ,3 0 1 dom _externalize 2 4 3 ,2 9 0 dom _fam ily 243 dom _init 243 dom _m axrtkey 243 dom _nam e 243 dom _next 243 dom _protosw 243 dom _protosw N PRO TO SW 243 dom _rtattach 8 4 ,2 4 3 dom _rtoffset 243 dom ain 2 42-243 ,265 domainf) 241 domaininit 243 Dove K. F. 217, 325 draining 8 9 ,9 1 dropsocket 143 drzew o podstaw ow e 81 D T Y P E _299 D TYPE_SOCKET 265 dw ukierunkow e zamknięcie 62 dw ustronne zam knięcie TCP 62

EEADDRINUSE 6 9 ,9 8 ,2 5 4 ECO N N ABO RTED 273 E C O N N R EFU SED 145 ECO N N RESET 2 5 1 ,2 7 3 EDEST ADDRREQ 78 EIN VAL 257 EISCONN 277 else 9 1 ,1 4 3 ,1 4 7 EMSGSIZE 257 ,291 EN O BUFS 278-279 ,294 ENOPROTOOPT 321 EN O TCO N N 7 8 ,2 7 7 , 319 EPIPE 280 err_sys 2 errno 3 error 294

ESTABLISHED, stan 3 9 ,4 0 ,4 6 -4 7 ,5 2 ,5 6 ,7 0 ,1 3 1 ,1 3 3 ,1 4 1 ,1 5 3

ESTABLISHED*, stan 3 9 -4 0 ,4 7 ,1 4 8 Expires 175

Ff 291f_count 284-285 ,290 ,292 ,294-297 ,299 ,301-302 f_data 265 f_flag 299f_m sgcount 2 8 4 -2 8 5 ,2 9 0 -2 9 2 ,2 9 4 -2 9 5 ,2 9 7 ,

299, 301 f_ops 265 f_type 299 falloc 265fałszyw y num er i-node 242-2 4 3 ,2 7 5FAQ 225fd 265fdalloc 291fdavail 291FD EFER 2 9 6 ,2 9 9 ,3 0 3Fielding R .T . 323-324file 258, 261, 2 6 5 ,2 7 4 ,2 7 7 , 284-286 ,288-297 ,

299, 301-304 file deskryptoram i 288 FIN_W AIT_1 3 8 -3 9 ,4 7 ,5 2 ,1 4 7 ,1 5 3 ,2 1 2 FIN _W A IT _lł 3 9 ,1 4 7 -1 4 8 FIN _W AIT_2 38-39, 4 7 ,5 2 ,1 5 6 , 212 findpcb 137-138 ,151 Floyd S. 26, 324 FM ARK 2 9 6 -2 9 7 ,2 9 9 ,3 0 1 , 303 fo_close 292 FO LLO W 2 5 3 ,2 5 6 for 289 fork 11, 284 found 89-91 fp 289, 301, 303 fp l2 6 5 FREAD 265FreeBSD 2 7 -2 8 ,8 2 ,1 0 2 ,1 6 7 From 175-176 ,277 fstat 274-275FTP 5, 9, 23, 26, 28, 59, 69, 218, 223-224 ftp ://ftp .isi.edu/pub/braden/T T C P.tar.Z 26 f t p :/ / ftp .m erit.ed u /statistics 169 f tp ://g re g o rio .stanford.edu/vm tp-ip 26 FW RITE 265

Page 354: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

332 Indeks

Ggatew ay 214 GET 1 7 3 ,1 7 7 ,1 8 4 GET ). 175 GET / 172-173 ,178 GET A LL 184 gethostbynam e 3 G ETLIST184 getpeernam e 2 5 8 ,2 7 5 getservbynam e 3 getsocknam e 275 gif 176 G opher 323 g o p h e r:/ 186 goto 137 Grandi S. XVII group 2 25 ,228-229

HH averlock P. M. XVI head 2 2 6 ,2 2 8 ,2 3 0 H eigh am C . XVI help 224H inden R. 2 5 ,3 2 6 -3 2 7historia protokołów transakcyjnych 24H og u eJ. E. XVIIH orton M. 2 2 1 ,3 2 4H P-U X 15H TTP 9, XII-XIV, 2 3 ,1 6 9 ,2 2 3 http://tow n.hall .org /A rchives//p ub /IT A / 188 h ttp ://w w w .a w .c o m 178 h ttp ://w w w .cd ro m .co m . 28 h ttp ://w w w .cu p .h p .co m /n e tp e rf/N e tp e rf Page.htm l 22h ttp ://w w w .freeb sd .o rg 27 http ://w w w .ncsa.uiuc.edu / SDG / Software /M osaic / Metalndex.html

173h ttp ://w w w .n csa .u iu c.ed u 173 h ttp ://w w w .sg m lo p en .o rg 172 httpd 1 8 7 ,1 9 0 ,2 0 0

IICM P 100 icm p_sysctl 101 idle 53 ,1 0 7 -1 0 8 IEEE 326if 7 9 ,1 3 9 ,1 4 3 ,1 4 7 ,1 6 3 ,2 0 9 ,2 5 7 , 296 If-Modified-Since 175 ,1 7 7

ifaddr 98 image 176 in_ 82in_addroute 8 5 ,9 2 , 94 in_clsroute 8 3 ,8 7 ,9 1 -9 4 in_inithead 8 4 ,8 8 ,9 4 in_localaddr 5 0 ,1 2 2 ,1 2 6 ,1 2 8 ,1 4 1 in_m atroute 86 ,9 3 -9 4 in_pcbbind 9 8 ,161 in_pcbconnect 95-98 in_pcbladdr 95 -98 ,161 in_pcblookup 9 8 ,1 6 1 in_rm xp 102 in_rtqkill 88-93in_rtqtim o 85, 88-90, 92-93, 212 INAD DR_AN Y 5 inetdomain 84informacja o początkow ym rozm iarze okna

204informacje w ątkow e 222IN N 2 2 1 ,2 2 6INND 223-224 ,235ino_t 242inode 253inp_route 114inpcb 215int 8 2 ,2 4 2ioctl 248ip_sysctl 8 3 ,101IPC XIII, 233-234IRIX 15irs 140 ,1 4 5IRTP 24IS N 45ISS 7 4 ,1 4 0 ,1 6 2

JJacobson V. 3 2 ,1 1 8 ,3 2 4 jednoczesne otw arcie 3 7 ,1 4 7 -1 4 8 ,1 5 2 jednoczesne serw ery HTTP 190 jednoczesne zam knięcie 3 7 ,4 0 jednolity identyfikator zasobów 173 jednolity lokalizator zasobów 173 język form atow ania tekstu 172 język hipertekstowego znakowania informaqi

170język znakow ania informacji 172 Johnson D. 323

Page 355: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Indeks 333

KKacker D. XVI Kantor B. 2 2 1 ,3 2 5 Karels M. J. XVII karetka 9, 223 k em /u ip c_p ro to .c 241 k em /u ip c_u srreq .c 241 kem ?uipc_syscalls.c 241 Kernighan B. W . XVI killed 89-91klaster mbuf 5 3 ,7 9 ,1 2 7 ,2 1 5 ,2 5 7 ,3 0 3 ,3 1 1 , 313Kleim an S. R. 253 klient N N TP 227 klient-serwer T /T C P 16 klient-serwer TCP 7 klient-serwer UDP 1 ,3 ,5 klonowanie m arszruty 81 kod źródłow y T /T C P 28 kod źródłow y, konwencja 2 kody odpow iedzi NN TP 224 kolejka kom pletnych połączeń 198-199,201 kolejka niekom pletnych połączeń 198-199,

201kombatybilność w stecz T /T C P 43 komunikat ICM P 2 7 9 ,3 0 6 konwencje typograficzne XVI korpus H TM L 172

LLam J. 326Lapsley P. 221, 325laptop 2 0 -2 1 ,2 8 , 43, 308LAST_ACK, stan 4 6 ,1 4 9 -1 5 1 ,1 5 7 , 212 ,2 1 9LAST_ACK*, stan 3 9 ,4 7last_adjusted_tim eout 90Last-M odified 175 ,1 7 7Leffler S. J. 294, 325len 108, 112licznik odw ołań 284licznik odw ołań do tablicy rutow ania 83, 87,

91licznik połączenia 32 -3 3 ,4 0 , 67, 72, 99-100Lindner P. 323link hipertekstu 170list 2 2 5 ,2 2 7 , 229-230lista HTM L 173listen 1 0 ,1 7 , 198-199, 201, 234, 255, 258 LISTEN, stan 38, 40, 5 6 ,1 3 7 ,1 4 0 ,1 4 3 ,1 4 9 ,

1 5 1 ,1 5 5 ,1 5 7 ,1 6 4 Liu C. -G. 324

Location 175 ,1 7 8 LO CK LEA F 256 LO CKPAREN T 253 log 90LOOKUP 256 lpd 235 Ipr 235

Mm 2 7 8 ,281 mO 293m _copy 2 5 5 ,2 5 8 , 275 M _FILE 301 m _free 2 5 2 ,2 7 3 m jr e e m 252, 273, 280-281 m _getclr 249 m _type 245 M _W AITOK 301 main 320, 322 M ALLO C 246, 301-302 m ax_sndw nd 108 mbuf 2 4 6 ,2 5 8 ,2 8 6 McCahill M. 323 M cCanne S. 324 M cGrath R. E. 325 M cKenney P. E. 217, 325 M cKusick M. K. 297 M CLBYTES 127 M ellor A. XVI mem set 3 M FREE 294 Miller T. 24, 325 M IM E-Version 175 M INCLSIZE 215, 311 M LEN 254M ogul J. C. XVI, 2 3 ,5 6 ,1 9 0 ,2 0 2 ,2 0 4 ,2 0 6 ,

212, 219, 325 m sg_accrights 286 m sg_accrightslen 286 m sg_control 286 m sg_controllen 286, 289 M SG_CTRUNC 291MSG_EOF 17, 46-47, 52, 7 7 -7 9 ,1 0 0 ,1 4 1 ,1 5 3 ,

1 6 2 ,1 6 4 -1 6 5 ,1 6 7 , 319, 322 M SG_EOR 17 msg_flags 291 MSG_OOB 79 m sghdr 286, 289MSL 13, 3 6 ,4 7 ,5 9 -6 2 , 64-71, 75-76, 9 5 ,9 9 ,

1 0 2 ,1 5 0 ,1 5 5 -1 5 7 ,1 6 1 ,1 6 7 , 319 MSS 1 2 1 ,1 2 5 -1 2 7 ,1 3 1 , 204 M T_CONTROL 2 8 6 ,2 9 0 ,2 9 3 -2 9 4 ,2 9 7

Page 356: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

334 Indeks

M T_PCB 249 M T_SONAM E 245M TU 5 ,1 0 1 ,1 2 2 -1 2 3 ,1 2 6 ,1 3 3 ,2 0 4 , 310 ,3 2 5 M TU ścieżki 5 6 ,1 2 2 ,2 0 6 M ueller M. XVI

Nnagłów ek H TM L 172n am 1 6 0 ,1 6 4 ,2 5 3 , 2 5 6 ,2 6 9 ,2 7 5 ,2 7 7nam ei 2 5 3 -2 5 5 ,2 5 7 ,2 7 6nam eidata 253, 256N CSA 1 8 7 ,1 9 0 -1 9 1 ,3 2 4nd.ni_cnd 255nd.ni_dvp 254-255nd.ni_vp 2 5 4 ,2 5 7nd.vi_vp 255ndd 201NDINIT 2 5 3 ,2 5 6 net.inet.ip 83 net.inet.tcp 100 ,1 6 6 N e t / l 1 2 7 ,1 2 9 ,1 5 0 N e t/2 12 9 ,1 6 7 , 301-302 N e t/3 2 8 ,5 0 ,5 2 ,6 0 -6 1 ,7 5 ,7 7 , 79-81, 83-85,

9 5 ,1 0 0 ,1 0 8 -1 0 9 ,1 1 3 ,1 1 6 -1 1 8 ,1 2 0 -1 2 2 ,1 2 7 , 1 2 9 -1 3 0 ,1 3 3 ,1 3 7 ,1 4 4 ,1 6 5 ,1 9 0 ,2 0 0 , 2 0 2 -2 0 3 ,2 0 8 ,2 1 3 ,2 1 5 ,2 1 7 ,2 3 9 ,2 4 2 ,3 0 2

NetBSD 28 n etin et/in _rm x.c 82 N etperf 22netstat 1 0 0 ,1 8 7 ,1 9 9 ,2 0 2new fds 291new sgroups 227nextstop 8 9 -9 0 ,9 2nfiles 301NFS 24, 81, 85, 253niejawne otw arcie połączenia 122niejawne w ypchnięcie 107Nielsen 323niezaw odność 18N N R P 223-224N N TP 9, XV-XVI, 221nntpin 235N O A O XIX-XXnoao.edu 3 0 7 -3 0 8 ,3 1 5 ,3 1 7N ODEV 275N O P 3 2 ,4 5 ,1 2 7 ,1 2 9 -1 3 0num ery portów klienta T /T C P 59 ,6 1num ery portów klienta HTTP 203nunref 301

0

offer 124 ,1 2 9 okn 154okno przeciążenia 1 2 8 ,1 3 7 ,2 1 8 oksym oron 25Olah A. XVIII, 2 7 ,6 7 ,1 6 3 ,3 2 5 oldfds 289 op 293opcja CC 3 2 -3 3 ,1 0 9opcja CCecho 32-33opcja CCnew 32-33opcja MSS 3 3 ,1 0 9 ,1 2 1opcja skali okna 3 3 ,2 0 6 ,3 2 4opcja znacznika czasu 3 3 ,1 0 9 ,2 0 6 ,3 2 4opcje SYN 2 0 3 ,2 0 5opcje T /T C P 32-33open 285opóźnienie uszeregow ania 3 1 5 ,3 1 7 opóźnione potwierdzenie 5 2 ,5 5 ,1 2 0 ,1 4 1 ,1 4 7 ,

1 5 5 ,1 9 6 ,2 1 7 origoffer 126 OSI 1 7 ,7 9 ,2 8 7 ,3 0 3

Pp 253, 2 5 6 ,2 6 5 Padm anabhan V. N. 325 pam ięć podręczna m arszruty 114-115 pam ięć podręczna PCB 2 1 5 ,2 1 7 pam ięć podręczna per-host 35 pam ięć TAO 3 5 ,4 1 ,4 4 ,4 6 ,5 5 ,9 3 ,1 0 5 -1 0 6 ,

1 1 3 ,1 2 4 ,1 2 9 ,1 4 1 ,1 4 6 -1 4 8 ,1 5 3 ,1 6 3 panie 280para gniazd 4 7 ,6 1 ,6 9 , 95, 98 Partridge C. XVI-XVII, 7 ,2 5 ,3 2 5 -3 2 6 pasyw ne otw arcie 1 4 0 -1 4 1 ,1 4 3 ,1 5 2 PAW S 4 3 ,1 5 1 ,3 2 4Paxson V. 6, XVII, 2 3 ,1 1 7 ,1 8 8 ,2 2 1 , 326PCB 95, 9 8 ,1 14-115 , 133Peterson 6 1 ,3 2 4PF_LO CA L 234PF_RO UTE 244PF_U N IX 238pipę 2 3 4 ,2 4 1 ,2 6 1 ,2 6 7 -2 6 9 , 276 pola nagłów ka N N TP 221, 225 pole nagłów ka H TM L 174 połow iczna synchronizacja 3 9 -4 0 ,1 0 2 ,1 0 8 ,

14 1 ,1 5 2 ,1 5 4 -1 5 5 połow iczne 8połow iczne zamknięcie 1 3 ,4 7 ,5 2 pom iar czasu, klient serw er 20-21 pom iar RTT 196-197 ,306-307

Page 357: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Indeks 335

pom iary czasu w stosie protokołu 308-309, 311, 313

POSIX 234 POST 174 POST ). 175P ostelJ. B. 2 5 ,3 2 ,3 8 ,5 6 , 326 pow olny start 5 0 -5 1 ,1 2 8 -1 2 9 ,1 4 1 ,1 5 4 ,2 1 5 ,

218, 324 PPP 118 ,1 9 6 , 2 08 ,229-230 PR_AD D R 244 PR_ATOM IC 244 PR_CO N N REQ UIRED 100 ,2 4 4 pr_flags 7 8 ,1 0 0 PR_IM PLO PCL 77-79 ,100 PR_RIGHTS 2 4 4 ,2 9 2 ,2 9 7 pr_sysctl 100 ,1 6 6 PR_W AN TRCVD 1 0 0 ,2 4 4 ,2 8 1 Pragm a 175 Pragm a: 184Pragm a: hold-connection 184 praw a autorskie XV praw a dostępu 2 4 4 ,2 8 3 present 133prędkość św iatła 2 2 ,3 1 4 proc 2 5 3 ,2 5 6 Program host 191program obsługi pętli zwrotnej 2 3 3 ,2 3 6 ,3 0 3 ,

305, 308-310 program Traceroute 314-315 ,317 protokoły dom eny unixowej 233 protokoły dom eny unixowej, implementaq'a

241protokoły dom eny unixowej, przykłady program ów 237 protokół HTTP 23protokół przesyłania hipertekstu 169 protosw 1 0 0 ,1 6 6 ,2 4 2 -2 4 4 protosw(| 241 p roxy 214 PR U .A B O R T 273 PR U _A CC EPT 269-270 ,275 PRU _A TTA CH 1 1 3 ,2 4 9 ,2 5 8 ,2 6 9 PRLLBIN D 252-253PRU _C O N N EC T 9 5 ,1 5 9 -1 6 1 ,2 5 5 ,2 5 7 ,2 5 9 PR U _C O N N EC T2 2 6 0 -2 6 1 ,2 6 3 ,2 6 6 ,2 6 8 PRU_CO N TRO L 248 PRU _D ETA CH 250-251 PRU_D ISCO N N ECT 2 5 0 ,2 6 9 ,2 7 1 PRU_LISTEN 255 PRU _PEERA D D R 275 PRU_RCVD 2 7 7 ,2 7 9 ,2 8 1 -2 8 2 , 304 PRU RCYO O B 275

PRU_SEN D 7 9 ,9 5 ,100 ,122-124 ,159 ,163-164 , 248 ,25 6 ,2 7 4 ,2 7 7 -2 7 9 ,2 8 1 ,2 8 6 ,2 8 8 ,3 0 3 -3 0 4

PRU_SEN D_EO F 53, 7 7 ,7 9 , 9 5 ,1 0 0 ,1 2 2 -1 2 4 , 1 2 9 ,1 5 9 ,1 6 3 -1 6 5 ,1 6 7

PRU_SENDOOB 7 9 ,2 7 5 PRU_SENSE 274-275 PRU_SH UTDO W N 1 6 5 ,2 7 2 PRU_SLOW TIM O 276 PRU_SOCKADDR 275 PR U _XXX 159, 274przekazyw anie deskryptorów 282 -2 8 3 ,2 8 5 ,

287przestrzeń nazw 245 przesyłanie grupow e 26-27, 8 6 ,9 4 przew idyw anie nagłów ka 2 7 ,137-139 ,

215-217 ,219 przyszłość T /T C P 166

Qqfds 293 Q uarterm an 325 quit 226

Rradix-32 226radix_node_head 8 3 ,8 5 , 87, 93-94Raggett D. 326Rago S. A. 2 3 6 ,2 7 9 , 326raw _ 244rcv-sb_cc 281-282rcv_adv 142-143 ,147rcv_w nd 142RDP XIX, 25 -26 ,325-326read 9 ,1 7 ,2 1 ,2 3 4read_stream 9 ,1 1 ,1 7 ,2 1 , 320recvfrom 3, 5, 7 ,1 7 ,2 0 -2 1 , 305recvit 288 ,2 9 1recvm sg 2 8 4 -2 8 6 ,2 9 1 ,2 9 4Reed D. A. 325Referer 175release 294REPLY 3REQUEST 3resid 79retransmisja SYN 206-207 return 133 retval 2 6 5 ,2 6 7 ,2 6 9 RFC 1009 323 RFC 1036 2 2 1 ,3 2 4 RFC 1045 2 5 -2 6 ,3 2 4

Page 358: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

336 Indeks

RFC 1122 13, 3 8 ,2 0 7 , 2 0 9 ,3 2 3 RFC 1151 2 5 ,3 2 6 RFC 1185 1 5 ,6 2 ,6 4 ,3 2 4 RFC 1191 5 6 ,2 0 4 ,2 0 6 ,3 2 5 RFC 1323 3 2 -3 4 ,4 0 ,4 3 ,1 1 0 ,1 1 2 ,1 2 7 ,

166-167, 2 0 6 ,3 2 4 RFC 1337 6 5 ,3 2 3 RFC 1379 1 5 ,2 6 ,3 9 ,7 4 ,3 2 3 RFC 1436 323 RFC 1630 323RFC 1644 2 6 ,3 2 ,7 1 ,7 5 ,1 0 1 ,1 2 0 ,1 2 7 ,1 4 7 ,3 2 4RFC 1700 326RFC 1716 323RFC 1738 323RFC 1808 324RFC 1812 6 4 ,3 2 3RFC 791 5 6 ,3 2 6RFC 793 3 2 ,3 8 ,5 6 ,6 2 ,6 4 -6 5 ,6 9 ,1 1 0 ,1 2 2 ,3 2 6RFC 908 25RFC 938 2 4 ,3 2 5RFC 955 2 5 -2 6 ,3 2 3RFC 977 221rm x_expire 86-87, 9 1 ,9 3rm x_filler 115rm x_m tu 1 2 2 ,1 2 6 ,1 6 4rm x_recvpipe 127rm x_rtt 1 1 7 ,1 2 1 ,1 2 5rm x_rttvar 117rm x_sendpipe 127rm x_ssthresh 129rm xp_tao 8 4 ,1 1 6rm x_taop 8 4 ,1 1 6rn_ 82rn_addroute 81, 86rn_delete 81rn_inithead 84-85rn_inithead:rnh_addaddr 85rn_m atch 81, 86rn_w alktree 81, 88-90, 92rnh 83, 89rnh_addaddr 85rnh_close 83, 8 5 ,8 7 , 93rnh_m atchaddr 85-86, 93R oseM . T. 326route 9 3 ,1 1 4 -1 1 5 ,1 2 2 ,1 2 7route_output 93rp 289RPC 24rstevens@ noao.edu XVII rsv 265 rt 82rt_flags 83rt_m etrics 83, 9 3 ,1 1 5 ,1 1 7 ,1 2 2 ,1 6 4 , 213 rt_prflags 83

rt_refcnt 8 3 ,8 6 rtalloc 114 rtallocl 86, 93 rtentry 8 3 -8 4 ,1 0 2 ,1 1 6 RTF_CLONING 83 RTF_HOST 8 7 ,1 1 6 RTF_LLIN FO 87 R T F JJ P 116 rtfree 83, 87, 93 RTM _ADD 85 RTM _LLINFO 93 RTM _RESOLVE 85 RTM .RTTUN IT 121 RTO 63, 6 6 ,1 0 3 ,1 1 6 -1 1 7 ,1 1 9 , 209 RTPRF_OURS 8 3 ,8 6 -8 7 ,9 1 RTPRF_W ASCLO N ED 83, 87 rtq_minreallyold 8 2 ,8 9 -9 0 rtq_reallyold 8 2 ,8 7 ,8 9 -9 2 rtq_tim eout 82, 88-89, 92 rtq_toom any 8 2 ,8 9 rtqk_arg 88-91 rtrequest 83, 85, 87, 9 1 ,1 0 2 RTT 6 -7 ,1 1 ,1 7 -1 8 , 22, 31, 62-64, 6 7 ,1 2 5 ,

1 9 6 -1 9 9 ,2 1 5 ,2 1 8 -2 1 9 ,3 0 5 -3 1 1 ,3 1 4 -3 1 5 RTV_BIT 125 R TV _R TT121 RTV_RTTVAR 121

sSA 3Salus P. H. 221, 326 Sax J. 25, 327 sb_cc 280-281 sb_hiwat 280-282 sb_m ax 127 sb_m bcnt 280 sb_m bm ax 280-282 sbappend 163, 280 sbappendaddr 2 7 8 ,2 9 4 sbappendcontrol 280, 294 sbappendcontrol 288 sbreserve 127 Schmidt D. C. XVII SCM_RIGHTS 2 8 4 ,2 8 9 ,2 9 3 select234send 1 7 ,7 7 , 7 9 ,3 1 9 ,3 2 2 send_request 320-321 sendalot 112 sendit 286sendm sg 77-79, 9 5 ,1 5 9 -1 6 0 ,1 6 2 ,1 6 4 ,1 6 7 ,

248, 277, 280, 284-286, 289, 319

Page 359: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Indeks 337

sendto 3 ,5 ,1 7 ,2 0 -2 1 ,2 9 ,4 4 ,4 6 , 5 2 ,5 4 , 61, 77-79, 95, 9 8 ,1 0 0 ,1 2 4 ,1 4 1 ,1 5 9 -1 6 0 ,1 6 2 , 1 6 4 -1 6 5 ,1 6 7 ,2 4 5 ,2 5 6 ,2 7 6 ,2 7 8 ,3 0 5 , 312-313,319-321

SEQ_xx 100 Server 175 serw er iteracyjny 11 serw er pośredniczący (proxy) 214 serw er p roxy 182 serw er w stępnie rozgałęziony 11 sesja HTTP 182 setsockopt 321 SGML 172Shim om ura T. 4 5 ,3 2 6shutdow n 8 ,1 7 , 29, 7 7 ,1 4 1 , 272, 319, 322sieć testow a 19Skibo T. 1 1 0 ,1 6 7sklonow ana m arszruta 8 3 ,8 6Sklower K. XVskrócenie czasu TIM E_W AIT 6 5 ,6 7 sleep 5SLIP 1 9 6 ,2 0 8 ,2 3 0SMTP 9 ,1 5 , 69, 223snd_cw nd 5 0 -5 1 ,1 2 8snd_m ax 108sn d _ n x t108snd-sb_hiw at 281snd_ssthresh 129snd_una 147 ,1 5 4snd_w nd 50-51so 2 5 7 ,2 6 1 ,2 6 4so2 257, 2 6 1 ,2 6 4 , 2 7 7 ,2 8 0 ,2 8 2so2 = so3 258SO _ACCEPTCO N N 258so_error 273so_head 2 5 8 ,2 6 4 ,2 7 3SO _KEEPALIVE 212so pcb 249so_q 2 5 8 ,2 6 4 , 297so_q0 2 5 8 ,2 6 4so_q01en 199so_qlen 199 ,2 5 8SO_REUSEADDR 60-61so_state 264soaccept 269socantrcvm ore 272socantsendm ore 1 6 5 ,2 7 2sock 229SOCK_DGRAM 2 3 4 ,2 6 4 SOCK_RDM 25 SOCK_SEQPACKET 25 SOCK_STREAM 2 5 ,2 3 4 SOCK_TRANSACT 26 sockaddr 275

sockaddr_in 9 6 ,1 1 4sockaddr_un 237, 2 3 9 ,2 4 1 ,2 4 4 ,2 4 6 ,2 5 4 ,2 5 8 ,

2 6 9 ,2 7 5 ,2 7 7 sockargs 2 5 4 ,2 5 7 ,2 8 6 , 288 socket 2 ,5 ,8 ,1 7 , 5 2 ,2 3 8 ,2 4 6 ,2 4 9 ,2 5 1 ,2 5 5 ,

2 5 8 ,2 6 0 -2 6 1 ,2 6 5 ,2 6 9 ,2 7 2 -2 7 3 ,2 7 7 ,2 8 0 , 282, 297

socketpair 2 4 1 ,2 6 0 -2 6 1 ,2 6 4 -2 6 8 ,2 7 6 sockfd 11 soclose 273soconnect2 2 6 1 ,2 6 6 ,2 6 8 -2 6 9 socreate 2 6 5 ,2 6 9 sofree 273soisconnected 143 ,264 soisconnecting 162 soisdisconnected 251 ,271 SOL_SOCKET 2 8 9 ,2 9 3 Solaris 1 5 ,5 5 -5 7 ,5 9 ,2 0 1 ,2 0 3 , 236, 305 solisten 258SO M A X C O N N 1 0 ,1 9 8 ,2 0 1 sondow anie trw ałości połączenia 208-209, 211sonew conn 1 9 8 ,2 4 9 ,2 5 8 ,2 6 9 soqinsque 258soreceive 2 8 1 ,2 8 6 ,2 9 0 ,2 9 4 ,3 0 3 soreserve 249sorflush 2 5 2 ,2 9 2 ,2 9 4 ,2 9 6 ,3 0 1 sorw akeup 278 ,2 8 1sosend 5 3 ,7 7 -7 9 ,1 0 0 ,1 6 4 ,2 1 4 -2 1 5 ,2 8 0 -2 8 1 ,

303, 322 soun-sun_path 2 5 3 ,2 5 6 Spero S. E. 326 splnet 79 splx 79SPT 6 - 7 ,1 1 ,1 5 ,1 7 ,2 2 ,5 7 SRC 172SS.CA N TSEN D M O RE 165S SJSC O N FIR M IN G 79S SJSC O N N E C T E D 264SS_NOFDREF 258st_blksize 274st_dev 275st_ino 275standardow y uogólniony język znakow aniainformacji 172

•stany rozszerzone 38-39stare duplikaty 6 5 ,6 8 ,7 0stat 274-275Stein L. D. 326step6 1 4 9 ,1 5 2 ,2 1 8Stevens W. R. 2 ,7 ,1 1 , XIII-XIV, XVI, XVII,

2 4 ,9 0 ,2 3 5 ,2 4 5 ,2 8 2 , 327 Stevens, D A . XVI Stevens, E.M . XVI

Page 360: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

338 Indeks

strncpy 238-239strona w yw oław cza 172struct dom ain 242struct protosw 242struct sockaddr 242struct sockaddr * 3subnetsarelocal 50sum a kontrolna 1 3 7 ,2 3 4 ,3 1 1sun XVIII, 180, 306sun_nonam e 2 4 2 ,2 6 9 ,2 7 5 ,2 7 7sun_path 244SunOS 1 5 ,2 6 ,2 8 ,1 6 7 ,2 3 6SVR4 2 8 ,5 4 -5 5 ,5 7 ,2 3 6 , 269, 2 7 9 ,2 8 2 ,3 2 0sw itch 149SYN , czas otrzym yw ania 1 9 1 ,1 9 3 ,1 9 5 SYN_RCVD 3 6 ,3 9 ,1 0 8 ,1 4 8 ,1 5 2 -1 5 3 ,1 6 6 ,

168, 202 SYN_RCVD* 3 9 ,1 0 8 ,1 5 3 SYN _SEN T 3 6 ,3 8 -3 9 ,5 3 ,1 0 5 -1 0 6 ,1 0 8 ,1 4 4 ,

1 4 6 ,1 4 8 -1 4 9 ,1 5 7 ,1 6 2 ,1 6 5 -1 6 6 ,1 6 8 SYN_SENT* 3 8 -4 0 ,4 5 ,4 7 ,5 3 ,1 0 8 ,1 1 0 ,

1 4 7 -1 4 8 ,1 6 2 ,1 6 5 sy s /u n .h 241 sys/u n p cb .h 241 sysctl 82, 8 7 ,1 0 0 -1 0 1 ,1 6 6 syslog 2 3 5 ,2 7 8 syslogd 9 0 ,2 3 5 ,2 7 8 system plików 254 szerokość pasm a 314-315 szkic internetow y 170 szybka retransmisja 2 7 ,1 5 3 szybkie odtw orzenie połączenia 2 7 ,1 5 3

r

sśw iatow a pajęczyna 169

Tt 229t_duration 35 ,101-103 t_flags 101 t_idle 211t_m axopd 1 0 1 ,1 1 2 ,1 1 4 ,1 2 3 -1 2 4 ,1 2 6 , 1 2 8 -1 2 9 ,1 3 1 ,1 6 4t_m axseg 1 0 1 ,1 1 4 ,1 2 3 -1 2 4 ,1 2 7 -1 2 9 ,1 3 1 ,1 6 4t_rttm in 125t_rttvar 121 ,125t_rxtcur 125t_srtt 121 ,1 2 5t_state 1 3 8 ,1 4 7tablica rutow ania T /T C P 81tablica rutow ania T /T C P , symulacja 212

TAO 1 8 ,3 2 ,6 9 ,7 1tao_cc 35, 73, 8 1 ,8 3 ,9 3 ,1 0 2 ,1 0 5 ,1 3 1 ,1 4 1 ,

148 ,153tao_ccsent 35, 4 4 ,4 6 ,5 5 ,7 3 ,8 1 , 83, 9 3 ,1 0 7 ,

145 ,1 6 3tao_m ssopt 3 5 ,4 9 , 8 1 ,8 3 , 9 3 ,1 2 9 ,1 6 4tao_noncached 105-106taop 105 ,124Taylor J. L. XVII, 315tcp_backoff 209tcp_cc 84, 9 9 ,101tcp_ccgen 3 5 ,4 4 ,4 6 ,4 8 ,6 7 ,6 9 -7 1 ,7 3 -7 6 ,

9 9 -1 0 0 ,1 0 2 -1 0 3 ,1 4 1 ,1 6 3 tcp_close 1 1 3 ,1 1 7 ,1 2 0 -1 2 1 ,1 3 3 ,1 6 1 tcp_connect 9 5 ,1 5 9 -1 6 2 ,1 6 4 -1 6 5 ,1 6 7 tcp_conn_req_m ax 201 tcp_ctloutput 159 tcp_disconnect 165 tcp_dooptions 1 1 3 ,1 2 7 ,1 2 9 -1 3 3 ,1 3 5 ,

137-140 ,164 tcp_do_rfcl323 100tcp_do_rfcl644 9 9 -1 0 0 ,1 0 3 ,1 0 9 ,1 1 4 ,1 3 1 tcp_drop 211tcp_gettaocache 1 1 3 ,1 1 5 -1 1 6 ,1 3 3 ,1 4 0 tcp_init 102tc p jn p u t 1 1 3 ,1 2 1 ,1 2 3 ,1 2 9 -1 3 1 ,1 3 5 ,1 3 7 -1 4 4 ,

146-157, 218 tcp_iss 162TCP_ISSINCR 7 4 ,1 6 2 tcp_last_inpcb 215 tcp_m axpersistidle 209 ,2 1 1 TCP_M AXRXTSHIFT 2 0 3 ,2 0 9 tcp .m ss 1 0 8 -1 0 9 ,1 1 3 -1 1 4 ,1 2 1 ,1 2 3 ,1 3 3 tcp_m ssdflt 1 1 4 ,1 2 2 ,1 2 4 ,1 2 6 tcp_m ssrcvd 1 0 1 ,1 0 9 ,1 1 3 ,1 1 7 ,1 2 1 ,1 2 3 -1 2 9 ,

1 3 1 ,1 3 3 ,1 6 4 tcp_m sssend 1 0 9 ,1 1 3 ,1 2 1 -1 2 2 ,1 3 3 tcp_new tcpcb 1 0 9 ,1 1 3 ,1 1 7 ,1 3 1 TCP_NOOPT 110 ,159 TCP_N O PUSH 5 2 -5 4 ,1 0 7 -1 0 8 ,1 5 9 ,3 2 1 tcp_outflags 105tcp .o u tp u t 5 3 -5 4 ,1 0 5 -1 1 4 ,1 2 1 -1 2 2 ,1 4 2 -1 4 3 ,

1 4 7 ,1 5 9 ,1 6 3 ,1 6 5 tcp_rcvseqinit 1 4 0 ,1 4 2 ,1 4 5 TCP_REASS 5 2 ,1 3 1 ,1 3 3 ,1 5 3 tcp_rtlookup 1 1 3 -1 1 6 ,1 2 2 ,1 2 4 ,1 3 3 tcp_sendseqinit 140 ,1 6 2 tcp_slow tim o 99 ,101-103 tcp_sysctl 1 0 0 -1 0 1 ,1 5 9 ,1 6 6 tcp_taook 100 tcp_tem plate 161 tcp_totbackoff 209 tcp_usrclosed 5 3 ,1 5 9 ,1 6 2 ,1 6 5 ,1 6 7

| tcp_usrreq 113 ,1 5 9

Page 361: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

Indeks 339

tcpcb 3 6 ,1 0 1 ,1 1 2 ,1 3 8tcpdum p-reduce 188TCPO LEN _C C _A PPA 127TCPO LEN _TSTAM P_APPA 126tcpopt 1 29-131 ,137tcps_accepts 188tcps_badccecho 100tcps_ccdrop 100tcps_connattem pt 188tcps_connects 143tcps_im pliedack 100TCPS_LISTEN 138tcps_pcbcachem iss 215tcps_persistdrop 209tcps_rcvoobyte 132tcps_rcvoopack 132TCPS_SYN_SENT 147tcps_taofail 100tcpstat 100, 209TCPT_KEEP 203TCPTV_KEEP_IDLE 209TCPTV_M SL 103TCPTV_TW TRUNC 103 ,155Telnet 5, XVIII, 2 8 ,5 9 ,2 2 3 , 226TF_ACKN O W 1 4 3 ,1 4 7TF_N EED FIN 102TF_N EED SYN 102TF_N O D ELA Y 107TF_N O O PT 1 0 9 -1 1 0 ,1 3 1 ,1 3 8TF_N O PUSH 5 3 ,1 0 2 ,1 0 5 ,1 0 7 ,1 3 8TF_RCVD_CC 1 1 2 ,1 3 1 ,1 5 1TF_RCVD_TSTM P 109 ,131TF_REQ _CC 1 0 9 ,1 1 4 ,1 3 1 ,1 5 1TF_REQ_TST A M P 126TF_SEN D CCN EW 102 ,111TF_SEN D FIN 4 0 ,1 0 2 ,1 3 9 ,1 4 7 ,1 6 6 ,1 6 8TF_SENDSYN 4 0 ,1 0 2 ,1 3 9 ,1 5 2 ,1 5 4 -1 5 5 ,1 6 2TF_SENTFIN 102TH _FIN 105TH_SYN 1 0 5 ,1 0 7ti_ack 145tim e.tv_sec 87TIM E_W AIT 13, XIII, 22, 31, 3 6 ,3 8 -3 9 ,4 7 ,

5 9 -6 9 ,75 -76 , 95, 98-99 ,101-103 , 137, 1 4 9 -1 5 0 ,1 5 4 -1 5 7 ,1 6 1 ,1 6 7 , 207, 319

tim eout 90, 92 tiwin 141 to 141to_cc 1 3 1 ,1 3 7 to_flag 130-131 ,139 to_tsval 139 TO F_CCN EW 131 TOF_TS 139 tom 1 XIII, 327

tom 2 XIII, 327 Torrey D. 323 tp 109 tpO 138 TP4 79transakcja 1, XIII trimthenstepó 1 3 1 ,1 4 3 ,1 4 9 Troff XVII tryb nasłuchu 188 ts_present 139 ts_recent 139 ts_val 139 tt_duration 35 ttcp 235TT CP_C LIEN T_SN D_W N D 164 TTL 6 4 ,3 2 6 tuc 20tuc.noap.edu 20 typedef 8 4 ,9 9 tytuł H TM L 172

Uu_long 101, 242 u_short 101 uap 265 ucl.ac.uk 307 UDP 25UDP_SERV_PORT 5udp_sysctl 101UICLSYSSPACE 2 5 3 ,2 5 6uipc_usrreq 244, 248, 275, 288uipc_usrreq.c 241unikanie przeciążenia 181, 324unikanie w ysyłania głupich segm entów 107uniwersalne nazw y zasobów 173unix 235unixdom ain 242-243 unixsw 2 42-243 ,248 unlink 254 unp 252, 261 ,2 7 1 unp2 261, 271 unp2-unp_refs 271 unp_addr 2 4 6 ,2 5 2 ,2 5 5 ,2 7 5 unp_attach 249-250 unp_bind 245, 252-253 unp_cc 281unp_conn 246, 260-262, 271, 275 unp_connect 245, 255-260, 277 unp_connect2 2 5 7 ,260-261 , 263, 269 unp_defer 242, 296-297, 299, 303 unp_detach 250 -2 5 1 ,2 7 3 , 2 9 2 ,2 9 4 , 296 unp_discard 291-293, 296, 301

Page 362: Biblia TCP IP Tom 3 - Uzupelnienie.pdf

340 Indeks

unp_disconnect 2 5 1 ,2 6 9 -2 7 1 ,2 7 3 ,2 7 9 unp_dispose 292-293, 296, 301 unp_drop 2 5 1 ,2 7 3 unp_externalize 2 8 6 ,2 8 8 ,2 9 0 -2 9 1 unp_gc 2 5 2 ,2 9 0 ,2 9 3 -2 9 7 ,2 9 9 -3 0 3 unp_gcing 2 4 2 ,2 9 6 , 302 unp_ino 242, 275unp_intem alize 2 7 7 ,2 8 6 ,2 8 8 -2 9 0 ,2 9 2unp_m ark 2 9 3 ,2 9 6 -2 9 7 ,2 9 9 ,3 0 2unp_m bcnt 281unp_nextref 261-262 ,271unp_refs 2 4 6 ,2 5 1 ,2 6 1 -2 6 2unp_rights 242 ,252 ,285 ,290-292 ,294-295 ,301unp_scan 2 9 2 -2 9 3 ,2 9 7 ,2 9 9 ,3 0 1 -3 0 2unp_shutdow n 272unp_socket 249unp_vnode 246, 254-255u np_xxx 249unpcb 2 4 0 ,2 4 5 -2 4 6 ,2 4 9 ,2 5 1 -2 5 2 ,2 5 7 -2 5 8 ,

2 6 0 -2 6 1 ,2 7 3 ,2 7 5 -2 7 6 unpdg_recvspace 242 unpdg_sendspace 242 unpst_recvspace 242 unpst_sendspace 242 unp-unp_cc 282 unp-unp_conn-unp_cc 281 unsigned long 99 update 89 updating 90-92 URI 173 U R L 173 U R N 173U ser-A gent 1 7 5 ,1 7 7 usr_cIosed 168 utw ente.nl 307 uu.net 308

Vv 254v-node 246v_socket 2 4 6 ,2 5 5 ,2 5 7 -2 5 8 v attr 255V A TTR _N U LL 255 Velten D. 25, 327 vm stat -m 301 VM TP 2 5 -2 6 ,3 2 4vnode 2 4 6 ,2 5 5 , 257-258, 2 6 1 ,2 7 6 ,2 8 4 ,2 9 9void * 3VOP 255V O P_ 253-254VO P_CREA TE 255VO P_IN ACTIVE 254

V O P_U N LO CK 254 vput 254 vrele 2 5 1 ,2 5 4 VSOCK 2 5 5 ,2 5 7 vsprintf 2

WW ait J. W. XVII w akeup 5w cielenie połączenia 47, 6 1 -6 2 ,64 -67 , 6 9 ,7 5 ,

9 5 ,9 8 ,1 5 7 ,1 6 0 ,1 6 7 , 207 w ebgatel 214 W ei L. 2 6 ,1 6 7 while 251 W olff R. XVII W olm ann G. 27 W right G. R. XIII, XV, 327 w rite 8 ,1 1 ,1 7 ,2 9 , 7 7 ,1 4 1 ,2 3 4 , 319, 322 W W W 5 ,1 0 ,1 3 , XV, 23, 59, 81, 9 0 ,1 6 7 ,1 8 8 ,

1 9 0 ,1 9 6 ,2 0 0 ,2 0 4 ,2 0 6 ,2 0 8 , 212, 2 1 9 ,2 2 2 ,2 2 9 ,3 1 1 ,3 2 3 -3 2 4

W W W -A uthenticate 175 w w w .aw .com 178 w w w .ncsa.uiuc.edu 173 w w w .netscape.com 190 w w w .organization.com 190 w w w p roxy l 214

XX 235X W indow s System XVIX0 254xhdr 2 2 8 ,2 3 0xover 230XXX 79

YY ee B. S. 301

Zzasada odporności 56 zbieranie bezużytecznych danych 294-295,

2 9 7 ,2 9 9 , 301 zdolność adaptacyjna XIII zegar nawiązywania połączenia 143,162,202-203 zegar podtrzym yw ania połączenia 202 Zhang L. 1 5 ,3 2 4

Page 363: Biblia TCP IP Tom 3 - Uzupelnienie.pdf