Guide pratique du maintien de connexion TCP

  Version franaise du TCP Keepalive HOWTO.

  Fabio Busatto

   <fabio.busatto@sikurezza.org>

  Laurent Gauthier

   Adaptation franaise <laurent POINT mail CHEZ gmail POINT com>

  Eric Deschamps

   Relecture de la version franaise <erdesc CHEZ free POINT fr>

  Jean-Philippe Gurard

   Prparation de la publication de la v.f. <fevrier CHEZ tigreraye POINT
   org>

   Version : 1.0.fr.1.0

   2007-05-04

   +------------------------------------------------------------------------+
   | Historique des versions                                                |
   |------------------------------------------------------------------------|
   | Version 1.0.fr.1.0          | 2008-05-02         | LG, ED, JPG         |
   |------------------------------------------------------------------------|
   | Premire adaptation franaise.                                         |
   |------------------------------------------------------------------------|
   | Version 1.0                 | 2007-05-04         | FB                  |
   |------------------------------------------------------------------------|
   | Premire dition, rvise par TM.                                      |
   +------------------------------------------------------------------------+

   Rsum

   Ce document dcrit l'implmentation du TCP keepalive dans le noyau linux,
   prsente le concept global et dtaille  la fois la configuration systme
   et le dveloppement d'application.

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

   Table des matires

   1. Introduction

                1.1. Droits d'utilisation

                1.2. Avertissement

                1.3. Remerciements et contributions

                1.4. Commentaires et corrections

                1.5. Traductions

   2. Aperu de TCP keepalive

                2.1. Qu'est-ce que TCP keepalive ?

                2.2. Pourquoi utiliser TCP keepalive ?

                2.3. Vrifier les htes injoignables

                2.4. viter une dconnexion due  une inactivit rseau.

   3. Utiliser TCP keepalive sous Linux

                3.1. Configurer le noyau

                3.2. Rendre les modifications persistantes au redmarrage

   4. Programmer des applications

                4.1. Quand votre code requiert keepalive

                4.2. L'appel de fonction setsockopt

                4.3. Exemples de code

   5. Implmenter keepalive sur une application tierce

                5.1. Modifier le code source

                5.2. libkeepalive: prchargement de bibliothque

