MEDIUM: spoe: Parse new "spoe-group" section in SPOE config file

For now, this section is only parsed. It should have the following format:

    spoe-group <grp-name>
      messages <msg-name> ...

And then SPOE groups must be referenced in spoe-agent section:

    spoe-agnt <name>
        ...
	groups <grp-name> ...

The purpose of these groups is to trigger messages sending from TCP or HTTP
rules, directly from HAProxy configuration, and not on specific event. This part
will be added in another patch.

It is important to note that a message belongs at most to a group.
This commit is contained in:
Christopher Faulet 2017-09-21 10:23:10 +02:00 committed by Willy Tarreau
parent 7ee8667c99
commit 11610f3b5a
3 changed files with 368 additions and 90 deletions

View File

@ -16,7 +16,8 @@ SUMMARY
2.1. SPOE scope
2.2. "spoe-agent" section
2.3. "spoe-message" section
2.4. Example
2.4. "spoe-group" section
2.5. Example
3. SPOP specification
3.1. Data types
3.2. Frames
@ -99,9 +100,8 @@ line, you completly disable the feature, including the parsing of sections
reserved to SPOE. This is also a way to keep the HAProxy configuration clean.
A SPOE configuration file must contains, at least, the SPOA configuration
("spoe-agent" section) and SPOE messages ("spoe-message" section) attached to
this agent. Unused messages (not reference in "spoe-agent" section) will be
ignored.
("spoe-agent" section) and SPOE messages/groups ("spoe-message" or "spoe-group"
sections) attached to this agent.
IMPORTANT : The configuration of a SPOE filter must be located in a dedicated
file. But the backend used by a SPOA must be declared in HAProxy configuration
@ -114,8 +114,8 @@ If you specify an engine name on the SPOE filter line, then you need to define
scope in the SPOE configuration with the same name. You can have several SPOE
scope in the same file. In each scope, you must define one and only one
"spoe-agent" section to configure the SPOA linked to your SPOE and several
"spoe-message" sections to describe messages sent to servers mananged by your
SPOA.
"spoe-message" and "spoe-group" sections to describe, respecively, messages and
group of messages sent to servers mananged by your SPOA.
A SPOE scope starts with this kind of line :
@ -132,6 +132,10 @@ scope ends when the file ends or when another scope is found.
...
spoe-message msg2
...
spoe-group grp1
...
spoe-group grp2
...
[my-second-engine]
...
@ -159,6 +163,7 @@ spoe-agent <name>
<name> is the name of the agent section.
following keywords are supported :
- groups
- maxconnrate
- maxerrrate
- max-frame-size
@ -173,6 +178,18 @@ spoe-agent <name>
- use-backend
groups <grp-name> ...
Declare the list of SPOE groups that an agent will handle.
Arguments :
<grp-name> is the name of a SPOE group.
Groups delcared here must be found in the same engine scope, else an error is
triggered during the configuration parsing. You can have many "groups" lines.
See also: "spoe-group" section.
maxconnrate <number>
Set the maximum number of connections per second to <number>. The SPOE will
stop to open new connections if the maximum is reached and will wait to
@ -407,7 +424,42 @@ event <name> [ { if | unless } <condition> ]
See section "Events & Messages" for more details about supported events.
See section 7 about ACL usage in the HAProxy Configuration Manual.
2.4. Example
2.4. "spoe-group" section
--------------------------
This section can be used to declare a group of SPOE messages. Unlike messages
referenced in a "spoe-agent" section, messages inside a group are not sent on a
specific event. The sending must be triggered by TCP or HTTP rules, from the
HAProxy configuration.
spoe-group <name>
Create a new SPOE group with the name <name>.
Arguments :
<name> is the name of the SPOE group.
Here you define a group of SPOE messages that can be referenced in a
"spoe-agent" section. Following keywords are supported :
- messages
See also: "spoe-agent" and "spoe-message" sections.
messages <msg-name> ...
Declare the list of SPOE messages belonging to the group.
Arguments :
<msg-name> is the name of a SPOE message.
Messages declared here must be found in the same engine scope, else an error
is triggered during the configuration parsing. Furthermore, a message belongs
at most to a group. You can have many "messages" lines.
See also: "spoe-message" section.
2.5. Example
-------------
Here is a simple but complete example that sends client-ip address to a ip

