- forc3
- Page perso
- Compte créé le 12 septembre 2001
- Vu le 10 septembre 2008
Format RSS des journaux- Contacter cet utilisateur
Derniers commentaire(s) [Tous] :
- HA proxy feature request (Score : -1)
- Re: idée toute simple (Score : 1)
- En attendant qu'elle soit stable (Score : 3)
- Re: Et du côté des perfs ? (Score : 2)
- Re: Et du côté des perfs ? (Score : -1)
- Re: Et du côté des perfs ? (Score : 4)
- En espérant que cela boost l'utilisation de smalltalk (Score : 1)
- Re: Durée de vie des objets et connexions permanentes... (Score : 1)
- Re: Durée de vie des objets et connexions permanentes... (Score : 1)
- Re: Durée de vie des objets et connexions permanentes... (Score : 3)
- Durée de vie des objets et connexions permanentes... (Score : 5)
- Drupal et YSlow ( (Score : 0)
- De PHP à un framework Python (Score : 3)
- Re: erlang ? (Score : 2)
- Re: Erlang ? (Score : 2)
- Re: Erlang ? (Score : 1)
- Re: Erlang ? (Score : 3)
- Erlang ? (Score : 5)
- Problèmes inérant à Nagios corrigés ? (Score : 4)
- Re: OCSF2 ? (Score : 6)
Dernières entrées de forum(s)
[Toutes] :
Ror ne se porte plus très bien ? Quid des autres ?
Posté le 04 janvier 2008
0
D'après le lien suivantZed Rant
la communauté ruby ne brille pas véritablement par ses compétences ...
Est-ce vraiment si dramatique que ca ?
Est-ce scalabilité signifie juste de mettre un serveur memcached dans l'architecture d'une plateforme ?
Il semblerait que ni PHP ni Ruby ni Python, out of the box ne permettent de batir des architectures scalables... Serait-ce peut être le moment de revoir les copies ?
En avons nous véritablement besoin ?
> Lire le journal (37 commentaires, moyenne: 1,2).
Flex mon ami !
Posté le 31 janvier 2005
0
** toutes mes excuses pour le formattage de code foireux** mais je n'obtiens pas les tabulations avec les balises code
** Donc j'utilise pre mais du coup les inf et sup des include sont pas
** affichés. J'espère que c'est un problème du à la css que j'utilise...
** Les lignes vides sont une des conséquences aussi...
De retour avec de nouvelles aventures à propos de flex, c'est outil
magnifique qui vous fait gagner du temps, de la sécurité, et de la
maintenabilité. Mais passons cette description qui bien sûr ne
satisfera pas tout le monde. Mais je m'en cogne. Je viens juste ici
vous livrez un peu de mon expérience à avec outil.
Un peu de 'background', j'ai toujours trouvé l'écriture de parser
très très lourd. Je me suis rendu compte très vite que pour faire
quelquechose de maintenable c'était impossible, car personne
n'avait le courage de replonger le nez dans ses lignes, même moi
l'auteur détestait me rendre compte que je devais y retourner.
Un beau jour, au gré de mes balades internet, il y a un moment je
tombe sur flex, et plus tard bison. Etant déjà grand utilisateur de
perl pour ses expressions rationnelles, j'ai trouvé l'approche très
intéressante de flex. Aimant la performance et ne supportant pas
savoir que ma chaine de caractère va être dupliquée X fois en
mémoire juste pour matcher un simple motif, j'ai vite abandonné
perl pour parser quoi que ce soit. L'énorme avantage de flex c'est
qu'il ne fonctionne pas par ligne. C'est beaucoup plus simple de
trouver des liens web dans une seule ligne qu'en Perl. Et c'est en
plus beaucoup plus efficace...
Une fois la maîtrise de l'outil, je me disais que c'était bien la
classe mais j'aurais vraiment voulu essayer d'étendre ses
possibilités autre part que sur des fichiers ... Sur des socket ca
serait fort intéressant. C'est à la suite du developpement d'un
serveur IMAP dont le parseur est écrit intégralement en flex/bison,
que me suis heurté au problème spécifique des sockets et de la
programmation réseau. C'est à dire, que tous les gens qui me
parlent ne pensent qu'a tenter de faire des overflow sur mes
buffer, et qu'ils prennent un malin plaisir à ouvrir des connexions
sans rien n'y faire.
C'est constation faite, je trouvais insoutenable de me voir ainsi à
la merci de n'importe qui. Il me fallait une solution. C'est une
mission pour moi !
Je vais donc vous présenter ici ma méthode pour rendre flex,
utilisable comme moteur principal d'une application utilisant un
protocole bien défini. Au hasard HTTP...
Cependant avant de passer au HTTP, je vais le faire sur un exemple
très simple. Un protocole utilisant des headers déjà très courant
sur internet ;p.
Récapitulons ce que nous cherchons à faire:
- lire un flux de données, avec un timeout
- lire un flux de données en controlant leur taille.
Ce qui veut dire que notre serveur ne dois attendre des données que
pendant un certains temps, et doit pouvoir vérifier qu'il n'a pas
reçu trop de données...
Afin de rendre possible ces deux choses nous avons besoin de rendre
notre fonction flex capable d'attendre des données seulement
pendant une durée définie, et capable de savoir combien de données
il me reste à lire. Pour la première chose c'est très simple, il
suffit de passer le fd en O_NONBLOCK et d'appeler poll dessus avant
de faire un read(). Pour la seconde chose nous allons utilisez ce
que le protocole ont prévus pour cela, c'est à dire le
Content-Length...
Pour bien comprendre ce que nous allons faire, il faut juste noter
que nous allons faire avec flex un parseur capable de s'arréter
s'il n'a rien lu, et surtout d'extraire du flux lui même la
quantité de données à lire.
Pour les paranoiaques comme moi, on notera qu'il est très important
de fixer une limite à la quantité des données à lire, il est hors
de question d'accepter toutes les valeurs...
Assez de blah blah, entrons dans le code. Première chose on
redéfini la fonction de lecture de flex !
#define YY_INPUT(buf, result, max_size) \
do { \
int ret = 0; \
struct pollfd fds; \
fds.fd = 0; \
fds.events = POLLIN; \
if ( ! poll(&fds, 1, 5000) ) { \
fatal = 1; \
result = 0; \
YY_FATAL_ERROR("input in flex scanner failed timeout reading") \
goto skip_reading; \
} \
if ( fds.revents & ( POLLOUT | POLLERR | POLLHUP ) ) { \
fatal = 1; \
result = 0; \
goto skip_reading; \
} \
if ( (result = read( 0, (char *) buf, max_size )) < 0 ) { \
fatal = 1; \
result = 0; \
YY_FATAL_ERROR( "input in flex scanner failed" ) \
} \
skip_reading: \
} while (0)
Ainsi flex va utiliser ce code pour lire des données, les attentifs
auront notés que ce code ne contient pas le passage du fd en
O_NONBLOCK, enfait c'est fait avant d'appeler yylex(). La
différence fondamentale entre le faire et ne pas le faire c'est que
le read sera bloquant ou pas, par contre il n'y aura aucune
différence sur la fonction poll(). Dans certains cas, il est
possible de ne pouvoir lire des données après la sortie d'une
fonction de monitoring de fd (poll(), select(), kqueue(), sigio,
epoll() etc). Donc dans un cas le read retourner -1 et errno a
EAGAIN, alors que dans l'autre il va bloquer jusqu'à obtenir des
données. Ce sont vos tests qui décideront de la validité de mettre
le fd en O_NONBLOCK, c'est pour cela que ce n'est pas inclu dans la
macro.
Autre problème, la fonction YY_FATAL_ERROR, sort définitivement du
lexer. Moi je ne veux pas qu'un timeout me fasse sortir, donc je
redifini la fonction YY_FATAL_ERROR.
#define YY_FATAL_ERROR(msg) fatal_error(msg);
J'aurais bien sur inseré cette ligne avant la macro YY_INPUT...
Le code de ma fonction fatal_error est le suivant
static void fatal_error(const char *msg)
{
printf("fatal error: %s\n", msg);
fatal = 1;
}
Vous aurez compris, je pense, que ma variable fatal est du type
extern volatile int, et est utilisée dans la boucle principale du
programme appelant la fonction yylex(). C'est un exemple, a vous
d'adapter en fonction de vos besoins/idées.
Maintenant passons à l'étape, lecture de données bornée. Flex nous
mets à disposition la fonction input() qui va appeler notre
fonction de lecture si besoin est, et nous retourner le caractère
suivant. C'est elle qui va être au coeur de notre gestion de
donnée... Et voici comment:
T_CONTENT_SIZE ^content-size:\ [0-9]+$
T_END_OF_HEADER \n\n
%%
{T_CONTENT_SIZE} {
bytes = atoi((const char *) &yytext[14]);
if ( bytes < 0 )
bytes = 0;
printf("+ CS %d\n", bytes);
}
{T_END_OF_HEADER} {
already_read = 0;
int ret;
buffer = malloc(sizeof(char) * bytes);
if ( buffer ) {
for ( already_read = 0; already_read < bytes; already_read++ ) {
ret = input();
if ( (ret == EOF) || (ret == 0) || fatal ) {
printf("error: end of input after reading only %d bytes.\n", already_read);
yyterminate();
break;
}
buffer[already_read] = ret;
}
}
}
Alors, nous utilisons content-size, pour le fun, changer le en
content-length ca marche autant ... Ensuite nous utilisons le motif
T_END_OF_HEADER afin de marquer le passage entre headers et data.
C'est très proche du HTTP... C'est voulu.
Dans le flux lorsque nous trouvons T_CONTENT_SIZE, nous récupérons
la valeur, (il faut checker errno avec atoi pour différencier de 0
et de 0 à cause d'une erreur, ne faites pas comme moi ...) nous la
stockons dans bytes.
Après à la fin de headers après T_END_OF_HEADER, nous allouons
assez de mémoire pour recevoir les données. Une simple boucle
permet de remplir le buffer tout justement alloué. Remarquer bien
que nous ne lisons pas plus que bytes... Nous n'écrasons rien.
(On peut/_doit_ tout a fait prévoir une vérification plus solide de bytes,
en la bornant à un certain maximum...)
Nous testons tous les valeur de retour de input() afin d'agir en
conséquence et de gérer une éventuelle déconnexion, ou erreur de
lecture. Libre à vous encore une fois d'appeler yyterminate() ou
pas.
Voici le code entier du programme compilable de cette manière:
- flex -Cr -i test.lex
- gcc lex.yy.c -o input_test
test.lex
{
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <poll.h>
static unsigned long bytes;
static unsigned long already_read;
static char *buffer;
static int fatal;
static void fatal_error(const char *msg);
#define YY_FATAL_ERROR(msg) fatal_error(msg);
#define YY_INPUT(buf, result, max_size) \
do { \
int ret = 0; \
struct pollfd fds; \
fds.fd = 0; \
fds.events = POLLIN; \
if ( ! poll(&fds, 1, 5000) ) { \
fatal = 1; \
result = 0; \
YY_FATAL_ERROR("input in flex scanner failed timeout reading") \
goto skip_reading; \
} \
if ( fds.revents & ( POLLOUT | POLLERR | POLLHUP ) ) { \
fatal = 1; \
result = 0; \
goto skip_reading; \
} \
if ( (result = read( 0, (char *) buf, max_size )) < 0 ) { \
fatal = 1; \
result = 0; \
YY_FATAL_ERROR( "input in flex scanner failed" ) \
} \
skip_reading: \
} while (0)
%}
T_CONTENT_TYPE ^content-type:\ [^ \n]+$
T_CONTENT_SIZE ^content-size:\ [0-9]+$
T_END_OF_HEADER \n\n
%%
{T_CONTENT_TYPE} {
printf("+ CT %.*s\n", yyleng - 14, &yytext[14]);
}
{T_CONTENT_SIZE} {
bytes = atoi((const char *) &yytext[14]);
if ( bytes < 0 )
bytes = 0;
printf("+ CS %d\n", bytes);
}
{T_END_OF_HEADER} {
already_read = 0;
int ret;
buffer = malloc(sizeof(char) * bytes);
if ( buffer ) {
for ( already_read = 0; already_read < bytes; already_read++ ) {
ret = input();
if ( (ret == EOF) || (ret == 0) || fatal ) {
printf("error: end of input after reading only %d bytes.\n", already_read);
yyterminate();
break;
}
buffer[already_read] = ret;
}
}
}
%%
static void fatal_error(const char *msg)
{
printf("fatal error: %s\n", msg);
fatal = 1;
}
int main()
{
fatal = 0;
buffer = 0;
yyin = stdin;
yylex();
printf("found %d bytes of data:\n%.*s\n", already_read, already_read, buffer);
if ( buffer )
free(buffer);
return 0;
}
En espérant que ça puisse vous vous inciter à coder
vos parsers avec des outils fait pour. Ca nous éviterait d'avoir
un nombre incalculable d'overflow dans les moindres petites fonctions
d'analyses de flux/caractères... Le libre en aurait bien besoin...
> Lire le journal (4 commentaires, moyenne: 1,5).
libc et sécurité...
Posté le 17 décembre 2004
0
Yop, amis coders !Combien sommes nous à utiliser une autre bibliothèque C que celle
standard ? Suis-je le seul à me rendre compte que tous les bugs
sont dus exclusivement, à la mauvaise utilisation des fonctions de
la libc. (toute plateforme confondue)
Que dès qu'un programme se veut secure, la première chose qu'il
implémente soit une bibliothèque ? Pourquoi ne sont elle jamais
réutilisées ?
Ne jamais réinventer la roue c'est ce qui se dit, mais je vois
surtout que c'est quelque-chose de très fréquent dès qu'il s'agit
d'un programme ''secure''. Pour s'en convaincre il suffit de voir
le nombre d'implémentations différentes dans la gestion de buffers
disponibles dans le monde des LL.
Suis-je réellement le seul malade à ne plus utiliser stdio.h et
string.h ?
J'utilise actuellement et essentiellement
http://www.fefe.de/libowfat/.(...) Et vous qu'utilisez vous ? ( ca fait
slogan pourri, mais j'aime bien !)
> Lire le journal (17 commentaires, moyenne: 2,1).
Générateur de générateur de 'parser'.
Posté le 16 décembre 2004
0
Non, ce n'est pas une typo, ni un récurrence foireuse...C'est juste un besoin ;p.
Voila, le but ultime et de prendre une RFC quelconque d'en extraire
l'EBNF et d'obtenir un parser.
J'ai déjà implémenté un générateur de FLEX/BISON capable de
comprendre des syntaxes assez simples, et j'aurais aimé souhaité
avoir des avis ou des références sur des travaux semblables.
Donc si certains ont des pointeurs, je suis preneur ...
> Lire le journal (7 commentaires, moyenne: 2,3).
Cette page donne des informations sur l'utilisateur forc3
telles que ses derniers commentaires, journaux, forums, date
de création, etc.
