source: bin/varnishd/cache_acceptor.c @ 10c90c

Revision 10c90c, 9.6 KB checked in by Poul-Henning Kamp <phk@…>, 4 years ago (diff)

Take another trip over the CLI code, this time the help function.

git-svn-id:  http://www.varnish-cache.org/svn/trunk/varnish-cache@4477 d4fa192b-c00b-0410-8231-f00ffab90ce4

  • Property mode set to 100644
Line 
1/*-
2 * Copyright (c) 2006 Verdens Gang AS
3 * Copyright (c) 2006-2009 Linpro 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 "svnid.h"
34SVNID("$Id$")
35
36#include <stdio.h>
37#include <errno.h>
38#include <poll.h>
39#include <string.h>
40#include <stdlib.h>
41#include <unistd.h>
42
43#include <sys/uio.h>
44#include <sys/types.h>
45#include <sys/socket.h>
46
47#include "cli.h"
48#include "cli_priv.h"
49#include "shmlog.h"
50#include "cache.h"
51#include "cache_waiter.h"
52
53static struct waiter * const vca_waiters[] = {
54#if defined(HAVE_KQUEUE)
55        &waiter_kqueue,
56#endif
57#if defined(HAVE_EPOLL_CTL)
58        &waiter_epoll,
59#endif
60#if defined(HAVE_PORT_CREATE)
61        &waiter_ports,
62#endif
63        &waiter_poll,
64        NULL,
65};
66
67static struct waiter const *vca_act;
68
69pthread_t               VCA_thread;
70static struct timeval   tv_sndtimeo;
71static struct timeval   tv_rcvtimeo;
72
73/*
74 * We want to get out of any kind of touble-hit TCP connections as fast
75 * as absolutely possible, so we set them LINGER enabled with zero timeout,
76 * so that even if there are outstanding write data on the socket, a close(2)
77 * will return immediately.
78 */
79static const struct linger linger = {
80        .l_onoff        =       1,
81};
82
83static unsigned char    need_sndtimeo, need_rcvtimeo, need_linger, need_test;
84
85int vca_pipes[2];
86
87static void
88sock_test(int fd)
89{
90        struct linger lin;
91        struct timeval tv;
92        socklen_t l;
93
94        l = sizeof lin;
95        AZ(getsockopt(fd, SOL_SOCKET, SO_LINGER, &lin, &l));
96        assert(l == sizeof lin);
97        if (memcmp(&lin, &linger, l))
98                need_linger = 1;
99
100#ifdef SO_SNDTIMEO_WORKS
101        l = sizeof tv;
102        AZ(getsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, &l));
103        assert(l == sizeof tv);
104        if (memcmp(&tv, &tv_sndtimeo, l))
105                need_sndtimeo = 1;
106#endif
107
108#ifdef SO_RCVTIMEO_WORKS
109        l = sizeof tv;
110        AZ(getsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, &l));
111        assert(l == sizeof tv);
112        if (memcmp(&tv, &tv_rcvtimeo, l))
113                need_rcvtimeo = 1;
114#endif
115
116        need_test = 0;
117}
118
119/*--------------------------------------------------------------------
120 * Called once the workerthread gets hold of the session, to do setup
121 * setup overhead, we don't want to bother the acceptor thread with.
122 */
123
124void
125VCA_Prep(struct sess *sp)
126{
127        char addr[TCP_ADDRBUFSIZE];
128        char port[TCP_PORTBUFSIZE];
129
130        TCP_name(sp->sockaddr, sp->sockaddrlen,
131            addr, sizeof addr, port, sizeof port);
132        sp->addr = WS_Dup(sp->ws, addr);
133        sp->port = WS_Dup(sp->ws, port);
134        if (params->log_local_addr) {
135                AZ(getsockname(sp->fd, sp->mysockaddr, &sp->mysockaddrlen));
136                TCP_name(sp->mysockaddr, sp->mysockaddrlen,
137                    addr, sizeof addr, port, sizeof port);
138                VSL(SLT_SessionOpen, sp->fd, "%s %s %s %s",
139                    sp->addr, sp->port, addr, port);
140        } else {
141                VSL(SLT_SessionOpen, sp->fd, "%s %s %s",
142                    sp->addr, sp->port, sp->mylsock->name);
143        }
144        sp->acct.first = sp->t_open;
145        if (need_test)
146                sock_test(sp->fd);
147        if (need_linger)
148                AZ(setsockopt(sp->fd, SOL_SOCKET, SO_LINGER,
149                    &linger, sizeof linger));
150#ifdef SO_SNDTIMEO_WORKS
151        if (need_sndtimeo)
152                AZ(setsockopt(sp->fd, SOL_SOCKET, SO_SNDTIMEO,
153                    &tv_sndtimeo, sizeof tv_sndtimeo));
154#endif
155#ifdef SO_RCVTIMEO_WORKS
156        if (need_rcvtimeo)
157                AZ(setsockopt(sp->fd, SOL_SOCKET, SO_RCVTIMEO,
158                    &tv_rcvtimeo, sizeof tv_rcvtimeo));
159#endif
160}
161
162/*--------------------------------------------------------------------*/
163
164static void *
165vca_acct(void *arg)
166{
167        struct sess *sp;
168        socklen_t l;
169        struct sockaddr_storage addr_s;
170        struct sockaddr *addr;
171        int i;
172        struct pollfd *pfd;
173        struct listen_sock *ls;
174        unsigned u;
175        double now;
176
177        THR_SetName("cache-acceptor");
178        (void)arg;
179
180        /* Set up the poll argument */
181        pfd = calloc(sizeof *pfd, heritage.nsocks);
182        AN(pfd);
183        i = 0;
184        VTAILQ_FOREACH(ls, &heritage.socks, list) {
185                if (ls->sock < 0)
186                        continue;
187                AZ(listen(ls->sock, params->listen_depth));
188                AZ(setsockopt(ls->sock, SOL_SOCKET, SO_LINGER,
189                    &linger, sizeof linger));
190                pfd[i].events = POLLIN;
191                pfd[i++].fd = ls->sock;
192        }
193
194        need_test = 1;
195        while (1) {
196#ifdef SO_SNDTIMEO_WORKS
197                if (params->send_timeout != tv_sndtimeo.tv_sec) {
198                        need_test = 1;
199                        tv_sndtimeo.tv_sec = params->send_timeout;
200                        VTAILQ_FOREACH(ls, &heritage.socks, list) {
201                                if (ls->sock < 0)
202                                        continue;
203                                AZ(setsockopt(ls->sock, SOL_SOCKET,
204                                    SO_SNDTIMEO,
205                                    &tv_sndtimeo, sizeof tv_sndtimeo));
206                        }
207                }
208#endif
209#ifdef SO_RCVTIMEO_WORKS
210                if (params->sess_timeout != tv_rcvtimeo.tv_sec) {
211                        need_test = 1;
212                        tv_rcvtimeo.tv_sec = params->sess_timeout;
213                        VTAILQ_FOREACH(ls, &heritage.socks, list) {
214                                if (ls->sock < 0)
215                                        continue;
216                                AZ(setsockopt(ls->sock, SOL_SOCKET,
217                                    SO_RCVTIMEO,
218                                    &tv_rcvtimeo, sizeof tv_rcvtimeo));
219                        }
220                }
221#endif
222                i = poll(pfd, heritage.nsocks, 1000);
223                now = TIM_real();
224                u = 0;
225                VTAILQ_FOREACH(ls, &heritage.socks, list) {
226                        if (ls->sock < 0)
227                                continue;
228                        if (pfd[u++].revents == 0)
229                                continue;
230                        VSL_stats->client_conn++;
231                        l = sizeof addr_s;
232                        addr = (void*)&addr_s;
233                        i = accept(ls->sock, addr, &l);
234                        if (i < 0) {
235                                switch (errno) {
236                                case EAGAIN:
237                                case ECONNABORTED:
238                                        break;
239                                case EMFILE:
240                                        VSL(SLT_Debug, ls->sock,
241                                            "Too many open files "
242                                            "when accept(2)ing. Sleeping.");
243                                        TIM_sleep(
244                                            params->accept_fd_holdoff * 0.001);
245                                        break;
246                                default:
247                                        VSL(SLT_Debug, ls->sock,
248                                            "Accept failed: %s",
249                                            strerror(errno));
250                                        /* XXX: stats ? */
251                                        break;
252                                }
253                                continue;
254                        }
255                        sp = SES_New(addr, l);
256                        if (sp == NULL) {
257                                AZ(close(i));
258                                VSL_stats->client_drop++;
259                                continue;
260                        }
261                        sp->fd = i;
262                        sp->id = i;
263                        sp->t_open = now;
264                        sp->t_end = now;
265                        sp->mylsock = ls;
266
267                        sp->step = STP_FIRST;
268                        WRK_QueueSession(sp);
269                }
270        }
271        NEEDLESS_RETURN(NULL);
272}
273
274/*--------------------------------------------------------------------*/
275
276void
277vca_handover(struct sess *sp, int status)
278{
279
280        switch (status) {
281        case -2:
282                vca_close_session(sp, "blast");
283                SES_Delete(sp);
284                break;
285        case -1:
286                vca_close_session(sp, "no request");
287                SES_Delete(sp);
288                break;
289        case 1:
290                sp->step = STP_START;
291                WRK_QueueSession(sp);
292                break;
293        default:
294                INCOMPL();
295        }
296}
297
298/*--------------------------------------------------------------------*/
299
300void
301vca_close_session(struct sess *sp, const char *why)
302{
303        int i;
304
305        VSL(SLT_SessionClose, sp->id, "%s", why);
306        if (sp->fd >= 0) {
307                i = close(sp->fd);
308                assert(i == 0 || errno != EBADF);       /* XXX EINVAL seen */
309        }
310        sp->fd = -1;
311}
312
313void
314vca_return_session(struct sess *sp)
315{
316
317        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
318        AZ(sp->obj);
319        AZ(sp->vcl);
320        assert(sp->fd >= 0);
321        /*
322         * Set nonblocking in the worker-thread, before passing to the
323         * acceptor thread, to reduce syscall density of the latter.
324         */
325        TCP_nonblocking(sp->fd);
326        if (vca_act->pass == NULL)
327                assert(sizeof sp == write(vca_pipes[1], &sp, sizeof sp));
328        else
329                vca_act->pass(sp);
330}
331
332
333/*--------------------------------------------------------------------*/
334
335static void
336ccf_start(struct cli *cli, const char * const *av, void *priv)
337{
338
339        (void)cli;
340        (void)av;
341        (void)priv;
342
343        if (vca_act == NULL)
344                vca_act = vca_waiters[0];
345
346        AN(vca_act);
347        AN(vca_act->name);
348
349        if (vca_act->pass == NULL)
350                AZ(pipe(vca_pipes));
351        vca_act->init();
352        AZ(pthread_create(&VCA_thread, NULL, vca_acct, NULL));
353        VSL(SLT_Debug, 0, "Acceptor is %s", vca_act->name);
354}
355
356/*--------------------------------------------------------------------*/
357
358static void
359ccf_listen_address(struct cli *cli, const char * const *av, void *priv)
360{
361        struct listen_sock *ls;
362        char h[32], p[32];
363
364        (void)cli;
365        (void)av;
366        (void)priv;
367        VTAILQ_FOREACH(ls, &heritage.socks, list) {
368                if (ls->sock < 0)
369                        continue;
370                TCP_myname(ls->sock, h, sizeof h, p, sizeof p);
371                cli_out(cli, "%s %s\n", h, p);
372        }
373}
374
375/*--------------------------------------------------------------------*/
376
377static struct cli_proto vca_cmds[] = {
378        { CLI_SERVER_START,     "i", ccf_start },
379        { "debug.listen_address",
380            "debug.listen_address",
381            "Report the actual listen address\n", 0, 0,
382            "d", ccf_listen_address, NULL },
383        { NULL }
384};
385
386void
387VCA_Init(void)
388{
389
390        CLI_AddFuncs(vca_cmds);
391}
392
393void
394VCA_tweak_waiter(struct cli *cli, const char *arg)
395{
396        int i;
397
398        if (arg == NULL) {
399                if (vca_act == NULL)
400                        cli_out(cli, "default");
401                else
402                        cli_out(cli, "%s", vca_act->name);
403
404                cli_out(cli, " (");
405                for (i = 0; vca_waiters[i] != NULL; i++)
406                        cli_out(cli, "%s%s", i == 0 ? "" : ", ",
407                            vca_waiters[i]->name);
408                cli_out(cli, ")");
409                return;
410        }
411        if (!strcmp(arg, "default")) {
412                vca_act = NULL;
413                return;
414        }
415        for (i = 0; vca_waiters[i]; i++) {
416                if (!strcmp(arg, vca_waiters[i]->name)) {
417                        vca_act = vca_waiters[i];
418                        return;
419                }
420        }
421        cli_out(cli, "Unknown waiter");
422        cli_result(cli, CLIS_PARAM);
423}
Note: See TracBrowser for help on using the repository browser.