~ubuntu-branches/debian/sid/haproxy/sid

« back to all changes in this revision

Viewing changes to .pc/from-upstream/0004-BUG-MAJOR-frontend-initialize-capture-pointers-earli.patch/src/frontend.c

  • Committer: Package Import Robot
  • Author(s): Vincent Bernat
  • Date: 2014-12-07 11:11:21 UTC
  • Revision ID: package-import@ubuntu.com-20141207111121-qgifv7nl6eoi3lek
Tags: 1.5.8-2
* Cherry-pick the following patches from 1.5.9 release:
    - 8a0b93bde77e BUG/MAJOR: sessions: unlink session from list on out
                              of memory
    - bae03eaad40a BUG/MEDIUM: pattern: don't load more than once a pattern
                               list.
    - 93637b6e8503 BUG/MEDIUM: connection: sanitize PPv2 header length before
                               parsing address information
    - 8ba50128832b BUG/MAJOR: frontend: initialize capture pointers earlier
    - 1f96a87c4e14 BUG/MEDIUM: checks: fix conflicts between agent checks and
                               ssl healthchecks
    - 9bcc01ae2598 BUG/MEDIUM: ssl: force a full GC in case of memory shortage
    - 909514970089 BUG/MEDIUM: ssl: fix bad ssl context init can cause
                               segfault in case of OOM.
* Cherry-pick the following patches from future 1.5.10 release:
    - 1e89acb6be9b BUG/MEDIUM: payload: ensure that a request channel is
                               available
    - bad3c6f1b6d7 BUG/MEDIUM: patterns: previous fix was incomplete

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Frontend variables and functions.
 
3
 *
 
4
 * Copyright 2000-2013 Willy Tarreau <w@1wt.eu>
 
5
 *
 
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 <errno.h>
 
14
#include <fcntl.h>
 
15
#include <stdio.h>
 
16
#include <stdlib.h>
 
17
#include <string.h>
 
18
 
 
19
#include <sys/socket.h>
 
20
#include <sys/stat.h>
 
21
#include <sys/types.h>
 
22
 
 
23
#include <netinet/tcp.h>
 
24
 
 
25
#include <common/chunk.h>
 
26
#include <common/compat.h>
 
27
#include <common/config.h>
 
28
#include <common/debug.h>
 
29
#include <common/standard.h>
 
30
#include <common/time.h>
 
31
 
 
32
#include <types/global.h>
 
33
 
 
34
#include <proto/acl.h>
 
35
#include <proto/arg.h>
 
36
#include <proto/channel.h>
 
37
#include <proto/fd.h>
 
38
#include <proto/frontend.h>
 
39
#include <proto/log.h>
 
40
#include <proto/hdr_idx.h>
 
41
#include <proto/proto_tcp.h>
 
42
#include <proto/proto_http.h>
 
43
#include <proto/proxy.h>
 
44
#include <proto/sample.h>
 
45
#include <proto/session.h>
 
46
#include <proto/stream_interface.h>
 
47
#include <proto/task.h>
 
48
 
 
49
/* Finish a session accept() for a proxy (TCP or HTTP). It returns a negative
 
50
 * value in case of a critical failure which must cause the listener to be
 
51
 * disabled, a positive value in case of success, or zero if it is a success
 
52
 * but the session must be closed ASAP (eg: monitoring). It only supports
 
53
 * sessions with a connection in si[0].
 
54
 */
 
55
int frontend_accept(struct session *s)
 
56
{
 
57
        struct connection *conn = __objt_conn(s->si[0].end);
 
58
        int cfd = conn->t.sock.fd;
 
59
 
 
60
        tv_zero(&s->logs.tv_request);
 
61
        s->logs.t_queue = -1;
 
62
        s->logs.t_connect = -1;
 
63
        s->logs.t_data = -1;
 
64
        s->logs.t_close = 0;
 
65
        s->logs.bytes_in = s->logs.bytes_out = 0;
 
66
        s->logs.prx_queue_size = 0;  /* we get the number of pending conns before us */
 
67
        s->logs.srv_queue_size = 0; /* we will get this number soon */
 
68
 
 
69
        /* FIXME: the logs are horribly complicated now, because they are
 
70
         * defined in <p>, <p>, and later <be> and <be>.
 
71
         */
 
72
        s->do_log = sess_log;
 
73
 
 
74
        /* default error reporting function, may be changed by analysers */
 
75
        s->srv_error = default_srv_error;
 
76
 
 
77
        /* Adjust some socket options */
 
78
        if (s->listener->addr.ss_family == AF_INET || s->listener->addr.ss_family == AF_INET6) {
 
79
                if (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
 
80
                               (char *) &one, sizeof(one)) == -1)
 
81
                        goto out_return;
 
82
 
 
83
                if (s->fe->options & PR_O_TCP_CLI_KA)
 
84
                        setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE,
 
85
                                   (char *) &one, sizeof(one));
 
