~ubuntu-branches/ubuntu/precise/haproxy/precise-proposed

« back to all changes in this revision

Viewing changes to src/client.c

  • Committer: Bazaar Package Importer
  • Author(s): Arnaud Cornet
  • Date: 2010-04-15 20:00:34 UTC
  • mfrom: (1.1.8 upstream) (2.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20100415200034-is2r38tyvmtvi3ml
Tags: 1.4.4-1
* New upstream release
* Add splice and tproxy support
* Add regparm optimization on i386
* Switch to dpkg-source 3.0 (quilt) format

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * Client-side variables and functions.
3
3
 *
4
 
 * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
 
4
 * Copyright 2000-2009 Willy Tarreau <w@1wt.eu>
5
5
 *
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>
107
109
                        }
108
110
                }
109
111
 
 
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
 
117
                         * be switched.
 
118
                         */
 
119
                        goto out_close;
 
120
                }
 
121
 
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));
162
174
 
 
175
                if (global.tune.client_sndbuf)
 
176
                        setsockopt(cfd, SOL_SOCKET, SO_SNDBUF, &global.tune.client_sndbuf, sizeof(global.tune.client_sndbuf));
 
177
 
 
178
                if (global.tune.client_rcvbuf)
 
179
                        setsockopt(cfd, SOL_SOCKET, SO_RCVBUF, &global.tune.client_rcvbuf, sizeof(global.tune.client_rcvbuf));
 
180
 
163
181
                t->process = l->handler;
164
182
                t->context = s;
 
183
                t->nice = l->nice;
165
184
 
166
185
                s->task = t;
167
186
                s->listener = l;
 
187
 
 
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.
 
191
                 */
168
192
                s->be = s->fe = p;
169
193
 
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.
174
 
                 */
175
 
                if (p->mode == PR_MODE_TCP) {
176
 
                        if (p->defbe.be)
177
 
                                s->be = p->defbe.be;
178
 
                        s->flags |= SN_BE_ASSIGNED;
179
 
                }
180
 
 
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 */
183
195
 
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;
215
233
 
 
234
                /* init store persistence */
 
235
                s->store_count = 0;
 
236
 
216
237
                /* FIXME: the logs are horribly complicated now, because they are
217
238
                 * defined in <p>, <p>, and later <be> and <be>.
218
239
                 */
227
248
                else
228
249
                        s->do_log = tcp_sess_log;
229
250
 
230
 
                if (p->mode == PR_MODE_HTTP)
231
 
                        s->srv_error = http_return_srv_error;
232
 
                else
233
 
                        s->srv_error = default_srv_error;
 
251
                /* default error reporting function, may be changed by analysers */
 
252
                s->srv_error = default_srv_error;
234
253
 
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;
247
266
 
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 */
250
269
 
251
270
                txn = &s->txn;
252
 
                txn->flags = 0;
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.
256
274
                 */
 
275
                txn->sessid = NULL;
257
276
                txn->srv_cookie = NULL;
258
277
                txn->cli_cookie = NULL;
259
278
                txn->uri = NULL;
263
282
                txn->hdr_idx.size = txn->hdr_idx.used = 0;
264
283
 
265
284
                if (p->mode == PR_MODE_HTTP) {
266
 
                        txn->status = -1;
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;
279
 
 
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 */
283
289
 
284
 
                                memset(txn->req.cap, 0, p->nb_req_cap*sizeof(char *));
285
 
                        }
286
 
 
287
 
 
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 */
291
 
 
292
 
                                memset(txn->rsp.cap, 0, p->nb_rsp_cap*sizeof(char *));
293
 
                        }
294
 
 
295
 
 
 
293
                }
 
294
 
 
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).
 
299
                         */
296
300
                        txn->hdr_idx.size = MAX_HTTP_HDR;
297
301
 
298
302
                        if ((txn->hdr_idx.v = pool_alloc2(p->hdr_idx_pool)) == NULL)
299
303
                                goto out_fail_idx; /* no memory */
300
 
 
301
 
                        hdr_idx_init(&txn->hdr_idx);
302
304
                }
303
305
 
 
306
                if (p->mode == PR_MODE_HTTP)
 
307
                        http_init_txn(s);
 
308
 
304
309
                if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
305
310
                    && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
306
311
                        if (p->to_log) {
376
381
                if ((s->req = pool_alloc2(pool2_buffer)) == NULL)
377
382
                        goto out_fail_req; /* no memory */
378
383
 
 
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];
383
389
 