View File

@ -164,29 +164,50 @@ struct spoe_arg {
};
/* Used during the config parsing only because, when a SPOE agent section is
* parsed, messages can be undefined. */
struct spoe_msg_placeholder {
char *id; /* SPOE message placeholder id */
struct list list; /* Use to chain SPOE message placeholders */
* parsed, messages/groups can be undefined. */
struct spoe_placeholder {
char *id; /* SPOE placeholder id */
struct list list; /* Use to chain SPOE placeholders */
};
/* Describe a message that will be sent in a NOTIFY frame. A message has a name,
* an argument list (see above) and it is linked to a specific event. */
struct spoe_message {
char *id; /* SPOE message id */
unsigned int id_len; /* The message id length */
struct spoe_agent *agent; /* SPOE agent owning this SPOE message */
char *id; /* SPOE message id */
unsigned int id_len; /* The message id length */
struct spoe_agent *agent; /* SPOE agent owning this SPOE message */
struct spoe_group *group; /* SPOE group owning this SPOE message (can be NULL) */
struct {
char *file; /* file where the SPOE message appears */
int line; /* line where the SPOE message appears */
char *file; /* file where the SPOE message appears */
int line; /* line where the SPOE message appears */
} conf; /* config information */
unsigned int nargs; /* # of arguments */
struct list args; /* Arguments added when the SPOE messages is sent */
struct list list; /* Used to chain SPOE messages */
unsigned int nargs; /* # of arguments */
struct list args; /* Arguments added when the SPOE messages is sent */
struct list list; /* Used to chain SPOE messages */
struct list by_evt; /* By event list */
struct list by_grp; /* By group list */
struct list acls; /* ACL declared on this message */
struct acl_cond *cond; /* acl condition to meet */
enum spoe_event event; /* SPOE_EV_* */
struct list acls; /* ACL declared on this message */
struct acl_cond *cond; /* acl condition to meet */
enum spoe_event event; /* SPOE_EV_* */
};
/* Describe a group of messages that will be sent in a NOTIFY frame. A group has
* a name and a list of messages. It can be used by HAProxy, outside events
* processing, mainly in (tcp|http) rules. */
struct spoe_group {
char *id; /* SPOE group id */
struct spoe_agent *agent; /* SPOE agent owning this SPOE group */
struct {
char *file; /* file where the SPOE group appears */
int line; /* line where the SPOE group appears */
} conf; /* config information */
struct list phs; /* List of placeholders used during conf parsing */
struct list messages; /* List of SPOE messages that will be sent by this
* group */
struct list list; /* Used to chain SPOE groups */
};
/* Describe a SPOE agent. */
@ -217,9 +238,13 @@ struct spoe_agent {
unsigned int min_applets; /* Minimum # applets alive at a time */
unsigned int max_fpa; /* Maximum # of frames handled per applet at once */
struct list messages[SPOE_EV_EVENTS]; /* List of SPOE messages that will be sent
struct list events[SPOE_EV_EVENTS]; /* List of SPOE messages that will be sent
* for each supported events */
struct list groups; /* List of available SPOE groups */
struct list messages; /* list of all messages attached to this SPOE agent */
/* running info */
unsigned int frame_size; /* current maximum frame size, only used to encode messages */
unsigned int applets_act; /* # of applets alive at a time */
@ -250,7 +275,8 @@ struct spoe_context {
struct filter *filter; /* The SPOE filter */
struct stream *strm; /* The stream that should be offloaded */
struct list *messages; /* List of messages that will be sent during the stream processing */
struct list *events; /* List of messages that will be sent during the stream processing */
struct buffer *buffer; /* Buffer used to store a encoded messages */
struct buffer_wait buffer_wait; /* position in the list of ressources waiting for a buffer */
struct list list;

View File

@ -74,14 +74,16 @@ struct proxy *curproxy = NULL;
char *curengine = NULL;
/* SPOE agent used during the parsing */
struct spoe_agent *curagent = NULL;
/* SPOE message used during the parsing */
struct spoe_message *curmsg = NULL;
/* SPOE agent/group/message used during the parsing */
struct spoe_agent *curagent = NULL;
struct spoe_group *curgrp = NULL;
struct spoe_message *curmsg = NULL;
/* list of SPOE messages and placeholders used during the parsing */
struct list curmsgs;
struct list curmps;
struct list curgrps;
struct list curmphs;
struct list curgphs;
/* Pools used to allocate SPOE structs */
static struct pool_head *pool2_spoe_ctx = NULL;
@ -97,12 +99,12 @@ static void spoe_release_buffer(struct buffer **buf, struct buffer_wait *buffer_
* helper functions/globals
********************************************************************/
static void
spoe_release_msg_placeholder(struct spoe_msg_placeholder *mp)
spoe_release_placeholder(struct spoe_placeholder *ph)
{
if (!mp)
if (!ph)
return;
free(mp->id);
free(mp);
free(ph->id);
free(ph);
}
static void
@ -133,11 +135,21 @@ spoe_release_message(struct spoe_message *msg)
free(msg);
}
static void
spoe_release_group(struct spoe_group *grp)
{
if (!grp)
return;
free(grp->id);
free(grp->conf.file);
free(grp);
}
static void
spoe_release_agent(struct spoe_agent *agent)
{
struct spoe_message *msg, *back;
int i;
struct spoe_message *msg, *msgback;
struct spoe_group *grp, *grpback;
if (!agent)
return;
@ -146,11 +158,13 @@ spoe_release_agent(struct spoe_agent *agent)
free(agent->var_pfx);
free(agent->engine_id);
free(agent->var_on_error);
for (i = 0; i < SPOE_EV_EVENTS; ++i) {
list_for_each_entry_safe(msg, back, &agent->messages[i], list) {
LIST_DEL(&msg->list);
spoe_release_message(msg);
}
list_for_each_entry_safe(msg, msgback, &agent->messages, list) {
LIST_DEL(&msg->list);
spoe_release_message(msg);
}
list_for_each_entry_safe(grp, grpback, &agent->groups, list) {
LIST_DEL(&grp->list);
spoe_release_group(grp);
}
free(agent);
}
@ -2105,7 +2119,7 @@ spoe_encode_messages(struct stream *s, struct spoe_context *ctx,
}
/* Loop on messages */
list_for_each_entry(msg, messages, list) {
list_for_each_entry(msg, messages, by_evt) {
ctx->frag_ctx.curmsg = msg;
ctx->frag_ctx.curarg = NULL;
ctx->frag_ctx.curoff = UINT_MAX;
@ -2466,7 +2480,7 @@ spoe_process_event(struct stream *s, struct spoe_context *ctx,
dir = ((ev < SPOE_EV_ON_SERVER_SESS) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES);
if (LIST_ISEMPTY(&(ctx->messages[ev])))
if (LIST_ISEMPTY(&(ctx->events[ev])))
goto out;
if (ctx->state == SPOE_CTX_ST_ERROR)
@ -2511,7 +2525,7 @@ spoe_process_event(struct stream *s, struct spoe_context *ctx,
if (ctx->state == SPOE_CTX_ST_ENCODING_MSGS) {
if (!spoe_acquire_buffer(&ctx->buffer, &ctx->buffer_wait))
goto out;
ret = spoe_encode_messages(s, ctx, &(ctx->messages[ev]), dir);
ret = spoe_encode_messages(s, ctx, &(ctx->events[ev]), dir);
if (ret < 0)
goto error;
if (!ret)
@ -2640,7 +2654,7 @@ spoe_create_context(struct filter *filter)
ctx->state = SPOE_CTX_ST_NONE;
ctx->status_code = SPOE_CTX_ERR_NONE;
ctx->flags = 0;
ctx->messages = conf->agent->messages;
ctx->events = conf->agent->events;
ctx->buffer = &buf_empty;
LIST_INIT(&ctx->buffer_wait.list);
ctx->buffer_wait.target = ctx;
@ -2834,22 +2848,22 @@ spoe_start(struct stream *s, struct filter *filter)
ctx->state = SPOE_CTX_ST_READY;
filter->ctx = ctx;
if (!LIST_ISEMPTY(&ctx->messages[SPOE_EV_ON_TCP_REQ_FE]))
if (!LIST_ISEMPTY(&ctx->events[SPOE_EV_ON_TCP_REQ_FE]))
filter->pre_analyzers |= AN_REQ_INSPECT_FE;
if (!LIST_ISEMPTY(&ctx->messages[SPOE_EV_ON_TCP_REQ_BE]))
if (!LIST_ISEMPTY(&ctx->events[SPOE_EV_ON_TCP_REQ_BE]))
filter->pre_analyzers |= AN_REQ_INSPECT_BE;
if (!LIST_ISEMPTY(&ctx->messages[SPOE_EV_ON_TCP_RSP]))
if (!LIST_ISEMPTY(&ctx->events[SPOE_EV_ON_TCP_RSP]))
filter->pre_analyzers |= AN_RES_INSPECT;
if (!LIST_ISEMPTY(&ctx->messages[SPOE_EV_ON_HTTP_REQ_FE]))
if (!LIST_ISEMPTY(&ctx->events[SPOE_EV_ON_HTTP_REQ_FE]))
filter->pre_analyzers |= AN_REQ_HTTP_PROCESS_FE;
if (!LIST_ISEMPTY(&ctx->messages[SPOE_EV_ON_HTTP_REQ_BE]))
if (!LIST_ISEMPTY(&ctx->events[SPOE_EV_ON_HTTP_REQ_BE]))
filter->pre_analyzers |= AN_REQ_HTTP_PROCESS_BE;
if (!LIST_ISEMPTY(&ctx->messages[SPOE_EV_ON_HTTP_RSP]))
if (!LIST_ISEMPTY(&ctx->events[SPOE_EV_ON_HTTP_RSP]))
filter->pre_analyzers |= AN_RES_HTTP_PROCESS_FE;
return 1;
@ -3083,7 +3097,9 @@ cfg_parse_spoe_agent(const char *file, int linenum, char **args, int kwm)
curagent->max_fpa = 100;
for (i = 0; i < SPOE_EV_EVENTS; ++i)
LIST_INIT(&curagent->messages[i]);
LIST_INIT(&curagent->events[i]);
LIST_INIT(&curagent->groups);
LIST_INIT(&curagent->messages);
curagent->frame_size = curagent->max_frame_size;
curagent->applets_act = 0;
@ -3109,24 +3125,48 @@ cfg_parse_spoe_agent(const char *file, int linenum, char **args, int kwm)
else if (!strcmp(args[0], "messages")) {
int cur_arg = 1;
while (*args[cur_arg]) {
struct spoe_msg_placeholder *mp = NULL;
struct spoe_placeholder *ph = NULL;
list_for_each_entry(mp, &curmps, list) {
if (!strcmp(mp->id, args[cur_arg])) {
Alert("parsing [%s:%d]: spoe-message message '%s' already declared.\n",
list_for_each_entry(ph, &curmphs, list) {
if (!strcmp(ph->id, args[cur_arg])) {
Alert("parsing [%s:%d]: spoe-message '%s' already used.\n",
file, linenum, args[cur_arg]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
}
if ((mp = calloc(1, sizeof(*mp))) == NULL) {
if ((ph = calloc(1, sizeof(*ph))) == NULL) {
Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
err_code |= ERR_ALERT | ERR_ABORT;
goto out;
}
mp->id = strdup(args[cur_arg]);
LIST_ADDQ(&curmps, &mp->list);
ph->id = strdup(args[cur_arg]);
LIST_ADDQ(&curmphs, &ph->list);
cur_arg++;
}
}
else if (!strcmp(args[0], "groups")) {
int cur_arg = 1;
while (*args[cur_arg]) {
struct spoe_placeholder *ph = NULL;
list_for_each_entry(ph, &curgphs, list) {
if (!strcmp(ph->id, args[cur_arg])) {
Alert("parsing [%s:%d]: spoe-group '%s' already used.\n",
file, linenum, args[cur_arg]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
}
if ((ph = calloc(1, sizeof(*ph))) == NULL) {
Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
err_code |= ERR_ALERT | ERR_ABORT;
goto out;
}
ph->id = strdup(args[cur_arg]);
LIST_ADDQ(&curgphs, &ph->list);
cur_arg++;
}
}
@ -3323,6 +3363,94 @@ cfg_parse_spoe_agent(const char *file, int linenum, char **args, int kwm)
out:
return err_code;
}
static int
cfg_parse_spoe_group(const char *file, int linenum, char **args, int kwm)
{
struct spoe_group *grp;
const char *err;
int err_code = 0;
if ((cfg_scope == NULL && curengine != NULL) ||
(cfg_scope != NULL && curengine == NULL) ||
(curengine != NULL && cfg_scope != NULL && strcmp(curengine, cfg_scope)))
goto out;
if (!strcmp(args[0], "spoe-group")) { /* new spoe-group section */
if (!*args[1]) {
Alert("parsing [%s:%d] : missing name for spoe-group section.\n",
file, linenum);
err_code |= ERR_ALERT | ERR_ABORT;
goto out;
}
if (alertif_too_many_args(1, file, linenum, args, &err_code)) {
err_code |= ERR_ABORT;
goto out;
}
err = invalid_char(args[1]);
if (err) {
Alert("parsing [%s:%d] : character '%c' is not permitted in '%s' name '%s'.\n",
file, linenum, *err, args[0], args[1]);
err_code |= ERR_ALERT | ERR_ABORT;
goto out;
}
list_for_each_entry(grp, &curgrps, list) {
if (!strcmp(grp->id, args[1])) {
Alert("parsing [%s:%d]: spoe-group section '%s' has the same"
" name as another one declared at %s:%d.\n",
file, linenum, args[1], grp->conf.file, grp->conf.line);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
}
if ((curgrp = calloc(1, sizeof(*curgrp))) == NULL) {
Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
err_code |= ERR_ALERT | ERR_ABORT;
goto out;
}
curgrp->id = strdup(args[1]);
curgrp->conf.file = strdup(file);
curgrp->conf.line = linenum;
LIST_INIT(&curgrp->phs);
LIST_INIT(&curgrp->messages);
LIST_ADDQ(&curgrps, &curgrp->list);
}
else if (!strcmp(args[0], "messages")) {
int cur_arg = 1;
while (*args[cur_arg]) {
struct spoe_placeholder *ph = NULL;
list_for_each_entry(ph, &curgrp->phs, list) {
if (!strcmp(ph->id, args[cur_arg])) {
Alert("parsing [%s:%d]: spoe-message '%s' already used.\n",
file, linenum, args[cur_arg]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
}
if ((ph = calloc(1, sizeof(*ph))) == NULL) {
Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
err_code |= ERR_ALERT | ERR_ABORT;
goto out;
}
ph->id = strdup(args[cur_arg]);
LIST_ADDQ(&curgrp->phs, &ph->list);
cur_arg++;
}
}
else if (*args[0]) {
Alert("parsing [%s:%d] : unknown keyword '%s' in spoe-group section.\n",
file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
out:
return err_code;
}
static int
cfg_parse_spoe_message(const char *file, int linenum, char **args, int kwm)
@ -3382,6 +3510,8 @@ cfg_parse_spoe_message(const char *file, int linenum, char **args, int kwm)
curmsg->nargs = 0;
LIST_INIT(&curmsg->args);
LIST_INIT(&curmsg->acls);
LIST_INIT(&curmsg->by_evt);
LIST_INIT(&curmsg->by_grp);
LIST_ADDQ(&curmsgs, &curmsg->list);
}
else if (!strcmp(args[0], "args")) {
@ -3518,7 +3648,8 @@ parse_spoe_flt(char **args, int *cur_arg, struct proxy *px,
struct list backup_sections;
struct spoe_config *conf;
struct spoe_message *msg, *msgback;
struct spoe_msg_placeholder *mp, *mpback;
struct spoe_group *grp, *grpback;
struct spoe_placeholder *ph, *phback;
char *file = NULL, *engine = NULL;
int ret, pos = *cur_arg + 1;
@ -3561,7 +3692,8 @@ parse_spoe_flt(char **args, int *cur_arg, struct proxy *px,
/* backup sections and register SPOE sections */
LIST_INIT(&backup_sections);
cfg_backup_sections(&backup_sections);
cfg_register_section("spoe-agent", cfg_parse_spoe_agent, NULL);
cfg_register_section("spoe-agent", cfg_parse_spoe_agent, NULL);
cfg_register_section("spoe-group", cfg_parse_spoe_group, NULL);
cfg_register_section("spoe-message", cfg_parse_spoe_message, NULL);
/* Parse SPOE filter configuration file */
@ -3569,6 +3701,10 @@ parse_spoe_flt(char **args, int *cur_arg, struct proxy *px,
curproxy = px;
curagent = NULL;
curmsg = NULL;
LIST_INIT(&curmsgs);
LIST_INIT(&curgrps);
LIST_INIT(&curmphs);
LIST_INIT(&curgphs);
ret = readcfgfile(file);
curproxy = NULL;
@ -3622,18 +3758,20 @@ parse_spoe_flt(char **args, int *cur_arg, struct proxy *px,
if (curagent->engine_id == NULL)
curagent->engine_id = generate_pseudo_uuid();
if (LIST_ISEMPTY(&curmps)) {
Warning("Proxy '%s': No message used by SPOE agent '%s' declared at %s:%d.\n",
if (LIST_ISEMPTY(&curmphs) && LIST_ISEMPTY(&curgphs)) {
Warning("Proxy '%s': No message/group used by SPOE agent '%s' declared at %s:%d.\n",
px->id, curagent->id, curagent->conf.file, curagent->conf.line);
goto finish;
}
list_for_each_entry_safe(mp, mpback, &curmps, list) {
list_for_each_entry_safe(msg, msgback, &curmsgs, list) {
/* Replace placeholders by the corresponding messages for the SPOE
* agent */
list_for_each_entry(ph, &curmphs, list) {
list_for_each_entry(msg, &curmsgs, list) {
struct spoe_arg *arg;
unsigned int where;
if (!strcmp(msg->id, mp->id)) {
if (!strcmp(msg->id, ph->id)) {
if ((px->cap & (PR_CAP_FE|PR_CAP_BE)) == (PR_CAP_FE|PR_CAP_BE)) {
if (msg->event == SPOE_EV_ON_TCP_REQ_BE)
msg->event = SPOE_EV_ON_TCP_REQ_FE;
@ -3645,12 +3783,12 @@ parse_spoe_flt(char **args, int *cur_arg, struct proxy *px,
msg->event == SPOE_EV_ON_HTTP_REQ_FE)) {
Warning("Proxy '%s': frontend event used on a backend proxy at %s:%d.\n",
px->id, msg->conf.file, msg->conf.line);
goto next;
goto next_mph;
}
if (msg->event == SPOE_EV_NONE) {
Warning("Proxy '%s': Ignore SPOE message without event at %s:%d.\n",
px->id, msg->conf.file, msg->conf.line);
goto next;
goto next_mph;
}
where = 0;
@ -3711,37 +3849,93 @@ parse_spoe_flt(char **args, int *cur_arg, struct proxy *px,
px->id, msg->conf.file, msg->conf.line,
sample_ckp_names(arg->expr->fetch->use),
sample_ckp_names(where));
goto next;
goto next_mph;
}
}
msg->agent = curagent;
LIST_DEL(&msg->list);
LIST_ADDQ(&curagent->messages[msg->event], &msg->list);
goto next;
LIST_ADDQ(&curagent->events[msg->event], &msg->by_evt);
goto next_mph;
}
}
memprintf(err, "SPOE agent '%s' try to use undefined SPOE message '%s' at %s:%d",
curagent->id, mp->id, curagent->conf.file, curagent->conf.line);
curagent->id, ph->id, curagent->conf.file, curagent->conf.line);
goto error;
next:
next_mph:
continue;
}
finish:
conf->id = strdup(engine ? engine : curagent->id);
conf->agent = curagent;
list_for_each_entry_safe(mp, mpback, &curmps, list) {
LIST_DEL(&mp->list);
spoe_release_msg_placeholder(mp);
}
list_for_each_entry_safe(msg, msgback, &curmsgs, list) {
Warning("Proxy '%s': Ignore unused SPOE messages '%s' declared at %s:%d.\n",
px->id, msg->id, msg->conf.file, msg->conf.line);
LIST_DEL(&msg->list);
spoe_release_message(msg);
/* Replace placeholders by the corresponding groups for the SPOE
* agent */
list_for_each_entry(ph, &curgphs, list) {
list_for_each_entry_safe(grp, grpback, &curgrps, list) {
if (!strcmp(grp->id, ph->id)) {
grp->agent = curagent;
LIST_DEL(&grp->list);
LIST_ADDQ(&curagent->groups, &grp->list);
goto next_aph;
}
}
memprintf(err, "SPOE agent '%s' try to use undefined SPOE group '%s' at %s:%d",
curagent->id, ph->id, curagent->conf.file, curagent->conf.line);
goto error;
next_aph:
continue;
}
/* Replace placeholders by the corresponding message for each SPOE
* group of the SPOE agent */
list_for_each_entry(grp, &curagent->groups, list) {
list_for_each_entry_safe(ph, phback, &grp->phs, list) {
list_for_each_entry(msg, &curmsgs, list) {
if (!strcmp(msg->id, ph->id)) {
if (msg->group != NULL) {
memprintf(err, "SPOE message '%s' already belongs to "
"the SPOE group '%s' declare at %s:%d",
msg->id, msg->group->id,
msg->group->conf.file,
msg->group->conf.line);
goto error;
}
/* Scope for arguments are not checked for now. We will check
* them only if a rule use the corresponding SPOE group. */
msg->agent = curagent;
msg->group = grp;
LIST_DEL(&ph->list);
LIST_ADDQ(&grp->messages, &msg->by_grp);
goto next_mph_grp;
}
}
memprintf(err, "SPOE group '%s' try to use undefined SPOE message '%s' at %s:%d",
grp->id, ph->id, curagent->conf.file, curagent->conf.line);
goto error;
next_mph_grp:
continue;
}
}
finish:
/* move curmsgs to the agent message list */
curmsgs.n->p = &curagent->messages;
curmsgs.p->n = &curagent->messages;
curagent->messages = curmsgs;
LIST_INIT(&curmsgs);
conf->id = strdup(engine ? engine : curagent->id);
conf->agent = curagent;
list_for_each_entry_safe(ph, phback, &curmphs, list) {
LIST_DEL(&ph->list);
spoe_release_placeholder(ph);
}
list_for_each_entry_safe(ph, phback, &curgphs, list) {
LIST_DEL(&ph->list);
spoe_release_placeholder(ph);
}
list_for_each_entry_safe(grp, grpback, &curgrps, list) {
LIST_DEL(&grp->list);
spoe_release_group(grp);
}
*cur_arg = pos;
fconf->id = spoe_filter_id;
fconf->ops = &spoe_ops;
@ -3750,9 +3944,17 @@ parse_spoe_flt(char **args, int *cur_arg, struct proxy *px,
error:
spoe_release_agent(curagent);
list_for_each_entry_safe(mp, mpback, &curmps, list) {
LIST_DEL(&mp->list);
spoe_release_msg_placeholder(mp);
list_for_each_entry_safe(ph, phback, &curmphs, list) {
LIST_DEL(&ph->list);
spoe_release_placeholder(ph);
}
list_for_each_entry_safe(ph, phback, &curgphs, list) {
LIST_DEL(&ph->list);
spoe_release_placeholder(ph);
}
list_for_each_entry_safe(grp, grpback, &curgrps, list) {
LIST_DEL(&grp->list);
spoe_release_group(grp);
}
list_for_each_entry_safe(msg, msgback, &curmsgs, list) {
LIST_DEL(&msg->list);
@ -3775,8 +3977,6 @@ static void __spoe_init(void)
{
flt_register_keywords(&flt_kws);
LIST_INIT(&curmsgs);
LIST_INIT(&curmps);
pool2_spoe_ctx = create_pool("spoe_ctx", sizeof(struct spoe_context), MEM_F_SHARED);
pool2_spoe_appctx = create_pool("spoe_appctx", sizeof(struct spoe_appctx), MEM_F_SHARED);
}