[MINOR] stream_interface: make use of an applet descriptor for IO handlers

I/O handlers are still delicate to manipulate. They have no type, they're
just raw functions which have no knowledge of themselves. Let's have them
declared as applets once for all. That way we can have multiple applets
share the same handler functions and we can store their names there. When
we later need to add more parameters (eg: usage stats), we'll be able to
do so in the applets themselves.

The CLI functions has been prefixed with "cli" instead of "stats" as it's
clearly what is going on there.

The applet descriptor in the stream interface should get all the applet
specific data (st0, ...) but this will be done in the next patch so that
we don't pollute this one too much.
This commit is contained in:
Willy Tarreau 2011-02-13 13:16:36 +01:00
parent dfd7fca26c
commit b24281b0ff
9 changed files with 60 additions and 42 deletions

View File

@ -3,7 +3,7 @@
* This file contains definitions of some primitives to dedicated to * This file contains definitions of some primitives to dedicated to
* statistics output. * statistics output.
* *
* Copyright (C) 2000-2010 Willy Tarreau - w@1wt.eu * Copyright (C) 2000-2011 Willy Tarreau - w@1wt.eu
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -61,6 +61,8 @@
#define STAT_STATUS_EXCD "EXCD" /* an error occured becayse the buffer couldn't store all data */ #define STAT_STATUS_EXCD "EXCD" /* an error occured becayse the buffer couldn't store all data */
#define STAT_STATUS_DENY "DENY" /* action denied */ #define STAT_STATUS_DENY "DENY" /* action denied */
extern struct si_applet http_stats_applet;
extern struct si_applet cli_applet;
int stats_accept(struct session *s); int stats_accept(struct session *s);
int stats_sock_parse_request(struct stream_interface *si, char *line); int stats_sock_parse_request(struct stream_interface *si, char *line);
@ -71,7 +73,6 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri);
int stats_dump_sess_to_buffer(struct session *s, struct buffer *rep); int stats_dump_sess_to_buffer(struct session *s, struct buffer *rep);
int stats_dump_table_to_buffer(struct session *s, struct buffer *rep); int stats_dump_table_to_buffer(struct session *s, struct buffer *rep);
int stats_dump_errors_to_buffer(struct session *s, struct buffer *rep); int stats_dump_errors_to_buffer(struct session *s, struct buffer *rep);
void http_stats_io_handler(struct stream_interface *si);
#endif /* _PROTO_DUMPSTATS_H */ #endif /* _PROTO_DUMPSTATS_H */

View File

@ -2,7 +2,7 @@
* include/proto/stream_interface.h * include/proto/stream_interface.h
* This file contains stream_interface function prototypes * This file contains stream_interface function prototypes
* *
* Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu * Copyright (C) 2000-2011 Willy Tarreau - w@1wt.eu
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -42,7 +42,7 @@ void stream_int_chk_rcv(struct stream_interface *si);
void stream_int_chk_snd(struct stream_interface *si); void stream_int_chk_snd(struct stream_interface *si);
struct task *stream_int_register_handler(struct stream_interface *si, struct task *stream_int_register_handler(struct stream_interface *si,
void (*fct)(struct stream_interface *)); struct si_applet *app);
struct task *stream_int_register_handler_task(struct stream_interface *si, struct task *stream_int_register_handler_task(struct stream_interface *si,
struct task *(*fct)(struct task *)); struct task *(*fct)(struct task *));
void stream_int_unregister_handler(struct stream_interface *si); void stream_int_unregister_handler(struct stream_interface *si);

View File

