Passer au contenu principal

L'extrait de code STCP suivant illustre un problème que j'ai constaté. Il reste bloqué sur l'appel recv jusqu'à ce qu'il y ait des données à lire, puis il traite les données reçues et appelle à nouveau recv, qui renverra soit d'autres données (ou une erreur), soit restera bloqué. Si une erreur s'est produite, recv renverra -1 et le code d'erreur sera enregistré dans la variable errno. Ce code vous semble-t-il correct ?

while (1)
   {
   cBytes = recv (socks1, buffer, BUFFERLEN, 0);
   if (cBytes == -1)
      {
      perror ("Unexpected error at recv");
      exit (errno);
      }
   else
      printf ("number of bytes received : %dn", cBytes);
   }

Le code part du principe que le correspondant distant ne fermera jamais la connexion de manière ordonnée. Lorsque le correspondant distant procède à une fermeture ordonnée, c'est-à-dire qu'il appelle la fonction close ou shutdown, la fonction recv le signale à l'application locale en renvoyant zéro octet. Les appels suivants à recv continueront de renvoyer zéro octet. Il en résulte que le code se retrouve alors dans une boucle sans issue qui ne fait rien. Par exemple

nombre d'octets reçus : 8
nombre d'octets reçus : 57
nombre d'octets reçus : 16
nombre d'octets reçus : 1
nombre d'octets reçus : 1
nombre d'octets reçus : 0
nombre d'octets reçus : 0
nombre d'octets reçus : 0
nombre d'octets reçus : 0
nombre d'octets reçus : 0
. . . . .

Même si le protocole d'application stipule que le correspondant distant ne fermera jamais la connexion de manière ordonnée, vous ne pouvez pas garantir que la connexion ne sera jamais fermée de cette manière. L'application distante peut comporter un bogue, ou la pile TCP distante peut procéder à une fermeture ordonnée lorsque le processus de l'application s'arrête. Il se peut aussi qu'une autre application ait établi une connexion puis l'ait fermée après n'avoir pas reçu la réponse attendue.  Un audit de sécurité (ou un utilisateur malveillant) effectuant un scan de ports ou une capture de bannière peut également procéder à une fermeture en douceur. En résumé, vous devez toujours gérer le cas où le flux est de zéro octet.

while (1)
   {
   cBytes = recv (socks1, buffer, BUFFERLEN, 0);
   if (cBytes <= 0)
      {
      if (cBytes < 0)
         {
         perror ("Unexpected error at recv");
         exit (errno);
         }
      else
         {
         printf ("received closen");
         close (socks1);
         exit (0);
         }
      }
   else
      printf ("number of bytes received : %dn", cBytes);
   }

nombre d'octets reçus : 28
nombre d'octets reçus : 2
nombre d'octets reçus : 58
commande de fermeture reçue