Passer au contenu principal

Il y a environ 18 mois, j’ai rédigé un article de blog traitant des modifications apportées au fonctionnement de la fonction `accept` dans la version 17.1 d’OpenVOS. J’avais toutefois omis de préciser que ces modifications ne s’appliquent que si le code de l’application est basé sur POSIX. Pour résumer, avant la version 17.1, STCP ne répondait à une demande de connexion d’un client que si le code de l’application serveur avait appelé la routine `accept`. Si le code n'avait pas appelé accept, la demande de connexion du client était placée dans une file d'attente mais restait sans réponse. Une fois que l'application appelait accept, STCP envoyait une réponse de connexion. Si le client attendait toujours, la connexion était établie à ce moment-là. Si le client avait déjà abandonné, il répondait à la réponse de connexion par une réinitialisation, STCP rejetait la connexion et la routine accept se bloquait (en mode bloquant) pour attendre une autre connexion.

La figure 1 illustre ce scénario ; les lignes de texte alignées à gauche correspondent aux messages d'état de l'application serveur, tandis que les lignes en retrait de `packet_monitor` (légèrement modifiées) reflètent l'activité du client. L'application (acceptTestnoPosix) est lancée et écoute sur le port 12345 ; une fois en mode écoute, elle se met en veille pendant 300 secondes. Le client établit alors une connexion vers le port 12345 en envoyant un segment TCP à ce port avec le drapeau Syn (S) activé. Il effectue trois tentatives avant d'abandonner. Au bout de 300 secondes, l'application se réveille et appelle la fonction accept. La pile STCP répond au client avec un segment TCP dont les indicateurs Syn et Ack (SA) sont activés. Comme le client n'a plus de trace de la connexion, s'il envoie un Reset (R), STCP se bloque à ce stade. Si la socket était en mode non bloquant, accept aurait renvoyé une erreur EAGAIN.

acceptTestnoPosix 12345
Exécution de acceptTestnoPosix 12345
En attente pendant 300 secondes

  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

Prêt à accepter une connexion sur le port numéro 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

Figure 1 – Accepter les versions antérieures à la 17.1 ou les versions non POSIX postérieures à la 17.1

 

Si l'application est basée sur POSIX, le fonctionnement est différent (figure 2). STCP répond immédiatement à la demande de connexion (S) en créant une session (SA). Puis, au bout de 300 secondes, l'application se réactive, appelle la fonction `accept` et STCP renvoie le socket accepté.

acceptTestwithPosix 12345
Exécution de acceptTestnoPosix 12345
En attente pendant 300 secondes

  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

Prêt à accepter une connexion sur le port 12345
Connexion acceptée

Figure 2 – Acceptation des messages basés sur POSIX 17.1

 

Cette différence de comportement peut s'avérer cruciale. Si le client attend une réponse de l'application serveur après avoir établi une connexion, il risque de déclencher un délai d'expiration et de fermer la connexion avant même que l'application n'appelle la fonction `accept`.

Comment créer une application avec POSIX ? Tout d'abord, la ligne

#define _POSIX_C_SOURCE 200112L

doit figurer en première ligne du code source de l'application. Ensuite, le chemin d'accès à la bibliothèque

(master_disk)>système>bibliothèque d'objets POSIX

doit figurer dans les chemins d'accès à la bibliothèque d'objets, après les bibliothèques STCP et avant la bibliothèque C.

Comment savoir si cela a été fait ? Eh bien, vous pouvez consulter les bibliothèques d'objets auxquelles l'application a été liée à l'aide de la commande `display_program_module -object_dirs`.

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

Carte des répertoires d'objets :

    11  répertoires de recherche
     0  répertoires hors recherche
    11  répertoires au total

   DTC  Chemin d'accès au répertoire

     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

Mais cela ne permet pas de savoir si la directive #define fait partie du code source.

Si vous pouvez exécuter le code, vous pouvez vérifier les indicateurs de socket : un programme basé sur POSIX aura l'indicateur de socket SF_POSIX activé. Par exemple, j'ai trois programmes : acceptTestnoPosix, acceptTestwithPosix et acceptTestwithPosixPathOnly. Ce dernier avait le répertoire >system>posix_object_library dans les chemins d'accès aux bibliothèques, mais n'incluait pas la directive #define dans le code source. Notez qu'il s'agit là d'une combinaison non valide. Seule l'application liée à la bibliothèque POSIX et comportant la directive #define POSIX_SOURCE dans son code a créé une socket avec le drapeau SF_POSIX.

acceptTestnoPosix.pm 12345          
Exécution de acceptTestnoPosix 12345
Mise en veille pendant 300 secondes
               comme suit :  match posix ; dump_stcbq -full -lport 12345       
               comme suit :
acceptTestwithPosix.pm 12345
Exécution de acceptTestnoPosix 12345
Mise en veille pendant 300 secondes
               comme suit :  match posix ; dump_stcbq -full -lport 12345
                                                   SF_POSIX
               comme :  
acceptTestwithPosixPathOnly.pm 12345
Exécution de acceptTestnoPosix 12345
Mise en attente pendant 300 secondes
               comme suit :  match posix ; dump_stcbq -full -lport 12345
               comme suit :

Il existe une quatrième possibilité : la directive #define a été incluse dans le code source, mais la bibliothèque posix_object_library n'a pas été utilisée. Dans ce cas, la routine de socket renverra une erreur.

acceptTestwithPosixDefineOnly 12345
Exécution de acceptTestnoPosix 12345
acceptTestnoPosix : impossible de créer le socket d'écoute : l'application a été compilée  
+  de manière incorrecte : le runtime POSIX doit être recherché avant le runtime C.

Toutes les commandes et tous les utilitaires STCP sont développés selon les normes POSIX, et je recommande vivement que les applications que vous développez respectent également ces normes.