86
 
 
87
                if (s->fe->options & PR_O_TCP_NOLING)
 
88
                        fdtab[cfd].linger_risk = 1;
 
89
 
 
90
#if defined(TCP_MAXSEG)
 
91
                if (s->listener->maxseg < 0) {
 
92
                        /* we just want to reduce the current MSS by that value */
 
93
                        int mss;
 
94
                        socklen_t mss_len = sizeof(mss);
 
95
                        if (getsockopt(cfd, IPPROTO_TCP, TCP_MAXSEG, &mss, &mss_len) == 0) {
 
96
                                mss += s->listener->maxseg; /* remember, it's < 0 */
 
97
                                setsockopt(cfd, IPPROTO_TCP, TCP_MAXSEG, &mss, sizeof(mss));
 
98
                        }
 
99
                }
 
100
#endif
 
101
        }
 
102
 
 
103
        if (global.tune.client_sndbuf)
 
104
                setsockopt(cfd, SOL_SOCKET, SO_SNDBUF, &global.tune.client_sndbuf, sizeof(global.tune.client_sndbuf));
 
105
 
 
106
        if (global.tune.client_rcvbuf)
 
107
                setsockopt(cfd, SOL_SOCKET, SO_RCVBUF, &global.tune.client_rcvbuf, sizeof(global.tune.client_rcvbuf));
 
108
 
 
109
        if (unlikely(s->fe->nb_req_cap > 0 && (s->txn.req.cap = pool_alloc2(s->fe->req_cap_pool)) == NULL))
 
110
                goto out_return;        /* no memory */
 
111
 
 
112
        if (unlikely(s->fe->nb_rsp_cap > 0 && (s->txn.rsp.cap = pool_alloc2(s->fe->rsp_cap_pool)) == NULL))
 
113
                goto out_free_reqcap;   /* no memory */
 
114
 
 
115
        if (s->fe->http_needed) {
 
116
                /* we have to allocate header indexes only if we know
 
117
                 * that we may make use of them. This of course includes
 
118
                 * (mode == PR_MODE_HTTP).
 
119
                 */
 
120
                s->txn.hdr_idx.size = global.tune.max_http_hdr;
 
121
 
 
122
                if (unlikely((s->txn.hdr_idx.v = pool_alloc2(pool2_hdr_idx)) == NULL))
 
123
                        goto out_free_rspcap; /* no memory */
 
124
 
 
125
                /* and now initialize the HTTP transaction state */
 
126
                http_init_txn(s);
 
127
        }
 
