Passa al contenuto principale

Circa 18 mesi fa ho scritto un post sul blog in cui parlavo delle modifiche apportate al funzionamento della funzione `accept` nella versione 17.1 di OpenVOS. Ciò che avevo tralasciato di precisare era che tali modifiche hanno effetto solo se il codice dell'applicazione è basato su POSIX. Per ricapitolare, prima della versione 17.1, STCP rispondeva a una richiesta di connessione da parte del client solo se il codice dell'applicazione server aveva chiamato la routine `accept`. Se il codice non avesse chiamato accept, la richiesta di connessione del client sarebbe stata inserita in una coda ma non avrebbe ricevuto risposta. Una volta che l'applicazione avesse chiamato accept, STCP avrebbe inviato una risposta di connessione. Se il client fosse ancora in attesa, la connessione si sarebbe completata in quel momento. Se il client avesse già rinunciato, avrebbe risposto alla risposta di connessione con un reset, STCP avrebbe scartato la connessione e accept sarebbe rimasto in sospeso (ipotizzando la modalità di blocco) in attesa di un'altra connessione.

La figura 1 illustra questo scenario; le righe di testo allineate a sinistra sono messaggi di stato provenienti dall'applicazione server, mentre le righe di packet_monitor rientrate (leggermente modificate) sono il risultato dell'attività del client. L'applicazione (acceptTestnoPosix) viene avviata e rimane in ascolto sulla porta 12345; una volta avviata l'ascolto, entra in stato di sospensione per 300 secondi. Il client stabilisce quindi una connessione alla porta 12345 inviando un segmento TCP alla porta 12345 con il flag Syn (S) impostato. Effettua tre tentativi prima di rinunciare. Dopo 300 secondi l'applicazione si riattiva e chiama accept. Lo stack STCP risponde al client con un segmento TCP con i flag Syn e Ack (SA) impostati. Poiché il client non ha più traccia della connessione, se invia un Reset (R), STCP si blocca a questo punto. Se il socket fosse in modalità non bloccante, accept avrebbe restituito un errore EAGAIN.

acceptTestnoPosix 12345
Esecuzione di acceptTestnoPosix 12345
In attesa per 300 secondi

  11:04:45.923 R TCP 164.152.77.50   164.152.77.217  11071  12345 S
  11:04:48.925 R TCP 164.152.77.50   164.152.77.217  11071  12345 S
  11:04:54.937 R TCP 164.152.77.50   164.152.77.217  11071  12345 S

Pronto ad accettare una connessione sulla porta numero 12345
  11:09:41.852 T TCP 164.152.77.217  164.152.77.50   12345  11071 SA 
  11:09:41.854 R TCP 164.152.77.50   164.152.77.217  11071  12345 R

Figura 1 – Accetta versioni precedenti alla 17.1 o versioni non POSIX successive alla 17.1

 

Se l'applicazione è basata su POSIX, la situazione è diversa (Figura 2). STCP risponde immediatamente alla richiesta di connessione (S) (SA). Successivamente, dopo 300 secondi, l'applicazione si riattiva, chiama la funzione `accept` e STCP restituisce il socket accettato.

acceptTestwithPosix 12345
Esecuzione di acceptTestnoPosix 12345
In attesa per 300 secondi

  10:58:43.962 R TCP 164.152.77.50   164.152.77.217  11024  12345 S
  10:58:43.964 T TCP 164.152.77.217  164.152.77.50   12345  11024 SA 
  10:58:43.964 R TCP 164.152.77.50   164.152.77.217  11024  12345 A

Pronto ad accettare una connessione sulla porta numero 12345
Connessione accettata

Figura 2 – Accetta post basati su POSIX 17.1

 

La differenza di comportamento può essere determinante. Se il client si aspetta una risposta dall'applicazione server dopo aver stabilito una connessione, potrebbe andare in timeout e chiudere la connessione prima che l'applicazione chiami effettivamente la funzione `accept`.

Come si crea un'applicazione con POSIX? Innanzitutto la riga

#define _POSIX_C_SOURCE 200112L

dovrebbe essere la prima riga del codice sorgente dell'applicazione. In secondo luogo, il percorso della libreria

(master_disk)>system>posix_object_library

deve trovarsi nei percorsi della libreria degli oggetti dopo le librerie STCP e prima della libreria C.

Come si fa a capire se questa operazione è stata eseguita? Beh, puoi controllare le librerie di oggetti a cui l'applicazione è stata associata utilizzando il comando `display_program_module -object_dirs`

display_program_module acceptTestwithPosix -object_dirs      
     %azvos#m17_mas>SysAdmin>Noah_Davids>temp>acceptTestwithPosix.pm 

Mappa delle directory degli oggetti:

    11  directory di ricerca
     0  directory non di ricerca
    11  directory in totale

   DTC  Percorso directory

     1  %azvos#m17_mas>SysAdmin>Noah_Davids>temp
     2  %azvos#m17_mas>system>stcp>object_library
     3  %azvos#m17_mas>system>stcp>object_library>socket
     4  %azvos#m17_mas>system>stcp>object_library>net
     5  %azvos#m17_mas>system>stcp>object_library>common
     6  %azvos#m17_mas>system>posix_object_library
     7  %azvos#m17_mas>system>c_object_library
     8  %azvos#m17_mas>system>object_library
     9  %azvos#m17_mas>opt>apache>lib
    10  %azvos#m17_mas>opt>openssl>lib
    11  %azvos#m17_mas>opt>mysql>lib>mysql

Ma questo non ti dice se il #define fa parte del codice sorgente.

Se riesci a eseguire il codice, puoi controllare i flag del socket: un programma basato su POSIX avrà il flag SF_POSIX impostato. Ad esempio, ho tre programmi: acceptTestnoPosix, acceptTestwithPosix e acceptTestwithPosixPathOnly. Quest'ultimo aveva la directory >system>posix_object_library nei percorsi delle librerie, ma non includeva la definizione #define nel codice sorgente. Si noti che questa combinazione è considerata non valida. Solo l'applicazione che era stata collegata alla libreria POSIX e che aveva l'istruzione #define POSIX_SOURCE nel codice ha creato un socket con il flag SF_POSIX.

acceptTestnoPosix.pm 12345          
Esecuzione di acceptTestnoPosix 12345
In attesa per 300 secondi
               come:  match posix; dump_stcbq -full -lport 12345       
               come:
acceptTestwithPosix.pm 12345
Esecuzione di acceptTestnoPosix 12345
In attesa per 300 secondi
               come:  corrispondenza Posix; dump_stcbq -full -lport 12345
                                                   SF_POSIX
               come:  
acceptTestwithPosixPathOnly.pm 12345
Esecuzione di acceptTestnoPosix 12345
In attesa per 300 secondi
               come:  corrispondenza Posix; dump_stcbq -full -lport 12345
               come:

Esiste una quarta possibilità: il #define era presente nel codice sorgente, ma la libreria posix_object_library non è stata utilizzata. In questo caso, la routine socket restituirà un errore.

acceptTestwithPosixDefineOnly 12345
Esecuzione di acceptTestnoPosix 12345
acceptTestnoPosix: impossibile creare il socket di ascolto: l'applicazione è stata compilata  
+  in modo errato: il runtime POSIX deve essere cercato prima del runtime C.

Tutti i comandi e le utilità STCP sono realizzati secondo lo standard POSIX e consiglio vivamente di utilizzare POSIX anche per tutte le applicazioni che svilupperete.