2
2
* Client-side variables and functions.
4
* Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
4
* Copyright 2000-2009 Willy Tarreau <w@1wt.eu>
6
6
* This program is free software; you can redistribute it and/or
7
7
* modify it under the terms of the GNU General Public License
32
32
#include <proto/fd.h>
33
33
#include <proto/log.h>
34
34
#include <proto/hdr_idx.h>
35
#include <proto/pattern.h>
36
#include <proto/proto_tcp.h>
35
37
#include <proto/proto_http.h>
36
38
#include <proto/proxy.h>
37
39
#include <proto/session.h>
112
if (l->nbconn >= l->maxconn) {
113
/* too many connections, we shoot this one and return.
114
* FIXME: it would be better to simply switch the listener's
115
* state to LI_FULL and disable the FD. We could re-enable
116
* it upon fd_delete(), but this requires all protocols to
110
122
if ((s = pool_alloc2(pool2_session)) == NULL) { /* disable this proxy for a while */
111
123
Alert("out of memory in event_accept().\n");
112
124
EV_FD_CLR(fd, DIR_RD);
160
172
if (p->options & PR_O_TCP_NOLING)
161
173
setsockopt(cfd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
175
if (global.tune.client_sndbuf)
176
setsockopt(cfd, SOL_SOCKET, SO_SNDBUF, &global.tune.client_sndbuf, sizeof(global.tune.client_sndbuf));
178
if (global.tune.client_rcvbuf)
179
setsockopt(cfd, SOL_SOCKET, SO_RCVBUF, &global.tune.client_rcvbuf, sizeof(global.tune.client_rcvbuf));
163
181
t->process = l->handler;
188
/* Note: initially, the session's backend points to the frontend.
189
* This changes later when switching rules are executed or
190
* when the default backend is assigned.
168
192
s->be = s->fe = p;
170
/* in HTTP mode, content switching requires that the backend
171
* first points to the same proxy as the frontend. However, in
172
* TCP mode there will be no header processing so any default
173
* backend must be assigned if set.
175
if (p->mode == PR_MODE_TCP) {
178
s->flags |= SN_BE_ASSIGNED;
181
s->ana_state = 0; /* analysers may change it but must reset it upon exit */
182
194
s->req = s->rep = NULL; /* will be allocated later */
184
196
s->si[0].state = s->si[0].prev_state = SI_ST_EST;
185
197
s->si[0].err_type = SI_ET_NONE;
186
198
s->si[0].err_loc = NULL;
187
199
s->si[0].owner = t;
200
s->si[0].update = stream_sock_data_finish;
188
201
s->si[0].shutr = stream_sock_shutr;
189
202
s->si[0].shutw = stream_sock_shutw;
190
203
s->si[0].chk_rcv = stream_sock_chk_rcv;
191
204
s->si[0].chk_snd = stream_sock_chk_snd;
205
s->si[0].connect = NULL;
206
s->si[0].iohandler = NULL;
192
207
s->si[0].fd = cfd;
193
s->si[0].flags = SI_FL_NONE;
208
s->si[0].flags = SI_FL_NONE | SI_FL_CAP_SPLTCP; /* TCP splicing capable */
194
209
if (s->fe->options2 & PR_O2_INDEPSTR)
195
210
s->si[0].flags |= SI_FL_INDEP_STR;
196
211
s->si[0].exp = TICK_ETERNITY;
199
214
s->si[1].err_type = SI_ET_NONE;
200
215
s->si[1].err_loc = NULL;
201
216
s->si[1].owner = t;
217
s->si[1].update = stream_sock_data_finish;
202
218
s->si[1].shutr = stream_sock_shutr;
203
219
s->si[1].shutw = stream_sock_shutw;
204
220
s->si[1].chk_rcv = stream_sock_chk_rcv;
205
221
s->si[1].chk_snd = stream_sock_chk_snd;
222
s->si[1].connect = tcpv4_connect_server;
223
s->si[1].iohandler = NULL;
206
224
s->si[1].exp = TICK_ETERNITY;
207
225
s->si[1].fd = -1; /* just to help with debugging */
208
226
s->si[1].flags = SI_FL_NONE;
213
231
s->pend_pos = NULL;
214
232
s->conn_retries = s->be->conn_retries;
234
/* init store persistence */
216
237
/* FIXME: the logs are horribly complicated now, because they are
217
238
* defined in <p>, <p>, and later <be> and <be>.
228
249
s->do_log = tcp_sess_log;
230
if (p->mode == PR_MODE_HTTP)
231
s->srv_error = http_return_srv_error;
233
s->srv_error = default_srv_error;
251
/* default error reporting function, may be changed by analysers */
252
s->srv_error = default_srv_error;
235
254
s->logs.accept_date = date; /* user-visible date for logging */
236
255
s->logs.tv_accept = now; /* corrected date for internal use */
246
265
s->data_source = DATA_SRC_NONE;
248
267
s->uniq_id = totalconn;
249
proxy_inc_fe_ctr(p); /* note: cum_beconn will be increased once assigned */
268
proxy_inc_fe_ctr(l, p); /* note: cum_beconn will be increased once assigned */
253
271
/* Those variables will be checked and freed if non-NULL in
254
272
* session.c:session_free(). It is important that they are
255
273
* properly initialized.
257
276
txn->srv_cookie = NULL;
258
277
txn->cli_cookie = NULL;
263
282
txn->hdr_idx.size = txn->hdr_idx.used = 0;
265
284
if (p->mode == PR_MODE_HTTP) {
267
txn->req.hdr_content_len = 0LL;
268
txn->rsp.hdr_content_len = 0LL;
269
txn->req.msg_state = HTTP_MSG_RQBEFORE; /* at the very beginning of the request */
270
txn->rsp.msg_state = HTTP_MSG_RPBEFORE; /* at the very beginning of the response */
271
txn->req.sol = txn->req.eol = NULL;
272
txn->req.som = txn->req.eoh = 0; /* relative to the buffer */
273
txn->rsp.sol = txn->rsp.eol = NULL;
274
txn->rsp.som = txn->rsp.eoh = 0; /* relative to the buffer */
275
txn->req.err_pos = txn->rsp.err_pos = -2; /* block buggy requests/responses */
276
if (p->options2 & PR_O2_REQBUG_OK)
277
txn->req.err_pos = -1; /* let buggy requests pass */
278
txn->auth_hdr.len = -1;
280
if (p->nb_req_cap > 0) {
281
if ((txn->req.cap = pool_alloc2(p->req_cap_pool)) == NULL)
285
/* the captures are only used in HTTP frontends */
286
if (p->nb_req_cap > 0 &&
287
(txn->req.cap = pool_alloc2(p->req_cap_pool)) == NULL)
282
288
goto out_fail_reqcap; /* no memory */
284
memset(txn->req.cap, 0, p->nb_req_cap*sizeof(char *));
288
if (p->nb_rsp_cap > 0) {
289
if ((txn->rsp.cap = pool_alloc2(p->rsp_cap_pool)) == NULL)
290
if (p->nb_rsp_cap > 0 &&
291
(txn->rsp.cap = pool_alloc2(p->rsp_cap_pool)) == NULL)
290
292
goto out_fail_rspcap; /* no memory */
292
memset(txn->rsp.cap, 0, p->nb_rsp_cap*sizeof(char *));
295
if (p->acl_requires & ACL_USE_L7_ANY) {
296
/* we have to allocate header indexes only if we know
297
* that we may make use of them. This of course includes
298
* (mode == PR_MODE_HTTP).
296
300
txn->hdr_idx.size = MAX_HTTP_HDR;
298
302
if ((txn->hdr_idx.v = pool_alloc2(p->hdr_idx_pool)) == NULL)
299
303
goto out_fail_idx; /* no memory */
301
hdr_idx_init(&txn->hdr_idx);
306
if (p->mode == PR_MODE_HTTP)
304
309
if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
305
310
&& (p->logfac1 >= 0 || p->logfac2 >= 0)) {
376
381
if ((s->req = pool_alloc2(pool2_buffer)) == NULL)
377
382
goto out_fail_req; /* no memory */
384
s->req->size = global.tune.bufsize;
379
385
buffer_init(s->req);
380
386
s->req->prod = &s->si[0];
381
387
s->req->cons = &s->si[1];
384
390
s->req->flags |= BF_READ_ATTACHED; /* the producer is already connected */
386
if (p->mode == PR_MODE_HTTP) { /* reserve some space for header rewriting */
387
s->req->max_len -= MAXREWRITE;
392
if (p->mode == PR_MODE_HTTP)
388
393
s->req->flags |= BF_READ_DONTWAIT; /* one read is usually enough */
391
395
/* activate default analysers enabled for this listener */
392
396
s->req->analysers = l->analysers;
394
if (!s->req->analysers)
395
buffer_write_ena(s->req); /* don't wait to establish connection */
398
/* note: this should not happen anymore since there's always at least the switching rules */
399
if (!s->req->analysers) {
400
buffer_auto_connect(s->req); /* don't wait to establish connection */
401
buffer_auto_close(s->req); /* let the producer forward close requests */
397
404
s->req->rto = s->fe->timeout.client;
398
405
s->req->wto = s->be->timeout.server;
401
408
if ((s->rep = pool_alloc2(pool2_buffer)) == NULL)
402
409
goto out_fail_rep; /* no memory */
411
s->rep->size = global.tune.bufsize;
404
412
buffer_init(s->rep);
405
413
s->rep->prod = &s->si[1];
406
414
s->rep->cons = &s->si[0];
422
430
fdtab[cfd].owner = &s->si[0];
423
431
fdtab[cfd].state = FD_STREADY;
432
fdtab[cfd].flags = FD_FL_TCP | FD_FL_TCP_NODELAY;
433
if (p->options & PR_O_TCP_NOLING)
434
fdtab[cfd].flags |= FD_FL_TCP_NOLING;
424
436
fdtab[cfd].cb[DIR_RD].f = l->proto->read;
425
437
fdtab[cfd].cb[DIR_RD].b = s->req;
426
438
fdtab[cfd].cb[DIR_WR].f = l->proto->write;
427
439
fdtab[cfd].cb[DIR_WR].b = s->rep;
428
fdtab[cfd].peeraddr = (struct sockaddr *)&s->cli_addr;
429
fdtab[cfd].peerlen = sizeof(s->cli_addr);
440
fdinfo[cfd].peeraddr = (struct sockaddr *)&s->cli_addr;
441
fdinfo[cfd].peerlen = sizeof(s->cli_addr);
431
443
if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
432
444
(p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK))) {
434
446
* or we're in health check mode with the 'httpchk' option enabled. In
435
447
* both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
437
struct chunk msg = { .str = "HTTP/1.0 200 OK\r\n\r\n", .len = 19 };
450
chunk_initstr(&msg, "HTTP/1.0 200 OK\r\n\r\n");
438
451
stream_int_retnclose(&s->si[0], &msg); /* forge a 200 response */
439
452
s->req->analysers = 0;
440
453
t->expire = s->rep->wex;
442
455
else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
443
struct chunk msg = { .str = "OK\n", .len = 3 };
457
chunk_initstr(&msg, "OK\n");
444
458
stream_int_retnclose(&s->si[0], &msg); /* forge an "OK" response */
445
459
s->req->analysers = 0;
446
460
t->expire = s->rep->wex;
456
470
task_wakeup(t, TASK_WOKEN_INIT);
472
l->nbconn++; /* warning! right now, it's up to the handler to decrease this */
473
if (l->nbconn >= l->maxconn) {
474
EV_FD_CLR(l->fd, DIR_RD);
458
478
p->feconn++; /* beconn will be increased later */
459
if (p->feconn > p->feconn_max)
460
p->feconn_max = p->feconn;
479
if (p->feconn > p->counters.feconn_max)
480
p->counters.feconn_max = p->feconn;
462
if (s->flags & SN_BE_ASSIGNED) {
463
proxy_inc_be_ctr(s->be);
465
if (s->be->beconn > s->be->beconn_max)
466
s->be->beconn_max = s->be->beconn;
483
if (l->nbconn > l->counters->conn_max)
484
l->counters->conn_max = l->nbconn;
516
/* set test->i to the connexion's source port */
534
/* extract the connection's source address */
536
pattern_fetch_src(struct proxy *px, struct session *l4, void *l7, int dir,
537
const char *arg, int arg_len, union pattern_data *data)
539
data->ip.s_addr = ((struct sockaddr_in *)&l4->cli_addr)->sin_addr.s_addr;
544
/* set test->i to the connection's source port */
518
546
acl_fetch_sport(struct proxy *px, struct session *l4, void *l7, int dir,
519
547
struct acl_expr *expr, struct acl_test *test)
576
/* extract the connection's destination address */
578
pattern_fetch_dst(struct proxy *px, struct session *l4, void *l7, int dir,
579
const char *arg, int arg_len, union pattern_data *data)
581
data->ip.s_addr = ((struct sockaddr_in *)&l4->frt_addr)->sin_addr.s_addr;
548
585
/* set test->i to the frontend connexion's destination port */
550
587
acl_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir,
602
pattern_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir,
603
const char *arg, int arg_len, union pattern_data *data)
606
data->integer = ntohs(((struct sockaddr_in *)&l4->frt_addr)->sin_port);
565
610
/* set test->i to the number of connexions to the same listening socket */
619
/* set test->i to the id of the frontend */
621
acl_fetch_fe_id(struct proxy *px, struct session *l4, void *l7, int dir,
622
struct acl_expr *expr, struct acl_test *test) {
624
test->flags = ACL_TEST_F_READ_ONLY;
626
test->i = l4->fe->uuid;
631
/* set test->i to the id of the socket (listener) */
633
acl_fetch_so_id(struct proxy *px, struct session *l4, void *l7, int dir,
634
struct acl_expr *expr, struct acl_test *test) {
636
test->flags = ACL_TEST_F_READ_ONLY;
638
test->i = l4->listener->luid;
575
644
/* Note: must not be declared <const> as its list will be overwritten */
576
645
static struct acl_kw_list acl_kws = {{ },{
582
651
{ "src_limit", acl_parse_int, acl_fetch_sconn, acl_match_int },
584
653
{ "dst_conn", acl_parse_int, acl_fetch_dconn, acl_match_int, ACL_USE_NOTHING },
654
{ "fe_id", acl_parse_int, acl_fetch_fe_id, acl_match_int, ACL_USE_NOTHING },
655
{ "so_id", acl_parse_int, acl_fetch_so_id, acl_match_int, ACL_USE_NOTHING },
585
656
{ NULL, NULL, NULL, NULL },
660
/* Note: must not be declared <const> as its list will be overwritten */
661
static struct pattern_fetch_kw_list pattern_fetch_keywords = {{ },{
662
{ "src", pattern_fetch_src, PATTERN_TYPE_IP, PATTERN_FETCH_REQ },
663
{ "dst", pattern_fetch_dst, PATTERN_TYPE_IP, PATTERN_FETCH_REQ },
664
{ "dst_port", pattern_fetch_dport, PATTERN_TYPE_INTEGER, PATTERN_FETCH_REQ },
665
{ NULL, NULL, 0, 0 },
589
669
__attribute__((constructor))
590
670
static void __client_init(void)
592
672
acl_register_keywords(&acl_kws);
673
pattern_register_fetches(&pattern_fetch_keywords);