/* Runs the polling loop */
void run_poll_loop()
{
int next;
tv_update_date(0,1);
while (1) {
/* check if we caught some signals and process them */
signal_process_queue();
/* Check if we can expire some tasks */
wake_expired_tasks(&next);
/* Process a few tasks */
process_runnable_tasks(&next);
/* stop when there's nothing left to do */
if (jobs == 0)
break;
/* The poller will ensure it returns around */
cur_poller.poll(&cur_poller, next);
fd_process_spec_events();
}
}
/* Add the various callbacks. Right now the transport layer is present
* but not initialized. Also note we need to be careful as the stream
* int is not initialized yet.
*/
conn_prepare(s->si[0].conn, &sess_conn_cb, l->proto, l->xprt, s);
fdtab[cfd].owner = s->si[0].conn; /*fd 对应的 owner 为 connection 结构*/
fdtab[cfd].iocb = conn_fd_handler;
conn_data_want_recv(s->si[0].conn);
if (conn_xprt_init(s->si[0].conn) < 0)
goto out_free_task;
...
si_takeover_conn(&s->si[0], l->proto, l->xprt);
...
t->process = l->handler;
...
if (p->accept && (ret = p->accept(s)) <= 0) {
/* Either we had an unrecoverable error (<0) or work is
* finished (=0, eg: monitoring), in both situations,
* we can release everything and close.
*/
goto out_free_rep_buf;
}
...
task_wakeup(t, TASK_WOKEN_INIT);
int conn_fd_handler(int fd)
{
struct connection *conn = fdtab[fd].owner;
...
if ((fdtab[fd].ev & (FD_POLL_IN | FD_POLL_HUP | FD_POLL_ERR)) &&
conn->xprt &&
!(conn->flags & (CO_FL_WAIT_RD|CO_FL_WAIT_ROOM|CO_FL_ERROR|CO_FL_HANDSHAKE))) {
/* force detection of a flag change : it's impossible to have both
* CONNECTED and WAIT_CONN so we're certain to trigger a change.
*/
flags = CO_FL_WAIT_L4_CONN | CO_FL_CONNECTED;
conn->data->recv(conn);
}
...
}
/* The acl will be linked to from the proxy where it is declared */
struct acl {
struct list list; /* chaining */
char *name; /* acl name */
struct list expr; /* list of acl_exprs */
int cache_idx; /* ACL index in cache */
unsigned int requires; /* or'ed bit mask of all acl_expr's ACL_USE_* */
};
rule 应该是 action + condition 组成
有些动作自身可能也需要记录一些信息。不同的 rule 对应动作的信息可能不同,比如 reqirep 等
block rules 的动作比较单一, condition 满足之后处理结果均相同
condition,完成 rule 检测的判断条件 对应数据结构: struct acl_cond
struct acl_cond {
struct list list; /* Some specific tests may use multiple conditions */
struct list suites; /* list of acl_term_suites */
int pol; /* polarity: ACL_COND_IF / ACL_COND_UNLESS */
unsigned int requires; /* or'ed bit mask of all acl's ACL_USE_* */
const char *file; /* config file where the condition is declared */
int line; /* line in the config file where the condition is declared */
};
condition 包含多个 ACL 组。组的分割逻辑是逻辑或(|| 或者 or),即 struct list suites 的成员,组的数据结构 struct acl_term_suite
struct acl_term_suite {
struct list list; /* chaining of term suites */
struct list terms; /* list of acl_terms */
};
该数据结构可以包含多个 ACL,以及每个 ACL 可能的一个取反标识 '!'
所有表达式中相邻的 ACL 且其逻辑关系为逻辑与(&&) 的构成一个 ACL 组
比如 if acl1 !acl2 or acl3 acl4,则构成两个 acl_term_suite,分别是 acl1 !acl2 和 acl3 acl4
每个 ACL 及其可能的取反标记对应的数据结构: struct acl_term
struct acl_term {
struct list list; /* chaining */
struct acl *acl; /* acl pointed to by this term */
int neg; /* 1 if the ACL result must be negated */
};
一个 ACL 包含多个 expr
3. rule 的执行
概括起来很简单,执行判断条件。符合条件,然后执行对应动作。
下面是 rspadd 的示例代码:
123456789101112131415
/* add response headers from the rule sets in the same order */
list_for_each_entry(wl, &rule_set->rsp_add, list) {
if (txn->status < 200)
break;
if (wl->cond) {
int ret = acl_exec_cond(wl->cond, px, t, txn, SMP_OPT_DIR_RES|SMP_OPT_FINAL);
ret = acl_pass(ret);
if (((struct acl_cond *)wl->cond)->pol == ACL_COND_UNLESS)
ret = !ret;
if (!ret)
continue;
}
if (unlikely(http_header_add_tail(&txn->rsp, &txn->hdr_idx, wl->s) < 0))
goto return_bad_resp;
}