@ -2,7 +2,7 @@
* include/types/stream_interface.h * include/types/stream_interface.h
* This file describes the stream_interface struct and associated constants. * This file describes the stream_interface struct and associated constants.
* *
* Copyright (C) 2000-2010 Willy Tarreau - w@1wt.eu * Copyright (C) 2000-2011 Willy Tarreau - w@1wt.eu
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -78,13 +78,11 @@ enum {
struct server; struct server;
struct proxy; struct proxy;
struct si_applet;
/* Note that if an iohandler is set, the update function will not be called by /* Note that if an applet is registered, the update function will not be called
* the session handler, so it may be used to resync flags at the end of the I/O * by the session handler, so it may be used to resync flags at the end of the
* handler. See stream_int_update_embedded() for reference. * applet handler. See stream_int_update_embedded() for reference.
* This struct could be optimized, because :
* - connect(), fd, conn_retries are only used in stream_sock mode
* - iohandler(), private, st0, st1 are only used in iohandler mode
*/ */
struct stream_interface { struct stream_interface {
unsigned int state; /* SI_ST* */ unsigned int state; /* SI_ST* */
@ -101,15 +99,22 @@ struct stream_interface {
int (*connect)(struct stream_interface *, struct proxy *, struct server *, int (*connect)(struct stream_interface *, struct proxy *, struct server *,
struct sockaddr *, struct sockaddr *); /* connect function if any */ struct sockaddr *, struct sockaddr *); /* connect function if any */
void (*release)(struct stream_interface *); /* handler to call after the last close() */ void (*release)(struct stream_interface *); /* handler to call after the last close() */
void (*iohandler)(struct stream_interface *); /* internal I/O handler when embedded */
struct buffer *ib, *ob; /* input and output buffers */ struct buffer *ib, *ob; /* input and output buffers */
int conn_retries; /* number of connect retries left */ int conn_retries; /* number of connect retries left */
unsigned int err_type; /* first error detected, one of SI_ET_* */ unsigned int err_type; /* first error detected, one of SI_ET_* */
void *err_loc; /* commonly the server, NULL when SI_ET_NONE */ void *err_loc; /* commonly the server, NULL when SI_ET_NONE */
struct {
struct si_applet *handler; /* applet to use instead of doing I/O */
} applet;
void *private; /* may be used by any function above */ void *private; /* may be used by any function above */
unsigned int st0, st1; /* may be used by any function above */ unsigned int st0, st1; /* may be used by any function above */
}; };
/* An applet designed to run in a stream interface */
struct si_applet {
char *name; /* applet's name to report in logs */
void (*fct)(struct stream_interface *); /* internal I/O handler, may never be NULL */
};
#endif /* _TYPES_STREAM_INTERFACE_H */ #endif /* _TYPES_STREAM_INTERFACE_H */

View File

@ -84,7 +84,7 @@ const char stats_permission_denied_msg[] =
int stats_accept(struct session *s) int stats_accept(struct session *s)
{ {
/* we have a dedicated I/O handler for the stats */ /* we have a dedicated I/O handler for the stats */
stream_int_register_handler(&s->si[1], stats_io_handler); stream_int_register_handler(&s->si[1], &cli_applet);
s->si[1].private = s; s->si[1].private = s;
s->si[1].st1 = 0; s->si[1].st1 = 0;
s->si[1].st0 = STAT_CLI_INIT; s->si[1].st0 = STAT_CLI_INIT;
@ -848,7 +848,7 @@ int stats_sock_parse_request(struct stream_interface *si, char *line)
* STAT_CLI_* constants. si->st1 is used to indicate whether prompt is enabled * STAT_CLI_* constants. si->st1 is used to indicate whether prompt is enabled
* or not. * or not.
*/ */
void stats_io_handler(struct stream_interface *si) static void cli_io_handler(struct stream_interface *si)
{ {
struct session *s = si->private; struct session *s = si->private;
struct buffer *req = si->ob; struct buffer *req = si->ob;
@ -1200,7 +1200,7 @@ int stats_http_redir(struct session *s, struct buffer *rep, struct uri_auth *uri
* si->st0 becomes non-zero once the transfer is finished. The handler * si->st0 becomes non-zero once the transfer is finished. The handler
* automatically unregisters itself once transfer is complete. * automatically unregisters itself once transfer is complete.
*/ */
void http_stats_io_handler(struct stream_interface *si) static void http_stats_io_handler(struct stream_interface *si)
{ {
struct session *s = si->private; struct session *s = si->private;
struct buffer *req = si->ob; struct buffer *req = si->ob;
@ -3583,6 +3583,15 @@ int stats_dump_errors_to_buffer(struct session *s, struct buffer *rep)
return 1; return 1;
} }
struct si_applet http_stats_applet = {
.name = "<STATS>", /* used for logging */
.fct = http_stats_io_handler,
};
struct si_applet cli_applet = {
.name = "<CLI>", /* used for logging */
.fct = cli_io_handler,
};
static struct cfg_kw_list cfg_kws = {{ },{ static struct cfg_kw_list cfg_kws = {{ },{
{ CFG_GLOBAL, "stats", stats_parse_global }, { CFG_GLOBAL, "stats", stats_parse_global },

View File

@ -216,7 +216,7 @@ void peer_session_release(struct stream_interface *si)
/* /*
* IO Handler to handle message exchance with a peer * IO Handler to handle message exchance with a peer
*/ */
void peer_io_handler(struct stream_interface *si) static void peer_io_handler(struct stream_interface *si)
{ {
struct task *t= (struct task *)si->owner; struct task *t= (struct task *)si->owner;
struct session *s = (struct session *)t->context; struct session *s = (struct session *)t->context;
@ -1041,6 +1041,10 @@ quit:
return; return;
} }
static struct si_applet peer_applet = {
.name = "<PEER>", /* used for logging */
.fct = peer_io_handler,
};
/* /*
* Use this function to force a close of a peer session * Use this function to force a close of a peer session
@ -1049,7 +1053,7 @@ void peer_session_forceshutdown(struct session * session)
{ {
struct stream_interface *oldsi; struct stream_interface *oldsi;
if (session->si[0].iohandler == peer_io_handler) { if (session->si[0].applet.handler == &peer_applet) {
oldsi = &session->si[0]; oldsi = &session->si[0];
} }
else { else {
@ -1072,7 +1076,7 @@ void peer_session_forceshutdown(struct session * session)
int peer_accept(struct session *s) int peer_accept(struct session *s)
{ {
/* we have a dedicated I/O handler for the stats */ /* we have a dedicated I/O handler for the stats */
stream_int_register_handler(&s->si[1], peer_io_handler); stream_int_register_handler(&s->si[1], &peer_applet);
s->si[1].release = peer_session_release; s->si[1].release = peer_session_release;
s->si[1].private = s; s->si[1].private = s;
s->si[1].st0 = PEER_SESSION_ACCEPT; s->si[1].st0 = PEER_SESSION_ACCEPT;
@ -1158,7 +1162,7 @@ struct session *peer_session_create(struct peer *peer, struct peer_session *ps)
s->si[0].private = (void *)ps; s->si[0].private = (void *)ps;
s->si[0].st0 = PEER_SESSION_CONNECT; s->si[0].st0 = PEER_SESSION_CONNECT;
stream_int_register_handler(&s->si[0], peer_io_handler); stream_int_register_handler(&s->si[0], &peer_applet);
s->si[0].release = peer_session_release; s->si[0].release = peer_session_release;
s->si[1].fd = -1; /* just to help with debugging */ s->si[1].fd = -1; /* just to help with debugging */

View File

@ -3226,7 +3226,7 @@ int http_process_req_common(struct session *s, struct buffer *req, int an_bit, s
s->data_source = DATA_SRC_STATS; s->data_source = DATA_SRC_STATS;
s->data_state = DATA_ST_INIT; s->data_state = DATA_ST_INIT;
s->task->nice = -32; /* small boost for HTTP statistics */ s->task->nice = -32; /* small boost for HTTP statistics */
stream_int_register_handler(s->rep->prod, http_stats_io_handler); stream_int_register_handler(s->rep->prod, &http_stats_applet);
s->rep->prod->private = s; s->rep->prod->private = s;
s->rep->prod->st0 = s->rep->prod->st1 = 0; s->rep->prod->st0 = s->rep->prod->st1 = 0;
req->analysers = 0; req->analysers = 0;

View File

@ -167,7 +167,7 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr)
s->si[0].err_type = SI_ET_NONE; s->si[0].err_type = SI_ET_NONE;
s->si[0].err_loc = NULL; s->si[0].err_loc = NULL;
s->si[0].connect = NULL; s->si[0].connect = NULL;
s->si[0].iohandler = NULL; s->si[0].applet.handler = NULL;
s->si[0].release = NULL; s->si[0].release = NULL;
s->si[0].exp = TICK_ETERNITY; s->si[0].exp = TICK_ETERNITY;
s->si[0].flags = SI_FL_NONE; s->si[0].flags = SI_FL_NONE;
@ -190,7 +190,7 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr)
s->si[1].err_type = SI_ET_NONE; s->si[1].err_type = SI_ET_NONE;
s->si[1].err_loc = NULL; s->si[1].err_loc = NULL;
s->si[1].connect = NULL; s->si[1].connect = NULL;
s->si[1].iohandler = NULL; s->si[1].applet.handler = NULL;
s->si[1].release = NULL; s->si[1].release = NULL;
s->si[1].shutr = stream_int_shutr; s->si[1].shutr = stream_int_shutr;
s->si[1].shutw = stream_int_shutw; s->si[1].shutw = stream_int_shutw;
@ -1786,13 +1786,13 @@ struct task *process_session(struct task *t)
if (s->req->cons->state == SI_ST_INI) { if (s->req->cons->state == SI_ST_INI) {
if (!(s->req->flags & BF_SHUTW)) { if (!(s->req->flags & BF_SHUTW)) {
if ((s->req->flags & (BF_AUTO_CONNECT|BF_OUT_EMPTY)) != BF_OUT_EMPTY) { if ((s->req->flags & (BF_AUTO_CONNECT|BF_OUT_EMPTY)) != BF_OUT_EMPTY) {
/* If we have an iohandler without a connect method, we immediately /* If we have an applet without a connect method, we immediately
* switch to the connected state, otherwise we perform a connection * switch to the connected state, otherwise we perform a connection
* request. * request.
*/ */
s->req->cons->state = SI_ST_REQ; /* new connection requested */ s->req->cons->state = SI_ST_REQ; /* new connection requested */
s->req->cons->conn_retries = s->be->conn_retries; s->req->cons->conn_retries = s->be->conn_retries;
if (unlikely(s->req->cons->iohandler && !s->req->cons->connect)) { if (unlikely(s->req->cons->applet.handler && !s->req->cons->connect)) {
s->req->cons->state = SI_ST_EST; /* connection established */ s->req->cons->state = SI_ST_EST; /* connection established */
s->rep->flags |= BF_READ_ATTACHED; /* producer is now attached */ s->rep->flags |= BF_READ_ATTACHED; /* producer is now attached */
s->req->wex = TICK_ETERNITY; s->req->wex = TICK_ETERNITY;
@ -1949,10 +1949,10 @@ struct task *process_session(struct task *t)
if ((s->fe->options & PR_O_CONTSTATS) && (s->flags & SN_BE_ASSIGNED)) if ((s->fe->options & PR_O_CONTSTATS) && (s->flags & SN_BE_ASSIGNED))
session_process_counters(s); session_process_counters(s);
if (s->rep->cons->state == SI_ST_EST && !s->rep->cons->iohandler) if (s->rep->cons->state == SI_ST_EST && !s->rep->cons->applet.handler)
s->rep->cons->update(s->rep->cons); s->rep->cons->update(s->rep->cons);
if (s->req->cons->state == SI_ST_EST && !s->req->cons->iohandler) if (s->req->cons->state == SI_ST_EST && !s->req->cons->applet.handler)
s->req->cons->update(s->req->cons); s->req->cons->update(s->req->cons);
s->req->flags &= ~(BF_READ_NULL|BF_READ_PARTIAL|BF_WRITE_NULL|BF_WRITE_PARTIAL|BF_READ_ATTACHED); s->req->flags &= ~(BF_READ_NULL|BF_READ_PARTIAL|BF_WRITE_NULL|BF_WRITE_PARTIAL|BF_READ_ATTACHED);
@ -1979,11 +1979,11 @@ struct task *process_session(struct task *t)
/* Call the stream interfaces' I/O handlers when embedded. /* Call the stream interfaces' I/O handlers when embedded.
* Note that this one may wake the task up again. * Note that this one may wake the task up again.
*/ */
if (s->req->cons->iohandler || s->rep->cons->iohandler) { if (s->req->cons->applet.handler || s->rep->cons->applet.handler) {
if (s->req->cons->iohandler) if (s->req->cons->applet.handler)
s->req->cons->iohandler(s->req->cons); s->req->cons->applet.handler->fct(s->req->cons);
if (s->rep->cons->iohandler) if (s->rep->cons->applet.handler)
s->rep->cons->iohandler(s->rep->cons); s->rep->cons->applet.handler->fct(s->rep->cons);
if (task_in_rq(t)) { if (task_in_rq(t)) {
/* If we woke up, we don't want to requeue the /* If we woke up, we don't want to requeue the
* task to the wait queue, but rather requeue * task to the wait queue, but rather requeue

View File

@ -1,7 +1,7 @@
/* /*
* Functions managing stream_interface structures * Functions managing stream_interface structures
* *
* Copyright 2000-2009 Willy Tarreau <w@1wt.eu> * Copyright 2000-2011 Willy Tarreau <w@1wt.eu>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -297,14 +297,13 @@ void stream_int_chk_snd(struct stream_interface *si)
task_wakeup(si->owner, TASK_WOKEN_IO); task_wakeup(si->owner, TASK_WOKEN_IO);
} }
/* Register a function to handle a stream_interface as part of the stream /* Register an applet to handle a stream_interface as part of the stream
* interface's owner task, which is returned. The SI will wake it up everytime * interface's owner task, which is returned. The SI will wake it up everytime
* it is solicited. The task's processing function must call the specified * it is solicited. The task's processing function must call the applet's
* function before returning. It must be deleted by the task handler using * function before returning. It must be deleted by the task handler using
* stream_int_unregister_handler(), possibly from withing the function itself. * stream_int_unregister_handler(), possibly from within the function itself.
*/ */
struct task *stream_int_register_handler(struct stream_interface *si, struct task *stream_int_register_handler(struct stream_interface *si, struct si_applet *app)
void (*fct)(struct stream_interface *))
{ {
DPRINTF(stderr, "registering handler %p for si %p (was %p)\n", fct, si, si->owner); DPRINTF(stderr, "registering handler %p for si %p (was %p)\n", fct, si, si->owner);
@ -314,7 +313,7 @@ struct task *stream_int_register_handler(struct stream_interface *si,
si->chk_rcv = stream_int_chk_rcv; si->chk_rcv = stream_int_chk_rcv;
si->chk_snd = stream_int_chk_snd; si->chk_snd = stream_int_chk_snd;
si->connect = NULL; si->connect = NULL;
si->iohandler = fct; si->applet.handler = app;
si->release = NULL; si->release = NULL;
si->flags |= SI_FL_WAIT_DATA; si->flags |= SI_FL_WAIT_DATA;
return si->owner; return si->owner;
@ -338,7 +337,7 @@ struct task *stream_int_register_handler_task(struct stream_interface *si,
si->chk_rcv = stream_int_chk_rcv; si->chk_rcv = stream_int_chk_rcv;
si->chk_snd = stream_int_chk_snd; si->chk_snd = stream_int_chk_snd;
si->connect = NULL; si->connect = NULL;
si->iohandler = NULL; /* not used when running as an external task */ si->applet.handler = NULL; /* not used when running as an external task */
si->release = NULL; si->release = NULL;
si->flags |= SI_FL_WAIT_DATA; si->flags |= SI_FL_WAIT_DATA;
@ -359,12 +358,12 @@ struct task *stream_int_register_handler_task(struct stream_interface *si,
*/ */
void stream_int_unregister_handler(struct stream_interface *si) void stream_int_unregister_handler(struct stream_interface *si)
{ {
if (!si->iohandler && si->owner) { if (!si->applet.handler && si->owner) {
/* external handler : kill the task */ /* external handler : kill the task */
task_delete(si->owner); task_delete(si->owner);
task_free(si->owner); task_free(si->owner);
} }
si->iohandler = NULL; si->applet.handler = NULL;
si->release = NULL; si->release = NULL;
si->owner = NULL; si->owner = NULL;
} }

View File

@ -1252,7 +1252,7 @@ void stream_sock_prepare_interface(struct stream_interface *si)
si->shutw = stream_sock_shutw; si->shutw = stream_sock_shutw;
si->chk_rcv = stream_sock_chk_rcv; si->chk_rcv = stream_sock_chk_rcv;
si->chk_snd = stream_sock_chk_snd; si->chk_snd = stream_sock_chk_snd;
si->iohandler = NULL; si->applet.handler = NULL;
} }