Virtlab:Konzolový server

Z VirtlabWiki

Verze z 13:38, 17. 3. 2008; zobrazit aktuální verzi
← Starší verze | Novější verze →
Přejít na: navigace, hledání

Obsah

Úkoly konzolového serveru

Jeho úkolem je zprostředkovat přístup k sériovým nebo telnetovým konzolím síťových zařízení prostřednictvím jednoduchého protokolu nad TCP/IP. Je využíván Java Appletem, který běží ve webovém ovládacím rozhraní, což umožňuje uživateli jednoduchý přístup k síťovým zařízením. Zároveň slouží i jako proxy server, který zprostředkovává přístup k zařízením, která jsou připojena ke vzdáleným konzolovým serverům, kam nemá místní uživatel přímý přístup. Také prostřednictvím speciálního PHP skriptu ověřuje, jsou-li požadavky uživatele oprávněné a tím konzoly prvků zabezpečuje od neautorizovaného přístupu.

Popis implementace

(pozor: nejde o skutecny sekvencni diagram)

Zdrojový soubor server.c obsahuje hlavní funkci (main), která po úvodní inicializaci volá v nekonečném cyklu funkci obsluhuj_klienta().

"Základní funkce Cserveru"

Ve funkci obsluhuj_klienta() jsou pak načteny 4 řádky parametrů od klientského apletu. Tyto parametry jsou ověřeny pomocí funkce check_applet_args() a v případě, že klient chce takto přistupovat k prvku, který má korektně na danou dobu rezervován, vrátí funkce čas do konce rezervace (v sekundách). (V opačném případě vrací nulu a obsluhuj_klienta() následně skončí.)

V případě úspěchu se nastaví alarm() a hned potom se dostane ke slovu funkce open_dev_fd(), která ověří, jestli zařízení již není používáno jiným apletem. Není-li, zamkne jej pro výlučný přístup a vrátí na něj deskriptor.

"Funkce volane z obsluhuj_klienta()"

Zamykání konzoly zařízení pro výlučný přístup

int lock_device( char *filename );
void unlock_device( void );

Tyto dvě funkce zajistí zamčení resp. odemčení konzoly aktivního prvku pro výlučný přístup. Funkce lock_device nejprve ověří, zda je zařízení "volné". Pokud ano, uzamkne jej tak, aby k němu měl přístup pouze aktuální proces. V opačném případě vrátí informaci, že zařízení je již používáno, na kterou pak proces reaguje tak, že po sobě uklidí, upozorní uživatele a skončí.

Funkce unlock_device funguje "inverzně" - bylo li zařízení zamčeno aktuálním procesem, odemkne jej, v opačném případě s ním nic neudělá.

Jak je to implementováno

Celá implementace je založena na použití volání systémové funkce

open( lock_file_name, O_RDWR | O_CREAT | O_EXCL )

Takto zavolaná funkce se pokusí vytvořit soubor s názvem lock_file_name s exkluzivním přístupem. Pokud již soubor existuje, vrátí chybu. Tohoto chování využívá naše funkce lock_device, která si takto vytváří pomocné soubory v adresáři /tmp. Jméno souboru vychází z označení aktivního prvku, ke kterému se vztahuje. Najde-li funkce lock_device již existující soubor, považuje odpovídající zařízení za obsazené. V opačném případě si jej "zamkne" vytvořením tohoto pomocného souboru.

Zde je ještě důležité upozornit na chování unlock_device, která se před odemčením musí přesvěčit, že aktuální proces je vlastníkem zařízení. To pozná podle hodnoty proměnné locked.Tato funkce se totiž volá na vždy na konci procesu, který pracuje s konzolou zařízení. Kdyby tento test neproběhl, mohlo by se stát, že proces uvolní zařízení, které "nevlastní".

Kde hledat pomocné soubory

V adresáři /tmp

Struktura zdrojových souborů

Výše uvedené diagramy popisovaly základní funkce obsažené v základním zdrojovém souboru server.c + pár funkcí z dalších zdrojových souborů.

Dále si popíšeme strukturu hlavního souboru - server.c (.h)

Odchytávání signálů SIGPIPE a SIGALARM

SIG_ALRM je v konzolovém serveru využíván k automatickému ukončení po vypršení rezervace prvku, ke kterému jsem připojen. Po ověření práva přístupu uživatele ke konkrétnímu prvku je nastaven timer pomocí funkce alarm(seconds) na čas, kdy rezervace skončí. Je zde přihlíženo ik takzvané patičce - čas potřebný ke smazání uživatelovy konfigurace a případnému restartu prvku.

