source: bin/varnishd/mgt_param.c @ b7a50b

Revision b7a50b, 26.3 KB checked in by Dag Erling Smørgrav <des@…>, 5 years ago (diff)

Update Linpro copyright (about 3 months late). Someone should
probably s/Linpro/Redpill Linpro/ at some point.

git-svn-id:  http://www.varnish-cache.org/svn/trunk@4025 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 * $Id$
30 */
31
32#include "config.h"
33
34#include <sys/types.h>
35#include <sys/stat.h>
36
37#include <grp.h>
38#include <limits.h>
39#include <pwd.h>
40#include <regex.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <unistd.h>
45
46#include "cli.h"
47#include "cli_priv.h"
48#include "cli_common.h"
49#include "mgt.h"
50#include "mgt_cli.h"
51
52#include "heritage.h"
53#include "vparam.h"
54
55#include "vss.h"
56
57#define MAGIC_INIT_STRING       "\001"
58struct params master;
59static int nparspec;
60static struct parspec const ** parspec;
61static int margin;
62
63/*--------------------------------------------------------------------*/
64
65static const struct parspec *
66mcf_findpar(const char *name)
67{
68        int i;
69
70        for (i = 0; i < nparspec; i++)
71                if (!strcmp(parspec[i]->name, name)) 
72                        return (parspec[i]);
73        return (NULL);
74}
75
76/*--------------------------------------------------------------------*/
77
78static void
79tweak_generic_timeout(struct cli *cli, volatile unsigned *dst, const char *arg)
80{
81        unsigned u;
82
83        if (arg != NULL) {
84                u = strtoul(arg, NULL, 0);
85                if (u == 0) {
86                        cli_out(cli, "Timeout must be greater than zero\n");
87                        cli_result(cli, CLIS_PARAM);
88                        return;
89                }
90                *dst = u;
91        } else
92                cli_out(cli, "%u", *dst);
93}
94
95static void
96tweak_generic_timeout_double(struct cli *cli, volatile double *dst, const char *arg)
97{
98        double u;
99
100        if (arg != NULL) {
101                u = strtod(arg, NULL);
102                if (u < 0) {
103                        cli_out(cli,
104                            "Timeout must be greater or equal to zero\n");
105                        cli_result(cli, CLIS_PARAM);
106                        return;
107                }
108                *dst = u;
109        } else
110                cli_out(cli, "%f", *dst);
111}
112
113
114/*--------------------------------------------------------------------*/
115
116void
117tweak_timeout(struct cli *cli, const struct parspec *par, const char *arg)
118{
119        volatile unsigned *dest;
120
121        dest = par->priv;
122        tweak_generic_timeout(cli, dest, arg);
123}
124
125static void
126tweak_timeout_double(struct cli *cli, const struct parspec *par, const char *arg)
127{
128        volatile double *dest;
129
130        dest = par->priv;
131        tweak_generic_timeout_double(cli, dest, arg);
132}
133/*--------------------------------------------------------------------*/
134
135static void
136tweak_generic_bool(struct cli *cli, volatile unsigned *dest, const char *arg)
137{
138        if (arg != NULL) {
139                if (!strcasecmp(arg, "off"))
140                        *dest = 0;
141                else if (!strcasecmp(arg, "disable"))
142                        *dest = 0;
143                else if (!strcasecmp(arg, "no"))
144                        *dest = 0;
145                else if (!strcasecmp(arg, "false"))
146                        *dest = 0;
147                else if (!strcasecmp(arg, "on"))
148                        *dest = 1;
149                else if (!strcasecmp(arg, "enable"))
150                        *dest = 1;
151                else if (!strcasecmp(arg, "yes"))
152                        *dest = 1;
153                else if (!strcasecmp(arg, "true"))
154                        *dest = 1;
155                else {
156                        cli_out(cli, "use \"on\" or \"off\"\n");
157                        cli_result(cli, CLIS_PARAM);
158                        return;
159                }
160        } else
161                cli_out(cli, *dest ? "on" : "off");
162}
163
164/*--------------------------------------------------------------------*/
165
166static void
167tweak_bool(struct cli *cli, const struct parspec *par, const char *arg)
168{
169        volatile unsigned *dest;
170
171        dest = par->priv;
172        tweak_generic_bool(cli, dest, arg);
173}
174
175/*--------------------------------------------------------------------*/
176
177void
178tweak_generic_uint(struct cli *cli, volatile unsigned *dest, const char *arg,
179    unsigned min, unsigned max)
180{
181        unsigned u;
182
183        if (arg != NULL) {
184                if (!strcasecmp(arg, "unlimited"))
185                        u = UINT_MAX;
186                else
187                        u = strtoul(arg, NULL, 0);
188                if (u < min) {
189                        cli_out(cli, "Must be at least %u\n", min);
190                        cli_result(cli, CLIS_PARAM);
191                        return;
192                }
193                if (u > max) {
194                        cli_out(cli, "Must be no more than %u\n", max);
195                        cli_result(cli, CLIS_PARAM);
196                        return;
197                }
198                *dest = u;
199        } else if (*dest == UINT_MAX) {
200                cli_out(cli, "unlimited", *dest);
201        } else {
202                cli_out(cli, "%u", *dest);
203        }
204}
205
206/*--------------------------------------------------------------------*/
207
208void
209tweak_uint(struct cli *cli, const struct parspec *par, const char *arg)
210{
211        volatile unsigned *dest;
212
213        dest = par->priv;
214        tweak_generic_uint(cli, dest, arg, par->umin, par->umax);
215}
216
217/*--------------------------------------------------------------------
218 * XXX: slightly magic.  We want to initialize to "nobody" (XXX: shouldn't
219 * XXX: that be something autocrap found for us ?) but we don't want to
220 * XXX: fail initialization if that user doesn't exists, even though we
221 * XXX: do want to fail it, in subsequent sets.
222 * XXX: The magic init string is a hack for this.
223 */
224
225static void
226tweak_user(struct cli *cli, const struct parspec *par, const char *arg)
227{
228        struct passwd *pw;
229        struct group *gr;
230
231        (void)par;
232        if (arg != NULL) {
233                if (!strcmp(arg, MAGIC_INIT_STRING)) {
234                        pw = getpwnam("nobody");
235                        if (pw == NULL) {
236                                master.uid = getuid();
237                                return;
238                        }
239                } else
240                        pw = getpwnam(arg);
241                if (pw == NULL) {
242                        cli_out(cli, "Unknown user");
243                        cli_result(cli, CLIS_PARAM);
244                        return;
245                }
246                REPLACE(master.user, pw->pw_name);
247                master.uid = pw->pw_uid;
248                master.gid = pw->pw_gid;
249
250                /* set group to user's primary group */
251                if ((gr = getgrgid(pw->pw_gid)) != NULL &&
252                    (gr = getgrnam(gr->gr_name)) != NULL &&
253                    gr->gr_gid == pw->pw_gid)
254                        REPLACE(master.group, gr->gr_name);
255        } else if (master.user) {
256                cli_out(cli, "%s (%d)", master.user, (int)master.uid);
257        } else {
258                cli_out(cli, "%d", (int)master.uid);
259        }
260}
261
262/*--------------------------------------------------------------------
263 * XXX: see comment for tweak_user, same thing here.
264 */
265
266static void
267tweak_group(struct cli *cli, const struct parspec *par, const char *arg)
268{
269        struct group *gr;
270
271        (void)par;
272        if (arg != NULL) {
273                if (!strcmp(arg, MAGIC_INIT_STRING)) {
274                        gr = getgrnam("nogroup");
275                        if (gr == NULL) {
276                                /* Only replace if tweak_user didn't */
277                                if (master.gid == 0)
278                                        master.gid = getgid();
279                                return;
280                        }
281                } else
282                        gr = getgrnam(arg);
283                if (gr == NULL) {
284                        cli_out(cli, "Unknown group");
285                        cli_result(cli, CLIS_PARAM);
286                        return;
287                }
288                REPLACE(master.group, gr->gr_name);
289                master.gid = gr->gr_gid;
290        } else if (master.group) {
291                cli_out(cli, "%s (%d)", master.group, (int)master.gid);
292        } else {
293                cli_out(cli, "%d", (int)master.gid);
294        }
295}
296
297/*--------------------------------------------------------------------*/
298
299static void
300clean_listen_sock_head(struct listen_sock_head *lsh)
301{
302        struct listen_sock *ls, *ls2;
303
304        VTAILQ_FOREACH_SAFE(ls, lsh, list, ls2) {
305                VTAILQ_REMOVE(lsh, ls, list);
306                free(ls->name);
307                free(ls->addr);
308                free(ls);
309        }
310}
311
312static void
313tweak_listen_address(struct cli *cli, const struct parspec *par,
314    const char *arg)
315{
316        char **av;
317        int i;
318        struct listen_sock              *ls;
319        struct listen_sock_head         lsh;
320
321        (void)par;
322        if (arg == NULL) {
323                cli_quote(cli, master.listen_address);
324                return;
325        }
326
327        av = ParseArgv(arg, ARGV_COMMA);
328        if (av == NULL) {
329                cli_out(cli, "Parse error: out of memory");
330                cli_result(cli, CLIS_PARAM);
331                return;
332        }
333        if (av[0] != NULL) {
334                cli_out(cli, "Parse error: %s", av[0]);
335                cli_result(cli, CLIS_PARAM);
336                FreeArgv(av);
337                return;
338        }
339        if (av[1] == NULL) {
340                cli_out(cli, "Empty listen address");
341                cli_result(cli, CLIS_PARAM);
342                FreeArgv(av);
343                return;
344        }
345        VTAILQ_INIT(&lsh);
346        for (i = 1; av[i] != NULL; i++) {
347                struct vss_addr **ta;
348                char *host, *port;
349                int j, n;
350
351                if (VSS_parse(av[i], &host, &port) != 0) {
352                        cli_out(cli, "Invalid listen address ");
353                        cli_quote(cli, av[i]);
354                        cli_result(cli, CLIS_PARAM);
355                        break;
356                }
357                n = VSS_resolve(host, port ? port : "http", &ta);
358                free(host);
359                free(port);
360                if (n == 0) {
361                        cli_out(cli, "Invalid listen address ");
362                        cli_quote(cli, av[i]);
363                        cli_result(cli, CLIS_PARAM);
364                        break;
365                }
366                for (j = 0; j < n; ++j) {
367                        ls = calloc(sizeof *ls, 1);
368                        AN(ls);
369                        ls->sock = -1;
370                        ls->addr = ta[j];
371                        ls->name = strdup(av[i]);
372                        AN(ls->name);
373                        VTAILQ_INSERT_TAIL(&lsh, ls, list);
374                }
375                free(ta);
376        }
377        FreeArgv(av);
378        if (cli != NULL && cli->result != CLIS_OK) {
379                clean_listen_sock_head(&lsh);
380                return;
381        }
382
383        REPLACE(master.listen_address, arg);
384
385        clean_listen_sock_head(&heritage.socks);
386        heritage.nsocks = 0;
387
388        while (!VTAILQ_EMPTY(&lsh)) {
389                ls = VTAILQ_FIRST(&lsh);
390                VTAILQ_REMOVE(&lsh, ls, list);
391                VTAILQ_INSERT_TAIL(&heritage.socks, ls, list);
392                heritage.nsocks++;
393        }
394}
395
396/*--------------------------------------------------------------------*/
397
398static void
399tweak_cc_command(struct cli *cli, const struct parspec *par, const char *arg)
400{
401
402        /* XXX should have tweak_generic_string */
403        (void)par;
404        if (arg == NULL) {
405                cli_quote(cli, mgt_cc_cmd);
406        } else {
407                free(mgt_cc_cmd);
408                mgt_cc_cmd = strdup(arg);
409                XXXAN(mgt_cc_cmd);
410        }
411}
412
413/*--------------------------------------------------------------------*/
414
415static void
416tweak_waiter(struct cli *cli, const struct parspec *par, const char *arg)
417{
418
419        /* XXX should have tweak_generic_string */
420        (void)par;
421        VCA_tweak_waiter(cli, arg);
422}
423
424/*--------------------------------------------------------------------*/
425
426static void
427tweak_diag_bitmap(struct cli *cli, const struct parspec *par, const char *arg)
428{
429        unsigned u;
430
431        (void)par;
432        if (arg != NULL) {
433                u = strtoul(arg, NULL, 0);
434                master.diag_bitmap = u;
435        } else {
436                cli_out(cli, "0x%x", master.diag_bitmap);
437        }
438}
439
440/*--------------------------------------------------------------------*/
441
442/*
443 * Make sure to end all lines with either a space or newline of the
444 * formatting will go haywire.
445 */
446
447#define DELAYED_EFFECT_TEXT \
448        "\nNB: This parameter may take quite some time to take (full) effect."
449
450#define MUST_RESTART_TEXT \
451        "\nNB: This parameter will not take any effect until the " \
452        "child process has been restarted."
453
454#define MUST_RELOAD_TEXT \
455        "\nNB: This parameter will not take any effect until the " \
456        "VCL programs have been reloaded."
457
458#define EXPERIMENTAL_TEXT \
459        "\nNB: We do not know yet if it is a good idea to change " \
460        "this parameter, or if the default value is even sensible.  " \
461        "Caution is advised, and feedback is most welcome."
462
463/*
464 * Remember to update varnishd.1 whenever you add / remove a parameter or
465 * change its default value.
466 * XXX: we should generate the relevant section of varnishd.1 from here.
467 */
468static const struct parspec input_parspec[] = {
469        { "user", tweak_user, NULL, 0, 0,
470                "The unprivileged user to run as.  Setting this will "
471                "also set \"group\" to the specified user's primary group.",
472                MUST_RESTART,
473                MAGIC_INIT_STRING },
474        { "group", tweak_group, NULL, 0, 0,
475                "The unprivileged group to run as.",
476                MUST_RESTART,
477                MAGIC_INIT_STRING },
478        { "default_ttl", tweak_uint, &master.default_ttl, 0, UINT_MAX,
479                "The TTL assigned to objects if neither the backend nor "
480                "the VCL code assigns one.\n"
481                "Objects already cached will not be affected by changes "
482                "made until they are fetched from the backend again.\n"
483                "To force an immediate effect at the expense of a total "
484                "flush of the cache use \"url.purge .\"",
485                0,
486                "120", "seconds" },
487        { "sess_workspace", tweak_uint, &master.sess_workspace, 1024, UINT_MAX,
488                "Bytes of HTTP protocol workspace allocated for sessions. "
489                "This space must be big enough for the entire HTTP protocol "
490                "header and any edits done to it in the VCL code.\n"
491                "Minimum is 1024 bytes.",
492                DELAYED_EFFECT,
493                "16384", "bytes" },
494        { "obj_workspace", tweak_uint, &master.obj_workspace, 1024, UINT_MAX,
495                "Bytes of HTTP protocol workspace allocated for objects. "
496                "This space must be big enough for the entire HTTP protocol "
497                "header and any edits done to it in the VCL code while it "
498                "is cached.\n"
499                "Minimum is 1024 bytes.",
500                DELAYED_EFFECT,
501                "8192", "bytes" },
502        { "shm_workspace", tweak_uint, &master.shm_workspace, 4096, UINT_MAX,
503                "Bytes of shmlog workspace allocated for worker threads. "
504                "If too big, it wastes some ram, if too small it causes "
505                "needless flushes of the SHM workspace.\n"
506                "These flushes show up in stats as "
507                "\"SHM flushes due to overflow\".\n"
508                "Minimum is 4096 bytes.",
509                DELAYED_EFFECT,
510                "8192", "bytes" },
511        { "shm_reclen", tweak_uint, &master.shm_reclen, 16, 65535,
512                "Maximum number of bytes in SHM log record.\n"
513                "Maximum is 65535 bytes.",
514                0,
515                "255", "bytes" },
516        { "default_grace", tweak_uint, &master.default_grace, 0, UINT_MAX,
517                "Default grace period.  We will deliver an object "
518                "this long after it has expired, provided another thread "
519                "is attempting to get a new copy.",
520                DELAYED_EFFECT,
521                "10" "seconds" },
522        { "sess_timeout", tweak_timeout, &master.sess_timeout, 0, 0,
523                "Idle timeout for persistent sessions. "
524                "If a HTTP request has not been received in this many "
525                "seconds, the session is closed.",
526                0,
527                "5", "seconds" },
528        { "pipe_timeout", tweak_timeout, &master.pipe_timeout, 0, 0,
529                "Idle timeout for PIPE sessions. "
530                "If nothing have been received in either direction for "
531                "this many seconds, the session is closed.\n",
532                0,
533                "60", "seconds" },
534        { "send_timeout", tweak_timeout, &master.send_timeout, 0, 0,
535                "Send timeout for client connections. "
536                "If no data has been sent to the client in this many seconds, "
537                "the session is closed.\n"
538                "See setsockopt(2) under SO_SNDTIMEO for more information.",
539                DELAYED_EFFECT,
540                "600", "seconds" },
541        { "auto_restart", tweak_bool, &master.auto_restart, 0, 0,
542                "Restart child process automatically if it dies.\n",
543                0,
544                "on", "bool" },
545        { "fetch_chunksize",
546                tweak_uint, &master.fetch_chunksize, 4, UINT_MAX / 1024,
547                "The default chunksize used by fetcher. "
548                "This should be bigger than the majority of objects with "
549                "short TTLs.\n"
550                "Internal limits in the storage_file module makes increases "
551                "above 128kb a dubious idea.",
552                EXPERIMENTAL,
553                "128", "kilobytes" },
554#ifdef SENDFILE_WORKS
555        { "sendfile_threshold",
556                tweak_uint, &master.sendfile_threshold, 0, UINT_MAX,
557                "The minimum size of objects transmitted with sendfile.",
558                EXPERIMENTAL,
559                "-1", "bytes" },
560#endif /* SENDFILE_WORKS */
561        { "vcl_trace", tweak_bool,  &master.vcl_trace, 0, 0,
562                "Trace VCL execution in the shmlog.\n"
563                "Enabling this will allow you to see the path each "
564                "request has taken through the VCL program.\n"
565                "This generates a lot of logrecords so it is off by "
566                "default.",
567                0,
568                "off", "bool" },
569        { "listen_address", tweak_listen_address, NULL, 0, 0,
570                "Whitespace separated list of network endpoints where "
571                "Varnish will accept requests.\n"
572                "Possible formats: host, host:port, :port",
573                MUST_RESTART,
574                ":80" },
575        { "listen_depth", tweak_uint, &master.listen_depth, 0, UINT_MAX,
576                "Listen queue depth.",
577                MUST_RESTART,
578                "1024", "connections" },
579        { "backend_http11", tweak_bool, &master.backend_http11, 0, 0,
580                "Force all backend requests to be HTTP/1.1.\n"
581                "By default we copy the protocol version from the "
582                "incoming client request.",
583                EXPERIMENTAL,
584                "on", "bool" },
585        { "client_http11", tweak_bool, &master.client_http11, 0, 0,
586                "Force all client responses to be HTTP/1.1.\n"
587                "By default we copy the protocol version from the "
588                "backend response.",
589                EXPERIMENTAL,
590                "off", "bool" },
591        { "cli_timeout", tweak_timeout, &master.cli_timeout, 0, 0,
592                "Timeout for the childs replies to CLI requests from "
593                "the master.",
594                0,
595                "5", "seconds" },
596        { "ping_interval", tweak_uint, &master.ping_interval, 0, UINT_MAX,
597                "Interval between pings from parent to child.\n"
598                "Zero will disable pinging entirely, which makes "
599                "it possible to attach a debugger to the child.",
600                MUST_RESTART,
601                "3", "seconds" },
602        { "lru_interval", tweak_timeout, &master.lru_timeout, 0, 0,
603                "Grace period before object moves on LRU list.\n"
604                "Objects are only moved to the front of the LRU "
605                "list if they have not been moved there already inside "
606                "this timeout period.  This reduces the amount of lock "
607                "operations necessary for LRU list access.",
608                EXPERIMENTAL,
609                "2", "seconds" },
610        { "cc_command", tweak_cc_command, NULL, 0, 0,
611                "Command used for compiling the C source code to a "
612                "dlopen(3) loadable object.  Any occurrence of %s in "
613                "the string will be replaced with the source file name, "
614                "and %o will be replaced with the output file name.",
615                MUST_RELOAD,
616                VCC_CC
617                , NULL },
618        { "max_restarts", tweak_uint, &master.max_restarts, 0, UINT_MAX,
619                "Upper limit on how many times a request can restart."
620                "\nBe aware that restarts are likely to cause a hit against "
621                "the backend, so don't increase thoughtlessly.\n",
622                0,
623                "4", "restarts" },
624        { "esi_syntax",
625                tweak_uint, &master.esi_syntax, 0, UINT_MAX,
626                "Bitmap controlling ESI parsing code:\n"
627                "  0x00000001 - Don't check if it looks like XML\n"
628                "  0x00000002 - Ignore non-esi elements\n"
629                "  0x00000004 - Emit parsing debug records\n"
630                "Use 0x notation and do the bitor in your head :-)\n",
631                0,
632                "0", "bitmap" },
633        { "max_esi_includes",
634                tweak_uint, &master.max_esi_includes, 0, UINT_MAX,
635                "Maximum depth of esi:include processing.\n",
636                0,
637                "5", "includes" },
638        { "cache_vbe_conns", tweak_bool,  &master.cache_vbe_conns, 0, 0,
639                "Cache vbe_conn's or rely on malloc, that's the question.",
640                EXPERIMENTAL,
641                "off", "bool" },
642        { "connect_timeout", tweak_timeout_double,
643                &master.connect_timeout,0, UINT_MAX,
644                "Default connection timeout for backend connections. "
645                "We only try to connect to the backend for this many "
646                "seconds before giving up. "
647                "VCL can override this default value for each backend and "
648                "backend request.",
649                0,
650                "0.4", "s" },
651        { "first_byte_timeout", tweak_timeout_double,
652                &master.first_byte_timeout,0, UINT_MAX,
653                "Default timeout for receiving first byte from backend. "
654                "We only wait for this many seconds for the first "
655                "byte before giving up. A value of 0 means it will never time out. "
656                "VCL can override this default value for each backend and "
657                "backend request. This parameter does not apply to pipe.",
658                0,
659                "60", "s" },
660        { "between_bytes_timeout", tweak_timeout_double,
661                &master.between_bytes_timeout,0, UINT_MAX,
662                "Default timeout between bytes when receiving data from backend. "
663                "We only wait for this many seconds between bytes "
664                "before giving up. A value of 0 means it will never time out. "
665                "VCL can override this default value for each backend request and "
666                "backend request. This parameter does not apply to pipe.",
667                0,
668                "60", "s" },
669        { "accept_fd_holdoff", tweak_timeout,
670                &master.accept_fd_holdoff, 0,  3600*1000,
671                "If we run out of file descriptors, the accept thread will "
672                "sleep.  This parameter control for how long it will sleep.",
673                EXPERIMENTAL,
674                "50", "ms" },
675        { "clock_skew", tweak_uint, &master.clock_skew, 0, UINT_MAX,
676                "How much clockskew we are willing to accept between the "
677                "backend and our own clock.",
678                0,
679                "10", "s" },
680        { "prefer_ipv6", tweak_bool, &master.prefer_ipv6, 0, 0,
681                "Prefer IPv6 address when connecting to backends which "
682                "have both IPv4 and IPv6 addresses.",
683                0,
684                "off", "bool" },
685        { "session_linger", tweak_uint,
686                &master.session_linger,0, UINT_MAX,
687                "How long time the workerthread lingers on the session "
688                "to see if a new request appears right away.\n"
689                "If sessions are reused, as much as half of all reuses "
690                "happen within the first 100 msec of the previous request "
691                "completing.\n"
692                "Setting this too high results in worker threads not doing "
693                "anything for their keep, setting it too low just means that "
694                "more sessions take a detour around the waiter.",
695                EXPERIMENTAL,
696                "0", "ms" },
697        { "cli_buffer", tweak_uint, &master.cli_buffer, 4096, UINT_MAX,
698                "Size of buffer for CLI input."
699                "\nYou may need to increase this if you have big VCL files "
700                "and use the vcl.inline CLI command.\n"
701                "NB: Must be specified with -p to have effect.\n",
702                0,
703                "8192", "bytes" },
704        { "log_hashstring", tweak_bool, &master.log_hash, 0, 0,
705                "Log the hash string to shared memory log.\n",
706                0,
707                "off", "bool" },
708        { "purge_hash", tweak_bool, &master.save_hash, 0, 0,
709                "Enable purge.hash command.\n"
710                "NB: this increases storage requirement per object "
711                "by the length of the hash string.\n",
712                MUST_RESTART,
713                "off", "bool" },
714        { "log_local_address", tweak_bool, &master.log_local_addr, 0, 0,
715                "Log the local address on the TCP connection in the "
716                "SessionOpen shared memory record.\n",
717                0,
718                "off", "bool" },
719        { "waiter", tweak_waiter, NULL, 0, 0,
720                "Select the waiter kernel interface.\n",
721                EXPERIMENTAL | MUST_RESTART,
722                "default", NULL },
723        { "diag_bitmap", tweak_diag_bitmap, 0, 0, 0,
724                "Bitmap controlling diagnostics code:\n"
725                "  0x00000001 - CNT_Session states.\n"
726                "  0x00000002 - workspace debugging.\n"
727                "  0x00000004 - kqueue debugging.\n"
728                "  0x00000008 - mutex logging.\n"
729                "  0x00000010 - mutex contests.\n"
730                "  0x00000020 - waiting list.\n"
731                "  0x00000040 - object workspace.\n"
732                "  0x00001000 - do not core-dump child process.\n"
733                "  0x00002000 - only short panic message.\n"
734                "  0x00004000 - panic to stderr.\n"
735#ifdef HAVE_ABORT2
736                "  0x00008000 - panic to abort2().\n"
737#endif
738                "  0x00010000 - synchronize shmlog.\n"
739                "  0x00020000 - synchronous start of persistence.\n"
740                "  0x80000000 - do edge-detection on digest.\n"
741                "Use 0x notation and do the bitor in your head :-)\n",
742                0,
743                "0", "bitmap" },
744        { "err_ttl", tweak_uint, &master.err_ttl, 0, UINT_MAX,
745                "The TTL assigned to the synthesized error pages\n",
746                0,
747                "0", "seconds" },
748        { "purge_dups", tweak_bool, &master.purge_dups, 0, 0,
749                "Detect and eliminate duplicate purges.\n",
750                0,
751                "off", "bool" },
752        { "cli_banner", tweak_bool, &master.cli_banner, 0, 0,
753                "Emit CLI banner on connect.\n"
754                "Set to off for compatibility with pre 2.1 versions.\n",
755                0,
756                "on", "bool" },
757        { NULL, NULL, NULL }
758};
759
760/*--------------------------------------------------------------------*/
761
762#define WIDTH 76
763
764static void
765mcf_wrap(struct cli *cli, const char *text)
766{
767        const char *p, *q;
768
769        /* Format text to COLUMNS width */
770        for (p = text; *p != '\0'; ) {
771                q = strchr(p, '\n');
772                if (q == NULL)
773                        q = strchr(p, '\0');
774                if (q > p + WIDTH - margin) {
775                        q = p + WIDTH - margin;
776                        while (q > p && *q != ' ')
777                                q--;
778                        AN(q);
779                }
780                cli_out(cli, "%*s %.*s\n", margin, "", (int)(q - p), p);
781                p = q;
782                if (*p == ' ' || *p == '\n')
783                        p++;
784        }
785}
786
787void
788mcf_param_show(struct cli *cli, const char * const *av, void *priv)
789{
790        int i;
791        const struct parspec *pp;
792        int lfmt;
793
794        (void)priv;
795        if (av[2] == NULL || strcmp(av[2], "-l"))
796                lfmt = 0;
797        else
798                lfmt = 1;
799        for (i = 0; i < nparspec; i++) {
800                pp = parspec[i];
801                if (av[2] != NULL && !lfmt && strcmp(pp->name, av[2]))
802                        continue;
803                cli_out(cli, "%-*s ", margin, pp->name);
804                if (pp->func == NULL) {
805                        cli_out(cli, "Not implemented.\n");
806                        if (av[2] != NULL && !lfmt)
807                                return;
808                        else
809                                continue;
810                }
811                pp->func(cli, pp, NULL);
812                if (pp->units != NULL)
813                        cli_out(cli, " [%s]\n", pp->units);
814                else
815                        cli_out(cli, "\n");
816                if (av[2] != NULL) {
817                        cli_out(cli, "%-*s Default is %s\n",
818                            margin, "", pp->def);
819                        mcf_wrap(cli, pp->descr);
820                        if (pp->flags & DELAYED_EFFECT)
821                                mcf_wrap(cli, DELAYED_EFFECT_TEXT);
822                        if (pp->flags & EXPERIMENTAL)
823                                mcf_wrap(cli, EXPERIMENTAL_TEXT);
824                        if (pp->flags & MUST_RELOAD)
825                                mcf_wrap(cli, MUST_RELOAD_TEXT);
826                        if (pp->flags & MUST_RESTART)
827                                mcf_wrap(cli, MUST_RESTART_TEXT);
828                        if (!lfmt)
829                                return;
830                        else
831                                cli_out(cli, "\n");
832                }
833        }
834        if (av[2] != NULL && !lfmt) {
835                cli_result(cli, CLIS_PARAM);
836                cli_out(cli, "Unknown parameter \"%s\".", av[2]);
837        }
838}
839
840/*--------------------------------------------------------------------*/
841
842void
843MCF_ParamSync(void)
844{
845        if (params != &master)
846                *params = master;
847}
848
849/*--------------------------------------------------------------------*/
850
851void
852MCF_ParamSet(struct cli *cli, const char *param, const char *val)
853{
854        const struct parspec *pp;
855
856        pp = mcf_findpar(param);
857        if (pp != NULL) {
858                pp->func(cli, pp, val);
859                if (cli->result != CLIS_OK) {
860                } else if (child_pid >= 0 && pp->flags & MUST_RESTART) {
861                        cli_out(cli, "Change will take effect"
862                            " when child is restarted");
863                } else if (pp->flags & MUST_RELOAD) {
864                        cli_out(cli, "Change will take effect"
865                            " when VCL script is reloaded");
866                }
867                MCF_ParamSync();
868                return;
869        }
870        cli_result(cli, CLIS_PARAM);
871        cli_out(cli, "Unknown parameter \"%s\".", param);
872}
873
874
875/*--------------------------------------------------------------------*/
876
877void
878mcf_param_set(struct cli *cli, const char * const *av, void *priv)
879{
880
881        (void)priv;
882        MCF_ParamSet(cli, av[2], av[3]);
883}
884
885/*--------------------------------------------------------------------
886 * Add a group of parameters to the global set and sort by name.
887 */
888
889static int
890parspec_cmp(const void *a, const void *b)
891{
892        struct parspec * const * pa = a;
893        struct parspec * const * pb = b;
894        return (strcmp((*pa)->name, (*pb)->name));
895}
896
897static void
898MCF_AddParams(const struct parspec *ps)
899{
900        const struct parspec *pp;
901        int n;
902
903        n = 0;
904        for (pp = ps; pp->name != NULL; pp++) {
905                if (mcf_findpar(pp->name) != NULL)
906                        fprintf(stderr, "Duplicate param: %s\n", pp->name);
907                if (strlen(pp->name) + 1 > margin)
908                        margin = strlen(pp->name) + 1;
909                n++;
910        }
911        parspec = realloc(parspec, (nparspec + n + 1) * sizeof *parspec);
912        XXXAN(parspec);
913        for (pp = ps; pp->name != NULL; pp++)
914                parspec[nparspec++] = pp;
915        parspec[nparspec] = NULL;
916        qsort (parspec, nparspec, sizeof parspec[0], parspec_cmp);
917}
918
919/*--------------------------------------------------------------------
920 * Set defaults for all parameters
921 */
922
923static void
924MCF_SetDefaults(struct cli *cli)
925{
926        const struct parspec *pp;
927        int i;
928
929        for (i = 0; i < nparspec; i++) {
930                pp = parspec[i];
931                if (cli != NULL)
932                        cli_out(cli,
933                            "Set Default for %s = %s\n", pp->name, pp->def);
934                pp->func(cli, pp, pp->def);
935                if (cli != NULL && cli->result != CLIS_OK)
936                        return;
937        }
938}
939
940/*--------------------------------------------------------------------*/
941
942void
943MCF_ParamInit(struct cli *cli)
944{
945
946        MCF_AddParams(input_parspec);
947        MCF_AddParams(WRK_parspec);
948
949        /* XXX: We do this twice, to get past any interdependencies */
950        MCF_SetDefaults(NULL);
951        MCF_SetDefaults(cli);
952
953        params = &master;
954}
Note: See TracBrowser for help on using the repository browser.