blob: 1730c3e222a36615a5b94a291b2d60397da9dc5c [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
Willy Tarreaua5357cd2021-05-09 06:14:25 +02002 * HAProxy : High Availability-enabled HTTP/TCP proxy
Willy Tarreau421ed392021-01-06 17:41:32 +01003 * Copyright 2000-2021 Willy Tarreau <willy@haproxy.org>.
Willy Tarreaubaaee002006-06-26 02:48:02 +02004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
Ilya Shipitsin46a030c2020-07-05 16:36:08 +050010 * Please refer to RFC7230 - RFC7235 information about HTTP protocol, and
11 * RFC6265 for information about cookies usage. More generally, the IETF HTTP
Willy Tarreaubaaee002006-06-26 02:48:02 +020012 * Working Group's web site should be consulted for protocol related changes :
13 *
14 * http://ftp.ics.uci.edu/pub/ietf/http/
15 *
16 * Pending bugs (may be not fixed because never reproduced) :
17 * - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
18 * the proxy to terminate (no core) if the client breaks the connection during
19 * the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
20 * the snprintf() bug since requests were simple (GET / HTTP/1.0), but may be
21 * related to missing setsid() (fixed in 1.1.15)
22 * - a proxy with an invalid config will prevent the startup even if disabled.
23 *
24 * ChangeLog has moved to the CHANGELOG file.
25 *
Willy Tarreaubaaee002006-06-26 02:48:02 +020026 */
27
David Carlier7ece0962015-12-08 21:43:09 +000028#define _GNU_SOURCE
Willy Tarreaubaaee002006-06-26 02:48:02 +020029#include <stdio.h>
30#include <stdlib.h>
31#include <unistd.h>
32#include <string.h>
33#include <ctype.h>
Maxime de Roucy379d9c72016-05-13 23:52:56 +020034#include <dirent.h>
Maxime de Roucy379d9c72016-05-13 23:52:56 +020035#include <sys/stat.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020036#include <sys/time.h>
37#include <sys/types.h>
38#include <sys/socket.h>
39#include <netinet/tcp.h>
40#include <netinet/in.h>
41#include <arpa/inet.h>
42#include <netdb.h>
43#include <fcntl.h>
44#include <errno.h>
45#include <signal.h>
46#include <stdarg.h>
47#include <sys/resource.h>
Tim Duesterhusdfad6a42020-04-18 16:02:47 +020048#include <sys/utsname.h>
Marc-Antoine Perennou992709b2013-02-12 10:53:52 +010049#include <sys/wait.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020050#include <time.h>
51#include <syslog.h>
Michael Schererab012dd2013-01-12 18:35:19 +010052#include <grp.h>
Willy Tarreaufc6c0322012-11-16 16:12:27 +010053#ifdef USE_CPU_AFFINITY
Willy Tarreaufc6c0322012-11-16 16:12:27 +010054#include <sched.h>
David Carlier42d9e5a2018-11-12 16:22:19 +000055#if defined(__FreeBSD__) || defined(__DragonFly__)
Pieter Baauwcaa6a1b2015-09-17 21:26:40 +020056#include <sys/param.h>
David Carlier42d9e5a2018-11-12 16:22:19 +000057#ifdef __FreeBSD__
Pieter Baauwcaa6a1b2015-09-17 21:26:40 +020058#include <sys/cpuset.h>
David Carlier42d9e5a2018-11-12 16:22:19 +000059#endif
David Carlier6d5c8412017-11-29 11:02:32 +000060#include <pthread_np.h>
Pieter Baauwcaa6a1b2015-09-17 21:26:40 +020061#endif
David Carlier5e4c8e22019-09-13 05:12:58 +010062#ifdef __APPLE__
63#include <mach/mach_types.h>
64#include <mach/thread_act.h>
65#include <mach/thread_policy.h>
66#endif
Willy Tarreaufc6c0322012-11-16 16:12:27 +010067#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +020068
Willy Tarreau636848a2019-04-15 19:38:50 +020069#if defined(USE_PRCTL)
70#include <sys/prctl.h>
71#endif
72
Willy Tarreaubaaee002006-06-26 02:48:02 +020073#ifdef DEBUG_FULL
74#include <assert.h>
75#endif
Tim Duesterhusd6942c82017-11-20 15:58:35 +010076#if defined(USE_SYSTEMD)
77#include <systemd/sd-daemon.h>
78#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +020079
Willy Tarreau6c3a6812020-03-06 18:57:15 +010080#include <import/sha1.h>
81
Willy Tarreaub2551052020-06-09 09:07:15 +020082#include <haproxy/acl.h>
Amaury Denoyelle68fd7e42021-03-25 17:15:52 +010083#include <haproxy/action.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020084#include <haproxy/activity.h>
85#include <haproxy/api.h>
86#include <haproxy/arg.h>
87#include <haproxy/auth.h>
Willy Tarreau8d366972020-05-27 16:10:29 +020088#include <haproxy/base64.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020089#include <haproxy/capture-t.h>
Amaury Denoyelle5a6926d2021-03-30 17:34:24 +020090#include <haproxy/cfgdiag.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020091#include <haproxy/cfgparse.h>
Willy Tarreauc13ed532020-06-02 10:22:45 +020092#include <haproxy/chunk.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020093#include <haproxy/cli.h>
Willy Tarreau7ea393d2020-06-04 18:02:10 +020094#include <haproxy/connection.h>
Amaury Denoyellea6f9c5d2021-04-23 16:58:08 +020095#ifdef USE_CPU_AFFINITY
Amaury Denoyelle982fb532021-04-21 18:39:58 +020096#include <haproxy/cpuset.h>
Amaury Denoyellea6f9c5d2021-04-23 16:58:08 +020097#endif
Willy Tarreaueb92deb2020-06-04 10:53:16 +020098#include <haproxy/dns.h>
Willy Tarreau2741c8c2020-06-02 11:28:02 +020099#include <haproxy/dynbuf.h>
Willy Tarreau8d366972020-05-27 16:10:29 +0200100#include <haproxy/errors.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200101#include <haproxy/fd.h>
Willy Tarreauc7babd82020-06-04 21:29:29 +0200102#include <haproxy/filters.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200103#include <haproxy/global.h>
Willy Tarreau86416052020-06-04 09:20:54 +0200104#include <haproxy/hlua.h>
Willy Tarreauc761f842020-06-04 11:40:28 +0200105#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +0200106#include <haproxy/list.h>
Willy Tarreau213e9902020-06-04 14:58:24 +0200107#include <haproxy/listener.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +0200108#include <haproxy/log.h>
Willy Tarreaub5abe5b2020-06-04 14:07:37 +0200109#include <haproxy/mworker.h>
Willy Tarreau7a00efb2020-06-02 17:02:59 +0200110#include <haproxy/namespace.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +0200111#include <haproxy/net_helper.h>
Willy Tarreau6019fab2020-05-27 16:26:00 +0200112#include <haproxy/openssl-compat.h>
Willy Tarreau225a90a2020-06-04 15:06:28 +0200113#include <haproxy/pattern.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +0200114#include <haproxy/peers.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200115#include <haproxy/pool.h>
116#include <haproxy/protocol.h>
Willy Tarreaubf3b06b2020-08-26 10:23:40 +0200117#include <haproxy/proto_tcp.h>
Willy Tarreaua264d962020-06-04 22:29:18 +0200118#include <haproxy/proxy.h>
Willy Tarreau7cd8b6e2020-06-02 17:32:26 +0200119#include <haproxy/regex.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200120#include <haproxy/sample.h>
Willy Tarreau1e56f922020-06-04 23:20:13 +0200121#include <haproxy/server.h>
Willy Tarreau48d25b32020-06-04 18:58:52 +0200122#include <haproxy/session.h>
Willy Tarreau3727a8a2020-06-04 17:37:26 +0200123#include <haproxy/signal.h>
Willy Tarreau063d47d2020-08-28 16:29:53 +0200124#include <haproxy/sock.h>
Willy Tarreau25140cc2020-08-28 15:40:33 +0200125#include <haproxy/sock_inet.h>
Willy Tarreau209108d2020-06-04 20:30:20 +0200126#include <haproxy/ssl_sock.h>
Amaury Denoyelleee63d4b2020-10-05 11:49:42 +0200127#include <haproxy/stats-t.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +0200128#include <haproxy/stream.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +0200129#include <haproxy/task.h>
Willy Tarreau3f567e42020-05-28 15:29:19 +0200130#include <haproxy/thread.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200131#include <haproxy/time.h>
132#include <haproxy/tools.h>
133#include <haproxy/uri_auth-t.h>
Willy Tarreaua1718922020-06-04 16:25:31 +0200134#include <haproxy/vars.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200135#include <haproxy/version.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +0200136
Willy Tarreaubaaee002006-06-26 02:48:02 +0200137
Willy Tarreau7b5654f2019-03-29 21:30:17 +0100138/* array of init calls for older platforms */
139DECLARE_INIT_STAGES;
140
Willy Tarreauf4596402021-04-10 16:53:05 +0200141/* create a read_mostly section to hold variables which are accessed a lot
142 * but which almost never change. The purpose is to isolate them in their
143 * own cache lines where they don't risk to be perturbated by write accesses
144 * to neighbor variables. We need to create an empty aligned variable for
145 * this. The fact that the variable is of size zero means that it will be
146 * eliminated at link time if no other variable uses it, but alignment will
147 * be respected.
148 */
149empty_t __read_mostly_align HA_SECTION("read_mostly") ALIGNED(64);
150
Willy Tarreauf0d3b732021-05-06 16:30:32 +0200151#ifdef BUILD_FEATURES
152const char *build_features = BUILD_FEATURES;
153#else
154const char *build_features = "";
155#endif
156
Willy Tarreau477ecd82010-01-03 21:12:30 +0100157/* list of config files */
158static struct list cfg_cfgfiles = LIST_HEAD_INIT(cfg_cfgfiles);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200159int pid; /* current process id */
Willy Tarreau28156642007-11-26 16:13:36 +0100160int relative_pid = 1; /* process id starting at 1 */
Willy Tarreau387bd4f2017-11-10 19:08:14 +0100161unsigned long pid_bit = 1; /* bit corresponding to the process id */
Willy Tarreaua38a7172019-02-02 17:11:28 +0100162unsigned long all_proc_mask = 1; /* mask of all processes */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200163
Willy Tarreauf8ea00e2020-03-12 17:24:53 +0100164volatile unsigned long sleeping_thread_mask = 0; /* Threads that are about to sleep in poll() */
Willy Tarreau4b3f27b2020-03-12 17:28:01 +0100165volatile unsigned long stopping_thread_mask = 0; /* Threads acknowledged stopping */
Willy Tarreauf8ea00e2020-03-12 17:24:53 +0100166
Willy Tarreaubaaee002006-06-26 02:48:02 +0200167/* global options */
168struct global global = {
Cyril Bonté203ec5a2017-03-23 22:44:13 +0100169 .hard_stop_after = TICK_ETERNITY,
Willy Tarreau247a13a2012-11-15 17:38:15 +0100170 .nbproc = 1,
Amaury Denoyelle0f50cb92021-03-26 18:50:33 +0100171 .numa_cpu_mapping = 1,
Willy Tarreau149ab772019-01-26 14:27:06 +0100172 .nbthread = 0,
William Lallemand5f232402012-04-05 18:02:55 +0200173 .req_count = 0,
William Lallemand0f99e342011-10-12 17:50:54 +0200174 .logsrvs = LIST_HEAD_INIT(global.logsrvs),
William Lallemand9d5f5482012-11-07 16:12:57 +0100175 .maxzlibmem = 0,
William Lallemandd85f9172012-11-09 17:05:39 +0100176 .comp_rate_lim = 0,
Emeric Brun850efd52014-01-29 12:24:34 +0100177 .ssl_server_verify = SSL_SERVER_VERIFY_REQUIRED,
Emeric Bruned760922010-10-22 17:59:25 +0200178 .unix_bind = {
179 .ux = {
180 .uid = -1,
181 .gid = -1,
182 .mode = 0,
183 }
184 },
Willy Tarreau27a674e2009-08-17 07:23:33 +0200185 .tune = {
Willy Tarreau7ac908b2019-02-27 12:02:18 +0100186 .options = GTUNE_LISTENER_MQ,
Willy Tarreauc77d3642018-12-12 06:19:42 +0100187 .bufsize = (BUFSIZE + 2*sizeof(void *) - 1) & -(2*sizeof(void *)),
Christopher Faulet546c4692020-01-22 14:31:21 +0100188 .maxrewrite = MAXREWRITE,
Willy Tarreaua24adf02014-11-27 01:11:56 +0100189 .reserved_bufs = RESERVED_BUFS,
Willy Tarreauf3045d22015-04-29 16:24:50 +0200190 .pattern_cache = DEFAULT_PAT_LRU_SIZE,
Olivier Houchard88698d92019-04-16 19:07:22 +0200191 .pool_low_ratio = 20,
192 .pool_high_ratio = 25,
Christopher Faulet41ba36f2019-07-19 09:36:45 +0200193 .max_http_hdr = MAX_HTTP_HDR,
Emeric Brunfc32aca2012-09-03 12:10:29 +0200194#ifdef USE_OPENSSL
Emeric Brun46635772012-11-14 11:32:56 +0100195 .sslcachesize = SSLCACHESIZE,
Emeric Brunfc32aca2012-09-03 12:10:29 +0200196#endif
William Lallemandf3747832012-11-09 12:33:10 +0100197 .comp_maxlevel = 1,
Willy Tarreau7e312732014-02-12 16:35:14 +0100198#ifdef DEFAULT_IDLE_TIMER
199 .idle_timer = DEFAULT_IDLE_TIMER,
200#else
201 .idle_timer = 1000, /* 1 second */
202#endif
Willy Tarreau27a674e2009-08-17 07:23:33 +0200203 },
Emeric Brun76d88952012-10-05 15:47:31 +0200204#ifdef USE_OPENSSL
205#ifdef DEFAULT_MAXSSLCONN
Willy Tarreau403edff2012-09-06 11:58:37 +0200206 .maxsslconn = DEFAULT_MAXSSLCONN,
207#endif
Emeric Brun76d88952012-10-05 15:47:31 +0200208#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +0200209 /* others NULL OK */
210};
211
212/*********************************************************************/
213
214int stopping; /* non zero means stopping in progress */
Cyril Bonté203ec5a2017-03-23 22:44:13 +0100215int killed; /* non zero means a hard-stop is triggered */
Willy Tarreauaf7ad002010-08-31 15:39:26 +0200216int jobs = 0; /* number of active jobs (conns, listeners, active tasks, ...) */
William Lallemanda7199262018-11-16 16:57:20 +0100217int unstoppable_jobs = 0; /* number of active jobs that can't be stopped during a soft stop */
Willy Tarreau199ad242018-11-05 16:31:22 +0100218int active_peers = 0; /* number of active peers (connection attempts and connected) */
Willy Tarreau2d372c22018-11-05 17:12:27 +0100219int connected_peers = 0; /* number of connected peers (verified ones) */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200220
Ilya Shipitsin46a030c2020-07-05 16:36:08 +0500221/* Here we store information about the pids of the processes we may pause
Willy Tarreaubaaee002006-06-26 02:48:02 +0200222 * or kill. We will send them a signal every 10 ms until we can bind to all
223 * our ports. With 200 retries, that's about 2 seconds.
224 */
225#define MAX_START_RETRIES 200
Willy Tarreaubaaee002006-06-26 02:48:02 +0200226static int *oldpids = NULL;
227static int oldpids_sig; /* use USR1 or TERM */
228
Olivier Houchardf73629d2017-04-05 22:33:04 +0200229/* Path to the unix socket we use to retrieve listener sockets from the old process */
230static const char *old_unixsocket;
231
William Lallemand85b0bd92017-06-01 17:38:53 +0200232static char *cur_unixsocket = NULL;
233
William Lallemandcb11fd22017-06-01 17:38:52 +0200234int atexit_flag = 0;
235
Willy Tarreaubb545b42010-08-25 12:58:59 +0200236int nb_oldpids = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200237const int zero = 0;
238const int one = 1;
Alexandre Cassen87ea5482007-10-11 20:48:58 +0200239const struct linger nolinger = { .l_onoff = 1, .l_linger = 0 };
Willy Tarreaubaaee002006-06-26 02:48:02 +0200240
Willy Tarreau1d21e0a2010-03-12 21:58:54 +0100241char hostname[MAX_HOSTNAME_LEN];
Dragan Dosen4f014152020-06-18 16:56:47 +0200242char *localpeer = NULL;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200243
William Lallemand00417412020-06-05 14:08:41 +0200244static char **old_argv = NULL; /* previous argv but cleaned up */
William Lallemand73b85e72017-06-01 17:38:51 +0200245
William Lallemandbc193052018-09-11 10:06:26 +0200246struct list proc_list = LIST_HEAD_INIT(proc_list);
247
248int master = 0; /* 1 if in master, 0 if in child */
Willy Tarreaubf696402019-03-01 10:09:28 +0100249unsigned int rlim_fd_cur_at_boot = 0;
250unsigned int rlim_fd_max_at_boot = 0;
William Lallemandbc193052018-09-11 10:06:26 +0200251
Willy Tarreau6c3a6812020-03-06 18:57:15 +0100252/* per-boot randomness */
253unsigned char boot_seed[20]; /* per-boot random seed (160 bits initially) */
254
William Lallemandb3f2be32018-09-11 10:06:18 +0200255static void *run_thread_poll_loop(void *data);
256
Willy Tarreauff055502014-04-28 22:27:06 +0200257/* bitfield of a few warnings to emit just once (WARN_*) */
258unsigned int warned = 0;
259
Amaury Denoyelle484454d2021-05-05 16:18:45 +0200260/* set if experimental features have been used for the current process */
261static unsigned int tainted = 0;
262
Amaury Denoyelled2e53cd2021-05-06 16:21:39 +0200263unsigned int experimental_directives_allowed = 0;
264
265int check_kw_experimental(struct cfg_keyword *kw, const char *file, int linenum,
266 char **errmsg)
267{
268 if (kw->flags & KWF_EXPERIMENTAL) {
269 if (!experimental_directives_allowed) {
Amaury Denoyelle86c1d0f2021-05-07 15:07:21 +0200270 memprintf(errmsg, "parsing [%s:%d] : '%s' directive is experimental, must be allowed via a global 'expose-experimental-directives'",
Amaury Denoyelled2e53cd2021-05-06 16:21:39 +0200271 file, linenum, kw->kw);
272 return 1;
273 }
274 mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
275 }
276
277 return 0;
278}
279
William Lallemande7361152018-10-26 14:47:36 +0200280/* master CLI configuration (-S flag) */
281struct list mworker_cli_conf = LIST_HEAD_INIT(mworker_cli_conf);
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100282
283/* These are strings to be reported in the output of "haproxy -vv". They may
284 * either be constants (in which case must_free must be zero) or dynamically
285 * allocated strings to pass to free() on exit, and in this case must_free
286 * must be non-zero.
287 */
288struct list build_opts_list = LIST_HEAD_INIT(build_opts_list);
289struct build_opts_str {
290 struct list list;
291 const char *str;
292 int must_free;
293};
294
Willy Tarreaubaaee002006-06-26 02:48:02 +0200295/*********************************************************************/
296/* general purpose functions ***************************************/
297/*********************************************************************/
298
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100299/* used to register some build option strings at boot. Set must_free to
300 * non-zero if the string must be freed upon exit.
301 */
302void hap_register_build_opts(const char *str, int must_free)
303{
304 struct build_opts_str *b;
305
306 b = calloc(1, sizeof(*b));
307 if (!b) {
308 fprintf(stderr, "out of memory\n");
309 exit(1);
310 }
311 b->str = str;
312 b->must_free = must_free;
Willy Tarreau2b718102021-04-21 07:32:39 +0200313 LIST_APPEND(&build_opts_list, &b->list);
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100314}
315
Willy Tarreaua43dfda2021-05-06 07:43:35 +0200316#define VERSION_MAX_ELTS 7
317
318/* This function splits an haproxy version string into an array of integers.
319 * The syntax of the supported version string is the following:
320 *
321 * <a>[.<b>[.<c>[.<d>]]][-{dev,pre,rc}<f>][-*][-<g>]
322 *
323 * This validates for example:
324 * 1.2.1-pre2, 1.2.1, 1.2.10.1, 1.3.16-rc1, 1.4-dev3, 1.5-dev18, 1.5-dev18-43
325 * 2.4-dev18-f6818d-20
326 *
327 * The result is set in a array of <VERSION_MAX_ELTS> elements. Each letter has
328 * one fixed place in the array. The tags take a numeric value called <e> which
329 * defaults to 3. "dev" is 1, "rc" and "pre" are 2. Numbers not encountered are
330 * considered as zero (henxe 1.5 and 1.5.0 are the same).
331 *
332 * The resulting values are:
333 * 1.2.1-pre2 1, 2, 1, 0, 2, 2, 0
334 * 1.2.1 1, 2, 1, 0, 3, 0, 0
335 * 1.2.10.1 1, 2, 10, 1, 3, 0, 0
336 * 1.3.16-rc1 1, 3, 16, 0, 2, 1, 0
337 * 1.4-dev3 1, 4, 0, 0, 1, 3, 0
338 * 1.5-dev18 1, 5, 0, 0, 1, 18, 0
339 * 1.5-dev18-43 1, 5, 0, 0, 1, 18, 43
340 * 2.4-dev18-f6818d-20 2, 4, 0, 0, 1, 18, 20
341 *
342 * The function returns non-zero if the conversion succeeded, or zero if it
343 * failed.
344 */
345int split_version(const char *version, unsigned int *value)
346{
347 const char *p, *s;
348 char *error;
349 int nelts;
350
351 /* Initialize array with zeroes */
352 for (nelts = 0; nelts < VERSION_MAX_ELTS; nelts++)
353 value[nelts] = 0;
354 value[4] = 3;
355
356 p = version;
357
358 /* If the version number is empty, return false */
359 if (*p == '\0')
360 return 0;
361
362 /* Convert first number <a> */
363 value[0] = strtol(p, &error, 10);
364 p = error + 1;
365 if (*error == '\0')
366 return 1;
367 if (*error == '-')
368 goto split_version_tag;
369 if (*error != '.')
370 return 0;
371
372 /* Convert first number <b> */
373 value[1] = strtol(p, &error, 10);
374 p = error + 1;
375 if (*error == '\0')
376 return 1;
377 if (*error == '-')
378 goto split_version_tag;
379 if (*error != '.')
380 return 0;
381
382 /* Convert first number <c> */
383 value[2] = strtol(p, &error, 10);
384 p = error + 1;
385 if (*error == '\0')
386 return 1;
387 if (*error == '-')
388 goto split_version_tag;
389 if (*error != '.')
390 return 0;
391
392 /* Convert first number <d> */
393 value[3] = strtol(p, &error, 10);
394 p = error + 1;
395 if (*error == '\0')
396 return 1;
397 if (*error != '-')
398 return 0;
399
400 split_version_tag:
401 /* Check for commit number */
402 if (*p >= '0' && *p <= '9')
403 goto split_version_commit;
404
405 /* Read tag */
406 if (strncmp(p, "dev", 3) == 0) { value[4] = 1; p += 3; }
407 else if (strncmp(p, "rc", 2) == 0) { value[4] = 2; p += 2; }
408 else if (strncmp(p, "pre", 3) == 0) { value[4] = 2; p += 3; }
409 else
410 goto split_version_commit;
411
412 /* Convert tag number */
413 value[5] = strtol(p, &error, 10);
414 p = error + 1;
415 if (*error == '\0')
416 return 1;
417 if (*error != '-')
418 return 0;
419
420 split_version_commit:
421 /* Search the last "-" */
422 s = strrchr(p, '-');
423 if (s) {
424 s++;
425 if (*s == '\0')
426 return 0;
427 value[6] = strtol(s, &error, 10);
428 if (*error != '\0')
429 value[6] = 0;
430 return 1;
431 }
432
433 /* convert the version */
434 value[6] = strtol(p, &error, 10);
435 if (*error != '\0')
436 value[6] = 0;
437
438 return 1;
439}
440
441/* This function compares the current haproxy version with an arbitrary version
442 * string. It returns:
443 * -1 : the version in argument is older than the current haproxy version
444 * 0 : the version in argument is the same as the current haproxy version
445 * 1 : the version in argument is newer than the current haproxy version
446 *
447 * Or some errors:
448 * -2 : the current haproxy version is not parsable
449 * -3 : the version in argument is not parsable
450 */
451int compare_current_version(const char *version)
452{
453 unsigned int loc[VERSION_MAX_ELTS];
454 unsigned int mod[VERSION_MAX_ELTS];
455 int i;
456
457 /* split versions */
458 if (!split_version(haproxy_version, loc))
459 return -2;
460 if (!split_version(version, mod))
461 return -3;
462
463 /* compare versions */
464 for (i = 0; i < VERSION_MAX_ELTS; i++) {
465 if (mod[i] < loc[i])
466 return -1;
467 else if (mod[i] > loc[i])
468 return 1;
469 }
470 return 0;
471}
472
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100473static void display_version()
Willy Tarreaubaaee002006-06-26 02:48:02 +0200474{
Tim Duesterhusdfad6a42020-04-18 16:02:47 +0200475 struct utsname utsname;
476
Willy Tarreaua5357cd2021-05-09 06:14:25 +0200477 printf("HAProxy version %s %s - https://haproxy.org/\n"
Willy Tarreau08dd2022019-11-21 18:07:30 +0100478 PRODUCT_STATUS "\n", haproxy_version, haproxy_date);
Willy Tarreau47479eb2019-11-21 18:48:20 +0100479
480 if (strlen(PRODUCT_URL_BUGS) > 0) {
481 char base_version[20];
482 int dots = 0;
483 char *del;
484
485 /* only retrieve the base version without distro-specific extensions */
486 for (del = haproxy_version; *del; del++) {
487 if (*del == '.')
488 dots++;
489 else if (*del < '0' || *del > '9')
490 break;
491 }
492
493 strlcpy2(base_version, haproxy_version, del - haproxy_version + 1);
494 if (dots < 2)
495 printf("Known bugs: https://github.com/haproxy/haproxy/issues?q=is:issue+is:open\n");
496 else
497 printf("Known bugs: " PRODUCT_URL_BUGS "\n", base_version);
498 }
Tim Duesterhusdfad6a42020-04-18 16:02:47 +0200499
500 if (uname(&utsname) == 0) {
501 printf("Running on: %s %s %s %s\n", utsname.sysname, utsname.release, utsname.version, utsname.machine);
502 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200503}
504
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100505static void display_build_opts()
Willy Tarreau7b066db2007-12-02 11:28:59 +0100506{
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100507 struct build_opts_str *item;
508
Willy Tarreau7b066db2007-12-02 11:28:59 +0100509 printf("Build options :"
510#ifdef BUILD_TARGET
Willy Tarreau9f2b7302008-01-02 20:48:34 +0100511 "\n TARGET = " BUILD_TARGET
Willy Tarreau7b066db2007-12-02 11:28:59 +0100512#endif
513#ifdef BUILD_CPU
Willy Tarreau9f2b7302008-01-02 20:48:34 +0100514 "\n CPU = " BUILD_CPU
Willy Tarreau7b066db2007-12-02 11:28:59 +0100515#endif
516#ifdef BUILD_CC
Willy Tarreau9f2b7302008-01-02 20:48:34 +0100517 "\n CC = " BUILD_CC
518#endif
519#ifdef BUILD_CFLAGS
520 "\n CFLAGS = " BUILD_CFLAGS
Willy Tarreau7b066db2007-12-02 11:28:59 +0100521#endif
Willy Tarreau9f2b7302008-01-02 20:48:34 +0100522#ifdef BUILD_OPTIONS
523 "\n OPTIONS = " BUILD_OPTIONS
Willy Tarreau7b066db2007-12-02 11:28:59 +0100524#endif
Tim Duesterhusc8d19702020-11-21 18:07:59 +0100525#ifdef BUILD_DEBUG
526 "\n DEBUG = " BUILD_DEBUG
527#endif
Willy Tarreau7728ed32019-03-27 13:20:08 +0100528#ifdef BUILD_FEATURES
529 "\n\nFeature list : " BUILD_FEATURES
530#endif
Willy Tarreau27a674e2009-08-17 07:23:33 +0200531 "\n\nDefault settings :"
Willy Tarreauca783d42019-03-13 10:03:07 +0100532 "\n bufsize = %d, maxrewrite = %d, maxpollevents = %d"
Willy Tarreau27a674e2009-08-17 07:23:33 +0200533 "\n\n",
Willy Tarreauca783d42019-03-13 10:03:07 +0100534 BUFSIZE, MAXREWRITE, MAX_POLL_EVENTS);
Willy Tarreaube5b6852009-10-03 18:57:08 +0200535
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100536 list_for_each_entry(item, &build_opts_list, list) {
537 puts(item->str);
538 }
539
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100540 putchar('\n');
541
Willy Tarreaube5b6852009-10-03 18:57:08 +0200542 list_pollers(stdout);
543 putchar('\n');
Christopher Faulet98d9fe22018-04-10 14:37:32 +0200544 list_mux_proto(stdout);
545 putchar('\n');
Willy Tarreau679bba12019-03-19 08:08:10 +0100546 list_services(stdout);
547 putchar('\n');
Christopher Fauletb3f4e142016-03-07 12:46:38 +0100548 list_filters(stdout);
549 putchar('\n');
Willy Tarreau7b066db2007-12-02 11:28:59 +0100550}
551
Willy Tarreaubaaee002006-06-26 02:48:02 +0200552/*
553 * This function prints the command line usage and exits
554 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100555static void usage(char *name)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200556{
557 display_version();
558 fprintf(stderr,
Maxime de Roucy379d9c72016-05-13 23:52:56 +0200559 "Usage : %s [-f <cfgfile|cfgdir>]* [ -vdV"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200560 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
Willy Tarreaua088d312015-10-08 11:58:48 +0200561 " [ -p <pidfile> ] [ -m <max megs> ] [ -C <dir> ] [-- <cfgfile>*]\n"
Willy Tarreau7b066db2007-12-02 11:28:59 +0100562 " -v displays version ; -vv shows known build options.\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200563 " -d enters debug mode ; -db only disables background mode.\n"
Willy Tarreau6e064432012-05-08 15:40:42 +0200564 " -dM[<byte>] poisons memory with <byte> (defaults to 0x50)\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200565 " -V enters verbose mode (disables quiet mode)\n"
Willy Tarreau576132e2011-09-10 19:26:56 +0200566 " -D goes daemon ; -C changes to <dir> before loading files.\n"
William Lallemand095ba4c2017-06-01 17:38:50 +0200567 " -W master-worker mode.\n"
Tim Duesterhusd6942c82017-11-20 15:58:35 +0100568#if defined(USE_SYSTEMD)
569 " -Ws master-worker mode with systemd notify support.\n"
570#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +0200571 " -q quiet mode : don't display messages\n"
Willy Tarreau5d01a632009-06-22 16:02:30 +0200572 " -c check mode : only check config files and exit\n"
Willy Tarreauca783d42019-03-13 10:03:07 +0100573 " -n sets the maximum total # of connections (uses ulimit -n)\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200574 " -m limits the usable amount of memory (in MB)\n"
575 " -N sets the default, per-proxy maximum # of connections (%d)\n"
Emeric Brun2b920a12010-09-23 18:30:22 +0200576 " -L set local peer name (default to hostname)\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200577 " -p writes pids of all children to this file\n"
Willy Tarreaue5733232019-05-22 19:24:06 +0200578#if defined(USE_EPOLL)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200579 " -de disables epoll() usage even when available\n"
580#endif
Willy Tarreaue5733232019-05-22 19:24:06 +0200581#if defined(USE_KQUEUE)
Willy Tarreau1e63130a2007-04-09 12:03:06 +0200582 " -dk disables kqueue() usage even when available\n"
583#endif
Willy Tarreaue5733232019-05-22 19:24:06 +0200584#if defined(USE_EVPORTS)
Emmanuel Hocdet0ba4f482019-04-08 16:53:32 +0000585 " -dv disables event ports usage even when available\n"
586#endif
Willy Tarreaue5733232019-05-22 19:24:06 +0200587#if defined(USE_POLL)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200588 " -dp disables poll() usage even when available\n"
589#endif
Willy Tarreaue5733232019-05-22 19:24:06 +0200590#if defined(USE_LINUX_SPLICE)
Willy Tarreau3ab68cf2009-01-25 16:03:28 +0100591 " -dS disables splice usage (broken on old kernels)\n"
592#endif
Nenad Merdanovic88afe032014-04-14 15:56:58 +0200593#if defined(USE_GETADDRINFO)
594 " -dG disables getaddrinfo() usage\n"
595#endif
Lukas Tribusa0bcbdc2016-09-12 21:42:20 +0000596#if defined(SO_REUSEPORT)
597 " -dR disables SO_REUSEPORT usage\n"
598#endif
Willy Tarreau3eed10e2016-11-07 21:03:16 +0100599 " -dr ignores server address resolution failures\n"
Emeric Brun850efd52014-01-29 12:24:34 +0100600 " -dV disables SSL verify on servers side\n"
Willy Tarreau3eb10b82020-04-15 16:42:39 +0200601 " -dW fails if any warning is emitted\n"
Amaury Denoyelle7b01a8d2021-03-29 10:29:07 +0200602 " -dD diagnostic mode : warn about suspicious configuration statements\n"
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +0200603 " -sf/-st [pid ]* finishes/terminates old pids.\n"
Olivier Houchardf73629d2017-04-05 22:33:04 +0200604 " -x <unix_socket> get listening sockets from a unix socket\n"
William Lallemand63329e32019-06-13 17:03:37 +0200605 " -S <bind>[,<bind options>...] new master CLI\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200606 "\n",
Willy Tarreauca783d42019-03-13 10:03:07 +0100607 name, cfg_maxpconn);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200608 exit(1);
609}
610
611
612
613/*********************************************************************/
614/* more specific functions ***************************************/
615/*********************************************************************/
616
William Lallemand73b85e72017-06-01 17:38:51 +0200617/* sends the signal <sig> to all pids found in <oldpids>. Returns the number of
618 * pids the signal was correctly delivered to.
619 */
William Lallemande25473c2019-04-01 11:29:56 +0200620int tell_old_pids(int sig)
William Lallemand73b85e72017-06-01 17:38:51 +0200621{
622 int p;
623 int ret = 0;
624 for (p = 0; p < nb_oldpids; p++)
625 if (kill(oldpids[p], sig) == 0)
626 ret++;
627 return ret;
628}
629
William Lallemand75ea0a02017-11-15 19:02:58 +0100630/*
William Lallemand73b85e72017-06-01 17:38:51 +0200631 * remove a pid forom the olpid array and decrease nb_oldpids
632 * return 1 pid was found otherwise return 0
633 */
634
635int delete_oldpid(int pid)
636{
637 int i;
638
639 for (i = 0; i < nb_oldpids; i++) {
640 if (oldpids[i] == pid) {
641 oldpids[i] = oldpids[nb_oldpids - 1];
642 oldpids[nb_oldpids - 1] = 0;
643 nb_oldpids--;
644 return 1;
645 }
646 }
647 return 0;
648}
649
William Lallemand85b0bd92017-06-01 17:38:53 +0200650
651static void get_cur_unixsocket()
652{
653 /* if -x was used, try to update the stat socket if not available anymore */
Willy Tarreau4975d142021-03-13 11:00:33 +0100654 if (global.cli_fe) {
William Lallemand85b0bd92017-06-01 17:38:53 +0200655 struct bind_conf *bind_conf;
656
657 /* pass through all stats socket */
Willy Tarreau4975d142021-03-13 11:00:33 +0100658 list_for_each_entry(bind_conf, &global.cli_fe->conf.bind, by_fe) {
William Lallemand85b0bd92017-06-01 17:38:53 +0200659 struct listener *l;
660
661 list_for_each_entry(l, &bind_conf->listeners, by_bind) {
662
Willy Tarreau37159062020-08-27 07:48:42 +0200663 if (l->rx.addr.ss_family == AF_UNIX &&
William Lallemand85b0bd92017-06-01 17:38:53 +0200664 (bind_conf->level & ACCESS_FD_LISTENERS)) {
665 const struct sockaddr_un *un;
666
Willy Tarreau37159062020-08-27 07:48:42 +0200667 un = (struct sockaddr_un *)&l->rx.addr;
William Lallemand85b0bd92017-06-01 17:38:53 +0200668 /* priority to old_unixsocket */
669 if (!cur_unixsocket) {
670 cur_unixsocket = strdup(un->sun_path);
671 } else {
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100672 if (old_unixsocket && strcmp(un->sun_path, old_unixsocket) == 0) {
William Lallemand85b0bd92017-06-01 17:38:53 +0200673 free(cur_unixsocket);
674 cur_unixsocket = strdup(old_unixsocket);
675 return;
676 }
677 }
678 }
679 }
680 }
681 }
682 if (!cur_unixsocket && old_unixsocket)
683 cur_unixsocket = strdup(old_unixsocket);
684}
685
William Lallemand73b85e72017-06-01 17:38:51 +0200686/*
687 * When called, this function reexec haproxy with -sf followed by current
Joseph Herlant03420902018-11-15 10:41:50 -0800688 * children PIDs and possibly old children PIDs if they didn't leave yet.
William Lallemand73b85e72017-06-01 17:38:51 +0200689 */
William Lallemanda57b7e32018-12-14 21:11:31 +0100690void mworker_reload()
William Lallemand73b85e72017-06-01 17:38:51 +0200691{
William Lallemand00417412020-06-05 14:08:41 +0200692 char **next_argv = NULL;
693 int old_argc = 0; /* previous number of argument */
William Lallemand73b85e72017-06-01 17:38:51 +0200694 int next_argc = 0;
William Lallemand00417412020-06-05 14:08:41 +0200695 int i = 0;
William Lallemand73b85e72017-06-01 17:38:51 +0200696 char *msg = NULL;
Willy Tarreau8dca1952019-03-01 10:21:55 +0100697 struct rlimit limit;
William Lallemand7c756a82018-11-26 11:53:40 +0100698 struct per_thread_deinit_fct *ptdf;
William Lallemand73b85e72017-06-01 17:38:51 +0200699
700 mworker_block_signals();
Tim Duesterhusd6942c82017-11-20 15:58:35 +0100701#if defined(USE_SYSTEMD)
702 if (global.tune.options & GTUNE_USE_SYSTEMD)
703 sd_notify(0, "RELOADING=1");
704#endif
William Lallemand73b85e72017-06-01 17:38:51 +0200705 setenv("HAPROXY_MWORKER_REEXEC", "1", 1);
706
William Lallemandbc193052018-09-11 10:06:26 +0200707 mworker_proc_list_to_env(); /* put the children description in the env */
708
William Lallemand7c756a82018-11-26 11:53:40 +0100709 /* during the reload we must ensure that every FDs that can't be
710 * reuse (ie those that are not referenced in the proc_list)
711 * are closed or they will leak. */
712
713 /* close the listeners FD */
714 mworker_cli_proxy_stop();
William Lallemand16866672019-06-24 17:40:48 +0200715
716 if (getenv("HAPROXY_MWORKER_WAIT_ONLY") == NULL) {
717 /* close the poller FD and the thread waker pipe FD */
718 list_for_each_entry(ptdf, &per_thread_deinit_list, list)
719 ptdf->fct();
720 if (fdtab)
721 deinit_pollers();
722 }
Ilya Shipitsin98a9e1b2021-02-19 23:42:53 +0500723#ifdef HAVE_SSL_RAND_KEEP_RANDOM_DEVICES_OPEN
William Lallemand5fdb5b32019-10-15 14:04:08 +0200724 /* close random device FDs */
725 RAND_keep_random_devices_open(0);
Rob Allen56996da2019-05-03 09:11:32 +0100726#endif
William Lallemand7c756a82018-11-26 11:53:40 +0100727
Willy Tarreau8dca1952019-03-01 10:21:55 +0100728 /* restore the initial FD limits */
729 limit.rlim_cur = rlim_fd_cur_at_boot;
730 limit.rlim_max = rlim_fd_max_at_boot;
731 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
732 getrlimit(RLIMIT_NOFILE, &limit);
733 ha_warning("Failed to restore initial FD limits (cur=%u max=%u), using cur=%u max=%u\n",
734 rlim_fd_cur_at_boot, rlim_fd_max_at_boot,
735 (unsigned int)limit.rlim_cur, (unsigned int)limit.rlim_max);
736 }
737
William Lallemand73b85e72017-06-01 17:38:51 +0200738 /* compute length */
William Lallemand00417412020-06-05 14:08:41 +0200739 while (old_argv[old_argc])
740 old_argc++;
William Lallemand73b85e72017-06-01 17:38:51 +0200741
William Lallemand85b0bd92017-06-01 17:38:53 +0200742 /* 1 for haproxy -sf, 2 for -x /socket */
William Lallemandaba7f8b2021-04-21 16:55:34 +0200743 next_argv = calloc(old_argc + 1 + 2 + mworker_child_nb() + 1,
Tim Duesterhuse52b6e52020-09-12 20:26:43 +0200744 sizeof(*next_argv));
William Lallemand73b85e72017-06-01 17:38:51 +0200745 if (next_argv == NULL)
746 goto alloc_error;
747
William Lallemand00417412020-06-05 14:08:41 +0200748 /* copy the program name */
749 next_argv[next_argc++] = old_argv[0];
750
751 /* insert the new options just after argv[0] in case we have a -- */
752
William Lallemand73b85e72017-06-01 17:38:51 +0200753 /* add -sf <PID>* to argv */
William Lallemand3f128872019-04-01 11:29:59 +0200754 if (mworker_child_nb() > 0) {
755 struct mworker_proc *child;
756
William Lallemand73b85e72017-06-01 17:38:51 +0200757 next_argv[next_argc++] = "-sf";
William Lallemand3f128872019-04-01 11:29:59 +0200758
759 list_for_each_entry(child, &proc_list, list) {
William Lallemand677e2f22019-11-19 17:04:18 +0100760 if (!(child->options & (PROC_O_TYPE_WORKER|PROC_O_TYPE_PROG)) || child->pid <= -1 )
William Lallemand3f128872019-04-01 11:29:59 +0200761 continue;
William Lallemand00417412020-06-05 14:08:41 +0200762 if ((next_argv[next_argc++] = memprintf(&msg, "%d", child->pid)) == NULL)
William Lallemand73b85e72017-06-01 17:38:51 +0200763 goto alloc_error;
764 msg = NULL;
765 }
766 }
William Lallemand2bf6d622017-06-20 11:20:23 +0200767 /* add the -x option with the stat socket */
William Lallemand85b0bd92017-06-01 17:38:53 +0200768 if (cur_unixsocket) {
William Lallemand2bf6d622017-06-20 11:20:23 +0200769 next_argv[next_argc++] = "-x";
770 next_argv[next_argc++] = (char *)cur_unixsocket;
William Lallemand85b0bd92017-06-01 17:38:53 +0200771 }
772
William Lallemand00417412020-06-05 14:08:41 +0200773 /* copy the previous options */
774 for (i = 1; i < old_argc; i++)
775 next_argv[next_argc++] = old_argv[i];
776
Christopher Faulet767a84b2017-11-24 16:50:31 +0100777 ha_warning("Reexecuting Master process\n");
Willy Tarreaue0d86e22019-08-26 10:37:39 +0200778 signal(SIGPROF, SIG_IGN);
Tim Duesterhus0436ab72017-11-12 17:39:18 +0100779 execvp(next_argv[0], next_argv);
William Lallemand73b85e72017-06-01 17:38:51 +0200780
Christopher Faulet767a84b2017-11-24 16:50:31 +0100781 ha_warning("Failed to reexecute the master process [%d]: %s\n", pid, strerror(errno));
Willy Tarreau61cfdf42021-02-20 10:46:51 +0100782 ha_free(&next_argv);
William Lallemand722d4ca2017-11-15 19:02:55 +0100783 return;
784
William Lallemand73b85e72017-06-01 17:38:51 +0200785alloc_error:
Willy Tarreau61cfdf42021-02-20 10:46:51 +0100786 ha_free(&next_argv);
Joseph Herlant07a08342018-11-15 10:43:05 -0800787 ha_warning("Failed to reexecute the master process [%d]: Cannot allocate memory\n", pid);
William Lallemand73b85e72017-06-01 17:38:51 +0200788 return;
789}
790
William Lallemandb3f2be32018-09-11 10:06:18 +0200791static void mworker_loop()
792{
793
794#if defined(USE_SYSTEMD)
795 if (global.tune.options & GTUNE_USE_SYSTEMD)
796 sd_notifyf(0, "READY=1\nMAINPID=%lu", (unsigned long)getpid());
797#endif
Willy Tarreaud83b6c12019-04-18 11:31:36 +0200798 /* Busy polling makes no sense in the master :-) */
799 global.tune.options &= ~GTUNE_BUSY_POLLING;
William Lallemandb3f2be32018-09-11 10:06:18 +0200800
William Lallemandbc193052018-09-11 10:06:26 +0200801 master = 1;
802
Willy Tarreaud26c9f92019-12-11 14:24:07 +0100803 signal_unregister(SIGTTIN);
804 signal_unregister(SIGTTOU);
William Lallemand0564d412018-11-20 17:36:53 +0100805 signal_unregister(SIGUSR1);
806 signal_unregister(SIGHUP);
807 signal_unregister(SIGQUIT);
808
William Lallemandb3f2be32018-09-11 10:06:18 +0200809 signal_register_fct(SIGTERM, mworker_catch_sigterm, SIGTERM);
810 signal_register_fct(SIGUSR1, mworker_catch_sigterm, SIGUSR1);
Willy Tarreaud26c9f92019-12-11 14:24:07 +0100811 signal_register_fct(SIGTTIN, mworker_broadcast_signal, SIGTTIN);
812 signal_register_fct(SIGTTOU, mworker_broadcast_signal, SIGTTOU);
William Lallemandb3f2be32018-09-11 10:06:18 +0200813 signal_register_fct(SIGINT, mworker_catch_sigterm, SIGINT);
814 signal_register_fct(SIGHUP, mworker_catch_sighup, SIGHUP);
815 signal_register_fct(SIGUSR2, mworker_catch_sighup, SIGUSR2);
816 signal_register_fct(SIGCHLD, mworker_catch_sigchld, SIGCHLD);
817
818 mworker_unblock_signals();
819 mworker_cleanlisteners();
William Lallemand27f3fa52018-12-06 14:05:20 +0100820 mworker_cleantasks();
William Lallemandb3f2be32018-09-11 10:06:18 +0200821
William Lallemandbc193052018-09-11 10:06:26 +0200822 mworker_catch_sigchld(NULL); /* ensure we clean the children in case
823 some SIGCHLD were lost */
824
William Lallemandb3f2be32018-09-11 10:06:18 +0200825 global.nbthread = 1;
826 relative_pid = 1;
827 pid_bit = 1;
Willy Tarreaua38a7172019-02-02 17:11:28 +0100828 all_proc_mask = 1;
William Lallemandb3f2be32018-09-11 10:06:18 +0200829
William Lallemand2672eb92018-12-14 15:52:39 +0100830#ifdef USE_THREAD
831 tid_bit = 1;
832 all_threads_mask = 1;
833#endif
834
William Lallemandb3f2be32018-09-11 10:06:18 +0200835 jobs++; /* this is the "master" job, we want to take care of the
836 signals even if there is no listener so the poll loop don't
837 leave */
838
839 fork_poller();
Willy Tarreaub4f7cc32019-05-03 09:27:30 +0200840 run_thread_poll_loop(0);
William Lallemandb3f2be32018-09-11 10:06:18 +0200841}
William Lallemandcb11fd22017-06-01 17:38:52 +0200842
843/*
844 * Reexec the process in failure mode, instead of exiting
845 */
846void reexec_on_failure()
847{
848 if (!atexit_flag)
849 return;
850
851 setenv("HAPROXY_MWORKER_WAIT_ONLY", "1", 1);
852
Christopher Faulet767a84b2017-11-24 16:50:31 +0100853 ha_warning("Reexecuting Master process in waitpid mode\n");
William Lallemandcb11fd22017-06-01 17:38:52 +0200854 mworker_reload();
William Lallemandcb11fd22017-06-01 17:38:52 +0200855}
William Lallemand73b85e72017-06-01 17:38:51 +0200856
857
858/*
Willy Tarreaud0807c32010-08-27 18:26:11 +0200859 * upon SIGUSR1, let's have a soft stop. Note that soft_stop() broadcasts
860 * a signal zero to all subscribers. This means that it's as easy as
861 * subscribing to signal 0 to get informed about an imminent shutdown.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200862 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100863static void sig_soft_stop(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200864{
865 soft_stop();
Willy Tarreau24f4efa2010-08-27 17:56:48 +0200866 signal_unregister_handler(sh);
Willy Tarreaubafbe012017-11-24 17:34:44 +0100867 pool_gc(NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200868}
869
870/*
871 * upon SIGTTOU, we pause everything
872 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100873static void sig_pause(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200874{
Willy Tarreau775e0012020-09-24 16:36:26 +0200875 if (protocol_pause_all() & ERR_FATAL) {
876 const char *msg = "Some proxies refused to pause, performing soft stop now.\n";
Willy Tarreau0a002df2020-10-09 19:26:27 +0200877 ha_warning("%s", msg);
878 send_log(NULL, LOG_WARNING, "%s", msg);
Willy Tarreau775e0012020-09-24 16:36:26 +0200879 soft_stop();
880 }
Willy Tarreaubafbe012017-11-24 17:34:44 +0100881 pool_gc(NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200882}
883
884/*
885 * upon SIGTTIN, let's have a soft stop.
886 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100887static void sig_listen(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200888{
Willy Tarreau775e0012020-09-24 16:36:26 +0200889 if (protocol_resume_all() & ERR_FATAL) {
890 const char *msg = "Some proxies refused to resume, probably due to a conflict on a listening port. You may want to try again after the conflicting application is stopped, otherwise a restart might be needed to resume safe operations.\n";
Willy Tarreau0a002df2020-10-09 19:26:27 +0200891 ha_warning("%s", msg);
892 send_log(NULL, LOG_WARNING, "%s", msg);
Willy Tarreau775e0012020-09-24 16:36:26 +0200893 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200894}
895
896/*
897 * this function dumps every server's state when the process receives SIGHUP.
898 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100899static void sig_dump_state(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200900{
Olivier Houchardfbc74e82017-11-24 16:54:05 +0100901 struct proxy *p = proxies_list;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200902
Christopher Faulet767a84b2017-11-24 16:50:31 +0100903 ha_warning("SIGHUP received, dumping servers states.\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +0200904 while (p) {
905 struct server *s = p->srv;
906
907 send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
908 while (s) {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100909 chunk_printf(&trash,
910 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %lld tot.",
911 p->id, s->id,
Emeric Brun52a91d32017-08-31 14:41:55 +0200912 (s->cur_state != SRV_ST_STOPPED) ? "UP" : "DOWN",
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100913 s->cur_sess, s->nbpend, s->counters.cum_sess);
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200914 ha_warning("%s\n", trash.area);
915 send_log(p, LOG_NOTICE, "%s\n", trash.area);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200916 s = s->next;
917 }
918
Willy Tarreau5fcc8f12007-09-17 11:27:09 +0200919 /* FIXME: those info are a bit outdated. We should be able to distinguish between FE and BE. */
920 if (!p->srv) {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100921 chunk_printf(&trash,
922 "SIGHUP: Proxy %s has no servers. Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
923 p->id,
924 p->feconn, p->beconn, p->totpend, p->nbpend, p->fe_counters.cum_conn, p->be_counters.cum_conn);
Willy Tarreau5fcc8f12007-09-17 11:27:09 +0200925 } else if (p->srv_act == 0) {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100926 chunk_printf(&trash,
927 "SIGHUP: Proxy %s %s ! Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
928 p->id,
929 (p->srv_bck) ? "is running on backup servers" : "has no server available",
930 p->feconn, p->beconn, p->totpend, p->nbpend, p->fe_counters.cum_conn, p->be_counters.cum_conn);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200931 } else {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100932 chunk_printf(&trash,
933 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
934 " Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
935 p->id, p->srv_act, p->srv_bck,
936 p->feconn, p->beconn, p->totpend, p->nbpend, p->fe_counters.cum_conn, p->be_counters.cum_conn);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200937 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200938 ha_warning("%s\n", trash.area);
939 send_log(p, LOG_NOTICE, "%s\n", trash.area);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200940
941 p = p->next;
942 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200943}
944
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100945static void dump(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200946{
Willy Tarreauc6ca1a02007-05-13 19:43:47 +0200947 /* dump memory usage then free everything possible */
948 dump_pools();
Willy Tarreaubafbe012017-11-24 17:34:44 +0100949 pool_gc(NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200950}
951
William Lallemande1340412017-12-28 16:09:36 +0100952/*
953 * This function dup2 the stdio FDs (0,1,2) with <fd>, then closes <fd>
954 * If <fd> < 0, it opens /dev/null and use it to dup
955 *
956 * In the case of chrooting, you have to open /dev/null before the chroot, and
957 * pass the <fd> to this function
958 */
959static void stdio_quiet(int fd)
960{
961 if (fd < 0)
962 fd = open("/dev/null", O_RDWR, 0);
963
964 if (fd > -1) {
965 fclose(stdin);
966 fclose(stdout);
967 fclose(stderr);
968
969 dup2(fd, 0);
970 dup2(fd, 1);
971 dup2(fd, 2);
972 if (fd > 2)
973 close(fd);
974 return;
975 }
976
977 ha_alert("Cannot open /dev/null\n");
978 exit(EXIT_FAILURE);
979}
980
981
Joseph Herlant03420902018-11-15 10:41:50 -0800982/* This function checks if cfg_cfgfiles contains directories.
983 * If it finds one, it adds all the files (and only files) it contains
984 * in cfg_cfgfiles in place of the directory (and removes the directory).
985 * It adds the files in lexical order.
986 * It adds only files with .cfg extension.
Maxime de Roucy379d9c72016-05-13 23:52:56 +0200987 * It doesn't add files with name starting with '.'
988 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100989static void cfgfiles_expand_directories(void)
Maxime de Roucy379d9c72016-05-13 23:52:56 +0200990{
991 struct wordlist *wl, *wlb;
992 char *err = NULL;
993
994 list_for_each_entry_safe(wl, wlb, &cfg_cfgfiles, list) {
995 struct stat file_stat;
996 struct dirent **dir_entries = NULL;
997 int dir_entries_nb;
998 int dir_entries_it;
999
1000 if (stat(wl->s, &file_stat)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001001 ha_alert("Cannot open configuration file/directory %s : %s\n",
1002 wl->s,
1003 strerror(errno));
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001004 exit(1);
1005 }
1006
1007 if (!S_ISDIR(file_stat.st_mode))
1008 continue;
1009
1010 /* from this point wl->s is a directory */
1011
1012 dir_entries_nb = scandir(wl->s, &dir_entries, NULL, alphasort);
1013 if (dir_entries_nb < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001014 ha_alert("Cannot open configuration directory %s : %s\n",
1015 wl->s,
1016 strerror(errno));
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001017 exit(1);
1018 }
1019
1020 /* for each element in the directory wl->s */
1021 for (dir_entries_it = 0; dir_entries_it < dir_entries_nb; dir_entries_it++) {
1022 struct dirent *dir_entry = dir_entries[dir_entries_it];
1023 char *filename = NULL;
1024 char *d_name_cfgext = strstr(dir_entry->d_name, ".cfg");
1025
1026 /* don't add filename that begin with .
Joseph Herlant03420902018-11-15 10:41:50 -08001027 * only add filename with .cfg extension
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001028 */
1029 if (dir_entry->d_name[0] == '.' ||
1030 !(d_name_cfgext && d_name_cfgext[4] == '\0'))
1031 goto next_dir_entry;
1032
1033 if (!memprintf(&filename, "%s/%s", wl->s, dir_entry->d_name)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001034 ha_alert("Cannot load configuration files %s : out of memory.\n",
1035 filename);
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001036 exit(1);
1037 }
1038
1039 if (stat(filename, &file_stat)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001040 ha_alert("Cannot open configuration file %s : %s\n",
1041 wl->s,
1042 strerror(errno));
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001043 exit(1);
1044 }
1045
1046 /* don't add anything else than regular file in cfg_cfgfiles
1047 * this way we avoid loops
1048 */
1049 if (!S_ISREG(file_stat.st_mode))
1050 goto next_dir_entry;
1051
1052 if (!list_append_word(&wl->list, filename, &err)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001053 ha_alert("Cannot load configuration files %s : %s\n",
1054 filename,
1055 err);
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001056 exit(1);
1057 }
1058
1059next_dir_entry:
1060 free(filename);
1061 free(dir_entry);
1062 }
1063
1064 free(dir_entries);
1065
1066 /* remove the current directory (wl) from cfg_cfgfiles */
1067 free(wl->s);
Willy Tarreau2b718102021-04-21 07:32:39 +02001068 LIST_DELETE(&wl->list);
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001069 free(wl);
1070 }
1071
1072 free(err);
1073}
1074
Willy Tarreaubaaee002006-06-26 02:48:02 +02001075/*
William Lallemand73b85e72017-06-01 17:38:51 +02001076 * copy and cleanup the current argv
William Lallemanddf6c5a82020-06-04 17:40:23 +02001077 * Remove the -sf /-st / -x parameters
William Lallemand73b85e72017-06-01 17:38:51 +02001078 * Return an allocated copy of argv
1079 */
1080
1081static char **copy_argv(int argc, char **argv)
1082{
William Lallemanddf6c5a82020-06-04 17:40:23 +02001083 char **newargv, **retargv;
William Lallemand73b85e72017-06-01 17:38:51 +02001084
Tim Duesterhuse52b6e52020-09-12 20:26:43 +02001085 newargv = calloc(argc + 2, sizeof(*newargv));
William Lallemand73b85e72017-06-01 17:38:51 +02001086 if (newargv == NULL) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001087 ha_warning("Cannot allocate memory\n");
William Lallemand73b85e72017-06-01 17:38:51 +02001088 return NULL;
1089 }
William Lallemanddf6c5a82020-06-04 17:40:23 +02001090 retargv = newargv;
William Lallemand73b85e72017-06-01 17:38:51 +02001091
William Lallemanddf6c5a82020-06-04 17:40:23 +02001092 /* first copy argv[0] */
1093 *newargv++ = *argv++;
1094 argc--;
1095
1096 while (argc > 0) {
1097 if (**argv != '-') {
1098 /* non options are copied but will fail in the argument parser */
1099 *newargv++ = *argv++;
1100 argc--;
1101
1102 } else {
1103 char *flag;
1104
1105 flag = *argv + 1;
1106
1107 if (flag[0] == '-' && flag[1] == 0) {
1108 /* "--\0" copy every arguments till the end of argv */
1109 *newargv++ = *argv++;
1110 argc--;
1111
1112 while (argc > 0) {
1113 *newargv++ = *argv++;
1114 argc--;
1115 }
1116 } else {
1117 switch (*flag) {
1118 case 's':
1119 /* -sf / -st and their parameters are ignored */
1120 if (flag[1] == 'f' || flag[1] == 't') {
1121 argc--;
1122 argv++;
1123 /* The list can't contain a negative value since the only
1124 way to know the end of this list is by looking for the
1125 next option or the end of the options */
1126 while (argc > 0 && argv[0][0] != '-') {
1127 argc--;
1128 argv++;
1129 }
William Lallemand398da622020-09-02 16:12:23 +02001130 } else {
1131 argc--;
1132 argv++;
1133
William Lallemanddf6c5a82020-06-04 17:40:23 +02001134 }
1135 break;
1136
1137 case 'x':
1138 /* this option and its parameter are ignored */
1139 argc--;
1140 argv++;
1141 if (argc > 0) {
1142 argc--;
1143 argv++;
1144 }
1145 break;
1146
1147 case 'C':
1148 case 'n':
1149 case 'm':
1150 case 'N':
1151 case 'L':
1152 case 'f':
1153 case 'p':
1154 case 'S':
1155 /* these options have only 1 parameter which must be copied and can start with a '-' */
1156 *newargv++ = *argv++;
1157 argc--;
1158 if (argc == 0)
1159 goto error;
1160 *newargv++ = *argv++;
1161 argc--;
1162 break;
1163 default:
1164 /* for other options just copy them without parameters, this is also done
1165 * for options like "--foo", but this will fail in the argument parser.
1166 * */
1167 *newargv++ = *argv++;
1168 argc--;
1169 break;
1170 }
William Lallemand73b85e72017-06-01 17:38:51 +02001171 }
1172 }
William Lallemand73b85e72017-06-01 17:38:51 +02001173 }
William Lallemand2bf6d622017-06-20 11:20:23 +02001174
William Lallemanddf6c5a82020-06-04 17:40:23 +02001175 return retargv;
1176
1177error:
1178 free(retargv);
1179 return NULL;
William Lallemand73b85e72017-06-01 17:38:51 +02001180}
1181
Willy Tarreau6c3a6812020-03-06 18:57:15 +01001182
1183/* Performs basic random seed initialization. The main issue with this is that
1184 * srandom_r() only takes 32 bits and purposely provides a reproducible sequence,
1185 * which means that there will only be 4 billion possible random sequences once
1186 * srandom() is called, regardless of the internal state. Not calling it is
1187 * even worse as we'll always produce the same randoms sequences. What we do
1188 * here is to create an initial sequence from various entropy sources, hash it
1189 * using SHA1 and keep the resulting 160 bits available globally.
1190 *
1191 * We initialize the current process with the first 32 bits before starting the
1192 * polling loop, where all this will be changed to have process specific and
1193 * thread specific sequences.
Willy Tarreau52bf8392020-03-08 00:42:37 +01001194 *
1195 * Before starting threads, it's still possible to call random() as srandom()
1196 * is initialized from this, but after threads and/or processes are started,
1197 * only ha_random() is expected to be used to guarantee distinct sequences.
Willy Tarreau6c3a6812020-03-06 18:57:15 +01001198 */
1199static void ha_random_boot(char *const *argv)
1200{
1201 unsigned char message[256];
1202 unsigned char *m = message;
1203 struct timeval tv;
1204 blk_SHA_CTX ctx;
1205 unsigned long l;
1206 int fd;
1207 int i;
1208
1209 /* start with current time as pseudo-random seed */
1210 gettimeofday(&tv, NULL);
1211 write_u32(m, tv.tv_sec); m += 4;
1212 write_u32(m, tv.tv_usec); m += 4;
1213
1214 /* PID and PPID add some OS-based randomness */
1215 write_u16(m, getpid()); m += 2;
1216 write_u16(m, getppid()); m += 2;
1217
1218 /* take up to 160 bits bytes from /dev/urandom if available (non-blocking) */
1219 fd = open("/dev/urandom", O_RDONLY);
1220 if (fd >= 0) {
1221 i = read(fd, m, 20);
1222 if (i > 0)
1223 m += i;
1224 close(fd);
1225 }
1226
1227 /* take up to 160 bits bytes from openssl (non-blocking) */
1228#ifdef USE_OPENSSL
1229 if (RAND_bytes(m, 20) == 1)
1230 m += 20;
1231#endif
1232
1233 /* take 160 bits from existing random in case it was already initialized */
1234 for (i = 0; i < 5; i++) {
1235 write_u32(m, random());
1236 m += 4;
1237 }
1238
1239 /* stack address (benefit form operating system's ASLR) */
1240 l = (unsigned long)&m;
1241 memcpy(m, &l, sizeof(l)); m += sizeof(l);
1242
1243 /* argv address (benefit form operating system's ASLR) */
1244 l = (unsigned long)&argv;
1245 memcpy(m, &l, sizeof(l)); m += sizeof(l);
1246
1247 /* use tv_usec again after all the operations above */
1248 gettimeofday(&tv, NULL);
1249 write_u32(m, tv.tv_usec); m += 4;
1250
1251 /*
1252 * At this point, ~84-92 bytes have been used
1253 */
1254
1255 /* finish with the hostname */
1256 strncpy((char *)m, hostname, message + sizeof(message) - m);
1257 m += strlen(hostname);
1258
1259 /* total message length */
1260 l = m - message;
1261
1262 memset(&ctx, 0, sizeof(ctx));
1263 blk_SHA1_Init(&ctx);
1264 blk_SHA1_Update(&ctx, message, l);
1265 blk_SHA1_Final(boot_seed, &ctx);
1266
1267 srandom(read_u32(boot_seed));
Willy Tarreau52bf8392020-03-08 00:42:37 +01001268 ha_random_seed(boot_seed, sizeof(boot_seed));
Willy Tarreau6c3a6812020-03-06 18:57:15 +01001269}
1270
Willy Tarreau5a023f02019-03-01 14:19:31 +01001271/* considers splicing proxies' maxconn, computes the ideal global.maxpipes
1272 * setting, and returns it. It may return -1 meaning "unlimited" if some
1273 * unlimited proxies have been found and the global.maxconn value is not yet
1274 * set. It may also return a value greater than maxconn if it's not yet set.
1275 * Note that a value of zero means there is no need for pipes. -1 is never
1276 * returned if global.maxconn is valid.
1277 */
1278static int compute_ideal_maxpipes()
1279{
1280 struct proxy *cur;
1281 int nbfe = 0, nbbe = 0;
1282 int unlimited = 0;
1283 int pipes;
1284 int max;
1285
1286 for (cur = proxies_list; cur; cur = cur->next) {
1287 if (cur->options2 & (PR_O2_SPLIC_ANY)) {
1288 if (cur->cap & PR_CAP_FE) {
1289 max = cur->maxconn;
1290 nbfe += max;
1291 if (!max) {
1292 unlimited = 1;
1293 break;
1294 }
1295 }
1296 if (cur->cap & PR_CAP_BE) {
1297 max = cur->fullconn ? cur->fullconn : global.maxconn;
1298 nbbe += max;
1299 if (!max) {
1300 unlimited = 1;
1301 break;
1302 }
1303 }
1304 }
1305 }
1306
1307 pipes = MAX(nbfe, nbbe);
1308 if (global.maxconn) {
1309 if (pipes > global.maxconn || unlimited)
1310 pipes = global.maxconn;
1311 } else if (unlimited) {
1312 pipes = -1;
1313 }
1314
1315 return pipes >= 4 ? pipes / 4 : pipes;
1316}
1317
Willy Tarreauac350932019-03-01 15:43:14 +01001318/* considers global.maxsocks, global.maxpipes, async engines, SSL frontends and
1319 * rlimits and computes an ideal maxconn. It's meant to be called only when
1320 * maxsock contains the sum of listening FDs, before it is updated based on
Willy Tarreaudf23c0c2019-03-13 10:10:49 +01001321 * maxconn and pipes. If there are not enough FDs left, DEFAULT_MAXCONN (by
1322 * default 100) is returned as it is expected that it will even run on tight
1323 * environments, and will maintain compatibility with previous packages that
1324 * used to rely on this value as the default one. The system will emit a
1325 * warning indicating how many FDs are missing anyway if needed.
Willy Tarreauac350932019-03-01 15:43:14 +01001326 */
1327static int compute_ideal_maxconn()
1328{
1329 int ssl_sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
1330 int engine_fds = global.ssl_used_async_engines * ssl_sides;
1331 int pipes = compute_ideal_maxpipes();
Willy Tarreaub1beaa32020-03-06 10:25:31 +01001332 int remain = MAX(rlim_fd_cur_at_boot, rlim_fd_max_at_boot);
Willy Tarreauac350932019-03-01 15:43:14 +01001333 int maxconn;
1334
1335 /* we have to take into account these elements :
1336 * - number of engine_fds, which inflates the number of FD needed per
1337 * connection by this number.
1338 * - number of pipes per connection on average : for the unlimited
1339 * case, this is 0.5 pipe FDs per connection, otherwise it's a
1340 * fixed value of 2*pipes.
1341 * - two FDs per connection
1342 */
1343
1344 /* subtract listeners and checks */
1345 remain -= global.maxsock;
1346
Willy Tarreau3f200852019-03-14 19:13:17 +01001347 /* one epoll_fd/kqueue_fd per thread */
1348 remain -= global.nbthread;
1349
1350 /* one wake-up pipe (2 fd) per thread */
1351 remain -= 2 * global.nbthread;
1352
Willy Tarreauac350932019-03-01 15:43:14 +01001353 /* Fixed pipes values : we only subtract them if they're not larger
1354 * than the remaining FDs because pipes are optional.
1355 */
1356 if (pipes >= 0 && pipes * 2 < remain)
1357 remain -= pipes * 2;
1358
1359 if (pipes < 0) {
1360 /* maxsock = maxconn * 2 + maxconn/4 * 2 + maxconn * engine_fds.
1361 * = maxconn * (2 + 0.5 + engine_fds)
1362 * = maxconn * (4 + 1 + 2*engine_fds) / 2
1363 */
1364 maxconn = 2 * remain / (5 + 2 * engine_fds);
1365 } else {
1366 /* maxsock = maxconn * 2 + maxconn * engine_fds.
1367 * = maxconn * (2 + engine_fds)
1368 */
1369 maxconn = remain / (2 + engine_fds);
1370 }
1371
Willy Tarreaudf23c0c2019-03-13 10:10:49 +01001372 return MAX(maxconn, DEFAULT_MAXCONN);
Willy Tarreauac350932019-03-01 15:43:14 +01001373}
1374
Willy Tarreaua409f302020-03-10 17:08:53 +01001375/* computes the estimated maxsock value for the given maxconn based on the
1376 * possibly set global.maxpipes and existing partial global.maxsock. It may
1377 * temporarily change global.maxconn for the time needed to propagate the
1378 * computations, and will reset it.
1379 */
1380static int compute_ideal_maxsock(int maxconn)
1381{
1382 int maxpipes = global.maxpipes;
1383 int maxsock = global.maxsock;
1384
1385
1386 if (!maxpipes) {
1387 int old_maxconn = global.maxconn;
1388
1389 global.maxconn = maxconn;
1390 maxpipes = compute_ideal_maxpipes();
1391 global.maxconn = old_maxconn;
1392 }
1393
1394 maxsock += maxconn * 2; /* each connection needs two sockets */
1395 maxsock += maxpipes * 2; /* each pipe needs two FDs */
1396 maxsock += global.nbthread; /* one epoll_fd/kqueue_fd per thread */
1397 maxsock += 2 * global.nbthread; /* one wake-up pipe (2 fd) per thread */
1398
1399 /* compute fd used by async engines */
1400 if (global.ssl_used_async_engines) {
1401 int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
1402
1403 maxsock += maxconn * sides * global.ssl_used_async_engines;
1404 }
1405 return maxsock;
1406}
1407
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07001408/* Tests if it is possible to set the current process's RLIMIT_NOFILE to
Willy Tarreau304e17e2020-03-10 17:54:54 +01001409 * <maxsock>, then sets it back to the previous value. Returns non-zero if the
1410 * value is accepted, non-zero otherwise. This is used to determine if an
1411 * automatic limit may be applied or not. When it is not, the caller knows that
1412 * the highest we can do is the rlim_max at boot. In case of error, we return
1413 * that the setting is possible, so that we defer the error processing to the
1414 * final stage in charge of enforcing this.
1415 */
1416static int check_if_maxsock_permitted(int maxsock)
1417{
1418 struct rlimit orig_limit, test_limit;
1419 int ret;
1420
1421 if (getrlimit(RLIMIT_NOFILE, &orig_limit) != 0)
1422 return 1;
1423
1424 /* don't go further if we can't even set to what we have */
1425 if (setrlimit(RLIMIT_NOFILE, &orig_limit) != 0)
1426 return 1;
1427
1428 test_limit.rlim_max = MAX(maxsock, orig_limit.rlim_max);
1429 test_limit.rlim_cur = test_limit.rlim_max;
1430 ret = setrlimit(RLIMIT_NOFILE, &test_limit);
1431
1432 if (setrlimit(RLIMIT_NOFILE, &orig_limit) != 0)
1433 return 1;
1434
1435 return ret == 0;
1436}
1437
Amaury Denoyelle484454d2021-05-05 16:18:45 +02001438void mark_tainted(const enum tainted_flags flag)
1439{
1440 HA_ATOMIC_OR(&tainted, flag);
1441}
1442
1443unsigned int get_tainted()
1444{
1445 int tainted_state;
1446 HA_ATOMIC_STORE(&tainted_state, tainted);
1447 return tainted_state;
1448}
Willy Tarreau304e17e2020-03-10 17:54:54 +01001449
William Lallemand73b85e72017-06-01 17:38:51 +02001450/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001451 * This function initializes all the necessary variables. It only returns
1452 * if everything is OK. If something fails, it exits.
1453 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +01001454static void init(int argc, char **argv)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001455{
Willy Tarreaubaaee002006-06-26 02:48:02 +02001456 int arg_mode = 0; /* MODE_DEBUG, ... */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001457 char *tmp;
1458 char *cfg_pidfile = NULL;
Willy Tarreau058e9072009-07-20 09:30:05 +02001459 int err_code = 0;
Maxime de Roucy0f503922016-05-13 23:52:55 +02001460 char *err_msg = NULL;
Willy Tarreau477ecd82010-01-03 21:12:30 +01001461 struct wordlist *wl;
Kevinm48936af2010-12-22 16:08:21 +00001462 char *progname;
Willy Tarreau576132e2011-09-10 19:26:56 +02001463 char *change_dir = NULL;
Christopher Fauletd7c91962015-04-30 11:48:27 +02001464 struct proxy *px;
Willy Tarreaue6945732016-12-21 19:57:00 +01001465 struct post_check_fct *pcf;
Willy Tarreauac350932019-03-01 15:43:14 +01001466 int ideal_maxconn;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001467
Christopher Faulete3a5e352017-10-24 13:53:54 +02001468 global.mode = MODE_STARTING;
William Lallemand00417412020-06-05 14:08:41 +02001469 old_argv = copy_argv(argc, argv);
1470 if (!old_argv) {
William Lallemanddf6c5a82020-06-04 17:40:23 +02001471 ha_alert("failed to copy argv.\n");
1472 exit(1);
1473 }
William Lallemand73b85e72017-06-01 17:38:51 +02001474
Christopher Fauletcd7879a2017-10-27 13:53:47 +02001475 if (!init_trash_buffers(1)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001476 ha_alert("failed to initialize trash buffers.\n");
Christopher Faulet748919a2017-07-26 14:59:46 +02001477 exit(1);
1478 }
David du Colombier7af46052012-05-16 14:16:48 +02001479
Emeric Brun2b920a12010-09-23 18:30:22 +02001480 /* NB: POSIX does not make it mandatory for gethostname() to NULL-terminate
1481 * the string in case of truncation, and at least FreeBSD appears not to do
1482 * it.
1483 */
1484 memset(hostname, 0, sizeof(hostname));
1485 gethostname(hostname, sizeof(hostname) - 1);
Dragan Dosen4f014152020-06-18 16:56:47 +02001486
1487 if ((localpeer = strdup(hostname)) == NULL) {
1488 ha_alert("Cannot allocate memory for local peer.\n");
1489 exit(EXIT_FAILURE);
1490 }
William Lallemanddaf4cd22018-04-17 16:46:13 +02001491 setenv("HAPROXY_LOCALPEER", localpeer, 1);
Emeric Brun2b920a12010-09-23 18:30:22 +02001492
William Lallemand24c928c2020-01-14 17:58:18 +01001493 /* we were in mworker mode, we should restart in mworker mode */
1494 if (getenv("HAPROXY_MWORKER_REEXEC") != NULL)
1495 global.mode |= MODE_MWORKER;
1496
Willy Tarreaubaaee002006-06-26 02:48:02 +02001497 /*
1498 * Initialize the previously static variables.
1499 */
Christopher Fauletcd7879a2017-10-27 13:53:47 +02001500
Willy Tarreau173d9952018-01-26 21:48:23 +01001501 totalconn = actconn = listeners = stopping = 0;
Cyril Bonté203ec5a2017-03-23 22:44:13 +01001502 killed = 0;
Christopher Fauletcd7879a2017-10-27 13:53:47 +02001503
Willy Tarreaubaaee002006-06-26 02:48:02 +02001504
1505#ifdef HAPROXY_MEMMAX
Willy Tarreau70060452015-12-14 12:46:07 +01001506 global.rlimit_memmax_all = HAPROXY_MEMMAX;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001507#endif
1508
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001509 tzset();
Willy Tarreauc4c80fb2021-04-11 15:00:34 +02001510 tv_init_process_date();
Willy Tarreaubaaee002006-06-26 02:48:02 +02001511 start_date = now;
1512
Willy Tarreau6c3a6812020-03-06 18:57:15 +01001513 ha_random_boot(argv);
Willy Tarreau84310e22014-02-14 11:59:04 +01001514
Willy Tarreau8ed669b2013-01-11 15:49:37 +01001515 if (init_acl() != 0)
1516 exit(1);
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001517
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +01001518 /* Initialise lua. */
1519 hlua_init();
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +01001520
Christopher Fauletff2613e2016-11-09 11:36:17 +01001521 /* Initialize process vars */
Willy Tarreaucfc4f242021-05-08 11:41:28 +02001522 vars_init(&proc_vars, SCOPE_PROC);
Christopher Fauletff2613e2016-11-09 11:36:17 +01001523
Willy Tarreau43b78992009-01-25 15:42:27 +01001524 global.tune.options |= GTUNE_USE_SELECT; /* select() is always available */
Willy Tarreaue5733232019-05-22 19:24:06 +02001525#if defined(USE_POLL)
Willy Tarreau43b78992009-01-25 15:42:27 +01001526 global.tune.options |= GTUNE_USE_POLL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001527#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001528#if defined(USE_EPOLL)
Willy Tarreau43b78992009-01-25 15:42:27 +01001529 global.tune.options |= GTUNE_USE_EPOLL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001530#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001531#if defined(USE_KQUEUE)
Willy Tarreau43b78992009-01-25 15:42:27 +01001532 global.tune.options |= GTUNE_USE_KQUEUE;
Willy Tarreau1e63130a2007-04-09 12:03:06 +02001533#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001534#if defined(USE_EVPORTS)
Emmanuel Hocdet0ba4f482019-04-08 16:53:32 +00001535 global.tune.options |= GTUNE_USE_EVPORTS;
1536#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001537#if defined(USE_LINUX_SPLICE)
Willy Tarreau3ab68cf2009-01-25 16:03:28 +01001538 global.tune.options |= GTUNE_USE_SPLICE;
1539#endif
Nenad Merdanovic88afe032014-04-14 15:56:58 +02001540#if defined(USE_GETADDRINFO)
1541 global.tune.options |= GTUNE_USE_GAI;
1542#endif
Lukas Tribusa0bcbdc2016-09-12 21:42:20 +00001543#if defined(SO_REUSEPORT)
1544 global.tune.options |= GTUNE_USE_REUSEPORT;
1545#endif
Willy Tarreau76cc6992020-07-01 18:49:24 +02001546#ifdef USE_THREAD
1547 global.tune.options |= GTUNE_IDLE_POOL_SHARED;
1548#endif
William Dauchya5194602020-03-28 19:29:58 +01001549 global.tune.options |= GTUNE_STRICT_LIMITS;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001550
1551 pid = getpid();
1552 progname = *argv;
1553 while ((tmp = strchr(progname, '/')) != NULL)
1554 progname = tmp + 1;
1555
Kevinm48936af2010-12-22 16:08:21 +00001556 /* the process name is used for the logs only */
Eric Salama7cea6062020-10-02 11:58:19 +02001557 chunk_initlen(&global.log_tag, strdup(progname), strlen(progname), strlen(progname));
1558 if (b_orig(&global.log_tag) == NULL) {
1559 chunk_destroy(&global.log_tag);
1560 ha_alert("Cannot allocate memory for log_tag.\n");
1561 exit(EXIT_FAILURE);
1562 }
Kevinm48936af2010-12-22 16:08:21 +00001563
Willy Tarreaubaaee002006-06-26 02:48:02 +02001564 argc--; argv++;
1565 while (argc > 0) {
1566 char *flag;
1567
1568 if (**argv == '-') {
1569 flag = *argv+1;
1570
1571 /* 1 arg */
1572 if (*flag == 'v') {
1573 display_version();
Willy Tarreau7b066db2007-12-02 11:28:59 +01001574 if (flag[1] == 'v') /* -vv */
1575 display_build_opts();
Willy Tarreaubaaee002006-06-26 02:48:02 +02001576 exit(0);
1577 }
Willy Tarreaue5733232019-05-22 19:24:06 +02001578#if defined(USE_EPOLL)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001579 else if (*flag == 'd' && flag[1] == 'e')
Willy Tarreau43b78992009-01-25 15:42:27 +01001580 global.tune.options &= ~GTUNE_USE_EPOLL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001581#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001582#if defined(USE_POLL)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001583 else if (*flag == 'd' && flag[1] == 'p')
Willy Tarreau43b78992009-01-25 15:42:27 +01001584 global.tune.options &= ~GTUNE_USE_POLL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001585#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001586#if defined(USE_KQUEUE)
Willy Tarreau1e63130a2007-04-09 12:03:06 +02001587 else if (*flag == 'd' && flag[1] == 'k')
Willy Tarreau43b78992009-01-25 15:42:27 +01001588 global.tune.options &= ~GTUNE_USE_KQUEUE;
Willy Tarreau1e63130a2007-04-09 12:03:06 +02001589#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001590#if defined(USE_EVPORTS)
Emmanuel Hocdet0ba4f482019-04-08 16:53:32 +00001591 else if (*flag == 'd' && flag[1] == 'v')
1592 global.tune.options &= ~GTUNE_USE_EVPORTS;
1593#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001594#if defined(USE_LINUX_SPLICE)
Willy Tarreau3ab68cf2009-01-25 16:03:28 +01001595 else if (*flag == 'd' && flag[1] == 'S')
1596 global.tune.options &= ~GTUNE_USE_SPLICE;
1597#endif
Nenad Merdanovic88afe032014-04-14 15:56:58 +02001598#if defined(USE_GETADDRINFO)
1599 else if (*flag == 'd' && flag[1] == 'G')
1600 global.tune.options &= ~GTUNE_USE_GAI;
1601#endif
Lukas Tribusa0bcbdc2016-09-12 21:42:20 +00001602#if defined(SO_REUSEPORT)
1603 else if (*flag == 'd' && flag[1] == 'R')
1604 global.tune.options &= ~GTUNE_USE_REUSEPORT;
1605#endif
Emeric Brun850efd52014-01-29 12:24:34 +01001606 else if (*flag == 'd' && flag[1] == 'V')
1607 global.ssl_server_verify = SSL_SERVER_VERIFY_NONE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001608 else if (*flag == 'V')
1609 arg_mode |= MODE_VERBOSE;
1610 else if (*flag == 'd' && flag[1] == 'b')
1611 arg_mode |= MODE_FOREGROUND;
Amaury Denoyelle7b01a8d2021-03-29 10:29:07 +02001612 else if (*flag == 'd' && flag[1] == 'D')
1613 arg_mode |= MODE_DIAG;
Willy Tarreau3eb10b82020-04-15 16:42:39 +02001614 else if (*flag == 'd' && flag[1] == 'W')
1615 arg_mode |= MODE_ZERO_WARNING;
Willy Tarreau6e064432012-05-08 15:40:42 +02001616 else if (*flag == 'd' && flag[1] == 'M')
1617 mem_poison_byte = flag[2] ? strtol(flag + 2, NULL, 0) : 'P';
Willy Tarreau3eed10e2016-11-07 21:03:16 +01001618 else if (*flag == 'd' && flag[1] == 'r')
1619 global.tune.options |= GTUNE_RESOLVE_DONTFAIL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001620 else if (*flag == 'd')
1621 arg_mode |= MODE_DEBUG;
1622 else if (*flag == 'c')
1623 arg_mode |= MODE_CHECK;
William Lallemand095ba4c2017-06-01 17:38:50 +02001624 else if (*flag == 'D')
Willy Tarreau6bde87b2009-05-18 16:29:51 +02001625 arg_mode |= MODE_DAEMON;
Tim Duesterhusd6942c82017-11-20 15:58:35 +01001626 else if (*flag == 'W' && flag[1] == 's') {
Lukas Tribusf46bf952017-11-21 12:39:34 +01001627 arg_mode |= MODE_MWORKER | MODE_FOREGROUND;
Tim Duesterhusd6942c82017-11-20 15:58:35 +01001628#if defined(USE_SYSTEMD)
1629 global.tune.options |= GTUNE_USE_SYSTEMD;
1630#else
Christopher Faulet767a84b2017-11-24 16:50:31 +01001631 ha_alert("master-worker mode with systemd support (-Ws) requested, but not compiled. Use master-worker mode (-W) if you are not using Type=notify in your unit file or recompile with USE_SYSTEMD=1.\n\n");
Tim Duesterhusd6942c82017-11-20 15:58:35 +01001632 usage(progname);
1633#endif
1634 }
William Lallemand095ba4c2017-06-01 17:38:50 +02001635 else if (*flag == 'W')
1636 arg_mode |= MODE_MWORKER;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001637 else if (*flag == 'q')
1638 arg_mode |= MODE_QUIET;
Olivier Houchardf73629d2017-04-05 22:33:04 +02001639 else if (*flag == 'x') {
William Lallemand4f71d302020-06-04 23:41:29 +02001640 if (argc <= 1) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001641 ha_alert("Unix socket path expected with the -x flag\n\n");
William Lallemand45eff442017-06-19 15:57:55 +02001642 usage(progname);
Olivier Houchardf73629d2017-04-05 22:33:04 +02001643 }
William Lallemand4fc09692017-06-19 16:37:19 +02001644 if (old_unixsocket)
Christopher Faulet767a84b2017-11-24 16:50:31 +01001645 ha_warning("-x option already set, overwriting the value\n");
Olivier Houchardf73629d2017-04-05 22:33:04 +02001646 old_unixsocket = argv[1];
William Lallemand4fc09692017-06-19 16:37:19 +02001647
Olivier Houchardf73629d2017-04-05 22:33:04 +02001648 argv++;
1649 argc--;
1650 }
William Lallemande7361152018-10-26 14:47:36 +02001651 else if (*flag == 'S') {
1652 struct wordlist *c;
1653
William Lallemanda6b32492020-06-04 23:49:20 +02001654 if (argc <= 1) {
William Lallemande7361152018-10-26 14:47:36 +02001655 ha_alert("Socket and optional bind parameters expected with the -S flag\n");
1656 usage(progname);
1657 }
1658 if ((c = malloc(sizeof(*c))) == NULL || (c->s = strdup(argv[1])) == NULL) {
1659 ha_alert("Cannot allocate memory\n");
1660 exit(EXIT_FAILURE);
1661 }
Willy Tarreau2b718102021-04-21 07:32:39 +02001662 LIST_INSERT(&mworker_cli_conf, &c->list);
William Lallemande7361152018-10-26 14:47:36 +02001663
1664 argv++;
1665 argc--;
1666 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001667 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
1668 /* list of pids to finish ('f') or terminate ('t') */
1669
1670 if (flag[1] == 'f')
1671 oldpids_sig = SIGUSR1; /* finish then exit */
1672 else
1673 oldpids_sig = SIGTERM; /* terminate immediately */
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001674 while (argc > 1 && argv[1][0] != '-') {
Chris Lane236062f2018-02-05 23:15:44 +00001675 char * endptr = NULL;
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001676 oldpids = realloc(oldpids, (nb_oldpids + 1) * sizeof(int));
1677 if (!oldpids) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001678 ha_alert("Cannot allocate old pid : out of memory.\n");
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001679 exit(1);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001680 }
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001681 argc--; argv++;
Chris Lane236062f2018-02-05 23:15:44 +00001682 errno = 0;
1683 oldpids[nb_oldpids] = strtol(*argv, &endptr, 10);
1684 if (errno) {
1685 ha_alert("-%2s option: failed to parse {%s}: %s\n",
1686 flag,
1687 *argv, strerror(errno));
1688 exit(1);
1689 } else if (endptr && strlen(endptr)) {
Willy Tarreau90807112020-02-25 08:16:33 +01001690 while (isspace((unsigned char)*endptr)) endptr++;
Aurélien Nephtali39b89882018-02-17 20:53:11 +01001691 if (*endptr != 0) {
Chris Lane236062f2018-02-05 23:15:44 +00001692 ha_alert("-%2s option: some bytes unconsumed in PID list {%s}\n",
1693 flag, endptr);
1694 exit(1);
Aurélien Nephtali39b89882018-02-17 20:53:11 +01001695 }
Chris Lane236062f2018-02-05 23:15:44 +00001696 }
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001697 if (oldpids[nb_oldpids] <= 0)
1698 usage(progname);
1699 nb_oldpids++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001700 }
1701 }
Willy Tarreaua088d312015-10-08 11:58:48 +02001702 else if (flag[0] == '-' && flag[1] == 0) { /* "--" */
1703 /* now that's a cfgfile list */
1704 argv++; argc--;
1705 while (argc > 0) {
Maxime de Roucy0f503922016-05-13 23:52:55 +02001706 if (!list_append_word(&cfg_cfgfiles, *argv, &err_msg)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001707 ha_alert("Cannot load configuration file/directory %s : %s\n",
1708 *argv,
1709 err_msg);
Willy Tarreaua088d312015-10-08 11:58:48 +02001710 exit(1);
1711 }
Willy Tarreaua088d312015-10-08 11:58:48 +02001712 argv++; argc--;
1713 }
1714 break;
1715 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001716 else { /* >=2 args */
1717 argv++; argc--;
1718 if (argc == 0)
Willy Tarreau3bafcdc2011-09-10 19:20:23 +02001719 usage(progname);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001720
1721 switch (*flag) {
Willy Tarreau576132e2011-09-10 19:26:56 +02001722 case 'C' : change_dir = *argv; break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001723 case 'n' : cfg_maxconn = atol(*argv); break;
Willy Tarreau70060452015-12-14 12:46:07 +01001724 case 'm' : global.rlimit_memmax_all = atol(*argv); break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001725 case 'N' : cfg_maxpconn = atol(*argv); break;
William Lallemanddaf4cd22018-04-17 16:46:13 +02001726 case 'L' :
Dragan Dosen4f014152020-06-18 16:56:47 +02001727 free(localpeer);
1728 if ((localpeer = strdup(*argv)) == NULL) {
1729 ha_alert("Cannot allocate memory for local peer.\n");
1730 exit(EXIT_FAILURE);
1731 }
William Lallemanddaf4cd22018-04-17 16:46:13 +02001732 setenv("HAPROXY_LOCALPEER", localpeer, 1);
Dragan Dosen13cd54c2020-06-18 18:24:05 +02001733 global.localpeer_cmdline = 1;
William Lallemanddaf4cd22018-04-17 16:46:13 +02001734 break;
Willy Tarreau5d01a632009-06-22 16:02:30 +02001735 case 'f' :
Maxime de Roucy0f503922016-05-13 23:52:55 +02001736 if (!list_append_word(&cfg_cfgfiles, *argv, &err_msg)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001737 ha_alert("Cannot load configuration file/directory %s : %s\n",
1738 *argv,
1739 err_msg);
Willy Tarreau5d01a632009-06-22 16:02:30 +02001740 exit(1);
1741 }
Willy Tarreau5d01a632009-06-22 16:02:30 +02001742 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001743 case 'p' : cfg_pidfile = *argv; break;
Willy Tarreau3bafcdc2011-09-10 19:20:23 +02001744 default: usage(progname);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001745 }
1746 }
1747 }
1748 else
Willy Tarreau3bafcdc2011-09-10 19:20:23 +02001749 usage(progname);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001750 argv++; argc--;
1751 }
1752
Christopher Faulete3a5e352017-10-24 13:53:54 +02001753 global.mode |= (arg_mode & (MODE_DAEMON | MODE_MWORKER | MODE_FOREGROUND | MODE_VERBOSE
Amaury Denoyelle7b01a8d2021-03-29 10:29:07 +02001754 | MODE_QUIET | MODE_CHECK | MODE_DEBUG | MODE_ZERO_WARNING
1755 | MODE_DIAG));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001756
William Lallemand944e6192018-11-21 15:48:31 +01001757 if (getenv("HAPROXY_MWORKER_WAIT_ONLY")) {
William Lallemandcb11fd22017-06-01 17:38:52 +02001758 unsetenv("HAPROXY_MWORKER_WAIT_ONLY");
William Lallemand944e6192018-11-21 15:48:31 +01001759 global.mode |= MODE_MWORKER_WAIT;
1760 global.mode &= ~MODE_MWORKER;
William Lallemandcb11fd22017-06-01 17:38:52 +02001761 }
1762
Willy Tarreau7a534eb2021-07-21 10:01:36 +02001763 if ((global.mode & (MODE_MWORKER | MODE_CHECK)) == MODE_MWORKER &&
1764 (getenv("HAPROXY_MWORKER_REEXEC") != NULL)) {
William Lallemandcb11fd22017-06-01 17:38:52 +02001765 atexit_flag = 1;
1766 atexit(reexec_on_failure);
1767 }
1768
Willy Tarreau576132e2011-09-10 19:26:56 +02001769 if (change_dir && chdir(change_dir) < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001770 ha_alert("Could not change to directory %s : %s\n", change_dir, strerror(errno));
Willy Tarreau576132e2011-09-10 19:26:56 +02001771 exit(1);
1772 }
1773
Willy Tarreaubaaee002006-06-26 02:48:02 +02001774 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
Willy Tarreau915e1eb2009-06-22 15:48:36 +02001775
Amaury Denoyellea6f9c5d2021-04-23 16:58:08 +02001776#ifdef USE_CPU_AFFINITY
1777 {
1778 int i;
1779 for (i = 0; i < MAX_PROCS; ++i) {
Amaury Denoyellefc6ac532021-04-27 10:46:36 +02001780 ha_cpuset_zero(&cpu_map.proc[i]);
1781 ha_cpuset_zero(&cpu_map.proc_t1[i]);
Willy Tarreau26f42a02021-05-14 08:26:38 +02001782 }
1783 for (i = 0; i < MAX_THREADS; ++i) {
Amaury Denoyellefc6ac532021-04-27 10:46:36 +02001784 ha_cpuset_zero(&cpu_map.thread[i]);
Amaury Denoyellea6f9c5d2021-04-23 16:58:08 +02001785 }
Amaury Denoyelle982fb532021-04-21 18:39:58 +02001786 }
Amaury Denoyellea6f9c5d2021-04-23 16:58:08 +02001787#endif
Amaury Denoyelle982fb532021-04-21 18:39:58 +02001788
William Lallemand944e6192018-11-21 15:48:31 +01001789 /* in wait mode, we don't try to read the configuration files */
1790 if (!(global.mode & MODE_MWORKER_WAIT)) {
Christopher Faulet4e366822021-01-12 18:57:38 +01001791 char *env_cfgfiles = NULL;
1792 int env_err = 0;
Willy Tarreauc4382422009-12-06 13:10:44 +01001793
William Lallemand944e6192018-11-21 15:48:31 +01001794 /* handle cfgfiles that are actually directories */
1795 cfgfiles_expand_directories();
1796
1797 if (LIST_ISEMPTY(&cfg_cfgfiles))
1798 usage(progname);
1799
1800
1801 list_for_each_entry(wl, &cfg_cfgfiles, list) {
1802 int ret;
1803
Christopher Faulet4e366822021-01-12 18:57:38 +01001804 if (env_err == 0) {
1805 if (!memprintf(&env_cfgfiles, "%s%s%s",
1806 (env_cfgfiles ? env_cfgfiles : ""),
1807 (env_cfgfiles ? ";" : ""), wl->s))
1808 env_err = 1;
1809 }
William Lallemand7b302d82019-05-20 11:15:37 +02001810
William Lallemand944e6192018-11-21 15:48:31 +01001811 ret = readcfgfile(wl->s);
1812 if (ret == -1) {
1813 ha_alert("Could not open configuration file %s : %s\n",
1814 wl->s, strerror(errno));
Christopher Faulet4e366822021-01-12 18:57:38 +01001815 free(env_cfgfiles);
William Lallemand944e6192018-11-21 15:48:31 +01001816 exit(1);
1817 }
1818 if (ret & (ERR_ABORT|ERR_FATAL))
1819 ha_alert("Error(s) found in configuration file : %s\n", wl->s);
1820 err_code |= ret;
Christopher Faulet4e366822021-01-12 18:57:38 +01001821 if (err_code & ERR_ABORT) {
1822 free(env_cfgfiles);
William Lallemand944e6192018-11-21 15:48:31 +01001823 exit(1);
Christopher Faulet4e366822021-01-12 18:57:38 +01001824 }
Willy Tarreauc4382422009-12-06 13:10:44 +01001825 }
Krzysztof Oledzkib304dc72007-10-14 23:40:01 +02001826
William Lallemand944e6192018-11-21 15:48:31 +01001827 /* do not try to resolve arguments nor to spot inconsistencies when
1828 * the configuration contains fatal errors caused by files not found
1829 * or failed memory allocations.
1830 */
1831 if (err_code & (ERR_ABORT|ERR_FATAL)) {
1832 ha_alert("Fatal errors found in configuration.\n");
Christopher Faulet4e366822021-01-12 18:57:38 +01001833 free(env_cfgfiles);
William Lallemand944e6192018-11-21 15:48:31 +01001834 exit(1);
1835 }
Christopher Faulet4e366822021-01-12 18:57:38 +01001836 if (env_err) {
1837 ha_alert("Could not allocate memory for HAPROXY_CFGFILES env variable\n");
1838 exit(1);
1839 }
1840 setenv("HAPROXY_CFGFILES", env_cfgfiles, 1);
1841 free(env_cfgfiles);
William Lallemand7b302d82019-05-20 11:15:37 +02001842
Willy Tarreaub83dc3d2017-04-19 11:24:07 +02001843 }
William Lallemandce83b4a2018-10-26 14:47:30 +02001844 if (global.mode & MODE_MWORKER) {
1845 int proc;
William Lallemand16dd1b32018-11-19 18:46:18 +01001846 struct mworker_proc *tmproc;
1847
William Lallemand482f9a92019-04-12 16:15:00 +02001848 setenv("HAPROXY_MWORKER", "1", 1);
1849
William Lallemand16dd1b32018-11-19 18:46:18 +01001850 if (getenv("HAPROXY_MWORKER_REEXEC") == NULL) {
1851
William Lallemandf3a86832019-04-01 11:29:58 +02001852 tmproc = calloc(1, sizeof(*tmproc));
William Lallemand16dd1b32018-11-19 18:46:18 +01001853 if (!tmproc) {
1854 ha_alert("Cannot allocate process structures.\n");
1855 exit(EXIT_FAILURE);
1856 }
William Lallemand8f7069a2019-04-12 16:09:23 +02001857 tmproc->options |= PROC_O_TYPE_MASTER; /* master */
William Lallemand16dd1b32018-11-19 18:46:18 +01001858 tmproc->reloads = 0;
1859 tmproc->relative_pid = 0;
1860 tmproc->pid = pid;
1861 tmproc->timestamp = start_date.tv_sec;
1862 tmproc->ipc_fd[0] = -1;
1863 tmproc->ipc_fd[1] = -1;
1864
1865 proc_self = tmproc;
1866
Willy Tarreau2b718102021-04-21 07:32:39 +02001867 LIST_APPEND(&proc_list, &tmproc->list);
William Lallemand16dd1b32018-11-19 18:46:18 +01001868 }
William Lallemandce83b4a2018-10-26 14:47:30 +02001869
1870 for (proc = 0; proc < global.nbproc; proc++) {
William Lallemandce83b4a2018-10-26 14:47:30 +02001871
William Lallemandf3a86832019-04-01 11:29:58 +02001872 tmproc = calloc(1, sizeof(*tmproc));
William Lallemandce83b4a2018-10-26 14:47:30 +02001873 if (!tmproc) {
1874 ha_alert("Cannot allocate process structures.\n");
1875 exit(EXIT_FAILURE);
1876 }
1877
William Lallemand8f7069a2019-04-12 16:09:23 +02001878 tmproc->options |= PROC_O_TYPE_WORKER; /* worker */
William Lallemandce83b4a2018-10-26 14:47:30 +02001879 tmproc->pid = -1;
1880 tmproc->reloads = 0;
William Lallemande3683302018-11-19 18:46:17 +01001881 tmproc->timestamp = -1;
William Lallemandce83b4a2018-10-26 14:47:30 +02001882 tmproc->relative_pid = 1 + proc;
William Lallemand550db6d2018-11-06 17:37:12 +01001883 tmproc->ipc_fd[0] = -1;
1884 tmproc->ipc_fd[1] = -1;
William Lallemandce83b4a2018-10-26 14:47:30 +02001885
1886 if (mworker_cli_sockpair_new(tmproc, proc) < 0) {
1887 exit(EXIT_FAILURE);
1888 }
1889
Willy Tarreau2b718102021-04-21 07:32:39 +02001890 LIST_APPEND(&proc_list, &tmproc->list);
William Lallemandce83b4a2018-10-26 14:47:30 +02001891 }
William Lallemand944e6192018-11-21 15:48:31 +01001892 }
1893 if (global.mode & (MODE_MWORKER|MODE_MWORKER_WAIT)) {
1894 struct wordlist *it, *c;
1895
Remi Tricot-Le Bretond90aa342021-05-19 10:45:12 +02001896 /* get the info of the children in the env */
1897 if (mworker_env_to_proc_list() < 0) {
1898 exit(EXIT_FAILURE);
1899 }
William Lallemande7361152018-10-26 14:47:36 +02001900
William Lallemand550db6d2018-11-06 17:37:12 +01001901 if (!LIST_ISEMPTY(&mworker_cli_conf)) {
William Lallemande7361152018-10-26 14:47:36 +02001902
William Lallemand550db6d2018-11-06 17:37:12 +01001903 if (mworker_cli_proxy_create() < 0) {
William Lallemande7361152018-10-26 14:47:36 +02001904 ha_alert("Can't create the master's CLI.\n");
1905 exit(EXIT_FAILURE);
1906 }
William Lallemande7361152018-10-26 14:47:36 +02001907
William Lallemand550db6d2018-11-06 17:37:12 +01001908 list_for_each_entry_safe(c, it, &mworker_cli_conf, list) {
1909
1910 if (mworker_cli_proxy_new_listener(c->s) < 0) {
1911 ha_alert("Can't create the master's CLI.\n");
1912 exit(EXIT_FAILURE);
1913 }
Willy Tarreau2b718102021-04-21 07:32:39 +02001914 LIST_DELETE(&c->list);
William Lallemand550db6d2018-11-06 17:37:12 +01001915 free(c->s);
1916 free(c);
1917 }
1918 }
William Lallemandce83b4a2018-10-26 14:47:30 +02001919 }
1920
Eric Salama5ba83352021-03-16 15:11:17 +01001921 if (!LIST_ISEMPTY(&mworker_cli_conf) && !(arg_mode & MODE_MWORKER)) {
1922 ha_warning("a master CLI socket was defined, but master-worker mode (-W) is not enabled.\n");
1923 }
1924
Willy Tarreauf42d7942020-10-20 11:54:49 +02001925 if (global.nbproc > 1 && !global.nbthread) {
1926 ha_warning("nbproc is deprecated!\n"
1927 " | For suffering many limitations, the 'nbproc' directive is now deprecated\n"
1928 " | and scheduled for removal in 2.5. Just comment it out: haproxy will use\n"
1929 " | threads and will run on all allocated processors. You may also switch to\n"
1930 " | 'nbthread %d' to keep the same number of processors. If you absolutely\n"
1931 " | want to run in multi-process mode, you can silence this warning by adding\n"
1932 " | 'nbthread 1', but then please report your use case to developers.\n",
1933 global.nbproc);
1934 }
1935
Willy Tarreaue90904d2021-02-12 14:08:31 +01001936 /* defaults sections are not needed anymore */
1937 proxy_destroy_all_defaults();
1938
Willy Tarreaubb925012009-07-23 13:36:36 +02001939 err_code |= check_config_validity();
Christopher Fauletc1692962019-08-12 09:51:07 +02001940 for (px = proxies_list; px; px = px->next) {
1941 struct server *srv;
1942 struct post_proxy_check_fct *ppcf;
1943 struct post_server_check_fct *pscf;
1944
Christopher Fauletd5bd8242020-11-02 16:20:13 +01001945 if (px->disabled)
1946 continue;
1947
Christopher Fauletc1692962019-08-12 09:51:07 +02001948 list_for_each_entry(pscf, &post_server_check_list, list) {
1949 for (srv = px->srv; srv; srv = srv->next)
1950 err_code |= pscf->fct(srv);
1951 }
1952 list_for_each_entry(ppcf, &post_proxy_check_list, list)
1953 err_code |= ppcf->fct(px);
1954 }
Willy Tarreaubb925012009-07-23 13:36:36 +02001955 if (err_code & (ERR_ABORT|ERR_FATAL)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001956 ha_alert("Fatal errors found in configuration.\n");
Willy Tarreau915e1eb2009-06-22 15:48:36 +02001957 exit(1);
1958 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001959
Carl Henrik Lundef91ac192020-02-27 16:45:50 +01001960 err_code |= pattern_finalize_config();
1961 if (err_code & (ERR_ABORT|ERR_FATAL)) {
1962 ha_alert("Failed to finalize pattern config.\n");
1963 exit(1);
1964 }
Willy Tarreau0f936722019-04-11 14:47:08 +02001965
Willy Tarreau70060452015-12-14 12:46:07 +01001966 /* recompute the amount of per-process memory depending on nbproc and
1967 * the shared SSL cache size (allowed to exist in all processes).
1968 */
1969 if (global.rlimit_memmax_all) {
1970#if defined (USE_OPENSSL) && !defined(USE_PRIVATE_CACHE)
1971 int64_t ssl_cache_bytes = global.tune.sslcachesize * 200LL;
1972
1973 global.rlimit_memmax =
1974 ((((int64_t)global.rlimit_memmax_all * 1048576LL) -
1975 ssl_cache_bytes) / global.nbproc +
1976 ssl_cache_bytes + 1048575LL) / 1048576LL;
1977#else
1978 global.rlimit_memmax = global.rlimit_memmax_all / global.nbproc;
1979#endif
1980 }
1981
Willy Tarreaue5733232019-05-22 19:24:06 +02001982#ifdef USE_NS
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01001983 err_code |= netns_init();
1984 if (err_code & (ERR_ABORT|ERR_FATAL)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001985 ha_alert("Failed to initialize namespace support.\n");
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01001986 exit(1);
1987 }
1988#endif
1989
Baptiste Assmann4215d7d2016-11-02 15:33:15 +01001990 /* Apply server states */
1991 apply_server_state();
1992
Olivier Houchardfbc74e82017-11-24 16:54:05 +01001993 for (px = proxies_list; px; px = px->next)
Baptiste Assmann4215d7d2016-11-02 15:33:15 +01001994 srv_compute_all_admin_states(px);
1995
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01001996 /* Apply servers' configured address */
1997 err_code |= srv_init_addr();
1998 if (err_code & (ERR_ABORT|ERR_FATAL)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001999 ha_alert("Failed to initialize server(s) addr.\n");
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01002000 exit(1);
2001 }
2002
Willy Tarreau3eb10b82020-04-15 16:42:39 +02002003 if (warned & WARN_ANY && global.mode & MODE_ZERO_WARNING) {
2004 ha_alert("Some warnings were found and 'zero-warning' is set. Aborting.\n");
2005 exit(1);
2006 }
2007
Willy Tarreaubaaee002006-06-26 02:48:02 +02002008 if (global.mode & MODE_CHECK) {
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002009 struct peers *pr;
2010 struct proxy *px;
2011
Willy Tarreaubebd2122020-04-15 16:06:11 +02002012 if (warned & WARN_ANY)
2013 qfprintf(stdout, "Warnings were found.\n");
2014
Frédéric Lécailleed2b4a62017-07-13 09:07:09 +02002015 for (pr = cfg_peers; pr; pr = pr->next)
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002016 if (pr->peers_fe)
2017 break;
2018
Olivier Houchardfbc74e82017-11-24 16:54:05 +01002019 for (px = proxies_list; px; px = px->next)
Willy Tarreauc3914d42020-09-24 08:39:22 +02002020 if (!px->disabled && px->li_all)
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002021 break;
2022
Emeric Brun3a9c0002021-08-13 09:32:50 +02002023 if (!px) {
2024 /* We may only have log-forward section */
2025 for (px = cfg_log_forward; px; px = px->next)
2026 if (!px->disabled && px->li_all)
2027 break;
2028 }
2029
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002030 if (pr || px) {
2031 /* At least one peer or one listener has been found */
2032 qfprintf(stdout, "Configuration file is valid\n");
Tim Duesterhus0a3b43d2020-06-14 00:37:42 +02002033 deinit_and_exit(0);
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002034 }
2035 qfprintf(stdout, "Configuration file has no error but will not start (no listener) => exit(2).\n");
2036 exit(2);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002037 }
Willy Tarreaue9b26022011-08-01 20:57:55 +02002038
Amaury Denoyelle5a6926d2021-03-30 17:34:24 +02002039 if (global.mode & MODE_DIAG) {
2040 cfg_run_diagnostics();
2041 }
2042
Willy Tarreau8263d2b2012-08-28 00:06:31 +02002043 /* now we know the buffer size, we can initialize the channels and buffers */
Willy Tarreau9b28e032012-10-12 23:49:43 +02002044 init_buffer();
Willy Tarreau8280d642009-09-23 23:37:52 +02002045
Willy Tarreaue6945732016-12-21 19:57:00 +01002046 list_for_each_entry(pcf, &post_check_list, list) {
2047 err_code |= pcf->fct();
2048 if (err_code & (ERR_ABORT|ERR_FATAL))
2049 exit(1);
2050 }
2051
Willy Tarreaubaaee002006-06-26 02:48:02 +02002052 if (cfg_maxconn > 0)
2053 global.maxconn = cfg_maxconn;
2054
Willy Tarreau4975d142021-03-13 11:00:33 +01002055 if (global.cli_fe)
2056 global.maxsock += global.cli_fe->maxconn;
Willy Tarreau8d687d82019-03-01 09:39:42 +01002057
2058 if (cfg_peers) {
2059 /* peers also need to bypass global maxconn */
2060 struct peers *p = cfg_peers;
2061
2062 for (p = cfg_peers; p; p = p->next)
2063 if (p->peers_fe)
2064 global.maxsock += p->peers_fe->maxconn;
2065 }
2066
Willy Tarreaubaaee002006-06-26 02:48:02 +02002067 if (cfg_pidfile) {
Willy Tarreaua534fea2008-08-03 12:19:50 +02002068 free(global.pidfile);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002069 global.pidfile = strdup(cfg_pidfile);
2070 }
2071
Willy Tarreaud0256482015-01-15 21:45:22 +01002072 /* Now we want to compute the maxconn and possibly maxsslconn values.
Willy Tarreauac350932019-03-01 15:43:14 +01002073 * It's a bit tricky. Maxconn defaults to the pre-computed value based
2074 * on rlim_fd_cur and the number of FDs in use due to the configuration,
2075 * and maxsslconn defaults to DEFAULT_MAXSSLCONN. On top of that we can
2076 * enforce a lower limit based on memmax.
Willy Tarreaud0256482015-01-15 21:45:22 +01002077 *
2078 * If memmax is set, then it depends on which values are set. If
2079 * maxsslconn is set, we use memmax to determine how many cleartext
2080 * connections may be added, and set maxconn to the sum of the two.
2081 * If maxconn is set and not maxsslconn, maxsslconn is computed from
2082 * the remaining amount of memory between memmax and the cleartext
2083 * connections. If neither are set, then it is considered that all
2084 * connections are SSL-capable, and maxconn is computed based on this,
2085 * then maxsslconn accordingly. We need to know if SSL is used on the
2086 * frontends, backends, or both, because when it's used on both sides,
2087 * we need twice the value for maxsslconn, but we only count the
2088 * handshake once since it is not performed on the two sides at the
2089 * same time (frontend-side is terminated before backend-side begins).
2090 * The SSL stack is supposed to have filled ssl_session_cost and
Willy Tarreau474b96a2015-01-28 19:03:21 +01002091 * ssl_handshake_cost during its initialization. In any case, if
2092 * SYSTEM_MAXCONN is set, we still enforce it as an upper limit for
2093 * maxconn in order to protect the system.
Willy Tarreaud0256482015-01-15 21:45:22 +01002094 */
Willy Tarreauac350932019-03-01 15:43:14 +01002095 ideal_maxconn = compute_ideal_maxconn();
2096
Willy Tarreaud0256482015-01-15 21:45:22 +01002097 if (!global.rlimit_memmax) {
2098 if (global.maxconn == 0) {
Willy Tarreauac350932019-03-01 15:43:14 +01002099 global.maxconn = ideal_maxconn;
Willy Tarreaud0256482015-01-15 21:45:22 +01002100 if (global.mode & (MODE_VERBOSE|MODE_DEBUG))
2101 fprintf(stderr, "Note: setting global.maxconn to %d.\n", global.maxconn);
2102 }
2103 }
2104#ifdef USE_OPENSSL
2105 else if (!global.maxconn && !global.maxsslconn &&
2106 (global.ssl_used_frontend || global.ssl_used_backend)) {
2107 /* memmax is set, compute everything automatically. Here we want
2108 * to ensure that all SSL connections will be served. We take
2109 * care of the number of sides where SSL is used, and consider
2110 * the worst case : SSL used on both sides and doing a handshake
2111 * simultaneously. Note that we can't have more than maxconn
2112 * handshakes at a time by definition, so for the worst case of
2113 * two SSL conns per connection, we count a single handshake.
2114 */
2115 int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
2116 int64_t mem = global.rlimit_memmax * 1048576ULL;
Willy Tarreau304e17e2020-03-10 17:54:54 +01002117 int retried = 0;
Willy Tarreaud0256482015-01-15 21:45:22 +01002118
2119 mem -= global.tune.sslcachesize * 200; // about 200 bytes per SSL cache entry
2120 mem -= global.maxzlibmem;
2121 mem = mem * MEM_USABLE_RATIO;
2122
Willy Tarreau304e17e2020-03-10 17:54:54 +01002123 /* Principle: we test once to set maxconn according to the free
2124 * memory. If it results in values the system rejects, we try a
2125 * second time by respecting rlim_fd_max. If it fails again, we
2126 * go back to the initial value and will let the final code
2127 * dealing with rlimit report the error. That's up to 3 attempts.
2128 */
2129 do {
2130 global.maxconn = mem /
2131 ((STREAM_MAX_COST + 2 * global.tune.bufsize) + // stream + 2 buffers per stream
2132 sides * global.ssl_session_max_cost + // SSL buffers, one per side
2133 global.ssl_handshake_max_cost); // 1 handshake per connection max
Willy Tarreaud0256482015-01-15 21:45:22 +01002134
Willy Tarreau304e17e2020-03-10 17:54:54 +01002135 if (retried == 1)
2136 global.maxconn = MIN(global.maxconn, ideal_maxconn);
2137 global.maxconn = round_2dig(global.maxconn);
Willy Tarreau474b96a2015-01-28 19:03:21 +01002138#ifdef SYSTEM_MAXCONN
Willy Tarreau304e17e2020-03-10 17:54:54 +01002139 if (global.maxconn > SYSTEM_MAXCONN)
2140 global.maxconn = SYSTEM_MAXCONN;
Willy Tarreau474b96a2015-01-28 19:03:21 +01002141#endif /* SYSTEM_MAXCONN */
Willy Tarreau304e17e2020-03-10 17:54:54 +01002142 global.maxsslconn = sides * global.maxconn;
2143
2144 if (check_if_maxsock_permitted(compute_ideal_maxsock(global.maxconn)))
2145 break;
2146 } while (retried++ < 2);
2147
Willy Tarreaud0256482015-01-15 21:45:22 +01002148 if (global.mode & (MODE_VERBOSE|MODE_DEBUG))
2149 fprintf(stderr, "Note: setting global.maxconn to %d and global.maxsslconn to %d.\n",
2150 global.maxconn, global.maxsslconn);
2151 }
2152 else if (!global.maxsslconn &&
2153 (global.ssl_used_frontend || global.ssl_used_backend)) {
2154 /* memmax and maxconn are known, compute maxsslconn automatically.
2155 * maxsslconn being forced, we don't know how many of it will be
2156 * on each side if both sides are being used. The worst case is
2157 * when all connections use only one SSL instance because
2158 * handshakes may be on two sides at the same time.
2159 */
2160 int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
2161 int64_t mem = global.rlimit_memmax * 1048576ULL;
2162 int64_t sslmem;
2163
2164 mem -= global.tune.sslcachesize * 200; // about 200 bytes per SSL cache entry
2165 mem -= global.maxzlibmem;
2166 mem = mem * MEM_USABLE_RATIO;
2167
Willy Tarreau87b09662015-04-03 00:22:06 +02002168 sslmem = mem - global.maxconn * (int64_t)(STREAM_MAX_COST + 2 * global.tune.bufsize);
Willy Tarreaud0256482015-01-15 21:45:22 +01002169 global.maxsslconn = sslmem / (global.ssl_session_max_cost + global.ssl_handshake_max_cost);
2170 global.maxsslconn = round_2dig(global.maxsslconn);
2171
2172 if (sslmem <= 0 || global.maxsslconn < sides) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002173 ha_alert("Cannot compute the automatic maxsslconn because global.maxconn is already too "
2174 "high for the global.memmax value (%d MB). The absolute maximum possible value "
2175 "without SSL is %d, but %d was found and SSL is in use.\n",
2176 global.rlimit_memmax,
2177 (int)(mem / (STREAM_MAX_COST + 2 * global.tune.bufsize)),
2178 global.maxconn);
Willy Tarreaud0256482015-01-15 21:45:22 +01002179 exit(1);
2180 }
2181
2182 if (global.maxsslconn > sides * global.maxconn)
2183 global.maxsslconn = sides * global.maxconn;
2184
2185 if (global.mode & (MODE_VERBOSE|MODE_DEBUG))
2186 fprintf(stderr, "Note: setting global.maxsslconn to %d\n", global.maxsslconn);
2187 }
2188#endif
2189 else if (!global.maxconn) {
2190 /* memmax and maxsslconn are known/unused, compute maxconn automatically */
2191 int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
2192 int64_t mem = global.rlimit_memmax * 1048576ULL;
2193 int64_t clearmem;
Willy Tarreau304e17e2020-03-10 17:54:54 +01002194 int retried = 0;
Willy Tarreaud0256482015-01-15 21:45:22 +01002195
2196 if (global.ssl_used_frontend || global.ssl_used_backend)
2197 mem -= global.tune.sslcachesize * 200; // about 200 bytes per SSL cache entry
2198
2199 mem -= global.maxzlibmem;
2200 mem = mem * MEM_USABLE_RATIO;
2201
2202 clearmem = mem;
2203 if (sides)
2204 clearmem -= (global.ssl_session_max_cost + global.ssl_handshake_max_cost) * (int64_t)global.maxsslconn;
2205
Willy Tarreau304e17e2020-03-10 17:54:54 +01002206 /* Principle: we test once to set maxconn according to the free
2207 * memory. If it results in values the system rejects, we try a
2208 * second time by respecting rlim_fd_max. If it fails again, we
2209 * go back to the initial value and will let the final code
2210 * dealing with rlimit report the error. That's up to 3 attempts.
2211 */
2212 do {
2213 global.maxconn = clearmem / (STREAM_MAX_COST + 2 * global.tune.bufsize);
2214 if (retried == 1)
2215 global.maxconn = MIN(global.maxconn, ideal_maxconn);
2216 global.maxconn = round_2dig(global.maxconn);
Willy Tarreau474b96a2015-01-28 19:03:21 +01002217#ifdef SYSTEM_MAXCONN
Willy Tarreau304e17e2020-03-10 17:54:54 +01002218 if (global.maxconn > SYSTEM_MAXCONN)
2219 global.maxconn = SYSTEM_MAXCONN;
Willy Tarreau474b96a2015-01-28 19:03:21 +01002220#endif /* SYSTEM_MAXCONN */
Willy Tarreaud0256482015-01-15 21:45:22 +01002221
Willy Tarreau304e17e2020-03-10 17:54:54 +01002222 if (clearmem <= 0 || !global.maxconn) {
2223 ha_alert("Cannot compute the automatic maxconn because global.maxsslconn is already too "
2224 "high for the global.memmax value (%d MB). The absolute maximum possible value "
2225 "is %d, but %d was found.\n",
2226 global.rlimit_memmax,
Christopher Faulet767a84b2017-11-24 16:50:31 +01002227 (int)(mem / (global.ssl_session_max_cost + global.ssl_handshake_max_cost)),
Willy Tarreau304e17e2020-03-10 17:54:54 +01002228 global.maxsslconn);
2229 exit(1);
2230 }
2231
2232 if (check_if_maxsock_permitted(compute_ideal_maxsock(global.maxconn)))
2233 break;
2234 } while (retried++ < 2);
Willy Tarreaud0256482015-01-15 21:45:22 +01002235
2236 if (global.mode & (MODE_VERBOSE|MODE_DEBUG)) {
2237 if (sides && global.maxsslconn > sides * global.maxconn) {
2238 fprintf(stderr, "Note: global.maxsslconn is forced to %d which causes global.maxconn "
2239 "to be limited to %d. Better reduce global.maxsslconn to get more "
2240 "room for extra connections.\n", global.maxsslconn, global.maxconn);
2241 }
2242 fprintf(stderr, "Note: setting global.maxconn to %d\n", global.maxconn);
2243 }
Willy Tarreau66aa61f2009-01-18 21:44:07 +01002244 }
2245
Willy Tarreaua409f302020-03-10 17:08:53 +01002246 global.maxsock = compute_ideal_maxsock(global.maxconn);
2247 global.hardmaxconn = global.maxconn;
Willy Tarreaua4818db2020-06-19 16:20:59 +02002248 if (!global.maxpipes)
2249 global.maxpipes = compute_ideal_maxpipes();
Willy Tarreaubaaee002006-06-26 02:48:02 +02002250
Olivier Houchard88698d92019-04-16 19:07:22 +02002251 /* update connection pool thresholds */
2252 global.tune.pool_low_count = ((long long)global.maxsock * global.tune.pool_low_ratio + 99) / 100;
2253 global.tune.pool_high_count = ((long long)global.maxsock * global.tune.pool_high_ratio + 99) / 100;
2254
Willy Tarreauc8d5b952019-02-27 17:25:52 +01002255 proxy_adjust_all_maxconn();
2256
Willy Tarreau1db37712007-06-03 17:16:49 +02002257 if (global.tune.maxpollevents <= 0)
2258 global.tune.maxpollevents = MAX_POLL_EVENTS;
2259
Willy Tarreau060a7612021-03-10 11:06:26 +01002260 if (global.tune.runqueue_depth <= 0) {
2261 /* tests on various thread counts from 1 to 64 have shown an
2262 * optimal queue depth following roughly 1/sqrt(threads).
2263 */
2264 int s = my_flsl(global.nbthread);
2265 s += (global.nbthread / s); // roughly twice the sqrt.
2266 global.tune.runqueue_depth = RUNQUEUE_DEPTH * 2 / s;
2267 }
Olivier Houchard1599b802018-05-24 18:59:04 +02002268
Willy Tarreau6f4a82c2009-03-21 20:43:57 +01002269 if (global.tune.recv_enough == 0)
2270 global.tune.recv_enough = MIN_RECV_AT_ONCE_ENOUGH;
2271
Willy Tarreau27a674e2009-08-17 07:23:33 +02002272 if (global.tune.maxrewrite >= global.tune.bufsize / 2)
2273 global.tune.maxrewrite = global.tune.bufsize / 2;
2274
Willy Tarreaubaaee002006-06-26 02:48:02 +02002275 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
2276 /* command line debug mode inhibits configuration mode */
William Lallemand095ba4c2017-06-01 17:38:50 +02002277 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
Willy Tarreau772f0dd2012-10-26 16:04:28 +02002278 global.mode |= (arg_mode & (MODE_DEBUG | MODE_FOREGROUND));
2279 }
2280
William Lallemand095ba4c2017-06-01 17:38:50 +02002281 if (arg_mode & MODE_DAEMON) {
Willy Tarreau772f0dd2012-10-26 16:04:28 +02002282 /* command line daemon mode inhibits foreground and debug modes mode */
2283 global.mode &= ~(MODE_DEBUG | MODE_FOREGROUND);
William Lallemand095ba4c2017-06-01 17:38:50 +02002284 global.mode |= arg_mode & MODE_DAEMON;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002285 }
Willy Tarreau772f0dd2012-10-26 16:04:28 +02002286
2287 global.mode |= (arg_mode & (MODE_QUIET | MODE_VERBOSE));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002288
William Lallemand095ba4c2017-06-01 17:38:50 +02002289 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002290 ha_warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
William Lallemand095ba4c2017-06-01 17:38:50 +02002291 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002292 }
2293
William Lallemand095ba4c2017-06-01 17:38:50 +02002294 if ((global.nbproc > 1) && !(global.mode & (MODE_DAEMON | MODE_MWORKER))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002295 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
Christopher Faulet767a84b2017-11-24 16:50:31 +01002296 ha_warning("<nbproc> is only meaningful in daemon mode or master-worker mode. Setting limit to 1 process.\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002297 global.nbproc = 1;
2298 }
2299
2300 if (global.nbproc < 1)
2301 global.nbproc = 1;
2302
Christopher Fauletbe0faa22017-08-29 15:37:10 +02002303 if (global.nbthread < 1)
2304 global.nbthread = 1;
2305
Christopher Faulet3ef26392017-08-29 16:46:57 +02002306 /* Realloc trash buffers because global.tune.bufsize may have changed */
Christopher Fauletcd7879a2017-10-27 13:53:47 +02002307 if (!init_trash_buffers(0)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002308 ha_alert("failed to initialize trash buffers.\n");
Christopher Faulet3ef26392017-08-29 16:46:57 +02002309 exit(1);
2310 }
2311
Christopher Faulet96d44832017-11-14 22:02:30 +01002312 if (!init_log_buffers()) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002313 ha_alert("failed to initialize log buffers.\n");
Christopher Faulet96d44832017-11-14 22:02:30 +01002314 exit(1);
2315 }
2316
Willy Tarreauef1d1f82007-04-16 00:25:25 +02002317 /*
2318 * Note: we could register external pollers here.
2319 * Built-in pollers have been registered before main().
2320 */
Willy Tarreau4f60f162007-04-08 16:39:58 +02002321
Willy Tarreau43b78992009-01-25 15:42:27 +01002322 if (!(global.tune.options & GTUNE_USE_KQUEUE))
Willy Tarreau1e63130a2007-04-09 12:03:06 +02002323 disable_poller("kqueue");
2324
Emmanuel Hocdet0ba4f482019-04-08 16:53:32 +00002325 if (!(global.tune.options & GTUNE_USE_EVPORTS))
2326 disable_poller("evports");
2327
Willy Tarreau43b78992009-01-25 15:42:27 +01002328 if (!(global.tune.options & GTUNE_USE_EPOLL))
Willy Tarreau4f60f162007-04-08 16:39:58 +02002329 disable_poller("epoll");
2330
Willy Tarreau43b78992009-01-25 15:42:27 +01002331 if (!(global.tune.options & GTUNE_USE_POLL))
Willy Tarreau4f60f162007-04-08 16:39:58 +02002332 disable_poller("poll");
2333
Willy Tarreau43b78992009-01-25 15:42:27 +01002334 if (!(global.tune.options & GTUNE_USE_SELECT))
Willy Tarreau4f60f162007-04-08 16:39:58 +02002335 disable_poller("select");
2336
2337 /* Note: we could disable any poller by name here */
2338
Christopher Fauletb3f4e142016-03-07 12:46:38 +01002339 if (global.mode & (MODE_VERBOSE|MODE_DEBUG)) {
Willy Tarreau2ff76222007-04-09 19:29:56 +02002340 list_pollers(stderr);
Christopher Fauletb3f4e142016-03-07 12:46:38 +01002341 fprintf(stderr, "\n");
2342 list_filters(stderr);
2343 }
Willy Tarreau2ff76222007-04-09 19:29:56 +02002344
Willy Tarreau4f60f162007-04-08 16:39:58 +02002345 if (!init_pollers()) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002346 ha_alert("No polling mechanism available.\n"
2347 " It is likely that haproxy was built with TARGET=generic and that FD_SETSIZE\n"
2348 " is too low on this platform to support maxconn and the number of listeners\n"
2349 " and servers. You should rebuild haproxy specifying your system using TARGET=\n"
2350 " in order to support other polling systems (poll, epoll, kqueue) or reduce the\n"
2351 " global maxconn setting to accommodate the system's limitation. For reference,\n"
2352 " FD_SETSIZE=%d on this system, global.maxconn=%d resulting in a maximum of\n"
2353 " %d file descriptors. You should thus reduce global.maxconn by %d. Also,\n"
2354 " check build settings using 'haproxy -vv'.\n\n",
2355 FD_SETSIZE, global.maxconn, global.maxsock, (global.maxsock + 1 - FD_SETSIZE) / 2);
Willy Tarreau4f60f162007-04-08 16:39:58 +02002356 exit(1);
2357 }
Willy Tarreau2ff76222007-04-09 19:29:56 +02002358 if (global.mode & (MODE_VERBOSE|MODE_DEBUG)) {
2359 printf("Using %s() as the polling mechanism.\n", cur_poller.name);
Willy Tarreau4f60f162007-04-08 16:39:58 +02002360 }
2361
Krzysztof Piotr Oledzki48cb2ae2009-10-02 22:51:14 +02002362 if (!global.node)
2363 global.node = strdup(hostname);
2364
Willy Tarreau02b092f2020-10-07 18:36:54 +02002365 /* stop disabled proxies */
2366 for (px = proxies_list; px; px = px->next) {
Willy Tarreauc3914d42020-09-24 08:39:22 +02002367 if (px->disabled)
Willy Tarreau02b092f2020-10-07 18:36:54 +02002368 stop_proxy(px);
2369 }
2370
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01002371 if (!hlua_post_init())
2372 exit(1);
Thomas Holmes6abded42015-05-12 16:23:58 +01002373
Maxime de Roucy0f503922016-05-13 23:52:55 +02002374 free(err_msg);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002375}
2376
Cyril Bonté203ec5a2017-03-23 22:44:13 +01002377void deinit(void)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002378{
Olivier Houchardfbc74e82017-11-24 16:54:05 +01002379 struct proxy *p = proxies_list, *p0;
Willy Tarreaudeb9ed82010-01-03 21:03:22 +01002380 struct wordlist *wl, *wlb;
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002381 struct uri_auth *uap, *ua = NULL;
William Lallemand0f99e342011-10-12 17:50:54 +02002382 struct logsrv *log, *logb;
Willy Tarreaucdb737e2016-12-21 18:43:10 +01002383 struct build_opts_str *bol, *bolb;
Tim Duesterhusfdf904a2020-07-04 11:49:48 +02002384 struct post_deinit_fct *pdf, *pdfb;
Tim Duesterhus17e363f2020-07-04 11:49:47 +02002385 struct proxy_deinit_fct *pxdf, *pxdfb;
Tim Duesterhus0837eb12020-07-04 11:49:49 +02002386 struct server_deinit_fct *srvdf, *srvdfb;
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002387 struct per_thread_init_fct *tif, *tifb;
2388 struct per_thread_deinit_fct *tdf, *tdfb;
2389 struct per_thread_alloc_fct *taf, *tafb;
2390 struct per_thread_free_fct *tff, *tffb;
Tim Duesterhus34bef072020-07-04 11:49:50 +02002391 struct post_server_check_fct *pscf, *pscfb;
Tim Duesterhusfc854942020-09-10 19:46:42 +02002392 struct post_check_fct *pcf, *pcfb;
Tim Duesterhus53508d62020-09-10 19:46:40 +02002393 struct post_proxy_check_fct *ppcf, *ppcfb;
Willy Tarreauae7bc4a2020-09-23 16:46:22 +02002394 int cur_fd;
2395
2396 /* At this point the listeners state is weird:
2397 * - most listeners are still bound and referenced in their protocol
2398 * - some might be zombies that are not in their proto anymore, but
2399 * still appear in their proxy's listeners with a valid FD.
2400 * - some might be stopped and still appear in their proxy as FD #-1
2401 * - among all of them, some might be inherited hence shared and we're
2402 * not allowed to pause them or whatever, we must just close them.
2403 * - finally some are not listeners (pipes, logs, stdout, etc) and
2404 * must be left intact.
2405 *
2406 * The safe way to proceed is to unbind (and close) whatever is not yet
2407 * unbound so that no more receiver/listener remains alive. Then close
2408 * remaining listener FDs, which correspond to zombie listeners (those
2409 * belonging to disabled proxies that were in another process).
2410 * objt_listener() would be cleaner here but not converted yet.
2411 */
2412 protocol_unbind_all();
2413
2414 for (cur_fd = 0; cur_fd < global.maxsock; cur_fd++) {
Willy Tarreau1a3770c2020-10-14 12:13:51 +02002415 if (!fdtab || !fdtab[cur_fd].owner)
Willy Tarreauae7bc4a2020-09-23 16:46:22 +02002416 continue;
2417
Willy Tarreaua74cb382020-10-15 21:29:49 +02002418 if (fdtab[cur_fd].iocb == &sock_accept_iocb) {
Willy Tarreauae7bc4a2020-09-23 16:46:22 +02002419 struct listener *l = fdtab[cur_fd].owner;
2420
2421 BUG_ON(l->state != LI_INIT);
2422 unbind_listener(l);
2423 }
2424 }
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002425
Willy Tarreau24f4efa2010-08-27 17:56:48 +02002426 deinit_signals();
Willy Tarreaubaaee002006-06-26 02:48:02 +02002427 while (p) {
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002428 /* build a list of unique uri_auths */
2429 if (!ua)
2430 ua = p->uri_auth;
2431 else {
2432 /* check if p->uri_auth is unique */
2433 for (uap = ua; uap; uap=uap->next)
2434 if (uap == p->uri_auth)
2435 break;
2436
Willy Tarreauaccc4e12008-06-24 11:14:45 +02002437 if (!uap && p->uri_auth) {
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002438 /* add it, if it is */
2439 p->uri_auth->next = ua;
2440 ua = p->uri_auth;
2441 }
William Lallemand0f99e342011-10-12 17:50:54 +02002442 }
2443
Willy Tarreau4d2d0982007-05-14 00:39:29 +02002444 p0 = p;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002445 p = p->next;
Amaury Denoyelle27fefa12021-03-24 16:13:20 +01002446 free_proxy(p0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002447 }/* end while(p) */
Willy Tarreaudd815982007-10-16 12:25:14 +02002448
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002449 while (ua) {
Tim Duesterhus00f00cf2020-09-10 19:46:38 +02002450 struct stat_scope *scope, *scopep;
2451
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002452 uap = ua;
2453 ua = ua->next;
2454
Willy Tarreaua534fea2008-08-03 12:19:50 +02002455 free(uap->uri_prefix);
2456 free(uap->auth_realm);
Krzysztof Piotr Oledzki48cb2ae2009-10-02 22:51:14 +02002457 free(uap->node);
2458 free(uap->desc);
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002459
Krzysztof Piotr Oledzki8c8bd452010-01-29 19:29:32 +01002460 userlist_free(uap->userlist);
Amaury Denoyelle68fd7e42021-03-25 17:15:52 +01002461 free_act_rules(&uap->http_req_rules);
Krzysztof Piotr Oledzki8c8bd452010-01-29 19:29:32 +01002462
Tim Duesterhus00f00cf2020-09-10 19:46:38 +02002463 scope = uap->scope;
2464 while (scope) {
2465 scopep = scope;
2466 scope = scope->next;
2467
2468 free(scopep->px_id);
2469 free(scopep);
2470 }
2471
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002472 free(uap);
2473 }
2474
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +01002475 userlist_free(userlist);
2476
David Carlier834cb2e2015-09-25 12:02:25 +01002477 cfg_unregister_sections();
2478
Christopher Faulet0132d062017-07-26 15:33:35 +02002479 deinit_log_buffers();
David Carlier834cb2e2015-09-25 12:02:25 +01002480
Willy Tarreau05554e62016-12-21 20:46:26 +01002481 list_for_each_entry(pdf, &post_deinit_list, list)
2482 pdf->fct();
2483
Willy Tarreau61cfdf42021-02-20 10:46:51 +01002484 ha_free(&global.log_send_hostname);
Dragan Dosen43885c72015-10-01 13:18:13 +02002485 chunk_destroy(&global.log_tag);
Willy Tarreau61cfdf42021-02-20 10:46:51 +01002486 ha_free(&global.chroot);
2487 ha_free(&global.pidfile);
2488 ha_free(&global.node);
2489 ha_free(&global.desc);
2490 ha_free(&oldpids);
2491 ha_free(&old_argv);
2492 ha_free(&localpeer);
2493 ha_free(&global.server_state_base);
2494 ha_free(&global.server_state_file);
Olivier Houchard3f795f72019-04-17 22:51:06 +02002495 task_destroy(idle_conn_task);
Olivier Houchard9ea5d362019-02-14 18:29:09 +01002496 idle_conn_task = NULL;
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002497
William Lallemand0f99e342011-10-12 17:50:54 +02002498 list_for_each_entry_safe(log, logb, &global.logsrvs, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002499 LIST_DELETE(&log->list);
Amaury Denoyelled688e012021-04-20 17:05:47 +02002500 free(log->conf.file);
William Lallemand0f99e342011-10-12 17:50:54 +02002501 free(log);
2502 }
Willy Tarreau477ecd82010-01-03 21:12:30 +01002503 list_for_each_entry_safe(wl, wlb, &cfg_cfgfiles, list) {
Maxime de Roucy0f503922016-05-13 23:52:55 +02002504 free(wl->s);
Willy Tarreau2b718102021-04-21 07:32:39 +02002505 LIST_DELETE(&wl->list);
Willy Tarreau477ecd82010-01-03 21:12:30 +01002506 free(wl);
2507 }
2508
Willy Tarreaucdb737e2016-12-21 18:43:10 +01002509 list_for_each_entry_safe(bol, bolb, &build_opts_list, list) {
2510 if (bol->must_free)
2511 free((void *)bol->str);
Willy Tarreau2b718102021-04-21 07:32:39 +02002512 LIST_DELETE(&bol->list);
Willy Tarreaucdb737e2016-12-21 18:43:10 +01002513 free(bol);
2514 }
2515
Tim Duesterhus17e363f2020-07-04 11:49:47 +02002516 list_for_each_entry_safe(pxdf, pxdfb, &proxy_deinit_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002517 LIST_DELETE(&pxdf->list);
Tim Duesterhus17e363f2020-07-04 11:49:47 +02002518 free(pxdf);
2519 }
2520
Tim Duesterhusfdf904a2020-07-04 11:49:48 +02002521 list_for_each_entry_safe(pdf, pdfb, &post_deinit_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002522 LIST_DELETE(&pdf->list);
Tim Duesterhusfdf904a2020-07-04 11:49:48 +02002523 free(pdf);
2524 }
2525
Tim Duesterhus0837eb12020-07-04 11:49:49 +02002526 list_for_each_entry_safe(srvdf, srvdfb, &server_deinit_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002527 LIST_DELETE(&srvdf->list);
Tim Duesterhus0837eb12020-07-04 11:49:49 +02002528 free(srvdf);
2529 }
2530
Tim Duesterhusfc854942020-09-10 19:46:42 +02002531 list_for_each_entry_safe(pcf, pcfb, &post_check_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002532 LIST_DELETE(&pcf->list);
Tim Duesterhusfc854942020-09-10 19:46:42 +02002533 free(pcf);
2534 }
2535
Tim Duesterhus34bef072020-07-04 11:49:50 +02002536 list_for_each_entry_safe(pscf, pscfb, &post_server_check_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002537 LIST_DELETE(&pscf->list);
Tim Duesterhus34bef072020-07-04 11:49:50 +02002538 free(pscf);
2539 }
2540
Tim Duesterhus53508d62020-09-10 19:46:40 +02002541 list_for_each_entry_safe(ppcf, ppcfb, &post_proxy_check_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002542 LIST_DELETE(&ppcf->list);
Tim Duesterhus53508d62020-09-10 19:46:40 +02002543 free(ppcf);
2544 }
2545
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002546 list_for_each_entry_safe(tif, tifb, &per_thread_init_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002547 LIST_DELETE(&tif->list);
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002548 free(tif);
2549 }
2550
2551 list_for_each_entry_safe(tdf, tdfb, &per_thread_deinit_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002552 LIST_DELETE(&tdf->list);
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002553 free(tdf);
2554 }
2555
2556 list_for_each_entry_safe(taf, tafb, &per_thread_alloc_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002557 LIST_DELETE(&taf->list);
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002558 free(taf);
2559 }
2560
2561 list_for_each_entry_safe(tff, tffb, &per_thread_free_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002562 LIST_DELETE(&tff->list);
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002563 free(tff);
2564 }
2565
Willy Tarreaucfc4f242021-05-08 11:41:28 +02002566 vars_prune(&proc_vars, NULL, NULL);
Willy Tarreau2455ceb2018-11-26 15:57:34 +01002567 pool_destroy_all();
Krzysztof Piotr Oledzkia643baf2008-05-29 23:53:44 +02002568 deinit_pollers();
Willy Tarreaubaaee002006-06-26 02:48:02 +02002569} /* end deinit() */
2570
Willy Tarreauf3ca5a02020-06-15 18:43:46 +02002571__attribute__((noreturn)) void deinit_and_exit(int status)
Tim Duesterhus26540552020-06-14 00:37:41 +02002572{
2573 deinit();
2574 exit(status);
2575}
William Lallemand72160322018-11-06 17:37:16 +01002576
Amaury Denoyelled3a88c12021-05-03 10:47:51 +02002577/* Handler of the task of mux_stopping_data.
2578 * Called on soft-stop.
2579 */
2580struct task *mux_stopping_process(struct task *t, void *ctx, unsigned int state)
2581{
2582 struct connection *conn, *back;
2583
2584 list_for_each_entry_safe(conn, back, &mux_stopping_data[tid].list, stopping_list) {
2585 if (conn->mux && conn->mux->wake)
2586 conn->mux->wake(conn);
2587 }
2588
2589 return t;
2590}
2591
Willy Tarreau918ff602011-07-25 16:33:49 +02002592/* Runs the polling loop */
Willy Tarreau3ebd55e2020-03-03 14:59:56 +01002593void run_poll_loop()
Willy Tarreau4f60f162007-04-08 16:39:58 +02002594{
Willy Tarreau2ae84e42019-05-28 16:44:05 +02002595 int next, wake;
Willy Tarreau4f60f162007-04-08 16:39:58 +02002596
Amaury Denoyelled3a88c12021-05-03 10:47:51 +02002597 /* allocates the thread bound mux_stopping_data task */
2598 mux_stopping_data[tid].task = task_new(tid_bit);
2599 mux_stopping_data[tid].task->process = mux_stopping_process;
2600 LIST_INIT(&mux_stopping_data[tid].list);
2601
Willy Tarreaub0b37bc2008-06-23 14:00:57 +02002602 tv_update_date(0,1);
Willy Tarreau4f60f162007-04-08 16:39:58 +02002603 while (1) {
Willy Tarreauc49ba522019-12-11 08:12:23 +01002604 wake_expired_tasks();
2605
William Lallemand1aab50b2018-06-07 09:46:01 +02002606 /* check if we caught some signals and process them in the
2607 first thread */
Willy Tarreaua7ad4ae2020-06-19 12:06:34 +02002608 if (signal_queue_len && tid == 0) {
2609 activity[tid].wake_signal++;
William Lallemand1aab50b2018-06-07 09:46:01 +02002610 signal_process_queue();
Willy Tarreaua7ad4ae2020-06-19 12:06:34 +02002611 }
2612
2613 /* Process a few tasks */
2614 process_runnable_tasks();
Willy Tarreau29857942009-05-10 09:01:21 +02002615
Willy Tarreau7067b3a2019-06-02 11:11:29 +02002616 /* also stop if we failed to cleanly stop all tasks */
2617 if (killed > 1)
2618 break;
2619
Willy Tarreau10146c92015-04-13 20:44:19 +02002620 /* expire immediately if events are pending */
Willy Tarreau2ae84e42019-05-28 16:44:05 +02002621 wake = 1;
Olivier Houchard305d5ab2019-07-24 18:07:06 +02002622 if (thread_has_tasks())
Willy Tarreaud80cb4e2018-01-20 19:30:13 +01002623 activity[tid].wake_tasks++;
Olivier Houchard79321b92018-07-26 17:55:11 +02002624 else {
Olivier Houchardb23a61f2019-03-08 18:51:17 +01002625 _HA_ATOMIC_OR(&sleeping_thread_mask, tid_bit);
2626 __ha_barrier_atomic_store();
Willy Tarreau95abd5b2020-03-23 09:33:32 +01002627 if (thread_has_tasks()) {
Olivier Houchard79321b92018-07-26 17:55:11 +02002628 activity[tid].wake_tasks++;
Olivier Houchardb23a61f2019-03-08 18:51:17 +01002629 _HA_ATOMIC_AND(&sleeping_thread_mask, ~tid_bit);
Olivier Houchard79321b92018-07-26 17:55:11 +02002630 } else
Willy Tarreau2ae84e42019-05-28 16:44:05 +02002631 wake = 0;
Olivier Houchard79321b92018-07-26 17:55:11 +02002632 }
Willy Tarreau10146c92015-04-13 20:44:19 +02002633
Willy Tarreau4f46a352020-03-23 09:27:28 +01002634 if (!wake) {
Willy Tarreaud7a6b2f2020-05-13 13:51:01 +02002635 int i;
2636
2637 if (stopping) {
Ilya Shipitsin3df59892021-05-10 12:50:00 +05002638 /* stop muxes before acknowledging stopping */
Amaury Denoyelled3a88c12021-05-03 10:47:51 +02002639 if (!(stopping_thread_mask & tid_bit)) {
2640 task_wakeup(mux_stopping_data[tid].task, TASK_WOKEN_OTHER);
2641 wake = 1;
2642 }
2643
Willy Tarreau1db42732021-04-06 11:44:07 +02002644 if (_HA_ATOMIC_OR_FETCH(&stopping_thread_mask, tid_bit) == tid_bit) {
Willy Tarreaud6455742020-05-13 14:30:25 +02002645 /* notify all threads that stopping was just set */
2646 for (i = 0; i < global.nbthread; i++)
Willy Tarreau369a2ef2020-06-29 19:23:19 +02002647 if (((all_threads_mask & ~stopping_thread_mask) >> i) & 1)
Willy Tarreaud6455742020-05-13 14:30:25 +02002648 wake_thread(i);
2649 }
Willy Tarreaud7a6b2f2020-05-13 13:51:01 +02002650 }
Willy Tarreau4f46a352020-03-23 09:27:28 +01002651
2652 /* stop when there's nothing left to do */
2653 if ((jobs - unstoppable_jobs) == 0 &&
Willy Tarreaud7a6b2f2020-05-13 13:51:01 +02002654 (stopping_thread_mask & all_threads_mask) == all_threads_mask) {
2655 /* wake all threads waiting on jobs==0 */
2656 for (i = 0; i < global.nbthread; i++)
2657 if (((all_threads_mask & ~tid_bit) >> i) & 1)
2658 wake_thread(i);
Willy Tarreau4f46a352020-03-23 09:27:28 +01002659 break;
Willy Tarreaud7a6b2f2020-05-13 13:51:01 +02002660 }
Willy Tarreau4f46a352020-03-23 09:27:28 +01002661 }
2662
Willy Tarreauc49ba522019-12-11 08:12:23 +01002663 /* If we have to sleep, measure how long */
2664 next = wake ? TICK_ETERNITY : next_timer_expiry();
2665
Willy Tarreau58b458d2008-06-29 22:40:23 +02002666 /* The poller will ensure it returns around <next> */
Willy Tarreau2ae84e42019-05-28 16:44:05 +02002667 cur_poller.poll(&cur_poller, next, wake);
Emeric Brun64cc49c2017-10-03 14:46:45 +02002668
Willy Tarreaud80cb4e2018-01-20 19:30:13 +01002669 activity[tid].loops++;
Willy Tarreau4f60f162007-04-08 16:39:58 +02002670 }
Amaury Denoyelled3a88c12021-05-03 10:47:51 +02002671
2672 task_destroy(mux_stopping_data[tid].task);
Willy Tarreau4f60f162007-04-08 16:39:58 +02002673}
2674
Christopher Faulet1d17c102017-08-29 15:38:48 +02002675static void *run_thread_poll_loop(void *data)
2676{
Willy Tarreau082b6282019-05-22 14:42:12 +02002677 struct per_thread_alloc_fct *ptaf;
Christopher Faulet1d17c102017-08-29 15:38:48 +02002678 struct per_thread_init_fct *ptif;
2679 struct per_thread_deinit_fct *ptdf;
Willy Tarreau082b6282019-05-22 14:42:12 +02002680 struct per_thread_free_fct *ptff;
Willy Tarreau34a150c2019-06-11 09:16:41 +02002681 static int init_left = 0;
Willy Tarreauaf613e82020-06-05 08:40:51 +02002682 __decl_thread(static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER);
2683 __decl_thread(static pthread_cond_t init_cond = PTHREAD_COND_INITIALIZER);
Christopher Faulet1d17c102017-08-29 15:38:48 +02002684
Willy Tarreaub4f7cc32019-05-03 09:27:30 +02002685 ha_set_tid((unsigned long)data);
Willy Tarreaud022e9c2019-09-24 08:25:15 +02002686 sched = &task_per_thread[tid];
Willy Tarreau91e6df02019-05-03 17:21:18 +02002687
Willy Tarreauf6178242019-05-21 19:46:58 +02002688#if (_POSIX_TIMERS > 0) && defined(_POSIX_THREAD_CPUTIME)
Willy Tarreau91e6df02019-05-03 17:21:18 +02002689#ifdef USE_THREAD
Willy Tarreau8323a372019-05-20 18:57:53 +02002690 pthread_getcpuclockid(pthread_self(), &ti->clock_id);
Willy Tarreau624dcbf2019-05-20 20:23:06 +02002691#else
Willy Tarreau8323a372019-05-20 18:57:53 +02002692 ti->clock_id = CLOCK_THREAD_CPUTIME_ID;
Willy Tarreau91e6df02019-05-03 17:21:18 +02002693#endif
Willy Tarreau663fda42019-05-21 15:14:08 +02002694#endif
Willy Tarreau6ec902a2019-06-07 14:41:11 +02002695 /* Now, initialize one thread init at a time. This is better since
2696 * some init code is a bit tricky and may release global resources
2697 * after reallocating them locally. This will also ensure there is
2698 * no race on file descriptors allocation.
2699 */
Willy Tarreau34a150c2019-06-11 09:16:41 +02002700#ifdef USE_THREAD
2701 pthread_mutex_lock(&init_mutex);
2702#endif
2703 /* The first thread must set the number of threads left */
2704 if (!init_left)
2705 init_left = global.nbthread;
2706 init_left--;
Willy Tarreau91e6df02019-05-03 17:21:18 +02002707
Willy Tarreauc4c80fb2021-04-11 15:00:34 +02002708 tv_init_thread_date();
Christopher Faulet1d17c102017-08-29 15:38:48 +02002709
Willy Tarreau082b6282019-05-22 14:42:12 +02002710 /* per-thread alloc calls performed here are not allowed to snoop on
2711 * other threads, so they are free to initialize at their own rhythm
2712 * as long as they act as if they were alone. None of them may rely
2713 * on resources initialized by the other ones.
2714 */
2715 list_for_each_entry(ptaf, &per_thread_alloc_list, list) {
2716 if (!ptaf->fct()) {
2717 ha_alert("failed to allocate resources for thread %u.\n", tid);
2718 exit(1);
2719 }
2720 }
2721
Willy Tarreau3078e9f2019-05-20 10:50:43 +02002722 /* per-thread init calls performed here are not allowed to snoop on
2723 * other threads, so they are free to initialize at their own rhythm
2724 * as long as they act as if they were alone.
2725 */
Christopher Faulet1d17c102017-08-29 15:38:48 +02002726 list_for_each_entry(ptif, &per_thread_init_list, list) {
2727 if (!ptif->fct()) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002728 ha_alert("failed to initialize thread %u.\n", tid);
Christopher Faulet1d17c102017-08-29 15:38:48 +02002729 exit(1);
2730 }
2731 }
2732
Willy Tarreau71092822019-06-10 09:51:04 +02002733 /* enabling protocols will result in fd_insert() calls to be performed,
2734 * we want all threads to have already allocated their local fd tables
Willy Tarreau34a150c2019-06-11 09:16:41 +02002735 * before doing so, thus only the last thread does it.
Willy Tarreau71092822019-06-10 09:51:04 +02002736 */
Willy Tarreau34a150c2019-06-11 09:16:41 +02002737 if (init_left == 0)
Willy Tarreaue4d7c9d2019-06-10 10:14:52 +02002738 protocol_enable_all();
Willy Tarreau6ec902a2019-06-07 14:41:11 +02002739
Willy Tarreau34a150c2019-06-11 09:16:41 +02002740#ifdef USE_THREAD
2741 pthread_cond_broadcast(&init_cond);
2742 pthread_mutex_unlock(&init_mutex);
2743
2744 /* now wait for other threads to finish starting */
2745 pthread_mutex_lock(&init_mutex);
2746 while (init_left)
2747 pthread_cond_wait(&init_cond, &init_mutex);
2748 pthread_mutex_unlock(&init_mutex);
2749#endif
Willy Tarreau3078e9f2019-05-20 10:50:43 +02002750
Willy Tarreaua45a8b52019-12-06 16:31:45 +01002751#if defined(PR_SET_NO_NEW_PRIVS) && defined(USE_PRCTL)
2752 /* Let's refrain from using setuid executables. This way the impact of
2753 * an eventual vulnerability in a library remains limited. It may
2754 * impact external checks but who cares about them anyway ? In the
2755 * worst case it's possible to disable the option. Obviously we do this
2756 * in workers only. We can't hard-fail on this one as it really is
2757 * implementation dependent though we're interested in feedback, hence
2758 * the warning.
2759 */
2760 if (!(global.tune.options & GTUNE_INSECURE_SETUID) && !master) {
2761 static int warn_fail;
Willy Tarreau18515722021-04-06 11:57:41 +02002762 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1 && !_HA_ATOMIC_FETCH_ADD(&warn_fail, 1)) {
Willy Tarreaua45a8b52019-12-06 16:31:45 +01002763 ha_warning("Failed to disable setuid, please report to developers with detailed "
2764 "information about your operating system. You can silence this warning "
2765 "by adding 'insecure-setuid-wanted' in the 'global' section.\n");
2766 }
2767 }
2768#endif
2769
Willy Tarreaud96f1122019-12-03 07:07:36 +01002770#if defined(RLIMIT_NPROC)
2771 /* all threads have started, it's now time to prevent any new thread
2772 * or process from starting. Obviously we do this in workers only. We
2773 * can't hard-fail on this one as it really is implementation dependent
2774 * though we're interested in feedback, hence the warning.
2775 */
2776 if (!(global.tune.options & GTUNE_INSECURE_FORK) && !master) {
2777 struct rlimit limit = { .rlim_cur = 0, .rlim_max = 0 };
2778 static int warn_fail;
2779
Willy Tarreau18515722021-04-06 11:57:41 +02002780 if (setrlimit(RLIMIT_NPROC, &limit) == -1 && !_HA_ATOMIC_FETCH_ADD(&warn_fail, 1)) {
Willy Tarreaud96f1122019-12-03 07:07:36 +01002781 ha_warning("Failed to disable forks, please report to developers with detailed "
2782 "information about your operating system. You can silence this warning "
2783 "by adding 'insecure-fork-wanted' in the 'global' section.\n");
2784 }
2785 }
2786#endif
Christopher Faulet1d17c102017-08-29 15:38:48 +02002787 run_poll_loop();
2788
2789 list_for_each_entry(ptdf, &per_thread_deinit_list, list)
2790 ptdf->fct();
2791
Willy Tarreau082b6282019-05-22 14:42:12 +02002792 list_for_each_entry(ptff, &per_thread_free_list, list)
2793 ptff->fct();
2794
Christopher Fauletcd7879a2017-10-27 13:53:47 +02002795#ifdef USE_THREAD
Olivier Houchardb23a61f2019-03-08 18:51:17 +01002796 _HA_ATOMIC_AND(&all_threads_mask, ~tid_bit);
Christopher Fauletcd7879a2017-10-27 13:53:47 +02002797 if (tid > 0)
2798 pthread_exit(NULL);
Christopher Faulet1d17c102017-08-29 15:38:48 +02002799#endif
Christopher Fauletcd7879a2017-10-27 13:53:47 +02002800 return NULL;
2801}
Christopher Faulet1d17c102017-08-29 15:38:48 +02002802
William Dauchyf9af9d72019-11-17 15:47:16 +01002803/* set uid/gid depending on global settings */
2804static void set_identity(const char *program_name)
2805{
2806 if (global.gid) {
2807 if (getgroups(0, NULL) > 0 && setgroups(0, NULL) == -1)
2808 ha_warning("[%s.main()] Failed to drop supplementary groups. Using 'gid'/'group'"
2809 " without 'uid'/'user' is generally useless.\n", program_name);
2810
2811 if (setgid(global.gid) == -1) {
2812 ha_alert("[%s.main()] Cannot set gid %d.\n", program_name, global.gid);
2813 protocol_unbind_all();
2814 exit(1);
2815 }
2816 }
2817
2818 if (global.uid && setuid(global.uid) == -1) {
2819 ha_alert("[%s.main()] Cannot set uid %d.\n", program_name, global.uid);
2820 protocol_unbind_all();
2821 exit(1);
2822 }
2823}
2824
Willy Tarreaubaaee002006-06-26 02:48:02 +02002825int main(int argc, char **argv)
2826{
2827 int err, retry;
2828 struct rlimit limit;
Willy Tarreau269ab312012-09-05 08:02:48 +02002829 int pidfd = -1;
Willy Tarreau08293ed2021-07-14 17:54:01 +02002830 int intovf = (unsigned char)argc + 1; /* let the compiler know it's strictly positive */
2831
2832 /* Catch forced CFLAGS that miss 2-complement integer overflow */
2833 if (intovf + 0x7FFFFFFF >= intovf) {
2834 fprintf(stderr,
2835 "FATAL ERROR: invalid code detected -- cannot go further, please recompile!\n"
2836 "The source code was miscompiled by the compiler, which usually indicates that\n"
2837 "some of the CFLAGS needed to work around overzealous compiler optimizations\n"
2838 "were overwritten at build time. Please do not force CFLAGS, and read Makefile\n"
2839 "and INSTALL files to decide on the best way to pass your local build options.\n"
2840 "\nBuild options :"
2841#ifdef BUILD_TARGET
2842 "\n TARGET = " BUILD_TARGET
2843#endif
2844#ifdef BUILD_CPU
2845 "\n CPU = " BUILD_CPU
2846#endif
2847#ifdef BUILD_CC
2848 "\n CC = " BUILD_CC
2849#endif
2850#ifdef BUILD_CFLAGS
2851 "\n CFLAGS = " BUILD_CFLAGS
2852#endif
2853#ifdef BUILD_OPTIONS
2854 "\n OPTIONS = " BUILD_OPTIONS
2855#endif
2856#ifdef BUILD_DEBUG
2857 "\n DEBUG = " BUILD_DEBUG
2858#endif
2859 "\n\n");
2860 return 1;
2861 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002862
Olivier Houchard5fa300d2018-02-03 15:15:21 +01002863 setvbuf(stdout, NULL, _IONBF, 0);
Willy Tarreau5794fb02018-11-25 18:43:29 +01002864
Willy Tarreauff9c9142019-02-07 10:39:36 +01002865 /* this can only safely be done here, though it's optimized away by
2866 * the compiler.
2867 */
2868 if (MAX_PROCS < 1 || MAX_PROCS > LONGBITS) {
2869 ha_alert("MAX_PROCS value must be between 1 and %d inclusive; "
2870 "HAProxy was built with value %d, please fix it and rebuild.\n",
2871 LONGBITS, MAX_PROCS);
2872 exit(1);
2873 }
2874
Willy Tarreaubf696402019-03-01 10:09:28 +01002875 /* take a copy of initial limits before we possibly change them */
2876 getrlimit(RLIMIT_NOFILE, &limit);
Willy Tarreau2bd0f812020-10-13 15:36:08 +02002877
2878 if (limit.rlim_max == RLIM_INFINITY)
2879 limit.rlim_max = limit.rlim_cur;
Willy Tarreaubf696402019-03-01 10:09:28 +01002880 rlim_fd_cur_at_boot = limit.rlim_cur;
2881 rlim_fd_max_at_boot = limit.rlim_max;
2882
Willy Tarreau5794fb02018-11-25 18:43:29 +01002883 /* process all initcalls in order of potential dependency */
2884 RUN_INITCALLS(STG_PREPARE);
2885 RUN_INITCALLS(STG_LOCK);
2886 RUN_INITCALLS(STG_ALLOC);
2887 RUN_INITCALLS(STG_POOL);
2888 RUN_INITCALLS(STG_REGISTER);
2889 RUN_INITCALLS(STG_INIT);
2890
Emeric Bruncf20bf12010-10-22 16:06:11 +02002891 init(argc, argv);
Willy Tarreau24f4efa2010-08-27 17:56:48 +02002892 signal_register_fct(SIGQUIT, dump, SIGQUIT);
2893 signal_register_fct(SIGUSR1, sig_soft_stop, SIGUSR1);
2894 signal_register_fct(SIGHUP, sig_dump_state, SIGHUP);
William Lallemand73b85e72017-06-01 17:38:51 +02002895 signal_register_fct(SIGUSR2, NULL, 0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002896
Willy Tarreaue437c442010-03-17 18:02:46 +01002897 /* Always catch SIGPIPE even on platforms which define MSG_NOSIGNAL.
2898 * Some recent FreeBSD setups report broken pipes, and MSG_NOSIGNAL
2899 * was defined there, so let's stay on the safe side.
Willy Tarreaubaaee002006-06-26 02:48:02 +02002900 */
Willy Tarreau24f4efa2010-08-27 17:56:48 +02002901 signal_register_fct(SIGPIPE, NULL, 0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002902
Willy Tarreaudc23a922011-02-16 11:10:36 +01002903 /* ulimits */
2904 if (!global.rlimit_nofile)
2905 global.rlimit_nofile = global.maxsock;
2906
2907 if (global.rlimit_nofile) {
Willy Tarreaue5cfdac2019-03-01 10:32:05 +01002908 limit.rlim_cur = global.rlimit_nofile;
2909 limit.rlim_max = MAX(rlim_fd_max_at_boot, limit.rlim_cur);
2910
Willy Tarreaudc23a922011-02-16 11:10:36 +01002911 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
Willy Tarreauef635472016-06-21 11:48:18 +02002912 getrlimit(RLIMIT_NOFILE, &limit);
William Dauchy0fec3ab2019-10-27 20:08:11 +01002913 if (global.tune.options & GTUNE_STRICT_LIMITS) {
2914 ha_alert("[%s.main()] Cannot raise FD limit to %d, limit is %d.\n",
2915 argv[0], global.rlimit_nofile, (int)limit.rlim_cur);
Jerome Magnin50f757c2021-01-12 20:19:38 +01002916 exit(1);
William Dauchy0fec3ab2019-10-27 20:08:11 +01002917 }
2918 else {
2919 /* try to set it to the max possible at least */
2920 limit.rlim_cur = limit.rlim_max;
2921 if (setrlimit(RLIMIT_NOFILE, &limit) != -1)
2922 getrlimit(RLIMIT_NOFILE, &limit);
Willy Tarreau164dd0b2016-06-21 11:51:59 +02002923
William Dauchya5194602020-03-28 19:29:58 +01002924 ha_warning("[%s.main()] Cannot raise FD limit to %d, limit is %d.\n",
William Dauchy0fec3ab2019-10-27 20:08:11 +01002925 argv[0], global.rlimit_nofile, (int)limit.rlim_cur);
2926 global.rlimit_nofile = limit.rlim_cur;
2927 }
Willy Tarreaudc23a922011-02-16 11:10:36 +01002928 }
2929 }
2930
2931 if (global.rlimit_memmax) {
2932 limit.rlim_cur = limit.rlim_max =
Willy Tarreau70060452015-12-14 12:46:07 +01002933 global.rlimit_memmax * 1048576ULL;
Willy Tarreaudc23a922011-02-16 11:10:36 +01002934#ifdef RLIMIT_AS
2935 if (setrlimit(RLIMIT_AS, &limit) == -1) {
William Dauchy0fec3ab2019-10-27 20:08:11 +01002936 if (global.tune.options & GTUNE_STRICT_LIMITS) {
2937 ha_alert("[%s.main()] Cannot fix MEM limit to %d megs.\n",
2938 argv[0], global.rlimit_memmax);
Jerome Magnin50f757c2021-01-12 20:19:38 +01002939 exit(1);
William Dauchy0fec3ab2019-10-27 20:08:11 +01002940 }
2941 else
William Dauchya5194602020-03-28 19:29:58 +01002942 ha_warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
William Dauchy0fec3ab2019-10-27 20:08:11 +01002943 argv[0], global.rlimit_memmax);
Willy Tarreaudc23a922011-02-16 11:10:36 +01002944 }
2945#else
2946 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
William Dauchy0fec3ab2019-10-27 20:08:11 +01002947 if (global.tune.options & GTUNE_STRICT_LIMITS) {
2948 ha_alert("[%s.main()] Cannot fix MEM limit to %d megs.\n",
2949 argv[0], global.rlimit_memmax);
Jerome Magnin50f757c2021-01-12 20:19:38 +01002950 exit(1);
William Dauchy0fec3ab2019-10-27 20:08:11 +01002951 }
2952 else
William Dauchya5194602020-03-28 19:29:58 +01002953 ha_warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
William Dauchy0fec3ab2019-10-27 20:08:11 +01002954 argv[0], global.rlimit_memmax);
Willy Tarreaudc23a922011-02-16 11:10:36 +01002955 }
2956#endif
2957 }
2958
Olivier Houchardf73629d2017-04-05 22:33:04 +02002959 if (old_unixsocket) {
William Lallemand85b0bd92017-06-01 17:38:53 +02002960 if (strcmp("/dev/null", old_unixsocket) != 0) {
Willy Tarreau42961742020-08-28 18:42:45 +02002961 if (sock_get_old_sockets(old_unixsocket) != 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002962 ha_alert("Failed to get the sockets from the old process!\n");
William Lallemand85b0bd92017-06-01 17:38:53 +02002963 if (!(global.mode & MODE_MWORKER))
2964 exit(1);
2965 }
Olivier Houchardf73629d2017-04-05 22:33:04 +02002966 }
2967 }
William Lallemand85b0bd92017-06-01 17:38:53 +02002968 get_cur_unixsocket();
2969
Willy Tarreaubaaee002006-06-26 02:48:02 +02002970 /* We will loop at most 100 times with 10 ms delay each time.
2971 * That's at most 1 second. We only send a signal to old pids
2972 * if we cannot grab at least one port.
2973 */
2974 retry = MAX_START_RETRIES;
2975 err = ERR_NONE;
2976 while (retry >= 0) {
2977 struct timeval w;
Willy Tarreaue91bff22020-09-02 11:11:43 +02002978 err = protocol_bind_all(retry == 0 || nb_oldpids == 0);
Willy Tarreaue13e9252007-12-20 23:05:50 +01002979 /* exit the loop on no error or fatal error */
2980 if ((err & (ERR_RETRYABLE|ERR_FATAL)) != ERR_RETRYABLE)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002981 break;
Willy Tarreaubb545b42010-08-25 12:58:59 +02002982 if (nb_oldpids == 0 || retry == 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002983 break;
2984
2985 /* FIXME-20060514: Solaris and OpenBSD do not support shutdown() on
2986 * listening sockets. So on those platforms, it would be wiser to
2987 * simply send SIGUSR1, which will not be undoable.
2988 */
Willy Tarreaubb545b42010-08-25 12:58:59 +02002989 if (tell_old_pids(SIGTTOU) == 0) {
2990 /* no need to wait if we can't contact old pids */
2991 retry = 0;
2992 continue;
2993 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002994 /* give some time to old processes to stop listening */
2995 w.tv_sec = 0;
2996 w.tv_usec = 10*1000;
2997 select(0, NULL, NULL, NULL, &w);
2998 retry--;
2999 }
3000
Willy Tarreaue91bff22020-09-02 11:11:43 +02003001 /* Note: protocol_bind_all() sends an alert when it fails. */
Willy Tarreau0a3b9d92009-02-04 17:05:23 +01003002 if ((err & ~ERR_WARN) != ERR_NONE) {
Willy Tarreaue91bff22020-09-02 11:11:43 +02003003 ha_alert("[%s.main()] Some protocols failed to start their listeners! Exiting.\n", argv[0]);
Willy Tarreauf68da462009-06-09 14:36:00 +02003004 if (retry != MAX_START_RETRIES && nb_oldpids) {
3005 protocol_unbind_all(); /* cleanup everything we can */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003006 tell_old_pids(SIGTTIN);
Willy Tarreauf68da462009-06-09 14:36:00 +02003007 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003008 exit(1);
3009 }
3010
William Lallemand944e6192018-11-21 15:48:31 +01003011 if (!(global.mode & MODE_MWORKER_WAIT) && listeners == 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003012 ha_alert("[%s.main()] No enabled listener found (check for 'bind' directives) ! Exiting.\n", argv[0]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003013 /* Note: we don't have to send anything to the old pids because we
3014 * never stopped them. */
3015 exit(1);
3016 }
3017
Willy Tarreaue91bff22020-09-02 11:11:43 +02003018 /* Ok, all listeners should now be bound, close any leftover sockets
Olivier Houchardf73629d2017-04-05 22:33:04 +02003019 * the previous process gave us, we don't need them anymore
3020 */
3021 while (xfer_sock_list != NULL) {
3022 struct xfer_sock_list *tmpxfer = xfer_sock_list->next;
3023 close(xfer_sock_list->fd);
3024 free(xfer_sock_list->iface);
3025 free(xfer_sock_list->namespace);
3026 free(xfer_sock_list);
3027 xfer_sock_list = tmpxfer;
3028 }
Willy Tarreaudd815982007-10-16 12:25:14 +02003029
Willy Tarreaubaaee002006-06-26 02:48:02 +02003030 /* prepare pause/play signals */
Willy Tarreau24f4efa2010-08-27 17:56:48 +02003031 signal_register_fct(SIGTTOU, sig_pause, SIGTTOU);
3032 signal_register_fct(SIGTTIN, sig_listen, SIGTTIN);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003033
Willy Tarreaubaaee002006-06-26 02:48:02 +02003034 /* MODE_QUIET can inhibit alerts and warnings below this line */
3035
PiBa-NL149a81a2017-12-25 21:03:31 +01003036 if (getenv("HAPROXY_MWORKER_REEXEC") != NULL) {
3037 /* either stdin/out/err are already closed or should stay as they are. */
3038 if ((global.mode & MODE_DAEMON)) {
3039 /* daemon mode re-executing, stdin/stdout/stderr are already closed so keep quiet */
3040 global.mode &= ~MODE_VERBOSE;
3041 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
3042 }
3043 } else {
3044 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
3045 /* detach from the tty */
William Lallemande1340412017-12-28 16:09:36 +01003046 stdio_quiet(-1);
PiBa-NL149a81a2017-12-25 21:03:31 +01003047 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003048 }
3049
3050 /* open log & pid files before the chroot */
William Lallemand80293002017-11-06 11:00:03 +01003051 if ((global.mode & MODE_DAEMON || global.mode & MODE_MWORKER) && global.pidfile != NULL) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003052 unlink(global.pidfile);
3053 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
3054 if (pidfd < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003055 ha_alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003056 if (nb_oldpids)
3057 tell_old_pids(SIGTTIN);
Willy Tarreaudd815982007-10-16 12:25:14 +02003058 protocol_unbind_all();
Willy Tarreaubaaee002006-06-26 02:48:02 +02003059 exit(1);
3060 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003061 }
3062
Willy Tarreaub38651a2007-03-24 17:24:39 +01003063 if ((global.last_checks & LSTCHK_NETADM) && global.uid) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003064 ha_alert("[%s.main()] Some configuration options require full privileges, so global.uid cannot be changed.\n"
3065 "", argv[0]);
Willy Tarreaudd815982007-10-16 12:25:14 +02003066 protocol_unbind_all();
Willy Tarreaub38651a2007-03-24 17:24:39 +01003067 exit(1);
3068 }
3069
Jackie Tapia749f74c2020-07-22 18:59:40 -05003070 /* If the user is not root, we'll still let them try the configuration
3071 * but we inform them that unexpected behaviour may occur.
Willy Tarreau4e30ed72009-02-04 18:02:48 +01003072 */
3073 if ((global.last_checks & LSTCHK_NETADM) && getuid())
Christopher Faulet767a84b2017-11-24 16:50:31 +01003074 ha_warning("[%s.main()] Some options which require full privileges"
3075 " might not work well.\n"
3076 "", argv[0]);
Willy Tarreau4e30ed72009-02-04 18:02:48 +01003077
William Lallemand095ba4c2017-06-01 17:38:50 +02003078 if ((global.mode & (MODE_MWORKER|MODE_DAEMON)) == 0) {
3079
3080 /* chroot if needed */
3081 if (global.chroot != NULL) {
3082 if (chroot(global.chroot) == -1 || chdir("/") == -1) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003083 ha_alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
William Lallemand095ba4c2017-06-01 17:38:50 +02003084 if (nb_oldpids)
3085 tell_old_pids(SIGTTIN);
3086 protocol_unbind_all();
3087 exit(1);
3088 }
Willy Tarreauf223cc02007-10-15 18:57:08 +02003089 }
Willy Tarreauf223cc02007-10-15 18:57:08 +02003090 }
3091
William Lallemand944e6192018-11-21 15:48:31 +01003092 if (nb_oldpids && !(global.mode & MODE_MWORKER_WAIT))
Willy Tarreaubb545b42010-08-25 12:58:59 +02003093 nb_oldpids = tell_old_pids(oldpids_sig);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003094
William Lallemand27edc4b2019-05-07 17:49:33 +02003095 /* send a SIGTERM to workers who have a too high reloads number */
3096 if ((global.mode & MODE_MWORKER) && !(global.mode & MODE_MWORKER_WAIT))
3097 mworker_kill_max_reloads(SIGTERM);
3098
Willy Tarreaubaaee002006-06-26 02:48:02 +02003099 /* Note that any error at this stage will be fatal because we will not
3100 * be able to restart the old pids.
3101 */
3102
William Dauchyf9af9d72019-11-17 15:47:16 +01003103 if ((global.mode & (MODE_MWORKER | MODE_DAEMON)) == 0)
3104 set_identity(argv[0]);
Willy Tarreau636848a2019-04-15 19:38:50 +02003105
Willy Tarreaubaaee002006-06-26 02:48:02 +02003106 /* check ulimits */
3107 limit.rlim_cur = limit.rlim_max = 0;
3108 getrlimit(RLIMIT_NOFILE, &limit);
3109 if (limit.rlim_cur < global.maxsock) {
William Dauchy0fec3ab2019-10-27 20:08:11 +01003110 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3111 ha_alert("[%s.main()] FD limit (%d) too low for maxconn=%d/maxsock=%d. "
3112 "Please raise 'ulimit-n' to %d or more to avoid any trouble.\n",
3113 argv[0], (int)limit.rlim_cur, global.maxconn, global.maxsock,
3114 global.maxsock);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003115 exit(1);
William Dauchy0fec3ab2019-10-27 20:08:11 +01003116 }
3117 else
3118 ha_alert("[%s.main()] FD limit (%d) too low for maxconn=%d/maxsock=%d. "
William Dauchya5194602020-03-28 19:29:58 +01003119 "Please raise 'ulimit-n' to %d or more to avoid any trouble.\n",
William Dauchy0fec3ab2019-10-27 20:08:11 +01003120 argv[0], (int)limit.rlim_cur, global.maxconn, global.maxsock,
3121 global.maxsock);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003122 }
3123
William Lallemand944e6192018-11-21 15:48:31 +01003124 if (global.mode & (MODE_DAEMON | MODE_MWORKER | MODE_MWORKER_WAIT)) {
Willy Tarreau0b9c02c2009-02-04 22:05:05 +01003125 struct proxy *px;
Willy Tarreauf83d3fe2015-05-01 19:13:41 +02003126 struct peers *curpeers;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003127 int ret = 0;
3128 int proc;
William Lallemande1340412017-12-28 16:09:36 +01003129 int devnullfd = -1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003130
William Lallemand095ba4c2017-06-01 17:38:50 +02003131 /*
3132 * if daemon + mworker: must fork here to let a master
3133 * process live in background before forking children
3134 */
William Lallemand73b85e72017-06-01 17:38:51 +02003135
3136 if ((getenv("HAPROXY_MWORKER_REEXEC") == NULL)
3137 && (global.mode & MODE_MWORKER)
3138 && (global.mode & MODE_DAEMON)) {
William Lallemand095ba4c2017-06-01 17:38:50 +02003139 ret = fork();
3140 if (ret < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003141 ha_alert("[%s.main()] Cannot fork.\n", argv[0]);
William Lallemand095ba4c2017-06-01 17:38:50 +02003142 protocol_unbind_all();
3143 exit(1); /* there has been an error */
William Lallemandbfd8eb52018-07-04 15:31:23 +02003144 } else if (ret > 0) { /* parent leave to daemonize */
William Lallemand095ba4c2017-06-01 17:38:50 +02003145 exit(0);
William Lallemandbfd8eb52018-07-04 15:31:23 +02003146 } else /* change the process group ID in the child (master process) */
3147 setsid();
William Lallemand095ba4c2017-06-01 17:38:50 +02003148 }
William Lallemande20b6a62017-06-01 17:38:55 +02003149
William Lallemande20b6a62017-06-01 17:38:55 +02003150
William Lallemanddeed7802017-11-06 11:00:04 +01003151 /* if in master-worker mode, write the PID of the father */
3152 if (global.mode & MODE_MWORKER) {
3153 char pidstr[100];
Willy Tarreau76a80c72019-06-22 07:41:38 +02003154 snprintf(pidstr, sizeof(pidstr), "%d\n", (int)getpid());
Willy Tarreau46ec48b2018-01-23 19:20:19 +01003155 if (pidfd >= 0)
Willy Tarreau2e8ab6b2020-03-14 11:03:20 +01003156 DISGUISE(write(pidfd, pidstr, strlen(pidstr)));
William Lallemanddeed7802017-11-06 11:00:04 +01003157 }
3158
Willy Tarreaubaaee002006-06-26 02:48:02 +02003159 /* the father launches the required number of processes */
William Lallemand944e6192018-11-21 15:48:31 +01003160 if (!(global.mode & MODE_MWORKER_WAIT)) {
William Lallemand9a1ee7a2019-04-01 11:30:02 +02003161 if (global.mode & MODE_MWORKER)
3162 mworker_ext_launch_all();
William Lallemand944e6192018-11-21 15:48:31 +01003163 for (proc = 0; proc < global.nbproc; proc++) {
3164 ret = fork();
3165 if (ret < 0) {
3166 ha_alert("[%s.main()] Cannot fork.\n", argv[0]);
3167 protocol_unbind_all();
3168 exit(1); /* there has been an error */
3169 }
Willy Tarreau52bf8392020-03-08 00:42:37 +01003170 else if (ret == 0) { /* child breaks here */
Willy Tarreaua9274a12021-07-21 10:17:02 +02003171 /* This one must not be exported, it's internal! */
3172 unsetenv("HAPROXY_MWORKER_REEXEC");
Willy Tarreau52bf8392020-03-08 00:42:37 +01003173 ha_random_jump96(relative_pid);
William Lallemand944e6192018-11-21 15:48:31 +01003174 break;
Willy Tarreau52bf8392020-03-08 00:42:37 +01003175 }
William Lallemand944e6192018-11-21 15:48:31 +01003176 if (pidfd >= 0 && !(global.mode & MODE_MWORKER)) {
3177 char pidstr[100];
3178 snprintf(pidstr, sizeof(pidstr), "%d\n", ret);
Willy Tarreau2e8ab6b2020-03-14 11:03:20 +01003179 DISGUISE(write(pidfd, pidstr, strlen(pidstr)));
William Lallemand944e6192018-11-21 15:48:31 +01003180 }
3181 if (global.mode & MODE_MWORKER) {
3182 struct mworker_proc *child;
William Lallemandce83b4a2018-10-26 14:47:30 +02003183
William Lallemand220567e2018-11-21 18:04:53 +01003184 ha_notice("New worker #%d (%d) forked\n", relative_pid, ret);
William Lallemand944e6192018-11-21 15:48:31 +01003185 /* find the right mworker_proc */
3186 list_for_each_entry(child, &proc_list, list) {
3187 if (child->relative_pid == relative_pid &&
William Lallemand8f7069a2019-04-12 16:09:23 +02003188 child->reloads == 0 && child->options & PROC_O_TYPE_WORKER) {
William Lallemand944e6192018-11-21 15:48:31 +01003189 child->timestamp = now.tv_sec;
3190 child->pid = ret;
William Lallemand1dc69632019-06-12 19:11:33 +02003191 child->version = strdup(haproxy_version);
William Lallemand944e6192018-11-21 15:48:31 +01003192 break;
3193 }
William Lallemandce83b4a2018-10-26 14:47:30 +02003194 }
3195 }
William Lallemandbc193052018-09-11 10:06:26 +02003196
William Lallemand944e6192018-11-21 15:48:31 +01003197 relative_pid++; /* each child will get a different one */
3198 pid_bit <<= 1;
3199 }
3200 } else {
3201 /* wait mode */
3202 global.nbproc = 1;
3203 proc = 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003204 }
Willy Tarreaufc6c0322012-11-16 16:12:27 +01003205
3206#ifdef USE_CPU_AFFINITY
3207 if (proc < global.nbproc && /* child */
Willy Tarreauff9c9142019-02-07 10:39:36 +01003208 proc < MAX_PROCS && /* only the first 32/64 processes may be pinned */
Amaury Denoyellefc6ac532021-04-27 10:46:36 +02003209 ha_cpuset_count(&cpu_map.proc[proc])) { /* only do this if the process has a CPU map */
Olivier Houchard97148f62017-08-16 17:29:11 +02003210
Amaury Denoyelle982fb532021-04-21 18:39:58 +02003211#ifdef __FreeBSD__
Amaury Denoyellefc6ac532021-04-27 10:46:36 +02003212 struct hap_cpuset *set = &cpu_map.proc[proc];
Amaury Denoyelle982fb532021-04-21 18:39:58 +02003213 ret = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(set->cpuset), &set->cpuset);
David Carlier2d0493a2020-12-02 21:14:51 +00003214#elif defined(__linux__) || defined(__DragonFly__)
Amaury Denoyellefc6ac532021-04-27 10:46:36 +02003215 struct hap_cpuset *set = &cpu_map.proc[proc];
Amaury Denoyelle982fb532021-04-21 18:39:58 +02003216 sched_setaffinity(0, sizeof(set->cpuset), &set->cpuset);
Willy Tarreaufc6c0322012-11-16 16:12:27 +01003217#endif
Amaury Denoyelle982fb532021-04-21 18:39:58 +02003218 }
Pieter Baauwcaa6a1b2015-09-17 21:26:40 +02003219#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02003220 /* close the pidfile both in children and father */
Willy Tarreau269ab312012-09-05 08:02:48 +02003221 if (pidfd >= 0) {
3222 //lseek(pidfd, 0, SEEK_SET); /* debug: emulate eglibc bug */
3223 close(pidfd);
3224 }
Willy Tarreaud137dd32010-08-25 12:49:05 +02003225
3226 /* We won't ever use this anymore */
Willy Tarreau61cfdf42021-02-20 10:46:51 +01003227 ha_free(&global.pidfile);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003228
Willy Tarreauedaff0a2015-05-01 17:01:08 +02003229 if (proc == global.nbproc) {
William Lallemand944e6192018-11-21 15:48:31 +01003230 if (global.mode & (MODE_MWORKER|MODE_MWORKER_WAIT)) {
PiBa-NLbaf6ea42017-11-28 23:26:08 +01003231
3232 if ((!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
3233 (global.mode & MODE_DAEMON)) {
3234 /* detach from the tty, this is required to properly daemonize. */
William Lallemande1340412017-12-28 16:09:36 +01003235 if ((getenv("HAPROXY_MWORKER_REEXEC") == NULL))
3236 stdio_quiet(-1);
3237
PiBa-NLbaf6ea42017-11-28 23:26:08 +01003238 global.mode &= ~MODE_VERBOSE;
3239 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
PiBa-NLbaf6ea42017-11-28 23:26:08 +01003240 }
3241
William Lallemandb3f2be32018-09-11 10:06:18 +02003242 mworker_loop();
William Lallemand1499b9b2017-06-07 15:04:47 +02003243 /* should never get there */
3244 exit(EXIT_FAILURE);
Willy Tarreauedaff0a2015-05-01 17:01:08 +02003245 }
William Lallemandcf4e4962017-06-08 19:05:48 +02003246#if defined(USE_OPENSSL) && !defined(OPENSSL_NO_DH)
Grant Zhang872f9c22017-01-21 01:10:18 +00003247 ssl_free_dh();
3248#endif
William Lallemand1499b9b2017-06-07 15:04:47 +02003249 exit(0); /* parent must leave */
Willy Tarreauedaff0a2015-05-01 17:01:08 +02003250 }
3251
William Lallemandcb11fd22017-06-01 17:38:52 +02003252 /* child must never use the atexit function */
3253 atexit_flag = 0;
3254
William Lallemandbc193052018-09-11 10:06:26 +02003255 /* close useless master sockets */
3256 if (global.mode & MODE_MWORKER) {
3257 struct mworker_proc *child, *it;
3258 master = 0;
3259
William Lallemand309dc9a2018-10-26 14:47:45 +02003260 mworker_cli_proxy_stop();
3261
William Lallemandbc193052018-09-11 10:06:26 +02003262 /* free proc struct of other processes */
3263 list_for_each_entry_safe(child, it, &proc_list, list) {
William Lallemandce83b4a2018-10-26 14:47:30 +02003264 /* close the FD of the master side for all
3265 * workers, we don't need to close the worker
3266 * side of other workers since it's done with
3267 * the bind_proc */
Tim Duesterhus742e0f92018-11-25 20:03:39 +01003268 if (child->ipc_fd[0] >= 0)
3269 close(child->ipc_fd[0]);
William Lallemandce83b4a2018-10-26 14:47:30 +02003270 if (child->relative_pid == relative_pid &&
3271 child->reloads == 0) {
3272 /* keep this struct if this is our pid */
3273 proc_self = child;
William Lallemandbc193052018-09-11 10:06:26 +02003274 continue;
William Lallemandce83b4a2018-10-26 14:47:30 +02003275 }
Willy Tarreau2b718102021-04-21 07:32:39 +02003276 LIST_DELETE(&child->list);
Tim Duesterhus9b7a9762019-05-16 20:23:22 +02003277 mworker_free_child(child);
3278 child = NULL;
William Lallemandbc193052018-09-11 10:06:26 +02003279 }
3280 }
Willy Tarreau1605c7a2018-01-23 19:01:49 +01003281
William Lallemande1340412017-12-28 16:09:36 +01003282 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
3283 devnullfd = open("/dev/null", O_RDWR, 0);
3284 if (devnullfd < 0) {
3285 ha_alert("Cannot open /dev/null\n");
3286 exit(EXIT_FAILURE);
3287 }
3288 }
3289
William Lallemand095ba4c2017-06-01 17:38:50 +02003290 /* Must chroot and setgid/setuid in the children */
3291 /* chroot if needed */
3292 if (global.chroot != NULL) {
3293 if (chroot(global.chroot) == -1 || chdir("/") == -1) {
Willy Tarreau46317372021-06-15 08:59:19 +02003294 ha_alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
William Lallemand095ba4c2017-06-01 17:38:50 +02003295 if (nb_oldpids)
3296 tell_old_pids(SIGTTIN);
3297 protocol_unbind_all();
3298 exit(1);
3299 }
3300 }
3301
Willy Tarreau61cfdf42021-02-20 10:46:51 +01003302 ha_free(&global.chroot);
William Dauchyf9af9d72019-11-17 15:47:16 +01003303 set_identity(argv[0]);
William Lallemand095ba4c2017-06-01 17:38:50 +02003304
William Lallemand7f80eb22017-05-26 18:19:55 +02003305 /* pass through every cli socket, and check if it's bound to
3306 * the current process and if it exposes listeners sockets.
3307 * Caution: the GTUNE_SOCKET_TRANSFER is now set after the fork.
3308 * */
3309
Willy Tarreau4975d142021-03-13 11:00:33 +01003310 if (global.cli_fe) {
William Lallemand7f80eb22017-05-26 18:19:55 +02003311 struct bind_conf *bind_conf;
3312
Willy Tarreau4975d142021-03-13 11:00:33 +01003313 list_for_each_entry(bind_conf, &global.cli_fe->conf.bind, by_fe) {
William Lallemand7f80eb22017-05-26 18:19:55 +02003314 if (bind_conf->level & ACCESS_FD_LISTENERS) {
Willy Tarreaue26993c2020-09-03 07:18:55 +02003315 if (!bind_conf->settings.bind_proc || bind_conf->settings.bind_proc & (1UL << proc)) {
William Lallemand7f80eb22017-05-26 18:19:55 +02003316 global.tune.options |= GTUNE_SOCKET_TRANSFER;
3317 break;
3318 }
3319 }
3320 }
3321 }
3322
Willy Tarreau0b9c02c2009-02-04 22:05:05 +01003323 /* we might have to unbind some proxies from some processes */
Olivier Houchardfbc74e82017-11-24 16:54:05 +01003324 px = proxies_list;
Willy Tarreau0b9c02c2009-02-04 22:05:05 +01003325 while (px != NULL) {
Willy Tarreauc3914d42020-09-24 08:39:22 +02003326 if (px->bind_proc && !px->disabled) {
Willy Tarreau337c8352020-09-24 10:51:29 +02003327 if (!(px->bind_proc & (1UL << proc)))
3328 stop_proxy(px);
Willy Tarreau0b9c02c2009-02-04 22:05:05 +01003329 }
3330 px = px->next;
3331 }
3332
Emeric Brunc47ba592020-10-07 10:13:10 +02003333 /* we might have to unbind some log forward proxies from some processes */
3334 px = cfg_log_forward;
3335 while (px != NULL) {
Willy Tarreauc3914d42020-09-24 08:39:22 +02003336 if (px->bind_proc && !px->disabled) {
Willy Tarreau337c8352020-09-24 10:51:29 +02003337 if (!(px->bind_proc & (1UL << proc)))
3338 stop_proxy(px);
Emeric Brunc47ba592020-10-07 10:13:10 +02003339 }
3340 px = px->next;
3341 }
3342
Willy Tarreauf83d3fe2015-05-01 19:13:41 +02003343 /* we might have to unbind some peers sections from some processes */
Frédéric Lécailleed2b4a62017-07-13 09:07:09 +02003344 for (curpeers = cfg_peers; curpeers; curpeers = curpeers->next) {
Willy Tarreauf83d3fe2015-05-01 19:13:41 +02003345 if (!curpeers->peers_fe)
3346 continue;
3347
3348 if (curpeers->peers_fe->bind_proc & (1UL << proc))
3349 continue;
3350
3351 stop_proxy(curpeers->peers_fe);
3352 /* disable this peer section so that it kills itself */
Willy Tarreau47c8c022015-09-28 16:39:25 +02003353 signal_unregister_handler(curpeers->sighandler);
Olivier Houchard3f795f72019-04-17 22:51:06 +02003354 task_destroy(curpeers->sync_task);
Willy Tarreau47c8c022015-09-28 16:39:25 +02003355 curpeers->sync_task = NULL;
Olivier Houchard3f795f72019-04-17 22:51:06 +02003356 task_destroy(curpeers->peers_fe->task);
Willy Tarreau47c8c022015-09-28 16:39:25 +02003357 curpeers->peers_fe->task = NULL;
Willy Tarreauf83d3fe2015-05-01 19:13:41 +02003358 curpeers->peers_fe = NULL;
3359 }
3360
William Lallemand2e8fad92018-11-13 16:18:23 +01003361 /*
3362 * This is only done in daemon mode because we might want the
3363 * logs on stdout in mworker mode. If we're NOT in QUIET mode,
3364 * we should now close the 3 first FDs to ensure that we can
3365 * detach from the TTY. We MUST NOT do it in other cases since
3366 * it would have already be done, and 0-2 would have been
3367 * affected to listening sockets
Willy Tarreaubaaee002006-06-26 02:48:02 +02003368 */
William Lallemand2e8fad92018-11-13 16:18:23 +01003369 if ((global.mode & MODE_DAEMON) &&
3370 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003371 /* detach from the tty */
William Lallemande1340412017-12-28 16:09:36 +01003372 stdio_quiet(devnullfd);
Willy Tarreau106cb762008-11-16 07:40:34 +01003373 global.mode &= ~MODE_VERBOSE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003374 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
3375 }
3376 pid = getpid(); /* update child's pid */
William Lallemandbfd8eb52018-07-04 15:31:23 +02003377 if (!(global.mode & MODE_MWORKER)) /* in mworker mode we don't want a new pgid for the children */
3378 setsid();
Willy Tarreau2ff76222007-04-09 19:29:56 +02003379 fork_poller();
Willy Tarreaubaaee002006-06-26 02:48:02 +02003380 }
3381
William Dauchye039f262019-11-17 15:47:15 +01003382 /* try our best to re-enable core dumps depending on system capabilities.
3383 * What is addressed here :
3384 * - remove file size limits
3385 * - remove core size limits
3386 * - mark the process dumpable again if it lost it due to user/group
3387 */
3388 if (global.tune.options & GTUNE_SET_DUMPABLE) {
3389 limit.rlim_cur = limit.rlim_max = RLIM_INFINITY;
3390
3391#if defined(RLIMIT_FSIZE)
3392 if (setrlimit(RLIMIT_FSIZE, &limit) == -1) {
3393 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3394 ha_alert("[%s.main()] Failed to set the raise the maximum "
3395 "file size.\n", argv[0]);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003396 exit(1);
William Dauchye039f262019-11-17 15:47:15 +01003397 }
3398 else
3399 ha_warning("[%s.main()] Failed to set the raise the maximum "
William Dauchya5194602020-03-28 19:29:58 +01003400 "file size.\n", argv[0]);
William Dauchye039f262019-11-17 15:47:15 +01003401 }
3402#endif
3403
3404#if defined(RLIMIT_CORE)
3405 if (setrlimit(RLIMIT_CORE, &limit) == -1) {
3406 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3407 ha_alert("[%s.main()] Failed to set the raise the core "
3408 "dump size.\n", argv[0]);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003409 exit(1);
William Dauchye039f262019-11-17 15:47:15 +01003410 }
3411 else
3412 ha_warning("[%s.main()] Failed to set the raise the core "
William Dauchya5194602020-03-28 19:29:58 +01003413 "dump size.\n", argv[0]);
William Dauchye039f262019-11-17 15:47:15 +01003414 }
3415#endif
3416
3417#if defined(USE_PRCTL)
3418 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1)
3419 ha_warning("[%s.main()] Failed to set the dumpable flag, "
3420 "no core will be dumped.\n", argv[0]);
3421#endif
3422 }
3423
Christopher Faulete3a5e352017-10-24 13:53:54 +02003424 global.mode &= ~MODE_STARTING;
Willy Tarreau4f60f162007-04-08 16:39:58 +02003425 /*
3426 * That's it : the central polling loop. Run until we stop.
3427 */
Christopher Faulet1d17c102017-08-29 15:38:48 +02003428#ifdef USE_THREAD
Christopher Fauletcd7879a2017-10-27 13:53:47 +02003429 {
William Lallemand1aab50b2018-06-07 09:46:01 +02003430 sigset_t blocked_sig, old_sig;
Willy Tarreauc40efc12019-05-03 09:22:44 +02003431 int i;
3432
William Lallemand1aab50b2018-06-07 09:46:01 +02003433 /* ensure the signals will be blocked in every thread */
3434 sigfillset(&blocked_sig);
3435 sigdelset(&blocked_sig, SIGPROF);
3436 sigdelset(&blocked_sig, SIGBUS);
3437 sigdelset(&blocked_sig, SIGFPE);
3438 sigdelset(&blocked_sig, SIGILL);
3439 sigdelset(&blocked_sig, SIGSEGV);
3440 pthread_sigmask(SIG_SETMASK, &blocked_sig, &old_sig);
3441
Christopher Fauletcd7879a2017-10-27 13:53:47 +02003442 /* Create nbthread-1 thread. The first thread is the current process */
David Carliera92c5ce2019-09-13 05:03:12 +01003443 ha_thread_info[0].pthread = pthread_self();
Christopher Fauletcd7879a2017-10-27 13:53:47 +02003444 for (i = 1; i < global.nbthread; i++)
David Carliera92c5ce2019-09-13 05:03:12 +01003445 pthread_create(&ha_thread_info[i].pthread, NULL, &run_thread_poll_loop, (void *)(long)i);
Christopher Fauletcd7879a2017-10-27 13:53:47 +02003446
Christopher Faulet62519022017-10-16 15:49:32 +02003447#ifdef USE_CPU_AFFINITY
Christopher Fauletcd7879a2017-10-27 13:53:47 +02003448 /* Now the CPU affinity for all threads */
Amaury Denoyelleaf02c572021-04-15 16:29:58 +02003449
3450 /* If on multiprocess, use proc_t1 except for the first process.
3451 */
3452 if ((relative_pid - 1) > 0)
Amaury Denoyellefc6ac532021-04-27 10:46:36 +02003453 cpu_map.thread[0] = cpu_map.proc_t1[relative_pid-1];
Willy Tarreau7764a572019-07-16 15:10:34 +02003454
Christopher Fauletcd7879a2017-10-27 13:53:47 +02003455 for (i = 0; i < global.nbthread; i++) {
Amaury Denoyellefc6ac532021-04-27 10:46:36 +02003456 if (ha_cpuset_count(&cpu_map.proc[relative_pid-1]))
3457 ha_cpuset_and(&cpu_map.thread[i], &cpu_map.proc[relative_pid-1]);
Christopher Faulet62519022017-10-16 15:49:32 +02003458
Willy Tarreau421f02e2018-01-20 18:19:22 +01003459 if (i < MAX_THREADS && /* only the first 32/64 threads may be pinned */
Amaury Denoyellefc6ac532021-04-27 10:46:36 +02003460 ha_cpuset_count(&cpu_map.thread[i])) {/* only do this if the thread has a THREAD map */
David Carlier5e4c8e22019-09-13 05:12:58 +01003461#if defined(__APPLE__)
3462 int j;
Amaury Denoyelle8f685c12021-04-27 16:45:29 +02003463 unsigned long set = cpu_map.thread[i].cpuset;
David Carlier5e4c8e22019-09-13 05:12:58 +01003464
Amaury Denoyelle8f685c12021-04-27 16:45:29 +02003465 while ((j = ffsl(set)) > 0) {
David Carlier5e4c8e22019-09-13 05:12:58 +01003466 thread_affinity_policy_data_t cpu_set = { j - 1 };
3467 thread_port_t mthread = pthread_mach_thread_np(ha_thread_info[i].pthread);
3468 thread_policy_set(mthread, THREAD_AFFINITY_POLICY, (thread_policy_t)&cpu_set, 1);
Amaury Denoyelle8f685c12021-04-27 16:45:29 +02003469 set &= ~(1UL << (j - 1));
David Carlier5e4c8e22019-09-13 05:12:58 +01003470 }
3471#else
Amaury Denoyellefc6ac532021-04-27 10:46:36 +02003472 struct hap_cpuset *set = &cpu_map.thread[i];
David Carliera92c5ce2019-09-13 05:03:12 +01003473 pthread_setaffinity_np(ha_thread_info[i].pthread,
Amaury Denoyelle982fb532021-04-21 18:39:58 +02003474 sizeof(set->cpuset), &set->cpuset);
David Carlier5e4c8e22019-09-13 05:12:58 +01003475#endif
Olivier Houchard829aa242017-12-01 18:19:43 +01003476 }
Christopher Faulet1d17c102017-08-29 15:38:48 +02003477 }
Christopher Fauletcd7879a2017-10-27 13:53:47 +02003478#endif /* !USE_CPU_AFFINITY */
3479
William Lallemand1aab50b2018-06-07 09:46:01 +02003480 /* when multithreading we need to let only the thread 0 handle the signals */
William Lallemandd3801c12018-09-11 10:06:23 +02003481 haproxy_unblock_signals();
William Lallemand1aab50b2018-06-07 09:46:01 +02003482
Christopher Fauletcd7879a2017-10-27 13:53:47 +02003483 /* Finally, start the poll loop for the first thread */
Willy Tarreaub4f7cc32019-05-03 09:27:30 +02003484 run_thread_poll_loop(0);
Christopher Fauletcd7879a2017-10-27 13:53:47 +02003485
3486 /* Wait the end of other threads */
3487 for (i = 1; i < global.nbthread; i++)
David Carliera92c5ce2019-09-13 05:03:12 +01003488 pthread_join(ha_thread_info[i].pthread, NULL);
Christopher Faulet1d17c102017-08-29 15:38:48 +02003489
Christopher Fauletb79a94c2017-05-30 15:34:30 +02003490#if defined(DEBUG_THREAD) || defined(DEBUG_FULL)
3491 show_lock_stats();
3492#endif
Christopher Faulet1d17c102017-08-29 15:38:48 +02003493 }
Christopher Fauletcd7879a2017-10-27 13:53:47 +02003494#else /* ! USE_THREAD */
William Lallemandd3801c12018-09-11 10:06:23 +02003495 haproxy_unblock_signals();
Willy Tarreaub4f7cc32019-05-03 09:27:30 +02003496 run_thread_poll_loop(0);
Christopher Faulet62519022017-10-16 15:49:32 +02003497#endif
Christopher Faulet1d17c102017-08-29 15:38:48 +02003498
Tim Duesterhus0a3b43d2020-06-14 00:37:42 +02003499 deinit_and_exit(0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003500}
3501
Willy Tarreaubaaee002006-06-26 02:48:02 +02003502/*
3503 * Local variables:
3504 * c-indent-level: 8
3505 * c-basic-offset: 8
3506 * End:
3507 */