source: bin/varnishd/cache_acceptor.c @ b37c01

Revision b37c01, 9.8 KB checked in by Poul-Henning Kamp <phk@…>, 3 years ago (diff)

Since we're cleaning up, rename TIM_ to VTIM_ and take out of libvarnish.h

  • Property mode set to 100644
Line 
1/*-
2 * Copyright (c) 2006 Verdens Gang AS
3 * Copyright (c) 2006-2011 Varnish Software AS
4 * All rights reserved.
5 *
6 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 */
30
31#include "config.h"
32
33#include "cache.h"
34
35#include "vcli.h"
36#include "vtcp.h"
37#include "vtim.h"
38#include "cli_priv.h"
39
40static pthread_t        VCA_thread;
41static struct timeval   tv_sndtimeo;
42static struct timeval   tv_rcvtimeo;
43
44/*--------------------------------------------------------------------
45 * We want to get out of any kind of trouble-hit TCP connections as fast
46 * as absolutely possible, so we set them LINGER enabled with zero timeout,
47 * so that even if there are outstanding write data on the socket, a close(2)
48 * will return immediately.
49 */
50static const struct linger linger = {
51        .l_onoff        =       0,
52};
53
54static unsigned char    need_sndtimeo, need_rcvtimeo, need_linger, need_test;
55
56static void
57sock_test(int fd)
58{
59        struct linger lin;
60        struct timeval tv;
61        socklen_t l;
62        int i;
63
64        l = sizeof lin;
65        i = getsockopt(fd, SOL_SOCKET, SO_LINGER, &lin, &l);
66        if (i) {
67                VTCP_Assert(i);
68                return;
69        }
70        assert(l == sizeof lin);
71        if (memcmp(&lin, &linger, l))
72                need_linger = 1;
73
74#ifdef SO_SNDTIMEO_WORKS
75        l = sizeof tv;
76        i = getsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, &l);
77        if (i) {
78                VTCP_Assert(i);
79                return;
80        }
81        assert(l == sizeof tv);
82        if (memcmp(&tv, &tv_sndtimeo, l))
83                need_sndtimeo = 1;
84#else
85        (void)tv;
86        (void)tv_sndtimeo;
87        (void)need_sndtimeo;
88#endif
89
90#ifdef SO_RCVTIMEO_WORKS
91        l = sizeof tv;
92        i = getsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, &l);
93        if (i) {
94                VTCP_Assert(i);
95                return;
96        }
97        assert(l == sizeof tv);
98        if (memcmp(&tv, &tv_rcvtimeo, l))
99                need_rcvtimeo = 1;
100#else
101        (void)tv;
102        (void)tv_rcvtimeo;
103        (void)need_rcvtimeo;
104#endif
105
106        need_test = 0;
107}
108
109/*--------------------------------------------------------------------
110 * Called once the workerthread gets hold of the session, to do setup
111 * setup overhead, we don't want to bother the acceptor thread with.
112 */
113
114void
115VCA_Prep(struct sess *sp)
116{
117        char addr[VTCP_ADDRBUFSIZE];
118        char port[VTCP_PORTBUFSIZE];
119
120        VTCP_name(&sp->sockaddr, sp->sockaddrlen,
121            addr, sizeof addr, port, sizeof port);
122        sp->addr = WS_Dup(sp->ws, addr);
123        sp->port = WS_Dup(sp->ws, port);
124        if (params->log_local_addr) {
125                AZ(getsockname(sp->fd, (void*)&sp->mysockaddr, &sp->mysockaddrlen));
126                VTCP_name(&sp->mysockaddr, sp->mysockaddrlen,
127                    addr, sizeof addr, port, sizeof port);
128                WSP(sp, SLT_SessionOpen, "%s %s %s %s",
129                    sp->addr, sp->port, addr, port);
130        } else {
131                WSP(sp, SLT_SessionOpen, "%s %s %s",
132                    sp->addr, sp->port, sp->mylsock->name);
133        }
134        sp->acct_ses.first = sp->t_open;
135        if (need_test)
136                sock_test(sp->fd);
137        if (need_linger)
138                VTCP_Assert(setsockopt(sp->fd, SOL_SOCKET, SO_LINGER,
139                    &linger, sizeof linger));
140#ifdef SO_SNDTIMEO_WORKS
141        if (need_sndtimeo)
142                VTCP_Assert(setsockopt(sp->fd, SOL_SOCKET, SO_SNDTIMEO,
143                    &tv_sndtimeo, sizeof tv_sndtimeo));
144#endif
145#ifdef SO_RCVTIMEO_WORKS
146        if (need_rcvtimeo)
147                VTCP_Assert(setsockopt(sp->fd, SOL_SOCKET, SO_RCVTIMEO,
148                    &tv_rcvtimeo, sizeof tv_rcvtimeo));
149#endif
150}
151
152/*--------------------------------------------------------------------
153 * If accept(2)'ing fails, we pace ourselves to relive any resource
154 * shortage if possible.
155 */
156
157static double vca_pace = 0.0;
158static struct lock pace_mtx;
159
160static void
161vca_pace_check(void)
162{
163        double p;
164
165        if (vca_pace == 0.0)
166                return;
167        Lck_Lock(&pace_mtx);
168        p = vca_pace;
169        Lck_Unlock(&pace_mtx);
170        if (p > 0.0)
171                VTIM_sleep(p);
172}
173
174static void
175vca_pace_bad(void)
176{
177
178        Lck_Lock(&pace_mtx);
179        vca_pace += params->acceptor_sleep_incr;
180        if (vca_pace > params->acceptor_sleep_max)
181                vca_pace = params->acceptor_sleep_max;
182        Lck_Unlock(&pace_mtx);
183}
184
185static void
186vca_pace_good(void)
187{
188
189        if (vca_pace == 0.0)
190                return;
191        Lck_Lock(&pace_mtx);
192        vca_pace *= params->acceptor_sleep_decay;
193        if (vca_pace < params->acceptor_sleep_incr)
194                vca_pace = 0.0;
195        Lck_Unlock(&pace_mtx);
196}
197
198/*--------------------------------------------------------------------
199 * Accept on a listen socket, and handle error returns.
200 */
201
202static int hack_ready;
203
204int
205VCA_Accept(struct listen_sock *ls, struct wrk_accept *wa)
206{
207        int i;
208
209        CHECK_OBJ_NOTNULL(ls, LISTEN_SOCK_MAGIC);
210        vca_pace_check();
211
212        while(!hack_ready)
213                (void)usleep(100*1000);
214
215        wa->acceptaddrlen = sizeof wa->acceptaddr;
216        i = accept(ls->sock, (void*)&wa->acceptaddr, &wa->acceptaddrlen);
217
218        if (i < 0) {
219                switch (errno) {
220                case ECONNABORTED:
221                        break;
222                case EMFILE:
223                        VSL(SLT_Debug, ls->sock, "Too many open files");
224                        vca_pace_bad();
225                        break;
226                default:
227                        VSL(SLT_Debug, ls->sock, "Accept failed: %s",
228                            strerror(errno));
229                        vca_pace_bad();
230                        break;
231                }
232        }
233        wa->acceptlsock = ls;
234        wa->acceptsock = i;
235        return (i);
236}
237
238/*--------------------------------------------------------------------
239 * Fail a session
240 *
241 * This happens if we accept the socket, but cannot get a session
242 * structure.
243 *
244 * We consider this a DoS situation (false positive:  Extremely popular
245 * busy objects) and silently close the connection with minimum effort
246 * and fuzz, rather than try to send an intelligent message back.
247 */
248
249void
250VCA_FailSess(struct worker *w)
251{
252        struct wrk_accept *wa;
253
254        CHECK_OBJ_NOTNULL(w, WORKER_MAGIC);
255        CAST_OBJ_NOTNULL(wa, (void*)w->ws->f, WRK_ACCEPT_MAGIC);
256        AZ(w->sp);
257        AZ(close(wa->acceptsock));
258        w->stats.sess_drop++;
259        vca_pace_bad();
260}
261
262/*--------------------------------------------------------------------*/
263
264void
265VCA_SetupSess(struct worker *w)
266{
267        struct sess *sp;
268        struct wrk_accept *wa;
269
270        CHECK_OBJ_NOTNULL(w, WORKER_MAGIC);
271        CAST_OBJ_NOTNULL(wa, (void*)w->ws->f, WRK_ACCEPT_MAGIC);
272        sp = w->sp;
273        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
274        sp->fd = wa->acceptsock;
275        sp->vsl_id = wa->acceptsock | VSL_CLIENTMARKER ;
276        wa->acceptsock = -1;
277        sp->t_open = VTIM_real();
278        sp->t_end = sp->t_open;
279        sp->mylsock = wa->acceptlsock;
280        CHECK_OBJ_NOTNULL(sp->mylsock, LISTEN_SOCK_MAGIC);
281        assert(wa->acceptaddrlen <= sp->sockaddrlen);
282        memcpy(&sp->sockaddr, &wa->acceptaddr, wa->acceptaddrlen);
283        sp->sockaddrlen = wa->acceptaddrlen;
284        sp->step = STP_FIRST;
285        vca_pace_good();
286        w->stats.sess_conn++;
287}
288
289/*--------------------------------------------------------------------*/
290
291static void *
292vca_acct(void *arg)
293{
294#ifdef SO_RCVTIMEO_WORKS
295        double sess_timeout = 0;
296#endif
297#ifdef SO_SNDTIMEO_WORKS
298        double send_timeout = 0;
299#endif
300        struct listen_sock *ls;
301        double t0, now;
302
303        THR_SetName("cache-acceptor");
304        (void)arg;
305
306        VTAILQ_FOREACH(ls, &heritage.socks, list) {
307                if (ls->sock < 0)
308                        continue;
309                AZ(listen(ls->sock, params->listen_depth));
310                AZ(setsockopt(ls->sock, SOL_SOCKET, SO_LINGER,
311                    &linger, sizeof linger));
312        }
313
314        hack_ready = 1;
315
316        need_test = 1;
317        t0 = VTIM_real();
318        while (1) {
319                (void)sleep(1);
320#ifdef SO_SNDTIMEO_WORKS
321                if (params->send_timeout != send_timeout) {
322                        need_test = 1;
323                        send_timeout = params->send_timeout;
324                        tv_sndtimeo = VTIM_timeval(send_timeout);
325                        VTAILQ_FOREACH(ls, &heritage.socks, list) {
326                                if (ls->sock < 0)
327                                        continue;
328                                AZ(setsockopt(ls->sock, SOL_SOCKET,
329                                    SO_SNDTIMEO,
330                                    &tv_sndtimeo, sizeof tv_sndtimeo));
331                        }
332                }
333#endif
334#ifdef SO_RCVTIMEO_WORKS
335                if (params->sess_timeout != sess_timeout) {
336                        need_test = 1;
337                        sess_timeout = params->sess_timeout;
338                        tv_rcvtimeo = VTIM_timeval(sess_timeout);
339                        VTAILQ_FOREACH(ls, &heritage.socks, list) {
340                                if (ls->sock < 0)
341                                        continue;
342                                AZ(setsockopt(ls->sock, SOL_SOCKET,
343                                    SO_RCVTIMEO,
344                                    &tv_rcvtimeo, sizeof tv_rcvtimeo));
345                        }
346                }
347#endif
348                now = VTIM_real();
349                VSC_C_main->uptime = (uint64_t)(now - t0);
350        }
351        NEEDLESS_RETURN(NULL);
352}
353
354
355/*--------------------------------------------------------------------*/
356
357static void
358ccf_start(struct cli *cli, const char * const *av, void *priv)
359{
360
361        (void)cli;
362        (void)av;
363        (void)priv;
364
365        AZ(pthread_create(&VCA_thread, NULL, vca_acct, NULL));
366}
367
368/*--------------------------------------------------------------------*/
369
370static void
371ccf_listen_address(struct cli *cli, const char * const *av, void *priv)
372{
373        struct listen_sock *ls;
374        char h[32], p[32];
375
376        (void)cli;
377        (void)av;
378        (void)priv;
379        VTAILQ_FOREACH(ls, &heritage.socks, list) {
380                if (ls->sock < 0)
381                        continue;
382                VTCP_myname(ls->sock, h, sizeof h, p, sizeof p);
383                VCLI_Out(cli, "%s %s\n", h, p);
384        }
385}
386
387/*--------------------------------------------------------------------*/
388
389static struct cli_proto vca_cmds[] = {
390        { CLI_SERVER_START,     "i", ccf_start },
391        { "debug.listen_address",
392            "debug.listen_address",
393            "Report the actual listen address\n", 0, 0,
394            "d", ccf_listen_address, NULL },
395        { NULL }
396};
397
398void
399VCA_Init(void)
400{
401
402        CLI_AddFuncs(vca_cmds);
403        Lck_New(&pace_mtx, lck_vcapace);
404}
405
406void
407VCA_Shutdown(void)
408{
409        struct listen_sock *ls;
410        int i;
411
412        VTAILQ_FOREACH(ls, &heritage.socks, list) {
413                if (ls->sock < 0)
414                        continue;
415                i = ls->sock;
416                ls->sock = -1;
417                (void)close(i);
418        }
419}
Note: See TracBrowser for help on using the repository browser.