blob: eb0a2521d970ee5edd380d3d64e5304958a80db6 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
Willy Tarreau81f9aa32010-06-01 17:45:26 +02002 * Session management functions.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003 *
Willy Tarreau81f9aa32010-06-01 17:45:26 +02004 * Copyright 2000-2010 Willy Tarreau <w@1wt.eu>
Willy Tarreaubaaee002006-06-26 02:48:02 +02005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <stdlib.h>
Willy Tarreau81f9aa32010-06-01 17:45:26 +020014#include <unistd.h>
15#include <fcntl.h>
Willy Tarreaue3ba5f02006-06-29 18:54:54 +020016
17#include <common/config.h>
Willy Tarreau7c669d72008-06-20 15:04:11 +020018#include <common/debug.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020019#include <common/memory.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020020
Willy Tarreaubaaee002006-06-26 02:48:02 +020021#include <types/capture.h>
Willy Tarreau55a8d0e2008-11-30 18:47:21 +010022#include <types/global.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020023
Willy Tarreau1d0dfb12009-07-07 15:10:31 +020024#include <proto/acl.h>
Willy Tarreau55a8d0e2008-11-30 18:47:21 +010025#include <proto/backend.h>
Willy Tarreau7341d942007-05-13 19:56:02 +020026#include <proto/buffers.h>
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +010027#include <proto/checks.h>
Willy Tarreau5ca791d2009-08-16 19:06:42 +020028#include <proto/dumpstats.h>
Willy Tarreau91c43d72010-06-20 11:19:22 +020029#include <proto/freq_ctr.h>
Willy Tarreau3041b9f2010-10-15 23:25:20 +020030#include <proto/frontend.h>
Willy Tarreau8d5d7f22007-01-21 19:16:41 +010031#include <proto/hdr_idx.h>
Willy Tarreau332f8bf2007-05-13 21:36:56 +020032#include <proto/log.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020033#include <proto/session.h>
Willy Tarreau3eba98a2009-01-25 13:56:13 +010034#include <proto/pipe.h>
Willy Tarreau55a8d0e2008-11-30 18:47:21 +010035#include <proto/proto_http.h>
36#include <proto/proto_tcp.h>
Willy Tarreau1d0dfb12009-07-07 15:10:31 +020037#include <proto/proxy.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020038#include <proto/queue.h>
Willy Tarreau7f062c42009-03-05 18:43:00 +010039#include <proto/server.h>
Emeric Brun1d33b292010-01-04 15:47:17 +010040#include <proto/stick_table.h>
Willy Tarreau55a8d0e2008-11-30 18:47:21 +010041#include <proto/stream_interface.h>
42#include <proto/stream_sock.h>
43#include <proto/task.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020044
Willy Tarreauc6ca1a02007-05-13 19:43:47 +020045struct pool_head *pool2_session;
Willy Tarreauf54f8bd2008-11-23 19:53:55 +010046struct list sessions;
Willy Tarreaubaaee002006-06-26 02:48:02 +020047
Willy Tarreau81f9aa32010-06-01 17:45:26 +020048/* This function is called from the protocol layer accept() in order to instanciate
49 * a new session on behalf of a given listener and frontend. It returns a positive
Willy Tarreauabe8ea52010-11-11 10:56:04 +010050 * value upon success, 0 if the connection can be ignored, or a negative value upon
51 * critical failure. The accepted file descriptor is closed if we return <= 0.
Willy Tarreau81f9aa32010-06-01 17:45:26 +020052 */
53int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr)
54{
55 struct proxy *p = l->frontend;
56 struct session *s;
57 struct http_txn *txn;
58 struct task *t;
Willy Tarreauabe8ea52010-11-11 10:56:04 +010059 int ret;
60
61
62 ret = -1; /* assume unrecoverable error by default */
Willy Tarreau81f9aa32010-06-01 17:45:26 +020063
Willy Tarreaufffe1322010-11-11 09:48:16 +010064 if (unlikely((s = pool_alloc2(pool2_session)) == NULL))
Willy Tarreau81f9aa32010-06-01 17:45:26 +020065 goto out_close;
Willy Tarreau81f9aa32010-06-01 17:45:26 +020066
67 /* minimum session initialization required for monitor mode below */
68 s->flags = 0;
69 s->logs.logwait = p->to_log;
Willy Tarreau56123282010-08-06 19:06:56 +020070 s->stkctr1_entry = NULL;
71 s->stkctr2_entry = NULL;
72 s->stkctr1_table = NULL;
73 s->stkctr2_table = NULL;
Willy Tarreau81f9aa32010-06-01 17:45:26 +020074
75 /* if this session comes from a known monitoring system, we want to ignore
76 * it as soon as possible, which means closing it immediately for TCP, but
77 * cleanly.
78 */
79 if (unlikely((l->options & LI_O_CHK_MONNET) &&
80 addr->ss_family == AF_INET &&
81 (((struct sockaddr_in *)addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr)) {
82 if (p->mode == PR_MODE_TCP) {
Willy Tarreauabe8ea52010-11-11 10:56:04 +010083 ret = 0; /* successful termination */
84 goto out_free_session;
Willy Tarreau81f9aa32010-06-01 17:45:26 +020085 }
86 s->flags |= SN_MONITOR;
87 s->logs.logwait = 0;
88 }
89
Willy Tarreauabe8ea52010-11-11 10:56:04 +010090 if (unlikely((t = task_new()) == NULL))
91 goto out_free_session;
92
Willy Tarreau81f9aa32010-06-01 17:45:26 +020093 /* OK, we're keeping the session, so let's properly initialize the session */
94 LIST_ADDQ(&sessions, &s->list);
95 LIST_INIT(&s->back_refs);
96
Willy Tarreau81f9aa32010-06-01 17:45:26 +020097 s->term_trace = 0;
Willy Tarreau957c0a52011-03-03 17:42:23 +010098 s->si[0].addr.c.from = *addr;
Willy Tarreau81f9aa32010-06-01 17:45:26 +020099 s->logs.accept_date = date; /* user-visible date for logging */
100 s->logs.tv_accept = now; /* corrected date for internal use */
101 s->uniq_id = totalconn;
Willy Tarreau24dcaf32010-06-05 10:49:41 +0200102 p->feconn++; /* beconn will be increased once assigned */
103
Willy Tarreaub36b4242010-06-04 20:59:39 +0200104 proxy_inc_fe_conn_ctr(l, p); /* note: cum_beconn will be increased once assigned */
Willy Tarreau81f9aa32010-06-01 17:45:26 +0200105
106 t->process = l->handler;
107 t->context = s;
108 t->nice = l->nice;
109 t->expire = TICK_ETERNITY;
110
111 s->task = t;
112 s->listener = l;
113
114 /* Note: initially, the session's backend points to the frontend.
115 * This changes later when switching rules are executed or
116 * when the default backend is assigned.
117 */
118 s->be = s->fe = p;
119 s->req = s->rep = NULL; /* will be allocated later */
120
121 /* now evaluate the tcp-request layer4 rules. Since we expect to be able
122 * to abort right here as soon as possible, we check the rules before
123 * even initializing the stream interfaces.
124 */
125 if ((l->options & LI_O_TCP_RULES) && !tcp_exec_req_rules(s)) {
Willy Tarreau81f9aa32010-06-01 17:45:26 +0200126 /* let's do a no-linger now to close with a single RST. */
127 setsockopt(cfd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
Willy Tarreauabe8ea52010-11-11 10:56:04 +0100128 ret = 0; /* successful termination */
129 goto out_free_task;
Willy Tarreau81f9aa32010-06-01 17:45:26 +0200130 }
131
Willy Tarreaub36b4242010-06-04 20:59:39 +0200132 /* This session was accepted, count it now */
Willy Tarreau24dcaf32010-06-05 10:49:41 +0200133 if (p->feconn > p->counters.feconn_max)
134 p->counters.feconn_max = p->feconn;
Willy Tarreauabe8ea52010-11-11 10:56:04 +0100135
Willy Tarreaub36b4242010-06-04 20:59:39 +0200136 proxy_inc_fe_sess_ctr(l, p);
Willy Tarreau56123282010-08-06 19:06:56 +0200137 if (s->stkctr1_entry) {
Willy Tarreau91c43d72010-06-20 11:19:22 +0200138 void *ptr;
139
Willy Tarreau56123282010-08-06 19:06:56 +0200140 ptr = stktable_data_ptr(s->stkctr1_table, s->stkctr1_entry, STKTABLE_DT_SESS_CNT);
Willy Tarreauf4d17d92010-06-18 22:10:12 +0200141 if (ptr)
142 stktable_data_cast(ptr, sess_cnt)++;
Willy Tarreau91c43d72010-06-20 11:19:22 +0200143
Willy Tarreau56123282010-08-06 19:06:56 +0200144 ptr = stktable_data_ptr(s->stkctr1_table, s->stkctr1_entry, STKTABLE_DT_SESS_RATE);
Willy Tarreau91c43d72010-06-20 11:19:22 +0200145 if (ptr)
146 update_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
Willy Tarreau56123282010-08-06 19:06:56 +0200147 s->stkctr1_table->data_arg[STKTABLE_DT_SESS_RATE].u, 1);
Willy Tarreauf4d17d92010-06-18 22:10:12 +0200148 }
Willy Tarreaub36b4242010-06-04 20:59:39 +0200149
Willy Tarreau56123282010-08-06 19:06:56 +0200150 if (s->stkctr2_entry) {
Willy Tarreau9e9879a2010-08-06 15:25:22 +0200151 void *ptr;
152
Willy Tarreau56123282010-08-06 19:06:56 +0200153 ptr = stktable_data_ptr(s->stkctr2_table, s->stkctr2_entry, STKTABLE_DT_SESS_CNT);
Willy Tarreau9e9879a2010-08-06 15:25:22 +0200154 if (ptr)
155 stktable_data_cast(ptr, sess_cnt)++;
156
Willy Tarreau56123282010-08-06 19:06:56 +0200157 ptr = stktable_data_ptr(s->stkctr2_table, s->stkctr2_entry, STKTABLE_DT_SESS_RATE);
Willy Tarreau9e9879a2010-08-06 15:25:22 +0200158 if (ptr)
159 update_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
Willy Tarreau56123282010-08-06 19:06:56 +0200160 s->stkctr2_table->data_arg[STKTABLE_DT_SESS_RATE].u, 1);
Willy Tarreau9e9879a2010-08-06 15:25:22 +0200161 }
162
Willy Tarreau81f9aa32010-06-01 17:45:26 +0200163 /* this part should be common with other protocols */
164 s->si[0].fd = cfd;
165 s->si[0].owner = t;
166 s->si[0].state = s->si[0].prev_state = SI_ST_EST;
167 s->si[0].err_type = SI_ET_NONE;
168 s->si[0].err_loc = NULL;
169 s->si[0].connect = NULL;
Willy Tarreau0bd05ea2010-07-02 11:18:03 +0200170 s->si[0].release = NULL;
Willy Tarreauac825402011-03-04 22:04:29 +0100171 s->si[0].target.type = TARG_TYPE_NONE;
172 s->si[0].target.ptr.v = NULL;
Willy Tarreau81f9aa32010-06-01 17:45:26 +0200173 s->si[0].exp = TICK_ETERNITY;
174 s->si[0].flags = SI_FL_NONE;
175
176 if (likely(s->fe->options2 & PR_O2_INDEPSTR))
177 s->si[0].flags |= SI_FL_INDEP_STR;
178
179 if (addr->ss_family == AF_INET || addr->ss_family == AF_INET6)
180 s->si[0].flags = SI_FL_CAP_SPLTCP; /* TCP/TCPv6 splicing possible */
181
182 /* add the various callbacks */
183 stream_sock_prepare_interface(&s->si[0]);
184
185 /* pre-initialize the other side's stream interface to an INIT state. The
186 * callbacks will be initialized before attempting to connect.
187 */
188 s->si[1].fd = -1; /* just to help with debugging */
189 s->si[1].owner = t;
190 s->si[1].state = s->si[1].prev_state = SI_ST_INI;
191 s->si[1].err_type = SI_ET_NONE;
192 s->si[1].err_loc = NULL;
193 s->si[1].connect = NULL;
Willy Tarreau0bd05ea2010-07-02 11:18:03 +0200194 s->si[1].release = NULL;
Willy Tarreauac825402011-03-04 22:04:29 +0100195 s->si[1].target.type = TARG_TYPE_NONE;
196 s->si[1].target.ptr.v = NULL;
Willy Tarreau81f9aa32010-06-01 17:45:26 +0200197 s->si[1].shutr = stream_int_shutr;
198 s->si[1].shutw = stream_int_shutw;
199 s->si[1].exp = TICK_ETERNITY;
200 s->si[1].flags = SI_FL_NONE;
201
202 if (likely(s->fe->options2 & PR_O2_INDEPSTR))
203 s->si[1].flags |= SI_FL_INDEP_STR;
204
205 s->srv = s->prev_srv = s->srv_conn = NULL;
206 s->pend_pos = NULL;
207
208 /* init store persistence */
209 s->store_count = 0;
210
211 /* Adjust some socket options */
Willy Tarreaufffe1322010-11-11 09:48:16 +0100212 if (unlikely(fcntl(cfd, F_SETFL, O_NONBLOCK) == -1))
Willy Tarreau81f9aa32010-06-01 17:45:26 +0200213 goto out_free_task;
Willy Tarreau81f9aa32010-06-01 17:45:26 +0200214
215 txn = &s->txn;
216 /* Those variables will be checked and freed if non-NULL in
217 * session.c:session_free(). It is important that they are
218 * properly initialized.
219 */
220 txn->sessid = NULL;
221 txn->srv_cookie = NULL;
222 txn->cli_cookie = NULL;
223 txn->uri = NULL;
224 txn->req.cap = NULL;
225 txn->rsp.cap = NULL;
226 txn->hdr_idx.v = NULL;
227 txn->hdr_idx.size = txn->hdr_idx.used = 0;
228
229 if (unlikely((s->req = pool_alloc2(pool2_buffer)) == NULL))
230 goto out_free_task; /* no memory */
231
232 if (unlikely((s->rep = pool_alloc2(pool2_buffer)) == NULL))
233 goto out_free_req; /* no memory */
234
235 /* initialize the request buffer */
236 s->req->size = global.tune.bufsize;
237 buffer_init(s->req);
238 s->req->prod = &s->si[0];
239 s->req->cons = &s->si[1];
240 s->si[0].ib = s->si[1].ob = s->req;
241 s->req->flags |= BF_READ_ATTACHED; /* the producer is already connected */
242
243 /* activate default analysers enabled for this listener */
244 s->req->analysers = l->analysers;
245
246 s->req->wto = TICK_ETERNITY;
247 s->req->rto = TICK_ETERNITY;
248 s->req->rex = TICK_ETERNITY;
249 s->req->wex = TICK_ETERNITY;
250 s->req->analyse_exp = TICK_ETERNITY;
251
252 /* initialize response buffer */
253 s->rep->size = global.tune.bufsize;
254 buffer_init(s->rep);
255 s->rep->prod = &s->si[1];
256 s->rep->cons = &s->si[0];
257 s->si[0].ob = s->si[1].ib = s->rep;
258 s->rep->analysers = 0;
259
260 s->rep->rto = TICK_ETERNITY;
261 s->rep->wto = TICK_ETERNITY;
262 s->rep->rex = TICK_ETERNITY;
263 s->rep->wex = TICK_ETERNITY;
264 s->rep->analyse_exp = TICK_ETERNITY;
265
266 /* finish initialization of the accepted file descriptor */
267 fd_insert(cfd);
268 fdtab[cfd].owner = &s->si[0];
269 fdtab[cfd].state = FD_STREADY;
270 fdtab[cfd].flags = 0;
271 fdtab[cfd].cb[DIR_RD].f = l->proto->read;
272 fdtab[cfd].cb[DIR_RD].b = s->req;
273 fdtab[cfd].cb[DIR_WR].f = l->proto->write;
274 fdtab[cfd].cb[DIR_WR].b = s->rep;
Willy Tarreau957c0a52011-03-03 17:42:23 +0100275 fdinfo[cfd].peeraddr = (struct sockaddr *)&s->si[0].addr.c.from;
276 fdinfo[cfd].peerlen = sizeof(s->si[0].addr.c.from);
Willy Tarreau81f9aa32010-06-01 17:45:26 +0200277 EV_FD_SET(cfd, DIR_RD);
278
Willy Tarreauabe8ea52010-11-11 10:56:04 +0100279 if (p->accept && (ret = p->accept(s)) <= 0) {
280 /* Either we had an unrecoverable error (<0) or work is
281 * finished (=0, eg: monitoring), in both situations,
282 * we can release everything and close.
283 */
284 goto out_free_rep;
Willy Tarreau81f9aa32010-06-01 17:45:26 +0200285 }
286
287 /* it is important not to call the wakeup function directly but to
288 * pass through task_wakeup(), because this one knows how to apply
289 * priorities to tasks.
290 */
291 task_wakeup(t, TASK_WOKEN_INIT);
292 return 1;
293
294 /* Error unrolling */
295 out_free_rep:
296 pool_free2(pool2_buffer, s->rep);
297 out_free_req:
298 pool_free2(pool2_buffer, s->req);
299 out_free_task:
Willy Tarreau24dcaf32010-06-05 10:49:41 +0200300 p->feconn--;
Willy Tarreau56123282010-08-06 19:06:56 +0200301 if (s->stkctr1_entry || s->stkctr2_entry)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200302 session_store_counters(s);
Willy Tarreau81f9aa32010-06-01 17:45:26 +0200303 task_free(t);
Willy Tarreau81f9aa32010-06-01 17:45:26 +0200304 LIST_DEL(&s->list);
Willy Tarreauabe8ea52010-11-11 10:56:04 +0100305 out_free_session:
Willy Tarreau81f9aa32010-06-01 17:45:26 +0200306 pool_free2(pool2_session, s);
307 out_close:
Willy Tarreauabe8ea52010-11-11 10:56:04 +0100308 if (fdtab[cfd].state != FD_STCLOSE)
309 fd_delete(cfd);
310 else
311 close(cfd);
312 return ret;
Willy Tarreau81f9aa32010-06-01 17:45:26 +0200313}
314
Willy Tarreaubaaee002006-06-26 02:48:02 +0200315/*
316 * frees the context associated to a session. It must have been removed first.
317 */
318void session_free(struct session *s)
319{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +0100320 struct http_txn *txn = &s->txn;
Willy Tarreau632f5a72007-07-11 10:42:35 +0200321 struct proxy *fe = s->fe;
Willy Tarreau62e4f1d2008-12-07 20:16:23 +0100322 struct bref *bref, *back;
Willy Tarreaua4cda672010-06-06 18:28:49 +0200323 int i;
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100324
Willy Tarreaubaaee002006-06-26 02:48:02 +0200325 if (s->pend_pos)
326 pendconn_free(s->pend_pos);
Willy Tarreau922a8062008-12-04 09:33:58 +0100327
Willy Tarreau1e62de62008-11-11 20:20:02 +0100328 if (s->srv) { /* there may be requests left pending in queue */
329 if (s->flags & SN_CURR_SESS) {
330 s->flags &= ~SN_CURR_SESS;
331 s->srv->cur_sess--;
332 }
Willy Tarreau922a8062008-12-04 09:33:58 +0100333 if (may_dequeue_tasks(s->srv, s->be))
334 process_srv_queue(s->srv);
Willy Tarreau1e62de62008-11-11 20:20:02 +0100335 }
Willy Tarreau922a8062008-12-04 09:33:58 +0100336
Willy Tarreau7c669d72008-06-20 15:04:11 +0200337 if (unlikely(s->srv_conn)) {
338 /* the session still has a reserved slot on a server, but
339 * it should normally be only the same as the one above,
340 * so this should not happen in fact.
341 */
342 sess_change_server(s, NULL);
343 }
344
Willy Tarreau3eba98a2009-01-25 13:56:13 +0100345 if (s->req->pipe)
346 put_pipe(s->req->pipe);
Willy Tarreau259de1b2009-01-18 21:56:21 +0100347
Willy Tarreau3eba98a2009-01-25 13:56:13 +0100348 if (s->rep->pipe)
349 put_pipe(s->rep->pipe);
Willy Tarreau259de1b2009-01-18 21:56:21 +0100350
Willy Tarreau48d63db2008-08-03 17:41:33 +0200351 pool_free2(pool2_buffer, s->req);
352 pool_free2(pool2_buffer, s->rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200353
Willy Tarreau46023632010-01-07 22:51:47 +0100354 http_end_txn(s);
355
Willy Tarreaua4cda672010-06-06 18:28:49 +0200356 for (i = 0; i < s->store_count; i++) {
357 if (!s->store[i].ts)
358 continue;
359 stksess_free(s->store[i].table, s->store[i].ts);
360 s->store[i].ts = NULL;
361 }
362
Willy Tarreau92fb9832007-10-16 17:34:28 +0200363 if (fe) {
Willy Tarreau48d63db2008-08-03 17:41:33 +0200364 pool_free2(fe->hdr_idx_pool, txn->hdr_idx.v);
Willy Tarreau46023632010-01-07 22:51:47 +0100365 pool_free2(fe->rsp_cap_pool, txn->rsp.cap);
366 pool_free2(fe->req_cap_pool, txn->req.cap);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200367 }
Willy Tarreau0937bc42009-12-22 15:03:09 +0100368
Willy Tarreau56123282010-08-06 19:06:56 +0200369 if (s->stkctr1_entry || s->stkctr2_entry)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200370 session_store_counters(s);
371
Willy Tarreau62e4f1d2008-12-07 20:16:23 +0100372 list_for_each_entry_safe(bref, back, &s->back_refs, users) {
Willy Tarreaufd3828e2009-02-22 15:17:24 +0100373 /* we have to unlink all watchers. We must not relink them if
374 * this session was the last one in the list.
375 */
Willy Tarreau62e4f1d2008-12-07 20:16:23 +0100376 LIST_DEL(&bref->users);
Willy Tarreaufd3828e2009-02-22 15:17:24 +0100377 LIST_INIT(&bref->users);
378 if (s->list.n != &sessions)
379 LIST_ADDQ(&LIST_ELEM(s->list.n, struct session *, list)->back_refs, &bref->users);
Willy Tarreau62e4f1d2008-12-07 20:16:23 +0100380 bref->ref = s->list.n;
381 }
Willy Tarreauf54f8bd2008-11-23 19:53:55 +0100382 LIST_DEL(&s->list);
Willy Tarreauc6ca1a02007-05-13 19:43:47 +0200383 pool_free2(pool2_session, s);
Willy Tarreau632f5a72007-07-11 10:42:35 +0200384
385 /* We may want to free the maximum amount of pools if the proxy is stopping */
Willy Tarreau92fb9832007-10-16 17:34:28 +0200386 if (fe && unlikely(fe->state == PR_STSTOPPED)) {
Willy Tarreau48d63db2008-08-03 17:41:33 +0200387 pool_flush2(pool2_buffer);
388 pool_flush2(fe->hdr_idx_pool);
389 pool_flush2(pool2_requri);
390 pool_flush2(pool2_capture);
391 pool_flush2(pool2_session);
392 pool_flush2(fe->req_cap_pool);
393 pool_flush2(fe->rsp_cap_pool);
Willy Tarreau632f5a72007-07-11 10:42:35 +0200394 }
Willy Tarreauc6ca1a02007-05-13 19:43:47 +0200395}
396
397
398/* perform minimal intializations, report 0 in case of error, 1 if OK. */
399int init_session()
400{
Willy Tarreauf54f8bd2008-11-23 19:53:55 +0100401 LIST_INIT(&sessions);
Willy Tarreauc6ca1a02007-05-13 19:43:47 +0200402 pool2_session = create_pool("session", sizeof(struct session), MEM_F_SHARED);
403 return pool2_session != NULL;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200404}
405
Willy Tarreau30e71012007-11-26 20:15:35 +0100406void session_process_counters(struct session *s)
407{
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100408 unsigned long long bytes;
409
Willy Tarreau30e71012007-11-26 20:15:35 +0100410 if (s->req) {
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100411 bytes = s->req->total - s->logs.bytes_in;
Willy Tarreau30e71012007-11-26 20:15:35 +0100412 s->logs.bytes_in = s->req->total;
413 if (bytes) {
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +0200414 s->fe->counters.bytes_in += bytes;
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100415
Willy Tarreau30e71012007-11-26 20:15:35 +0100416 if (s->be != s->fe)
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +0200417 s->be->counters.bytes_in += bytes;
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100418
Willy Tarreau30e71012007-11-26 20:15:35 +0100419 if (s->srv)
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +0200420 s->srv->counters.bytes_in += bytes;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +0200421
422 if (s->listener->counters)
423 s->listener->counters->bytes_in += bytes;
Willy Tarreau855e4bb2010-06-18 18:33:32 +0200424
Willy Tarreau56123282010-08-06 19:06:56 +0200425 if (s->stkctr2_entry) {
Willy Tarreau6c59e0a2010-06-20 11:56:30 +0200426 void *ptr;
427
Willy Tarreau56123282010-08-06 19:06:56 +0200428 ptr = stktable_data_ptr(s->stkctr2_table,
429 s->stkctr2_entry,
Willy Tarreau6c59e0a2010-06-20 11:56:30 +0200430 STKTABLE_DT_BYTES_IN_CNT);
Willy Tarreau855e4bb2010-06-18 18:33:32 +0200431 if (ptr)
432 stktable_data_cast(ptr, bytes_in_cnt) += bytes;
Willy Tarreau6c59e0a2010-06-20 11:56:30 +0200433
Willy Tarreau56123282010-08-06 19:06:56 +0200434 ptr = stktable_data_ptr(s->stkctr2_table,
435 s->stkctr2_entry,
Willy Tarreau6c59e0a2010-06-20 11:56:30 +0200436 STKTABLE_DT_BYTES_IN_RATE);
437 if (ptr)
438 update_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
Willy Tarreau56123282010-08-06 19:06:56 +0200439 s->stkctr2_table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u, bytes);
Willy Tarreauf059a0f2010-08-03 16:29:52 +0200440 }
441
Willy Tarreau56123282010-08-06 19:06:56 +0200442 if (s->stkctr1_entry) {
Willy Tarreauf059a0f2010-08-03 16:29:52 +0200443 void *ptr;
444
Willy Tarreau56123282010-08-06 19:06:56 +0200445 ptr = stktable_data_ptr(s->stkctr1_table,
446 s->stkctr1_entry,
Willy Tarreauf059a0f2010-08-03 16:29:52 +0200447 STKTABLE_DT_BYTES_IN_CNT);
448 if (ptr)
449 stktable_data_cast(ptr, bytes_in_cnt) += bytes;
450
Willy Tarreau56123282010-08-06 19:06:56 +0200451 ptr = stktable_data_ptr(s->stkctr1_table,
452 s->stkctr1_entry,
Willy Tarreauf059a0f2010-08-03 16:29:52 +0200453 STKTABLE_DT_BYTES_IN_RATE);
454 if (ptr)
455 update_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
Willy Tarreau56123282010-08-06 19:06:56 +0200456 s->stkctr1_table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u, bytes);
Willy Tarreau855e4bb2010-06-18 18:33:32 +0200457 }
Willy Tarreau30e71012007-11-26 20:15:35 +0100458 }
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100459 }
460
Willy Tarreau30e71012007-11-26 20:15:35 +0100461 if (s->rep) {
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100462 bytes = s->rep->total - s->logs.bytes_out;
Willy Tarreau30e71012007-11-26 20:15:35 +0100463 s->logs.bytes_out = s->rep->total;
464 if (bytes) {
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +0200465 s->fe->counters.bytes_out += bytes;
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100466
Willy Tarreau30e71012007-11-26 20:15:35 +0100467 if (s->be != s->fe)
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +0200468 s->be->counters.bytes_out += bytes;
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100469
Willy Tarreau30e71012007-11-26 20:15:35 +0100470 if (s->srv)
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +0200471 s->srv->counters.bytes_out += bytes;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +0200472
473 if (s->listener->counters)
474 s->listener->counters->bytes_out += bytes;
Willy Tarreau855e4bb2010-06-18 18:33:32 +0200475
Willy Tarreau56123282010-08-06 19:06:56 +0200476 if (s->stkctr2_entry) {
Willy Tarreauf059a0f2010-08-03 16:29:52 +0200477 void *ptr;
478
Willy Tarreau56123282010-08-06 19:06:56 +0200479 ptr = stktable_data_ptr(s->stkctr2_table,
480 s->stkctr2_entry,
Willy Tarreauf059a0f2010-08-03 16:29:52 +0200481 STKTABLE_DT_BYTES_OUT_CNT);
482 if (ptr)
483 stktable_data_cast(ptr, bytes_out_cnt) += bytes;
484
Willy Tarreau56123282010-08-06 19:06:56 +0200485 ptr = stktable_data_ptr(s->stkctr2_table,
486 s->stkctr2_entry,
Willy Tarreauf059a0f2010-08-03 16:29:52 +0200487 STKTABLE_DT_BYTES_OUT_RATE);
488 if (ptr)
489 update_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
Willy Tarreau56123282010-08-06 19:06:56 +0200490 s->stkctr2_table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u, bytes);
Willy Tarreauf059a0f2010-08-03 16:29:52 +0200491 }
492
Willy Tarreau56123282010-08-06 19:06:56 +0200493 if (s->stkctr1_entry) {
Willy Tarreau6c59e0a2010-06-20 11:56:30 +0200494 void *ptr;
495
Willy Tarreau56123282010-08-06 19:06:56 +0200496 ptr = stktable_data_ptr(s->stkctr1_table,
497 s->stkctr1_entry,
Willy Tarreau6c59e0a2010-06-20 11:56:30 +0200498 STKTABLE_DT_BYTES_OUT_CNT);
Willy Tarreau855e4bb2010-06-18 18:33:32 +0200499 if (ptr)
500 stktable_data_cast(ptr, bytes_out_cnt) += bytes;
Willy Tarreau6c59e0a2010-06-20 11:56:30 +0200501
Willy Tarreau56123282010-08-06 19:06:56 +0200502 ptr = stktable_data_ptr(s->stkctr1_table,
503 s->stkctr1_entry,
Willy Tarreau6c59e0a2010-06-20 11:56:30 +0200504 STKTABLE_DT_BYTES_OUT_RATE);
505 if (ptr)
506 update_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
Willy Tarreau56123282010-08-06 19:06:56 +0200507 s->stkctr1_table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u, bytes);
Willy Tarreau855e4bb2010-06-18 18:33:32 +0200508 }
Willy Tarreau30e71012007-11-26 20:15:35 +0100509 }
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100510 }
511}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200512
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100513/* This function is called with (si->state == SI_ST_CON) meaning that a
514 * connection was attempted and that the file descriptor is already allocated.
515 * We must check for establishment, error and abort. Possible output states
516 * are SI_ST_EST (established), SI_ST_CER (error), SI_ST_DIS (abort), and
517 * SI_ST_CON (no change). The function returns 0 if it switches to SI_ST_CER,
518 * otherwise 1.
519 */
520int sess_update_st_con_tcp(struct session *s, struct stream_interface *si)
521{
522 struct buffer *req = si->ob;
523 struct buffer *rep = si->ib;
524
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100525 /* If we got an error, or if nothing happened and the connection timed
526 * out, we must give up. The CER state handler will take care of retry
527 * attempts and error reports.
528 */
529 if (unlikely(si->flags & (SI_FL_EXP|SI_FL_ERR))) {
Willy Tarreau127334e2009-03-28 10:47:26 +0100530 si->exp = TICK_ETERNITY;
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100531 si->state = SI_ST_CER;
Willy Tarreaudc340a92009-06-28 23:10:19 +0200532 si->flags &= ~SI_FL_CAP_SPLICE;
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100533 fd_delete(si->fd);
534
Willy Tarreau0bd05ea2010-07-02 11:18:03 +0200535 if (si->release)
536 si->release(si);
537
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100538 if (si->err_type)
539 return 0;
540
541 si->err_loc = s->srv;
542 if (si->flags & SI_FL_ERR)
543 si->err_type = SI_ET_CONN_ERR;
544 else
545 si->err_type = SI_ET_CONN_TO;
546 return 0;
547 }
548
549 /* OK, maybe we want to abort */
Willy Tarreau418fd472009-09-06 21:37:23 +0200550 if (unlikely((rep->flags & BF_SHUTW) ||
551 ((req->flags & BF_SHUTW_NOW) && /* FIXME: this should not prevent a connection from establishing */
Willy Tarreauba0b63d2009-09-20 08:09:44 +0200552 (((req->flags & (BF_OUT_EMPTY|BF_WRITE_ACTIVITY)) == BF_OUT_EMPTY) ||
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100553 s->be->options & PR_O_ABRT_CLOSE)))) {
554 /* give up */
555 si->shutw(si);
556 si->err_type |= SI_ET_CONN_ABRT;
557 si->err_loc = s->srv;
Willy Tarreaudc340a92009-06-28 23:10:19 +0200558 si->flags &= ~SI_FL_CAP_SPLICE;
Willy Tarreau84455332009-03-15 22:34:05 +0100559 if (s->srv_error)
560 s->srv_error(s, si);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100561 return 1;
562 }
563
564 /* we need to wait a bit more if there was no activity either */
565 if (!(req->flags & BF_WRITE_ACTIVITY))
566 return 1;
567
568 /* OK, this means that a connection succeeded. The caller will be
569 * responsible for handling the transition from CON to EST.
570 */
571 s->logs.t_connect = tv_ms_elapsed(&s->logs.tv_accept, &now);
Willy Tarreau127334e2009-03-28 10:47:26 +0100572 si->exp = TICK_ETERNITY;
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100573 si->state = SI_ST_EST;
574 si->err_type = SI_ET_NONE;
575 si->err_loc = NULL;
576 return 1;
577}
578
579/* This function is called with (si->state == SI_ST_CER) meaning that a
580 * previous connection attempt has failed and that the file descriptor
581 * has already been released. Possible causes include asynchronous error
582 * notification and time out. Possible output states are SI_ST_CLO when
583 * retries are exhausted, SI_ST_TAR when a delay is wanted before a new
584 * connection attempt, SI_ST_ASS when it's wise to retry on the same server,
585 * and SI_ST_REQ when an immediate redispatch is wanted. The buffers are
586 * marked as in error state. It returns 0.
587 */
588int sess_update_st_cer(struct session *s, struct stream_interface *si)
589{
590 /* we probably have to release last session from the server */
591 if (s->srv) {
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +0100592 health_adjust(s->srv, HANA_STATUS_L4_ERR);
593
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100594 if (s->flags & SN_CURR_SESS) {
595 s->flags &= ~SN_CURR_SESS;
596 s->srv->cur_sess--;
597 }
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100598 }
599
600 /* ensure that we have enough retries left */
Willy Tarreauee28de02010-06-01 09:51:00 +0200601 si->conn_retries--;
602 if (si->conn_retries < 0) {
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100603 if (!si->err_type) {
604 si->err_type = SI_ET_CONN_ERR;
605 si->err_loc = s->srv;
606 }
607
608 if (s->srv)
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +0200609 s->srv->counters.failed_conns++;
610 s->be->counters.failed_conns++;
Willy Tarreaub89cfca2010-12-29 14:32:28 +0100611 sess_change_server(s, NULL);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100612 if (may_dequeue_tasks(s->srv, s->be))
613 process_srv_queue(s->srv);
614
615 /* shutw is enough so stop a connecting socket */
616 si->shutw(si);
617 si->ob->flags |= BF_WRITE_ERROR;
618 si->ib->flags |= BF_READ_ERROR;
619
620 si->state = SI_ST_CLO;
Willy Tarreau0cac36f2008-11-30 20:44:17 +0100621 if (s->srv_error)
622 s->srv_error(s, si);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100623 return 0;
624 }
625
626 /* If the "redispatch" option is set on the backend, we are allowed to
627 * retry on another server for the last retry. In order to achieve this,
628 * we must mark the session unassigned, and eventually clear the DIRECT
629 * bit to ignore any persistence cookie. We won't count a retry nor a
630 * redispatch yet, because this will depend on what server is selected.
631 */
Willy Tarreauee28de02010-06-01 09:51:00 +0200632 if (s->srv && si->conn_retries == 0 &&
Willy Tarreau4de91492010-01-22 19:10:05 +0100633 s->be->options & PR_O_REDISP && !(s->flags & SN_FORCE_PRST)) {
Willy Tarreaub89cfca2010-12-29 14:32:28 +0100634 sess_change_server(s, NULL);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100635 if (may_dequeue_tasks(s->srv, s->be))
636 process_srv_queue(s->srv);
637
638 s->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
639 s->prev_srv = s->srv;
640 si->state = SI_ST_REQ;
641 } else {
642 if (s->srv)
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +0200643 s->srv->counters.retries++;
644 s->be->counters.retries++;
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100645 si->state = SI_ST_ASS;
646 }
647
648 if (si->flags & SI_FL_ERR) {
649 /* The error was an asynchronous connection error, and we will
650 * likely have to retry connecting to the same server, most
651 * likely leading to the same result. To avoid this, we wait
652 * one second before retrying.
653 */
654
655 if (!si->err_type)
656 si->err_type = SI_ET_CONN_ERR;
657
658 si->state = SI_ST_TAR;
659 si->exp = tick_add(now_ms, MS_TO_TICKS(1000));
660 return 0;
661 }
662 return 0;
663}
664
665/*
666 * This function handles the transition between the SI_ST_CON state and the
Willy Tarreau85e7d002010-05-31 11:57:51 +0200667 * SI_ST_EST state. It must only be called after switching from SI_ST_CON (or
668 * SI_ST_INI) to SI_ST_EST, but only when a ->connect function is defined.
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100669 */
670void sess_establish(struct session *s, struct stream_interface *si)
671{
672 struct buffer *req = si->ob;
673 struct buffer *rep = si->ib;
674
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +0100675 if (s->srv)
676 health_adjust(s->srv, HANA_STATUS_L4_OK);
677
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100678 if (s->be->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100679 /* if the user wants to log as soon as possible, without counting
680 * bytes from the server, then this is the right moment. */
681 if (s->fe->to_log && !(s->logs.logwait & LW_BYTES)) {
682 s->logs.t_close = s->logs.t_connect; /* to get a valid end date */
Willy Tarreaua5555ec2008-11-30 19:02:32 +0100683 s->do_log(s);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100684 }
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100685 }
686 else {
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100687 s->txn.rsp.msg_state = HTTP_MSG_RPBEFORE;
688 /* reset hdr_idx which was already initialized by the request.
689 * right now, the http parser does it.
690 * hdr_idx_init(&s->txn.hdr_idx);
691 */
692 }
693
Willy Tarreau4e5b8282009-08-16 22:57:50 +0200694 rep->analysers |= s->fe->fe_rsp_ana | s->be->be_rsp_ana;
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100695 rep->flags |= BF_READ_ATTACHED; /* producer is now attached */
Willy Tarreaud04e8582010-05-31 12:31:35 +0200696 if (si->connect) {
697 /* real connections have timeouts */
698 req->wto = s->be->timeout.server;
699 rep->rto = s->be->timeout.server;
700 }
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100701 req->wex = TICK_ETERNITY;
702}
703
704/* Update stream interface status for input states SI_ST_ASS, SI_ST_QUE, SI_ST_TAR.
705 * Other input states are simply ignored.
706 * Possible output states are SI_ST_CLO, SI_ST_TAR, SI_ST_ASS, SI_ST_REQ, SI_ST_CON.
707 * Flags must have previously been updated for timeouts and other conditions.
708 */
709void sess_update_stream_int(struct session *s, struct stream_interface *si)
710{
711 DPRINTF(stderr,"[%u] %s: sess=%p rq=%p, rp=%p, exp(r,w)=%u,%u rqf=%08x rpf=%08x rql=%d rpl=%d cs=%d ss=%d\n",
712 now_ms, __FUNCTION__,
713 s,
714 s->req, s->rep,
715 s->req->rex, s->rep->wex,
716 s->req->flags, s->rep->flags,
717 s->req->l, s->rep->l, s->rep->cons->state, s->req->cons->state);
718
719 if (si->state == SI_ST_ASS) {
720 /* Server assigned to connection request, we have to try to connect now */
721 int conn_err;
722
723 conn_err = connect_server(s);
724 if (conn_err == SN_ERR_NONE) {
725 /* state = SI_ST_CON now */
Willy Tarreau8f6457c2008-12-01 00:08:28 +0100726 if (s->srv)
Willy Tarreau7f062c42009-03-05 18:43:00 +0100727 srv_inc_sess_ctr(s->srv);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100728 return;
729 }
730
731 /* We have received a synchronous error. We might have to
732 * abort, retry immediately or redispatch.
733 */
734 if (conn_err == SN_ERR_INTERNAL) {
735 if (!si->err_type) {
736 si->err_type = SI_ET_CONN_OTHER;
737 si->err_loc = s->srv;
738 }
739
740 if (s->srv)
Willy Tarreau7f062c42009-03-05 18:43:00 +0100741 srv_inc_sess_ctr(s->srv);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100742 if (s->srv)
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +0200743 s->srv->counters.failed_conns++;
744 s->be->counters.failed_conns++;
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100745
746 /* release other sessions waiting for this server */
Willy Tarreaub89cfca2010-12-29 14:32:28 +0100747 sess_change_server(s, NULL);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100748 if (may_dequeue_tasks(s->srv, s->be))
749 process_srv_queue(s->srv);
750
751 /* Failed and not retryable. */
752 si->shutr(si);
753 si->shutw(si);
754 si->ob->flags |= BF_WRITE_ERROR;
755
756 s->logs.t_queue = tv_ms_elapsed(&s->logs.tv_accept, &now);
757
758 /* no session was ever accounted for this server */
759 si->state = SI_ST_CLO;
Willy Tarreau0cac36f2008-11-30 20:44:17 +0100760 if (s->srv_error)
761 s->srv_error(s, si);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100762 return;
763 }
764
765 /* We are facing a retryable error, but we don't want to run a
766 * turn-around now, as the problem is likely a source port
767 * allocation problem, so we want to retry now.
768 */
769 si->state = SI_ST_CER;
770 si->flags &= ~SI_FL_ERR;
771 sess_update_st_cer(s, si);
772 /* now si->state is one of SI_ST_CLO, SI_ST_TAR, SI_ST_ASS, SI_ST_REQ */
773 return;
774 }
775 else if (si->state == SI_ST_QUE) {
776 /* connection request was queued, check for any update */
777 if (!s->pend_pos) {
778 /* The connection is not in the queue anymore. Either
779 * we have a server connection slot available and we
780 * go directly to the assigned state, or we need to
781 * load-balance first and go to the INI state.
782 */
783 si->exp = TICK_ETERNITY;
784 if (unlikely(!(s->flags & SN_ASSIGNED)))
785 si->state = SI_ST_REQ;
786 else {
787 s->logs.t_queue = tv_ms_elapsed(&s->logs.tv_accept, &now);
788 si->state = SI_ST_ASS;
789 }
790 return;
791 }
792
793 /* Connection request still in queue... */
794 if (si->flags & SI_FL_EXP) {
795 /* ... and timeout expired */
796 si->exp = TICK_ETERNITY;
797 s->logs.t_queue = tv_ms_elapsed(&s->logs.tv_accept, &now);
798 if (s->srv)
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +0200799 s->srv->counters.failed_conns++;
800 s->be->counters.failed_conns++;
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100801 si->shutr(si);
802 si->shutw(si);
803 si->ob->flags |= BF_WRITE_TIMEOUT;
804 if (!si->err_type)
805 si->err_type = SI_ET_QUEUE_TO;
806 si->state = SI_ST_CLO;
Willy Tarreau0cac36f2008-11-30 20:44:17 +0100807 if (s->srv_error)
808 s->srv_error(s, si);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100809 return;
810 }
811
812 /* Connection remains in queue, check if we have to abort it */
Willy Tarreau418fd472009-09-06 21:37:23 +0200813 if ((si->ob->flags & (BF_READ_ERROR)) ||
814 ((si->ob->flags & BF_SHUTW_NOW) && /* empty and client aborted */
Willy Tarreauba0b63d2009-09-20 08:09:44 +0200815 (si->ob->flags & BF_OUT_EMPTY || s->be->options & PR_O_ABRT_CLOSE))) {
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100816 /* give up */
817 si->exp = TICK_ETERNITY;
818 s->logs.t_queue = tv_ms_elapsed(&s->logs.tv_accept, &now);
819 si->shutr(si);
820 si->shutw(si);
821 si->err_type |= SI_ET_QUEUE_ABRT;
822 si->state = SI_ST_CLO;
Willy Tarreau0cac36f2008-11-30 20:44:17 +0100823 if (s->srv_error)
824 s->srv_error(s, si);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100825 return;
826 }
827
828 /* Nothing changed */
829 return;
830 }
831 else if (si->state == SI_ST_TAR) {
832 /* Connection request might be aborted */
Willy Tarreau418fd472009-09-06 21:37:23 +0200833 if ((si->ob->flags & (BF_READ_ERROR)) ||
834 ((si->ob->flags & BF_SHUTW_NOW) && /* empty and client aborted */
Willy Tarreauba0b63d2009-09-20 08:09:44 +0200835 (si->ob->flags & BF_OUT_EMPTY || s->be->options & PR_O_ABRT_CLOSE))) {
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100836 /* give up */
837 si->exp = TICK_ETERNITY;
838 si->shutr(si);
839 si->shutw(si);
840 si->err_type |= SI_ET_CONN_ABRT;
841 si->state = SI_ST_CLO;
Willy Tarreau0cac36f2008-11-30 20:44:17 +0100842 if (s->srv_error)
843 s->srv_error(s, si);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100844 return;
845 }
846
847 if (!(si->flags & SI_FL_EXP))
848 return; /* still in turn-around */
849
850 si->exp = TICK_ETERNITY;
851
852 /* we keep trying on the same server as long as the session is
853 * marked "assigned".
854 * FIXME: Should we force a redispatch attempt when the server is down ?
855 */
856 if (s->flags & SN_ASSIGNED)
857 si->state = SI_ST_ASS;
858 else
859 si->state = SI_ST_REQ;
860 return;
861 }
862}
863
864/* This function initiates a server connection request on a stream interface
865 * already in SI_ST_REQ state. Upon success, the state goes to SI_ST_ASS,
866 * indicating that a server has been assigned. It may also return SI_ST_QUE,
867 * or SI_ST_CLO upon error.
868 */
869static void sess_prepare_conn_req(struct session *s, struct stream_interface *si) {
870 DPRINTF(stderr,"[%u] %s: sess=%p rq=%p, rp=%p, exp(r,w)=%u,%u rqf=%08x rpf=%08x rql=%d rpl=%d cs=%d ss=%d\n",
871 now_ms, __FUNCTION__,
872 s,
873 s->req, s->rep,
874 s->req->rex, s->rep->wex,
875 s->req->flags, s->rep->flags,
876 s->req->l, s->rep->l, s->rep->cons->state, s->req->cons->state);
877
878 if (si->state != SI_ST_REQ)
879 return;
880
881 /* Try to assign a server */
882 if (srv_redispatch_connect(s) != 0) {
883 /* We did not get a server. Either we queued the
884 * connection request, or we encountered an error.
885 */
886 if (si->state == SI_ST_QUE)
887 return;
888
889 /* we did not get any server, let's check the cause */
890 si->shutr(si);
891 si->shutw(si);
892 si->ob->flags |= BF_WRITE_ERROR;
893 if (!si->err_type)
894 si->err_type = SI_ET_CONN_OTHER;
895 si->state = SI_ST_CLO;
Willy Tarreau0cac36f2008-11-30 20:44:17 +0100896 if (s->srv_error)
897 s->srv_error(s, si);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100898 return;
899 }
900
901 /* The server is assigned */
902 s->logs.t_queue = tv_ms_elapsed(&s->logs.tv_accept, &now);
903 si->state = SI_ST_ASS;
904}
905
Willy Tarreau1d0dfb12009-07-07 15:10:31 +0200906/* This stream analyser checks the switching rules and changes the backend
Willy Tarreau4de91492010-01-22 19:10:05 +0100907 * if appropriate. The default_backend rule is also considered, then the
908 * target backend's forced persistence rules are also evaluated last if any.
Willy Tarreau1d0dfb12009-07-07 15:10:31 +0200909 * It returns 1 if the processing can continue on next analysers, or zero if it
910 * either needs more data or wants to immediately abort the request.
911 */
912int process_switching_rules(struct session *s, struct buffer *req, int an_bit)
913{
Cyril Bonté47fdd8e2010-04-25 00:00:51 +0200914 struct persist_rule *prst_rule;
Willy Tarreau4de91492010-01-22 19:10:05 +0100915
Willy Tarreau1d0dfb12009-07-07 15:10:31 +0200916 req->analysers &= ~an_bit;
917 req->analyse_exp = TICK_ETERNITY;
918
919 DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
920 now_ms, __FUNCTION__,
921 s,
922 req,
923 req->rex, req->wex,
924 req->flags,
925 req->l,
926 req->analysers);
927
928 /* now check whether we have some switching rules for this request */
929 if (!(s->flags & SN_BE_ASSIGNED)) {
930 struct switching_rule *rule;
931
932 list_for_each_entry(rule, &s->fe->switching_rules, list) {
933 int ret;
934
935 ret = acl_exec_cond(rule->cond, s->fe, s, &s->txn, ACL_DIR_REQ);
936 ret = acl_pass(ret);
937 if (rule->cond->pol == ACL_COND_UNLESS)
938 ret = !ret;
939
940 if (ret) {
Willy Tarreaubedb9ba2009-07-12 08:27:39 +0200941 if (!session_set_backend(s, rule->be.backend))
942 goto sw_failed;
Willy Tarreau1d0dfb12009-07-07 15:10:31 +0200943 break;
944 }
945 }
946
947 /* To ensure correct connection accounting on the backend, we
948 * have to assign one if it was not set (eg: a listen). This
949 * measure also takes care of correctly setting the default
950 * backend if any.
951 */
952 if (!(s->flags & SN_BE_ASSIGNED))
Willy Tarreaubedb9ba2009-07-12 08:27:39 +0200953 if (!session_set_backend(s, s->fe->defbe.be ? s->fe->defbe.be : s->be))
954 goto sw_failed;
Willy Tarreau1d0dfb12009-07-07 15:10:31 +0200955 }
956
Willy Tarreaufb356202010-08-03 14:02:05 +0200957 /* we don't want to run the TCP or HTTP filters again if the backend has not changed */
958 if (s->fe == s->be) {
959 s->req->analysers &= ~AN_REQ_INSPECT_BE;
Willy Tarreau1d0dfb12009-07-07 15:10:31 +0200960 s->req->analysers &= ~AN_REQ_HTTP_PROCESS_BE;
Willy Tarreaufb356202010-08-03 14:02:05 +0200961 }
Willy Tarreau1d0dfb12009-07-07 15:10:31 +0200962
Cyril Bonté47fdd8e2010-04-25 00:00:51 +0200963 /* as soon as we know the backend, we must check if we have a matching forced or ignored
Willy Tarreau4de91492010-01-22 19:10:05 +0100964 * persistence rule, and report that in the session.
965 */
Cyril Bonté47fdd8e2010-04-25 00:00:51 +0200966 list_for_each_entry(prst_rule, &s->be->persist_rules, list) {
Willy Tarreau4de91492010-01-22 19:10:05 +0100967 int ret = 1;
968
969 if (prst_rule->cond) {
970 ret = acl_exec_cond(prst_rule->cond, s->be, s, &s->txn, ACL_DIR_REQ);
971 ret = acl_pass(ret);
972 if (prst_rule->cond->pol == ACL_COND_UNLESS)
973 ret = !ret;
974 }
975
976 if (ret) {
977 /* no rule, or the rule matches */
Cyril Bonté47fdd8e2010-04-25 00:00:51 +0200978 if (prst_rule->type == PERSIST_TYPE_FORCE) {
979 s->flags |= SN_FORCE_PRST;
980 } else {
981 s->flags |= SN_IGNORE_PRST;
982 }
Willy Tarreau4de91492010-01-22 19:10:05 +0100983 break;
984 }
985 }
986
Willy Tarreau1d0dfb12009-07-07 15:10:31 +0200987 return 1;
Willy Tarreaubedb9ba2009-07-12 08:27:39 +0200988
989 sw_failed:
990 /* immediately abort this request in case of allocation failure */
991 buffer_abort(s->req);
992 buffer_abort(s->rep);
993
994 if (!(s->flags & SN_ERR_MASK))
995 s->flags |= SN_ERR_RESOURCE;
996 if (!(s->flags & SN_FINST_MASK))
997 s->flags |= SN_FINST_R;
998
999 s->txn.status = 500;
1000 s->req->analysers = 0;
1001 s->req->analyse_exp = TICK_ETERNITY;
1002 return 0;
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02001003}
1004
Emeric Brun1d33b292010-01-04 15:47:17 +01001005/* This stream analyser works on a request. It applies all sticking rules on
1006 * it then returns 1. The data must already be present in the buffer otherwise
1007 * they won't match. It always returns 1.
1008 */
1009int process_sticking_rules(struct session *s, struct buffer *req, int an_bit)
1010{
1011 struct proxy *px = s->be;
1012 struct sticking_rule *rule;
1013
1014 DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
1015 now_ms, __FUNCTION__,
1016 s,
1017 req,
1018 req->rex, req->wex,
1019 req->flags,
1020 req->l,
1021 req->analysers);
1022
1023 list_for_each_entry(rule, &px->sticking_rules, list) {
1024 int ret = 1 ;
1025 int i;
1026
1027 for (i = 0; i < s->store_count; i++) {
1028 if (rule->table.t == s->store[i].table)
1029 break;
1030 }
1031
1032 if (i != s->store_count)
1033 continue;
1034
1035 if (rule->cond) {
1036 ret = acl_exec_cond(rule->cond, px, s, &s->txn, ACL_DIR_REQ);
1037 ret = acl_pass(ret);
1038 if (rule->cond->pol == ACL_COND_UNLESS)
1039 ret = !ret;
1040 }
1041
1042 if (ret) {
1043 struct stktable_key *key;
1044
Emeric Brun485479d2010-09-23 18:02:19 +02001045 key = stktable_fetch_key(rule->table.t, px, s, &s->txn, PATTERN_FETCH_REQ, rule->expr);
Emeric Brun1d33b292010-01-04 15:47:17 +01001046 if (!key)
1047 continue;
1048
1049 if (rule->flags & STK_IS_MATCH) {
1050 struct stksess *ts;
1051
Willy Tarreauf16d2b82010-06-06 15:38:59 +02001052 if ((ts = stktable_lookup_key(rule->table.t, key)) != NULL) {
Emeric Brun1d33b292010-01-04 15:47:17 +01001053 if (!(s->flags & SN_ASSIGNED)) {
1054 struct eb32_node *node;
Willy Tarreau13c29de2010-06-06 16:40:39 +02001055 void *ptr;
Emeric Brun1d33b292010-01-04 15:47:17 +01001056
1057 /* srv found in table */
Willy Tarreau13c29de2010-06-06 16:40:39 +02001058 ptr = stktable_data_ptr(rule->table.t, ts, STKTABLE_DT_SERVER_ID);
1059 node = eb32_lookup(&px->conf.used_server_id, stktable_data_cast(ptr, server_id));
Emeric Brun1d33b292010-01-04 15:47:17 +01001060 if (node) {
1061 struct server *srv;
1062
1063 srv = container_of(node, struct server, conf.id);
Willy Tarreau4de91492010-01-22 19:10:05 +01001064 if ((srv->state & SRV_RUNNING) ||
1065 (px->options & PR_O_PERSIST) ||
1066 (s->flags & SN_FORCE_PRST)) {
Emeric Brun1d33b292010-01-04 15:47:17 +01001067 s->flags |= SN_DIRECT | SN_ASSIGNED;
1068 s->srv = srv;
1069 }
1070 }
1071 }
Emeric Brun85e77c72010-09-23 18:16:52 +02001072 stktable_touch(rule->table.t, ts, 1);
Emeric Brun1d33b292010-01-04 15:47:17 +01001073 }
1074 }
1075 if (rule->flags & STK_IS_STORE) {
1076 if (s->store_count < (sizeof(s->store) / sizeof(s->store[0]))) {
1077 struct stksess *ts;
1078
1079 ts = stksess_new(rule->table.t, key);
1080 if (ts) {
1081 s->store[s->store_count].table = rule->table.t;
1082 s->store[s->store_count++].ts = ts;
1083 }
1084 }
1085 }
1086 }
1087 }
1088
1089 req->analysers &= ~an_bit;
1090 req->analyse_exp = TICK_ETERNITY;
1091 return 1;
1092}
1093
1094/* This stream analyser works on a response. It applies all store rules on it
1095 * then returns 1. The data must already be present in the buffer otherwise
1096 * they won't match. It always returns 1.
1097 */
1098int process_store_rules(struct session *s, struct buffer *rep, int an_bit)
1099{
1100 struct proxy *px = s->be;
1101 struct sticking_rule *rule;
1102 int i;
1103
1104 DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
1105 now_ms, __FUNCTION__,
1106 s,
Willy Tarreau2e2b3eb2010-02-09 20:55:44 +01001107 rep,
1108 rep->rex, rep->wex,
1109 rep->flags,
1110 rep->l,
1111 rep->analysers);
Emeric Brun1d33b292010-01-04 15:47:17 +01001112
1113 list_for_each_entry(rule, &px->storersp_rules, list) {
1114 int ret = 1 ;
1115 int storereqidx = -1;
1116
1117 for (i = 0; i < s->store_count; i++) {
1118 if (rule->table.t == s->store[i].table) {
1119 if (!(s->store[i].flags))
1120 storereqidx = i;
1121 break;
1122 }
1123 }
1124
1125 if ((i != s->store_count) && (storereqidx == -1))
1126 continue;
1127
1128 if (rule->cond) {
1129 ret = acl_exec_cond(rule->cond, px, s, &s->txn, ACL_DIR_RTR);
1130 ret = acl_pass(ret);
1131 if (rule->cond->pol == ACL_COND_UNLESS)
1132 ret = !ret;
1133 }
1134
1135 if (ret) {
1136 struct stktable_key *key;
1137
Emeric Brun485479d2010-09-23 18:02:19 +02001138 key = stktable_fetch_key(rule->table.t, px, s, &s->txn, PATTERN_FETCH_RTR, rule->expr);
Emeric Brun1d33b292010-01-04 15:47:17 +01001139 if (!key)
1140 continue;
1141
1142 if (storereqidx != -1) {
Willy Tarreau393379c2010-06-06 12:11:37 +02001143 stksess_setkey(s->store[storereqidx].table, s->store[storereqidx].ts, key);
Emeric Brun1d33b292010-01-04 15:47:17 +01001144 s->store[storereqidx].flags = 1;
1145 }
1146 else if (s->store_count < (sizeof(s->store) / sizeof(s->store[0]))) {
1147 struct stksess *ts;
1148
1149 ts = stksess_new(rule->table.t, key);
1150 if (ts) {
1151 s->store[s->store_count].table = rule->table.t;
1152 s->store[s->store_count].flags = 1;
1153 s->store[s->store_count++].ts = ts;
1154 }
1155 }
1156 }
1157 }
1158
1159 /* process store request and store response */
1160 for (i = 0; i < s->store_count; i++) {
Willy Tarreauf16d2b82010-06-06 15:38:59 +02001161 struct stksess *ts;
Willy Tarreau13c29de2010-06-06 16:40:39 +02001162 void *ptr;
Willy Tarreauf16d2b82010-06-06 15:38:59 +02001163
1164 ts = stktable_lookup(s->store[i].table, s->store[i].ts);
1165 if (ts) {
1166 /* the entry already existed, we can free ours */
Emeric Brun85e77c72010-09-23 18:16:52 +02001167 stktable_touch(s->store[i].table, ts, 1);
Emeric Brun1d33b292010-01-04 15:47:17 +01001168 stksess_free(s->store[i].table, s->store[i].ts);
Emeric Brun1d33b292010-01-04 15:47:17 +01001169 }
Willy Tarreauf16d2b82010-06-06 15:38:59 +02001170 else
Emeric Brun85e77c72010-09-23 18:16:52 +02001171 ts = stktable_store(s->store[i].table, s->store[i].ts, 1);
Willy Tarreauf16d2b82010-06-06 15:38:59 +02001172
1173 s->store[i].ts = NULL;
Willy Tarreau13c29de2010-06-06 16:40:39 +02001174 ptr = stktable_data_ptr(s->store[i].table, ts, STKTABLE_DT_SERVER_ID);
1175 stktable_data_cast(ptr, server_id) = s->srv->puid;
Emeric Brun1d33b292010-01-04 15:47:17 +01001176 }
Willy Tarreau2a164ee2010-06-18 09:57:45 +02001177 s->store_count = 0; /* everything is stored */
Emeric Brun1d33b292010-01-04 15:47:17 +01001178
1179 rep->analysers &= ~an_bit;
1180 rep->analyse_exp = TICK_ETERNITY;
1181 return 1;
1182}
1183
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001184/* This macro is very specific to the function below. See the comments in
1185 * process_session() below to understand the logic and the tests.
1186 */
1187#define UPDATE_ANALYSERS(real, list, back, flag) { \
1188 list = (((list) & ~(flag)) | ~(back)) & (real); \
1189 back = real; \
1190 if (!(list)) \
1191 break; \
1192 if (((list) ^ ((list) & ((list) - 1))) < (flag)) \
1193 continue; \
1194}
1195
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001196/* Processes the client, server, request and response jobs of a session task,
1197 * then puts it back to the wait queue in a clean state, or cleans up its
1198 * resources if it must be deleted. Returns in <next> the date the task wants
1199 * to be woken up, or TICK_ETERNITY. In order not to call all functions for
1200 * nothing too many times, the request and response buffers flags are monitored
1201 * and each function is called only if at least another function has changed at
1202 * least one flag it is interested in.
1203 */
Willy Tarreau26c25062009-03-08 09:38:41 +01001204struct task *process_session(struct task *t)
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001205{
1206 struct session *s = t->context;
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001207 unsigned int rqf_last, rpf_last;
Willy Tarreau815a9b22010-07-27 17:15:12 +02001208 unsigned int rq_prod_last, rq_cons_last;
1209 unsigned int rp_cons_last, rp_prod_last;
Willy Tarreau576507f2010-01-07 00:09:04 +01001210 unsigned int req_ana_back;
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001211
1212 //DPRINTF(stderr, "%s:%d: cs=%d ss=%d(%d) rqf=0x%08x rpf=0x%08x\n", __FUNCTION__, __LINE__,
1213 // s->si[0].state, s->si[1].state, s->si[1].err_type, s->req->flags, s->rep->flags);
1214
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +01001215 /* this data may be no longer valid, clear it */
1216 memset(&s->txn.auth, 0, sizeof(s->txn.auth));
1217
Willy Tarreaub67a9b82009-06-21 22:03:51 +02001218 /* This flag must explicitly be set every time */
1219 s->req->flags &= ~BF_READ_NOEXP;
1220
1221 /* Keep a copy of req/rep flags so that we can detect shutdowns */
Willy Tarreau2f976e12010-11-11 14:28:47 +01001222 rqf_last = s->req->flags & ~BF_MASK_ANALYSER;
1223 rpf_last = s->rep->flags & ~BF_MASK_ANALYSER;
Willy Tarreaub67a9b82009-06-21 22:03:51 +02001224
Willy Tarreau89f7ef22009-09-05 20:57:35 +02001225 /* we don't want the stream interface functions to recursively wake us up */
1226 if (s->req->prod->owner == t)
1227 s->req->prod->flags |= SI_FL_DONT_WAKE;
1228 if (s->req->cons->owner == t)
1229 s->req->cons->flags |= SI_FL_DONT_WAKE;
1230
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001231 /* 1a: Check for low level timeouts if needed. We just set a flag on
1232 * stream interfaces when their timeouts have expired.
1233 */
1234 if (unlikely(t->state & TASK_WOKEN_TIMER)) {
1235 stream_int_check_timeouts(&s->si[0]);
1236 stream_int_check_timeouts(&s->si[1]);
Willy Tarreaub67a9b82009-06-21 22:03:51 +02001237
1238 /* check buffer timeouts, and close the corresponding stream interfaces
1239 * for future reads or writes. Note: this will also concern upper layers
1240 * but we do not touch any other flag. We must be careful and correctly
1241 * detect state changes when calling them.
1242 */
1243
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001244 buffer_check_timeouts(s->req);
Willy Tarreaub67a9b82009-06-21 22:03:51 +02001245
Willy Tarreau14641402009-12-29 14:49:56 +01001246 if (unlikely((s->req->flags & (BF_SHUTW|BF_WRITE_TIMEOUT)) == BF_WRITE_TIMEOUT)) {
1247 s->req->cons->flags |= SI_FL_NOLINGER;
1248 s->req->cons->shutw(s->req->cons);
1249 }
1250
Willy Tarreaub67a9b82009-06-21 22:03:51 +02001251 if (unlikely((s->req->flags & (BF_SHUTR|BF_READ_TIMEOUT)) == BF_READ_TIMEOUT))
1252 s->req->prod->shutr(s->req->prod);
1253
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001254 buffer_check_timeouts(s->rep);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001255
Willy Tarreau14641402009-12-29 14:49:56 +01001256 if (unlikely((s->rep->flags & (BF_SHUTW|BF_WRITE_TIMEOUT)) == BF_WRITE_TIMEOUT)) {
1257 s->rep->cons->flags |= SI_FL_NOLINGER;
1258 s->rep->cons->shutw(s->rep->cons);
1259 }
1260
Willy Tarreaub67a9b82009-06-21 22:03:51 +02001261 if (unlikely((s->rep->flags & (BF_SHUTR|BF_READ_TIMEOUT)) == BF_READ_TIMEOUT))
1262 s->rep->prod->shutr(s->rep->prod);
Willy Tarreaub67a9b82009-06-21 22:03:51 +02001263 }
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001264
1265 /* 1b: check for low-level errors reported at the stream interface.
1266 * First we check if it's a retryable error (in which case we don't
1267 * want to tell the buffer). Otherwise we report the error one level
1268 * upper by setting flags into the buffers. Note that the side towards
1269 * the client cannot have connect (hence retryable) errors. Also, the
1270 * connection setup code must be able to deal with any type of abort.
1271 */
1272 if (unlikely(s->si[0].flags & SI_FL_ERR)) {
1273 if (s->si[0].state == SI_ST_EST || s->si[0].state == SI_ST_DIS) {
1274 s->si[0].shutr(&s->si[0]);
1275 s->si[0].shutw(&s->si[0]);
1276 stream_int_report_error(&s->si[0]);
Willy Tarreau05cb29b2008-12-14 11:44:04 +01001277 if (!(s->req->analysers) && !(s->rep->analysers)) {
Willy Tarreauae526782010-03-04 20:34:23 +01001278 s->be->counters.cli_aborts++;
1279 if (s->srv)
1280 s->srv->counters.cli_aborts++;
Willy Tarreau05cb29b2008-12-14 11:44:04 +01001281 if (!(s->flags & SN_ERR_MASK))
1282 s->flags |= SN_ERR_CLICL;
1283 if (!(s->flags & SN_FINST_MASK))
1284 s->flags |= SN_FINST_D;
1285 }
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001286 }
1287 }
1288
1289 if (unlikely(s->si[1].flags & SI_FL_ERR)) {
1290 if (s->si[1].state == SI_ST_EST || s->si[1].state == SI_ST_DIS) {
1291 s->si[1].shutr(&s->si[1]);
1292 s->si[1].shutw(&s->si[1]);
1293 stream_int_report_error(&s->si[1]);
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +02001294 s->be->counters.failed_resp++;
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001295 if (s->srv)
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +02001296 s->srv->counters.failed_resp++;
Willy Tarreau05cb29b2008-12-14 11:44:04 +01001297 if (!(s->req->analysers) && !(s->rep->analysers)) {
Willy Tarreauae526782010-03-04 20:34:23 +01001298 s->be->counters.srv_aborts++;
1299 if (s->srv)
1300 s->srv->counters.srv_aborts++;
Willy Tarreau05cb29b2008-12-14 11:44:04 +01001301 if (!(s->flags & SN_ERR_MASK))
1302 s->flags |= SN_ERR_SRVCL;
1303 if (!(s->flags & SN_FINST_MASK))
1304 s->flags |= SN_FINST_D;
1305 }
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001306 }
1307 /* note: maybe we should process connection errors here ? */
1308 }
1309
1310 if (s->si[1].state == SI_ST_CON) {
1311 /* we were trying to establish a connection on the server side,
1312 * maybe it succeeded, maybe it failed, maybe we timed out, ...
1313 */
1314 if (unlikely(!sess_update_st_con_tcp(s, &s->si[1])))
1315 sess_update_st_cer(s, &s->si[1]);
1316 else if (s->si[1].state == SI_ST_EST)
1317 sess_establish(s, &s->si[1]);
1318
1319 /* state is now one of SI_ST_CON (still in progress), SI_ST_EST
1320 * (established), SI_ST_DIS (abort), SI_ST_CLO (last error),
1321 * SI_ST_ASS/SI_ST_TAR/SI_ST_REQ for retryable errors.
1322 */
1323 }
1324
Willy Tarreau815a9b22010-07-27 17:15:12 +02001325 rq_prod_last = s->si[0].state;
1326 rq_cons_last = s->si[1].state;
1327 rp_cons_last = s->si[0].state;
1328 rp_prod_last = s->si[1].state;
1329
1330 resync_stream_interface:
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001331 /* Check for connection closure */
1332
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001333 DPRINTF(stderr,
1334 "[%u] %s:%d: task=%p s=%p, sfl=0x%08x, rq=%p, rp=%p, exp(r,w)=%u,%u rqf=%08x rpf=%08x rql=%d rpl=%d cs=%d ss=%d, cet=0x%x set=0x%x retr=%d\n",
1335 now_ms, __FUNCTION__, __LINE__,
1336 t,
1337 s, s->flags,
1338 s->req, s->rep,
1339 s->req->rex, s->rep->wex,
1340 s->req->flags, s->rep->flags,
1341 s->req->l, s->rep->l, s->rep->cons->state, s->req->cons->state,
1342 s->rep->cons->err_type, s->req->cons->err_type,
Willy Tarreauee28de02010-06-01 09:51:00 +02001343 s->req->cons->conn_retries);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001344
1345 /* nothing special to be done on client side */
1346 if (unlikely(s->req->prod->state == SI_ST_DIS))
1347 s->req->prod->state = SI_ST_CLO;
1348
1349 /* When a server-side connection is released, we have to count it and
1350 * check for pending connections on this server.
1351 */
1352 if (unlikely(s->req->cons->state == SI_ST_DIS)) {
1353 s->req->cons->state = SI_ST_CLO;
1354 if (s->srv) {
1355 if (s->flags & SN_CURR_SESS) {
1356 s->flags &= ~SN_CURR_SESS;
1357 s->srv->cur_sess--;
1358 }
1359 sess_change_server(s, NULL);
1360 if (may_dequeue_tasks(s->srv, s->be))
1361 process_srv_queue(s->srv);
1362 }
1363 }
1364
1365 /*
1366 * Note: of the transient states (REQ, CER, DIS), only REQ may remain
1367 * at this point.
1368 */
1369
Willy Tarreau0be0ef92009-03-08 19:20:25 +01001370 resync_request:
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001371 /* Analyse request */
Willy Tarreau2f976e12010-11-11 14:28:47 +01001372 if (((s->req->flags & ~rqf_last) & BF_MASK_ANALYSER) ||
Willy Tarreau815a9b22010-07-27 17:15:12 +02001373 ((s->req->flags ^ rqf_last) & BF_MASK_STATIC) ||
1374 s->si[0].state != rq_prod_last ||
1375 s->si[1].state != rq_cons_last) {
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001376 unsigned int flags = s->req->flags;
1377
1378 if (s->req->prod->state >= SI_ST_EST) {
Willy Tarreaue34070e2010-01-08 00:32:27 +01001379 int max_loops = global.tune.maxpollevents;
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001380 unsigned int ana_list;
1381 unsigned int ana_back;
Willy Tarreau1a52dbd2009-06-28 19:37:53 +02001382
Willy Tarreau90deb182010-01-07 00:20:41 +01001383 /* it's up to the analysers to stop new connections,
1384 * disable reading or closing. Note: if an analyser
1385 * disables any of these bits, it is responsible for
1386 * enabling them again when it disables itself, so
1387 * that other analysers are called in similar conditions.
1388 */
1389 buffer_auto_read(s->req);
Willy Tarreau520d95e2009-09-19 21:04:57 +02001390 buffer_auto_connect(s->req);
1391 buffer_auto_close(s->req);
Willy Tarreauedcf6682008-11-30 23:15:34 +01001392
1393 /* We will call all analysers for which a bit is set in
1394 * s->req->analysers, following the bit order from LSB
1395 * to MSB. The analysers must remove themselves from
Willy Tarreau1a52dbd2009-06-28 19:37:53 +02001396 * the list when not needed. Any analyser may return 0
1397 * to break out of the loop, either because of missing
1398 * data to take a decision, or because it decides to
1399 * kill the session. We loop at least once through each
1400 * analyser, and we may loop again if other analysers
1401 * are added in the middle.
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001402 *
1403 * We build a list of analysers to run. We evaluate all
1404 * of these analysers in the order of the lower bit to
1405 * the higher bit. This ordering is very important.
1406 * An analyser will often add/remove other analysers,
1407 * including itself. Any changes to itself have no effect
1408 * on the loop. If it removes any other analysers, we
1409 * want those analysers not to be called anymore during
1410 * this loop. If it adds an analyser that is located
1411 * after itself, we want it to be scheduled for being
1412 * processed during the loop. If it adds an analyser
1413 * which is located before it, we want it to switch to
1414 * it immediately, even if it has already been called
1415 * once but removed since.
1416 *
1417 * In order to achieve this, we compare the analyser
1418 * list after the call with a copy of it before the
1419 * call. The work list is fed with analyser bits that
1420 * appeared during the call. Then we compare previous
1421 * work list with the new one, and check the bits that
1422 * appeared. If the lowest of these bits is lower than
1423 * the current bit, it means we have enabled a previous
1424 * analyser and must immediately loop again.
Willy Tarreauedcf6682008-11-30 23:15:34 +01001425 */
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001426
1427 ana_list = ana_back = s->req->analysers;
Willy Tarreaue34070e2010-01-08 00:32:27 +01001428 while (ana_list && max_loops--) {
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001429 /* Warning! ensure that analysers are always placed in ascending order! */
Willy Tarreau1a52dbd2009-06-28 19:37:53 +02001430
Willy Tarreau3041b9f2010-10-15 23:25:20 +02001431 if (ana_list & AN_REQ_DECODE_PROXY) {
1432 if (!frontend_decode_proxy_request(s, s->req, AN_REQ_DECODE_PROXY))
1433 break;
1434 UPDATE_ANALYSERS(s->req->analysers, ana_list, ana_back, AN_REQ_DECODE_PROXY);
1435 }
1436
Willy Tarreaufb356202010-08-03 14:02:05 +02001437 if (ana_list & AN_REQ_INSPECT_FE) {
1438 if (!tcp_inspect_request(s, s->req, AN_REQ_INSPECT_FE))
Willy Tarreauedcf6682008-11-30 23:15:34 +01001439 break;
Willy Tarreaufb356202010-08-03 14:02:05 +02001440 UPDATE_ANALYSERS(s->req->analysers, ana_list, ana_back, AN_REQ_INSPECT_FE);
Willy Tarreau1a52dbd2009-06-28 19:37:53 +02001441 }
Willy Tarreauedcf6682008-11-30 23:15:34 +01001442
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001443 if (ana_list & AN_REQ_WAIT_HTTP) {
Willy Tarreau3a816292009-07-07 10:55:49 +02001444 if (!http_wait_for_request(s, s->req, AN_REQ_WAIT_HTTP))
Willy Tarreaud787e662009-07-07 10:14:51 +02001445 break;
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001446 UPDATE_ANALYSERS(s->req->analysers, ana_list, ana_back, AN_REQ_WAIT_HTTP);
Willy Tarreaud787e662009-07-07 10:14:51 +02001447 }
1448
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001449 if (ana_list & AN_REQ_HTTP_PROCESS_FE) {
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02001450 if (!http_process_req_common(s, s->req, AN_REQ_HTTP_PROCESS_FE, s->fe))
1451 break;
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001452 UPDATE_ANALYSERS(s->req->analysers, ana_list, ana_back, AN_REQ_HTTP_PROCESS_FE);
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02001453 }
1454
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001455 if (ana_list & AN_REQ_SWITCHING_RULES) {
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02001456 if (!process_switching_rules(s, s->req, AN_REQ_SWITCHING_RULES))
1457 break;
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001458 UPDATE_ANALYSERS(s->req->analysers, ana_list, ana_back, AN_REQ_SWITCHING_RULES);
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02001459 }
1460
Willy Tarreaufb356202010-08-03 14:02:05 +02001461 if (ana_list & AN_REQ_INSPECT_BE) {
1462 if (!tcp_inspect_request(s, s->req, AN_REQ_INSPECT_BE))
1463 break;
1464 UPDATE_ANALYSERS(s->req->analysers, ana_list, ana_back, AN_REQ_INSPECT_BE);
1465 }
1466
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001467 if (ana_list & AN_REQ_HTTP_PROCESS_BE) {
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02001468 if (!http_process_req_common(s, s->req, AN_REQ_HTTP_PROCESS_BE, s->be))
1469 break;
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001470 UPDATE_ANALYSERS(s->req->analysers, ana_list, ana_back, AN_REQ_HTTP_PROCESS_BE);
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02001471 }
1472
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001473 if (ana_list & AN_REQ_HTTP_TARPIT) {
Willy Tarreau3a816292009-07-07 10:55:49 +02001474 if (!http_process_tarpit(s, s->req, AN_REQ_HTTP_TARPIT))
Willy Tarreau60b85b02008-11-30 23:28:40 +01001475 break;
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001476 UPDATE_ANALYSERS(s->req->analysers, ana_list, ana_back, AN_REQ_HTTP_TARPIT);
Willy Tarreau1a52dbd2009-06-28 19:37:53 +02001477 }
Willy Tarreau60b85b02008-11-30 23:28:40 +01001478
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001479 if (ana_list & AN_REQ_HTTP_INNER) {
Willy Tarreauc465fd72009-08-31 00:17:18 +02001480 if (!http_process_request(s, s->req, AN_REQ_HTTP_INNER))
1481 break;
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001482 UPDATE_ANALYSERS(s->req->analysers, ana_list, ana_back, AN_REQ_HTTP_INNER);
Willy Tarreauc465fd72009-08-31 00:17:18 +02001483 }
1484
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001485 if (ana_list & AN_REQ_HTTP_BODY) {
Willy Tarreau3a816292009-07-07 10:55:49 +02001486 if (!http_process_request_body(s, s->req, AN_REQ_HTTP_BODY))
Willy Tarreaud34af782008-11-30 23:36:37 +01001487 break;
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001488 UPDATE_ANALYSERS(s->req->analysers, ana_list, ana_back, AN_REQ_HTTP_BODY);
Willy Tarreau1a52dbd2009-06-28 19:37:53 +02001489 }
Emeric Brun647caf12009-06-30 17:57:00 +02001490
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001491 if (ana_list & AN_REQ_PRST_RDP_COOKIE) {
Emeric Brun647caf12009-06-30 17:57:00 +02001492 if (!tcp_persist_rdp_cookie(s, s->req, AN_REQ_PRST_RDP_COOKIE))
1493 break;
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001494 UPDATE_ANALYSERS(s->req->analysers, ana_list, ana_back, AN_REQ_PRST_RDP_COOKIE);
Emeric Brun647caf12009-06-30 17:57:00 +02001495 }
Willy Tarreaud98cf932009-12-27 22:54:55 +01001496
Emeric Brun1d33b292010-01-04 15:47:17 +01001497 if (ana_list & AN_REQ_STICKING_RULES) {
1498 if (!process_sticking_rules(s, s->req, AN_REQ_STICKING_RULES))
1499 break;
1500 UPDATE_ANALYSERS(s->req->analysers, ana_list, ana_back, AN_REQ_STICKING_RULES);
1501 }
1502
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001503 if (ana_list & AN_REQ_HTTP_XFER_BODY) {
Willy Tarreaud98cf932009-12-27 22:54:55 +01001504 if (!http_request_forward_body(s, s->req, AN_REQ_HTTP_XFER_BODY))
1505 break;
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001506 UPDATE_ANALYSERS(s->req->analysers, ana_list, ana_back, AN_REQ_HTTP_XFER_BODY);
Willy Tarreaud98cf932009-12-27 22:54:55 +01001507 }
Willy Tarreaue34070e2010-01-08 00:32:27 +01001508 break;
1509 }
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001510 }
Willy Tarreau84455332009-03-15 22:34:05 +01001511
Willy Tarreau815a9b22010-07-27 17:15:12 +02001512 rq_prod_last = s->si[0].state;
1513 rq_cons_last = s->si[1].state;
Willy Tarreau0499e352010-12-17 07:13:42 +01001514 s->req->flags &= ~BF_WAKE_ONCE;
Willy Tarreau815a9b22010-07-27 17:15:12 +02001515 rqf_last = s->req->flags;
1516
1517 if ((s->req->flags ^ flags) & BF_MASK_STATIC)
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001518 goto resync_request;
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001519 }
1520
Willy Tarreau576507f2010-01-07 00:09:04 +01001521 /* we'll monitor the request analysers while parsing the response,
1522 * because some response analysers may indirectly enable new request
1523 * analysers (eg: HTTP keep-alive).
1524 */
1525 req_ana_back = s->req->analysers;
1526
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001527 resync_response:
1528 /* Analyse response */
1529
1530 if (unlikely(s->rep->flags & BF_HIJACK)) {
1531 /* In inject mode, we wake up everytime something has
1532 * happened on the write side of the buffer.
1533 */
1534 unsigned int flags = s->rep->flags;
1535
1536 if ((s->rep->flags & (BF_WRITE_PARTIAL|BF_WRITE_ERROR|BF_SHUTW)) &&
1537 !(s->rep->flags & BF_FULL)) {
1538 s->rep->hijacker(s, s->rep);
1539 }
1540
1541 if ((s->rep->flags ^ flags) & BF_MASK_STATIC) {
1542 rpf_last = s->rep->flags;
1543 goto resync_response;
1544 }
1545 }
Willy Tarreau2f976e12010-11-11 14:28:47 +01001546 else if (((s->rep->flags & ~rpf_last) & BF_MASK_ANALYSER) ||
Willy Tarreau815a9b22010-07-27 17:15:12 +02001547 (s->rep->flags ^ rpf_last) & BF_MASK_STATIC ||
1548 s->si[0].state != rp_cons_last ||
1549 s->si[1].state != rp_prod_last) {
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001550 unsigned int flags = s->rep->flags;
1551
Willy Tarreau0499e352010-12-17 07:13:42 +01001552 if ((s->rep->flags & BF_MASK_ANALYSER) &&
1553 (s->rep->analysers & AN_REQ_WAIT_HTTP)) {
1554 /* Due to HTTP pipelining, the HTTP request analyser might be waiting
1555 * for some free space in the response buffer, so we might need to call
1556 * it when something changes in the response buffer, but still we pass
1557 * it the request buffer. Note that the SI state might very well still
1558 * be zero due to us returning a flow of redirects!
1559 */
1560 s->rep->analysers &= ~AN_REQ_WAIT_HTTP;
1561 s->req->flags |= BF_WAKE_ONCE;
1562 }
1563
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001564 if (s->rep->prod->state >= SI_ST_EST) {
Willy Tarreaue34070e2010-01-08 00:32:27 +01001565 int max_loops = global.tune.maxpollevents;
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001566 unsigned int ana_list;
1567 unsigned int ana_back;
Willy Tarreaub37c27e2009-10-18 22:53:08 +02001568
Willy Tarreau90deb182010-01-07 00:20:41 +01001569 /* it's up to the analysers to stop disable reading or
1570 * closing. Note: if an analyser disables any of these
1571 * bits, it is responsible for enabling them again when
1572 * it disables itself, so that other analysers are called
1573 * in similar conditions.
1574 */
1575 buffer_auto_read(s->rep);
Willy Tarreau520d95e2009-09-19 21:04:57 +02001576 buffer_auto_close(s->rep);
Willy Tarreaub37c27e2009-10-18 22:53:08 +02001577
1578 /* We will call all analysers for which a bit is set in
1579 * s->rep->analysers, following the bit order from LSB
1580 * to MSB. The analysers must remove themselves from
1581 * the list when not needed. Any analyser may return 0
1582 * to break out of the loop, either because of missing
1583 * data to take a decision, or because it decides to
1584 * kill the session. We loop at least once through each
1585 * analyser, and we may loop again if other analysers
1586 * are added in the middle.
1587 */
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001588
1589 ana_list = ana_back = s->rep->analysers;
Willy Tarreaue34070e2010-01-08 00:32:27 +01001590 while (ana_list && max_loops--) {
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001591 /* Warning! ensure that analysers are always placed in ascending order! */
1592
Emeric Brun97679e72010-09-23 17:56:44 +02001593 if (ana_list & AN_RES_INSPECT) {
1594 if (!tcp_inspect_response(s, s->rep, AN_RES_INSPECT))
1595 break;
1596 UPDATE_ANALYSERS(s->rep->analysers, ana_list, ana_back, AN_RES_INSPECT);
1597 }
1598
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001599 if (ana_list & AN_RES_WAIT_HTTP) {
Willy Tarreaub37c27e2009-10-18 22:53:08 +02001600 if (!http_wait_for_response(s, s->rep, AN_RES_WAIT_HTTP))
1601 break;
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001602 UPDATE_ANALYSERS(s->rep->analysers, ana_list, ana_back, AN_RES_WAIT_HTTP);
Willy Tarreaub37c27e2009-10-18 22:53:08 +02001603 }
1604
Emeric Brun1d33b292010-01-04 15:47:17 +01001605 if (ana_list & AN_RES_STORE_RULES) {
1606 if (!process_store_rules(s, s->rep, AN_RES_STORE_RULES))
1607 break;
1608 UPDATE_ANALYSERS(s->rep->analysers, ana_list, ana_back, AN_RES_STORE_RULES);
1609 }
1610
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001611 if (ana_list & AN_RES_HTTP_PROCESS_BE) {
Willy Tarreaub37c27e2009-10-18 22:53:08 +02001612 if (!http_process_res_common(s, s->rep, AN_RES_HTTP_PROCESS_BE, s->be))
1613 break;
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001614 UPDATE_ANALYSERS(s->rep->analysers, ana_list, ana_back, AN_RES_HTTP_PROCESS_BE);
Willy Tarreaub37c27e2009-10-18 22:53:08 +02001615 }
Willy Tarreaud98cf932009-12-27 22:54:55 +01001616
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001617 if (ana_list & AN_RES_HTTP_XFER_BODY) {
Willy Tarreaud98cf932009-12-27 22:54:55 +01001618 if (!http_response_forward_body(s, s->rep, AN_RES_HTTP_XFER_BODY))
1619 break;
Willy Tarreau1e0bbaf2010-01-06 23:53:24 +01001620 UPDATE_ANALYSERS(s->rep->analysers, ana_list, ana_back, AN_RES_HTTP_XFER_BODY);
Willy Tarreaud98cf932009-12-27 22:54:55 +01001621 }
Willy Tarreaue34070e2010-01-08 00:32:27 +01001622 break;
1623 }
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001624 }
1625
Willy Tarreau815a9b22010-07-27 17:15:12 +02001626 rp_cons_last = s->si[0].state;
1627 rp_prod_last = s->si[1].state;
1628 rpf_last = s->rep->flags;
1629
1630 if ((s->rep->flags ^ flags) & BF_MASK_STATIC)
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001631 goto resync_response;
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001632 }
1633
Willy Tarreau576507f2010-01-07 00:09:04 +01001634 /* maybe someone has added some request analysers, so we must check and loop */
1635 if (s->req->analysers & ~req_ana_back)
1636 goto resync_request;
1637
Willy Tarreau0499e352010-12-17 07:13:42 +01001638 if ((s->req->flags & ~rqf_last) & BF_MASK_ANALYSER)
1639 goto resync_request;
1640
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001641 /* FIXME: here we should call protocol handlers which rely on
1642 * both buffers.
1643 */
1644
1645
1646 /*
Willy Tarreauae526782010-03-04 20:34:23 +01001647 * Now we propagate unhandled errors to the session. Normally
1648 * we're just in a data phase here since it means we have not
1649 * seen any analyser who could set an error status.
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001650 */
Willy Tarreau2f976e12010-11-11 14:28:47 +01001651 if (unlikely(!(s->flags & SN_ERR_MASK))) {
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001652 if (s->req->flags & (BF_READ_ERROR|BF_READ_TIMEOUT|BF_WRITE_ERROR|BF_WRITE_TIMEOUT)) {
1653 /* Report it if the client got an error or a read timeout expired */
Willy Tarreau84455332009-03-15 22:34:05 +01001654 s->req->analysers = 0;
Willy Tarreauae526782010-03-04 20:34:23 +01001655 if (s->req->flags & BF_READ_ERROR) {
1656 s->be->counters.cli_aborts++;
1657 if (s->srv)
1658 s->srv->counters.cli_aborts++;
Willy Tarreau84455332009-03-15 22:34:05 +01001659 s->flags |= SN_ERR_CLICL;
Willy Tarreauae526782010-03-04 20:34:23 +01001660 }
1661 else if (s->req->flags & BF_READ_TIMEOUT) {
1662 s->be->counters.cli_aborts++;
1663 if (s->srv)
1664 s->srv->counters.cli_aborts++;
Willy Tarreau84455332009-03-15 22:34:05 +01001665 s->flags |= SN_ERR_CLITO;
Willy Tarreauae526782010-03-04 20:34:23 +01001666 }
1667 else if (s->req->flags & BF_WRITE_ERROR) {
1668 s->be->counters.srv_aborts++;
1669 if (s->srv)
1670 s->srv->counters.srv_aborts++;
Willy Tarreau84455332009-03-15 22:34:05 +01001671 s->flags |= SN_ERR_SRVCL;
Willy Tarreauae526782010-03-04 20:34:23 +01001672 }
1673 else {
1674 s->be->counters.srv_aborts++;
1675 if (s->srv)
1676 s->srv->counters.srv_aborts++;
Willy Tarreau84455332009-03-15 22:34:05 +01001677 s->flags |= SN_ERR_SRVTO;
Willy Tarreauae526782010-03-04 20:34:23 +01001678 }
Willy Tarreau84455332009-03-15 22:34:05 +01001679 sess_set_term_flags(s);
1680 }
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001681 else if (s->rep->flags & (BF_READ_ERROR|BF_READ_TIMEOUT|BF_WRITE_ERROR|BF_WRITE_TIMEOUT)) {
1682 /* Report it if the server got an error or a read timeout expired */
1683 s->rep->analysers = 0;
Willy Tarreauae526782010-03-04 20:34:23 +01001684 if (s->rep->flags & BF_READ_ERROR) {
1685 s->be->counters.srv_aborts++;
1686 if (s->srv)
1687 s->srv->counters.srv_aborts++;
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001688 s->flags |= SN_ERR_SRVCL;
Willy Tarreauae526782010-03-04 20:34:23 +01001689 }
1690 else if (s->rep->flags & BF_READ_TIMEOUT) {
1691 s->be->counters.srv_aborts++;
1692 if (s->srv)
1693 s->srv->counters.srv_aborts++;
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001694 s->flags |= SN_ERR_SRVTO;
Willy Tarreauae526782010-03-04 20:34:23 +01001695 }
1696 else if (s->rep->flags & BF_WRITE_ERROR) {
1697 s->be->counters.cli_aborts++;
1698 if (s->srv)
1699 s->srv->counters.cli_aborts++;
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001700 s->flags |= SN_ERR_CLICL;
Willy Tarreauae526782010-03-04 20:34:23 +01001701 }
1702 else {
1703 s->be->counters.cli_aborts++;
1704 if (s->srv)
1705 s->srv->counters.cli_aborts++;
1706 s->flags |= SN_ERR_CLITO;
1707 }
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001708 sess_set_term_flags(s);
1709 }
Willy Tarreau84455332009-03-15 22:34:05 +01001710 }
1711
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001712 /*
1713 * Here we take care of forwarding unhandled data. This also includes
1714 * connection establishments and shutdown requests.
1715 */
1716
1717
Willy Tarreau7c84bab2009-03-08 21:38:23 +01001718 /* If noone is interested in analysing data, it's time to forward
Willy Tarreau31971e52009-09-20 12:07:52 +02001719 * everything. We configure the buffer to forward indefinitely.
Willy Tarreauda4d9fe2010-11-07 20:26:56 +01001720 * Note that we're checking BF_SHUTR_NOW as an indication of a possible
1721 * recent call to buffer_abort().
Willy Tarreau6b66f3e2008-12-14 17:31:54 +01001722 */
Willy Tarreau7c84bab2009-03-08 21:38:23 +01001723 if (!s->req->analysers &&
Willy Tarreauda4d9fe2010-11-07 20:26:56 +01001724 !(s->req->flags & (BF_HIJACK|BF_SHUTW|BF_SHUTR_NOW)) &&
Willy Tarreau31971e52009-09-20 12:07:52 +02001725 (s->req->prod->state >= SI_ST_EST) &&
1726 (s->req->to_forward != BUF_INFINITE_FORWARD)) {
Willy Tarreau7c84bab2009-03-08 21:38:23 +01001727 /* This buffer is freewheeling, there's no analyser nor hijacker
1728 * attached to it. If any data are left in, we'll permit them to
1729 * move.
1730 */
Willy Tarreau90deb182010-01-07 00:20:41 +01001731 buffer_auto_read(s->req);
Willy Tarreau520d95e2009-09-19 21:04:57 +02001732 buffer_auto_connect(s->req);
1733 buffer_auto_close(s->req);
Willy Tarreau7c84bab2009-03-08 21:38:23 +01001734 buffer_flush(s->req);
Willy Tarreau5bd8c372009-01-19 00:32:22 +01001735
Willy Tarreauda4d9fe2010-11-07 20:26:56 +01001736 /* We'll let data flow between the producer (if still connected)
1737 * to the consumer (which might possibly not be connected yet).
Willy Tarreau7c84bab2009-03-08 21:38:23 +01001738 */
Willy Tarreauda4d9fe2010-11-07 20:26:56 +01001739 if (!(s->req->flags & (BF_SHUTR|BF_SHUTW_NOW)))
Willy Tarreau31971e52009-09-20 12:07:52 +02001740 buffer_forward(s->req, BUF_INFINITE_FORWARD);
Willy Tarreau6b66f3e2008-12-14 17:31:54 +01001741 }
Willy Tarreauf890dc92008-12-13 21:12:26 +01001742
Willy Tarreau7c84bab2009-03-08 21:38:23 +01001743 /* check if it is wise to enable kernel splicing to forward request data */
1744 if (!(s->req->flags & (BF_KERN_SPLICING|BF_SHUTR)) &&
1745 s->req->to_forward &&
1746 (global.tune.options & GTUNE_USE_SPLICE) &&
Willy Tarreaudc340a92009-06-28 23:10:19 +02001747 (s->si[0].flags & s->si[1].flags & SI_FL_CAP_SPLICE) &&
Willy Tarreau7c84bab2009-03-08 21:38:23 +01001748 (pipes_used < global.maxpipes) &&
1749 (((s->fe->options2|s->be->options2) & PR_O2_SPLIC_REQ) ||
1750 (((s->fe->options2|s->be->options2) & PR_O2_SPLIC_AUT) &&
1751 (s->req->flags & BF_STREAMER_FAST)))) {
1752 s->req->flags |= BF_KERN_SPLICING;
1753 }
1754
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001755 /* reflect what the L7 analysers have seen last */
1756 rqf_last = s->req->flags;
1757
1758 /*
1759 * Now forward all shutdown requests between both sides of the buffer
1760 */
1761
Willy Tarreau520d95e2009-09-19 21:04:57 +02001762 /* first, let's check if the request buffer needs to shutdown(write), which may
1763 * happen either because the input is closed or because we want to force a close
Willy Tarreaue4599762010-03-21 23:25:09 +01001764 * once the server has begun to respond.
Willy Tarreau520d95e2009-09-19 21:04:57 +02001765 */
Willy Tarreau82eeaf22009-12-29 12:09:05 +01001766 if (unlikely((s->req->flags & (BF_SHUTW|BF_SHUTW_NOW|BF_HIJACK|BF_AUTO_CLOSE|BF_SHUTR)) ==
Willy Tarreaue4599762010-03-21 23:25:09 +01001767 (BF_AUTO_CLOSE|BF_SHUTR)))
Willy Tarreauba0b63d2009-09-20 08:09:44 +02001768 buffer_shutw_now(s->req);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001769
1770 /* shutdown(write) pending */
Willy Tarreauba0b63d2009-09-20 08:09:44 +02001771 if (unlikely((s->req->flags & (BF_SHUTW|BF_SHUTW_NOW|BF_OUT_EMPTY)) == (BF_SHUTW_NOW|BF_OUT_EMPTY)))
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001772 s->req->cons->shutw(s->req->cons);
1773
1774 /* shutdown(write) done on server side, we must stop the client too */
Willy Tarreau3dbc6942008-12-07 13:05:04 +01001775 if (unlikely((s->req->flags & (BF_SHUTW|BF_SHUTR|BF_SHUTR_NOW)) == BF_SHUTW &&
1776 !s->req->analysers))
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001777 buffer_shutr_now(s->req);
1778
1779 /* shutdown(read) pending */
1780 if (unlikely((s->req->flags & (BF_SHUTR|BF_SHUTR_NOW)) == BF_SHUTR_NOW))
1781 s->req->prod->shutr(s->req->prod);
1782
Willy Tarreau520d95e2009-09-19 21:04:57 +02001783 /* it's possible that an upper layer has requested a connection setup or abort.
1784 * There are 2 situations where we decide to establish a new connection :
1785 * - there are data scheduled for emission in the buffer
1786 * - the BF_AUTO_CONNECT flag is set (active connection)
1787 */
1788 if (s->req->cons->state == SI_ST_INI) {
Willy Tarreaue4599762010-03-21 23:25:09 +01001789 if (!(s->req->flags & BF_SHUTW)) {
Willy Tarreauba0b63d2009-09-20 08:09:44 +02001790 if ((s->req->flags & (BF_AUTO_CONNECT|BF_OUT_EMPTY)) != BF_OUT_EMPTY) {
Willy Tarreaub24281b2011-02-13 13:16:36 +01001791 /* If we have an applet without a connect method, we immediately
Willy Tarreau85e7d002010-05-31 11:57:51 +02001792 * switch to the connected state, otherwise we perform a connection
1793 * request.
Willy Tarreau520d95e2009-09-19 21:04:57 +02001794 */
Willy Tarreau85e7d002010-05-31 11:57:51 +02001795 s->req->cons->state = SI_ST_REQ; /* new connection requested */
Willy Tarreau070ceb62010-06-01 10:36:43 +02001796 s->req->cons->conn_retries = s->be->conn_retries;
Willy Tarreau7c0a1512011-03-10 11:17:02 +01001797 if (unlikely(s->req->cons->target.type == TARG_TYPE_APPLET && !s->req->cons->connect)) {
Willy Tarreau520d95e2009-09-19 21:04:57 +02001798 s->req->cons->state = SI_ST_EST; /* connection established */
Willy Tarreau85e7d002010-05-31 11:57:51 +02001799 s->rep->flags |= BF_READ_ATTACHED; /* producer is now attached */
1800 s->req->wex = TICK_ETERNITY;
1801 }
Willy Tarreau520d95e2009-09-19 21:04:57 +02001802 }
Willy Tarreau73201222009-08-16 18:27:24 +02001803 }
Willy Tarreauf41ffdc2009-09-20 08:19:25 +02001804 else {
Willy Tarreau92795622009-03-06 12:51:23 +01001805 s->req->cons->state = SI_ST_CLO; /* shutw+ini = abort */
Willy Tarreauf41ffdc2009-09-20 08:19:25 +02001806 buffer_shutw_now(s->req); /* fix buffer flags upon abort */
1807 buffer_shutr_now(s->rep);
1808 }
Willy Tarreau92795622009-03-06 12:51:23 +01001809 }
1810
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001811
1812 /* we may have a pending connection request, or a connection waiting
1813 * for completion.
1814 */
1815 if (s->si[1].state >= SI_ST_REQ && s->si[1].state < SI_ST_CON) {
1816 do {
1817 /* nb: step 1 might switch from QUE to ASS, but we first want
1818 * to give a chance to step 2 to perform a redirect if needed.
1819 */
1820 if (s->si[1].state != SI_ST_REQ)
1821 sess_update_stream_int(s, &s->si[1]);
1822 if (s->si[1].state == SI_ST_REQ)
1823 sess_prepare_conn_req(s, &s->si[1]);
1824
1825 if (s->si[1].state == SI_ST_ASS && s->srv &&
1826 s->srv->rdr_len && (s->flags & SN_REDIRECTABLE))
1827 perform_http_redirect(s, &s->si[1]);
1828 } while (s->si[1].state == SI_ST_ASS);
1829 }
1830
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001831 /* Benchmarks have shown that it's optimal to do a full resync now */
Willy Tarreau0be0ef92009-03-08 19:20:25 +01001832 if (s->req->prod->state == SI_ST_DIS || s->req->cons->state == SI_ST_DIS)
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001833 goto resync_stream_interface;
1834
Willy Tarreau815a9b22010-07-27 17:15:12 +02001835 /* otherwise we want to check if we need to resync the req buffer or not */
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001836 if ((s->req->flags ^ rqf_last) & BF_MASK_STATIC)
Willy Tarreau0be0ef92009-03-08 19:20:25 +01001837 goto resync_request;
1838
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001839 /* perform output updates to the response buffer */
Willy Tarreau84455332009-03-15 22:34:05 +01001840
Willy Tarreau7c84bab2009-03-08 21:38:23 +01001841 /* If noone is interested in analysing data, it's time to forward
Willy Tarreau31971e52009-09-20 12:07:52 +02001842 * everything. We configure the buffer to forward indefinitely.
Willy Tarreauda4d9fe2010-11-07 20:26:56 +01001843 * Note that we're checking BF_SHUTR_NOW as an indication of a possible
1844 * recent call to buffer_abort().
Willy Tarreau6b66f3e2008-12-14 17:31:54 +01001845 */
Willy Tarreau7c84bab2009-03-08 21:38:23 +01001846 if (!s->rep->analysers &&
Willy Tarreauda4d9fe2010-11-07 20:26:56 +01001847 !(s->rep->flags & (BF_HIJACK|BF_SHUTW|BF_SHUTR_NOW)) &&
Willy Tarreau31971e52009-09-20 12:07:52 +02001848 (s->rep->prod->state >= SI_ST_EST) &&
1849 (s->rep->to_forward != BUF_INFINITE_FORWARD)) {
Willy Tarreau7c84bab2009-03-08 21:38:23 +01001850 /* This buffer is freewheeling, there's no analyser nor hijacker
1851 * attached to it. If any data are left in, we'll permit them to
1852 * move.
1853 */
Willy Tarreau90deb182010-01-07 00:20:41 +01001854 buffer_auto_read(s->rep);
Willy Tarreau520d95e2009-09-19 21:04:57 +02001855 buffer_auto_close(s->rep);
Willy Tarreau7c84bab2009-03-08 21:38:23 +01001856 buffer_flush(s->rep);
Willy Tarreauda4d9fe2010-11-07 20:26:56 +01001857
1858 /* We'll let data flow between the producer (if still connected)
1859 * to the consumer.
1860 */
1861 if (!(s->rep->flags & (BF_SHUTR|BF_SHUTW_NOW)))
Willy Tarreau31971e52009-09-20 12:07:52 +02001862 buffer_forward(s->rep, BUF_INFINITE_FORWARD);
Willy Tarreau6b66f3e2008-12-14 17:31:54 +01001863 }
Willy Tarreauf890dc92008-12-13 21:12:26 +01001864
Willy Tarreau7c84bab2009-03-08 21:38:23 +01001865 /* check if it is wise to enable kernel splicing to forward response data */
1866 if (!(s->rep->flags & (BF_KERN_SPLICING|BF_SHUTR)) &&
1867 s->rep->to_forward &&
1868 (global.tune.options & GTUNE_USE_SPLICE) &&
Willy Tarreaudc340a92009-06-28 23:10:19 +02001869 (s->si[0].flags & s->si[1].flags & SI_FL_CAP_SPLICE) &&
Willy Tarreau7c84bab2009-03-08 21:38:23 +01001870 (pipes_used < global.maxpipes) &&
1871 (((s->fe->options2|s->be->options2) & PR_O2_SPLIC_RTR) ||
1872 (((s->fe->options2|s->be->options2) & PR_O2_SPLIC_AUT) &&
1873 (s->rep->flags & BF_STREAMER_FAST)))) {
1874 s->rep->flags |= BF_KERN_SPLICING;
1875 }
1876
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001877 /* reflect what the L7 analysers have seen last */
1878 rpf_last = s->rep->flags;
1879
1880 /*
1881 * Now forward all shutdown requests between both sides of the buffer
1882 */
1883
1884 /*
1885 * FIXME: this is probably where we should produce error responses.
1886 */
1887
Willy Tarreau6b66f3e2008-12-14 17:31:54 +01001888 /* first, let's check if the response buffer needs to shutdown(write) */
Willy Tarreau520d95e2009-09-19 21:04:57 +02001889 if (unlikely((s->rep->flags & (BF_SHUTW|BF_SHUTW_NOW|BF_HIJACK|BF_AUTO_CLOSE|BF_SHUTR)) ==
1890 (BF_AUTO_CLOSE|BF_SHUTR)))
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001891 buffer_shutw_now(s->rep);
1892
1893 /* shutdown(write) pending */
Willy Tarreauba0b63d2009-09-20 08:09:44 +02001894 if (unlikely((s->rep->flags & (BF_SHUTW|BF_OUT_EMPTY|BF_SHUTW_NOW)) == (BF_OUT_EMPTY|BF_SHUTW_NOW)))
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001895 s->rep->cons->shutw(s->rep->cons);
1896
1897 /* shutdown(write) done on the client side, we must stop the server too */
Willy Tarreau3dbc6942008-12-07 13:05:04 +01001898 if (unlikely((s->rep->flags & (BF_SHUTW|BF_SHUTR|BF_SHUTR_NOW)) == BF_SHUTW) &&
1899 !s->rep->analysers)
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001900 buffer_shutr_now(s->rep);
1901
1902 /* shutdown(read) pending */
1903 if (unlikely((s->rep->flags & (BF_SHUTR|BF_SHUTR_NOW)) == BF_SHUTR_NOW))
1904 s->rep->prod->shutr(s->rep->prod);
1905
Willy Tarreau0be0ef92009-03-08 19:20:25 +01001906 if (s->req->prod->state == SI_ST_DIS || s->req->cons->state == SI_ST_DIS)
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001907 goto resync_stream_interface;
1908
Willy Tarreau0be0ef92009-03-08 19:20:25 +01001909 if (s->req->flags != rqf_last)
1910 goto resync_request;
1911
Willy Tarreau3deb3d02009-06-21 22:43:05 +02001912 if ((s->rep->flags ^ rpf_last) & BF_MASK_STATIC)
Willy Tarreau0be0ef92009-03-08 19:20:25 +01001913 goto resync_response;
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001914
Willy Tarreau89f7ef22009-09-05 20:57:35 +02001915 /* we're interested in getting wakeups again */
1916 s->req->prod->flags &= ~SI_FL_DONT_WAKE;
1917 s->req->cons->flags &= ~SI_FL_DONT_WAKE;
1918
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001919 /* This is needed only when debugging is enabled, to indicate
1920 * client-side or server-side close. Please note that in the unlikely
1921 * event where both sides would close at once, the sequence is reported
1922 * on the server side first.
1923 */
1924 if (unlikely((global.mode & MODE_DEBUG) &&
1925 (!(global.mode & MODE_QUIET) ||
1926 (global.mode & MODE_VERBOSE)))) {
1927 int len;
1928
1929 if (s->si[1].state == SI_ST_CLO &&
1930 s->si[1].prev_state == SI_ST_EST) {
1931 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n",
1932 s->uniq_id, s->be->id,
1933 (unsigned short)s->si[0].fd,
1934 (unsigned short)s->si[1].fd);
1935 write(1, trash, len);
1936 }
1937
1938 if (s->si[0].state == SI_ST_CLO &&
1939 s->si[0].prev_state == SI_ST_EST) {
1940 len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n",
1941 s->uniq_id, s->be->id,
1942 (unsigned short)s->si[0].fd,
1943 (unsigned short)s->si[1].fd);
1944 write(1, trash, len);
1945 }
1946 }
1947
1948 if (likely((s->rep->cons->state != SI_ST_CLO) ||
1949 (s->req->cons->state > SI_ST_INI && s->req->cons->state < SI_ST_CLO))) {
1950
1951 if ((s->fe->options & PR_O_CONTSTATS) && (s->flags & SN_BE_ASSIGNED))
1952 session_process_counters(s);
1953
Willy Tarreau7c0a1512011-03-10 11:17:02 +01001954 if (s->rep->cons->state == SI_ST_EST && s->rep->cons->target.type != TARG_TYPE_APPLET)
Willy Tarreaudc85b392009-08-18 07:38:19 +02001955 s->rep->cons->update(s->rep->cons);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001956
Willy Tarreau7c0a1512011-03-10 11:17:02 +01001957 if (s->req->cons->state == SI_ST_EST && s->req->cons->target.type != TARG_TYPE_APPLET)
Willy Tarreaudc85b392009-08-18 07:38:19 +02001958 s->req->cons->update(s->req->cons);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001959
Willy Tarreaua6eebb32010-06-04 11:40:20 +02001960 s->req->flags &= ~(BF_READ_NULL|BF_READ_PARTIAL|BF_WRITE_NULL|BF_WRITE_PARTIAL|BF_READ_ATTACHED);
1961 s->rep->flags &= ~(BF_READ_NULL|BF_READ_PARTIAL|BF_WRITE_NULL|BF_WRITE_PARTIAL|BF_READ_ATTACHED);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001962 s->si[0].prev_state = s->si[0].state;
1963 s->si[1].prev_state = s->si[1].state;
Willy Tarreaub0ef7352008-12-14 13:26:20 +01001964 s->si[0].flags &= ~(SI_FL_ERR|SI_FL_EXP);
1965 s->si[1].flags &= ~(SI_FL_ERR|SI_FL_EXP);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001966
1967 /* Trick: if a request is being waiting for the server to respond,
1968 * and if we know the server can timeout, we don't want the timeout
1969 * to expire on the client side first, but we're still interested
1970 * in passing data from the client to the server (eg: POST). Thus,
1971 * we can cancel the client's request timeout if the server's
1972 * request timeout is set and the server has not yet sent a response.
1973 */
1974
Willy Tarreau520d95e2009-09-19 21:04:57 +02001975 if ((s->rep->flags & (BF_AUTO_CLOSE|BF_SHUTR)) == 0 &&
Willy Tarreau86491c32008-12-14 09:04:47 +01001976 (tick_isset(s->req->wex) || tick_isset(s->rep->rex))) {
1977 s->req->flags |= BF_READ_NOEXP;
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001978 s->req->rex = TICK_ETERNITY;
Willy Tarreau86491c32008-12-14 09:04:47 +01001979 }
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001980
Willy Tarreau7a20aa62010-07-13 16:30:45 +02001981 /* Call the stream interfaces' I/O handlers when embedded.
Willy Tarreau1accfc02009-09-05 20:57:35 +02001982 * Note that this one may wake the task up again.
1983 */
Willy Tarreau7c0a1512011-03-10 11:17:02 +01001984 if (s->req->cons->target.type == TARG_TYPE_APPLET ||
1985 s->rep->cons->target.type == TARG_TYPE_APPLET) {
1986 if (s->req->cons->target.type == TARG_TYPE_APPLET)
1987 s->req->cons->target.ptr.a->fct(s->req->cons);
1988 if (s->rep->cons->target.type == TARG_TYPE_APPLET)
1989 s->rep->cons->target.ptr.a->fct(s->rep->cons);
Willy Tarreau1accfc02009-09-05 20:57:35 +02001990 if (task_in_rq(t)) {
1991 /* If we woke up, we don't want to requeue the
1992 * task to the wait queue, but rather requeue
1993 * it into the runqueue ASAP.
1994 */
1995 t->expire = TICK_ETERNITY;
1996 return t;
1997 }
1998 }
1999
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01002000 t->expire = tick_first(tick_first(s->req->rex, s->req->wex),
2001 tick_first(s->rep->rex, s->rep->wex));
2002 if (s->req->analysers)
2003 t->expire = tick_first(t->expire, s->req->analyse_exp);
2004
2005 if (s->si[0].exp)
2006 t->expire = tick_first(t->expire, s->si[0].exp);
2007
2008 if (s->si[1].exp)
2009 t->expire = tick_first(t->expire, s->si[1].exp);
2010
2011#ifdef DEBUG_FULL
Willy Tarreau127334e2009-03-28 10:47:26 +01002012 fprintf(stderr,
2013 "[%u] queuing with exp=%u req->rex=%u req->wex=%u req->ana_exp=%u"
2014 " rep->rex=%u rep->wex=%u, si[0].exp=%u, si[1].exp=%u, cs=%d, ss=%d\n",
2015 now_ms, t->expire, s->req->rex, s->req->wex, s->req->analyse_exp,
2016 s->rep->rex, s->rep->wex, s->si[0].exp, s->si[1].exp, s->si[0].state, s->si[1].state);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01002017#endif
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01002018
2019#ifdef DEBUG_DEV
2020 /* this may only happen when no timeout is set or in case of an FSM bug */
Willy Tarreaud0a201b2009-03-08 15:53:06 +01002021 if (!tick_isset(t->expire))
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01002022 ABORT_NOW();
2023#endif
Willy Tarreau26c25062009-03-08 09:38:41 +01002024 return t; /* nothing more to do */
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01002025 }
2026
2027 s->fe->feconn--;
2028 if (s->flags & SN_BE_ASSIGNED)
2029 s->be->beconn--;
2030 actconn--;
Willy Tarreauaf7ad002010-08-31 15:39:26 +02002031 jobs--;
Willy Tarreau6e6fb2b2009-08-16 18:20:44 +02002032 s->listener->nbconn--;
2033 if (s->listener->state == LI_FULL &&
2034 s->listener->nbconn < s->listener->maxconn) {
2035 /* we should reactivate the listener */
2036 EV_FD_SET(s->listener->fd, DIR_RD);
2037 s->listener->state = LI_READY;
2038 }
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01002039
2040 if (unlikely((global.mode & MODE_DEBUG) &&
2041 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
2042 int len;
Willy Tarreauec22b2c2009-03-06 13:07:40 +01002043 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01002044 s->uniq_id, s->be->id,
Willy Tarreauec22b2c2009-03-06 13:07:40 +01002045 (unsigned short)s->req->prod->fd, (unsigned short)s->req->cons->fd);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01002046 write(1, trash, len);
2047 }
2048
2049 s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
2050 session_process_counters(s);
2051
Krzysztof Piotr Oledzkide71d162009-10-24 15:36:15 +02002052 if (s->txn.status) {
2053 int n;
2054
2055 n = s->txn.status / 100;
2056 if (n < 1 || n > 5)
2057 n = 0;
2058
2059 if (s->fe->mode == PR_MODE_HTTP)
Willy Tarreau24657792010-02-26 10:30:28 +01002060 s->fe->counters.fe.http.rsp[n]++;
Krzysztof Piotr Oledzkide71d162009-10-24 15:36:15 +02002061
Willy Tarreau24657792010-02-26 10:30:28 +01002062 if ((s->flags & SN_BE_ASSIGNED) &&
Krzysztof Piotr Oledzkide71d162009-10-24 15:36:15 +02002063 (s->be->mode == PR_MODE_HTTP))
Willy Tarreau24657792010-02-26 10:30:28 +01002064 s->be->counters.be.http.rsp[n]++;
Krzysztof Piotr Oledzkide71d162009-10-24 15:36:15 +02002065 }
2066
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01002067 /* let's do a final log if we need it */
2068 if (s->logs.logwait &&
2069 !(s->flags & SN_MONITOR) &&
2070 (!(s->fe->options & PR_O_NULLNOLOG) || s->req->total)) {
Willy Tarreaua5555ec2008-11-30 19:02:32 +01002071 s->do_log(s);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01002072 }
2073
2074 /* the task MUST not be in the run queue anymore */
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01002075 session_free(s);
Willy Tarreau26c25062009-03-08 09:38:41 +01002076 task_delete(t);
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01002077 task_free(t);
Willy Tarreau26c25062009-03-08 09:38:41 +01002078 return NULL;
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01002079}
2080
Willy Tarreau7c669d72008-06-20 15:04:11 +02002081/*
2082 * This function adjusts sess->srv_conn and maintains the previous and new
2083 * server's served session counts. Setting newsrv to NULL is enough to release
2084 * current connection slot. This function also notifies any LB algo which might
2085 * expect to be informed about any change in the number of active sessions on a
2086 * server.
2087 */
2088void sess_change_server(struct session *sess, struct server *newsrv)
2089{
2090 if (sess->srv_conn == newsrv)
2091 return;
2092
2093 if (sess->srv_conn) {
2094 sess->srv_conn->served--;
2095 if (sess->srv_conn->proxy->lbprm.server_drop_conn)
2096 sess->srv_conn->proxy->lbprm.server_drop_conn(sess->srv_conn);
2097 sess->srv_conn = NULL;
2098 }
2099
2100 if (newsrv) {
2101 newsrv->served++;
2102 if (newsrv->proxy->lbprm.server_take_conn)
2103 newsrv->proxy->lbprm.server_take_conn(newsrv);
2104 sess->srv_conn = newsrv;
2105 }
2106}
2107
Willy Tarreau84455332009-03-15 22:34:05 +01002108/* Set correct session termination flags in case no analyser has done it. It
2109 * also counts a failed request if the server state has not reached the request
2110 * stage.
2111 */
2112void sess_set_term_flags(struct session *s)
2113{
2114 if (!(s->flags & SN_FINST_MASK)) {
2115 if (s->si[1].state < SI_ST_REQ) {
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02002116
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +02002117 s->fe->counters.failed_req++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02002118 if (s->listener->counters)
2119 s->listener->counters->failed_req++;
2120
Willy Tarreau84455332009-03-15 22:34:05 +01002121 s->flags |= SN_FINST_R;
2122 }
2123 else if (s->si[1].state == SI_ST_QUE)
2124 s->flags |= SN_FINST_Q;
2125 else if (s->si[1].state < SI_ST_EST)
2126 s->flags |= SN_FINST_C;
Willy Tarreau033b2db2010-03-04 17:54:21 +01002127 else if (s->si[1].state == SI_ST_EST || s->si[1].prev_state == SI_ST_EST)
Willy Tarreau84455332009-03-15 22:34:05 +01002128 s->flags |= SN_FINST_D;
2129 else
2130 s->flags |= SN_FINST_L;
2131 }
2132}
2133
2134/* Handle server-side errors for default protocols. It is called whenever a a
2135 * connection setup is aborted or a request is aborted in queue. It sets the
2136 * session termination flags so that the caller does not have to worry about
2137 * them. It's installed as ->srv_error for the server-side stream_interface.
2138 */
2139void default_srv_error(struct session *s, struct stream_interface *si)
2140{
2141 int err_type = si->err_type;
2142 int err = 0, fin = 0;
2143
2144 if (err_type & SI_ET_QUEUE_ABRT) {
2145 err = SN_ERR_CLICL;
2146 fin = SN_FINST_Q;
2147 }
2148 else if (err_type & SI_ET_CONN_ABRT) {
2149 err = SN_ERR_CLICL;
2150 fin = SN_FINST_C;
2151 }
2152 else if (err_type & SI_ET_QUEUE_TO) {
2153 err = SN_ERR_SRVTO;
2154 fin = SN_FINST_Q;
2155 }
2156 else if (err_type & SI_ET_QUEUE_ERR) {
2157 err = SN_ERR_SRVCL;
2158 fin = SN_FINST_Q;
2159 }
2160 else if (err_type & SI_ET_CONN_TO) {
2161 err = SN_ERR_SRVTO;
2162 fin = SN_FINST_C;
2163 }
2164 else if (err_type & SI_ET_CONN_ERR) {
2165 err = SN_ERR_SRVCL;
2166 fin = SN_FINST_C;
2167 }
2168 else /* SI_ET_CONN_OTHER and others */ {
2169 err = SN_ERR_INTERNAL;
2170 fin = SN_FINST_C;
2171 }
2172
2173 if (!(s->flags & SN_ERR_MASK))
2174 s->flags |= err;
2175 if (!(s->flags & SN_FINST_MASK))
2176 s->flags |= fin;
2177}
Willy Tarreau7c669d72008-06-20 15:04:11 +02002178
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +02002179
Willy Tarreau8b22a712010-06-18 17:46:06 +02002180/************************************************************************/
2181/* All supported ACL keywords must be declared here. */
2182/************************************************************************/
2183
Willy Tarreauc3bd9722010-06-20 12:47:25 +02002184/* set test->i to the General Purpose Counter 0 value in the stksess entry <ts> */
2185static int
2186acl_fetch_get_gpc0(struct stktable *table, struct acl_test *test, struct stksess *ts)
2187{
2188 test->flags = ACL_TEST_F_VOL_TEST;
2189 test->i = 0;
2190 if (ts != NULL) {
2191 void *ptr = stktable_data_ptr(table, ts, STKTABLE_DT_GPC0);
2192 if (!ptr)
2193 return 0; /* parameter not stored */
2194 test->i = stktable_data_cast(ptr, gpc0);
2195 }
2196 return 1;
2197}
2198
2199/* set test->i to the General Purpose Counter 0 value from the session's tracked
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002200 * frontend counters.
Willy Tarreauc3bd9722010-06-20 12:47:25 +02002201 */
2202static int
Willy Tarreau56123282010-08-06 19:06:56 +02002203acl_fetch_sc1_get_gpc0(struct proxy *px, struct session *l4, void *l7, int dir,
2204 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002205{
Willy Tarreau56123282010-08-06 19:06:56 +02002206 if (!l4->stkctr1_entry)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002207 return 0;
Willy Tarreau56123282010-08-06 19:06:56 +02002208 return acl_fetch_get_gpc0(l4->stkctr1_table, test, l4->stkctr1_entry);
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002209}
2210
2211/* set test->i to the General Purpose Counter 0 value from the session's tracked
2212 * backend counters.
2213 */
2214static int
Willy Tarreau56123282010-08-06 19:06:56 +02002215acl_fetch_sc2_get_gpc0(struct proxy *px, struct session *l4, void *l7, int dir,
2216 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauc3bd9722010-06-20 12:47:25 +02002217{
Willy Tarreau56123282010-08-06 19:06:56 +02002218 if (!l4->stkctr2_entry)
Willy Tarreauc3bd9722010-06-20 12:47:25 +02002219 return 0;
Willy Tarreau56123282010-08-06 19:06:56 +02002220 return acl_fetch_get_gpc0(l4->stkctr2_table, test, l4->stkctr2_entry);
Willy Tarreauc3bd9722010-06-20 12:47:25 +02002221}
2222
2223/* set test->i to the General Purpose Counter 0 value from the session's source
2224 * address in the table pointed to by expr.
2225 */
2226static int
2227acl_fetch_src_get_gpc0(struct proxy *px, struct session *l4, void *l7, int dir,
2228 struct acl_expr *expr, struct acl_test *test)
2229{
2230 struct stktable_key *key;
2231
2232 key = tcpv4_src_to_stktable_key(l4);
2233 if (!key)
2234 return 0; /* only TCPv4 is supported right now */
2235
2236 if (expr->arg_len)
2237 px = find_stktable(expr->arg.str);
2238
2239 if (!px)
2240 return 0; /* table not found */
2241
2242 return acl_fetch_get_gpc0(&px->table, test, stktable_lookup_key(&px->table, key));
2243}
2244
2245/* Increment the General Purpose Counter 0 value in the stksess entry <ts> and
2246 * return it into test->i.
2247 */
2248static int
2249acl_fetch_inc_gpc0(struct stktable *table, struct acl_test *test, struct stksess *ts)
2250{
2251 test->flags = ACL_TEST_F_VOL_TEST;
2252 test->i = 0;
2253 if (ts != NULL) {
2254 void *ptr = stktable_data_ptr(table, ts, STKTABLE_DT_GPC0);
2255 if (!ptr)
2256 return 0; /* parameter not stored */
2257 test->i = ++stktable_data_cast(ptr, gpc0);
2258 }
2259 return 1;
2260}
2261
2262/* Increment the General Purpose Counter 0 value from the session's tracked
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002263 * frontend counters and return it into test->i.
Willy Tarreauc3bd9722010-06-20 12:47:25 +02002264 */
2265static int
Willy Tarreau56123282010-08-06 19:06:56 +02002266acl_fetch_sc1_inc_gpc0(struct proxy *px, struct session *l4, void *l7, int dir,
2267 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002268{
Willy Tarreau56123282010-08-06 19:06:56 +02002269 if (!l4->stkctr1_entry)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002270 return 0;
Willy Tarreau56123282010-08-06 19:06:56 +02002271 return acl_fetch_inc_gpc0(l4->stkctr1_table, test, l4->stkctr1_entry);
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002272}
2273
2274/* Increment the General Purpose Counter 0 value from the session's tracked
2275 * backend counters and return it into test->i.
2276 */
2277static int
Willy Tarreau56123282010-08-06 19:06:56 +02002278acl_fetch_sc2_inc_gpc0(struct proxy *px, struct session *l4, void *l7, int dir,
2279 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauc3bd9722010-06-20 12:47:25 +02002280{
Willy Tarreau56123282010-08-06 19:06:56 +02002281 if (!l4->stkctr2_entry)
Willy Tarreauc3bd9722010-06-20 12:47:25 +02002282 return 0;
Willy Tarreau56123282010-08-06 19:06:56 +02002283 return acl_fetch_inc_gpc0(l4->stkctr2_table, test, l4->stkctr2_entry);
Willy Tarreauc3bd9722010-06-20 12:47:25 +02002284}
2285
2286/* Increment the General Purpose Counter 0 value from the session's source
2287 * address in the table pointed to by expr, and return it into test->i.
2288 */
2289static int
2290acl_fetch_src_inc_gpc0(struct proxy *px, struct session *l4, void *l7, int dir,
2291 struct acl_expr *expr, struct acl_test *test)
2292{
2293 struct stktable_key *key;
2294
2295 key = tcpv4_src_to_stktable_key(l4);
2296 if (!key)
2297 return 0; /* only TCPv4 is supported right now */
2298
2299 if (expr->arg_len)
2300 px = find_stktable(expr->arg.str);
2301
2302 if (!px)
2303 return 0; /* table not found */
2304
2305 return acl_fetch_inc_gpc0(&px->table, test, stktable_update_key(&px->table, key));
2306}
2307
Willy Tarreau9a3f8492010-06-18 19:53:25 +02002308/* set test->i to the cumulated number of connections in the stksess entry <ts> */
2309static int
2310acl_fetch_conn_cnt(struct stktable *table, struct acl_test *test, struct stksess *ts)
2311{
2312 test->flags = ACL_TEST_F_VOL_TEST;
2313 test->i = 0;
2314 if (ts != NULL) {
2315 void *ptr = stktable_data_ptr(table, ts, STKTABLE_DT_CONN_CNT);
2316 if (!ptr)
2317 return 0; /* parameter not stored */
2318 test->i = stktable_data_cast(ptr, conn_cnt);
2319 }
Willy Tarreau9a3f8492010-06-18 19:53:25 +02002320 return 1;
2321}
2322
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002323/* set test->i to the cumulated number of connections from the session's tracked FE counters */
Willy Tarreau9a3f8492010-06-18 19:53:25 +02002324static int
Willy Tarreau56123282010-08-06 19:06:56 +02002325acl_fetch_sc1_conn_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
2326 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002327{
Willy Tarreau56123282010-08-06 19:06:56 +02002328 if (!l4->stkctr1_entry)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002329 return 0;
2330
Willy Tarreau56123282010-08-06 19:06:56 +02002331 return acl_fetch_conn_cnt(l4->stkctr1_table, test, l4->stkctr1_entry);
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002332}
2333
2334/* set test->i to the cumulated number of connections from the session's tracked BE counters */
2335static int
Willy Tarreau56123282010-08-06 19:06:56 +02002336acl_fetch_sc2_conn_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
2337 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau9a3f8492010-06-18 19:53:25 +02002338{
Willy Tarreau56123282010-08-06 19:06:56 +02002339 if (!l4->stkctr2_entry)
Willy Tarreau9a3f8492010-06-18 19:53:25 +02002340 return 0;
2341
Willy Tarreau56123282010-08-06 19:06:56 +02002342 return acl_fetch_conn_cnt(l4->stkctr2_table, test, l4->stkctr2_entry);
Willy Tarreau9a3f8492010-06-18 19:53:25 +02002343}
2344
2345/* set test->i to the cumulated number of connections from the session's source
2346 * address in the table pointed to by expr.
Willy Tarreau8b22a712010-06-18 17:46:06 +02002347 */
2348static int
2349acl_fetch_src_conn_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
2350 struct acl_expr *expr, struct acl_test *test)
2351{
Willy Tarreau8b22a712010-06-18 17:46:06 +02002352 struct stktable_key *key;
2353
2354 key = tcpv4_src_to_stktable_key(l4);
2355 if (!key)
2356 return 0; /* only TCPv4 is supported right now */
2357
2358 if (expr->arg_len)
2359 px = find_stktable(expr->arg.str);
2360
2361 if (!px)
2362 return 0; /* table not found */
2363
Willy Tarreau9a3f8492010-06-18 19:53:25 +02002364 return acl_fetch_conn_cnt(&px->table, test, stktable_lookup_key(&px->table, key));
Willy Tarreau8b22a712010-06-18 17:46:06 +02002365}
2366
Willy Tarreau91c43d72010-06-20 11:19:22 +02002367/* set test->i to the connection rate in the stksess entry <ts> over the configured period */
2368static int
2369acl_fetch_conn_rate(struct stktable *table, struct acl_test *test, struct stksess *ts)
2370{
2371 test->flags = ACL_TEST_F_VOL_TEST;
2372 test->i = 0;
2373 if (ts != NULL) {
2374 void *ptr = stktable_data_ptr(table, ts, STKTABLE_DT_CONN_RATE);
2375 if (!ptr)
2376 return 0; /* parameter not stored */
2377 test->i = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2378 table->data_arg[STKTABLE_DT_CONN_RATE].u);
2379 }
2380 return 1;
2381}
2382
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002383/* set test->i to the connection rate from the session's tracked FE counters over
Willy Tarreau91c43d72010-06-20 11:19:22 +02002384 * the configured period.
2385 */
2386static int
Willy Tarreau56123282010-08-06 19:06:56 +02002387acl_fetch_sc1_conn_rate(struct proxy *px, struct session *l4, void *l7, int dir,
2388 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002389{
Willy Tarreau56123282010-08-06 19:06:56 +02002390 if (!l4->stkctr1_entry)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002391 return 0;
2392
Willy Tarreau56123282010-08-06 19:06:56 +02002393 return acl_fetch_conn_rate(l4->stkctr1_table, test, l4->stkctr1_entry);
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002394}
2395
2396/* set test->i to the connection rate from the session's tracked BE counters over
2397 * the configured period.
2398 */
2399static int
Willy Tarreau56123282010-08-06 19:06:56 +02002400acl_fetch_sc2_conn_rate(struct proxy *px, struct session *l4, void *l7, int dir,
2401 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau91c43d72010-06-20 11:19:22 +02002402{
Willy Tarreau56123282010-08-06 19:06:56 +02002403 if (!l4->stkctr2_entry)
Willy Tarreau91c43d72010-06-20 11:19:22 +02002404 return 0;
2405
Willy Tarreau56123282010-08-06 19:06:56 +02002406 return acl_fetch_conn_rate(l4->stkctr2_table, test, l4->stkctr2_entry);
Willy Tarreau91c43d72010-06-20 11:19:22 +02002407}
2408
2409/* set test->i to the connection rate from the session's source address in the
2410 * table pointed to by expr, over the configured period.
2411 */
2412static int
2413acl_fetch_src_conn_rate(struct proxy *px, struct session *l4, void *l7, int dir,
2414 struct acl_expr *expr, struct acl_test *test)
2415{
2416 struct stktable_key *key;
2417
2418 key = tcpv4_src_to_stktable_key(l4);
2419 if (!key)
2420 return 0; /* only TCPv4 is supported right now */
2421
2422 if (expr->arg_len)
2423 px = find_stktable(expr->arg.str);
2424
2425 if (!px)
2426 return 0; /* table not found */
2427
2428 return acl_fetch_conn_rate(&px->table, test, stktable_lookup_key(&px->table, key));
2429}
2430
Willy Tarreau8b22a712010-06-18 17:46:06 +02002431/* set test->i to the number of connections from the session's source address
2432 * in the table pointed to by expr, after updating it.
2433 */
2434static int
2435acl_fetch_src_updt_conn_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
2436 struct acl_expr *expr, struct acl_test *test)
2437{
2438 struct stksess *ts;
2439 struct stktable_key *key;
2440 void *ptr;
2441
2442 key = tcpv4_src_to_stktable_key(l4);
2443 if (!key)
2444 return 0; /* only TCPv4 is supported right now */
2445
2446 if (expr->arg_len)
2447 px = find_stktable(expr->arg.str);
2448
2449 if (!px)
2450 return 0; /* table not found */
2451
Willy Tarreau1f7e9252010-06-20 12:27:21 +02002452 if ((ts = stktable_update_key(&px->table, key)) == NULL)
2453 /* entry does not exist and could not be created */
2454 return 0;
Willy Tarreau8b22a712010-06-18 17:46:06 +02002455
2456 ptr = stktable_data_ptr(&px->table, ts, STKTABLE_DT_CONN_CNT);
2457 if (!ptr)
2458 return 0; /* parameter not stored in this table */
2459
2460 test->i = ++stktable_data_cast(ptr, conn_cnt);
2461 test->flags = ACL_TEST_F_VOL_TEST;
2462 return 1;
2463}
2464
Willy Tarreau9b0ddcf2010-06-18 21:14:36 +02002465/* set test->i to the number of concurrent connections in the stksess entry <ts> */
2466static int
2467acl_fetch_conn_cur(struct stktable *table, struct acl_test *test, struct stksess *ts)
2468{
2469 test->flags = ACL_TEST_F_VOL_TEST;
2470 test->i = 0;
2471
2472 if (ts != NULL) {
2473 void *ptr = stktable_data_ptr(table, ts, STKTABLE_DT_CONN_CUR);
2474 if (!ptr)
2475 return 0; /* parameter not stored */
2476 test->i = stktable_data_cast(ptr, conn_cur);
2477 }
2478 return 1;
2479}
2480
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002481/* set test->i to the number of concurrent connections from the session's tracked FE counters */
Willy Tarreau9b0ddcf2010-06-18 21:14:36 +02002482static int
Willy Tarreau56123282010-08-06 19:06:56 +02002483acl_fetch_sc1_conn_cur(struct proxy *px, struct session *l4, void *l7, int dir,
2484 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau9b0ddcf2010-06-18 21:14:36 +02002485{
Willy Tarreau56123282010-08-06 19:06:56 +02002486 if (!l4->stkctr1_entry)
Willy Tarreau9b0ddcf2010-06-18 21:14:36 +02002487 return 0;
2488
Willy Tarreau56123282010-08-06 19:06:56 +02002489 return acl_fetch_conn_cur(l4->stkctr1_table, test, l4->stkctr1_entry);
Willy Tarreau9b0ddcf2010-06-18 21:14:36 +02002490}
2491
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002492/* set test->i to the number of concurrent connections from the session's tracked BE counters */
2493static int
Willy Tarreau56123282010-08-06 19:06:56 +02002494acl_fetch_sc2_conn_cur(struct proxy *px, struct session *l4, void *l7, int dir,
2495 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002496{
Willy Tarreau56123282010-08-06 19:06:56 +02002497 if (!l4->stkctr2_entry)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002498 return 0;
2499
Willy Tarreau56123282010-08-06 19:06:56 +02002500 return acl_fetch_conn_cur(l4->stkctr2_table, test, l4->stkctr2_entry);
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002501}
2502
Willy Tarreau38285c12010-06-18 16:35:43 +02002503/* set test->i to the number of concurrent connections from the session's source
2504 * address in the table pointed to by expr.
2505 */
2506static int
2507acl_fetch_src_conn_cur(struct proxy *px, struct session *l4, void *l7, int dir,
2508 struct acl_expr *expr, struct acl_test *test)
2509{
Willy Tarreau38285c12010-06-18 16:35:43 +02002510 struct stktable_key *key;
2511
2512 key = tcpv4_src_to_stktable_key(l4);
2513 if (!key)
2514 return 0; /* only TCPv4 is supported right now */
2515
2516 if (expr->arg_len)
2517 px = find_stktable(expr->arg.str);
2518
2519 if (!px)
2520 return 0; /* table not found */
2521
Willy Tarreau9b0ddcf2010-06-18 21:14:36 +02002522 return acl_fetch_conn_cnt(&px->table, test, stktable_lookup_key(&px->table, key));
Willy Tarreau38285c12010-06-18 16:35:43 +02002523}
2524
Willy Tarreauf4d17d92010-06-18 22:10:12 +02002525/* set test->i to the cumulated number of sessions in the stksess entry <ts> */
2526static int
2527acl_fetch_sess_cnt(struct stktable *table, struct acl_test *test, struct stksess *ts)
2528{
2529 test->flags = ACL_TEST_F_VOL_TEST;
2530 test->i = 0;
2531 if (ts != NULL) {
2532 void *ptr = stktable_data_ptr(table, ts, STKTABLE_DT_SESS_CNT);
2533 if (!ptr)
2534 return 0; /* parameter not stored */
2535 test->i = stktable_data_cast(ptr, sess_cnt);
2536 }
2537 return 1;
2538}
2539
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002540/* set test->i to the cumulated number of sessions from the session's tracked FE counters */
Willy Tarreauf4d17d92010-06-18 22:10:12 +02002541static int
Willy Tarreau56123282010-08-06 19:06:56 +02002542acl_fetch_sc1_sess_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
2543 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002544{
Willy Tarreau56123282010-08-06 19:06:56 +02002545 if (!l4->stkctr1_entry)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002546 return 0;
2547
Willy Tarreau56123282010-08-06 19:06:56 +02002548 return acl_fetch_sess_cnt(l4->stkctr1_table, test, l4->stkctr1_entry);
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002549}
2550
2551/* set test->i to the cumulated number of sessions from the session's tracked BE counters */
2552static int
Willy Tarreau56123282010-08-06 19:06:56 +02002553acl_fetch_sc2_sess_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
2554 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauf4d17d92010-06-18 22:10:12 +02002555{
Willy Tarreau56123282010-08-06 19:06:56 +02002556 if (!l4->stkctr2_entry)
Willy Tarreauf4d17d92010-06-18 22:10:12 +02002557 return 0;
2558
Willy Tarreau56123282010-08-06 19:06:56 +02002559 return acl_fetch_sess_cnt(l4->stkctr2_table, test, l4->stkctr2_entry);
Willy Tarreauf4d17d92010-06-18 22:10:12 +02002560}
2561
2562/* set test->i to the cumulated number of session from the session's source
2563 * address in the table pointed to by expr.
2564 */
2565static int
2566acl_fetch_src_sess_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
2567 struct acl_expr *expr, struct acl_test *test)
2568{
2569 struct stktable_key *key;
2570
2571 key = tcpv4_src_to_stktable_key(l4);
2572 if (!key)
2573 return 0; /* only TCPv4 is supported right now */
2574
2575 if (expr->arg_len)
2576 px = find_stktable(expr->arg.str);
2577
2578 if (!px)
2579 return 0; /* table not found */
2580
2581 return acl_fetch_sess_cnt(&px->table, test, stktable_lookup_key(&px->table, key));
2582}
2583
Willy Tarreau91c43d72010-06-20 11:19:22 +02002584/* set test->i to the session rate in the stksess entry <ts> over the configured period */
2585static int
2586acl_fetch_sess_rate(struct stktable *table, struct acl_test *test, struct stksess *ts)
2587{
2588 test->flags = ACL_TEST_F_VOL_TEST;
2589 test->i = 0;
2590 if (ts != NULL) {
2591 void *ptr = stktable_data_ptr(table, ts, STKTABLE_DT_SESS_RATE);
2592 if (!ptr)
2593 return 0; /* parameter not stored */
2594 test->i = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2595 table->data_arg[STKTABLE_DT_SESS_RATE].u);
2596 }
2597 return 1;
2598}
2599
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002600/* set test->i to the session rate from the session's tracked FE counters over
2601 * the configured period.
2602 */
2603static int
Willy Tarreau56123282010-08-06 19:06:56 +02002604acl_fetch_sc1_sess_rate(struct proxy *px, struct session *l4, void *l7, int dir,
2605 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002606{
Willy Tarreau56123282010-08-06 19:06:56 +02002607 if (!l4->stkctr1_entry)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002608 return 0;
2609
Willy Tarreau56123282010-08-06 19:06:56 +02002610 return acl_fetch_sess_rate(l4->stkctr1_table, test, l4->stkctr1_entry);
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002611}
2612
2613/* set test->i to the session rate from the session's tracked BE counters over
Willy Tarreau91c43d72010-06-20 11:19:22 +02002614 * the configured period.
2615 */
2616static int
Willy Tarreau56123282010-08-06 19:06:56 +02002617acl_fetch_sc2_sess_rate(struct proxy *px, struct session *l4, void *l7, int dir,
2618 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau91c43d72010-06-20 11:19:22 +02002619{
Willy Tarreau56123282010-08-06 19:06:56 +02002620 if (!l4->stkctr2_entry)
Willy Tarreau91c43d72010-06-20 11:19:22 +02002621 return 0;
2622
Willy Tarreau56123282010-08-06 19:06:56 +02002623 return acl_fetch_sess_rate(l4->stkctr2_table, test, l4->stkctr2_entry);
Willy Tarreau91c43d72010-06-20 11:19:22 +02002624}
2625
2626/* set test->i to the session rate from the session's source address in the
2627 * table pointed to by expr, over the configured period.
2628 */
2629static int
2630acl_fetch_src_sess_rate(struct proxy *px, struct session *l4, void *l7, int dir,
2631 struct acl_expr *expr, struct acl_test *test)
2632{
2633 struct stktable_key *key;
2634
2635 key = tcpv4_src_to_stktable_key(l4);
2636 if (!key)
2637 return 0; /* only TCPv4 is supported right now */
2638
2639 if (expr->arg_len)
2640 px = find_stktable(expr->arg.str);
2641
2642 if (!px)
2643 return 0; /* table not found */
2644
2645 return acl_fetch_sess_rate(&px->table, test, stktable_lookup_key(&px->table, key));
2646}
2647
Willy Tarreauda7ff642010-06-23 11:44:09 +02002648/* set test->i to the cumulated number of sessions in the stksess entry <ts> */
2649static int
2650acl_fetch_http_req_cnt(struct stktable *table, struct acl_test *test, struct stksess *ts)
2651{
2652 test->flags = ACL_TEST_F_VOL_TEST;
2653 test->i = 0;
2654 if (ts != NULL) {
2655 void *ptr = stktable_data_ptr(table, ts, STKTABLE_DT_HTTP_REQ_CNT);
2656 if (!ptr)
2657 return 0; /* parameter not stored */
2658 test->i = stktable_data_cast(ptr, http_req_cnt);
2659 }
2660 return 1;
2661}
2662
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002663/* set test->i to the cumulated number of sessions from the session's tracked FE counters */
Willy Tarreauda7ff642010-06-23 11:44:09 +02002664static int
Willy Tarreau56123282010-08-06 19:06:56 +02002665acl_fetch_sc1_http_req_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
2666 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002667{
Willy Tarreau56123282010-08-06 19:06:56 +02002668 if (!l4->stkctr1_entry)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002669 return 0;
2670
Willy Tarreau56123282010-08-06 19:06:56 +02002671 return acl_fetch_http_req_cnt(l4->stkctr1_table, test, l4->stkctr1_entry);
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002672}
2673
2674/* set test->i to the cumulated number of sessions from the session's tracked BE counters */
2675static int
Willy Tarreau56123282010-08-06 19:06:56 +02002676acl_fetch_sc2_http_req_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
2677 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauda7ff642010-06-23 11:44:09 +02002678{
Willy Tarreau56123282010-08-06 19:06:56 +02002679 if (!l4->stkctr2_entry)
Willy Tarreauda7ff642010-06-23 11:44:09 +02002680 return 0;
2681
Willy Tarreau56123282010-08-06 19:06:56 +02002682 return acl_fetch_http_req_cnt(l4->stkctr2_table, test, l4->stkctr2_entry);
Willy Tarreauda7ff642010-06-23 11:44:09 +02002683}
2684
2685/* set test->i to the cumulated number of session from the session's source
2686 * address in the table pointed to by expr.
2687 */
2688static int
2689acl_fetch_src_http_req_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
Willy Tarreau56123282010-08-06 19:06:56 +02002690 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauda7ff642010-06-23 11:44:09 +02002691{
2692 struct stktable_key *key;
2693
2694 key = tcpv4_src_to_stktable_key(l4);
2695 if (!key)
2696 return 0; /* only TCPv4 is supported right now */
2697
2698 if (expr->arg_len)
2699 px = find_stktable(expr->arg.str);
2700
2701 if (!px)
2702 return 0; /* table not found */
2703
2704 return acl_fetch_http_req_cnt(&px->table, test, stktable_lookup_key(&px->table, key));
2705}
2706
2707/* set test->i to the session rate in the stksess entry <ts> over the configured period */
2708static int
2709acl_fetch_http_req_rate(struct stktable *table, struct acl_test *test, struct stksess *ts)
2710{
2711 test->flags = ACL_TEST_F_VOL_TEST;
2712 test->i = 0;
2713 if (ts != NULL) {
2714 void *ptr = stktable_data_ptr(table, ts, STKTABLE_DT_HTTP_REQ_RATE);
2715 if (!ptr)
2716 return 0; /* parameter not stored */
2717 test->i = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
2718 table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
2719 }
2720 return 1;
2721}
2722
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002723/* set test->i to the session rate from the session's tracked FE counters over
Willy Tarreauda7ff642010-06-23 11:44:09 +02002724 * the configured period.
2725 */
2726static int
Willy Tarreau56123282010-08-06 19:06:56 +02002727acl_fetch_sc1_http_req_rate(struct proxy *px, struct session *l4, void *l7, int dir,
2728 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002729{
Willy Tarreau56123282010-08-06 19:06:56 +02002730 if (!l4->stkctr1_entry)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002731 return 0;
2732
Willy Tarreau56123282010-08-06 19:06:56 +02002733 return acl_fetch_http_req_rate(l4->stkctr1_table, test, l4->stkctr1_entry);
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002734}
2735
2736/* set test->i to the session rate from the session's tracked BE counters over
2737 * the configured period.
2738 */
2739static int
Willy Tarreau56123282010-08-06 19:06:56 +02002740acl_fetch_sc2_http_req_rate(struct proxy *px, struct session *l4, void *l7, int dir,
2741 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauda7ff642010-06-23 11:44:09 +02002742{
Willy Tarreau56123282010-08-06 19:06:56 +02002743 if (!l4->stkctr2_entry)
Willy Tarreauda7ff642010-06-23 11:44:09 +02002744 return 0;
2745
Willy Tarreau56123282010-08-06 19:06:56 +02002746 return acl_fetch_http_req_rate(l4->stkctr2_table, test, l4->stkctr2_entry);
Willy Tarreauda7ff642010-06-23 11:44:09 +02002747}
2748
2749/* set test->i to the session rate from the session's source address in the
2750 * table pointed to by expr, over the configured period.
2751 */
2752static int
2753acl_fetch_src_http_req_rate(struct proxy *px, struct session *l4, void *l7, int dir,
Willy Tarreau56123282010-08-06 19:06:56 +02002754 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauda7ff642010-06-23 11:44:09 +02002755{
2756 struct stktable_key *key;
2757
2758 key = tcpv4_src_to_stktable_key(l4);
2759 if (!key)
2760 return 0; /* only TCPv4 is supported right now */
2761
2762 if (expr->arg_len)
2763 px = find_stktable(expr->arg.str);
2764
2765 if (!px)
2766 return 0; /* table not found */
2767
2768 return acl_fetch_http_req_rate(&px->table, test, stktable_lookup_key(&px->table, key));
2769}
2770
2771/* set test->i to the cumulated number of sessions in the stksess entry <ts> */
2772static int
2773acl_fetch_http_err_cnt(struct stktable *table, struct acl_test *test, struct stksess *ts)
2774{
2775 test->flags = ACL_TEST_F_VOL_TEST;
2776 test->i = 0;
2777 if (ts != NULL) {
2778 void *ptr = stktable_data_ptr(table, ts, STKTABLE_DT_HTTP_ERR_CNT);
2779 if (!ptr)
2780 return 0; /* parameter not stored */
2781 test->i = stktable_data_cast(ptr, http_err_cnt);
2782 }
2783 return 1;
2784}
2785
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002786/* set test->i to the cumulated number of sessions from the session's tracked FE counters */
Willy Tarreauda7ff642010-06-23 11:44:09 +02002787static int
Willy Tarreau56123282010-08-06 19:06:56 +02002788acl_fetch_sc1_http_err_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
2789 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002790{
Willy Tarreau56123282010-08-06 19:06:56 +02002791 if (!l4->stkctr1_entry)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002792 return 0;
2793
Willy Tarreau56123282010-08-06 19:06:56 +02002794 return acl_fetch_http_err_cnt(l4->stkctr1_table, test, l4->stkctr1_entry);
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002795}
2796
2797/* set test->i to the cumulated number of sessions from the session's tracked BE counters */
2798static int
Willy Tarreau56123282010-08-06 19:06:56 +02002799acl_fetch_sc2_http_err_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
2800 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauda7ff642010-06-23 11:44:09 +02002801{
Willy Tarreau56123282010-08-06 19:06:56 +02002802 if (!l4->stkctr2_entry)
Willy Tarreauda7ff642010-06-23 11:44:09 +02002803 return 0;
2804
Willy Tarreau56123282010-08-06 19:06:56 +02002805 return acl_fetch_http_err_cnt(l4->stkctr2_table, test, l4->stkctr2_entry);
Willy Tarreauda7ff642010-06-23 11:44:09 +02002806}
2807
2808/* set test->i to the cumulated number of session from the session's source
2809 * address in the table pointed to by expr.
2810 */
2811static int
2812acl_fetch_src_http_err_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
Willy Tarreau56123282010-08-06 19:06:56 +02002813 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauda7ff642010-06-23 11:44:09 +02002814{
2815 struct stktable_key *key;
2816
2817 key = tcpv4_src_to_stktable_key(l4);
2818 if (!key)
2819 return 0; /* only TCPv4 is supported right now */
2820
2821 if (expr->arg_len)
2822 px = find_stktable(expr->arg.str);
2823
2824 if (!px)
2825 return 0; /* table not found */
2826
2827 return acl_fetch_http_err_cnt(&px->table, test, stktable_lookup_key(&px->table, key));
2828}
2829
2830/* set test->i to the session rate in the stksess entry <ts> over the configured period */
2831static int
2832acl_fetch_http_err_rate(struct stktable *table, struct acl_test *test, struct stksess *ts)
2833{
2834 test->flags = ACL_TEST_F_VOL_TEST;
2835 test->i = 0;
2836 if (ts != NULL) {
2837 void *ptr = stktable_data_ptr(table, ts, STKTABLE_DT_HTTP_ERR_RATE);
2838 if (!ptr)
2839 return 0; /* parameter not stored */
2840 test->i = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
2841 table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
2842 }
2843 return 1;
2844}
2845
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002846/* set test->i to the session rate from the session's tracked FE counters over
Willy Tarreauda7ff642010-06-23 11:44:09 +02002847 * the configured period.
2848 */
2849static int
Willy Tarreau56123282010-08-06 19:06:56 +02002850acl_fetch_sc1_http_err_rate(struct proxy *px, struct session *l4, void *l7, int dir,
2851 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002852{
Willy Tarreau56123282010-08-06 19:06:56 +02002853 if (!l4->stkctr1_entry)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002854 return 0;
2855
Willy Tarreau56123282010-08-06 19:06:56 +02002856 return acl_fetch_http_err_rate(l4->stkctr1_table, test, l4->stkctr1_entry);
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002857}
2858
2859/* set test->i to the session rate from the session's tracked BE counters over
2860 * the configured period.
2861 */
2862static int
Willy Tarreau56123282010-08-06 19:06:56 +02002863acl_fetch_sc2_http_err_rate(struct proxy *px, struct session *l4, void *l7, int dir,
2864 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauda7ff642010-06-23 11:44:09 +02002865{
Willy Tarreau56123282010-08-06 19:06:56 +02002866 if (!l4->stkctr2_entry)
Willy Tarreauda7ff642010-06-23 11:44:09 +02002867 return 0;
2868
Willy Tarreau56123282010-08-06 19:06:56 +02002869 return acl_fetch_http_err_rate(l4->stkctr2_table, test, l4->stkctr2_entry);
Willy Tarreauda7ff642010-06-23 11:44:09 +02002870}
2871
2872/* set test->i to the session rate from the session's source address in the
2873 * table pointed to by expr, over the configured period.
2874 */
2875static int
2876acl_fetch_src_http_err_rate(struct proxy *px, struct session *l4, void *l7, int dir,
2877 struct acl_expr *expr, struct acl_test *test)
2878{
2879 struct stktable_key *key;
2880
2881 key = tcpv4_src_to_stktable_key(l4);
2882 if (!key)
2883 return 0; /* only TCPv4 is supported right now */
2884
2885 if (expr->arg_len)
2886 px = find_stktable(expr->arg.str);
2887
2888 if (!px)
2889 return 0; /* table not found */
2890
2891 return acl_fetch_http_err_rate(&px->table, test, stktable_lookup_key(&px->table, key));
2892}
2893
Willy Tarreau1aa006f2010-06-18 21:52:52 +02002894/* set test->i to the number of kbytes received from clients matching the stksess entry <ts> */
2895static int
2896acl_fetch_kbytes_in(struct stktable *table, struct acl_test *test, struct stksess *ts)
2897{
2898 test->flags = ACL_TEST_F_VOL_TEST;
2899 test->i = 0;
2900
2901 if (ts != NULL) {
2902 void *ptr = stktable_data_ptr(table, ts, STKTABLE_DT_BYTES_IN_CNT);
2903 if (!ptr)
2904 return 0; /* parameter not stored */
2905 test->i = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
2906 }
2907 return 1;
2908}
2909
2910/* set test->i to the number of kbytes received from clients according to the
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002911 * session's tracked FE counters.
Willy Tarreau1aa006f2010-06-18 21:52:52 +02002912 */
2913static int
Willy Tarreau56123282010-08-06 19:06:56 +02002914acl_fetch_sc1_kbytes_in(struct proxy *px, struct session *l4, void *l7, int dir,
2915 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002916{
Willy Tarreau56123282010-08-06 19:06:56 +02002917 if (!l4->stkctr1_entry)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002918 return 0;
2919
Willy Tarreau56123282010-08-06 19:06:56 +02002920 return acl_fetch_kbytes_in(l4->stkctr1_table, test, l4->stkctr1_entry);
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002921}
2922
2923/* set test->i to the number of kbytes received from clients according to the
2924 * session's tracked BE counters.
2925 */
2926static int
Willy Tarreau56123282010-08-06 19:06:56 +02002927acl_fetch_sc2_kbytes_in(struct proxy *px, struct session *l4, void *l7, int dir,
2928 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau1aa006f2010-06-18 21:52:52 +02002929{
Willy Tarreau56123282010-08-06 19:06:56 +02002930 if (!l4->stkctr2_entry)
Willy Tarreau1aa006f2010-06-18 21:52:52 +02002931 return 0;
2932
Willy Tarreau56123282010-08-06 19:06:56 +02002933 return acl_fetch_kbytes_in(l4->stkctr2_table, test, l4->stkctr2_entry);
Willy Tarreau1aa006f2010-06-18 21:52:52 +02002934}
2935
Willy Tarreau855e4bb2010-06-18 18:33:32 +02002936/* set test->i to the number of kbytes received from the session's source
2937 * address in the table pointed to by expr.
2938 */
2939static int
2940acl_fetch_src_kbytes_in(struct proxy *px, struct session *l4, void *l7, int dir,
2941 struct acl_expr *expr, struct acl_test *test)
2942{
Willy Tarreau855e4bb2010-06-18 18:33:32 +02002943 struct stktable_key *key;
2944
2945 key = tcpv4_src_to_stktable_key(l4);
2946 if (!key)
2947 return 0; /* only TCPv4 is supported right now */
2948
2949 if (expr->arg_len)
2950 px = find_stktable(expr->arg.str);
2951
2952 if (!px)
2953 return 0; /* table not found */
2954
Willy Tarreau1aa006f2010-06-18 21:52:52 +02002955 return acl_fetch_kbytes_in(&px->table, test, stktable_lookup_key(&px->table, key));
2956}
2957
Willy Tarreau6c59e0a2010-06-20 11:56:30 +02002958/* set test->i to the bytes rate from clients in the stksess entry <ts> over the
2959 * configured period.
2960 */
2961static int
2962acl_fetch_bytes_in_rate(struct stktable *table, struct acl_test *test, struct stksess *ts)
2963{
2964 test->flags = ACL_TEST_F_VOL_TEST;
2965 test->i = 0;
2966 if (ts != NULL) {
2967 void *ptr = stktable_data_ptr(table, ts, STKTABLE_DT_BYTES_IN_RATE);
2968 if (!ptr)
2969 return 0; /* parameter not stored */
2970 test->i = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
2971 table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
2972 }
2973 return 1;
2974}
2975
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002976/* set test->i to the bytes rate from clients from the session's tracked FE
Willy Tarreau6c59e0a2010-06-20 11:56:30 +02002977 * counters over the configured period.
2978 */
2979static int
Willy Tarreau56123282010-08-06 19:06:56 +02002980acl_fetch_sc1_bytes_in_rate(struct proxy *px, struct session *l4, void *l7, int dir,
2981 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002982{
Willy Tarreau56123282010-08-06 19:06:56 +02002983 if (!l4->stkctr1_entry)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002984 return 0;
2985
Willy Tarreau56123282010-08-06 19:06:56 +02002986 return acl_fetch_bytes_in_rate(l4->stkctr1_table, test, l4->stkctr1_entry);
Willy Tarreauf059a0f2010-08-03 16:29:52 +02002987}
2988
2989/* set test->i to the bytes rate from clients from the session's tracked BE
2990 * counters over the configured period.
2991 */
2992static int
Willy Tarreau56123282010-08-06 19:06:56 +02002993acl_fetch_sc2_bytes_in_rate(struct proxy *px, struct session *l4, void *l7, int dir,
2994 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau6c59e0a2010-06-20 11:56:30 +02002995{
Willy Tarreau56123282010-08-06 19:06:56 +02002996 if (!l4->stkctr2_entry)
Willy Tarreau6c59e0a2010-06-20 11:56:30 +02002997 return 0;
2998
Willy Tarreau56123282010-08-06 19:06:56 +02002999 return acl_fetch_bytes_in_rate(l4->stkctr2_table, test, l4->stkctr2_entry);
Willy Tarreau6c59e0a2010-06-20 11:56:30 +02003000}
3001
3002/* set test->i to the bytes rate from clients from the session's source address
3003 * in the table pointed to by expr, over the configured period.
3004 */
3005static int
3006acl_fetch_src_bytes_in_rate(struct proxy *px, struct session *l4, void *l7, int dir,
Willy Tarreau56123282010-08-06 19:06:56 +02003007 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau6c59e0a2010-06-20 11:56:30 +02003008{
3009 struct stktable_key *key;
3010
3011 key = tcpv4_src_to_stktable_key(l4);
3012 if (!key)
3013 return 0; /* only TCPv4 is supported right now */
3014
3015 if (expr->arg_len)
3016 px = find_stktable(expr->arg.str);
3017
3018 if (!px)
3019 return 0; /* table not found */
3020
3021 return acl_fetch_bytes_in_rate(&px->table, test, stktable_lookup_key(&px->table, key));
3022}
3023
Willy Tarreau1aa006f2010-06-18 21:52:52 +02003024/* set test->i to the number of kbytes sent to clients matching the stksess entry <ts> */
3025static int
3026acl_fetch_kbytes_out(struct stktable *table, struct acl_test *test, struct stksess *ts)
3027{
Willy Tarreau855e4bb2010-06-18 18:33:32 +02003028 test->flags = ACL_TEST_F_VOL_TEST;
3029 test->i = 0;
3030
Willy Tarreau1aa006f2010-06-18 21:52:52 +02003031 if (ts != NULL) {
3032 void *ptr = stktable_data_ptr(table, ts, STKTABLE_DT_BYTES_OUT_CNT);
Willy Tarreau855e4bb2010-06-18 18:33:32 +02003033 if (!ptr)
3034 return 0; /* parameter not stored */
Willy Tarreau1aa006f2010-06-18 21:52:52 +02003035 test->i = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreau855e4bb2010-06-18 18:33:32 +02003036 }
Willy Tarreau855e4bb2010-06-18 18:33:32 +02003037 return 1;
3038}
3039
Willy Tarreau1aa006f2010-06-18 21:52:52 +02003040/* set test->i to the number of kbytes sent to clients according to the session's
Willy Tarreauf059a0f2010-08-03 16:29:52 +02003041 * tracked FE counters.
Willy Tarreau1aa006f2010-06-18 21:52:52 +02003042 */
3043static int
Willy Tarreau56123282010-08-06 19:06:56 +02003044acl_fetch_sc1_kbytes_out(struct proxy *px, struct session *l4, void *l7, int dir,
3045 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02003046{
Willy Tarreau56123282010-08-06 19:06:56 +02003047 if (!l4->stkctr1_entry)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02003048 return 0;
3049
Willy Tarreau56123282010-08-06 19:06:56 +02003050 return acl_fetch_kbytes_out(l4->stkctr1_table, test, l4->stkctr1_entry);
Willy Tarreauf059a0f2010-08-03 16:29:52 +02003051}
3052
3053/* set test->i to the number of kbytes sent to clients according to the session's
3054 * tracked BE counters.
3055 */
3056static int
Willy Tarreau56123282010-08-06 19:06:56 +02003057acl_fetch_sc2_kbytes_out(struct proxy *px, struct session *l4, void *l7, int dir,
3058 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau1aa006f2010-06-18 21:52:52 +02003059{
Willy Tarreau56123282010-08-06 19:06:56 +02003060 if (!l4->stkctr2_entry)
Willy Tarreau1aa006f2010-06-18 21:52:52 +02003061 return 0;
3062
Willy Tarreau56123282010-08-06 19:06:56 +02003063 return acl_fetch_kbytes_out(l4->stkctr2_table, test, l4->stkctr2_entry);
Willy Tarreau1aa006f2010-06-18 21:52:52 +02003064}
3065
Willy Tarreau855e4bb2010-06-18 18:33:32 +02003066/* set test->i to the number of kbytes sent to the session's source address in
3067 * the table pointed to by expr.
3068 */
3069static int
3070acl_fetch_src_kbytes_out(struct proxy *px, struct session *l4, void *l7, int dir,
3071 struct acl_expr *expr, struct acl_test *test)
3072{
Willy Tarreau855e4bb2010-06-18 18:33:32 +02003073 struct stktable_key *key;
3074
3075 key = tcpv4_src_to_stktable_key(l4);
3076 if (!key)
3077 return 0; /* only TCPv4 is supported right now */
3078
3079 if (expr->arg_len)
3080 px = find_stktable(expr->arg.str);
3081
3082 if (!px)
3083 return 0; /* table not found */
3084
Willy Tarreau1aa006f2010-06-18 21:52:52 +02003085 return acl_fetch_kbytes_out(&px->table, test, stktable_lookup_key(&px->table, key));
Willy Tarreau855e4bb2010-06-18 18:33:32 +02003086}
3087
Willy Tarreau6c59e0a2010-06-20 11:56:30 +02003088/* set test->i to the bytes rate to clients in the stksess entry <ts> over the
3089 * configured period.
3090 */
3091static int
3092acl_fetch_bytes_out_rate(struct stktable *table, struct acl_test *test, struct stksess *ts)
3093{
3094 test->flags = ACL_TEST_F_VOL_TEST;
3095 test->i = 0;
3096 if (ts != NULL) {
3097 void *ptr = stktable_data_ptr(table, ts, STKTABLE_DT_BYTES_OUT_RATE);
3098 if (!ptr)
3099 return 0; /* parameter not stored */
3100 test->i = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
3101 table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
3102 }
3103 return 1;
3104}
3105
Willy Tarreauf059a0f2010-08-03 16:29:52 +02003106/* set test->i to the bytes rate to clients from the session's tracked FE counters
Willy Tarreau6c59e0a2010-06-20 11:56:30 +02003107 * over the configured period.
3108 */
3109static int
Willy Tarreau56123282010-08-06 19:06:56 +02003110acl_fetch_sc1_bytes_out_rate(struct proxy *px, struct session *l4, void *l7, int dir,
3111 struct acl_expr *expr, struct acl_test *test)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02003112{
Willy Tarreau56123282010-08-06 19:06:56 +02003113 if (!l4->stkctr1_entry)
Willy Tarreauf059a0f2010-08-03 16:29:52 +02003114 return 0;
3115
Willy Tarreau56123282010-08-06 19:06:56 +02003116 return acl_fetch_bytes_out_rate(l4->stkctr1_table, test, l4->stkctr1_entry);
Willy Tarreauf059a0f2010-08-03 16:29:52 +02003117}
3118
3119/* set test->i to the bytes rate to clients from the session's tracked BE counters
3120 * over the configured period.
3121 */
3122static int
Willy Tarreau56123282010-08-06 19:06:56 +02003123acl_fetch_sc2_bytes_out_rate(struct proxy *px, struct session *l4, void *l7, int dir,
3124 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau6c59e0a2010-06-20 11:56:30 +02003125{
Willy Tarreau56123282010-08-06 19:06:56 +02003126 if (!l4->stkctr2_entry)
Willy Tarreau6c59e0a2010-06-20 11:56:30 +02003127 return 0;
3128
Willy Tarreau56123282010-08-06 19:06:56 +02003129 return acl_fetch_bytes_out_rate(l4->stkctr2_table, test, l4->stkctr2_entry);
Willy Tarreau6c59e0a2010-06-20 11:56:30 +02003130}
3131
3132/* set test->i to the bytes rate to client from the session's source address in
3133 * the table pointed to by expr, over the configured period.
3134 */
3135static int
3136acl_fetch_src_bytes_out_rate(struct proxy *px, struct session *l4, void *l7, int dir,
Willy Tarreau56123282010-08-06 19:06:56 +02003137 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau6c59e0a2010-06-20 11:56:30 +02003138{
3139 struct stktable_key *key;
3140
3141 key = tcpv4_src_to_stktable_key(l4);
3142 if (!key)
3143 return 0; /* only TCPv4 is supported right now */
3144
3145 if (expr->arg_len)
3146 px = find_stktable(expr->arg.str);
3147
3148 if (!px)
3149 return 0; /* table not found */
3150
3151 return acl_fetch_bytes_out_rate(&px->table, test, stktable_lookup_key(&px->table, key));
3152}
3153
Willy Tarreau8b22a712010-06-18 17:46:06 +02003154
3155/* Note: must not be declared <const> as its list will be overwritten */
3156static struct acl_kw_list acl_kws = {{ },{
Willy Tarreau56123282010-08-06 19:06:56 +02003157 { "sc1_get_gpc0", acl_parse_int, acl_fetch_sc1_get_gpc0, acl_match_int, ACL_USE_NOTHING },
3158 { "sc2_get_gpc0", acl_parse_int, acl_fetch_sc2_get_gpc0, acl_match_int, ACL_USE_NOTHING },
3159 { "src_get_gpc0", acl_parse_int, acl_fetch_src_get_gpc0, acl_match_int, ACL_USE_TCP4_VOLATILE },
3160 { "sc1_inc_gpc0", acl_parse_int, acl_fetch_sc1_inc_gpc0, acl_match_int, ACL_USE_NOTHING },
3161 { "sc2_inc_gpc0", acl_parse_int, acl_fetch_sc2_inc_gpc0, acl_match_int, ACL_USE_NOTHING },
3162 { "src_inc_gpc0", acl_parse_int, acl_fetch_src_inc_gpc0, acl_match_int, ACL_USE_TCP4_VOLATILE },
3163 { "sc1_conn_cnt", acl_parse_int, acl_fetch_sc1_conn_cnt, acl_match_int, ACL_USE_NOTHING },
3164 { "sc2_conn_cnt", acl_parse_int, acl_fetch_sc2_conn_cnt, acl_match_int, ACL_USE_NOTHING },
3165 { "src_conn_cnt", acl_parse_int, acl_fetch_src_conn_cnt, acl_match_int, ACL_USE_TCP4_VOLATILE },
3166 { "sc1_conn_rate", acl_parse_int, acl_fetch_sc1_conn_rate, acl_match_int, ACL_USE_NOTHING },
3167 { "sc2_conn_rate", acl_parse_int, acl_fetch_sc2_conn_rate, acl_match_int, ACL_USE_NOTHING },
3168 { "src_conn_rate", acl_parse_int, acl_fetch_src_conn_rate, acl_match_int, ACL_USE_TCP4_VOLATILE },
3169 { "src_updt_conn_cnt", acl_parse_int, acl_fetch_src_updt_conn_cnt, acl_match_int, ACL_USE_TCP4_VOLATILE },
3170 { "sc1_conn_cur", acl_parse_int, acl_fetch_sc1_conn_cur, acl_match_int, ACL_USE_NOTHING },
3171 { "sc2_conn_cur", acl_parse_int, acl_fetch_sc2_conn_cur, acl_match_int, ACL_USE_NOTHING },
3172 { "src_conn_cur", acl_parse_int, acl_fetch_src_conn_cur, acl_match_int, ACL_USE_TCP4_VOLATILE },
3173 { "sc1_sess_cnt", acl_parse_int, acl_fetch_sc1_sess_cnt, acl_match_int, ACL_USE_NOTHING },
3174 { "sc2_sess_cnt", acl_parse_int, acl_fetch_sc2_sess_cnt, acl_match_int, ACL_USE_NOTHING },
3175 { "src_sess_cnt", acl_parse_int, acl_fetch_src_sess_cnt, acl_match_int, ACL_USE_TCP4_VOLATILE },
3176 { "sc1_sess_rate", acl_parse_int, acl_fetch_sc1_sess_rate, acl_match_int, ACL_USE_NOTHING },
3177 { "sc2_sess_rate", acl_parse_int, acl_fetch_sc2_sess_rate, acl_match_int, ACL_USE_NOTHING },
3178 { "src_sess_rate", acl_parse_int, acl_fetch_src_sess_rate, acl_match_int, ACL_USE_TCP4_VOLATILE },
3179 { "sc1_http_req_cnt", acl_parse_int, acl_fetch_sc1_http_req_cnt, acl_match_int, ACL_USE_NOTHING },
3180 { "sc2_http_req_cnt", acl_parse_int, acl_fetch_sc2_http_req_cnt, acl_match_int, ACL_USE_NOTHING },
3181 { "src_http_req_cnt", acl_parse_int, acl_fetch_src_http_req_cnt, acl_match_int, ACL_USE_TCP4_VOLATILE },
3182 { "sc1_http_req_rate", acl_parse_int, acl_fetch_sc1_http_req_rate, acl_match_int, ACL_USE_NOTHING },
3183 { "sc2_http_req_rate", acl_parse_int, acl_fetch_sc2_http_req_rate, acl_match_int, ACL_USE_NOTHING },
3184 { "src_http_req_rate", acl_parse_int, acl_fetch_src_http_req_rate, acl_match_int, ACL_USE_TCP4_VOLATILE },
3185 { "sc1_http_err_cnt", acl_parse_int, acl_fetch_sc1_http_err_cnt, acl_match_int, ACL_USE_NOTHING },
3186 { "sc2_http_err_cnt", acl_parse_int, acl_fetch_sc2_http_err_cnt, acl_match_int, ACL_USE_NOTHING },
3187 { "src_http_err_cnt", acl_parse_int, acl_fetch_src_http_err_cnt, acl_match_int, ACL_USE_TCP4_VOLATILE },
3188 { "sc1_http_err_rate", acl_parse_int, acl_fetch_sc1_http_err_rate, acl_match_int, ACL_USE_NOTHING },
3189 { "sc2_http_err_rate", acl_parse_int, acl_fetch_sc2_http_err_rate, acl_match_int, ACL_USE_NOTHING },
3190 { "src_http_err_rate", acl_parse_int, acl_fetch_src_http_err_rate, acl_match_int, ACL_USE_TCP4_VOLATILE },
3191 { "sc1_kbytes_in", acl_parse_int, acl_fetch_sc1_kbytes_in, acl_match_int, ACL_USE_TCP4_VOLATILE },
3192 { "sc2_kbytes_in", acl_parse_int, acl_fetch_sc2_kbytes_in, acl_match_int, ACL_USE_TCP4_VOLATILE },
3193 { "src_kbytes_in", acl_parse_int, acl_fetch_src_kbytes_in, acl_match_int, ACL_USE_TCP4_VOLATILE },
3194 { "sc1_bytes_in_rate", acl_parse_int, acl_fetch_sc1_bytes_in_rate, acl_match_int, ACL_USE_NOTHING },
3195 { "sc2_bytes_in_rate", acl_parse_int, acl_fetch_sc2_bytes_in_rate, acl_match_int, ACL_USE_NOTHING },
3196 { "src_bytes_in_rate", acl_parse_int, acl_fetch_src_bytes_in_rate, acl_match_int, ACL_USE_TCP4_VOLATILE },
3197 { "sc1_kbytes_out", acl_parse_int, acl_fetch_sc1_kbytes_out, acl_match_int, ACL_USE_TCP4_VOLATILE },
3198 { "sc2_kbytes_out", acl_parse_int, acl_fetch_sc2_kbytes_out, acl_match_int, ACL_USE_TCP4_VOLATILE },
3199 { "src_kbytes_out", acl_parse_int, acl_fetch_src_kbytes_out, acl_match_int, ACL_USE_TCP4_VOLATILE },
3200 { "sc1_bytes_out_rate", acl_parse_int, acl_fetch_sc1_bytes_out_rate, acl_match_int, ACL_USE_NOTHING },
3201 { "sc2_bytes_out_rate", acl_parse_int, acl_fetch_sc2_bytes_out_rate, acl_match_int, ACL_USE_NOTHING },
3202 { "src_bytes_out_rate", acl_parse_int, acl_fetch_src_bytes_out_rate, acl_match_int, ACL_USE_TCP4_VOLATILE },
Willy Tarreau8b22a712010-06-18 17:46:06 +02003203 { NULL, NULL, NULL, NULL },
3204}};
3205
3206
Willy Tarreau56123282010-08-06 19:06:56 +02003207/* Parse a "track-sc[12]" line starting with "track-sc[12]" in args[arg-1].
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +02003208 * Returns the number of warnings emitted, or -1 in case of fatal errors. The
3209 * <prm> struct is fed with the table name if any. If unspecified, the caller
3210 * will assume that the current proxy's table is used.
3211 */
3212int parse_track_counters(char **args, int *arg,
3213 int section_type, struct proxy *curpx,
3214 struct track_ctr_prm *prm,
3215 struct proxy *defpx, char *err, int errlen)
3216{
3217 int pattern_type = 0;
Willy Tarreau56123282010-08-06 19:06:56 +02003218 char *kw = args[*arg - 1];
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +02003219
Willy Tarreau56123282010-08-06 19:06:56 +02003220 /* parse the arguments of "track-sc[12]" before the condition in the
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +02003221 * following form :
Willy Tarreau56123282010-08-06 19:06:56 +02003222 * track-sc[12] src [ table xxx ] [ if|unless ... ]
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +02003223 */
3224 while (args[*arg]) {
3225 if (strcmp(args[*arg], "src") == 0) {
3226 prm->type = STKTABLE_TYPE_IP;
3227 pattern_type = 1;
3228 }
3229 else if (strcmp(args[*arg], "table") == 0) {
3230 if (!args[*arg + 1]) {
3231 snprintf(err, errlen,
Willy Tarreau56123282010-08-06 19:06:56 +02003232 "missing table for %s in %s '%s'.",
3233 kw, proxy_type_str(curpx), curpx->id);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +02003234 return -1;
3235 }
3236 /* we copy the table name for now, it will be resolved later */
3237 prm->table.n = strdup(args[*arg + 1]);
3238 (*arg)++;
3239 }
3240 else {
3241 /* unhandled keywords are handled by the caller */
3242 break;
3243 }
3244 (*arg)++;
3245 }
3246
3247 if (!pattern_type) {
3248 snprintf(err, errlen,
Willy Tarreau56123282010-08-06 19:06:56 +02003249 "%s key not specified in %s '%s' (found %s, only 'src' is supported).",
3250 kw, proxy_type_str(curpx), curpx->id, quote_arg(args[*arg]));
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +02003251 return -1;
3252 }
3253
3254 return 0;
3255}
3256
Willy Tarreau8b22a712010-06-18 17:46:06 +02003257__attribute__((constructor))
3258static void __session_init(void)
3259{
3260 acl_register_keywords(&acl_kws);
3261}
3262
Willy Tarreaubaaee002006-06-26 02:48:02 +02003263/*
3264 * Local variables:
3265 * c-indent-level: 8
3266 * c-basic-offset: 8
3267 * End:
3268 */