384
390
                s->req->flags |= BF_READ_ATTACHED; /* the producer is already connected */
385
391
 
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 */
389
 
                }
390
394
 
391
395
                /* activate default analysers enabled for this listener */
392
396
                s->req->analysers = l->analysers;
393
397
 
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 */
 
402
                }
396
403
 
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 */
403
410
 
 
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];
421
429
                fd_insert(cfd);
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;
 
435
 
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);
430
442
 
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.
436
448
                         */
437
 
                        struct chunk msg = { .str = "HTTP/1.0 200 OK\r\n\r\n", .len = 19 };
 
449
                        struct chunk msg;
 
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;
441
454
                }
442
455
                else if (p->mode == PR_MODE_HEALTH) {  /* health check mode, no client reading */
443
 
                        struct chunk msg = { .str = "OK\n", .len = 3 };
 
456
                        struct chunk msg;
 
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;
455
469
                 */
456
470
                task_wakeup(t, TASK_WOKEN_INIT);
457
471
 
 
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);
 
475
                        l->state = LI_FULL;
 
476
                }
 
477
 
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;
461
481
 
462
 
                if (s->flags & SN_BE_ASSIGNED) {
463
 
                        proxy_inc_be_ctr(s->be);
464
 
                        s->be->beconn++;
465
 
                        if (s->be->beconn > s->be->beconn_max)
466
 
                                s->be->beconn_max = s->be->beconn;
 
482
                if (l->counters) {
 
483
                        if (l->nbconn > l->counters->conn_max)
 
484
                                l->counters->conn_max = l->nbconn;
467
485
                }
 
486
 
468
487
                actconn++;
469
488
                totalconn++;
470
489
 
512
531
        return 1;
513
532
}
514
533
 
515
 
 
516
 
/* set test->i to the connexion's source port */
 
534
/* extract the connection's source address */
 
535
static int
 
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)
 
538
{
 
539
        data->ip.s_addr = ((struct sockaddr_in *)&l4->cli_addr)->sin_addr.s_addr;
 
540
        return 1;
 
541
}
 
542
 
 
543
 
 
544
/* set test->i to the connection's source port */
517
545
static int
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)
545
573
}
546
574
 
547
575
 
 
576
/* extract the connection's destination address */
 
577
static int
 
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)
 
580
{
 
581
        data->ip.s_addr = ((struct sockaddr_in *)&l4->frt_addr)->sin_addr.s_addr;
 
582
        return 1;
 
583
}
 
584
 
548
585
/* set test->i to the frontend connexion's destination port */
549
586
static int
550
587
acl_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir,
561
598
        return 1;
562
599
}
563
600
 
 
601
static int
 
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)
 
604
 
 
605
{
 
606
        data->integer = ntohs(((struct sockaddr_in *)&l4->frt_addr)->sin_port);
 
607
        return 1;
 
608
}
564
609
 
565
610
/* set test->i to the number of connexions to the same listening socket */
566
611
static int
571
616
        return 1;
572
617
}
573
618
 
 
619
/* set test->i to the id of the frontend */
 
620
static int
 
621
acl_fetch_fe_id(struct proxy *px, struct session *l4, void *l7, int dir,
 
622
                struct acl_expr *expr, struct acl_test *test) {
 
623
 
 
624
        test->flags = ACL_TEST_F_READ_ONLY;
 
625
 
 
626
        test->i = l4->fe->uuid;
 
627
 
 
628
        return 1;
 
629
}
 
630
 
 
631
/* set test->i to the id of the socket (listener) */
 
632
static int
 
633
acl_fetch_so_id(struct proxy *px, struct session *l4, void *l7, int dir,
 
634
                struct acl_expr *expr, struct acl_test *test) {
 
635
 
 
636
        test->flags = ACL_TEST_F_READ_ONLY;
 
637
 
 
638
        test->i = l4->listener->luid;
 
639
 
 
640
        return 1;
 
641
}
 
642
 
574
643
 
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 },
583
652
#endif
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 },
586
657
}};
587
658
 
588
659
 
 
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 },
 
666
}};
 
667
 
 
668
 
589
669
__attribute__((constructor))
590
670
static void __client_init(void)
591
671
{
592
672
        acl_register_keywords(&acl_kws);
 
673
        pattern_register_fetches(&pattern_fetch_keywords);
593
674
}
594
675
 
595
676