128
 
 
129
        if ((s->fe->mode == PR_MODE_TCP || s->fe->mode == PR_MODE_HTTP)
 
130
            && (!LIST_ISEMPTY(&s->fe->logsrvs))) {
 
131
                if (likely(!LIST_ISEMPTY(&s->fe->logformat))) {
 
132
                        /* we have the client ip */
 
133
                        if (s->logs.logwait & LW_CLIP)
 
134
                                if (!(s->logs.logwait &= ~(LW_CLIP|LW_INIT)))
 
135
                                        s->do_log(s);
 
136
                }
 
137
                else {
 
138
                        char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
 
139
 
 
140
                        conn_get_from_addr(conn);
 
141
                        conn_get_to_addr(conn);
 
142
 
 
143
                        switch (addr_to_str(&conn->addr.from, pn, sizeof(pn))) {
 
144
                        case AF_INET:
 
145
                        case AF_INET6:
 
146
                                addr_to_str(&conn->addr.to, sn, sizeof(sn));
 
147
                                send_log(s->fe, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
 
148
                                         pn, get_host_port(&conn->addr.from),
 
149
                                         sn, get_host_port(&conn->addr.to),
 
150
                                         s->fe->id, (s->fe->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
 
151
                                break;
 
152
                        case AF_UNIX:
 
153
                                /* UNIX socket, only the destination is known */
 
154
                                send_log(s->fe, LOG_INFO, "Connect to unix:%d (%s/%s)\n",
 
155
                                         s->listener->luid,
 
156
                                         s->fe->id, (s->fe->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
 
157
                                break;
 
158
                        }
 
159
                }
 
160
        }
 
161
 
 
162
        if (unlikely((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
 
163
                char pn[INET6_ADDRSTRLEN];
 
164
 
 
165
                conn_get_from_addr(conn);
 
166
 
 
167
                switch (addr_to_str(&conn->addr.from, pn, sizeof(pn))) {
 
168
                case AF_INET:
 
169
                case AF_INET6:
 
170
                        chunk_printf(&trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
 
171
                                     s->uniq_id, s->fe->id, (unsigned short)s->listener->fd, (unsigned short)cfd,
 
172
                                     pn, get_host_port(&conn->addr.from));
 
173
                        break;
 
174
                case AF_UNIX:
 
175
                        /* UNIX socket, only the destination is known */
 
176
                        chunk_printf(&trash, "%08x:%s.accept(%04x)=%04x from [unix:%d]\n",
 
177
                                     s->uniq_id, s->fe->id, (unsigned short)s->listener->fd, (unsigned short)cfd,
 
178
                                     s->listener->luid);
 
179
                        break;
 
180
                }
 
181
 
 
182
                shut_your_big_mouth_gcc(write(1, trash.str, trash.len));
 
183
        }
 
184
 
 
185
        if (s->fe->mode == PR_MODE_HTTP)
 
186
                s->req->flags |= CF_READ_DONTWAIT; /* one read is usually enough */
 
187
 
 
188
        /* note: this should not happen anymore since there's always at least the switching rules */
 
189
        if (!s->req->analysers) {
 
190
                channel_auto_connect(s->req);  /* don't wait to establish connection */
 
191
                channel_auto_close(s->req);    /* let the producer forward close requests */
 
192
        }
 
193
 
 
194
        s->req->rto = s->fe->timeout.client;
 
195
        s->rep->wto = s->fe->timeout.client;
 
196
 
 
197
        /* everything's OK, let's go on */
 
198
        return 1;
 
199
 
 
200
        /* Error unrolling */
 
201
 out_free_rspcap:
 
202
        pool_free2(s->fe->rsp_cap_pool, s->txn.rsp.cap);
 
203
 out_free_reqcap:
 
204
        pool_free2(s->fe->req_cap_pool, s->txn.req.cap);
 
205
 out_return:
 
206
        return -1;
 
207
}
 
208
 
 
209
/************************************************************************/
 
210
/*      All supported sample and ACL keywords must be declared here.    */
 
211
/************************************************************************/
 
212
 
 
213
/* set temp integer to the id of the frontend */
 
214
static int
 
215
smp_fetch_fe_id(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
 
216
                const struct arg *args, struct sample *smp, const char *kw)
 
217
{
 
218
        smp->flags = SMP_F_VOL_SESS;
 
219
        smp->type = SMP_T_UINT;
 
220
        smp->data.uint = l4->fe->uuid;
 
221
        return 1;
 
222
}
 
223
 
 
224
/* set temp integer to the number of connections per second reaching the frontend.
 
225
 * Accepts exactly 1 argument. Argument is a frontend, other types will cause
 
226
 * an undefined behaviour.
 
227
 */
 
228
static int
 
229
smp_fetch_fe_sess_rate(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
 
230
                       const struct arg *args, struct sample *smp, const char *kw)
 
231
{
 
232
        smp->flags = SMP_F_VOL_TEST;
 
233
        smp->type = SMP_T_UINT;
 
234
        smp->data.uint = read_freq_ctr(&args->data.prx->fe_sess_per_sec);
 
235
        return 1;
 
236
}
 
237
 
 
238
/* set temp integer to the number of concurrent connections on the frontend
 
239
 * Accepts exactly 1 argument. Argument is a frontend, other types will cause
 
240
 * an undefined behaviour.
 
241
 */
 
242
static int
 
243
smp_fetch_fe_conn(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
 
244
                  const struct arg *args, struct sample *smp, const char *kw)
 
245
{
 
246
        smp->flags = SMP_F_VOL_TEST;
 
247
        smp->type = SMP_T_UINT;
 
248
        smp->data.uint = args->data.prx->feconn;
 
249
        return 1;
 
250
}
 
251
 
 
252
 
 
253
/* Note: must not be declared <const> as its list will be overwritten.
 
254
 * Please take care of keeping this list alphabetically sorted.
 
255
 */
 
256
static struct sample_fetch_kw_list smp_kws = {ILH, {
 
257
        { "fe_conn",      smp_fetch_fe_conn,      ARG1(1,FE), NULL, SMP_T_UINT, SMP_USE_INTRN, },
 
258
        { "fe_id",        smp_fetch_fe_id,        0,          NULL, SMP_T_UINT, SMP_USE_FTEND, },
 
259
        { "fe_sess_rate", smp_fetch_fe_sess_rate, ARG1(1,FE), NULL, SMP_T_UINT, SMP_USE_INTRN, },
 
260
        { /* END */ },
 
261
}};
 
262
 
 
263
 
 
264
/* Note: must not be declared <const> as its list will be overwritten.
 
265
 * Please take care of keeping this list alphabetically sorted.
 
266
 */
 
267
static struct acl_kw_list acl_kws = {ILH, {
 
268
        { /* END */ },
 
269
}};
 
270
 
 
271
 
 
272
__attribute__((constructor))
 
273
static void __frontend_init(void)
 
274
{
 
275
        sample_register_fetches(&smp_kws);
 
276
        acl_register_keywords(&acl_kws);
 
277
}
 
278
 
 
279
 
 
280
/*
 
281
 * Local variables:
 
282
 *  c-indent-level: 8
 
283
 *  c-basic-offset: 8
 
284
 * End:
 
285
 */