From: willy tarreau Date: Sun, 18 Dec 2005 00:13:11 +0000 (+0100) Subject: * released 1.2.5 (1.1.31) X-Git-Tag: v1.2.5 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=64a3cc3660fd2b036a4cca533a52e197558e6a72;p=thirdparty%2Fhaproxy.git * released 1.2.5 (1.1.31) * changed the runtime argument to disable epoll() to '-de' * changed the runtime argument to disable poll() to '-dp' * added global options 'nopoll' and 'noepoll' to do the same at the configuration level. * added a 'linux24e' target to the Makefile for Linux 2.4 systems patched to support epoll(). * changed default FD_SETSIZE to 65536 on Solaris (default=1024) * conditionned signals redirection to #ifdef DEBUG_MEMORY --- diff --git a/CHANGELOG b/CHANGELOG index 6b129d024c..7db21e51e1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,16 @@ ChangeLog : =========== +2005/04/30 : 1.2.5 (1.1.31) + - changed the runtime argument to disable epoll() to '-de' + - changed the runtime argument to disable poll() to '-dp' + - added global options 'nopoll' and 'noepoll' to do the same at the + configuration level. + - added a 'linux24e' target to the Makefile for Linux 2.4 systems patched to + support epoll(). + - changed default FD_SETSIZE to 65536 on Solaris (default=1024) + - conditionned signals redirection to #ifdef DEBUG_MEMORY + 2005/04/26 : 1.2.5-pre4 - made epoll() support a compile-time option : ENABLE_EPOLL - provided a very little libc replacement for a possibly missing epoll() diff --git a/Makefile b/Makefile index 3991baa4cf..c99933af76 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ # correctly defined below. #TARGET = linux26 TARGET = linux24 +#TARGET = linux24e #TARGET = linux22 #TARGET = solaris #TARGET = openbsd @@ -28,11 +29,15 @@ LD = gcc PCREDIR := $(shell pcre-config --prefix 2>/dev/null || :) #PCREDIR=/usr/local -# This is for Linux 2.6 with netfilter and EPOLL +# This is for standard Linux 2.6 with netfilter and epoll() COPTS.linux26 = -DNETFILTER -DENABLE_POLL -DENABLE_EPOLL LIBS.linux26 = -# This is for Linux 2.4 with netfilter +# This is for enhanced Linux 2.4 with netfilter and epoll() patch +COPTS.linux24e = -DNETFILTER -DENABLE_POLL -DENABLE_EPOLL -DUSE_MY_EPOLL +LIBS.linux24e = + +# This is for standard Linux 2.4 with netfilter but without epoll() COPTS.linux24 = -DNETFILTER -DENABLE_POLL LIBS.linux24 = @@ -41,7 +46,7 @@ COPTS.linux22 = -DUSE_GETSOCKNAME -DENABLE_POLL LIBS.linux22 = # This is for Solaris 8 -COPTS.solaris = -fomit-frame-pointer -DSOLARIS -DENABLE_POLL +COPTS.solaris = -fomit-frame-pointer -DENABLE_POLL -DFD_SETSIZE=65536 LIBS.solaris = -lnsl -lsocket # This is for OpenBSD 3.0 @@ -63,13 +68,14 @@ COPTS.pcre=-DUSE_PCRE -I$(PCREDIR)/include LIBS.pcre=-L$(PCREDIR)/lib -lpcreposix -lpcre # you can enable debug arguments with "DEBUG=-g" or disable them with "DEBUG=" -#DEBUG = +#DEBUG = -g -DDEBUG_MEMORY DEBUG = -g # if small memory footprint is required, you can reduce the buffer size. There # are 2 buffers per concurrent session, so 16 kB buffers will eat 32 MB memory -# with 1000 concurrent sessions. -#SMALL_OPTS = -DBUFSIZE=8192 -DMAXREWRITE=1024 +# with 1000 concurrent sessions. Putting it slightly lower than a page size +# will avoid the additionnal paramters to overflow a page. +#SMALL_OPTS = -DBUFSIZE=8100 -DMAXREWRITE=1000 SMALL_OPTS = # redefine this if you want to add some special PATH to include/libs diff --git a/TODO b/TODO index 66a4ec6ac6..0ef9fed9b4 100644 --- a/TODO +++ b/TODO @@ -141,3 +141,10 @@ Todo for 1.2 - option to shutdown(listen_sock) when max connections reached * epoll - replace the event scheduler with an O(log(N)) one +- refine memory management so that the request buffer is only allocated in + cli_read() and response buffer during srv_read(). This would protect against + attacks with thousands connections : 20000 connections consume 340 MB RSS and + 1.3 GB VSZ on Linux. Data should be in a separate buffer to prevent any + activity on the buffer's pointers from touching the buffer page itself. +- make buffer size configurable in global options +- monitor number of simultaneous sessions in logs (per srv/inst/global) diff --git a/doc/haproxy-en.txt b/doc/haproxy-en.txt index 65ebb96d6e..d9068a5628 100644 --- a/doc/haproxy-en.txt +++ b/doc/haproxy-en.txt @@ -4,7 +4,7 @@ ------------------- version 1.2.5 willy tarreau - 2005/04/24 + 2005/04/30 ============ | Abstract | @@ -44,6 +44,8 @@ There are only a few command line options : pids to this file in daemon mode. -s shows statistics (only if compiled in) -l shows even more statistics (implies '-s') + -de disables use of epoll() + -dp disables use of poll() The maximal number of connections per proxy is used as the default parameter for @@ -98,6 +100,8 @@ the following ones : - nbproc - daemon - debug + - noepoll + - nopoll - quiet - pidfile - stats @@ -264,6 +268,43 @@ Example : # kill $( - daemon - debug + - noepoll + - nopoll - quiet - pidfile @@ -117,9 +122,9 @@ syslog vers un ou deux serveurs. La syntaxe est la suivante : Les connexions sont envoyées en niveau "info". Les démarrages de service et de serveurs seront envoyés en "notice", les signaux d'arrêts en "warning" et les arrêts définitifs de services et de serveurs en "alert". Ceci est valable aussi -bien pour les proxies que pour les serveurs testés par les proxies. Le paramètre -optionnel définit le niveau maximal de traces émises parmi les 8 -valeurs suivantes : +bien pour les proxies que pour les serveurs testés par les proxies. Le +paramètre optionnel définit le niveau maximal de traces émises +parmi les 8 valeurs suivantes : emerg, alert, crit, err, warning, notice, info, debug Par compatibilité avec les versions 1.1.16 et antérieures, la valeur par défaut @@ -152,8 +157,8 @@ de sockets n - 1 socket pour chaque serveur en cours de health-check - 1 socket pour les logs (tous serveurs confondus) -Dans le cas où chaque proxy n'écoute que sur un couple adresse/port, positionner -la limite du nombre de descripteurs de fichiers (ulimit -n) à +Dans le cas où chaque proxy n'écoute que sur un couple adresse/port, +positionner la limite du nombre de descripteurs de fichiers (ulimit -n) à (2 * maxconn + nbproxy + nbserveurs + 1). Dans une future version, haproxy sera capable de positionner lui-même cette limite. @@ -184,20 +189,23 @@ plusieurs services de nature diff il est conseillé d'utiliser un répertoire vide, sans aucun droit, et de changer l'uid du processus de sorte qu'il ne puisse rien faire dans ledit répertoire. -Remarque: dans le cas où une telle faille serait mise en évidence, il est fort -probable que les premières tentatives de son exploitation provoquent un arrêt du +Remarque importante : +--------------------- +Dans le cas où une telle faille serait mise en évidence, il est fort probable +que les premières tentatives de son exploitation provoquent un arrêt du programme, à cause d'un signal de type 'Segmentation Fault', 'Bus Error' ou -encore 'Illegal Instruction'. Même s'il est vrai que faire tourner le serveur en -environnement limité réduit les risques d'intrusion, il est parfois bien utile -dans ces circonstances de connaître les conditions d'apparition du problème, via -l'obtention d'un fichier 'core'. La plupart des systèmes, pour des raisons de -sécurité, désactivent la génération du fichier 'core' après un changement -d'identifiant pour le processus. Il faudra donc soit lancer le processus à -partir d'un compte utilisateur aux droits réduits (mais ne pouvant pas effectuer -le chroot), ou bien le faire en root sans réduction des droits (uid 0). Dans ce -cas, le fichier se trouvera soit dans le répertoire de lancement, soit dans le -répertoire spécifié après l'option 'chroot'. Ne pas oublier la commande suivante -pour autoriser la génération du fichier avant de lancer le programme : +encore 'Illegal Instruction'. Même s'il est vrai que faire tourner le serveur +en environnement limité réduit les risques d'intrusion, il est parfois bien +utile dans ces circonstances de connaître les conditions d'apparition du +problème, via l'obtention d'un fichier 'core'. La plupart des systèmes, pour +des raisons de sécurité, désactivent la génération du fichier 'core' après un +changement d'identifiant pour le processus. Il faudra donc soit lancer le +processus à partir d'un compte utilisateur aux droits réduits (mais ne pouvant +pas effectuer le chroot), ou bien le faire en root sans réduction des droits +(uid 0). Dans ce cas, le fichier se trouvera soit dans le répertoire de +lancement, soit dans le répertoire spécifié après l'option 'chroot'. Ne pas +oublier la commande suivante pour autoriser la génération du fichier avant de +lancer le programme : # ulimit -c unlimited @@ -215,9 +223,9 @@ Le service peut fonctionner dans plusieurs modes : - avant- / arrière-plan - silencieux / normal / debug -Le mode par défaut est normal, avant-plan, c'est à dire que le programme ne rend -pas la main une fois lancé. Il ne faut surtout pas le lancer comme ceci dans un -script de démarrage du système, sinon le système ne finirait pas son +Le mode par défaut est normal, avant-plan, c'est à dire que le programme ne +rend pas la main une fois lancé. Il ne faut surtout pas le lancer comme ceci +dans un script de démarrage du système, sinon le système ne finirait pas son initialisation. Il faut le mettre en arrière-plan, de sorte qu'il rende la main au processus appelant. C'est ce que fait l'option 'daemon' de la section 'global', et qui est l'équivalent du paramètre '-D' de la ligne de commande. @@ -277,6 +285,44 @@ Exemple : # kill $( [ :[,...] ] - est le nom de l'instance décrite. Ce nom sera envoyé dans les - logs, donc il est souhaitable d'utiliser un nom relatif au service relayé. Aucun - test n'est effectué concernant l'unicité de ce nom, qui n'est pas obligatoire, - mais fortement recommandée. + logs, donc il est souhaitable d'utiliser un nom relatif au service relayé. + Aucun test n'est effectué concernant l'unicité de ce nom, qui n'est pas + obligatoire, mais fortement recommandée. - est l'adresse IP sur laquelle le relais attend ses connexions. L'absence d'adresse ainsi que l'adresse 0.0.0.0 signifient que les connexions @@ -304,8 +350,8 @@ Les sections de service d : consomme une socket, donc un descripteur de fichier. Le couple : doit être unique pour toutes les instances d'une même machine. L'attachement à un port inférieur à 1024 nécessite un - niveau de privilège particulier lors du lancement du programme (indépendamment - du paramètre 'uid' de la section 'global'). + niveau de privilège particulier lors du lancement du programme + (indépendamment du paramètre 'uid' de la section 'global'). - le couple : peut être répété indéfiniment pour demander au relais d'écouter également sur d'autres adresses et/ou d'autres @@ -353,9 +399,10 @@ Un service peut fonctionner dans trois modes diff Mode TCP -------- -Dans ce mode, le service relaye, dès leur établissement, les connexions TCP vers -un ou plusieurs serveurs. Aucun traitement n'est effectué sur le flux. Il s'agit -simplement d'une association source -> destination. +Dans ce mode, le service relaye, dès leur établissement, les connexions TCP +vers un ou plusieurs serveurs. Aucun traitement n'est effectué sur le flux. Il +s'agit simplement d'une association + source -> destination. Pour l'utiliser, préciser le mode TCP sous la déclaration du relais. Exemple : @@ -414,15 +461,19 @@ Exemple : 2.4) Arrêt en douceur --------------------- -Il est possible d'arrêter les services en douceur en envoyant un signal SIG_USR1 -au processus relais. Tous les services seront alors mis en phase d'arrêt, mais -pourront continuer d'accepter des connexions pendant un temps défini par le -paramètre 'grace' (en millisecondes). Cela permet par exemple, de faire savoir -rapidement à un répartiteur de charge qu'il ne doit plus utiliser un relais, -tout en continuant d'assurer le service le temps qu'il s'en rende compte. -Remarque : les connexions actives ne sont jamais cassées. Dans le pire des cas, -il faudra attendre en plus leur expiration avant l'arrêt total du processus. La -valeur par défaut est 0 (pas de grâce, arrêt immédiat de l'écoute). +Il est possible d'arrêter les services en douceur en envoyant un signal +SIG_USR1 au processus relais. Tous les services seront alors mis en phase +d'arrêt, mais pourront continuer d'accepter des connexions pendant un temps +défini par le paramètre 'grace' (en millisecondes). Cela permet par exemple, +de faire savoir rapidement à un répartiteur de charge qu'il ne doit plus +utiliser un relais, tout en continuant d'assurer le service le temps qu'il +s'en rende compte. + +Remarque : +---------- +Les connexions actives ne sont jamais cassées. Dans le pire des cas, il faudra +attendre en plus leur expiration avant l'arrêt total du processus. La valeur +par défaut est 0 (pas de grâce, arrêt immédiat de l'écoute). Exemple : --------- @@ -468,11 +519,12 @@ Remarques : - "contimeout" et "srvtimeout" n'ont pas d'utilité dans le cas du serveur de type "health". - sous de fortes charges, ou sur un réseau saturé ou défectueux, il est - possible de perdre des paquets. Du fait que la première retransmission TCP - n'ait lieu qu'au bout de 3 secoudes, fixer un timeout de connexion inférieur - à 3 secondes ne permet pas de se rattraper sur la perte de paquets car la - session aura été abandonnée avant la première retransmission. Une valeur de - 4 secondes réduira considérablement le nombre d'échecs de connexion. + possible de perdre des paquets. Du fait que la première retransmission + TCP n'ait lieu qu'au bout de 3 secoudes, fixer un timeout de connexion + inférieur à 3 secondes ne permet pas de se rattraper sur la perte + de paquets car la session aura été abandonnée avant la première + retransmission. Une valeur de 4 secondes réduira considérablement + le nombre d'échecs de connexion. 2.6) Tentatives de reconnexion ------------------------------ @@ -514,12 +566,12 @@ Il est possible de forcer l'adresse utilis les serveurs à l'aide du paramètre "source". Il est même possible de forcer le port, bien que cette fonctionnalité se limite à des usages très spécifiques. C'est particulièrement utile en cas d'adressage multiple, et plus généralement -pour permettre aux serveurs de trouver le chemin de retour dans des contextes de -routage difficiles. Si l'adresse est '0.0.0.0' ou '*' ou vide, elle sera choisie -librement par le systeme. Si le port est '0' ou vide, il sera choisi librement -par le système. Il est à noter que depuis la version 1.1.18, les tests de bon -fonctionnement des serveurs seront aussi effectués à partir de la source -spécifiée par ce paramètre. +pour permettre aux serveurs de trouver le chemin de retour dans des contextes +de routage difficiles. Si l'adresse est '0.0.0.0' ou '*' ou vide, elle sera +choisie librement par le systeme. Si le port est '0' ou vide, il sera choisi +librement par le système. Il est à noter que depuis la version 1.1.18, les +tests de bon fonctionnement des serveurs seront aussi effectués à partir de la +source spécifiée par ce paramètre. Exemples : ---------- @@ -565,9 +617,9 @@ lors d'un acc cookie SERVERID rewrite -Pour créer un cookie comportant la valeur attribuée à un serveur lors d'un accès -en répartition de charge interne. Dans ce cas, il est souhaitable que tous les -serveurs aient un cookie renseigné. Un serveur non assigné d'un cookie +Pour créer un cookie comportant la valeur attribuée à un serveur lors d'un +accès en répartition de charge interne. Dans ce cas, il est souhaitable que +tous les serveurs aient un cookie renseigné. Un serveur non assigné d'un cookie retournera un cookie vide (cookie de suppression) : cookie SERVERID insert @@ -585,17 +637,17 @@ ajouter le mot cl cookie SERVERID insert nocache -Pour insérer un cookie seulement suite aux requêtes de type POST, ajouter le mot -clé 'postonly' après 'insert' : +Pour insérer un cookie seulement suite aux requêtes de type POST, ajouter le +mot clé 'postonly' après 'insert' : cookie SERVERID insert postonly Remarques : ----------- -- Il est possible de combiner 'insert' avec 'indirect' ou 'rewrite' pour s'adapter - à des applications générant déjà le cookie, avec un contenu invalide. Il suffit - pour cela de les spécifier sur la même ligne. +- Il est possible de combiner 'insert' avec 'indirect' ou 'rewrite' pour + s'adapter à des applications générant déjà le cookie, avec un contenu + invalide. Il suffit pour cela de les spécifier sur la même ligne. - dans le cas où 'insert' et 'indirect' sont spécifiés, le cookie n'est jamais transmis au serveur vu qu'il n'en a pas connaissance et ne pourrait pas le @@ -719,35 +771,36 @@ Exemples : 3.1) Surveillance des serveurs ------------------------------ -Il est possible de tester l'état des serveurs par établissement de connexion TCP -ou par envoi d'une requête HTTP. Un serveur hors d'usage ne sera pas utilisé -dans le processus de répartition de charge interne. Pour activer la surveillance, -ajouter le mot clé 'check' à la fin de la déclaration du serveur. Il est -possible de spécifier l'intervalle (en millisecondes) séparant deux tests du -serveur par le paramètre "inter", le nombre d'échecs acceptés par le paramètre -"fall", et le nombre de succès avant reprise par le paramètre "rise". Les -paramètres non précisés prennent les valeurs suivantes par défaut : +Il est possible de tester l'état des serveurs par établissement de connexion +TCP ou par envoi d'une requête HTTP. Un serveur hors d'usage ne sera pas +utilisé dans le processus de répartition de charge interne. Pour activer la +surveillance, ajouter le mot clé 'check' à la fin de la déclaration du serveur. +Il est possible de spécifier l'intervalle (en millisecondes) séparant deux +tests du serveur par le paramètre "inter", le nombre d'échecs acceptés par le +paramètre "fall", et le nombre de succès avant reprise par le paramètre "rise". +Les paramètres non précisés prennent les valeurs suivantes par défaut : - inter : 2000 - rise : 2 - fall : 3 - port : port de connexion du serveur Le mode par défaut consiste à établir des connexions TCP uniquement. Dans -certains cas de pannes, des serveurs peuvent continuer à accepter les connexions -sans les traiter. Depuis la version 1.1.16, haproxy est en mesure d'envoyer des -requêtes HTTP courtes et très peu coûteuses. Les versions 1.1.16 et 1.1.17 -utilisent "OPTIONS / HTTP/1.0". Dans les versions 1.1.18 à 1.1.20, les requêtes -ont été changées en "OPTIONS * HTTP/1.0" pour des raisons de contrôle d'accès aux -ressources. Cependant, cette requête documentée dans la RFC2068 n'est pas -comprise par tous les serveurs. Donc à partir de la version 1.1.21, la requête -par défaut est revenue à "OPTIONS / HTTP/1.0", mais il est possible de -paramétrer la partie URI. Les requêtes OPTIONS présentent l'avantage d'être -facilement extractibles des logs, et de ne pas induire d'accès aux fichiers côté -serveur. Seules les réponses 2xx et 3xx sont considérées valides, les autres (y -compris non-réponses) aboutissent à un échec. Le temps maximal imparti pour une -réponse est égal à l'intervalle entre deux tests (paramètre "inter"). Pour -activer ce mode, spécifier l'option "httpchk", éventuellement suivie d'une -méthode et d'une URI. L'option "httpchk" accepte donc 4 formes : +certains cas de pannes, des serveurs peuvent continuer à accepter les +connexions sans les traiter. Depuis la version 1.1.16, haproxy est en mesure +d'envoyer des requêtes HTTP courtes et très peu coûteuses. Les versions 1.1.16 +et 1.1.17 utilisent "OPTIONS / HTTP/1.0". Dans les versions 1.1.18 à 1.1.20, +les requêtes ont été changées en "OPTIONS * HTTP/1.0" pour des raisons de +contrôle d'accès aux ressources. Cependant, cette requête documentée dans la +RFC2068 n'est pas comprise par tous les serveurs. Donc à partir de la version +1.1.21, la requête par défaut est revenue à "OPTIONS / HTTP/1.0", mais il est +possible de paramétrer la partie URI. Les requêtes OPTIONS présentent +l'avantage d'être facilement extractibles des logs, et de ne pas induire +d'accès aux fichiers côté serveur. Seules les réponses 2xx et 3xx sont +considérées valides, les autres (y compris non-réponses) aboutissent à un +échec. Le temps maximal imparti pour une réponse est égal à l'intervalle entre +deux tests (paramètre "inter"). Pour activer ce mode, spécifier l'option +"httpchk", éventuellement suivie d'une méthode et d'une URI. L'option "httpchk" +accepte donc 4 formes : - option httpchk -> OPTIONS / HTTP/1.0 - option httpchk URI -> OPTIONS HTTP/1.0 - option httpchk METH URI -> HTTP/1.0 @@ -772,12 +825,12 @@ pour les configurations o lorsqu'il est déduit du port d'acceptation de la connexion. Pour cela, utiliser le paramètre 'port' suivi du numéro de port devant répondre aux requêtes. -Enfin, depuis la version 1.1.17, il est possible de visualiser rapidement l'état -courant de tous les serveurs. Pour cela, il suffit d'envoyer un signal SIGHUP au -processus proxy. L'état de tous les serveurs de tous les proxies est envoyé dans -les logs en niveau "notice", ainsi que sur la sortie d'erreurs si elle est -active. C'est une bonne raison pour avoir au moins un serveur de logs local en -niveau notice. +Enfin, depuis la version 1.1.17, il est possible de visualiser rapidement +l'état courant de tous les serveurs. Pour cela, il suffit d'envoyer un signal +SIGHUP au processus proxy. L'état de tous les serveurs de tous les proxies est +envoyé dans les logs en niveau "notice", ainsi que sur la sortie d'erreurs si +elle est active. C'est une bonne raison pour avoir au moins un serveur de logs +local en niveau notice. Depuis la version 1.1.18 (et 1.2.1), un message d'urgence est envoyé dans les logs en niveau 'emerg' si tous les serveurs d'une même instance sont tombés, @@ -890,12 +943,12 @@ Exemple : server web2 192.168.1.2:80 cookie server02 redispatch # renvoyer vers dispatch si refus de connexion. -Par défaut (et dans les versions 1.1.16 et antérieures), le paramètre redispatch -ne s'applique qu'aux échecs de connexion au serveur. Depuis la version 1.1.17, -il s'applique aussi aux connexions destinées à des serveurs identifiés comme -hors d'usage par la surveillance. Si l'on souhaite malgré tout qu'un client -disposant d'un cookie correspondant à un serveur défectueux tente de s'y -connecter, il faut préciser l'option "persist" : +Par défaut (et dans les versions 1.1.16 et antérieures), le paramètre +redispatch ne s'applique qu'aux échecs de connexion au serveur. Depuis la +version 1.1.17, il s'applique aussi aux connexions destinées à des serveurs +identifiés comme hors d'usage par la surveillance. Si l'on souhaite malgré +tout qu'un client disposant d'un cookie correspondant à un serveur défectueux +tente de s'y connecter, il faut préciser l'option "persist" : listen http_proxy 0.0.0.0:80 mode http @@ -918,9 +971,9 @@ la r --------------------------- 4.1.1) Fonctionnement en mode transparent --------------------------------------- -En mode HTTP, le mot clé 'transparent' permet d'intercepter des sessions routées -à travers la machine hébergeant le proxy. Dans ce mode, on ne précise pas -l'adresse de répartition 'dispatch', car celle-ci est tirée de l'adresse +En mode HTTP, le mot clé 'transparent' permet d'intercepter des sessions +routées à travers la machine hébergeant le proxy. Dans ce mode, on ne précise +pas l'adresse de répartition 'dispatch', car celle-ci est tirée de l'adresse destination de la session détournée. Le système doit permettre de rediriger les paquets vers un processus local. @@ -938,9 +991,10 @@ Exemple : Remarque : ---------- -Si le port n'est pas spécifié sur le serveur, c'est le port auquel s'est adressé -le client qui sera utilisé. Cela permet de relayer tous les ports TCP d'une même -adresse avec une même instance et sans utiliser directement le mode transparent. +Si le port n'est pas spécifié sur le serveur, c'est le port auquel s'est +adressé le client qui sera utilisé. Cela permet de relayer tous les ports TCP +d'une même adresse avec une même instance et sans utiliser directement le mode +transparent. Exemple : --------- @@ -1067,16 +1121,16 @@ Exemple : Le problème de loguer uniquement en fin de session, c'est qu'il est impossible de savoir ce qui se passe durant de gros transferts ou des sessions longues. Pour pallier à ce problème, une nouvelle option 'logasap' a été introduite dans -la version 1.1.28 (1.2.1). Lorsqu'elle est activée, le proxy loguera le plus tôt -possible, c'est à dire juste avant que ne débutent les transferts de données. -Cela signifie, dans le cas du TCP, qu'il loguera toujours le résultat de la -connexion vers le serveur, et dans le cas HTTP, qu'il loguera en fin de +la version 1.1.28 (1.2.1). Lorsqu'elle est activée, le proxy loguera le plus +tôt possible, c'est à dire juste avant que ne débutent les transferts de +données. Cela signifie, dans le cas du TCP, qu'il loguera toujours le résultat +de la connexion vers le serveur, et dans le cas HTTP, qu'il loguera en fin de traitement des entêtes de la réponse du serveur, auquel cas le nombre d'octets représentera la taille des entêtes retournés au client. -Afin d'éviter toute confusion avec les logs normaux, le temps total de transfert -et le nombre d'octets transférés sont préfixés d'un signe '+' rappeleant que les -valeurs réelles sont certainement plus élevées. +Afin d'éviter toute confusion avec les logs normaux, le temps total de +transfert et le nombre d'octets transférés sont préfixés d'un signe '+' +rappeleant que les valeurs réelles sont certainement plus élevées. Exemple : --------- @@ -1167,9 +1221,9 @@ Autres cas ('xx' repr 4.2.4) Conditions de déconnexion -------------------------------- Les logs TCP et HTTP fournissent un indicateur de complétude de la session. -C'est un champ de 4 caractères (2 en TCP) précédant la requête HTTP, indiquant : - - sur le premier caractère, un code précisant le premier événement qui a causé - la terminaison de la session : +C'est un champ de 4 caractères (2 en TCP) précédant la requête HTTP, indiquant: + - sur le premier caractère, un code précisant le premier événement qui a + causé la terminaison de la session : C : fermeture de la session TCP de la part du client S : fermeture de la session TCP de la part du serveur, ou refus de connexion @@ -1206,8 +1260,8 @@ C'est un champ de 4 caract serveur correspondant. - : non appliquable - - le dernier caractère indique l'éventuel traitement effectué sur un cookie de - persistence retrourné par le serveur (uniquement en mode HTTP) : + - le dernier caractère indique l'éventuel traitement effectué sur un cookie + de persistence retrourné par le serveur (uniquement en mode HTTP) : N : aucun cookie de persistence n'a été fourni par le serveur. P : un cookie de persistence a été fourni par le serveur et transmis @@ -1241,9 +1295,9 @@ Exemples : capture cookie vgnvisitor= len 32 Dans les logs, le champ précédant l'indicateur de complétude contient le cookie -positionné par le serveur, précédé du cookie positionné par le client. Chacun de -ces champs est remplacé par le signe "-" lorsqu'aucun cookie n'est fourni par le -client ou le serveur. +positionné par le serveur, précédé du cookie positionné par le client. Chacun +de ces champs est remplacé par le signe "-" lorsqu'aucun cookie n'est fourni +par le client ou le serveur. 4.2.5) Exemples de logs ----------------------- @@ -1281,17 +1335,18 @@ client ou le serveur. - haproxy[18989]: 10.0.0.1:34552 [15/Oct/2003:15:26:31] relais-http Srv1 3183/-1/-1/11215 503 0 - - SC-- "HEAD / HTTP/1.0" => La requête client met 3s à entrer (peut-être un problème réseau), et la connexion ('SC--') vers le serveur échoue au bout de 4 tentatives de 2 - secondes (retries 3 dans la conf), puis un code 503 est retourné au client. + secondes (retries 3 dans la conf), puis un code 503 est retourné au + client. 4.2.6) Caractères non-imprimables --------------------------------- Depuis la version 1.1.29, les caractères non-imprimables ne sont plus envoyés -tels quels dans les lignes de logs, mais inscrits sous la forme de deux chiffres -hexadécimaux, préfixés du caractère d'échappement '#'. Les seuls caractères -dorénavant logués tels quels sont compris entre 32 et 126. Bien évidemment, le -caractère d'échappement '#' est lui-même encodé afin de lever l'ambiguité. Il en -est de même pour le caractère '"', ainsi que les caractères '{', '|' et '}' pour -les en-têtes. +tels quels dans les lignes de logs, mais inscrits sous la forme de deux +chiffres hexadécimaux, préfixés du caractère d'échappement '#'. Les seuls +caractères dorénavant logués tels quels sont compris entre 32 et 126. Bien +évidemment, le caractère d'échappement '#' est lui-même encodé afin de lever +l'ambiguité. Il en est de même pour le caractère '"', ainsi que les caractères +'{', '|' et '}' pour les en-têtes. 4.2.7) Journalisation d'en-têtes -------------------------------- @@ -1300,10 +1355,10 @@ d'en-t requête que de la réponse. C'est particulièrement pratique pour savoir à quel serveur virtuel une requête s'adressait, pour connaitre la longueur des données émises lors d'un POST, ou encore loguer un identifiant unique de requête -positionné en amont. Dans la réponse, on peut chercher également à conserver des -informations relatives à la taille annoncée de la réponse, le fonctionnement -attendu du cache, ou encore la localisation d'un objet en cas de redirection. -La syntaxe est la suivante : +positionné en amont. Dans la réponse, on peut chercher également à conserver +des informations relatives à la taille annoncée de la réponse, le +fonctionnement attendu du cache, ou encore la localisation d'un objet en cas +de redirection. La syntaxe est la suivante : capture request header len capture response header len @@ -1322,12 +1377,13 @@ Exemples: # noter l'URL de redirection capture response header Location len 20 -Les en-têtes non trouvés sont logués à vide, et si un en-tête apparait plusieurs -fois, seule la dernière occurence sera conservée. Les en-têtes de requête sont -regroupés entre deux accolades '{' et '}' dans l'ordre de leur déclaration, et -chacun séparés par une barre verticale '|', sans aucun espace. Les en-têtes de -réponse sont présentés de la même manière, mais après un espace suivant le bloc -d'en-tête de requête. Le tout précède la requête HTTP. Exemple : +Les en-têtes non trouvés sont logués à vide, et si un en-tête apparait +plusieurs fois, seule la dernière occurence sera conservée. Les en-têtes de +requête sont regroupés entre deux accolades '{' et '}' dans l'ordre de leur +déclaration, et chacun séparés par une barre verticale '|', sans aucun espace. +Les en-têtes de réponse sont présentés de la même manière, mais après un +espace suivant le bloc d'en-tête de requête. Le tout précède la requête HTTP. +Exemple : Config: @@ -1350,8 +1406,8 @@ Aug 9 20:30:46 localhost haproxy[2022]: 127.0.0.1:34028 [09/Aug/2004:20:30:46] ---------------------------------- En mode HTTP uniquement, il est possible de remplacer certains en-têtes dans la requête et/ou la réponse à partir d'expressions régulières. Il est également -possible de bloquer certaines requêtes en fonction du contenu des en-têtes ou de -la requête. Une limitation cependant : les en-têtes fournis au milieu de +possible de bloquer certaines requêtes en fonction du contenu des en-têtes ou +de la requête. Une limitation cependant : les en-têtes fournis au milieu de connexions persistentes (keep-alive) ne sont pas vus car ils sont considérés comme faisant partie des échanges de données consécutifs à la première requête. Les données ne sont pas affectées, ceci ne s'applique qu'aux en-têtes. @@ -1517,14 +1573,14 @@ puisse corriger le nom du cookie dans toutes les futures requ 4.5) Protection contre les fuites d'informations du serveur ----------------------------------------------------------- -Dans les versions 1.1.28 et 1.2.1, une nouvelle option 'checkcache' a été créée. -Elle sert à inspecter minutieusement les entêtes 'Cache-control', 'Pragma', et -'Set-cookie' dans les réponses serveur pour déterminer s'il y a un risque de -cacher un cookie sur un proxy côté client. Quand cette option est activée, les -seules réponses qui peuvent être retournées au client sont : +Dans les versions 1.1.28 et 1.2.1, une nouvelle option 'checkcache' a été +créée. Elle sert à inspecter minutieusement les entêtes 'Cache-control', +'Pragma', et 'Set-cookie' dans les réponses serveur pour déterminer s'il y a +un risque de cacher un cookie sur un proxy côté client. Quand cette option est +activée, les seules réponses qui peuvent être retournées au client sont : - toutes celles qui n'ont pas d'entête 'Set-cookie' ; - toutes celles qui ont un code de retour autre que 200, 203, 206, 300, 301, - 410, sauf si le server a positionné un entête 'Cache-control: public' ; + 410, sauf si le serveur a positionné un entête 'Cache-control: public' ; - celles qui font suite à une requête POST, sauf si le serveur a positionné un entête 'Cache-control: public' ; - celles qui ont un entête 'Pragma: no-cache' ; @@ -1557,7 +1613,7 @@ Certaines situations conduisent Un message d'erreur succint tiré de la RFC accompagne ces codes de retour. Cependant, en fonction du type de clientèle, on peut préférer retourner des -pages personnalisées. Ceci est possible par le biais de la commande "errorloc" : +pages personnalisées. Ceci est possible par le biais de la commande "errorloc": errorloc @@ -1595,9 +1651,9 @@ d 4.7) Changement des valeurs par défaut -------------------------------------- -Dans la version 1.1.22 est apparue la notion de valeurs par défaut, ce qui évite -de répéter des paramètres communs à toutes les instances, tels que les timeouts, -adresses de log, modes de fonctionnement, etc. +Dans la version 1.1.22 est apparue la notion de valeurs par défaut, ce qui +évite de répéter des paramètres communs à toutes les instances, tels que les +timeouts, adresses de log, modes de fonctionnement, etc. Les valeurs par défaut sont positionnées dans la dernière section 'defaults' précédent l'instance qui les utilisera. On peut donc mettre autant de sections diff --git a/haproxy.c b/haproxy.c index 63822e5037..301ad25e9f 100644 --- a/haproxy.c +++ b/haproxy.c @@ -77,7 +77,7 @@ #include "include/appsession.h" #define HAPROXY_VERSION "1.2.5" -#define HAPROXY_DATE "2005/04/24" +#define HAPROXY_DATE "2005/04/30" /* this is for libc5 for example */ #ifndef TCP_NODELAY @@ -255,9 +255,9 @@ int strlcpy2(char *dst, const char *src, int size) { #define sizeof_session sizeof(struct session) #define sizeof_buffer sizeof(struct buffer) #define sizeof_fdtab sizeof(struct fdtab) -#define sizeof_curappsession CAPTURE_LEN /* current_session pool */ #define sizeof_requri REQURI_LEN #define sizeof_capture CAPTURE_LEN +#define sizeof_curappsession CAPTURE_LEN /* current_session pool */ #define sizeof_appsess sizeof(struct appsessions) /* different possible states for the sockets */ @@ -287,6 +287,11 @@ int strlcpy2(char *dst, const char *src, int size) { #define POLL_LOOP_ACTION_RUN 1 #define POLL_LOOP_ACTION_CLEAN 2 +/* poll mechanisms available */ +#define POLL_USE_SELECT (1<<0) +#define POLL_USE_POLL (1<<1) +#define POLL_USE_EPOLL (1<<2) + /* bits for proxy->options */ #define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */ #define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */ @@ -622,8 +627,7 @@ static struct { fd_set *StaticReadEvent, *StaticWriteEvent; -int cfg_use_epoll = 0; /* use epoll() instead of select() ? */ -int cfg_use_poll = 0; /* use poll() instead of select() ? */ +int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */ void **pool_session = NULL, **pool_buffer = NULL, @@ -823,10 +827,10 @@ void usage(char *name) { " -N sets the default, per-proxy maximum # of connections (%d)\n" " -p writes pids of all children to this file\n" #if defined(ENABLE_EPOLL) - " -E tries to use epoll() instead of select()\n" + " -de disables epoll() usage even when available\n" #endif #if defined(ENABLE_POLL) - " -P tries to use poll() instead of select()\n" + " -dp disables poll() usage even when available\n" #endif "\n", name, DEFAULT_MAXCONN, cfg_maxpconn); @@ -5191,7 +5195,6 @@ int select_loop(int action) { } #endif - if (next_time > 0) { /* FIXME */ /* Convert to timeval */ /* to avoid eventual select loops due to timer precision */ @@ -5247,10 +5250,10 @@ int select_loop(int action) { */ if (fdtab[fd].state == FD_STCLOSE) continue; - + if (FD_ISSET(fd, ReadEvent)) fdtab[fd].read(fd); - + if (FD_ISSET(fd, WriteEvent)) fdtab[fd].write(fd); } @@ -5462,6 +5465,7 @@ void dump(int sig) { } } +#ifdef DEBUG_MEMORY static void fast_stop(void) { struct proxy *p; @@ -5494,6 +5498,7 @@ void sig_term(int sig) { /* If we are killed twice, we decide to die*/ signal(sig, SIG_DFL); } +#endif /* returns the pointer to an error in the replacement string, or NULL if OK */ char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) { @@ -5535,6 +5540,12 @@ int cfg_parse_global(char *file, int linenum, char **args) { else if (!strcmp(args[0], "debug")) { global.mode |= MODE_DEBUG; } + else if (!strcmp(args[0], "noepoll")) { + cfg_polling_mechanism &= ~POLL_USE_EPOLL; + } + else if (!strcmp(args[0], "nopoll")) { + cfg_polling_mechanism &= ~POLL_USE_POLL; + } else if (!strcmp(args[0], "quiet")) { global.mode |= MODE_QUIET; } @@ -7139,6 +7150,14 @@ void init(int argc, char **argv) { tmp++; } + cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */ +#if defined(ENABLE_POLL) + cfg_polling_mechanism |= POLL_USE_POLL; +#endif +#if defined(ENABLE_EPOLL) + cfg_polling_mechanism |= POLL_USE_EPOLL; +#endif + pid = getpid(); progname = *argv; while ((tmp = strchr(progname, '/')) != NULL) @@ -7157,12 +7176,12 @@ void init(int argc, char **argv) { exit(0); } #if defined(ENABLE_EPOLL) - else if (*flag == 'E') - cfg_use_epoll = 1; + else if (*flag == 'd' && flag[1] == 'e') + cfg_polling_mechanism &= ~POLL_USE_EPOLL; #endif #if defined(ENABLE_POLL) - else if (*flag == 'P') - cfg_use_poll = 1; + else if (*flag == 'd' && flag[1] == 'p') + cfg_polling_mechanism &= ~POLL_USE_POLL; #endif else if (*flag == 'V') arg_mode |= MODE_VERBOSE; @@ -7501,8 +7520,10 @@ int main(int argc, char **argv) { signal(SIGQUIT, dump); signal(SIGUSR1, sig_soft_stop); signal(SIGHUP, sig_dump_state); +#ifdef DEBUG_MEMORY signal(SIGINT, sig_int); signal(SIGTERM, sig_term); +#endif /* on very high loads, a sigpipe sometimes happen just between the * getsockopt() which tells "it's OK to write", and the following write :-( @@ -7588,34 +7609,37 @@ int main(int argc, char **argv) { } #if defined(ENABLE_EPOLL) - if (cfg_use_epoll) { + if (cfg_polling_mechanism & POLL_USE_EPOLL) { if (epoll_loop(POLL_LOOP_ACTION_INIT)) { epoll_loop(POLL_LOOP_ACTION_RUN); epoll_loop(POLL_LOOP_ACTION_CLEAN); + cfg_polling_mechanism &= POLL_USE_EPOLL; } else { - Warning("epoll() is not available. Trying poll() or select() instead.\n"); - cfg_use_epoll = 0; + Warning("epoll() is not available. Using poll()/select() instead.\n"); + cfg_polling_mechanism &= ~POLL_USE_EPOLL; } } #endif #if defined(ENABLE_POLL) - if (cfg_use_poll) { + if (cfg_polling_mechanism & POLL_USE_POLL) { if (poll_loop(POLL_LOOP_ACTION_INIT)) { poll_loop(POLL_LOOP_ACTION_RUN); poll_loop(POLL_LOOP_ACTION_CLEAN); + cfg_polling_mechanism &= POLL_USE_POLL; } else { Warning("poll() is not available. Using select() instead.\n"); - cfg_use_poll = 0; + cfg_polling_mechanism &= ~POLL_USE_POLL; } } #endif - if (!cfg_use_epoll && !cfg_use_poll) { + if (cfg_polling_mechanism & POLL_USE_SELECT) { if (select_loop(POLL_LOOP_ACTION_INIT)) { select_loop(POLL_LOOP_ACTION_RUN); select_loop(POLL_LOOP_ACTION_CLEAN); + cfg_polling_mechanism &= POLL_USE_SELECT; } }