1. Introduction

   Comprendre TCP keepalive n'est pas indispensable dans la plupart des cas,
   mais cela peut tre trs utile dans certaines circonstances. Il vous
   faudra possder quelques notions de base des rseaux TCP/IP et de la
   programmation en langage C pour comprendre toutes les sections de ce
   document.

   Le principal objectif de ce tutoriel (HOWTO) est de dcrire en dtail le
   TCP keepalive et de prsenter diffrents cas d'application. Aprs avoir
   dbut avec un peu de thorie, le propos se concentre sur l'implmentation
   des routines TCP keepalive dans les noyaux Linux actuels (2.4.x, 2.6.x),
   et sur les moyens dont les administrateurs systme peuvent tirer parti de
   ces routines, avec des exemples de configuration prcis et des astuces.

   La seconde partie de ce tutoriel met en jeu l'interface de programmation
   propose par le noyau Linux, et le mode d'criture des applications qui
   implmentent le TCP keepalive en langage C. Des exemples pratiques sont
   prsents, et une approche du projet libkeepalive est amorce, permettant
   aux applications de bnficier par hritage du keepalive sans modification
   de code.

  1.1. Droits d'utilisation

   Les droits de ce document, TCP Keepalive HOWTO, sont dposs sous
   copyright (c) 2007 par Fabio Busatto. Il est permis de copier, distribuer
   et/ou modifier ce document dans le cadre de la Licence de Documentation
   Libre GNU, Version 1.1 ou ultrieure publie par la Free Software
   Foundation; aucune section invariable, pas de texte de couverture. Un
   exemplaire de la licence est disponible  l'adresse
   http://www.gnu.org/licenses/licenses.fr.html#GPL
   [http://www.gnu.org/licenses/licenses.fr.html#FDL].

   Le code source inclus dans ce document relve de la licence publique
   gnrale (GPL) GNU General Public License, Version 2 ou ultrieure publie
   par la Free Software Foundation. Un exemplaire de la licence est
   disponible  l'adresse http://www.gnu.org/licenses/licenses.fr.html#GPL
   [http://www.gnu.org/licenses/licenses.fr.html#GPL].

   Linux est une marque dpose de Linus Torvalds.

  1.2. Avertissement

   Aucune responsabilit relative au contenu du prsent document ne sera
   endosse. L'utilisation des concepts, exemples et informations est  vos
   propres risques. Des erreurs ou imprcisions peuvent endommager votre
   systme. Agissez avec prcaution, et mme si cela est peu commun, l'auteur
   n'endosse aucune responsabilit (NdT : le traducteur non plus).

   Tous les droits sont dtenus par leurs propritaires respectifs, sauf
   mention particulire. L'utilisation de termes de ce document ne doit pas
   tre considre comme une atteinte  la validit d'une marque dpose ou
   marque de service. Citer un produit ou une marque ne devrait pas tre
   considr comme rprhensible.

  1.3. Remerciements et contributions

   Ce travail ne doit  personne que je devrais remercier. Mais il doit  ma
   vie, et  mon savoir aussi: donc, merci  chacun m'ayant soutenu, avant ma
   naissance, actuellement, ou dans le futur. Sincrement.

   Un merci tout spcial  Tabatha, la femme patiente qui a lu mon travail et
   fait les corrections ncessaires.

  1.4. Commentaires et corrections

   Vos retours sur ce document seront les bienvenus. Adressez vos ajouts,
   commentaires et remarques  l'auteur  l'adresse mail suivante :
   <fabio.busatto@sikurezza.org>.

  1.5. Traductions

   Si vous tes intress par la traduction de ce HOWTO en d'autres langues,
   n'hsitez pas  me contacter. Votre contribution sera la bienvenue.

   Langues disponibles :

     * anglais (document original)
       [http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/]

     * franais
       [http://www.traduc.org/docs/howto/lecture/TCP-Keepalive-HOWTO.html]

2. Aperu de TCP keepalive

   Afin de comprendre ce que fait TCP keepalive (que nous appellerons
   'keepalive'), vous n'avez besoin que d'en lire le nom : keep TCP alive
   (maintenir TCP en vie), c'est  dire conserver la connexion TCP. Cela
   signifie que vous serez en mesure de vrifier l'tat de votre socket de
   connexion (appele aussi socket TCP), et de dterminer si la connexion est
   toujours tablie ou si elle est rompue.

  2.1. Qu'est-ce que TCP keepalive ?

   Le concept du keepalive est trs simple: lorsque vous initiez une
   connexion TCP, vous y associez un jeu de chronomtres. Certains de ces
   chronomtres ont trait  la procdure du keepalive. Quand la dure
   maximale du keepalive est atteinte, vous adressez  l'hte distant un
   paquet sonde de keepalive ne contenant aucune donne, avec le bit ACK
   positionn. Cela est possible grce aux particularits de TCP/IP, une
   sorte de ACK doubl, et l'hte distant n'aura aucun argument, puisque TCP
   est un protocole orient flux. En retour vous aurez une rponse de l'hte
   distant (qui n'a nul besoin d'implmenter le keepalive, mais seulement
   TCP/IP), sans donne, et le ACK positionn.

   Si vous recevez une rponse  votre sonde keepalive, vous pouvez tre
   certain que la connexion est toujours tablie et active sans inquitude
   pour le niveau applicatif. Concrtement, TCP permet de maintenir un flux,
   sans paquet, donc un paquet de longueur zro n'est pas dangereux pour le
   programme utilisateur.

   Cette mthode est utile car si les autres points distants perdent leurs
   connexions (en raison d'un redmarrage par exemple) vous dtecterez que la
   connexion est rompue, mme sans avoir de flux de donne. Si les sondes
   keepalive n'obtiennent pas de rponse, vous pouvez certifier que la
   connexion ne peut plus tre considre comme valide et agir en
   consquence.

  2.2. Pourquoi utiliser TCP keepalive ?

   Vous pouvez vivre plutt heureux sans keepalive, donc si vous lisez ces
   lignes, soit vous essayez de comprendre si keepalive est une rponse
   possible  vos problmes, soit vous n'avez rien de plus intressant 
   faire et c'est bien aussi. :)

   Keepalive est non invasif, et dans la plupart des cas, si vous avez un
   doute, vous pouvez l'activer sans risque d'erreur. mais souvenez vous que
   c'est gnrateur de flux supplmentaire, ce qui peut avoir un impact sur
   les routeurs et les pare-feu.

   En rsum, utilisez vos mninges et soyez prudent.

   Dans la section suivante nous distinguerons les deux objectifs de
   keepalive:

     * S'assurer qu'un hte distant n'est pas injoignable

     * viter une dconnexion due  une inactivit rseau.

  2.3. Vrifier les htes injoignables

   Keepalive peut tre utilis pour tre averti que l'hte distant est mort
   avant qu'il soit capable de vous le notifier. Cela pourrait se produire en
   diffrentes circonstances, une panique noyau ou une interruption soudaine
   du processus maintenant la connexion par exemple. Un autre cas justifiant
   keepalive pour dtecter que l'hte distant n'est pas joignable est la
   dfaillance du rseau. Dans ce cas, si le rseau n'est pas  nouveau
   oprationnel, vous tes dans la mme situation que pour la mort de l'hte
   distant. C'est dans ces cas de figure que les mcanismes TCP classiques ne
   permettent pas de s'assurer de l'tat d'une connexion.

   Songez  une simple connexion TCP entre l'hte A et l'hte B: il y a la
   poigne de main initiale en trois phases, le paquet SYN de A vers B, le
   SYN/ACK en retour de B vers A, et le ACK final de A vers B. A ce stade,
   nous sommes dans une situation stable : la connexion est tablie, et les
   donnes peuvent donc tre envoyes sur ce lien. Mais le problme survient
   : dbranchez l'alimentation de B et instantanment il s'teint, sans rien
   envoyer sur le rseau pour notifier A que la connexion va tre
   interrompue. A, de son ct, est prt  envoyer des donnes, et n'imagine
   pas que B est muet. Maintenant rebranchez l'alimentation de B et attendez
   que le systme redmarre. A et B sont de retour, mais A prsente une
   connexion toujours active vers B, alors que B l'ignore. La situation se
   rsout d'elle-mme lorsque A tente d'envoyer des donnes  B sur une
   connexion morte, et que B rpond par un paquet RST, forant A  finalement
   mettre fin  la connexion.

   Keepalive peut vous notifier quand un destinataire devient injoignable
   sans risque de faux positif. En fait, si le problme tient au rseau entre
   les deux htes, le rle du keepalive est d'attendre un temps pour tenter 
   nouveau, adressant le paquet keepalive avant de notifier de la rupture du
   lien.

  _____                                                     _____
 |     |                                                   |     |
 |  A  |                                                   |  B  |
 |_____|                                                   |_____|
    ^                                                         ^
    |--->--->--->-------------- SYN -------------->--->--->---|
    |---<---<---<------------ SYN/ACK ------------<---<---<---|
    |--->--->--->-------------- ACK -------------->--->--->---|
    |                                                         |
    |                                   le systme meurt ---> X
    |
    |                               le systme redmarre ---> ^
    |                                                         |
    |--->--->--->-------------- PSH -------------->--->--->---|
    |---<---<---<-------------- RST --------------<---<---<---|
    |                                                         |

  2.4. viter une dconnexion due  une inactivit rseau.

   L'autre objectif utile de keepalive est d'viter que l'inactivit ne
   provoque une dconnexion. C'est un cas frquent d'tre dconnect sans
   raison lorsque vous vous trouvez derrire un proxy NAT ou un pare-feu. Ce
   comportement est d aux procdures de surveillance des connexions des
   proxies et pare-feu, qui tiennent un inventaire des connexions qui les
   traverse. En raison des limites physiques de leurs ressources, ces
   machines ne peuvent conserver en mmoire qu'un nombre dtermin de
   connexions. La rgle la plus courante et la plus logique est de maintenir
   les connexions les plus rcentes et de mettre d'abord fin aux connexions
   les plus anciennes ou inactives.

   Pour revenir  nos htes A et B, reconnectons les. Une fois le lien
   tabli, attendons qu'un vnement se produise pour le transmettre  l'hte
   distant. Qu'en est-il si cet vnement se produit aprs un long moment ?
   Notre connexion a sa propre dure, qui est inconnue du proxy. Lorsque nous
   finissons par transmettre des donnes, le proxy n'est plus capable de les
   traiter correctement, et la connexion est rompue.

   Puisque le fonctionnement normal est de mettre en tte de liste la
   connexion par laquelle transitent des paquets, et de choisir la dernire
   connexion de la file quand il faut en supprimer une, le fait d'envoyer
   priodiquement des paquets sur le rseau est un bon moyen pour toujours
   rester en phase avec un risque minime de suppression.

  _____           _____                                     _____
 |     |         |     |                                   |     |
 |  A  |         | NAT |                                   |  B  |
 |_____|         |_____|                                   |_____|
    ^               ^                                         ^
    |--->--->--->---|----------- SYN ------------->--->--->---|
    |---<---<---<---|--------- SYN/ACK -----------<---<---<---|
    |--->--->--->---|----------- ACK ------------->--->--->---|
    |               |                                         |
    |               | <--- connexion supprime de la table    |
    |               |                                         |
    |--->- PSH ->---| <--- connexion invalide                 |
    |               |                                         |

3. Utiliser TCP keepalive sous Linux

   Linux intgre nativement le keepalive. Vous devez activer le rseau TCP/IP
   pour pouvoir l'utiliser. Vous avez aussi besoin du support de procfs et de
   sysctl pour pouvoir configurer les paramtre noyau au lancement.

   Les fonctions impliquant keepalive utilisent trois variables manipules
   par l'utilisateur :

   tcp_keepalive_time

           intervalle entre le dernier envoi de paquet (le simple ACK n'tant
           pas considr comme de la donne) et la premire sonde keepalive;
           aprs que la connexion ait t marque comme requrant un
           keepalive, ce compteur n'est plus utilis.

   tcp_keepalive_intvl

           intervalle entre deux sondes keepalive, indpendamment de ce qui
           est chang sur la connexion dans l'intervalle

   tcp_keepalive_probes

           nombre de sondes non acquittes  envoyer avant de considrer la
           connexion perdue et de notifier la couche applicative.

   Rappelez-vous que le support du keepalive, mme s'il est configur dans le
   noyau, n'est pas le comportement par dfaut de Linux. Les programmes
   doivent requrir le contrle du keepalive pour que ses sockets puissent
   utiliser l'interface setsockopt. Relativement peu de programmes
   implmentent keepalive, mais vous pouvez facilement ajouter le support du
   keepalive pour la plupart d'entre eux en suivant les instructions
   dtailles plus avant dans ce document.

  3.1. Configurer le noyau

   Il existe deux moyens de configurer les paramtres keepalive du noyau au
   travers de commandes utilisateur:

     * l'interface procfs

     * l'interface sysctl

   Nous aborderons essentiellement comment procder au travers de l'interface
   procfs car elle est la plus utilise, recommande et la plus simple 
   apprhender. L'interface sysctl, particulirement sous l'aspect de l'appel
   systme (syscall) sysctl(2) et non de l'outil sysctl(8), n'est l qu'
   titre informatif.

    3.1.1. L'interfaceprocfs

   Cette interface ncessite quesysctl et procfs soient inclus au noayu, et
   que procfs soit mont quelque part dans le systme de fichiers
   (habituellement /proc, comme dans l'exemple ci-dessous). Vous pouvez lire
   les valeurs des paramtres actuels en listant avec la commande  cat  les
   fichiers du rpertoire /proc/sys/net/ipv4/ :

   # cat /proc/sys/net/ipv4/tcp_keepalive_time
   7200

   # cat /proc/sys/net/ipv4/tcp_keepalive_intvl
   75

   # cat /proc/sys/net/ipv4/tcp_keepalive_probes
   9


   Les deux premiers paramtres sont exprims en secondes, et le dernier est
   un nombre simple. Cela signifie que les routines keepalive attendent deux
   heures (7200 secs) avant d'adresser la premire sonde keepalive, et en
   adressent une nouvelle toutes les 75 secondes. Si aucune rponse ACK n'est
   reue aprs neuf tentatives conscutives, la connexion est considre
   comme rompue.

   La modification de ces valeurs est directe : il faut crire de nouvelles
   valeurs dans les fichiers. Supposons que souhaitiez configurer la machine
   pour que le keepalive dbute aprs dix minutes d'inactivit sur le lien,
   et que des sondes soient envoyes chaque minute. En raison de
   l'instabilit de ce brin de votre rseau et de la faible valeur de
   l'intervalle, supposons que vous vouliez augmenter le nombre de tentatives
    20.

   Voici comment paramtrer ces valeurs :

   # echo 600 > /proc/sys/net/ipv4/tcp_keepalive_time

   # echo 60 > /proc/sys/net/ipv4/tcp_keepalive_intvl

   # echo 20 > /proc/sys/net/ipv4/tcp_keepalive_probes


   Pour confirmer la prise en compte des nouvelles valeurs, affichez 
   nouveau le contenu des fichiers pour vrifier qu'ils prsentent bien les
   valeurs souhaites.

   Il faut garder prsent  l'esprit que procfs manipule des fichiers
   spciaux, et vous ne pouvez pas tout faire sur ces fichiers qui ne sont
   qu'une interface vers l'environnement du noyau, non de vritables
   fichiers. Testez vos scripts avant de les utiliser et faites en sorte
   d'utiliser des modes d'accs simples comme dans les exemples ci-dessus.

   Vous pouvez accder  l'interface grce  l'outil sysctl(8), en prcisant
   ce que vos voulez lire ou crire.

   # sysctl \
   > net.ipv4.tcp_keepalive_time \
   > net.ipv4.tcp_keepalive_intvl \
   > net.ipv4.tcp_keepalive_probes
   net.ipv4.tcp_keepalive_time = 7200
   net.ipv4.tcp_keepalive_intvl = 75
   net.ipv4.tcp_keepalive_probes = 9


   Remarquez que les noms sysctl sont proches des chemins procfs. L'criture
   se fait grce  l'option -w de sysctl (8):

   # sysctl -w \
   > net.ipv4.tcp_keepalive_time=600 \
   > net.ipv4.tcp_keepalive_intvl=60 \
   > net.ipv4.tcp_keepalive_probes=20
   net.ipv4.tcp_keepalive_time = 600
   net.ipv4.tcp_keepalive_intvl = 60
   net.ipv4.tcp_keepalive_probes = 20


   Remarquez que sysctl (8) n'utilise pas l'appel systme (syscall)sysctl(2),
   mais lit et crit directement dans l'arborescence procfs, donc procfs
   devra tre activ dans le noyau et mont dans le systme de fichiers,
   comme si vous accdiez directement aux fichiers via l'interface procfs.
   Sysctl(8) n'est qu'un moyen diffrent de faire la mme chose.

    3.1.2. L'interfacesysctl

   Il existe un autre moyen d'accder aux variables du noyau : l'appel
   systme sysctl (2). Cela peut tre utile lorque procfs n'est pas
   disponible du fait que la communication avec le noyau est ralise
   directement via syscall et pas au travers de l'arborescence procfs . Il
   n'existe actuellement aucun programme qui implmente l'appel syscall
   (souvenez-vous que sysctl(8) ne l'utilise pas).

   Pour une utilisation dtaill de sysctl(2) reportez vous au manuel (man).

  3.2. Rendre les modifications persistantes au redmarrage

   Il existe diffrents moyens de paramtrer le systme  chaque dmarrage.
   Tout d'abord, souvenez vous que chaque distribution Linux possde son
   propre jeu de scripts d'initialisation appel par init (8). Les
   configurations les plus courantes incluent soit le rpertoire /etc/rc.d/ ,
   soit /etc/init.d/ . Dans ce cas vous pouvez positionner les paramtres
   dans un script de dmarrage quelconque, keepalive relisant les valeurs 
   chaque fois que ses routines en ont besoin. Donc si vous changez la valeur
   de tcp_keepalive_intvl alors que la connexion est encore active, le noyau
   utilisera la nouvelle valeur pour continuer.

   Les commandes d'initialisation peuvent logiquement tre places en trois
   endroits diffrents : le premier est dans la configuration rseau, le
   second dans le script rc.local , habituellement inclus dans toutes les
   distributions, et connu comme tant le point de configuration utilisateur
   au dmarrage. Le troisime point existe peut-tre dj sur votre systme.
   En revenant  l'outil sysctl (8) , vous pouvez voir que l'option -p charge
   les paramtres du fichier de configuration /etc/sysctl.conf . Il est
   frquent que votre script d'initialisation excute dj sysctl -p (un
    grep  sur le rpertoire de configuration le confirmera), et vous n'avez
   alors qu' ajouter les lignes dans /etc/sysctl.conf pour qu'elles soient
   prises en compte  chaque dmarrage. Pour davantage d'informations sur la
   syntaxe de sysctl.conf (5), reportez vous au manuel.

4. Programmer des applications

   Cette section aborde le code ncessaire  l'criture d'une application
   utilisant keepalive. Ce n'est pas un manuel de programmation, et il
   requiert d'avoir une connaissance du langage C et des concepts rseau. Je
   considre que la notion de socket vous est familire, de mme que tous les
   aspects gnraux de votre application.

  4.1. Quand votre code requiert keepalive

   Les applications rseau ne requirent pas toutes l'aide du keepalive.
   Souvenez vous qu'il s'agit de TCP keepalive. Comme vous pouvez le deviner,
   seules les sockets TCP peuvent en tirer parti.

   La plus belle chose que vous puissiez faire en crivant une application
   est de la rendre aussi paramtrable que possible, et de ne pas en forcer
   les choix. Si vous voulez prendre en compte le bonheur de vos
   utilisateurs, vous devriez implmenter keepalive et laisser les
   utilisateurs dcider s'ils veulent ou non l'utiliser en prvoyant un
   paramtre de configuration ou une option de ligne de commande.

  4.2. L'appel de fonction setsockopt

   Tout ce dont vous avez besoin pour que keepalive soit activ sur une
   socket particulire est de positionner l'option sur cette socket. Le
   prototype de fonction est le suivant:

   int setsockopt(int s, int level, int optname,
                  const void *optval, socklen_t optlen)


   Le premier paramtre est la socket, pralablement cre avec socket(2); le
   second doit tre SOL_SOCKET, et le troisime SO_KEEPALIVE . Le quatrime
   doit tre un entier booleen, indiquant que l'option est active, alors que
   le dernier est la taille de la valeur passe prcdemment.

   Conformment au manuel, le code retour 0 indique le succs, -1 est la
   valeur d'erreur (et errno est correctement renseigne).

   Il existe aussi trois autres options de socket qu'il est possible de
   renseigner en crivant votre application. Toutes utilisent le niveau
   SOL_TCP au lieu de SOL_SOCKET, et elles prennent le pas sur les variables
   systme pour la socket courante. Si vous lisez avant d'crire, les
   paramtres systme seront retourns.

     * TCP_KEEPCNT : prend le pas sur tcp_keepalive_probes

     * TCP_KEEPIDLE : prend le pas sur tcp_keepalive_time

     * TCP_KEEPINTVL : prend le pas sur tcp_keepalive_intvl

  4.3. Exemples de code

   Voici un petit exemple qui cre une socket, montre que keepalive est
   dsactiv, puis l'active et vrifie que l'option est rellement
   positionne.

             /* --- dbut du programme de test  KEEPALIVE --- */

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>

 int main(void);

 int main()
 {
    int s;
    int optval;
    socklen_t optlen = sizeof(optval);

    /* Creation de la socket */
    if((s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
       perror("socket()");
       exit(EXIT_FAILURE);
    }

    /* Verifie l'etat de l'option keepalive */
    if(getsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen) < 0) {
       perror("getsockopt()");
       close(s);
       exit(EXIT_FAILURE);
    }
    printf("SO_KEEPALIVE is %s\n", (optval ? "ON" : "OFF"));

    /* Rend l'option active */
    optval = 1;
    optlen = sizeof(optval);
    if(setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) {
       perror("setsockopt()");
       close(s);
       exit(EXIT_FAILURE);
    }
    printf("SO_KEEPALIVE set on socket\n");

    /* Verifie a nouveau son etat */
    if(getsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen) < 0) {
       perror("getsockopt()");
       close(s);
       exit(EXIT_FAILURE);
    }
    printf("SO_KEEPALIVE is %s\n", (optval ? "ON" : "OFF"));

    close(s);

    exit(EXIT_SUCCESS);
 }

             /* ---  fin du programme de test  KEEPALIVE  --- */


5. Implmenter keepalive sur une application tierce

   Tout le monde n'est pas dveloppeur d'application, et tout le monde ne
   rcrira pas entirement une application pour combler le manque d'une
   fonctionnalit. Peut-tre souhaitez vous ajouter keepalive  une
   application existante, et mme si son auteur n'a pas considr cela
   important, vous pensez que ce sera utile.

   Tout d'abord, souvenez vous de ce qui a t dit prcdemment  propos des
   cas o keepalive est ncessaire. Ensuite vous devrez affecter les sockets
   TCP orientes connexion.

   Comme Linux ne fournit pas la possibilit d'activer le support keepalive
   via le noyau (les OS de type BSD le permettent souvent), le seul moyen est
   d'appeler setsockopt (2) aprs la cration de la socket. Il y a deux
   solutions:

     * modification du code source du programme original

     * injection setsockopt (2) en utilisant la technique de prchargement de
       bibliothque

  5.1. Modifier le code source

   Souvenez-vous que keepalive n'est pas orient programme, mais orient
   socket, donc si vous avez de multiples sockets, vous pouvez grer
   keepalive sparment pour chacune d'entre elles. La premire tape
   consiste  comprendre ce que fait le programme, la seconde  rechercher le
   code pour chaque socket dans le programme. Cela peut tre fait en
   utilisant grep(1), comme suit:

   # grep 'socket *(' *.c


   Cela vous montrera  peu prs toutes les sockets du code. L'tape suivante
   consiste  choisir les bonnes : vous ciblez les sockets TCP, donc
   recherchez PF_INET (ou AF_INET), SOCK_STREAM et IPPROTO_TCP (ou plus
   communment, 0) dans les paramtres de votre liste de sockets, et enlevez
   celles qui ne correspondent pas.

   Il existe un autre moyen de crer une socket au travers de accept(2). En
   ce ce cas, suivez les sockets TCP identifies et vrifiez si certaines
   sont en coute : si c'est le cas, gardez  l'esprit que accept(2) retourne
   un descripteur de socket, qui doit tre ajout  votre liste de sockets.

   Une fois les sockets identifies, vous pouvez procder aux modifications.
   Le patch le plus 'fast & furious' peut consister  simplement ajouter la
   fonction setsockopt(2 ) juste aprs le bloc de cration de la socket.
   ventuellement, vous pouvez ajouter des appels supplmentaires pour
   modifier les paramtres systmes par dfaut de keepalive. Surtout soyez
   attentif au positionnement des vrifications d'erreurs et des handlers de
   la fonction, peut-tre en recopiant le style du code alentour. Songez 
   affecter  optval une valeur non nulle et  initialiser optlen avant
   d'appeler la fonction.

   Si vous en avez le temps ou pensez que ce serait plus lgant, essayez
   d'implmenter compltement le keepalive  votre programme, en incluant une
   option de ligne de commande ou un paramtre de configuration pour laisser
    l'utilisateur la libert d'utiliser ou non keepalive.

  5.2. libkeepalive: prchargement de bibliothque

   Dans de nombreux cas vous n'avez pas la possibilit de modifier le code
   source d'une application, ou bien lorsque vous devez activer keepalive
   pour tous vos programmes, tout patcher et tout recompiler n'est pas
   recommand.

   Le projet libkeepalive a vu le jour pour faciliter l'implmentation du
   keepalive au sein des applications puisque le noyau Linux ne permet pas de
   le faire nativement (comme le fait BSD). La page d'accueil du projet
   libkeepalive est disponible  l'adresse
   http://libkeepalive.sourceforge.net/
   [http://libkeepalive.sourceforge.net/]

   Il consiste en une bibliothque partage qui outrepasse l'appel systme
   socket de la plupart des excutables, sans aucun besoin de les recompiler
   ni de les modifier. La technique repose sur la fonctionnalit de
   pr-chargement (preloading) de ld.so(8), chargeur inclus dans Linux, qui
   qui permet le chargement de bibliothques partages avec une priorit
   suprieure  la normale. Les programmes utilisent habituellement l'appel
   de fonction socket (2) situ dans la glibc, librairie partage; avec
   libkeepalive il est possible d'encapsuler la fonction setsockopt(2) juste
   aprs la cration, retournant au programme principal une socket avec
   keepalive dj positionn. En raison des mcanismes utiliss pour raliser
   l'appel systme, ce procd ne fonctionne pas lorsque la fonction socket
   est compile statiquement dans le binaire, comme dans le cas d'un
   programme li par l'option -static de gcc(1 ).

   Aprs avoir tlcharg et install libkeepalive, vous serez en mesure
   d'ajouter le support de keepalive  vos programmes sans tre root au
   pralable, simplement en initialisant la variable d'environnement
   LD_PRELOAD avant d'excuter le programme. Au fait, le super utilisateur
   peut aussi forcer la pr-chargement au travers d'une configuration
   globale, et les utilisateurs peuvent choisir de le dsactiver en
   positionnant la variable d'environnement KEEPALIVE  off.

   L'environnement est aussi utilis pour positionner des valeurs spcifiques
   pour les paramtres de keepalive, vous avez donc la possibilit de grer
   chaque programme de faon distincte, en initialisant KEEPCNT, KEEPIDLE et
   KEEPINTVL avant de lancer l'application.

   Voici un exemple d'utilisation de libkeepalive :

   $ test
   SO_KEEPALIVE is OFF

   $ LD_PRELOAD=libkeepalive.so \
   > KEEPCNT=20 \
   > KEEPIDLE=180 \
   > KEEPINTVL=60 \
   > test
   SO_KEEPALIVE is ON
   TCP_KEEPCNT   = 20
   TCP_KEEPIDLE  = 180
   TCP_KEEPINTVL = 60


   Et vous pouvez utiliser strace (1) pour comprendre ce qui se passe:

   $ strace test
   execve("test", ["test"], [/* 26 vars */]) = 0
   [..]
   open("/lib/libc.so.6", O_RDONLY)        = 3
   [..]
   socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
   getsockopt(3, SOL_SOCKET, SO_KEEPALIVE, [0], [4]) = 0
   close(3)                                = 0
   [..]
   _exit(0)                                = ?

   $ LD_PRELOAD=libkeepalive.so \
   > strace test
   execve("test", ["test"], [/* 27 vars */]) = 0
   [..]
   open("/usr/local/lib/libkeepalive.so", O_RDONLY) = 3
   [..]
   open("/lib/libc.so.6", O_RDONLY)        = 3
   [..]
   open("/lib/libdl.so.2", O_RDONLY)       = 3
   [..]
   socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
   setsockopt(3, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0
   setsockopt(3, SOL_TCP, TCP_KEEPCNT, [20], 4) = 0
   setsockopt(3, SOL_TCP, TCP_KEEPIDLE, [180], 4) = 0
   setsockopt(3, SOL_TCP, TCP_KEEPINTVL, [60], 4) = 0
   [..]
   getsockopt(3, SOL_SOCKET, SO_KEEPALIVE, [1], [4]) = 0
   [..]
   getsockopt(3, SOL_TCP, TCP_KEEPCNT, [20], [4]) = 0
   [..]
   getsockopt(3, SOL_TCP, TCP_KEEPIDLE, [180], [4]) = 0
   [..]
   getsockopt(3, SOL_TCP, TCP_KEEPINTVL, [60], [4]) = 0
   [..]
   close(3)                                = 0
   [..]
   _exit(0)                                = ?


   Pour d'autres informations, visitez la page d'accueil du projet
   libkeepalive : http://libkeepalive.sourceforge.net/
   [http://libkeepalive.sourceforge.net/]