static void sig_pipe(int signo);
static void sig_alarm(int signo);


main

Hlavni funkce pro cely Konzolovy server.

Postupně provádí tyto akce:

  • nahraje soubor s doménami
  • nahraje soubor se zařízeními
  • vytvoří socket pro příjem spojení od klientů
    • a nastaví některé jeho parametry
    • funkcí bind jej pojmenuje
    • funkcí listen bude očekávat spojení od klientů
  • následuje "nekonečná" smyčka, ve které se vlastně pro každého připojeného klienta vytvoří nový proces, jehož úkolem je obsluha tohoto klienta. Tu zajišťujeme funkcí obsluhuj_klienta

obsluhuj_klienta

Tato funkce je spouštěna pro každý nově otevřený aplet v samostatném procesu (předtím je tedy volán fork). Jejím úkolem je pak řídit veškerou komunikaci od apletu k zařízení a zpět. Musí rovněž zajistit otevření tohoto obousměrného spojení a jeho korektní uzavření. Pro tyto účely využívá další funkce (viz. obrázek výše).

get_line_from_socket

Funkce znaky čte ze soketu, který dostane jako první parametr. Tím je právě vytvořený socket ke klientskému apletu. Přečte nejvýše tolik znaků, kolik udává třetí parametr a výsledek uloží do parametru dvě. Čtení končí, narazí-li na znaky CR/LF nebo načte-li maximální počet znaků (třetí parametr).

Tato funkce je tedy volána na začátku obsluhy klienta a její pomocí o něm zjistíme potřebné informace. Ty pak ověřujeme ve funkci check_applet_args().

check_applet_args

Funkce, ktera zkontroluje platnost parametru poslanych appletem oproti webovemu serveru

  • V případě, že aplet s těmito parametry má právo přistupovat k požadovanému zařízení, funkce vrátí počet sekund do konce rezervace (bez "patičky")
  • V opačném případě vrátí hodnout 0

Vlastní kontrolu parametrů provádí externí skript check-applet-args.sh, který výsledek zapíše do souboru v /tmp/. Z něj pak druhý proces hodnotu převezme. (Druhým procesem je myšlen rodičovský proces - po volání funkce fork)

# define applet_checker "./check-applet-args.sh"
# define result_basefile "/tmp/appletchecker"
int check_applet_args(char* sid, char* sip, char* did, char* tm, char *resid)
{
  ...
      fork();
  //child:
      execlp(applet_checker, applet_checker, sid, sip, did, tm, resid, result_file, (char*)(NULL));
  //parent:
      //prevezmi hodnotu ze souboru a pak ji predej jako svou navratovou hodnotu pomoci
      return result;
  ...
 }

open_dev_fd

funkce, ktera otevre seriovy port/TCP stream pro cteni

int open_dev_fd(const char *_dev_id, int *target_is_cserver, int tutor, int* fd_to_tutor);
  • Funkce nejdříve převezme první argument a rozdelí jej na část pro zařízení a část pro lokalitu. Následně ověří, zda lokalita existuje a je dostupná. Stejnětak ověří i existenci zařízení. Podle typu zařízení a hlavně jeho umístění se rozhoduje, zda se s ním bude komunikovat přes sériový port, nebo přes TCP spojení (Jde-li o vzdálené zařízení.)
  • V této funkci dochází rovněž k zamykání konzolí laboratorních prvků. V případě, že již je prvek zamknut, celý proces končí a do klientského apletu je poslána informace o tom, že zařízení je již používáno jiným procesem a apletem.


close_fd_dev

Zavre socket zarizeni, je-li od tutora ke klientovi, posle jen zpravu o ukonceni

void close_fd_dev(int fd, int is_tutor)
{
  if(is_tutor)
  {
    close_tutor(fd);
  }
  else
    close(fd);
}

get_timestamp

vrati casove razitko

char *get_timestamp(void);

Nastavení FD jako NONBLOCKING

void set_nonblocking(int fd);

Nastavení FD jako BLOCKING

void set_blocking(int fd);


Implementace zakázaných příkazů

Virtuální laboratoř funguje zcela automaticky. Po vypršení času rezervovaného jedním studentem se smaže jím vytvořená konfigurace a síťové prvky se připraví pro práci dalšímu uživateli. Tohle by nebylo možné, kdyby studenti mohli zadávat do zařízení například libovolná hesla, která by pak byla vyžadována i pro smazání konfigurace.

Některé příkazy bylo tedy nutné zakázat.

Zakázané příkazy

Osobní nástroje