blob: 481fe5a0ea72547f83dc6c9c33fcb4778da84133 [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 Tarreau40c88f92023-01-07 09:45:17 +01003 * Copyright 2000-2023 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 Tarreaud10385a2021-10-06 22:22:40 +020053
Willy Tarreau5e03dfa2021-10-06 22:53:51 +020054#ifdef USE_THREAD
55#include <pthread.h>
56#endif
57
Willy Tarreaufc6c0322012-11-16 16:12:27 +010058#ifdef USE_CPU_AFFINITY
Willy Tarreaufc6c0322012-11-16 16:12:27 +010059#include <sched.h>
David Carlier42d9e5a2018-11-12 16:22:19 +000060#if defined(__FreeBSD__) || defined(__DragonFly__)
Pieter Baauwcaa6a1b2015-09-17 21:26:40 +020061#include <sys/param.h>
David Carlier42d9e5a2018-11-12 16:22:19 +000062#ifdef __FreeBSD__
Pieter Baauwcaa6a1b2015-09-17 21:26:40 +020063#include <sys/cpuset.h>
David Carlier42d9e5a2018-11-12 16:22:19 +000064#endif
David Carlier5e4c8e22019-09-13 05:12:58 +010065#endif
Willy Tarreaufc6c0322012-11-16 16:12:27 +010066#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +020067
Willy Tarreau636848a2019-04-15 19:38:50 +020068#if defined(USE_PRCTL)
69#include <sys/prctl.h>
70#endif
71
devnexen@gmail.com21185972021-08-21 09:13:10 +010072#if defined(USE_PROCCTL)
73#include <sys/procctl.h>
74#endif
75
Willy Tarreaubaaee002006-06-26 02:48:02 +020076#ifdef DEBUG_FULL
77#include <assert.h>
78#endif
Tim Duesterhusd6942c82017-11-20 15:58:35 +010079#if defined(USE_SYSTEMD)
80#include <systemd/sd-daemon.h>
81#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +020082
Willy Tarreau6c3a6812020-03-06 18:57:15 +010083#include <import/sha1.h>
84
Willy Tarreaub2551052020-06-09 09:07:15 +020085#include <haproxy/acl.h>
Amaury Denoyelle68fd7e42021-03-25 17:15:52 +010086#include <haproxy/action.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020087#include <haproxy/activity.h>
88#include <haproxy/api.h>
89#include <haproxy/arg.h>
90#include <haproxy/auth.h>
Willy Tarreau8d366972020-05-27 16:10:29 +020091#include <haproxy/base64.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020092#include <haproxy/capture-t.h>
Willy Tarreau66243b42021-07-16 15:39:28 +020093#include <haproxy/cfgcond.h>
Amaury Denoyelle5a6926d2021-03-30 17:34:24 +020094#include <haproxy/cfgdiag.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020095#include <haproxy/cfgparse.h>
Willy Tarreauc13ed532020-06-02 10:22:45 +020096#include <haproxy/chunk.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020097#include <haproxy/cli.h>
Willy Tarreau55542642021-10-08 09:33:24 +020098#include <haproxy/clock.h>
Willy Tarreau7ea393d2020-06-04 18:02:10 +020099#include <haproxy/connection.h>
Amaury Denoyellea6f9c5d2021-04-23 16:58:08 +0200100#ifdef USE_CPU_AFFINITY
Amaury Denoyelle982fb532021-04-21 18:39:58 +0200101#include <haproxy/cpuset.h>
Amaury Denoyellea6f9c5d2021-04-23 16:58:08 +0200102#endif
Willy Tarreaueb92deb2020-06-04 10:53:16 +0200103#include <haproxy/dns.h>
Willy Tarreau2741c8c2020-06-02 11:28:02 +0200104#include <haproxy/dynbuf.h>
Willy Tarreau8d366972020-05-27 16:10:29 +0200105#include <haproxy/errors.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200106#include <haproxy/fd.h>
Willy Tarreauc7babd82020-06-04 21:29:29 +0200107#include <haproxy/filters.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200108#include <haproxy/global.h>
Willy Tarreau86416052020-06-04 09:20:54 +0200109#include <haproxy/hlua.h>
Willy Tarreauc761f842020-06-04 11:40:28 +0200110#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +0200111#include <haproxy/list.h>
Willy Tarreau213e9902020-06-04 14:58:24 +0200112#include <haproxy/listener.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +0200113#include <haproxy/log.h>
Willy Tarreaub5abe5b2020-06-04 14:07:37 +0200114#include <haproxy/mworker.h>
Willy Tarreau7a00efb2020-06-02 17:02:59 +0200115#include <haproxy/namespace.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +0200116#include <haproxy/net_helper.h>
Willy Tarreau6019fab2020-05-27 16:26:00 +0200117#include <haproxy/openssl-compat.h>
Amaury Denoyelle92fa63f2022-09-30 18:11:13 +0200118#include <haproxy/quic_conn-t.h>
Frédéric Lécaille1d96d6e2022-05-23 16:38:14 +0200119#include <haproxy/quic_tp-t.h>
Willy Tarreau225a90a2020-06-04 15:06:28 +0200120#include <haproxy/pattern.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +0200121#include <haproxy/peers.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200122#include <haproxy/pool.h>
123#include <haproxy/protocol.h>
Willy Tarreaubf3b06b2020-08-26 10:23:40 +0200124#include <haproxy/proto_tcp.h>
Willy Tarreaua264d962020-06-04 22:29:18 +0200125#include <haproxy/proxy.h>
Willy Tarreau7cd8b6e2020-06-02 17:32:26 +0200126#include <haproxy/regex.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200127#include <haproxy/sample.h>
Willy Tarreau1e56f922020-06-04 23:20:13 +0200128#include <haproxy/server.h>
Willy Tarreau48d25b32020-06-04 18:58:52 +0200129#include <haproxy/session.h>
Willy Tarreau3727a8a2020-06-04 17:37:26 +0200130#include <haproxy/signal.h>
Willy Tarreau063d47d2020-08-28 16:29:53 +0200131#include <haproxy/sock.h>
Willy Tarreau25140cc2020-08-28 15:40:33 +0200132#include <haproxy/sock_inet.h>
Willy Tarreau209108d2020-06-04 20:30:20 +0200133#include <haproxy/ssl_sock.h>
Amaury Denoyelleee63d4b2020-10-05 11:49:42 +0200134#include <haproxy/stats-t.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +0200135#include <haproxy/stream.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +0200136#include <haproxy/task.h>
Willy Tarreau3f567e42020-05-28 15:29:19 +0200137#include <haproxy/thread.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200138#include <haproxy/time.h>
139#include <haproxy/tools.h>
140#include <haproxy/uri_auth-t.h>
Willy Tarreaua1718922020-06-04 16:25:31 +0200141#include <haproxy/vars.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200142#include <haproxy/version.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +0200143
Willy Tarreaubaaee002006-06-26 02:48:02 +0200144
Willy Tarreau7b5654f2019-03-29 21:30:17 +0100145/* array of init calls for older platforms */
146DECLARE_INIT_STAGES;
147
Willy Tarreauf4596402021-04-10 16:53:05 +0200148/* create a read_mostly section to hold variables which are accessed a lot
149 * but which almost never change. The purpose is to isolate them in their
150 * own cache lines where they don't risk to be perturbated by write accesses
151 * to neighbor variables. We need to create an empty aligned variable for
152 * this. The fact that the variable is of size zero means that it will be
153 * eliminated at link time if no other variable uses it, but alignment will
154 * be respected.
155 */
156empty_t __read_mostly_align HA_SECTION("read_mostly") ALIGNED(64);
157
Willy Tarreauf0d3b732021-05-06 16:30:32 +0200158#ifdef BUILD_FEATURES
159const char *build_features = BUILD_FEATURES;
160#else
161const char *build_features = "";
162#endif
163
Willy Tarreau477ecd82010-01-03 21:12:30 +0100164/* list of config files */
165static struct list cfg_cfgfiles = LIST_HEAD_INIT(cfg_cfgfiles);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200166int pid; /* current process id */
167
Willy Tarreauef422ce2022-06-28 19:29:29 +0200168static unsigned long stopping_tgroup_mask; /* Thread groups acknowledging stopping */
Willy Tarreauf8ea00e2020-03-12 17:24:53 +0100169
Willy Tarreaubaaee002006-06-26 02:48:02 +0200170/* global options */
171struct global global = {
Cyril Bonté203ec5a2017-03-23 22:44:13 +0100172 .hard_stop_after = TICK_ETERNITY,
Remi Tricot-Le Bretonb5d968d2022-04-08 18:04:18 +0200173 .close_spread_time = TICK_ETERNITY,
174 .close_spread_end = TICK_ETERNITY,
Amaury Denoyelle0f50cb92021-03-26 18:50:33 +0100175 .numa_cpu_mapping = 1,
Willy Tarreau149ab772019-01-26 14:27:06 +0100176 .nbthread = 0,
William Lallemand5f232402012-04-05 18:02:55 +0200177 .req_count = 0,
William Lallemand0f99e342011-10-12 17:50:54 +0200178 .logsrvs = LIST_HEAD_INIT(global.logsrvs),
Willy Tarreau197715a2022-04-25 19:29:10 +0200179 .maxzlibmem = DEFAULT_MAXZLIBMEM * 1024U * 1024U,
William Lallemandd85f9172012-11-09 17:05:39 +0100180 .comp_rate_lim = 0,
Emeric Brun850efd52014-01-29 12:24:34 +0100181 .ssl_server_verify = SSL_SERVER_VERIFY_REQUIRED,
Emeric Bruned760922010-10-22 17:59:25 +0200182 .unix_bind = {
183 .ux = {
184 .uid = -1,
185 .gid = -1,
186 .mode = 0,
187 }
188 },
Willy Tarreau27a674e2009-08-17 07:23:33 +0200189 .tune = {
Willy Tarreau7ac908b2019-02-27 12:02:18 +0100190 .options = GTUNE_LISTENER_MQ,
Willy Tarreauc77d3642018-12-12 06:19:42 +0100191 .bufsize = (BUFSIZE + 2*sizeof(void *) - 1) & -(2*sizeof(void *)),
Christopher Faulet546c4692020-01-22 14:31:21 +0100192 .maxrewrite = MAXREWRITE,
Willy Tarreaua24adf02014-11-27 01:11:56 +0100193 .reserved_bufs = RESERVED_BUFS,
Willy Tarreauf3045d22015-04-29 16:24:50 +0200194 .pattern_cache = DEFAULT_PAT_LRU_SIZE,
Olivier Houchard88698d92019-04-16 19:07:22 +0200195 .pool_low_ratio = 20,
196 .pool_high_ratio = 25,
Christopher Faulet41ba36f2019-07-19 09:36:45 +0200197 .max_http_hdr = MAX_HTTP_HDR,
Emeric Brunfc32aca2012-09-03 12:10:29 +0200198#ifdef USE_OPENSSL
Emeric Brun46635772012-11-14 11:32:56 +0100199 .sslcachesize = SSLCACHESIZE,
Emeric Brunfc32aca2012-09-03 12:10:29 +0200200#endif
William Lallemandf3747832012-11-09 12:33:10 +0100201 .comp_maxlevel = 1,
Willy Tarreau7e312732014-02-12 16:35:14 +0100202#ifdef DEFAULT_IDLE_TIMER
203 .idle_timer = DEFAULT_IDLE_TIMER,
204#else
205 .idle_timer = 1000, /* 1 second */
206#endif
Willy Tarreau6c011712023-01-06 16:09:58 +0100207 .nb_stk_ctr = MAX_SESS_STKCTR,
Amaury Denoyelle97e84c62022-04-19 18:26:55 +0200208#ifdef USE_QUIC
Frédéric Lécailleaee67572022-05-23 18:29:39 +0200209 .quic_backend_max_idle_timeout = QUIC_TP_DFLT_BACK_MAX_IDLE_TIMEOUT,
210 .quic_frontend_max_idle_timeout = QUIC_TP_DFLT_FRONT_MAX_IDLE_TIMEOUT,
211 .quic_frontend_max_streams_bidi = QUIC_TP_DFLT_FRONT_MAX_STREAMS_BIDI,
Frédéric Lécaille92862102022-05-20 16:29:10 +0200212 .quic_retry_threshold = QUIC_DFLT_RETRY_THRESHOLD,
Amaury Denoyelle97e84c62022-04-19 18:26:55 +0200213 .quic_streams_buf = 30,
214#endif /* USE_QUIC */
Willy Tarreau27a674e2009-08-17 07:23:33 +0200215 },
Emeric Brun76d88952012-10-05 15:47:31 +0200216#ifdef USE_OPENSSL
217#ifdef DEFAULT_MAXSSLCONN
Willy Tarreau403edff2012-09-06 11:58:37 +0200218 .maxsslconn = DEFAULT_MAXSSLCONN,
219#endif
Emeric Brun76d88952012-10-05 15:47:31 +0200220#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +0200221 /* others NULL OK */
222};
223
224/*********************************************************************/
225
226int stopping; /* non zero means stopping in progress */
Cyril Bonté203ec5a2017-03-23 22:44:13 +0100227int killed; /* non zero means a hard-stop is triggered */
Willy Tarreauaf7ad002010-08-31 15:39:26 +0200228int jobs = 0; /* number of active jobs (conns, listeners, active tasks, ...) */
William Lallemanda7199262018-11-16 16:57:20 +0100229int unstoppable_jobs = 0; /* number of active jobs that can't be stopped during a soft stop */
Willy Tarreau199ad242018-11-05 16:31:22 +0100230int active_peers = 0; /* number of active peers (connection attempts and connected) */
Willy Tarreau2d372c22018-11-05 17:12:27 +0100231int connected_peers = 0; /* number of connected peers (verified ones) */
Willy Tarreau392524d2022-02-17 18:10:36 +0100232int arg_mode = 0; /* MODE_DEBUG etc as passed on command line ... */
233char *change_dir = NULL; /* set when -C is passed */
234char *check_condition = NULL; /* check condition passed to -cc */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200235
Ilya Shipitsin46a030c2020-07-05 16:36:08 +0500236/* Here we store information about the pids of the processes we may pause
Willy Tarreaubaaee002006-06-26 02:48:02 +0200237 * or kill. We will send them a signal every 10 ms until we can bind to all
238 * our ports. With 200 retries, that's about 2 seconds.
239 */
240#define MAX_START_RETRIES 200
Willy Tarreaubaaee002006-06-26 02:48:02 +0200241static int *oldpids = NULL;
242static int oldpids_sig; /* use USR1 or TERM */
243
Olivier Houchardf73629d2017-04-05 22:33:04 +0200244/* Path to the unix socket we use to retrieve listener sockets from the old process */
245static const char *old_unixsocket;
246
William Lallemandcb11fd22017-06-01 17:38:52 +0200247int atexit_flag = 0;
248
Willy Tarreaubb545b42010-08-25 12:58:59 +0200249int nb_oldpids = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200250const int zero = 0;
251const int one = 1;
Alexandre Cassen87ea5482007-10-11 20:48:58 +0200252const struct linger nolinger = { .l_onoff = 1, .l_linger = 0 };
Willy Tarreaubaaee002006-06-26 02:48:02 +0200253
Willy Tarreau1d21e0a2010-03-12 21:58:54 +0100254char hostname[MAX_HOSTNAME_LEN];
Dragan Dosen4f014152020-06-18 16:56:47 +0200255char *localpeer = NULL;
Willy Tarreau76871a42022-03-08 16:01:40 +0100256static char *kwd_dump = NULL; // list of keyword dumps to produce
Willy Tarreaubaaee002006-06-26 02:48:02 +0200257
William Lallemand00417412020-06-05 14:08:41 +0200258static char **old_argv = NULL; /* previous argv but cleaned up */
William Lallemand73b85e72017-06-01 17:38:51 +0200259
William Lallemandbc193052018-09-11 10:06:26 +0200260struct list proc_list = LIST_HEAD_INIT(proc_list);
261
262int master = 0; /* 1 if in master, 0 if in child */
Willy Tarreaubf696402019-03-01 10:09:28 +0100263unsigned int rlim_fd_cur_at_boot = 0;
264unsigned int rlim_fd_max_at_boot = 0;
William Lallemandbc193052018-09-11 10:06:26 +0200265
Willy Tarreau6c3a6812020-03-06 18:57:15 +0100266/* per-boot randomness */
267unsigned char boot_seed[20]; /* per-boot random seed (160 bits initially) */
268
Willy Tarreau43ab05b2021-09-28 09:43:11 +0200269/* takes the thread config in argument or NULL for any thread */
William Lallemandb3f2be32018-09-11 10:06:18 +0200270static void *run_thread_poll_loop(void *data);
271
Willy Tarreauff055502014-04-28 22:27:06 +0200272/* bitfield of a few warnings to emit just once (WARN_*) */
273unsigned int warned = 0;
274
Amaury Denoyelle484454d2021-05-05 16:18:45 +0200275/* set if experimental features have been used for the current process */
Willy Tarreauedd42682022-02-25 10:10:00 +0100276unsigned int tainted = 0;
Amaury Denoyelle484454d2021-05-05 16:18:45 +0200277
Amaury Denoyelled2e53cd2021-05-06 16:21:39 +0200278unsigned int experimental_directives_allowed = 0;
279
280int check_kw_experimental(struct cfg_keyword *kw, const char *file, int linenum,
281 char **errmsg)
282{
283 if (kw->flags & KWF_EXPERIMENTAL) {
284 if (!experimental_directives_allowed) {
Amaury Denoyelle86c1d0f2021-05-07 15:07:21 +0200285 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 +0200286 file, linenum, kw->kw);
287 return 1;
288 }
289 mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
290 }
291
292 return 0;
293}
294
William Lallemande7361152018-10-26 14:47:36 +0200295/* master CLI configuration (-S flag) */
296struct list mworker_cli_conf = LIST_HEAD_INIT(mworker_cli_conf);
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100297
298/* These are strings to be reported in the output of "haproxy -vv". They may
299 * either be constants (in which case must_free must be zero) or dynamically
300 * allocated strings to pass to free() on exit, and in this case must_free
301 * must be non-zero.
302 */
303struct list build_opts_list = LIST_HEAD_INIT(build_opts_list);
304struct build_opts_str {
305 struct list list;
306 const char *str;
307 int must_free;
308};
309
Willy Tarreaubaaee002006-06-26 02:48:02 +0200310/*********************************************************************/
311/* general purpose functions ***************************************/
312/*********************************************************************/
313
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100314/* used to register some build option strings at boot. Set must_free to
315 * non-zero if the string must be freed upon exit.
316 */
317void hap_register_build_opts(const char *str, int must_free)
318{
319 struct build_opts_str *b;
320
321 b = calloc(1, sizeof(*b));
322 if (!b) {
323 fprintf(stderr, "out of memory\n");
324 exit(1);
325 }
326 b->str = str;
327 b->must_free = must_free;
Willy Tarreau2b718102021-04-21 07:32:39 +0200328 LIST_APPEND(&build_opts_list, &b->list);
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100329}
330
Willy Tarreaua43dfda2021-05-06 07:43:35 +0200331#define VERSION_MAX_ELTS 7
332
333/* This function splits an haproxy version string into an array of integers.
334 * The syntax of the supported version string is the following:
335 *
336 * <a>[.<b>[.<c>[.<d>]]][-{dev,pre,rc}<f>][-*][-<g>]
337 *
338 * This validates for example:
339 * 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
340 * 2.4-dev18-f6818d-20
341 *
342 * The result is set in a array of <VERSION_MAX_ELTS> elements. Each letter has
343 * one fixed place in the array. The tags take a numeric value called <e> which
344 * defaults to 3. "dev" is 1, "rc" and "pre" are 2. Numbers not encountered are
345 * considered as zero (henxe 1.5 and 1.5.0 are the same).
346 *
347 * The resulting values are:
348 * 1.2.1-pre2 1, 2, 1, 0, 2, 2, 0
349 * 1.2.1 1, 2, 1, 0, 3, 0, 0
350 * 1.2.10.1 1, 2, 10, 1, 3, 0, 0
351 * 1.3.16-rc1 1, 3, 16, 0, 2, 1, 0
352 * 1.4-dev3 1, 4, 0, 0, 1, 3, 0
353 * 1.5-dev18 1, 5, 0, 0, 1, 18, 0
354 * 1.5-dev18-43 1, 5, 0, 0, 1, 18, 43
355 * 2.4-dev18-f6818d-20 2, 4, 0, 0, 1, 18, 20
356 *
357 * The function returns non-zero if the conversion succeeded, or zero if it
358 * failed.
359 */
360int split_version(const char *version, unsigned int *value)
361{
362 const char *p, *s;
363 char *error;
364 int nelts;
365
366 /* Initialize array with zeroes */
367 for (nelts = 0; nelts < VERSION_MAX_ELTS; nelts++)
368 value[nelts] = 0;
369 value[4] = 3;
370
371 p = version;
372
373 /* If the version number is empty, return false */
374 if (*p == '\0')
375 return 0;
376
377 /* Convert first number <a> */
378 value[0] = strtol(p, &error, 10);
379 p = error + 1;
380 if (*error == '\0')
381 return 1;
382 if (*error == '-')
383 goto split_version_tag;
384 if (*error != '.')
385 return 0;
386
387 /* Convert first number <b> */
388 value[1] = strtol(p, &error, 10);
389 p = error + 1;
390 if (*error == '\0')
391 return 1;
392 if (*error == '-')
393 goto split_version_tag;
394 if (*error != '.')
395 return 0;
396
397 /* Convert first number <c> */
398 value[2] = strtol(p, &error, 10);
399 p = error + 1;
400 if (*error == '\0')
401 return 1;
402 if (*error == '-')
403 goto split_version_tag;
404 if (*error != '.')
405 return 0;
406
407 /* Convert first number <d> */
408 value[3] = strtol(p, &error, 10);
409 p = error + 1;
410 if (*error == '\0')
411 return 1;
412 if (*error != '-')
413 return 0;
414
415 split_version_tag:
416 /* Check for commit number */
417 if (*p >= '0' && *p <= '9')
418 goto split_version_commit;
419
420 /* Read tag */
421 if (strncmp(p, "dev", 3) == 0) { value[4] = 1; p += 3; }
422 else if (strncmp(p, "rc", 2) == 0) { value[4] = 2; p += 2; }
423 else if (strncmp(p, "pre", 3) == 0) { value[4] = 2; p += 3; }
424 else
425 goto split_version_commit;
426
427 /* Convert tag number */
428 value[5] = strtol(p, &error, 10);
429 p = error + 1;
430 if (*error == '\0')
431 return 1;
432 if (*error != '-')
433 return 0;
434
435 split_version_commit:
436 /* Search the last "-" */
437 s = strrchr(p, '-');
438 if (s) {
439 s++;
440 if (*s == '\0')
441 return 0;
442 value[6] = strtol(s, &error, 10);
443 if (*error != '\0')
444 value[6] = 0;
445 return 1;
446 }
447
448 /* convert the version */
449 value[6] = strtol(p, &error, 10);
450 if (*error != '\0')
451 value[6] = 0;
452
453 return 1;
454}
455
456/* This function compares the current haproxy version with an arbitrary version
457 * string. It returns:
458 * -1 : the version in argument is older than the current haproxy version
459 * 0 : the version in argument is the same as the current haproxy version
460 * 1 : the version in argument is newer than the current haproxy version
461 *
462 * Or some errors:
463 * -2 : the current haproxy version is not parsable
464 * -3 : the version in argument is not parsable
465 */
466int compare_current_version(const char *version)
467{
468 unsigned int loc[VERSION_MAX_ELTS];
469 unsigned int mod[VERSION_MAX_ELTS];
470 int i;
471
472 /* split versions */
473 if (!split_version(haproxy_version, loc))
474 return -2;
475 if (!split_version(version, mod))
476 return -3;
477
478 /* compare versions */
479 for (i = 0; i < VERSION_MAX_ELTS; i++) {
480 if (mod[i] < loc[i])
481 return -1;
482 else if (mod[i] > loc[i])
483 return 1;
484 }
485 return 0;
486}
487
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100488static void display_version()
Willy Tarreaubaaee002006-06-26 02:48:02 +0200489{
Tim Duesterhusdfad6a42020-04-18 16:02:47 +0200490 struct utsname utsname;
491
Willy Tarreaua5357cd2021-05-09 06:14:25 +0200492 printf("HAProxy version %s %s - https://haproxy.org/\n"
Willy Tarreau08dd2022019-11-21 18:07:30 +0100493 PRODUCT_STATUS "\n", haproxy_version, haproxy_date);
Willy Tarreau47479eb2019-11-21 18:48:20 +0100494
495 if (strlen(PRODUCT_URL_BUGS) > 0) {
496 char base_version[20];
497 int dots = 0;
498 char *del;
499
500 /* only retrieve the base version without distro-specific extensions */
501 for (del = haproxy_version; *del; del++) {
502 if (*del == '.')
503 dots++;
504 else if (*del < '0' || *del > '9')
505 break;
506 }
507
508 strlcpy2(base_version, haproxy_version, del - haproxy_version + 1);
509 if (dots < 2)
510 printf("Known bugs: https://github.com/haproxy/haproxy/issues?q=is:issue+is:open\n");
511 else
512 printf("Known bugs: " PRODUCT_URL_BUGS "\n", base_version);
513 }
Tim Duesterhusdfad6a42020-04-18 16:02:47 +0200514
515 if (uname(&utsname) == 0) {
516 printf("Running on: %s %s %s %s\n", utsname.sysname, utsname.release, utsname.version, utsname.machine);
517 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200518}
519
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100520static void display_build_opts()
Willy Tarreau7b066db2007-12-02 11:28:59 +0100521{
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100522 struct build_opts_str *item;
523
Willy Tarreau7b066db2007-12-02 11:28:59 +0100524 printf("Build options :"
525#ifdef BUILD_TARGET
Willy Tarreau9f2b7302008-01-02 20:48:34 +0100526 "\n TARGET = " BUILD_TARGET
Willy Tarreau7b066db2007-12-02 11:28:59 +0100527#endif
528#ifdef BUILD_CPU
Willy Tarreau9f2b7302008-01-02 20:48:34 +0100529 "\n CPU = " BUILD_CPU
Willy Tarreau7b066db2007-12-02 11:28:59 +0100530#endif
531#ifdef BUILD_CC
Willy Tarreau9f2b7302008-01-02 20:48:34 +0100532 "\n CC = " BUILD_CC
533#endif
534#ifdef BUILD_CFLAGS
535 "\n CFLAGS = " BUILD_CFLAGS
Willy Tarreau7b066db2007-12-02 11:28:59 +0100536#endif
Willy Tarreau9f2b7302008-01-02 20:48:34 +0100537#ifdef BUILD_OPTIONS
538 "\n OPTIONS = " BUILD_OPTIONS
Willy Tarreau7b066db2007-12-02 11:28:59 +0100539#endif
Tim Duesterhusc8d19702020-11-21 18:07:59 +0100540#ifdef BUILD_DEBUG
541 "\n DEBUG = " BUILD_DEBUG
542#endif
Willy Tarreau7728ed32019-03-27 13:20:08 +0100543#ifdef BUILD_FEATURES
544 "\n\nFeature list : " BUILD_FEATURES
545#endif
Willy Tarreau27a674e2009-08-17 07:23:33 +0200546 "\n\nDefault settings :"
Willy Tarreauca783d42019-03-13 10:03:07 +0100547 "\n bufsize = %d, maxrewrite = %d, maxpollevents = %d"
Willy Tarreau27a674e2009-08-17 07:23:33 +0200548 "\n\n",
Willy Tarreauca783d42019-03-13 10:03:07 +0100549 BUFSIZE, MAXREWRITE, MAX_POLL_EVENTS);
Willy Tarreaube5b6852009-10-03 18:57:08 +0200550
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100551 list_for_each_entry(item, &build_opts_list, list) {
552 puts(item->str);
553 }
554
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100555 putchar('\n');
556
Willy Tarreaube5b6852009-10-03 18:57:08 +0200557 list_pollers(stdout);
558 putchar('\n');
Christopher Faulet98d9fe22018-04-10 14:37:32 +0200559 list_mux_proto(stdout);
560 putchar('\n');
Willy Tarreau679bba12019-03-19 08:08:10 +0100561 list_services(stdout);
562 putchar('\n');
Christopher Fauletb3f4e142016-03-07 12:46:38 +0100563 list_filters(stdout);
564 putchar('\n');
Willy Tarreau7b066db2007-12-02 11:28:59 +0100565}
566
Willy Tarreaubaaee002006-06-26 02:48:02 +0200567/*
568 * This function prints the command line usage and exits
569 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100570static void usage(char *name)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200571{
572 display_version();
573 fprintf(stderr,
Maxime de Roucy379d9c72016-05-13 23:52:56 +0200574 "Usage : %s [-f <cfgfile|cfgdir>]* [ -vdV"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200575 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
Willy Tarreaua088d312015-10-08 11:58:48 +0200576 " [ -p <pidfile> ] [ -m <max megs> ] [ -C <dir> ] [-- <cfgfile>*]\n"
Willy Tarreau7b066db2007-12-02 11:28:59 +0100577 " -v displays version ; -vv shows known build options.\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200578 " -d enters debug mode ; -db only disables background mode.\n"
Willy Tarreauf4b79c42022-02-23 15:20:53 +0100579 " -dM[<byte>,help,...] debug memory (default: poison with <byte>/0x50)\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200580 " -V enters verbose mode (disables quiet mode)\n"
Willy Tarreau576132e2011-09-10 19:26:56 +0200581 " -D goes daemon ; -C changes to <dir> before loading files.\n"
William Lallemand095ba4c2017-06-01 17:38:50 +0200582 " -W master-worker mode.\n"
Tim Duesterhusd6942c82017-11-20 15:58:35 +0100583#if defined(USE_SYSTEMD)
584 " -Ws master-worker mode with systemd notify support.\n"
585#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +0200586 " -q quiet mode : don't display messages\n"
Willy Tarreau5d01a632009-06-22 16:02:30 +0200587 " -c check mode : only check config files and exit\n"
Maximilian Maderfc0cceb2021-06-06 00:50:22 +0200588 " -cc check condition : evaluate a condition and exit\n"
Willy Tarreauca783d42019-03-13 10:03:07 +0100589 " -n sets the maximum total # of connections (uses ulimit -n)\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200590 " -m limits the usable amount of memory (in MB)\n"
591 " -N sets the default, per-proxy maximum # of connections (%d)\n"
Emeric Brun2b920a12010-09-23 18:30:22 +0200592 " -L set local peer name (default to hostname)\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200593 " -p writes pids of all children to this file\n"
Erwan Le Goasf30c5d72022-09-29 10:34:04 +0200594 " -dC[[key],line] display the configuration file, if there is a key, the file will be anonymised\n"
Willy Tarreaue5733232019-05-22 19:24:06 +0200595#if defined(USE_EPOLL)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200596 " -de disables epoll() usage even when available\n"
597#endif
Willy Tarreaue5733232019-05-22 19:24:06 +0200598#if defined(USE_KQUEUE)
Willy Tarreau1e63130a2007-04-09 12:03:06 +0200599 " -dk disables kqueue() usage even when available\n"
600#endif
Willy Tarreaue5733232019-05-22 19:24:06 +0200601#if defined(USE_EVPORTS)
Emmanuel Hocdet0ba4f482019-04-08 16:53:32 +0000602 " -dv disables event ports usage even when available\n"
603#endif
Willy Tarreaue5733232019-05-22 19:24:06 +0200604#if defined(USE_POLL)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200605 " -dp disables poll() usage even when available\n"
606#endif
Willy Tarreaue5733232019-05-22 19:24:06 +0200607#if defined(USE_LINUX_SPLICE)
Willy Tarreau3ab68cf2009-01-25 16:03:28 +0100608 " -dS disables splice usage (broken on old kernels)\n"
609#endif
Nenad Merdanovic88afe032014-04-14 15:56:58 +0200610#if defined(USE_GETADDRINFO)
611 " -dG disables getaddrinfo() usage\n"
612#endif
Lukas Tribusa0bcbdc2016-09-12 21:42:20 +0000613#if defined(SO_REUSEPORT)
614 " -dR disables SO_REUSEPORT usage\n"
615#endif
Willy Tarreau654726d2021-12-28 15:43:11 +0100616#if defined(HA_HAVE_DUMP_LIBS)
617 " -dL dumps loaded object files after config checks\n"
618#endif
Willy Tarreau76871a42022-03-08 16:01:40 +0100619 " -dK{class[,...]} dump registered keywords (use 'help' for list)\n"
Willy Tarreau3eed10e2016-11-07 21:03:16 +0100620 " -dr ignores server address resolution failures\n"
Emeric Brun850efd52014-01-29 12:24:34 +0100621 " -dV disables SSL verify on servers side\n"
Willy Tarreau3eb10b82020-04-15 16:42:39 +0200622 " -dW fails if any warning is emitted\n"
Amaury Denoyelle7b01a8d2021-03-29 10:29:07 +0200623 " -dD diagnostic mode : warn about suspicious configuration statements\n"
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +0200624 " -sf/-st [pid ]* finishes/terminates old pids.\n"
Olivier Houchardf73629d2017-04-05 22:33:04 +0200625 " -x <unix_socket> get listening sockets from a unix socket\n"
William Lallemand63329e32019-06-13 17:03:37 +0200626 " -S <bind>[,<bind options>...] new master CLI\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200627 "\n",
Willy Tarreauca783d42019-03-13 10:03:07 +0100628 name, cfg_maxpconn);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200629 exit(1);
630}
631
632
633
634/*********************************************************************/
635/* more specific functions ***************************************/
636/*********************************************************************/
637
William Lallemand73b85e72017-06-01 17:38:51 +0200638/* sends the signal <sig> to all pids found in <oldpids>. Returns the number of
639 * pids the signal was correctly delivered to.
640 */
William Lallemande25473c2019-04-01 11:29:56 +0200641int tell_old_pids(int sig)
William Lallemand73b85e72017-06-01 17:38:51 +0200642{
643 int p;
644 int ret = 0;
645 for (p = 0; p < nb_oldpids; p++)
646 if (kill(oldpids[p], sig) == 0)
647 ret++;
648 return ret;
649}
650
William Lallemand75ea0a02017-11-15 19:02:58 +0100651/*
William Lallemand73b85e72017-06-01 17:38:51 +0200652 * remove a pid forom the olpid array and decrease nb_oldpids
653 * return 1 pid was found otherwise return 0
654 */
655
656int delete_oldpid(int pid)
657{
658 int i;
659
660 for (i = 0; i < nb_oldpids; i++) {
661 if (oldpids[i] == pid) {
662 oldpids[i] = oldpids[nb_oldpids - 1];
663 oldpids[nb_oldpids - 1] = 0;
664 nb_oldpids--;
665 return 1;
666 }
667 }
668 return 0;
669}
670
William Lallemand85b0bd92017-06-01 17:38:53 +0200671
William Lallemand73b85e72017-06-01 17:38:51 +0200672/*
673 * When called, this function reexec haproxy with -sf followed by current
Joseph Herlant03420902018-11-15 10:41:50 -0800674 * children PIDs and possibly old children PIDs if they didn't leave yet.
William Lallemand73b85e72017-06-01 17:38:51 +0200675 */
William Lallemandfab0fdc2021-11-09 18:01:22 +0100676static void mworker_reexec()
William Lallemand73b85e72017-06-01 17:38:51 +0200677{
William Lallemand00417412020-06-05 14:08:41 +0200678 char **next_argv = NULL;
679 int old_argc = 0; /* previous number of argument */
William Lallemand73b85e72017-06-01 17:38:51 +0200680 int next_argc = 0;
William Lallemand00417412020-06-05 14:08:41 +0200681 int i = 0;
William Lallemand73b85e72017-06-01 17:38:51 +0200682 char *msg = NULL;
Willy Tarreau8dca1952019-03-01 10:21:55 +0100683 struct rlimit limit;
William Lallemand2be557f2021-11-24 18:45:37 +0100684 struct mworker_proc *current_child = NULL;
William Lallemand73b85e72017-06-01 17:38:51 +0200685
686 mworker_block_signals();
William Lallemand73b85e72017-06-01 17:38:51 +0200687 setenv("HAPROXY_MWORKER_REEXEC", "1", 1);
688
William Lallemand55a921c2022-01-28 21:17:30 +0100689 mworker_cleanup_proc();
William Lallemandbc193052018-09-11 10:06:26 +0200690 mworker_proc_list_to_env(); /* put the children description in the env */
691
William Lallemandc4810b82021-11-18 10:51:30 +0100692 /* ensure that we close correctly every listeners before reexecuting */
693 mworker_cleanlisteners();
694
William Lallemand7c756a82018-11-26 11:53:40 +0100695 /* during the reload we must ensure that every FDs that can't be
696 * reuse (ie those that are not referenced in the proc_list)
697 * are closed or they will leak. */
698
699 /* close the listeners FD */
700 mworker_cli_proxy_stop();
William Lallemand16866672019-06-24 17:40:48 +0200701
William Lallemand67e371e2021-11-25 10:03:44 +0100702 if (fdtab)
703 deinit_pollers();
William Lallemandefd95472021-11-26 14:43:57 +0100704
Ilya Shipitsin98a9e1b2021-02-19 23:42:53 +0500705#ifdef HAVE_SSL_RAND_KEEP_RANDOM_DEVICES_OPEN
William Lallemand5fdb5b32019-10-15 14:04:08 +0200706 /* close random device FDs */
707 RAND_keep_random_devices_open(0);
Rob Allen56996da2019-05-03 09:11:32 +0100708#endif
William Lallemand7c756a82018-11-26 11:53:40 +0100709
Willy Tarreau8dca1952019-03-01 10:21:55 +0100710 /* restore the initial FD limits */
711 limit.rlim_cur = rlim_fd_cur_at_boot;
712 limit.rlim_max = rlim_fd_max_at_boot;
Willy Tarreauc06557c2022-09-22 16:12:08 +0200713 if (raise_rlim_nofile(&limit, &limit) != 0) {
Willy Tarreau8dca1952019-03-01 10:21:55 +0100714 ha_warning("Failed to restore initial FD limits (cur=%u max=%u), using cur=%u max=%u\n",
715 rlim_fd_cur_at_boot, rlim_fd_max_at_boot,
716 (unsigned int)limit.rlim_cur, (unsigned int)limit.rlim_max);
717 }
718
William Lallemand73b85e72017-06-01 17:38:51 +0200719 /* compute length */
William Lallemand00417412020-06-05 14:08:41 +0200720 while (old_argv[old_argc])
721 old_argc++;
William Lallemand73b85e72017-06-01 17:38:51 +0200722
William Lallemand85b0bd92017-06-01 17:38:53 +0200723 /* 1 for haproxy -sf, 2 for -x /socket */
William Lallemandaba7f8b2021-04-21 16:55:34 +0200724 next_argv = calloc(old_argc + 1 + 2 + mworker_child_nb() + 1,
Tim Duesterhuse52b6e52020-09-12 20:26:43 +0200725 sizeof(*next_argv));
William Lallemand73b85e72017-06-01 17:38:51 +0200726 if (next_argv == NULL)
727 goto alloc_error;
728
William Lallemand00417412020-06-05 14:08:41 +0200729 /* copy the program name */
730 next_argv[next_argc++] = old_argv[0];
731
732 /* insert the new options just after argv[0] in case we have a -- */
733
William Lallemandbefab9e2021-11-25 00:49:19 +0100734 if (getenv("HAPROXY_MWORKER_WAIT_ONLY") == NULL) {
735 /* add -sf <PID>* to argv */
736 if (mworker_child_nb() > 0) {
737 struct mworker_proc *child;
William Lallemand3f128872019-04-01 11:29:59 +0200738
William Lallemandbefab9e2021-11-25 00:49:19 +0100739 next_argv[next_argc++] = "-sf";
William Lallemand3f128872019-04-01 11:29:59 +0200740
William Lallemandbefab9e2021-11-25 00:49:19 +0100741 list_for_each_entry(child, &proc_list, list) {
742 if (!(child->options & PROC_O_LEAVING) && (child->options & PROC_O_TYPE_WORKER))
743 current_child = child;
William Lallemand2be557f2021-11-24 18:45:37 +0100744
William Lallemandbefab9e2021-11-25 00:49:19 +0100745 if (!(child->options & (PROC_O_TYPE_WORKER|PROC_O_TYPE_PROG)) || child->pid <= -1)
746 continue;
747 if ((next_argv[next_argc++] = memprintf(&msg, "%d", child->pid)) == NULL)
748 goto alloc_error;
749 msg = NULL;
750 }
William Lallemand73b85e72017-06-01 17:38:51 +0200751 }
William Lallemand2be557f2021-11-24 18:45:37 +0100752
753 if (current_child) {
754 /* add the -x option with the socketpair of the current worker */
755 next_argv[next_argc++] = "-x";
756 if ((next_argv[next_argc++] = memprintf(&msg, "sockpair@%d", current_child->ipc_fd[0])) == NULL)
757 goto alloc_error;
758 msg = NULL;
759 }
William Lallemand85b0bd92017-06-01 17:38:53 +0200760 }
761
William Lallemand00417412020-06-05 14:08:41 +0200762 /* copy the previous options */
763 for (i = 1; i < old_argc; i++)
764 next_argv[next_argc++] = old_argv[i];
765
Willy Tarreaue0d86e22019-08-26 10:37:39 +0200766 signal(SIGPROF, SIG_IGN);
Tim Duesterhus0436ab72017-11-12 17:39:18 +0100767 execvp(next_argv[0], next_argv);
Christopher Faulet767a84b2017-11-24 16:50:31 +0100768 ha_warning("Failed to reexecute the master process [%d]: %s\n", pid, strerror(errno));
Willy Tarreau61cfdf42021-02-20 10:46:51 +0100769 ha_free(&next_argv);
William Lallemand722d4ca2017-11-15 19:02:55 +0100770 return;
771
William Lallemand73b85e72017-06-01 17:38:51 +0200772alloc_error:
Willy Tarreau61cfdf42021-02-20 10:46:51 +0100773 ha_free(&next_argv);
Joseph Herlant07a08342018-11-15 10:43:05 -0800774 ha_warning("Failed to reexecute the master process [%d]: Cannot allocate memory\n", pid);
William Lallemand73b85e72017-06-01 17:38:51 +0200775 return;
776}
777
William Lallemandfab0fdc2021-11-09 18:01:22 +0100778/* reexec haproxy in waitmode */
779static void mworker_reexec_waitmode()
780{
781 setenv("HAPROXY_MWORKER_WAIT_ONLY", "1", 1);
782 mworker_reexec();
783}
784
785/* reload haproxy and emit a warning */
786void mworker_reload()
787{
William Lallemandad221f42021-11-09 18:43:59 +0100788 struct mworker_proc *child;
William Lallemandefd95472021-11-26 14:43:57 +0100789 struct per_thread_deinit_fct *ptdf;
William Lallemandad221f42021-11-09 18:43:59 +0100790
William Lallemand836bda22021-11-09 18:16:47 +0100791 ha_notice("Reloading HAProxy\n");
William Lallemandad221f42021-11-09 18:43:59 +0100792
William Lallemandefd95472021-11-26 14:43:57 +0100793 /* close the poller FD and the thread waker pipe FD */
794 list_for_each_entry(ptdf, &per_thread_deinit_list, list)
795 ptdf->fct();
796
William Lallemandad221f42021-11-09 18:43:59 +0100797 /* increment the number of reloads */
798 list_for_each_entry(child, &proc_list, list) {
799 child->reloads++;
800 }
801
William Lallemanda46a99e2022-07-07 14:00:36 +0200802#if defined(USE_SYSTEMD)
803 if (global.tune.options & GTUNE_USE_SYSTEMD)
804 sd_notify(0, "RELOADING=1\nSTATUS=Reloading Configuration.\n");
805#endif
William Lallemandfab0fdc2021-11-09 18:01:22 +0100806 mworker_reexec();
807}
808
William Lallemandb3f2be32018-09-11 10:06:18 +0200809static void mworker_loop()
810{
811
Willy Tarreaud83b6c12019-04-18 11:31:36 +0200812 /* Busy polling makes no sense in the master :-) */
813 global.tune.options &= ~GTUNE_BUSY_POLLING;
William Lallemandb3f2be32018-09-11 10:06:18 +0200814
William Lallemandbc193052018-09-11 10:06:26 +0200815
Willy Tarreaud26c9f92019-12-11 14:24:07 +0100816 signal_unregister(SIGTTIN);
817 signal_unregister(SIGTTOU);
William Lallemand0564d412018-11-20 17:36:53 +0100818 signal_unregister(SIGUSR1);
819 signal_unregister(SIGHUP);
820 signal_unregister(SIGQUIT);
821
William Lallemandb3f2be32018-09-11 10:06:18 +0200822 signal_register_fct(SIGTERM, mworker_catch_sigterm, SIGTERM);
823 signal_register_fct(SIGUSR1, mworker_catch_sigterm, SIGUSR1);
Willy Tarreaud26c9f92019-12-11 14:24:07 +0100824 signal_register_fct(SIGTTIN, mworker_broadcast_signal, SIGTTIN);
825 signal_register_fct(SIGTTOU, mworker_broadcast_signal, SIGTTOU);
William Lallemandb3f2be32018-09-11 10:06:18 +0200826 signal_register_fct(SIGINT, mworker_catch_sigterm, SIGINT);
827 signal_register_fct(SIGHUP, mworker_catch_sighup, SIGHUP);
828 signal_register_fct(SIGUSR2, mworker_catch_sighup, SIGUSR2);
829 signal_register_fct(SIGCHLD, mworker_catch_sigchld, SIGCHLD);
830
831 mworker_unblock_signals();
William Lallemand27f3fa52018-12-06 14:05:20 +0100832 mworker_cleantasks();
William Lallemandb3f2be32018-09-11 10:06:18 +0200833
William Lallemandbc193052018-09-11 10:06:26 +0200834 mworker_catch_sigchld(NULL); /* ensure we clean the children in case
835 some SIGCHLD were lost */
836
William Lallemandb3f2be32018-09-11 10:06:18 +0200837 jobs++; /* this is the "master" job, we want to take care of the
838 signals even if there is no listener so the poll loop don't
839 leave */
840
841 fork_poller();
Willy Tarreau43ab05b2021-09-28 09:43:11 +0200842 run_thread_poll_loop(NULL);
William Lallemandb3f2be32018-09-11 10:06:18 +0200843}
William Lallemandcb11fd22017-06-01 17:38:52 +0200844
845/*
846 * Reexec the process in failure mode, instead of exiting
847 */
848void reexec_on_failure()
849{
William Lallemand68836742021-11-10 10:49:06 +0100850 struct mworker_proc *child;
851
William Lallemandcb11fd22017-06-01 17:38:52 +0200852 if (!atexit_flag)
853 return;
William Lallemand68836742021-11-10 10:49:06 +0100854
855 /* get the info of the children in the env */
856 if (mworker_env_to_proc_list() < 0) {
857 exit(EXIT_FAILURE);
858 }
859
860 /* increment the number of failed reloads */
861 list_for_each_entry(child, &proc_list, list) {
862 child->failedreloads++;
863 }
864
Willy Tarreaue08acae2022-01-28 18:40:06 +0100865 /* do not keep unused FDs retrieved from the previous process */
866 sock_drop_unused_old_sockets();
867
William Lallemandfab0fdc2021-11-09 18:01:22 +0100868 usermsgs_clr(NULL);
William Lallemand68192b22022-09-24 15:44:42 +0200869 setenv("HAPROXY_LOAD_SUCCESS", "0", 1);
William Lallemand836bda22021-11-09 18:16:47 +0100870 ha_warning("Loading failure!\n");
William Lallemanda46a99e2022-07-07 14:00:36 +0200871#if defined(USE_SYSTEMD)
872 /* the sd_notify API is not able to send a reload failure signal. So
873 * the READY=1 signal still need to be sent */
874 if (global.tune.options & GTUNE_USE_SYSTEMD)
875 sd_notify(0, "READY=1\nSTATUS=Reload failed!\n");
876#endif
877
William Lallemandfab0fdc2021-11-09 18:01:22 +0100878 mworker_reexec_waitmode();
William Lallemandcb11fd22017-06-01 17:38:52 +0200879}
William Lallemand73b85e72017-06-01 17:38:51 +0200880
William Lallemand40db4ae2022-12-07 15:03:55 +0100881/*
882 * Exit with an error message upon a wait-mode failure.
883 */
884void exit_on_waitmode_failure()
885{
886 if (!atexit_flag)
887 return;
888
889 ha_alert("Non-recoverable mworker wait-mode error, exiting.\n");
890}
891
William Lallemand73b85e72017-06-01 17:38:51 +0200892
893/*
Willy Tarreaud0807c32010-08-27 18:26:11 +0200894 * upon SIGUSR1, let's have a soft stop. Note that soft_stop() broadcasts
895 * a signal zero to all subscribers. This means that it's as easy as
896 * subscribing to signal 0 to get informed about an imminent shutdown.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200897 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100898static void sig_soft_stop(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200899{
900 soft_stop();
Willy Tarreau24f4efa2010-08-27 17:56:48 +0200901 signal_unregister_handler(sh);
Willy Tarreaubafbe012017-11-24 17:34:44 +0100902 pool_gc(NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200903}
904
905/*
906 * upon SIGTTOU, we pause everything
907 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100908static void sig_pause(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200909{
Willy Tarreau775e0012020-09-24 16:36:26 +0200910 if (protocol_pause_all() & ERR_FATAL) {
911 const char *msg = "Some proxies refused to pause, performing soft stop now.\n";
Willy Tarreau0a002df2020-10-09 19:26:27 +0200912 ha_warning("%s", msg);
913 send_log(NULL, LOG_WARNING, "%s", msg);
Willy Tarreau775e0012020-09-24 16:36:26 +0200914 soft_stop();
915 }
Willy Tarreaubafbe012017-11-24 17:34:44 +0100916 pool_gc(NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200917}
918
919/*
920 * upon SIGTTIN, let's have a soft stop.
921 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100922static void sig_listen(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200923{
Willy Tarreau775e0012020-09-24 16:36:26 +0200924 if (protocol_resume_all() & ERR_FATAL) {
925 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 +0200926 ha_warning("%s", msg);
927 send_log(NULL, LOG_WARNING, "%s", msg);
Willy Tarreau775e0012020-09-24 16:36:26 +0200928 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200929}
930
931/*
932 * this function dumps every server's state when the process receives SIGHUP.
933 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100934static void sig_dump_state(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200935{
Olivier Houchardfbc74e82017-11-24 16:54:05 +0100936 struct proxy *p = proxies_list;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200937
Christopher Faulet767a84b2017-11-24 16:50:31 +0100938 ha_warning("SIGHUP received, dumping servers states.\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +0200939 while (p) {
940 struct server *s = p->srv;
941
942 send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
943 while (s) {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100944 chunk_printf(&trash,
945 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %lld tot.",
946 p->id, s->id,
Emeric Brun52a91d32017-08-31 14:41:55 +0200947 (s->cur_state != SRV_ST_STOPPED) ? "UP" : "DOWN",
Willy Tarreaua0570452021-06-18 09:30:30 +0200948 s->cur_sess, s->queue.length, s->counters.cum_sess);
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200949 ha_warning("%s\n", trash.area);
950 send_log(p, LOG_NOTICE, "%s\n", trash.area);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200951 s = s->next;
952 }
953
Willy Tarreau5fcc8f12007-09-17 11:27:09 +0200954 /* FIXME: those info are a bit outdated. We should be able to distinguish between FE and BE. */
955 if (!p->srv) {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100956 chunk_printf(&trash,
957 "SIGHUP: Proxy %s has no servers. Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
958 p->id,
Willy Tarreau7f3c1df2021-06-18 09:22:21 +0200959 p->feconn, p->beconn, p->totpend, p->queue.length, p->fe_counters.cum_conn, p->be_counters.cum_conn);
Willy Tarreau5fcc8f12007-09-17 11:27:09 +0200960 } else if (p->srv_act == 0) {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100961 chunk_printf(&trash,
962 "SIGHUP: Proxy %s %s ! Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
963 p->id,
964 (p->srv_bck) ? "is running on backup servers" : "has no server available",
Willy Tarreau7f3c1df2021-06-18 09:22:21 +0200965 p->feconn, p->beconn, p->totpend, p->queue.length, p->fe_counters.cum_conn, p->be_counters.cum_conn);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200966 } else {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100967 chunk_printf(&trash,
968 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
969 " Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
970 p->id, p->srv_act, p->srv_bck,
Willy Tarreau7f3c1df2021-06-18 09:22:21 +0200971 p->feconn, p->beconn, p->totpend, p->queue.length, p->fe_counters.cum_conn, p->be_counters.cum_conn);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200972 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200973 ha_warning("%s\n", trash.area);
974 send_log(p, LOG_NOTICE, "%s\n", trash.area);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200975
976 p = p->next;
977 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200978}
979
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100980static void dump(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200981{
Willy Tarreauc6ca1a02007-05-13 19:43:47 +0200982 /* dump memory usage then free everything possible */
983 dump_pools();
Willy Tarreaubafbe012017-11-24 17:34:44 +0100984 pool_gc(NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200985}
986
William Lallemande1340412017-12-28 16:09:36 +0100987/*
988 * This function dup2 the stdio FDs (0,1,2) with <fd>, then closes <fd>
989 * If <fd> < 0, it opens /dev/null and use it to dup
990 *
991 * In the case of chrooting, you have to open /dev/null before the chroot, and
992 * pass the <fd> to this function
993 */
994static void stdio_quiet(int fd)
995{
996 if (fd < 0)
997 fd = open("/dev/null", O_RDWR, 0);
998
999 if (fd > -1) {
1000 fclose(stdin);
1001 fclose(stdout);
1002 fclose(stderr);
1003
1004 dup2(fd, 0);
1005 dup2(fd, 1);
1006 dup2(fd, 2);
1007 if (fd > 2)
1008 close(fd);
1009 return;
1010 }
1011
1012 ha_alert("Cannot open /dev/null\n");
1013 exit(EXIT_FAILURE);
1014}
1015
1016
Joseph Herlant03420902018-11-15 10:41:50 -08001017/* This function checks if cfg_cfgfiles contains directories.
1018 * If it finds one, it adds all the files (and only files) it contains
1019 * in cfg_cfgfiles in place of the directory (and removes the directory).
1020 * It adds the files in lexical order.
1021 * It adds only files with .cfg extension.
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001022 * It doesn't add files with name starting with '.'
1023 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +01001024static void cfgfiles_expand_directories(void)
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001025{
1026 struct wordlist *wl, *wlb;
1027 char *err = NULL;
1028
1029 list_for_each_entry_safe(wl, wlb, &cfg_cfgfiles, list) {
1030 struct stat file_stat;
1031 struct dirent **dir_entries = NULL;
1032 int dir_entries_nb;
1033 int dir_entries_it;
1034
1035 if (stat(wl->s, &file_stat)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001036 ha_alert("Cannot open configuration file/directory %s : %s\n",
1037 wl->s,
1038 strerror(errno));
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001039 exit(1);
1040 }
1041
1042 if (!S_ISDIR(file_stat.st_mode))
1043 continue;
1044
1045 /* from this point wl->s is a directory */
1046
1047 dir_entries_nb = scandir(wl->s, &dir_entries, NULL, alphasort);
1048 if (dir_entries_nb < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001049 ha_alert("Cannot open configuration directory %s : %s\n",
1050 wl->s,
1051 strerror(errno));
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001052 exit(1);
1053 }
1054
1055 /* for each element in the directory wl->s */
1056 for (dir_entries_it = 0; dir_entries_it < dir_entries_nb; dir_entries_it++) {
1057 struct dirent *dir_entry = dir_entries[dir_entries_it];
1058 char *filename = NULL;
1059 char *d_name_cfgext = strstr(dir_entry->d_name, ".cfg");
1060
1061 /* don't add filename that begin with .
Joseph Herlant03420902018-11-15 10:41:50 -08001062 * only add filename with .cfg extension
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001063 */
1064 if (dir_entry->d_name[0] == '.' ||
1065 !(d_name_cfgext && d_name_cfgext[4] == '\0'))
1066 goto next_dir_entry;
1067
1068 if (!memprintf(&filename, "%s/%s", wl->s, dir_entry->d_name)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001069 ha_alert("Cannot load configuration files %s : out of memory.\n",
1070 filename);
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001071 exit(1);
1072 }
1073
1074 if (stat(filename, &file_stat)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001075 ha_alert("Cannot open configuration file %s : %s\n",
1076 wl->s,
1077 strerror(errno));
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001078 exit(1);
1079 }
1080
1081 /* don't add anything else than regular file in cfg_cfgfiles
1082 * this way we avoid loops
1083 */
1084 if (!S_ISREG(file_stat.st_mode))
1085 goto next_dir_entry;
1086
1087 if (!list_append_word(&wl->list, filename, &err)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001088 ha_alert("Cannot load configuration files %s : %s\n",
1089 filename,
1090 err);
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001091 exit(1);
1092 }
1093
1094next_dir_entry:
1095 free(filename);
1096 free(dir_entry);
1097 }
1098
1099 free(dir_entries);
1100
1101 /* remove the current directory (wl) from cfg_cfgfiles */
1102 free(wl->s);
Willy Tarreau2b718102021-04-21 07:32:39 +02001103 LIST_DELETE(&wl->list);
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001104 free(wl);
1105 }
1106
1107 free(err);
1108}
1109
Willy Tarreaubaaee002006-06-26 02:48:02 +02001110/*
William Lallemand73b85e72017-06-01 17:38:51 +02001111 * copy and cleanup the current argv
William Lallemanddf6c5a82020-06-04 17:40:23 +02001112 * Remove the -sf /-st / -x parameters
William Lallemand73b85e72017-06-01 17:38:51 +02001113 * Return an allocated copy of argv
1114 */
1115
1116static char **copy_argv(int argc, char **argv)
1117{
William Lallemanddf6c5a82020-06-04 17:40:23 +02001118 char **newargv, **retargv;
William Lallemand73b85e72017-06-01 17:38:51 +02001119
Tim Duesterhuse52b6e52020-09-12 20:26:43 +02001120 newargv = calloc(argc + 2, sizeof(*newargv));
William Lallemand73b85e72017-06-01 17:38:51 +02001121 if (newargv == NULL) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001122 ha_warning("Cannot allocate memory\n");
William Lallemand73b85e72017-06-01 17:38:51 +02001123 return NULL;
1124 }
William Lallemanddf6c5a82020-06-04 17:40:23 +02001125 retargv = newargv;
William Lallemand73b85e72017-06-01 17:38:51 +02001126
William Lallemanddf6c5a82020-06-04 17:40:23 +02001127 /* first copy argv[0] */
1128 *newargv++ = *argv++;
1129 argc--;
1130
1131 while (argc > 0) {
1132 if (**argv != '-') {
1133 /* non options are copied but will fail in the argument parser */
1134 *newargv++ = *argv++;
1135 argc--;
1136
1137 } else {
1138 char *flag;
1139
1140 flag = *argv + 1;
1141
1142 if (flag[0] == '-' && flag[1] == 0) {
1143 /* "--\0" copy every arguments till the end of argv */
1144 *newargv++ = *argv++;
1145 argc--;
1146
1147 while (argc > 0) {
1148 *newargv++ = *argv++;
1149 argc--;
1150 }
1151 } else {
1152 switch (*flag) {
1153 case 's':
1154 /* -sf / -st and their parameters are ignored */
1155 if (flag[1] == 'f' || flag[1] == 't') {
1156 argc--;
1157 argv++;
1158 /* The list can't contain a negative value since the only
1159 way to know the end of this list is by looking for the
1160 next option or the end of the options */
1161 while (argc > 0 && argv[0][0] != '-') {
1162 argc--;
1163 argv++;
1164 }
William Lallemand398da622020-09-02 16:12:23 +02001165 } else {
1166 argc--;
1167 argv++;
1168
William Lallemanddf6c5a82020-06-04 17:40:23 +02001169 }
1170 break;
1171
1172 case 'x':
1173 /* this option and its parameter are ignored */
1174 argc--;
1175 argv++;
1176 if (argc > 0) {
1177 argc--;
1178 argv++;
1179 }
1180 break;
1181
1182 case 'C':
1183 case 'n':
1184 case 'm':
1185 case 'N':
1186 case 'L':
1187 case 'f':
1188 case 'p':
1189 case 'S':
1190 /* these options have only 1 parameter which must be copied and can start with a '-' */
1191 *newargv++ = *argv++;
1192 argc--;
1193 if (argc == 0)
1194 goto error;
1195 *newargv++ = *argv++;
1196 argc--;
1197 break;
1198 default:
1199 /* for other options just copy them without parameters, this is also done
1200 * for options like "--foo", but this will fail in the argument parser.
1201 * */
1202 *newargv++ = *argv++;
1203 argc--;
1204 break;
1205 }
William Lallemand73b85e72017-06-01 17:38:51 +02001206 }
1207 }
William Lallemand73b85e72017-06-01 17:38:51 +02001208 }
William Lallemand2bf6d622017-06-20 11:20:23 +02001209
William Lallemanddf6c5a82020-06-04 17:40:23 +02001210 return retargv;
1211
1212error:
1213 free(retargv);
1214 return NULL;
William Lallemand73b85e72017-06-01 17:38:51 +02001215}
1216
Willy Tarreau6c3a6812020-03-06 18:57:15 +01001217
1218/* Performs basic random seed initialization. The main issue with this is that
1219 * srandom_r() only takes 32 bits and purposely provides a reproducible sequence,
1220 * which means that there will only be 4 billion possible random sequences once
1221 * srandom() is called, regardless of the internal state. Not calling it is
1222 * even worse as we'll always produce the same randoms sequences. What we do
1223 * here is to create an initial sequence from various entropy sources, hash it
1224 * using SHA1 and keep the resulting 160 bits available globally.
1225 *
1226 * We initialize the current process with the first 32 bits before starting the
1227 * polling loop, where all this will be changed to have process specific and
1228 * thread specific sequences.
Willy Tarreau52bf8392020-03-08 00:42:37 +01001229 *
1230 * Before starting threads, it's still possible to call random() as srandom()
1231 * is initialized from this, but after threads and/or processes are started,
1232 * only ha_random() is expected to be used to guarantee distinct sequences.
Willy Tarreau6c3a6812020-03-06 18:57:15 +01001233 */
1234static void ha_random_boot(char *const *argv)
1235{
1236 unsigned char message[256];
1237 unsigned char *m = message;
1238 struct timeval tv;
1239 blk_SHA_CTX ctx;
1240 unsigned long l;
1241 int fd;
1242 int i;
1243
1244 /* start with current time as pseudo-random seed */
1245 gettimeofday(&tv, NULL);
1246 write_u32(m, tv.tv_sec); m += 4;
1247 write_u32(m, tv.tv_usec); m += 4;
1248
1249 /* PID and PPID add some OS-based randomness */
1250 write_u16(m, getpid()); m += 2;
1251 write_u16(m, getppid()); m += 2;
1252
1253 /* take up to 160 bits bytes from /dev/urandom if available (non-blocking) */
1254 fd = open("/dev/urandom", O_RDONLY);
1255 if (fd >= 0) {
1256 i = read(fd, m, 20);
1257 if (i > 0)
1258 m += i;
1259 close(fd);
1260 }
1261
1262 /* take up to 160 bits bytes from openssl (non-blocking) */
1263#ifdef USE_OPENSSL
1264 if (RAND_bytes(m, 20) == 1)
1265 m += 20;
1266#endif
1267
1268 /* take 160 bits from existing random in case it was already initialized */
1269 for (i = 0; i < 5; i++) {
1270 write_u32(m, random());
1271 m += 4;
1272 }
1273
1274 /* stack address (benefit form operating system's ASLR) */
1275 l = (unsigned long)&m;
1276 memcpy(m, &l, sizeof(l)); m += sizeof(l);
1277
1278 /* argv address (benefit form operating system's ASLR) */
1279 l = (unsigned long)&argv;
1280 memcpy(m, &l, sizeof(l)); m += sizeof(l);
1281
1282 /* use tv_usec again after all the operations above */
1283 gettimeofday(&tv, NULL);
1284 write_u32(m, tv.tv_usec); m += 4;
1285
1286 /*
1287 * At this point, ~84-92 bytes have been used
1288 */
1289
1290 /* finish with the hostname */
1291 strncpy((char *)m, hostname, message + sizeof(message) - m);
1292 m += strlen(hostname);
1293
1294 /* total message length */
1295 l = m - message;
1296
1297 memset(&ctx, 0, sizeof(ctx));
1298 blk_SHA1_Init(&ctx);
1299 blk_SHA1_Update(&ctx, message, l);
1300 blk_SHA1_Final(boot_seed, &ctx);
1301
1302 srandom(read_u32(boot_seed));
Willy Tarreau52bf8392020-03-08 00:42:37 +01001303 ha_random_seed(boot_seed, sizeof(boot_seed));
Willy Tarreau6c3a6812020-03-06 18:57:15 +01001304}
1305
Willy Tarreau5a023f02019-03-01 14:19:31 +01001306/* considers splicing proxies' maxconn, computes the ideal global.maxpipes
1307 * setting, and returns it. It may return -1 meaning "unlimited" if some
1308 * unlimited proxies have been found and the global.maxconn value is not yet
1309 * set. It may also return a value greater than maxconn if it's not yet set.
1310 * Note that a value of zero means there is no need for pipes. -1 is never
1311 * returned if global.maxconn is valid.
1312 */
1313static int compute_ideal_maxpipes()
1314{
1315 struct proxy *cur;
1316 int nbfe = 0, nbbe = 0;
1317 int unlimited = 0;
1318 int pipes;
1319 int max;
1320
1321 for (cur = proxies_list; cur; cur = cur->next) {
1322 if (cur->options2 & (PR_O2_SPLIC_ANY)) {
1323 if (cur->cap & PR_CAP_FE) {
1324 max = cur->maxconn;
1325 nbfe += max;
1326 if (!max) {
1327 unlimited = 1;
1328 break;
1329 }
1330 }
1331 if (cur->cap & PR_CAP_BE) {
1332 max = cur->fullconn ? cur->fullconn : global.maxconn;
1333 nbbe += max;
1334 if (!max) {
1335 unlimited = 1;
1336 break;
1337 }
1338 }
1339 }
1340 }
1341
1342 pipes = MAX(nbfe, nbbe);
1343 if (global.maxconn) {
1344 if (pipes > global.maxconn || unlimited)
1345 pipes = global.maxconn;
1346 } else if (unlimited) {
1347 pipes = -1;
1348 }
1349
1350 return pipes >= 4 ? pipes / 4 : pipes;
1351}
1352
Willy Tarreauac350932019-03-01 15:43:14 +01001353/* considers global.maxsocks, global.maxpipes, async engines, SSL frontends and
1354 * rlimits and computes an ideal maxconn. It's meant to be called only when
1355 * maxsock contains the sum of listening FDs, before it is updated based on
Willy Tarreaudf23c0c2019-03-13 10:10:49 +01001356 * maxconn and pipes. If there are not enough FDs left, DEFAULT_MAXCONN (by
1357 * default 100) is returned as it is expected that it will even run on tight
1358 * environments, and will maintain compatibility with previous packages that
1359 * used to rely on this value as the default one. The system will emit a
1360 * warning indicating how many FDs are missing anyway if needed.
Willy Tarreauac350932019-03-01 15:43:14 +01001361 */
1362static int compute_ideal_maxconn()
1363{
1364 int ssl_sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
1365 int engine_fds = global.ssl_used_async_engines * ssl_sides;
1366 int pipes = compute_ideal_maxpipes();
Willy Tarreaub1beaa32020-03-06 10:25:31 +01001367 int remain = MAX(rlim_fd_cur_at_boot, rlim_fd_max_at_boot);
Willy Tarreauac350932019-03-01 15:43:14 +01001368 int maxconn;
1369
1370 /* we have to take into account these elements :
1371 * - number of engine_fds, which inflates the number of FD needed per
1372 * connection by this number.
1373 * - number of pipes per connection on average : for the unlimited
1374 * case, this is 0.5 pipe FDs per connection, otherwise it's a
1375 * fixed value of 2*pipes.
1376 * - two FDs per connection
1377 */
1378
Willy Tarreau2df1fbf2022-04-25 18:02:03 +02001379 if (global.fd_hard_limit && remain > global.fd_hard_limit)
1380 remain = global.fd_hard_limit;
1381
Willy Tarreauac350932019-03-01 15:43:14 +01001382 /* subtract listeners and checks */
1383 remain -= global.maxsock;
1384
Willy Tarreau3f200852019-03-14 19:13:17 +01001385 /* one epoll_fd/kqueue_fd per thread */
1386 remain -= global.nbthread;
1387
1388 /* one wake-up pipe (2 fd) per thread */
1389 remain -= 2 * global.nbthread;
1390
Willy Tarreauac350932019-03-01 15:43:14 +01001391 /* Fixed pipes values : we only subtract them if they're not larger
1392 * than the remaining FDs because pipes are optional.
1393 */
1394 if (pipes >= 0 && pipes * 2 < remain)
1395 remain -= pipes * 2;
1396
1397 if (pipes < 0) {
1398 /* maxsock = maxconn * 2 + maxconn/4 * 2 + maxconn * engine_fds.
1399 * = maxconn * (2 + 0.5 + engine_fds)
1400 * = maxconn * (4 + 1 + 2*engine_fds) / 2
1401 */
1402 maxconn = 2 * remain / (5 + 2 * engine_fds);
1403 } else {
1404 /* maxsock = maxconn * 2 + maxconn * engine_fds.
1405 * = maxconn * (2 + engine_fds)
1406 */
1407 maxconn = remain / (2 + engine_fds);
1408 }
1409
Willy Tarreaudf23c0c2019-03-13 10:10:49 +01001410 return MAX(maxconn, DEFAULT_MAXCONN);
Willy Tarreauac350932019-03-01 15:43:14 +01001411}
1412
Willy Tarreaua409f302020-03-10 17:08:53 +01001413/* computes the estimated maxsock value for the given maxconn based on the
1414 * possibly set global.maxpipes and existing partial global.maxsock. It may
1415 * temporarily change global.maxconn for the time needed to propagate the
1416 * computations, and will reset it.
1417 */
1418static int compute_ideal_maxsock(int maxconn)
1419{
1420 int maxpipes = global.maxpipes;
1421 int maxsock = global.maxsock;
1422
1423
1424 if (!maxpipes) {
1425 int old_maxconn = global.maxconn;
1426
1427 global.maxconn = maxconn;
1428 maxpipes = compute_ideal_maxpipes();
1429 global.maxconn = old_maxconn;
1430 }
1431
1432 maxsock += maxconn * 2; /* each connection needs two sockets */
1433 maxsock += maxpipes * 2; /* each pipe needs two FDs */
1434 maxsock += global.nbthread; /* one epoll_fd/kqueue_fd per thread */
1435 maxsock += 2 * global.nbthread; /* one wake-up pipe (2 fd) per thread */
1436
1437 /* compute fd used by async engines */
1438 if (global.ssl_used_async_engines) {
1439 int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
1440
1441 maxsock += maxconn * sides * global.ssl_used_async_engines;
1442 }
1443 return maxsock;
1444}
1445
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07001446/* Tests if it is possible to set the current process's RLIMIT_NOFILE to
Willy Tarreau304e17e2020-03-10 17:54:54 +01001447 * <maxsock>, then sets it back to the previous value. Returns non-zero if the
1448 * value is accepted, non-zero otherwise. This is used to determine if an
1449 * automatic limit may be applied or not. When it is not, the caller knows that
1450 * the highest we can do is the rlim_max at boot. In case of error, we return
1451 * that the setting is possible, so that we defer the error processing to the
1452 * final stage in charge of enforcing this.
1453 */
1454static int check_if_maxsock_permitted(int maxsock)
1455{
1456 struct rlimit orig_limit, test_limit;
1457 int ret;
1458
Willy Tarreau2df1fbf2022-04-25 18:02:03 +02001459 if (global.fd_hard_limit && maxsock > global.fd_hard_limit)
1460 return 0;
1461
Willy Tarreau304e17e2020-03-10 17:54:54 +01001462 if (getrlimit(RLIMIT_NOFILE, &orig_limit) != 0)
1463 return 1;
1464
1465 /* don't go further if we can't even set to what we have */
Willy Tarreauc06557c2022-09-22 16:12:08 +02001466 if (raise_rlim_nofile(NULL, &orig_limit) != 0)
Willy Tarreau304e17e2020-03-10 17:54:54 +01001467 return 1;
1468
1469 test_limit.rlim_max = MAX(maxsock, orig_limit.rlim_max);
1470 test_limit.rlim_cur = test_limit.rlim_max;
Willy Tarreauc06557c2022-09-22 16:12:08 +02001471 ret = raise_rlim_nofile(NULL, &test_limit);
Willy Tarreau304e17e2020-03-10 17:54:54 +01001472
Willy Tarreauc06557c2022-09-22 16:12:08 +02001473 if (raise_rlim_nofile(NULL, &orig_limit) != 0)
Willy Tarreau304e17e2020-03-10 17:54:54 +01001474 return 1;
1475
1476 return ret == 0;
1477}
1478
Willy Tarreau34527d52022-02-17 17:45:58 +01001479/* This performs th every basic early initialization at the end of the PREPARE
1480 * init stage. It may only assume that list heads are initialized, but not that
1481 * anything else is correct. It will initialize a number of variables that
1482 * depend on command line and will pre-parse the command line. If it fails, it
1483 * directly exits.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001484 */
Willy Tarreau34527d52022-02-17 17:45:58 +01001485static void init_early(int argc, char **argv)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001486{
Kevinm48936af2010-12-22 16:08:21 +00001487 char *progname;
Willy Tarreau34527d52022-02-17 17:45:58 +01001488 char *tmp;
1489 int len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001490
Willy Tarreau34527d52022-02-17 17:45:58 +01001491 /* First, let's initialize most global variables */
1492 totalconn = actconn = listeners = stopping = 0;
1493 killed = pid = 0;
1494
1495 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
1496 global.rlimit_memmax_all = HAPROXY_MEMMAX;
Christopher Faulete3a5e352017-10-24 13:53:54 +02001497 global.mode = MODE_STARTING;
William Lallemand73b85e72017-06-01 17:38:51 +02001498
Willy Tarreau34527d52022-02-17 17:45:58 +01001499 /* if we were in mworker mode, we should restart in mworker mode */
1500 if (getenv("HAPROXY_MWORKER_REEXEC") != NULL)
1501 global.mode |= MODE_MWORKER;
David du Colombier7af46052012-05-16 14:16:48 +02001502
Willy Tarreau34527d52022-02-17 17:45:58 +01001503 /* initialize date, time, and pid */
1504 tzset();
1505 clock_init_process_date();
1506 start_date = now;
1507 pid = getpid();
1508
1509 /* Set local host name and adjust some environment variables.
1510 * NB: POSIX does not make it mandatory for gethostname() to
1511 * NULL-terminate the string in case of truncation, and at least
1512 * FreeBSD appears not to do it.
Emeric Brun2b920a12010-09-23 18:30:22 +02001513 */
1514 memset(hostname, 0, sizeof(hostname));
1515 gethostname(hostname, sizeof(hostname) - 1);
Dragan Dosen4f014152020-06-18 16:56:47 +02001516
Willy Tarreau34527d52022-02-17 17:45:58 +01001517 /* preset some environment variables */
1518 localpeer = strdup(hostname);
1519 if (!localpeer || setenv("HAPROXY_LOCALPEER", localpeer, 1) < 0) {
Dragan Dosen4f014152020-06-18 16:56:47 +02001520 ha_alert("Cannot allocate memory for local peer.\n");
1521 exit(EXIT_FAILURE);
1522 }
Emeric Brun2b920a12010-09-23 18:30:22 +02001523
Willy Tarreau34527d52022-02-17 17:45:58 +01001524 /* Some CPU affinity stuff may have to be initialized */
1525#ifdef USE_CPU_AFFINITY
1526 {
Willy Tarreau5b093412022-07-08 09:38:30 +02001527 int g, i;
1528
1529 for (g = 0; g < MAX_TGROUPS; g++) {
1530 ha_cpuset_zero(&cpu_map[g].proc);
1531 ha_cpuset_zero(&cpu_map[g].proc_t1);
1532 for (i = 0; i < MAX_THREADS_PER_GROUP; ++i) {
1533 ha_cpuset_zero(&cpu_map[g].thread[i]);
1534 }
Willy Tarreau34527d52022-02-17 17:45:58 +01001535 }
1536 }
1537#endif
Christopher Fauletcd7879a2017-10-27 13:53:47 +02001538
Willy Tarreau34527d52022-02-17 17:45:58 +01001539 /* extract the program name from argv[0], it will be used for the logs
1540 * and error messages.
1541 */
1542 progname = *argv;
1543 while ((tmp = strchr(progname, '/')) != NULL)
1544 progname = tmp + 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001545
Willy Tarreau34527d52022-02-17 17:45:58 +01001546 len = strlen(progname);
1547 progname = strdup(progname);
1548 if (!progname) {
1549 ha_alert("Cannot allocate memory for log_tag.\n");
1550 exit(EXIT_FAILURE);
1551 }
Willy Tarreau84310e22014-02-14 11:59:04 +01001552
Willy Tarreau34527d52022-02-17 17:45:58 +01001553 chunk_initlen(&global.log_tag, progname, len, len);
1554}
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001555
Willy Tarreau392524d2022-02-17 18:10:36 +01001556/* handles program arguments. Very minimal parsing is performed, variables are
1557 * fed with some values, and lists are completed with other ones. In case of
1558 * error, it will exit.
Willy Tarreau34527d52022-02-17 17:45:58 +01001559 */
Willy Tarreau392524d2022-02-17 18:10:36 +01001560static void init_args(int argc, char **argv)
Willy Tarreau34527d52022-02-17 17:45:58 +01001561{
Willy Tarreau34527d52022-02-17 17:45:58 +01001562 char *progname = global.log_tag.area;
Willy Tarreau392524d2022-02-17 18:10:36 +01001563 char *err_msg = NULL;
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +01001564
Willy Tarreau34527d52022-02-17 17:45:58 +01001565 /* pre-fill in the global tuning options before we let the cmdline
1566 * change them.
1567 */
Willy Tarreau43b78992009-01-25 15:42:27 +01001568 global.tune.options |= GTUNE_USE_SELECT; /* select() is always available */
Willy Tarreaue5733232019-05-22 19:24:06 +02001569#if defined(USE_POLL)
Willy Tarreau43b78992009-01-25 15:42:27 +01001570 global.tune.options |= GTUNE_USE_POLL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001571#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001572#if defined(USE_EPOLL)
Willy Tarreau43b78992009-01-25 15:42:27 +01001573 global.tune.options |= GTUNE_USE_EPOLL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001574#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001575#if defined(USE_KQUEUE)
Willy Tarreau43b78992009-01-25 15:42:27 +01001576 global.tune.options |= GTUNE_USE_KQUEUE;
Willy Tarreau1e63130a2007-04-09 12:03:06 +02001577#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001578#if defined(USE_EVPORTS)
Emmanuel Hocdet0ba4f482019-04-08 16:53:32 +00001579 global.tune.options |= GTUNE_USE_EVPORTS;
1580#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001581#if defined(USE_LINUX_SPLICE)
Willy Tarreau3ab68cf2009-01-25 16:03:28 +01001582 global.tune.options |= GTUNE_USE_SPLICE;
1583#endif
Nenad Merdanovic88afe032014-04-14 15:56:58 +02001584#if defined(USE_GETADDRINFO)
1585 global.tune.options |= GTUNE_USE_GAI;
1586#endif
Lukas Tribusa0bcbdc2016-09-12 21:42:20 +00001587#if defined(SO_REUSEPORT)
1588 global.tune.options |= GTUNE_USE_REUSEPORT;
1589#endif
Willy Tarreau76cc6992020-07-01 18:49:24 +02001590#ifdef USE_THREAD
1591 global.tune.options |= GTUNE_IDLE_POOL_SHARED;
1592#endif
Amaury Denoyellee30f3782022-11-21 11:54:13 +01001593#ifdef USE_QUIC
1594 global.tune.options |= GTUNE_QUIC_SOCK_PER_CONN;
1595#endif
William Dauchya5194602020-03-28 19:29:58 +01001596 global.tune.options |= GTUNE_STRICT_LIMITS;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001597
Willy Tarreau392524d2022-02-17 18:10:36 +01001598 /* keep a copy of original arguments for the master process */
1599 old_argv = copy_argv(argc, argv);
1600 if (!old_argv) {
1601 ha_alert("failed to copy argv.\n");
1602 exit(EXIT_FAILURE);
1603 }
1604
1605 /* skip program name and start */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001606 argc--; argv++;
1607 while (argc > 0) {
1608 char *flag;
1609
1610 if (**argv == '-') {
1611 flag = *argv+1;
1612
1613 /* 1 arg */
1614 if (*flag == 'v') {
1615 display_version();
Willy Tarreau7b066db2007-12-02 11:28:59 +01001616 if (flag[1] == 'v') /* -vv */
1617 display_build_opts();
Tim Duesterhus77b3db02022-04-27 00:08:11 +02001618 deinit_and_exit(0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001619 }
Willy Tarreaue5733232019-05-22 19:24:06 +02001620#if defined(USE_EPOLL)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001621 else if (*flag == 'd' && flag[1] == 'e')
Willy Tarreau43b78992009-01-25 15:42:27 +01001622 global.tune.options &= ~GTUNE_USE_EPOLL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001623#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001624#if defined(USE_POLL)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001625 else if (*flag == 'd' && flag[1] == 'p')
Willy Tarreau43b78992009-01-25 15:42:27 +01001626 global.tune.options &= ~GTUNE_USE_POLL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001627#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001628#if defined(USE_KQUEUE)
Willy Tarreau1e63130a2007-04-09 12:03:06 +02001629 else if (*flag == 'd' && flag[1] == 'k')
Willy Tarreau43b78992009-01-25 15:42:27 +01001630 global.tune.options &= ~GTUNE_USE_KQUEUE;
Willy Tarreau1e63130a2007-04-09 12:03:06 +02001631#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001632#if defined(USE_EVPORTS)
Emmanuel Hocdet0ba4f482019-04-08 16:53:32 +00001633 else if (*flag == 'd' && flag[1] == 'v')
1634 global.tune.options &= ~GTUNE_USE_EVPORTS;
1635#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001636#if defined(USE_LINUX_SPLICE)
Willy Tarreau3ab68cf2009-01-25 16:03:28 +01001637 else if (*flag == 'd' && flag[1] == 'S')
1638 global.tune.options &= ~GTUNE_USE_SPLICE;
1639#endif
Nenad Merdanovic88afe032014-04-14 15:56:58 +02001640#if defined(USE_GETADDRINFO)
1641 else if (*flag == 'd' && flag[1] == 'G')
1642 global.tune.options &= ~GTUNE_USE_GAI;
1643#endif
Lukas Tribusa0bcbdc2016-09-12 21:42:20 +00001644#if defined(SO_REUSEPORT)
1645 else if (*flag == 'd' && flag[1] == 'R')
1646 global.tune.options &= ~GTUNE_USE_REUSEPORT;
1647#endif
Emeric Brun850efd52014-01-29 12:24:34 +01001648 else if (*flag == 'd' && flag[1] == 'V')
1649 global.ssl_server_verify = SSL_SERVER_VERIFY_NONE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001650 else if (*flag == 'V')
1651 arg_mode |= MODE_VERBOSE;
Erwan Le Goasb0c05012022-09-14 17:51:55 +02001652 else if (*flag == 'd' && flag[1] == 'C') {
Erwan Le Goasf30c5d72022-09-29 10:34:04 +02001653 char *end;
1654 char *key;
1655
1656 key = flag + 2;
1657 for (;key && *key; key = end) {
1658 end = strchr(key, ',');
1659 if (end)
1660 *(end++) = 0;
1661
1662 if (strcmp(key, "line") == 0)
1663 arg_mode |= MODE_DUMP_NB_L;
1664
1665 }
Erwan Le Goasb0c05012022-09-14 17:51:55 +02001666 arg_mode |= MODE_DUMP_CFG;
1667 HA_ATOMIC_STORE(&global.anon_key, atoll(flag + 2));
1668 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001669 else if (*flag == 'd' && flag[1] == 'b')
1670 arg_mode |= MODE_FOREGROUND;
Amaury Denoyelle7b01a8d2021-03-29 10:29:07 +02001671 else if (*flag == 'd' && flag[1] == 'D')
1672 arg_mode |= MODE_DIAG;
Willy Tarreau3eb10b82020-04-15 16:42:39 +02001673 else if (*flag == 'd' && flag[1] == 'W')
1674 arg_mode |= MODE_ZERO_WARNING;
Willy Tarreauef301b72022-02-23 14:15:18 +01001675 else if (*flag == 'd' && flag[1] == 'M') {
Willy Tarreau1408b1f2022-02-18 18:54:40 +01001676 int ret = pool_parse_debugging(flag + 2, &err_msg);
1677
1678 if (ret <= -1) {
1679 if (ret < -1)
1680 ha_alert("-dM: %s\n", err_msg);
1681 else
1682 printf("%s\n", err_msg);
1683 ha_free(&err_msg);
1684 exit(ret < -1 ? EXIT_FAILURE : 0);
1685 } else if (ret == 0) {
1686 ha_warning("-dM: %s\n", err_msg);
1687 ha_free(&err_msg);
1688 }
Willy Tarreauef301b72022-02-23 14:15:18 +01001689 }
Willy Tarreau3eed10e2016-11-07 21:03:16 +01001690 else if (*flag == 'd' && flag[1] == 'r')
1691 global.tune.options |= GTUNE_RESOLVE_DONTFAIL;
Willy Tarreau654726d2021-12-28 15:43:11 +01001692#if defined(HA_HAVE_DUMP_LIBS)
1693 else if (*flag == 'd' && flag[1] == 'L')
1694 arg_mode |= MODE_DUMP_LIBS;
1695#endif
Willy Tarreau76871a42022-03-08 16:01:40 +01001696 else if (*flag == 'd' && flag[1] == 'K') {
1697 arg_mode |= MODE_DUMP_KWD;
1698 kwd_dump = flag + 2;
1699 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001700 else if (*flag == 'd')
1701 arg_mode |= MODE_DEBUG;
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02001702 else if (*flag == 'c' && flag[1] == 'c') {
1703 arg_mode |= MODE_CHECK_CONDITION;
1704 argv++;
1705 argc--;
1706 check_condition = *argv;
1707 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001708 else if (*flag == 'c')
1709 arg_mode |= MODE_CHECK;
William Lallemand095ba4c2017-06-01 17:38:50 +02001710 else if (*flag == 'D')
Willy Tarreau6bde87b2009-05-18 16:29:51 +02001711 arg_mode |= MODE_DAEMON;
Tim Duesterhusd6942c82017-11-20 15:58:35 +01001712 else if (*flag == 'W' && flag[1] == 's') {
Lukas Tribusf46bf952017-11-21 12:39:34 +01001713 arg_mode |= MODE_MWORKER | MODE_FOREGROUND;
Tim Duesterhusd6942c82017-11-20 15:58:35 +01001714#if defined(USE_SYSTEMD)
1715 global.tune.options |= GTUNE_USE_SYSTEMD;
1716#else
Christopher Faulet767a84b2017-11-24 16:50:31 +01001717 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 +01001718 usage(progname);
1719#endif
1720 }
William Lallemand095ba4c2017-06-01 17:38:50 +02001721 else if (*flag == 'W')
1722 arg_mode |= MODE_MWORKER;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001723 else if (*flag == 'q')
1724 arg_mode |= MODE_QUIET;
Olivier Houchardf73629d2017-04-05 22:33:04 +02001725 else if (*flag == 'x') {
William Lallemand4f71d302020-06-04 23:41:29 +02001726 if (argc <= 1) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001727 ha_alert("Unix socket path expected with the -x flag\n\n");
William Lallemand45eff442017-06-19 15:57:55 +02001728 usage(progname);
Olivier Houchardf73629d2017-04-05 22:33:04 +02001729 }
William Lallemand4fc09692017-06-19 16:37:19 +02001730 if (old_unixsocket)
Christopher Faulet767a84b2017-11-24 16:50:31 +01001731 ha_warning("-x option already set, overwriting the value\n");
Olivier Houchardf73629d2017-04-05 22:33:04 +02001732 old_unixsocket = argv[1];
William Lallemand4fc09692017-06-19 16:37:19 +02001733
Olivier Houchardf73629d2017-04-05 22:33:04 +02001734 argv++;
1735 argc--;
1736 }
William Lallemande7361152018-10-26 14:47:36 +02001737 else if (*flag == 'S') {
1738 struct wordlist *c;
1739
William Lallemanda6b32492020-06-04 23:49:20 +02001740 if (argc <= 1) {
William Lallemande7361152018-10-26 14:47:36 +02001741 ha_alert("Socket and optional bind parameters expected with the -S flag\n");
1742 usage(progname);
1743 }
1744 if ((c = malloc(sizeof(*c))) == NULL || (c->s = strdup(argv[1])) == NULL) {
1745 ha_alert("Cannot allocate memory\n");
1746 exit(EXIT_FAILURE);
1747 }
Willy Tarreau2b718102021-04-21 07:32:39 +02001748 LIST_INSERT(&mworker_cli_conf, &c->list);
William Lallemande7361152018-10-26 14:47:36 +02001749
1750 argv++;
1751 argc--;
1752 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001753 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
1754 /* list of pids to finish ('f') or terminate ('t') */
1755
1756 if (flag[1] == 'f')
1757 oldpids_sig = SIGUSR1; /* finish then exit */
1758 else
1759 oldpids_sig = SIGTERM; /* terminate immediately */
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001760 while (argc > 1 && argv[1][0] != '-') {
Chris Lane236062f2018-02-05 23:15:44 +00001761 char * endptr = NULL;
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001762 oldpids = realloc(oldpids, (nb_oldpids + 1) * sizeof(int));
1763 if (!oldpids) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001764 ha_alert("Cannot allocate old pid : out of memory.\n");
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001765 exit(1);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001766 }
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001767 argc--; argv++;
Chris Lane236062f2018-02-05 23:15:44 +00001768 errno = 0;
1769 oldpids[nb_oldpids] = strtol(*argv, &endptr, 10);
1770 if (errno) {
1771 ha_alert("-%2s option: failed to parse {%s}: %s\n",
1772 flag,
1773 *argv, strerror(errno));
1774 exit(1);
1775 } else if (endptr && strlen(endptr)) {
Willy Tarreau90807112020-02-25 08:16:33 +01001776 while (isspace((unsigned char)*endptr)) endptr++;
Aurélien Nephtali39b89882018-02-17 20:53:11 +01001777 if (*endptr != 0) {
Chris Lane236062f2018-02-05 23:15:44 +00001778 ha_alert("-%2s option: some bytes unconsumed in PID list {%s}\n",
1779 flag, endptr);
1780 exit(1);
Aurélien Nephtali39b89882018-02-17 20:53:11 +01001781 }
Chris Lane236062f2018-02-05 23:15:44 +00001782 }
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001783 if (oldpids[nb_oldpids] <= 0)
1784 usage(progname);
1785 nb_oldpids++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001786 }
1787 }
Willy Tarreaua088d312015-10-08 11:58:48 +02001788 else if (flag[0] == '-' && flag[1] == 0) { /* "--" */
1789 /* now that's a cfgfile list */
1790 argv++; argc--;
1791 while (argc > 0) {
Maxime de Roucy0f503922016-05-13 23:52:55 +02001792 if (!list_append_word(&cfg_cfgfiles, *argv, &err_msg)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001793 ha_alert("Cannot load configuration file/directory %s : %s\n",
1794 *argv,
1795 err_msg);
Willy Tarreaua088d312015-10-08 11:58:48 +02001796 exit(1);
1797 }
Willy Tarreaua088d312015-10-08 11:58:48 +02001798 argv++; argc--;
1799 }
1800 break;
1801 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001802 else { /* >=2 args */
1803 argv++; argc--;
1804 if (argc == 0)
Willy Tarreau3bafcdc2011-09-10 19:20:23 +02001805 usage(progname);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001806
1807 switch (*flag) {
Willy Tarreau576132e2011-09-10 19:26:56 +02001808 case 'C' : change_dir = *argv; break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001809 case 'n' : cfg_maxconn = atol(*argv); break;
Willy Tarreau70060452015-12-14 12:46:07 +01001810 case 'm' : global.rlimit_memmax_all = atol(*argv); break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001811 case 'N' : cfg_maxpconn = atol(*argv); break;
William Lallemanddaf4cd22018-04-17 16:46:13 +02001812 case 'L' :
Dragan Dosen4f014152020-06-18 16:56:47 +02001813 free(localpeer);
1814 if ((localpeer = strdup(*argv)) == NULL) {
1815 ha_alert("Cannot allocate memory for local peer.\n");
1816 exit(EXIT_FAILURE);
1817 }
William Lallemanddaf4cd22018-04-17 16:46:13 +02001818 setenv("HAPROXY_LOCALPEER", localpeer, 1);
Dragan Dosen13cd54c2020-06-18 18:24:05 +02001819 global.localpeer_cmdline = 1;
William Lallemanddaf4cd22018-04-17 16:46:13 +02001820 break;
Willy Tarreau5d01a632009-06-22 16:02:30 +02001821 case 'f' :
Maxime de Roucy0f503922016-05-13 23:52:55 +02001822 if (!list_append_word(&cfg_cfgfiles, *argv, &err_msg)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001823 ha_alert("Cannot load configuration file/directory %s : %s\n",
1824 *argv,
1825 err_msg);
Willy Tarreau5d01a632009-06-22 16:02:30 +02001826 exit(1);
1827 }
Willy Tarreau5d01a632009-06-22 16:02:30 +02001828 break;
Willy Tarreau392524d2022-02-17 18:10:36 +01001829 case 'p' :
1830 free(global.pidfile);
1831 if ((global.pidfile = strdup(*argv)) == NULL) {
1832 ha_alert("Cannot allocate memory for pidfile.\n");
1833 exit(EXIT_FAILURE);
1834 }
1835 break;
Willy Tarreau3bafcdc2011-09-10 19:20:23 +02001836 default: usage(progname);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001837 }
1838 }
1839 }
1840 else
Willy Tarreau3bafcdc2011-09-10 19:20:23 +02001841 usage(progname);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001842 argv++; argc--;
1843 }
Willy Tarreau392524d2022-02-17 18:10:36 +01001844 free(err_msg);
1845}
1846
Willy Tarreau76871a42022-03-08 16:01:40 +01001847/* call the various keyword dump functions based on the comma-delimited list of
1848 * classes in kwd_dump.
1849 */
1850static void dump_registered_keywords(void)
1851{
1852 char *end;
1853 int all __maybe_unused = 0;
1854
1855 for (; kwd_dump && *kwd_dump; kwd_dump = end) {
1856 end = strchr(kwd_dump, ',');
1857 if (end)
1858 *(end++) = 0;
1859
1860 if (strcmp(kwd_dump, "help") == 0) {
1861 printf("# List of supported keyword classes:\n");
1862 printf("all: list all keywords\n");
Willy Tarreau6ff7d1b2022-03-29 15:36:56 +02001863 printf("acl: ACL keywords\n");
Willy Tarreauca1acd62022-03-29 15:02:44 +02001864 printf("cfg: configuration keywords\n");
Willy Tarreau06d0e2e2022-03-29 15:25:30 +02001865 printf("cli: CLI keywords\n");
Willy Tarreau29d799d2022-03-29 16:59:49 +02001866 printf("cnv: sample converter keywords\n");
Willy Tarreau3b65e142022-03-29 15:03:09 +02001867 printf("flt: filter names\n");
Willy Tarreauf78813f2022-03-29 16:51:29 +02001868 printf("smp: sample fetch functions\n");
Willy Tarreau5fcc1002022-03-29 15:10:44 +02001869 printf("svc: service names\n");
Willy Tarreau76871a42022-03-08 16:01:40 +01001870 continue;
1871 }
1872 else if (strcmp(kwd_dump, "all") == 0) {
1873 all = 1;
1874 }
Willy Tarreauca1acd62022-03-29 15:02:44 +02001875
Willy Tarreau6ff7d1b2022-03-29 15:36:56 +02001876 if (all || strcmp(kwd_dump, "acl") == 0) {
1877 printf("# List of registered ACL keywords:\n");
1878 acl_dump_kwd();
1879 }
1880
Willy Tarreauca1acd62022-03-29 15:02:44 +02001881 if (all || strcmp(kwd_dump, "cfg") == 0) {
1882 printf("# List of registered configuration keywords:\n");
1883 cfg_dump_registered_keywords();
1884 }
Willy Tarreau3b65e142022-03-29 15:03:09 +02001885
Willy Tarreau06d0e2e2022-03-29 15:25:30 +02001886 if (all || strcmp(kwd_dump, "cli") == 0) {
1887 printf("# List of registered CLI keywords:\n");
1888 cli_list_keywords();
1889 }
1890
Willy Tarreau29d799d2022-03-29 16:59:49 +02001891 if (all || strcmp(kwd_dump, "cnv") == 0) {
1892 printf("# List of registered sample converter functions:\n");
1893 smp_dump_conv_kw();
1894 }
1895
Willy Tarreau3b65e142022-03-29 15:03:09 +02001896 if (all || strcmp(kwd_dump, "flt") == 0) {
1897 printf("# List of registered filter names:\n");
1898 flt_dump_kws(NULL);
1899 }
Willy Tarreau5fcc1002022-03-29 15:10:44 +02001900
Willy Tarreauf78813f2022-03-29 16:51:29 +02001901 if (all || strcmp(kwd_dump, "smp") == 0) {
1902 printf("# List of registered sample fetch functions:\n");
1903 smp_dump_fetch_kw();
1904 }
1905
Willy Tarreau5fcc1002022-03-29 15:10:44 +02001906 if (all || strcmp(kwd_dump, "svc") == 0) {
1907 printf("# List of registered service names:\n");
1908 list_services(NULL);
1909 }
Willy Tarreau76871a42022-03-08 16:01:40 +01001910 }
1911}
1912
Amaury Denoyelle28ea31c2022-11-14 16:18:46 +01001913/* Generate a random cluster-secret in case the setting is not provided in the
1914 * configuration. This allows to use features which rely on it albeit with some
1915 * limitations.
1916 */
1917static void generate_random_cluster_secret()
1918{
1919 /* used as a default random cluster-secret if none defined. */
1920 uint64_t rand = ha_random64();
1921
1922 /* The caller must not overwrite an already defined secret. */
1923 BUG_ON(global.cluster_secret);
1924
1925 global.cluster_secret = malloc(8);
1926 if (!global.cluster_secret)
1927 return;
1928
1929 memcpy(global.cluster_secret, &rand, sizeof(rand));
1930 global.cluster_secret[7] = '\0';
1931}
1932
Willy Tarreau392524d2022-02-17 18:10:36 +01001933/*
1934 * This function initializes all the necessary variables. It only returns
1935 * if everything is OK. If something fails, it exits.
1936 */
1937static void init(int argc, char **argv)
1938{
1939 char *progname = global.log_tag.area;
1940 int err_code = 0;
1941 struct wordlist *wl;
1942 struct proxy *px;
1943 struct post_check_fct *pcf;
William Lallemandb53eb872022-04-21 18:02:53 +02001944 struct pre_check_fct *prcf;
Willy Tarreau392524d2022-02-17 18:10:36 +01001945 int ideal_maxconn;
1946
William Lallemand151dbbe2022-12-02 17:17:43 +01001947#ifdef USE_OPENSSL
1948#ifdef USE_OPENSSL_WOLFSSL
1949 wolfSSL_Init();
1950 wolfSSL_Debugging_ON();
1951#endif
1952#if (HA_OPENSSL_VERSION_NUMBER < 0x1010000fL)
William Lallemand44c80ce2022-12-02 17:06:59 +01001953 /* Initialize the error strings of OpenSSL
1954 * It only needs to be done explicitly with older versions of the SSL
1955 * library. On newer versions, errors strings are loaded during start
1956 * up. */
1957 SSL_load_error_strings();
1958#endif
William Lallemand151dbbe2022-12-02 17:17:43 +01001959#endif
William Lallemand44c80ce2022-12-02 17:06:59 +01001960
William Lallemandeba6a542022-09-26 12:54:39 +02001961 startup_logs_init();
1962
Willy Tarreau392524d2022-02-17 18:10:36 +01001963 if (!init_trash_buffers(1)) {
1964 ha_alert("failed to initialize trash buffers.\n");
1965 exit(1);
1966 }
1967
1968 if (init_acl() != 0)
1969 exit(1);
1970
1971 /* Initialise lua. */
1972 hlua_init();
Willy Tarreaubaaee002006-06-26 02:48:02 +02001973
Christopher Faulete3a5e352017-10-24 13:53:54 +02001974 global.mode |= (arg_mode & (MODE_DAEMON | MODE_MWORKER | MODE_FOREGROUND | MODE_VERBOSE
Amaury Denoyelle7b01a8d2021-03-29 10:29:07 +02001975 | MODE_QUIET | MODE_CHECK | MODE_DEBUG | MODE_ZERO_WARNING
Erwan Le Goasf30c5d72022-09-29 10:34:04 +02001976 | MODE_DIAG | MODE_CHECK_CONDITION | MODE_DUMP_LIBS | MODE_DUMP_KWD
1977 | MODE_DUMP_CFG | MODE_DUMP_NB_L));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001978
William Lallemand944e6192018-11-21 15:48:31 +01001979 if (getenv("HAPROXY_MWORKER_WAIT_ONLY")) {
William Lallemandcb11fd22017-06-01 17:38:52 +02001980 unsetenv("HAPROXY_MWORKER_WAIT_ONLY");
William Lallemand944e6192018-11-21 15:48:31 +01001981 global.mode |= MODE_MWORKER_WAIT;
1982 global.mode &= ~MODE_MWORKER;
William Lallemandcb11fd22017-06-01 17:38:52 +02001983 }
1984
William Lallemand40db4ae2022-12-07 15:03:55 +01001985 /* set the atexit functions when not doing configuration check */
1986 if (!(global.mode & (MODE_CHECK | MODE_CHECK_CONDITION))
1987 && (getenv("HAPROXY_MWORKER_REEXEC") != NULL)) {
1988
1989 if (global.mode & MODE_MWORKER) {
1990 atexit_flag = 1;
1991 atexit(reexec_on_failure);
1992 } else if (global.mode & MODE_MWORKER_WAIT) {
1993 atexit_flag = 1;
1994 atexit(exit_on_waitmode_failure);
1995 }
William Lallemandcb11fd22017-06-01 17:38:52 +02001996 }
1997
Willy Tarreau576132e2011-09-10 19:26:56 +02001998 if (change_dir && chdir(change_dir) < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001999 ha_alert("Could not change to directory %s : %s\n", change_dir, strerror(errno));
Willy Tarreau576132e2011-09-10 19:26:56 +02002000 exit(1);
2001 }
2002
Amaury Denoyelle11124302021-06-04 18:22:08 +02002003 usermsgs_clr("config");
2004
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02002005 if (global.mode & MODE_CHECK_CONDITION) {
2006 int result;
2007
2008 uint32_t err;
2009 const char *errptr;
2010 char *errmsg = NULL;
2011
2012 char *args[MAX_LINE_ARGS+1];
2013 int arg = sizeof(args) / sizeof(*args);
William Lallemand89e236f2022-05-06 17:22:36 +02002014 size_t outlen;
Willy Tarreauc8194c32021-07-16 16:38:58 +02002015 char *w;
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02002016
William Lallemand89e236f2022-05-06 17:22:36 +02002017 if (!check_condition)
2018 usage(progname);
2019
2020 outlen = strlen(check_condition) + 1;
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02002021 err = parse_line(check_condition, check_condition, &outlen, args, &arg,
Willy Tarreaua87e7822021-07-16 19:14:54 +02002022 PARSE_OPT_ENV | PARSE_OPT_WORD_EXPAND | PARSE_OPT_DQUOTE | PARSE_OPT_SQUOTE | PARSE_OPT_BKSLASH,
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02002023 &errptr);
2024
2025 if (err & PARSE_ERR_QUOTE) {
2026 ha_alert("Syntax Error in condition: Unmatched quote.\n");
2027 exit(2);
2028 }
2029
2030 if (err & PARSE_ERR_HEX) {
2031 ha_alert("Syntax Error in condition: Truncated or invalid hexadecimal sequence.\n");
2032 exit(2);
2033 }
2034
2035 if (err & (PARSE_ERR_TOOLARGE|PARSE_ERR_OVERLAP)) {
2036 ha_alert("Error in condition: Line too long.\n");
2037 exit(2);
2038 }
2039
Willy Tarreauc8194c32021-07-16 16:38:58 +02002040 if (err & PARSE_ERR_TOOMANY) {
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02002041 ha_alert("Error in condition: Too many words.\n");
2042 exit(2);
2043 }
2044
2045 if (err) {
2046 ha_alert("Unhandled error in condition, please report this to the developers.\n");
2047 exit(2);
2048 }
2049
Willy Tarreauc8194c32021-07-16 16:38:58 +02002050 /* remerge all words into a single expression */
2051 for (w = *args; (w += strlen(w)) < check_condition + outlen - 1; *w = ' ')
2052 ;
2053
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02002054 result = cfg_eval_condition(args, &errmsg, &errptr);
2055
2056 if (result < 0) {
2057 if (errmsg)
2058 ha_alert("Failed to evaluate condition: %s\n", errmsg);
2059
2060 exit(2);
2061 }
2062
2063 exit(result ? 0 : 1);
2064 }
2065
William Lallemand944e6192018-11-21 15:48:31 +01002066 /* in wait mode, we don't try to read the configuration files */
2067 if (!(global.mode & MODE_MWORKER_WAIT)) {
Christopher Faulet4e366822021-01-12 18:57:38 +01002068 char *env_cfgfiles = NULL;
2069 int env_err = 0;
Willy Tarreauc4382422009-12-06 13:10:44 +01002070
William Lallemand944e6192018-11-21 15:48:31 +01002071 /* handle cfgfiles that are actually directories */
2072 cfgfiles_expand_directories();
2073
2074 if (LIST_ISEMPTY(&cfg_cfgfiles))
2075 usage(progname);
2076
Sébastien Gross537b9e72022-11-30 22:36:50 +01002077 /* temporary create environment variables with default
2078 * values to ease user configuration. Do not forget to
2079 * unset them after the list_for_each_entry loop.
2080 */
2081 setenv("HAPROXY_HTTP_LOG_FMT", default_http_log_format, 1);
2082 setenv("HAPROXY_HTTPS_LOG_FMT", default_https_log_format, 1);
2083 setenv("HAPROXY_TCP_LOG_FMT", default_tcp_log_format, 1);
William Lallemand944e6192018-11-21 15:48:31 +01002084 list_for_each_entry(wl, &cfg_cfgfiles, list) {
2085 int ret;
2086
Christopher Faulet4e366822021-01-12 18:57:38 +01002087 if (env_err == 0) {
2088 if (!memprintf(&env_cfgfiles, "%s%s%s",
2089 (env_cfgfiles ? env_cfgfiles : ""),
2090 (env_cfgfiles ? ";" : ""), wl->s))
2091 env_err = 1;
2092 }
William Lallemand7b302d82019-05-20 11:15:37 +02002093
William Lallemand944e6192018-11-21 15:48:31 +01002094 ret = readcfgfile(wl->s);
2095 if (ret == -1) {
2096 ha_alert("Could not open configuration file %s : %s\n",
2097 wl->s, strerror(errno));
Christopher Faulet4e366822021-01-12 18:57:38 +01002098 free(env_cfgfiles);
William Lallemand944e6192018-11-21 15:48:31 +01002099 exit(1);
2100 }
2101 if (ret & (ERR_ABORT|ERR_FATAL))
2102 ha_alert("Error(s) found in configuration file : %s\n", wl->s);
2103 err_code |= ret;
Christopher Faulet4e366822021-01-12 18:57:38 +01002104 if (err_code & ERR_ABORT) {
2105 free(env_cfgfiles);
William Lallemand944e6192018-11-21 15:48:31 +01002106 exit(1);
Christopher Faulet4e366822021-01-12 18:57:38 +01002107 }
Willy Tarreauc4382422009-12-06 13:10:44 +01002108 }
Sébastien Gross537b9e72022-11-30 22:36:50 +01002109 /* remove temporary environment variables. */
2110 unsetenv("HAPROXY_HTTP_LOG_FMT");
2111 unsetenv("HAPROXY_HTTPS_LOG_FMT");
2112 unsetenv("HAPROXY_TCP_LOG_FMT");
Krzysztof Oledzkib304dc72007-10-14 23:40:01 +02002113
William Lallemand944e6192018-11-21 15:48:31 +01002114 /* do not try to resolve arguments nor to spot inconsistencies when
2115 * the configuration contains fatal errors caused by files not found
2116 * or failed memory allocations.
2117 */
2118 if (err_code & (ERR_ABORT|ERR_FATAL)) {
2119 ha_alert("Fatal errors found in configuration.\n");
Christopher Faulet4e366822021-01-12 18:57:38 +01002120 free(env_cfgfiles);
William Lallemand944e6192018-11-21 15:48:31 +01002121 exit(1);
2122 }
Christopher Faulet4e366822021-01-12 18:57:38 +01002123 if (env_err) {
2124 ha_alert("Could not allocate memory for HAPROXY_CFGFILES env variable\n");
2125 exit(1);
2126 }
2127 setenv("HAPROXY_CFGFILES", env_cfgfiles, 1);
2128 free(env_cfgfiles);
William Lallemand7b302d82019-05-20 11:15:37 +02002129
Willy Tarreaub83dc3d2017-04-19 11:24:07 +02002130 }
William Lallemandce83b4a2018-10-26 14:47:30 +02002131 if (global.mode & MODE_MWORKER) {
William Lallemand16dd1b32018-11-19 18:46:18 +01002132 struct mworker_proc *tmproc;
2133
William Lallemand482f9a92019-04-12 16:15:00 +02002134 setenv("HAPROXY_MWORKER", "1", 1);
2135
William Lallemand16dd1b32018-11-19 18:46:18 +01002136 if (getenv("HAPROXY_MWORKER_REEXEC") == NULL) {
2137
William Lallemand56be0e02022-01-28 21:11:41 +01002138 tmproc = mworker_proc_new();
William Lallemand16dd1b32018-11-19 18:46:18 +01002139 if (!tmproc) {
2140 ha_alert("Cannot allocate process structures.\n");
2141 exit(EXIT_FAILURE);
2142 }
William Lallemand8f7069a2019-04-12 16:09:23 +02002143 tmproc->options |= PROC_O_TYPE_MASTER; /* master */
William Lallemand16dd1b32018-11-19 18:46:18 +01002144 tmproc->pid = pid;
2145 tmproc->timestamp = start_date.tv_sec;
William Lallemand16dd1b32018-11-19 18:46:18 +01002146 proc_self = tmproc;
2147
Willy Tarreau2b718102021-04-21 07:32:39 +02002148 LIST_APPEND(&proc_list, &tmproc->list);
William Lallemand16dd1b32018-11-19 18:46:18 +01002149 }
William Lallemandce83b4a2018-10-26 14:47:30 +02002150
William Lallemand56be0e02022-01-28 21:11:41 +01002151 tmproc = mworker_proc_new();
Willy Tarreau6185a032021-06-15 08:02:06 +02002152 if (!tmproc) {
2153 ha_alert("Cannot allocate process structures.\n");
2154 exit(EXIT_FAILURE);
2155 }
Willy Tarreau6185a032021-06-15 08:02:06 +02002156 tmproc->options |= PROC_O_TYPE_WORKER; /* worker */
William Lallemandce83b4a2018-10-26 14:47:30 +02002157
Willy Tarreau6185a032021-06-15 08:02:06 +02002158 if (mworker_cli_sockpair_new(tmproc, 0) < 0) {
2159 exit(EXIT_FAILURE);
William Lallemandce83b4a2018-10-26 14:47:30 +02002160 }
Willy Tarreau6185a032021-06-15 08:02:06 +02002161
2162 LIST_APPEND(&proc_list, &tmproc->list);
William Lallemand944e6192018-11-21 15:48:31 +01002163 }
Willy Tarreau53bfac82022-07-22 17:35:49 +02002164
2165 if (global.mode & MODE_MWORKER_WAIT) {
2166 /* in exec mode, there's always exactly one thread. Failure to
2167 * set these ones now will result in nbthread being detected
2168 * automatically.
2169 */
2170 global.nbtgroups = 1;
2171 global.nbthread = 1;
2172 }
2173
William Lallemand944e6192018-11-21 15:48:31 +01002174 if (global.mode & (MODE_MWORKER|MODE_MWORKER_WAIT)) {
2175 struct wordlist *it, *c;
2176
Remi Tricot-Le Breton1f4fa902021-05-19 10:45:12 +02002177 /* get the info of the children in the env */
2178 if (mworker_env_to_proc_list() < 0) {
2179 exit(EXIT_FAILURE);
2180 }
William Lallemande7361152018-10-26 14:47:36 +02002181
William Lallemand550db6d2018-11-06 17:37:12 +01002182 if (!LIST_ISEMPTY(&mworker_cli_conf)) {
William Lallemandec059c22022-09-22 17:26:23 +02002183 char *path = NULL;
William Lallemande7361152018-10-26 14:47:36 +02002184
William Lallemand550db6d2018-11-06 17:37:12 +01002185 if (mworker_cli_proxy_create() < 0) {
William Lallemande7361152018-10-26 14:47:36 +02002186 ha_alert("Can't create the master's CLI.\n");
2187 exit(EXIT_FAILURE);
2188 }
William Lallemande7361152018-10-26 14:47:36 +02002189
William Lallemand550db6d2018-11-06 17:37:12 +01002190 list_for_each_entry_safe(c, it, &mworker_cli_conf, list) {
2191
William Lallemand21623b52022-09-24 15:51:27 +02002192 if (mworker_cli_proxy_new_listener(c->s) == NULL) {
William Lallemand550db6d2018-11-06 17:37:12 +01002193 ha_alert("Can't create the master's CLI.\n");
2194 exit(EXIT_FAILURE);
2195 }
Willy Tarreau2b718102021-04-21 07:32:39 +02002196 LIST_DELETE(&c->list);
William Lallemand550db6d2018-11-06 17:37:12 +01002197 free(c->s);
2198 free(c);
2199 }
William Lallemande57b7022022-12-07 14:25:41 +01002200 /* Creates the mcli_reload listener, which is the listener used
2201 * to retrieve the master CLI session which asked for the reload.
2202 *
2203 * ipc_fd[1] will be used as a listener, and ipc_fd[0]
2204 * will be used to send the FD of the session.
2205 *
2206 * Both FDs will be kept in the master. The sockets are
2207 * created only if they weren't inherited.
2208 */
2209 if ((proc_self->ipc_fd[1] == -1) &&
2210 socketpair(AF_UNIX, SOCK_STREAM, 0, proc_self->ipc_fd) < 0) {
2211 ha_alert("cannot create the mcli_reload socketpair.\n");
2212 exit(EXIT_FAILURE);
2213 }
2214
William Lallemandec059c22022-09-22 17:26:23 +02002215 /* Create the mcli_reload listener from the proc_self struct */
2216 memprintf(&path, "sockpair@%d", proc_self->ipc_fd[1]);
William Lallemand56f73b22022-09-24 15:56:25 +02002217 mcli_reload_bind_conf = mworker_cli_proxy_new_listener(path);
2218 if (mcli_reload_bind_conf == NULL) {
William Lallemandec059c22022-09-22 17:26:23 +02002219 ha_alert("Cannot create the mcli_reload listener.\n");
2220 exit(EXIT_FAILURE);
2221 }
2222 ha_free(&path);
William Lallemand550db6d2018-11-06 17:37:12 +01002223 }
William Lallemandce83b4a2018-10-26 14:47:30 +02002224 }
2225
Eric Salama5ba83352021-03-16 15:11:17 +01002226 if (!LIST_ISEMPTY(&mworker_cli_conf) && !(arg_mode & MODE_MWORKER)) {
2227 ha_warning("a master CLI socket was defined, but master-worker mode (-W) is not enabled.\n");
2228 }
2229
Christopher Faulet27c8d202021-10-13 09:50:53 +02002230 /* destroy unreferenced defaults proxies */
2231 proxy_destroy_all_unref_defaults();
2232
William Lallemandb53eb872022-04-21 18:02:53 +02002233 list_for_each_entry(prcf, &pre_check_list, list)
2234 err_code |= prcf->fct();
Willy Tarreaue90904d2021-02-12 14:08:31 +01002235
William Lallemand8b9a2df2022-05-04 14:29:46 +02002236 if (err_code & (ERR_ABORT|ERR_FATAL)) {
2237 ha_alert("Fatal errors found in configuration.\n");
2238 exit(1);
2239 }
2240
Willy Tarreau57c3e752022-12-08 08:13:20 +01002241 /* Note: global.nbthread will be initialized as part of this call */
Willy Tarreaubb925012009-07-23 13:36:36 +02002242 err_code |= check_config_validity();
Christopher Fauletc1692962019-08-12 09:51:07 +02002243 for (px = proxies_list; px; px = px->next) {
2244 struct server *srv;
2245 struct post_proxy_check_fct *ppcf;
2246 struct post_server_check_fct *pscf;
2247
Christopher Fauletdfd10ab2021-10-06 14:24:19 +02002248 if (px->flags & (PR_FL_DISABLED|PR_FL_STOPPED))
Christopher Fauletd5bd8242020-11-02 16:20:13 +01002249 continue;
2250
Christopher Fauletc1692962019-08-12 09:51:07 +02002251 list_for_each_entry(pscf, &post_server_check_list, list) {
2252 for (srv = px->srv; srv; srv = srv->next)
2253 err_code |= pscf->fct(srv);
2254 }
2255 list_for_each_entry(ppcf, &post_proxy_check_list, list)
2256 err_code |= ppcf->fct(px);
2257 }
Willy Tarreaubb925012009-07-23 13:36:36 +02002258 if (err_code & (ERR_ABORT|ERR_FATAL)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002259 ha_alert("Fatal errors found in configuration.\n");
Willy Tarreau915e1eb2009-06-22 15:48:36 +02002260 exit(1);
2261 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002262
Carl Henrik Lundef91ac192020-02-27 16:45:50 +01002263 err_code |= pattern_finalize_config();
2264 if (err_code & (ERR_ABORT|ERR_FATAL)) {
2265 ha_alert("Failed to finalize pattern config.\n");
2266 exit(1);
2267 }
Willy Tarreau0f936722019-04-11 14:47:08 +02002268
Willy Tarreau79c9bdf2021-07-17 12:31:08 +02002269 if (global.rlimit_memmax_all)
2270 global.rlimit_memmax = global.rlimit_memmax_all;
2271
Willy Tarreaue5733232019-05-22 19:24:06 +02002272#ifdef USE_NS
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01002273 err_code |= netns_init();
2274 if (err_code & (ERR_ABORT|ERR_FATAL)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002275 ha_alert("Failed to initialize namespace support.\n");
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01002276 exit(1);
2277 }
2278#endif
2279
Baptiste Assmann4215d7d2016-11-02 15:33:15 +01002280 /* Apply server states */
2281 apply_server_state();
2282
Olivier Houchardfbc74e82017-11-24 16:54:05 +01002283 for (px = proxies_list; px; px = px->next)
Baptiste Assmann4215d7d2016-11-02 15:33:15 +01002284 srv_compute_all_admin_states(px);
2285
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01002286 /* Apply servers' configured address */
2287 err_code |= srv_init_addr();
2288 if (err_code & (ERR_ABORT|ERR_FATAL)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002289 ha_alert("Failed to initialize server(s) addr.\n");
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01002290 exit(1);
2291 }
2292
Willy Tarreau3eb10b82020-04-15 16:42:39 +02002293 if (warned & WARN_ANY && global.mode & MODE_ZERO_WARNING) {
2294 ha_alert("Some warnings were found and 'zero-warning' is set. Aborting.\n");
2295 exit(1);
2296 }
2297
Willy Tarreau654726d2021-12-28 15:43:11 +01002298#if defined(HA_HAVE_DUMP_LIBS)
2299 if (global.mode & MODE_DUMP_LIBS) {
2300 qfprintf(stdout, "List of loaded object files:\n");
2301 chunk_reset(&trash);
2302 if (dump_libs(&trash, 0))
2303 printf("%s", trash.area);
2304 }
2305#endif
2306
Willy Tarreau76871a42022-03-08 16:01:40 +01002307 if (global.mode & MODE_DUMP_KWD)
2308 dump_registered_keywords();
2309
Willy Tarreaubaaee002006-06-26 02:48:02 +02002310 if (global.mode & MODE_CHECK) {
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002311 struct peers *pr;
2312 struct proxy *px;
2313
Willy Tarreaubebd2122020-04-15 16:06:11 +02002314 if (warned & WARN_ANY)
2315 qfprintf(stdout, "Warnings were found.\n");
2316
Frédéric Lécailleed2b4a62017-07-13 09:07:09 +02002317 for (pr = cfg_peers; pr; pr = pr->next)
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002318 if (pr->peers_fe)
2319 break;
2320
Olivier Houchardfbc74e82017-11-24 16:54:05 +01002321 for (px = proxies_list; px; px = px->next)
Christopher Fauletdfd10ab2021-10-06 14:24:19 +02002322 if (!(px->flags & (PR_FL_DISABLED|PR_FL_STOPPED)) && px->li_all)
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002323 break;
2324
Emeric Brunbc5c8212021-08-13 09:32:50 +02002325 if (!px) {
2326 /* We may only have log-forward section */
2327 for (px = cfg_log_forward; px; px = px->next)
Christopher Fauletdfd10ab2021-10-06 14:24:19 +02002328 if (!(px->flags & (PR_FL_DISABLED|PR_FL_STOPPED)) && px->li_all)
Emeric Brunbc5c8212021-08-13 09:32:50 +02002329 break;
2330 }
2331
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002332 if (pr || px) {
2333 /* At least one peer or one listener has been found */
2334 qfprintf(stdout, "Configuration file is valid\n");
Tim Duesterhus0a3b43d2020-06-14 00:37:42 +02002335 deinit_and_exit(0);
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002336 }
2337 qfprintf(stdout, "Configuration file has no error but will not start (no listener) => exit(2).\n");
2338 exit(2);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002339 }
Willy Tarreaue9b26022011-08-01 20:57:55 +02002340
Erwan Le Goasb0c05012022-09-14 17:51:55 +02002341 if (global.mode & MODE_DUMP_CFG)
2342 deinit_and_exit(0);
2343
Amaury Denoyelle5a6926d2021-03-30 17:34:24 +02002344 if (global.mode & MODE_DIAG) {
2345 cfg_run_diagnostics();
2346 }
2347
Remi Tricot-Le Breton51944462022-05-16 16:24:31 +02002348#ifdef USE_OPENSSL
William Lallemand3b8bafd2022-07-19 18:13:29 +02002349
Remi Tricot-Le Breton51944462022-05-16 16:24:31 +02002350 /* Initialize SSL random generator. Must be called before chroot for
2351 * access to /dev/urandom, and before ha_random_boot() which may use
2352 * RAND_bytes().
2353 */
2354 if (!ssl_initialize_random()) {
2355 ha_alert("OpenSSL random data generator initialization failed.\n");
2356 exit(EXIT_FAILURE);
2357 }
2358#endif
2359 ha_random_boot(argv); // the argv pointer brings some kernel-fed entropy
2360
Willy Tarreau8263d2b2012-08-28 00:06:31 +02002361 /* now we know the buffer size, we can initialize the channels and buffers */
Willy Tarreau9b28e032012-10-12 23:49:43 +02002362 init_buffer();
Willy Tarreau8280d642009-09-23 23:37:52 +02002363
Willy Tarreaue6945732016-12-21 19:57:00 +01002364 list_for_each_entry(pcf, &post_check_list, list) {
2365 err_code |= pcf->fct();
2366 if (err_code & (ERR_ABORT|ERR_FATAL))
2367 exit(1);
2368 }
2369
William Lallemand0a012aa2022-06-21 11:11:50 +02002370 /* set the default maxconn in the master, but let it be rewritable with -n */
2371 if (global.mode & MODE_MWORKER_WAIT)
2372 global.maxconn = DEFAULT_MAXCONN;
2373
Willy Tarreaubaaee002006-06-26 02:48:02 +02002374 if (cfg_maxconn > 0)
2375 global.maxconn = cfg_maxconn;
2376
Willy Tarreau4975d142021-03-13 11:00:33 +01002377 if (global.cli_fe)
2378 global.maxsock += global.cli_fe->maxconn;
Willy Tarreau8d687d82019-03-01 09:39:42 +01002379
2380 if (cfg_peers) {
2381 /* peers also need to bypass global maxconn */
2382 struct peers *p = cfg_peers;
2383
2384 for (p = cfg_peers; p; p = p->next)
2385 if (p->peers_fe)
2386 global.maxsock += p->peers_fe->maxconn;
2387 }
2388
Willy Tarreaud0256482015-01-15 21:45:22 +01002389 /* Now we want to compute the maxconn and possibly maxsslconn values.
Willy Tarreauac350932019-03-01 15:43:14 +01002390 * It's a bit tricky. Maxconn defaults to the pre-computed value based
2391 * on rlim_fd_cur and the number of FDs in use due to the configuration,
2392 * and maxsslconn defaults to DEFAULT_MAXSSLCONN. On top of that we can
2393 * enforce a lower limit based on memmax.
Willy Tarreaud0256482015-01-15 21:45:22 +01002394 *
2395 * If memmax is set, then it depends on which values are set. If
2396 * maxsslconn is set, we use memmax to determine how many cleartext
2397 * connections may be added, and set maxconn to the sum of the two.
2398 * If maxconn is set and not maxsslconn, maxsslconn is computed from
2399 * the remaining amount of memory between memmax and the cleartext
2400 * connections. If neither are set, then it is considered that all
2401 * connections are SSL-capable, and maxconn is computed based on this,
2402 * then maxsslconn accordingly. We need to know if SSL is used on the
2403 * frontends, backends, or both, because when it's used on both sides,
2404 * we need twice the value for maxsslconn, but we only count the
2405 * handshake once since it is not performed on the two sides at the
2406 * same time (frontend-side is terminated before backend-side begins).
2407 * The SSL stack is supposed to have filled ssl_session_cost and
Willy Tarreau474b96a2015-01-28 19:03:21 +01002408 * ssl_handshake_cost during its initialization. In any case, if
2409 * SYSTEM_MAXCONN is set, we still enforce it as an upper limit for
2410 * maxconn in order to protect the system.
Willy Tarreaud0256482015-01-15 21:45:22 +01002411 */
Willy Tarreauac350932019-03-01 15:43:14 +01002412 ideal_maxconn = compute_ideal_maxconn();
2413
Willy Tarreaud0256482015-01-15 21:45:22 +01002414 if (!global.rlimit_memmax) {
2415 if (global.maxconn == 0) {
Willy Tarreauac350932019-03-01 15:43:14 +01002416 global.maxconn = ideal_maxconn;
Willy Tarreaud0256482015-01-15 21:45:22 +01002417 if (global.mode & (MODE_VERBOSE|MODE_DEBUG))
2418 fprintf(stderr, "Note: setting global.maxconn to %d.\n", global.maxconn);
2419 }
2420 }
2421#ifdef USE_OPENSSL
2422 else if (!global.maxconn && !global.maxsslconn &&
2423 (global.ssl_used_frontend || global.ssl_used_backend)) {
2424 /* memmax is set, compute everything automatically. Here we want
2425 * to ensure that all SSL connections will be served. We take
2426 * care of the number of sides where SSL is used, and consider
2427 * the worst case : SSL used on both sides and doing a handshake
2428 * simultaneously. Note that we can't have more than maxconn
2429 * handshakes at a time by definition, so for the worst case of
2430 * two SSL conns per connection, we count a single handshake.
2431 */
2432 int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
2433 int64_t mem = global.rlimit_memmax * 1048576ULL;
Willy Tarreau304e17e2020-03-10 17:54:54 +01002434 int retried = 0;
Willy Tarreaud0256482015-01-15 21:45:22 +01002435
Willy Tarreau2cb3be72022-05-24 07:43:57 +02002436 mem -= global.tune.sslcachesize * 200ULL; // about 200 bytes per SSL cache entry
Willy Tarreaud0256482015-01-15 21:45:22 +01002437 mem -= global.maxzlibmem;
2438 mem = mem * MEM_USABLE_RATIO;
2439
Willy Tarreau304e17e2020-03-10 17:54:54 +01002440 /* Principle: we test once to set maxconn according to the free
2441 * memory. If it results in values the system rejects, we try a
2442 * second time by respecting rlim_fd_max. If it fails again, we
2443 * go back to the initial value and will let the final code
2444 * dealing with rlimit report the error. That's up to 3 attempts.
2445 */
2446 do {
2447 global.maxconn = mem /
2448 ((STREAM_MAX_COST + 2 * global.tune.bufsize) + // stream + 2 buffers per stream
2449 sides * global.ssl_session_max_cost + // SSL buffers, one per side
2450 global.ssl_handshake_max_cost); // 1 handshake per connection max
Willy Tarreaud0256482015-01-15 21:45:22 +01002451
Willy Tarreau304e17e2020-03-10 17:54:54 +01002452 if (retried == 1)
2453 global.maxconn = MIN(global.maxconn, ideal_maxconn);
2454 global.maxconn = round_2dig(global.maxconn);
Willy Tarreau474b96a2015-01-28 19:03:21 +01002455#ifdef SYSTEM_MAXCONN
Willy Tarreau304e17e2020-03-10 17:54:54 +01002456 if (global.maxconn > SYSTEM_MAXCONN)
2457 global.maxconn = SYSTEM_MAXCONN;
Willy Tarreau474b96a2015-01-28 19:03:21 +01002458#endif /* SYSTEM_MAXCONN */
Willy Tarreau304e17e2020-03-10 17:54:54 +01002459 global.maxsslconn = sides * global.maxconn;
2460
2461 if (check_if_maxsock_permitted(compute_ideal_maxsock(global.maxconn)))
2462 break;
2463 } while (retried++ < 2);
2464
Willy Tarreaud0256482015-01-15 21:45:22 +01002465 if (global.mode & (MODE_VERBOSE|MODE_DEBUG))
2466 fprintf(stderr, "Note: setting global.maxconn to %d and global.maxsslconn to %d.\n",
2467 global.maxconn, global.maxsslconn);
2468 }
2469 else if (!global.maxsslconn &&
2470 (global.ssl_used_frontend || global.ssl_used_backend)) {
2471 /* memmax and maxconn are known, compute maxsslconn automatically.
2472 * maxsslconn being forced, we don't know how many of it will be
2473 * on each side if both sides are being used. The worst case is
2474 * when all connections use only one SSL instance because
2475 * handshakes may be on two sides at the same time.
2476 */
2477 int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
2478 int64_t mem = global.rlimit_memmax * 1048576ULL;
2479 int64_t sslmem;
2480
Willy Tarreau8e5b9582022-05-26 08:55:05 +02002481 mem -= global.tune.sslcachesize * 200ULL; // about 200 bytes per SSL cache entry
Willy Tarreaud0256482015-01-15 21:45:22 +01002482 mem -= global.maxzlibmem;
2483 mem = mem * MEM_USABLE_RATIO;
2484
Willy Tarreau87b09662015-04-03 00:22:06 +02002485 sslmem = mem - global.maxconn * (int64_t)(STREAM_MAX_COST + 2 * global.tune.bufsize);
Willy Tarreaud0256482015-01-15 21:45:22 +01002486 global.maxsslconn = sslmem / (global.ssl_session_max_cost + global.ssl_handshake_max_cost);
2487 global.maxsslconn = round_2dig(global.maxsslconn);
2488
2489 if (sslmem <= 0 || global.maxsslconn < sides) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002490 ha_alert("Cannot compute the automatic maxsslconn because global.maxconn is already too "
2491 "high for the global.memmax value (%d MB). The absolute maximum possible value "
2492 "without SSL is %d, but %d was found and SSL is in use.\n",
2493 global.rlimit_memmax,
2494 (int)(mem / (STREAM_MAX_COST + 2 * global.tune.bufsize)),
2495 global.maxconn);
Willy Tarreaud0256482015-01-15 21:45:22 +01002496 exit(1);
2497 }
2498
2499 if (global.maxsslconn > sides * global.maxconn)
2500 global.maxsslconn = sides * global.maxconn;
2501
2502 if (global.mode & (MODE_VERBOSE|MODE_DEBUG))
2503 fprintf(stderr, "Note: setting global.maxsslconn to %d\n", global.maxsslconn);
2504 }
2505#endif
2506 else if (!global.maxconn) {
2507 /* memmax and maxsslconn are known/unused, compute maxconn automatically */
2508 int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
2509 int64_t mem = global.rlimit_memmax * 1048576ULL;
2510 int64_t clearmem;
Willy Tarreau304e17e2020-03-10 17:54:54 +01002511 int retried = 0;
Willy Tarreaud0256482015-01-15 21:45:22 +01002512
2513 if (global.ssl_used_frontend || global.ssl_used_backend)
Willy Tarreau8e5b9582022-05-26 08:55:05 +02002514 mem -= global.tune.sslcachesize * 200ULL; // about 200 bytes per SSL cache entry
Willy Tarreaud0256482015-01-15 21:45:22 +01002515
2516 mem -= global.maxzlibmem;
2517 mem = mem * MEM_USABLE_RATIO;
2518
2519 clearmem = mem;
2520 if (sides)
2521 clearmem -= (global.ssl_session_max_cost + global.ssl_handshake_max_cost) * (int64_t)global.maxsslconn;
2522
Willy Tarreau304e17e2020-03-10 17:54:54 +01002523 /* Principle: we test once to set maxconn according to the free
2524 * memory. If it results in values the system rejects, we try a
2525 * second time by respecting rlim_fd_max. If it fails again, we
2526 * go back to the initial value and will let the final code
2527 * dealing with rlimit report the error. That's up to 3 attempts.
2528 */
2529 do {
2530 global.maxconn = clearmem / (STREAM_MAX_COST + 2 * global.tune.bufsize);
2531 if (retried == 1)
2532 global.maxconn = MIN(global.maxconn, ideal_maxconn);
2533 global.maxconn = round_2dig(global.maxconn);
Willy Tarreau474b96a2015-01-28 19:03:21 +01002534#ifdef SYSTEM_MAXCONN
Willy Tarreau304e17e2020-03-10 17:54:54 +01002535 if (global.maxconn > SYSTEM_MAXCONN)
2536 global.maxconn = SYSTEM_MAXCONN;
Willy Tarreau474b96a2015-01-28 19:03:21 +01002537#endif /* SYSTEM_MAXCONN */
Willy Tarreaud0256482015-01-15 21:45:22 +01002538
Willy Tarreau304e17e2020-03-10 17:54:54 +01002539 if (clearmem <= 0 || !global.maxconn) {
2540 ha_alert("Cannot compute the automatic maxconn because global.maxsslconn is already too "
2541 "high for the global.memmax value (%d MB). The absolute maximum possible value "
2542 "is %d, but %d was found.\n",
2543 global.rlimit_memmax,
Christopher Faulet767a84b2017-11-24 16:50:31 +01002544 (int)(mem / (global.ssl_session_max_cost + global.ssl_handshake_max_cost)),
Willy Tarreau304e17e2020-03-10 17:54:54 +01002545 global.maxsslconn);
2546 exit(1);
2547 }
2548
2549 if (check_if_maxsock_permitted(compute_ideal_maxsock(global.maxconn)))
2550 break;
2551 } while (retried++ < 2);
Willy Tarreaud0256482015-01-15 21:45:22 +01002552
2553 if (global.mode & (MODE_VERBOSE|MODE_DEBUG)) {
2554 if (sides && global.maxsslconn > sides * global.maxconn) {
2555 fprintf(stderr, "Note: global.maxsslconn is forced to %d which causes global.maxconn "
2556 "to be limited to %d. Better reduce global.maxsslconn to get more "
2557 "room for extra connections.\n", global.maxsslconn, global.maxconn);
2558 }
2559 fprintf(stderr, "Note: setting global.maxconn to %d\n", global.maxconn);
2560 }
Willy Tarreau66aa61f2009-01-18 21:44:07 +01002561 }
2562
Willy Tarreaua409f302020-03-10 17:08:53 +01002563 global.maxsock = compute_ideal_maxsock(global.maxconn);
2564 global.hardmaxconn = global.maxconn;
Willy Tarreaua4818db2020-06-19 16:20:59 +02002565 if (!global.maxpipes)
2566 global.maxpipes = compute_ideal_maxpipes();
Willy Tarreaubaaee002006-06-26 02:48:02 +02002567
Olivier Houchard88698d92019-04-16 19:07:22 +02002568 /* update connection pool thresholds */
2569 global.tune.pool_low_count = ((long long)global.maxsock * global.tune.pool_low_ratio + 99) / 100;
2570 global.tune.pool_high_count = ((long long)global.maxsock * global.tune.pool_high_ratio + 99) / 100;
2571
Willy Tarreauc8d5b952019-02-27 17:25:52 +01002572 proxy_adjust_all_maxconn();
2573
Willy Tarreau1db37712007-06-03 17:16:49 +02002574 if (global.tune.maxpollevents <= 0)
2575 global.tune.maxpollevents = MAX_POLL_EVENTS;
2576
Willy Tarreau060a7612021-03-10 11:06:26 +01002577 if (global.tune.runqueue_depth <= 0) {
2578 /* tests on various thread counts from 1 to 64 have shown an
2579 * optimal queue depth following roughly 1/sqrt(threads).
2580 */
2581 int s = my_flsl(global.nbthread);
2582 s += (global.nbthread / s); // roughly twice the sqrt.
2583 global.tune.runqueue_depth = RUNQUEUE_DEPTH * 2 / s;
2584 }
Olivier Houchard1599b802018-05-24 18:59:04 +02002585
Willy Tarreau6f4a82c2009-03-21 20:43:57 +01002586 if (global.tune.recv_enough == 0)
2587 global.tune.recv_enough = MIN_RECV_AT_ONCE_ENOUGH;
2588
Willy Tarreau27a674e2009-08-17 07:23:33 +02002589 if (global.tune.maxrewrite >= global.tune.bufsize / 2)
2590 global.tune.maxrewrite = global.tune.bufsize / 2;
2591
Amaury Denoyelle11124302021-06-04 18:22:08 +02002592 usermsgs_clr(NULL);
2593
Willy Tarreaubaaee002006-06-26 02:48:02 +02002594 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
2595 /* command line debug mode inhibits configuration mode */
William Lallemand095ba4c2017-06-01 17:38:50 +02002596 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
Willy Tarreau772f0dd2012-10-26 16:04:28 +02002597 global.mode |= (arg_mode & (MODE_DEBUG | MODE_FOREGROUND));
2598 }
2599
William Lallemand095ba4c2017-06-01 17:38:50 +02002600 if (arg_mode & MODE_DAEMON) {
Willy Tarreau772f0dd2012-10-26 16:04:28 +02002601 /* command line daemon mode inhibits foreground and debug modes mode */
2602 global.mode &= ~(MODE_DEBUG | MODE_FOREGROUND);
William Lallemand095ba4c2017-06-01 17:38:50 +02002603 global.mode |= arg_mode & MODE_DAEMON;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002604 }
Willy Tarreau772f0dd2012-10-26 16:04:28 +02002605
2606 global.mode |= (arg_mode & (MODE_QUIET | MODE_VERBOSE));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002607
William Lallemand095ba4c2017-06-01 17:38:50 +02002608 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002609 ha_warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
William Lallemand095ba4c2017-06-01 17:38:50 +02002610 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002611 }
2612
Christopher Faulet3ef26392017-08-29 16:46:57 +02002613 /* Realloc trash buffers because global.tune.bufsize may have changed */
Christopher Fauletcd7879a2017-10-27 13:53:47 +02002614 if (!init_trash_buffers(0)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002615 ha_alert("failed to initialize trash buffers.\n");
Christopher Faulet3ef26392017-08-29 16:46:57 +02002616 exit(1);
2617 }
2618
Christopher Faulet96d44832017-11-14 22:02:30 +01002619 if (!init_log_buffers()) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002620 ha_alert("failed to initialize log buffers.\n");
Christopher Faulet96d44832017-11-14 22:02:30 +01002621 exit(1);
2622 }
2623
Amaury Denoyelle28ea31c2022-11-14 16:18:46 +01002624 if (!global.cluster_secret)
2625 generate_random_cluster_secret();
2626
Willy Tarreauef1d1f82007-04-16 00:25:25 +02002627 /*
2628 * Note: we could register external pollers here.
2629 * Built-in pollers have been registered before main().
2630 */
Willy Tarreau4f60f162007-04-08 16:39:58 +02002631
Willy Tarreau43b78992009-01-25 15:42:27 +01002632 if (!(global.tune.options & GTUNE_USE_KQUEUE))
Willy Tarreau1e63130a2007-04-09 12:03:06 +02002633 disable_poller("kqueue");
2634
Emmanuel Hocdet0ba4f482019-04-08 16:53:32 +00002635 if (!(global.tune.options & GTUNE_USE_EVPORTS))
2636 disable_poller("evports");
2637
Willy Tarreau43b78992009-01-25 15:42:27 +01002638 if (!(global.tune.options & GTUNE_USE_EPOLL))
Willy Tarreau4f60f162007-04-08 16:39:58 +02002639 disable_poller("epoll");
2640
Willy Tarreau43b78992009-01-25 15:42:27 +01002641 if (!(global.tune.options & GTUNE_USE_POLL))
Willy Tarreau4f60f162007-04-08 16:39:58 +02002642 disable_poller("poll");
2643
Willy Tarreau43b78992009-01-25 15:42:27 +01002644 if (!(global.tune.options & GTUNE_USE_SELECT))
Willy Tarreau4f60f162007-04-08 16:39:58 +02002645 disable_poller("select");
2646
2647 /* Note: we could disable any poller by name here */
2648
Christopher Fauletb3f4e142016-03-07 12:46:38 +01002649 if (global.mode & (MODE_VERBOSE|MODE_DEBUG)) {
Willy Tarreau2ff76222007-04-09 19:29:56 +02002650 list_pollers(stderr);
Christopher Fauletb3f4e142016-03-07 12:46:38 +01002651 fprintf(stderr, "\n");
2652 list_filters(stderr);
2653 }
Willy Tarreau2ff76222007-04-09 19:29:56 +02002654
Willy Tarreau4f60f162007-04-08 16:39:58 +02002655 if (!init_pollers()) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002656 ha_alert("No polling mechanism available.\n"
Willy Tarreaue5715bf2022-07-09 23:38:46 +02002657 " This may happen when using thread-groups with old pollers (poll/select), or\n"
2658 " it is possible that haproxy was built with TARGET=generic and that FD_SETSIZE\n"
Christopher Faulet767a84b2017-11-24 16:50:31 +01002659 " is too low on this platform to support maxconn and the number of listeners\n"
2660 " and servers. You should rebuild haproxy specifying your system using TARGET=\n"
2661 " in order to support other polling systems (poll, epoll, kqueue) or reduce the\n"
2662 " global maxconn setting to accommodate the system's limitation. For reference,\n"
2663 " FD_SETSIZE=%d on this system, global.maxconn=%d resulting in a maximum of\n"
2664 " %d file descriptors. You should thus reduce global.maxconn by %d. Also,\n"
2665 " check build settings using 'haproxy -vv'.\n\n",
2666 FD_SETSIZE, global.maxconn, global.maxsock, (global.maxsock + 1 - FD_SETSIZE) / 2);
Willy Tarreau4f60f162007-04-08 16:39:58 +02002667 exit(1);
2668 }
Willy Tarreau2ff76222007-04-09 19:29:56 +02002669 if (global.mode & (MODE_VERBOSE|MODE_DEBUG)) {
2670 printf("Using %s() as the polling mechanism.\n", cur_poller.name);
Willy Tarreau4f60f162007-04-08 16:39:58 +02002671 }
2672
Krzysztof Piotr Oledzki48cb2ae2009-10-02 22:51:14 +02002673 if (!global.node)
2674 global.node = strdup(hostname);
2675
Willy Tarreau02b092f2020-10-07 18:36:54 +02002676 /* stop disabled proxies */
2677 for (px = proxies_list; px; px = px->next) {
Christopher Fauletdfd10ab2021-10-06 14:24:19 +02002678 if (px->flags & (PR_FL_DISABLED|PR_FL_STOPPED))
Willy Tarreau02b092f2020-10-07 18:36:54 +02002679 stop_proxy(px);
2680 }
2681
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01002682 if (!hlua_post_init())
2683 exit(1);
Willy Tarreau284cfc62022-12-19 08:15:57 +01002684
2685 /* Set the per-thread pool cache size to the default value if not set.
2686 * This is the right place to decide to automatically adjust it (e.g.
2687 * check L2 cache size, thread counts or take into account certain
2688 * expensive pools).
2689 */
2690 if (!global.tune.pool_cache_size)
2691 global.tune.pool_cache_size = CONFIG_HAP_POOL_CACHE_SIZE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002692}
2693
Cyril Bonté203ec5a2017-03-23 22:44:13 +01002694void deinit(void)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002695{
Olivier Houchardfbc74e82017-11-24 16:54:05 +01002696 struct proxy *p = proxies_list, *p0;
Willy Tarreaudeb9ed82010-01-03 21:03:22 +01002697 struct wordlist *wl, *wlb;
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002698 struct uri_auth *uap, *ua = NULL;
William Lallemand0f99e342011-10-12 17:50:54 +02002699 struct logsrv *log, *logb;
Willy Tarreaucdb737e2016-12-21 18:43:10 +01002700 struct build_opts_str *bol, *bolb;
Tim Duesterhusfdf904a2020-07-04 11:49:48 +02002701 struct post_deinit_fct *pdf, *pdfb;
Tim Duesterhus17e363f2020-07-04 11:49:47 +02002702 struct proxy_deinit_fct *pxdf, *pxdfb;
Tim Duesterhus0837eb12020-07-04 11:49:49 +02002703 struct server_deinit_fct *srvdf, *srvdfb;
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002704 struct per_thread_init_fct *tif, *tifb;
2705 struct per_thread_deinit_fct *tdf, *tdfb;
2706 struct per_thread_alloc_fct *taf, *tafb;
2707 struct per_thread_free_fct *tff, *tffb;
Tim Duesterhus34bef072020-07-04 11:49:50 +02002708 struct post_server_check_fct *pscf, *pscfb;
Tim Duesterhusfc854942020-09-10 19:46:42 +02002709 struct post_check_fct *pcf, *pcfb;
Tim Duesterhus53508d62020-09-10 19:46:40 +02002710 struct post_proxy_check_fct *ppcf, *ppcfb;
Willy Tarreau65009eb2022-04-27 18:02:54 +02002711 struct pre_check_fct *prcf, *prcfb;
Willy Tarreau226866e2022-04-27 18:07:24 +02002712 struct cfg_postparser *pprs, *pprsb;
Willy Tarreauae7bc4a2020-09-23 16:46:22 +02002713 int cur_fd;
2714
Willy Tarreaue98d3852022-11-15 09:34:07 +01002715 /* the user may want to skip this phase */
2716 if (global.tune.options & GTUNE_QUICK_EXIT)
2717 return;
2718
Willy Tarreauae7bc4a2020-09-23 16:46:22 +02002719 /* At this point the listeners state is weird:
2720 * - most listeners are still bound and referenced in their protocol
2721 * - some might be zombies that are not in their proto anymore, but
2722 * still appear in their proxy's listeners with a valid FD.
2723 * - some might be stopped and still appear in their proxy as FD #-1
2724 * - among all of them, some might be inherited hence shared and we're
2725 * not allowed to pause them or whatever, we must just close them.
2726 * - finally some are not listeners (pipes, logs, stdout, etc) and
2727 * must be left intact.
2728 *
2729 * The safe way to proceed is to unbind (and close) whatever is not yet
2730 * unbound so that no more receiver/listener remains alive. Then close
2731 * remaining listener FDs, which correspond to zombie listeners (those
2732 * belonging to disabled proxies that were in another process).
2733 * objt_listener() would be cleaner here but not converted yet.
2734 */
2735 protocol_unbind_all();
2736
2737 for (cur_fd = 0; cur_fd < global.maxsock; cur_fd++) {
Willy Tarreau1a3770c2020-10-14 12:13:51 +02002738 if (!fdtab || !fdtab[cur_fd].owner)
Willy Tarreauae7bc4a2020-09-23 16:46:22 +02002739 continue;
2740
Willy Tarreaua74cb382020-10-15 21:29:49 +02002741 if (fdtab[cur_fd].iocb == &sock_accept_iocb) {
Willy Tarreauae7bc4a2020-09-23 16:46:22 +02002742 struct listener *l = fdtab[cur_fd].owner;
2743
2744 BUG_ON(l->state != LI_INIT);
2745 unbind_listener(l);
2746 }
2747 }
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002748
Willy Tarreau24f4efa2010-08-27 17:56:48 +02002749 deinit_signals();
Willy Tarreaubaaee002006-06-26 02:48:02 +02002750 while (p) {
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002751 /* build a list of unique uri_auths */
2752 if (!ua)
2753 ua = p->uri_auth;
2754 else {
2755 /* check if p->uri_auth is unique */
2756 for (uap = ua; uap; uap=uap->next)
2757 if (uap == p->uri_auth)
2758 break;
2759
Willy Tarreauaccc4e12008-06-24 11:14:45 +02002760 if (!uap && p->uri_auth) {
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002761 /* add it, if it is */
2762 p->uri_auth->next = ua;
2763 ua = p->uri_auth;
2764 }
William Lallemand0f99e342011-10-12 17:50:54 +02002765 }
2766
Willy Tarreau4d2d0982007-05-14 00:39:29 +02002767 p0 = p;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002768 p = p->next;
Amaury Denoyelle27fefa12021-03-24 16:13:20 +01002769 free_proxy(p0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002770 }/* end while(p) */
Willy Tarreaudd815982007-10-16 12:25:14 +02002771
Christopher Faulet27c8d202021-10-13 09:50:53 +02002772 /* destroy all referenced defaults proxies */
2773 proxy_destroy_all_unref_defaults();
2774
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002775 while (ua) {
Tim Duesterhus00f00cf2020-09-10 19:46:38 +02002776 struct stat_scope *scope, *scopep;
2777
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002778 uap = ua;
2779 ua = ua->next;
2780
Willy Tarreaua534fea2008-08-03 12:19:50 +02002781 free(uap->uri_prefix);
2782 free(uap->auth_realm);
Krzysztof Piotr Oledzki48cb2ae2009-10-02 22:51:14 +02002783 free(uap->node);
2784 free(uap->desc);
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002785
Krzysztof Piotr Oledzki8c8bd452010-01-29 19:29:32 +01002786 userlist_free(uap->userlist);
Amaury Denoyelle68fd7e42021-03-25 17:15:52 +01002787 free_act_rules(&uap->http_req_rules);
Krzysztof Piotr Oledzki8c8bd452010-01-29 19:29:32 +01002788
Tim Duesterhus00f00cf2020-09-10 19:46:38 +02002789 scope = uap->scope;
2790 while (scope) {
2791 scopep = scope;
2792 scope = scope->next;
2793
2794 free(scopep->px_id);
2795 free(scopep);
2796 }
2797
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002798 free(uap);
2799 }
2800
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +01002801 userlist_free(userlist);
2802
David Carlier834cb2e2015-09-25 12:02:25 +01002803 cfg_unregister_sections();
2804
Christopher Faulet0132d062017-07-26 15:33:35 +02002805 deinit_log_buffers();
David Carlier834cb2e2015-09-25 12:02:25 +01002806
Willy Tarreau05554e62016-12-21 20:46:26 +01002807 list_for_each_entry(pdf, &post_deinit_list, list)
2808 pdf->fct();
2809
Willy Tarreau61cfdf42021-02-20 10:46:51 +01002810 ha_free(&global.log_send_hostname);
Dragan Dosen43885c72015-10-01 13:18:13 +02002811 chunk_destroy(&global.log_tag);
Willy Tarreau61cfdf42021-02-20 10:46:51 +01002812 ha_free(&global.chroot);
Frédéric Lécaille372508c2022-05-06 08:53:16 +02002813 ha_free(&global.cluster_secret);
Willy Tarreau61cfdf42021-02-20 10:46:51 +01002814 ha_free(&global.pidfile);
2815 ha_free(&global.node);
2816 ha_free(&global.desc);
2817 ha_free(&oldpids);
2818 ha_free(&old_argv);
2819 ha_free(&localpeer);
2820 ha_free(&global.server_state_base);
2821 ha_free(&global.server_state_file);
Olivier Houchard3f795f72019-04-17 22:51:06 +02002822 task_destroy(idle_conn_task);
Olivier Houchard9ea5d362019-02-14 18:29:09 +01002823 idle_conn_task = NULL;
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002824
William Lallemand0f99e342011-10-12 17:50:54 +02002825 list_for_each_entry_safe(log, logb, &global.logsrvs, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002826 LIST_DELETE(&log->list);
Amaury Denoyelled688e012021-04-20 17:05:47 +02002827 free(log->conf.file);
William Lallemand0f99e342011-10-12 17:50:54 +02002828 free(log);
2829 }
Willy Tarreau477ecd82010-01-03 21:12:30 +01002830 list_for_each_entry_safe(wl, wlb, &cfg_cfgfiles, list) {
Maxime de Roucy0f503922016-05-13 23:52:55 +02002831 free(wl->s);
Willy Tarreau2b718102021-04-21 07:32:39 +02002832 LIST_DELETE(&wl->list);
Willy Tarreau477ecd82010-01-03 21:12:30 +01002833 free(wl);
2834 }
2835
Willy Tarreaucdb737e2016-12-21 18:43:10 +01002836 list_for_each_entry_safe(bol, bolb, &build_opts_list, list) {
2837 if (bol->must_free)
2838 free((void *)bol->str);
Willy Tarreau2b718102021-04-21 07:32:39 +02002839 LIST_DELETE(&bol->list);
Willy Tarreaucdb737e2016-12-21 18:43:10 +01002840 free(bol);
2841 }
2842
Tim Duesterhus17e363f2020-07-04 11:49:47 +02002843 list_for_each_entry_safe(pxdf, pxdfb, &proxy_deinit_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002844 LIST_DELETE(&pxdf->list);
Tim Duesterhus17e363f2020-07-04 11:49:47 +02002845 free(pxdf);
2846 }
2847
Tim Duesterhusfdf904a2020-07-04 11:49:48 +02002848 list_for_each_entry_safe(pdf, pdfb, &post_deinit_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002849 LIST_DELETE(&pdf->list);
Tim Duesterhusfdf904a2020-07-04 11:49:48 +02002850 free(pdf);
2851 }
2852
Tim Duesterhus0837eb12020-07-04 11:49:49 +02002853 list_for_each_entry_safe(srvdf, srvdfb, &server_deinit_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002854 LIST_DELETE(&srvdf->list);
Tim Duesterhus0837eb12020-07-04 11:49:49 +02002855 free(srvdf);
2856 }
2857
Tim Duesterhusfc854942020-09-10 19:46:42 +02002858 list_for_each_entry_safe(pcf, pcfb, &post_check_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002859 LIST_DELETE(&pcf->list);
Tim Duesterhusfc854942020-09-10 19:46:42 +02002860 free(pcf);
2861 }
2862
Tim Duesterhus34bef072020-07-04 11:49:50 +02002863 list_for_each_entry_safe(pscf, pscfb, &post_server_check_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002864 LIST_DELETE(&pscf->list);
Tim Duesterhus34bef072020-07-04 11:49:50 +02002865 free(pscf);
2866 }
2867
Tim Duesterhus53508d62020-09-10 19:46:40 +02002868 list_for_each_entry_safe(ppcf, ppcfb, &post_proxy_check_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002869 LIST_DELETE(&ppcf->list);
Tim Duesterhus53508d62020-09-10 19:46:40 +02002870 free(ppcf);
2871 }
2872
Willy Tarreau65009eb2022-04-27 18:02:54 +02002873 list_for_each_entry_safe(prcf, prcfb, &pre_check_list, list) {
2874 LIST_DELETE(&prcf->list);
2875 free(prcf);
2876 }
2877
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002878 list_for_each_entry_safe(tif, tifb, &per_thread_init_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002879 LIST_DELETE(&tif->list);
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002880 free(tif);
2881 }
2882
2883 list_for_each_entry_safe(tdf, tdfb, &per_thread_deinit_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002884 LIST_DELETE(&tdf->list);
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002885 free(tdf);
2886 }
2887
2888 list_for_each_entry_safe(taf, tafb, &per_thread_alloc_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002889 LIST_DELETE(&taf->list);
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002890 free(taf);
2891 }
2892
2893 list_for_each_entry_safe(tff, tffb, &per_thread_free_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002894 LIST_DELETE(&tff->list);
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002895 free(tff);
2896 }
2897
Willy Tarreau226866e2022-04-27 18:07:24 +02002898 list_for_each_entry_safe(pprs, pprsb, &postparsers, list) {
2899 LIST_DELETE(&pprs->list);
2900 free(pprs);
2901 }
2902
Willy Tarreaucfc4f242021-05-08 11:41:28 +02002903 vars_prune(&proc_vars, NULL, NULL);
Willy Tarreau2455ceb2018-11-26 15:57:34 +01002904 pool_destroy_all();
Krzysztof Piotr Oledzkia643baf2008-05-29 23:53:44 +02002905 deinit_pollers();
Willy Tarreaubaaee002006-06-26 02:48:02 +02002906} /* end deinit() */
2907
Willy Tarreauf3ca5a02020-06-15 18:43:46 +02002908__attribute__((noreturn)) void deinit_and_exit(int status)
Tim Duesterhus26540552020-06-14 00:37:41 +02002909{
Amaury Denoyelle7afa5c12021-08-09 15:02:56 +02002910 global.mode |= MODE_STOPPING;
Tim Duesterhus26540552020-06-14 00:37:41 +02002911 deinit();
2912 exit(status);
2913}
William Lallemand72160322018-11-06 17:37:16 +01002914
Willy Tarreau918ff602011-07-25 16:33:49 +02002915/* Runs the polling loop */
Willy Tarreau3ebd55e2020-03-03 14:59:56 +01002916void run_poll_loop()
Willy Tarreau4f60f162007-04-08 16:39:58 +02002917{
Willy Tarreau2ae84e42019-05-28 16:44:05 +02002918 int next, wake;
Willy Tarreau4f60f162007-04-08 16:39:58 +02002919
Willy Tarreau55542642021-10-08 09:33:24 +02002920 clock_update_date(0,1);
Willy Tarreau4f60f162007-04-08 16:39:58 +02002921 while (1) {
Willy Tarreauc49ba522019-12-11 08:12:23 +01002922 wake_expired_tasks();
2923
William Lallemand1aab50b2018-06-07 09:46:01 +02002924 /* check if we caught some signals and process them in the
2925 first thread */
Willy Tarreaua7ad4ae2020-06-19 12:06:34 +02002926 if (signal_queue_len && tid == 0) {
2927 activity[tid].wake_signal++;
William Lallemand1aab50b2018-06-07 09:46:01 +02002928 signal_process_queue();
Willy Tarreaua7ad4ae2020-06-19 12:06:34 +02002929 }
2930
2931 /* Process a few tasks */
2932 process_runnable_tasks();
Willy Tarreau29857942009-05-10 09:01:21 +02002933
Willy Tarreau7067b3a2019-06-02 11:11:29 +02002934 /* also stop if we failed to cleanly stop all tasks */
2935 if (killed > 1)
2936 break;
2937
Matthias Wirtheea152e2022-09-09 10:21:00 +02002938 /* expire immediately if events or signals are pending */
Willy Tarreau2ae84e42019-05-28 16:44:05 +02002939 wake = 1;
Olivier Houchard305d5ab2019-07-24 18:07:06 +02002940 if (thread_has_tasks())
Willy Tarreaud80cb4e2018-01-20 19:30:13 +01002941 activity[tid].wake_tasks++;
Olivier Houchard79321b92018-07-26 17:55:11 +02002942 else {
Willy Tarreaue7475c82022-06-20 09:23:24 +02002943 _HA_ATOMIC_OR(&th_ctx->flags, TH_FL_SLEEPING);
Willy Tarreaudce4ad72022-06-22 15:38:38 +02002944 _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_NOTIFIED);
Olivier Houchardb23a61f2019-03-08 18:51:17 +01002945 __ha_barrier_atomic_store();
Willy Tarreau95abd5b2020-03-23 09:33:32 +01002946 if (thread_has_tasks()) {
Olivier Houchard79321b92018-07-26 17:55:11 +02002947 activity[tid].wake_tasks++;
Willy Tarreaue7475c82022-06-20 09:23:24 +02002948 _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_SLEEPING);
Matthias Wirtheea152e2022-09-09 10:21:00 +02002949 } else if (signal_queue_len) {
2950 /* this check is required after setting TH_FL_SLEEPING to avoid
2951 * a race with wakeup on signals using wake_threads() */
2952 _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_SLEEPING);
Olivier Houchard79321b92018-07-26 17:55:11 +02002953 } else
Willy Tarreau2ae84e42019-05-28 16:44:05 +02002954 wake = 0;
Olivier Houchard79321b92018-07-26 17:55:11 +02002955 }
Willy Tarreau10146c92015-04-13 20:44:19 +02002956
Willy Tarreau4f46a352020-03-23 09:27:28 +01002957 if (!wake) {
Willy Tarreaud7a6b2f2020-05-13 13:51:01 +02002958 int i;
2959
2960 if (stopping) {
Ilya Shipitsin3df59892021-05-10 12:50:00 +05002961 /* stop muxes before acknowledging stopping */
Willy Tarreau24cfc9f2022-07-04 14:07:29 +02002962 if (!(tg_ctx->stopping_threads & ti->ltid_bit)) {
Amaury Denoyelled3a88c12021-05-03 10:47:51 +02002963 task_wakeup(mux_stopping_data[tid].task, TASK_WOKEN_OTHER);
2964 wake = 1;
2965 }
2966
Willy Tarreauef422ce2022-06-28 19:29:29 +02002967 if (_HA_ATOMIC_OR_FETCH(&tg_ctx->stopping_threads, ti->ltid_bit) == ti->ltid_bit &&
2968 _HA_ATOMIC_OR_FETCH(&stopping_tgroup_mask, tg->tgid_bit) == tg->tgid_bit) {
2969 /* first one to detect it, notify all threads that stopping was just set */
2970 for (i = 0; i < global.nbthread; i++) {
2971 if (ha_thread_info[i].tg->threads_enabled &
2972 ha_thread_info[i].ltid_bit &
2973 ~_HA_ATOMIC_LOAD(&ha_thread_info[i].tg_ctx->stopping_threads))
Willy Tarreaud6455742020-05-13 14:30:25 +02002974 wake_thread(i);
Willy Tarreauef422ce2022-06-28 19:29:29 +02002975 }
Willy Tarreaud6455742020-05-13 14:30:25 +02002976 }
Willy Tarreaud7a6b2f2020-05-13 13:51:01 +02002977 }
Willy Tarreau4f46a352020-03-23 09:27:28 +01002978
2979 /* stop when there's nothing left to do */
2980 if ((jobs - unstoppable_jobs) == 0 &&
Willy Tarreauef422ce2022-06-28 19:29:29 +02002981 (_HA_ATOMIC_LOAD(&stopping_tgroup_mask) & all_tgroups_mask) == all_tgroups_mask) {
2982 /* check that all threads are aware of the stopping status */
2983 for (i = 0; i < global.nbtgroups; i++)
Willy Tarreauf34a3fa2022-07-06 10:13:05 +02002984 if ((_HA_ATOMIC_LOAD(&ha_tgroup_ctx[i].stopping_threads) & ha_tgroup_info[i].threads_enabled) !=
2985 ha_tgroup_info[i].threads_enabled)
Willy Tarreauef422ce2022-06-28 19:29:29 +02002986 break;
2987#ifdef USE_THREAD
2988 if (i == global.nbtgroups) {
2989 /* all are OK, let's wake them all and stop */
2990 for (i = 0; i < global.nbthread; i++)
2991 if (i != tid && ha_thread_info[i].tg->threads_enabled & ha_thread_info[i].ltid_bit)
2992 wake_thread(i);
2993 break;
2994 }
2995#endif
Willy Tarreaud7a6b2f2020-05-13 13:51:01 +02002996 }
Willy Tarreau4f46a352020-03-23 09:27:28 +01002997 }
2998
Willy Tarreauc49ba522019-12-11 08:12:23 +01002999 /* If we have to sleep, measure how long */
3000 next = wake ? TICK_ETERNITY : next_timer_expiry();
3001
Willy Tarreau58b458d2008-06-29 22:40:23 +02003002 /* The poller will ensure it returns around <next> */
Willy Tarreau2ae84e42019-05-28 16:44:05 +02003003 cur_poller.poll(&cur_poller, next, wake);
Emeric Brun64cc49c2017-10-03 14:46:45 +02003004
Willy Tarreaud80cb4e2018-01-20 19:30:13 +01003005 activity[tid].loops++;
Willy Tarreau4f60f162007-04-08 16:39:58 +02003006 }
3007}
3008
Christopher Faulet1d17c102017-08-29 15:38:48 +02003009static void *run_thread_poll_loop(void *data)
3010{
Willy Tarreau082b6282019-05-22 14:42:12 +02003011 struct per_thread_alloc_fct *ptaf;
Christopher Faulet1d17c102017-08-29 15:38:48 +02003012 struct per_thread_init_fct *ptif;
3013 struct per_thread_deinit_fct *ptdf;
Willy Tarreau082b6282019-05-22 14:42:12 +02003014 struct per_thread_free_fct *ptff;
Willy Tarreau34a150c2019-06-11 09:16:41 +02003015 static int init_left = 0;
Willy Tarreauaf613e82020-06-05 08:40:51 +02003016 __decl_thread(static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER);
3017 __decl_thread(static pthread_cond_t init_cond = PTHREAD_COND_INITIALIZER);
Christopher Faulet1d17c102017-08-29 15:38:48 +02003018
Willy Tarreau43ab05b2021-09-28 09:43:11 +02003019 ha_set_thread(data);
Willy Tarreaufb641d72021-09-28 10:15:47 +02003020 set_thread_cpu_affinity();
Willy Tarreau44c58da2021-10-08 12:27:54 +02003021 clock_set_local_source();
Willy Tarreau91e6df02019-05-03 17:21:18 +02003022
Willy Tarreau6ec902a2019-06-07 14:41:11 +02003023 /* Now, initialize one thread init at a time. This is better since
3024 * some init code is a bit tricky and may release global resources
3025 * after reallocating them locally. This will also ensure there is
3026 * no race on file descriptors allocation.
3027 */
Willy Tarreau34a150c2019-06-11 09:16:41 +02003028#ifdef USE_THREAD
3029 pthread_mutex_lock(&init_mutex);
3030#endif
3031 /* The first thread must set the number of threads left */
3032 if (!init_left)
3033 init_left = global.nbthread;
3034 init_left--;
Willy Tarreau91e6df02019-05-03 17:21:18 +02003035
Willy Tarreau55542642021-10-08 09:33:24 +02003036 clock_init_thread_date();
Christopher Faulet1d17c102017-08-29 15:38:48 +02003037
Willy Tarreau082b6282019-05-22 14:42:12 +02003038 /* per-thread alloc calls performed here are not allowed to snoop on
3039 * other threads, so they are free to initialize at their own rhythm
3040 * as long as they act as if they were alone. None of them may rely
3041 * on resources initialized by the other ones.
3042 */
3043 list_for_each_entry(ptaf, &per_thread_alloc_list, list) {
3044 if (!ptaf->fct()) {
3045 ha_alert("failed to allocate resources for thread %u.\n", tid);
Willy Tarreaub3c4a8f2021-07-22 14:42:32 +02003046#ifdef USE_THREAD
jenny-cheung048368e2021-07-18 16:40:57 +08003047 pthread_mutex_unlock(&init_mutex);
Willy Tarreaub3c4a8f2021-07-22 14:42:32 +02003048#endif
Willy Tarreau082b6282019-05-22 14:42:12 +02003049 exit(1);
3050 }
3051 }
3052
Willy Tarreau3078e9f2019-05-20 10:50:43 +02003053 /* per-thread init calls performed here are not allowed to snoop on
3054 * other threads, so they are free to initialize at their own rhythm
3055 * as long as they act as if they were alone.
3056 */
Christopher Faulet1d17c102017-08-29 15:38:48 +02003057 list_for_each_entry(ptif, &per_thread_init_list, list) {
3058 if (!ptif->fct()) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003059 ha_alert("failed to initialize thread %u.\n", tid);
Willy Tarreaub3c4a8f2021-07-22 14:42:32 +02003060#ifdef USE_THREAD
jenny-cheung048368e2021-07-18 16:40:57 +08003061 pthread_mutex_unlock(&init_mutex);
Willy Tarreaub3c4a8f2021-07-22 14:42:32 +02003062#endif
Christopher Faulet1d17c102017-08-29 15:38:48 +02003063 exit(1);
3064 }
3065 }
3066
Willy Tarreau71092822019-06-10 09:51:04 +02003067 /* enabling protocols will result in fd_insert() calls to be performed,
3068 * we want all threads to have already allocated their local fd tables
Willy Tarreau34a150c2019-06-11 09:16:41 +02003069 * before doing so, thus only the last thread does it.
Willy Tarreau71092822019-06-10 09:51:04 +02003070 */
Willy Tarreau34a150c2019-06-11 09:16:41 +02003071 if (init_left == 0)
Willy Tarreaue4d7c9d2019-06-10 10:14:52 +02003072 protocol_enable_all();
Willy Tarreau6ec902a2019-06-07 14:41:11 +02003073
Willy Tarreau34a150c2019-06-11 09:16:41 +02003074#ifdef USE_THREAD
3075 pthread_cond_broadcast(&init_cond);
3076 pthread_mutex_unlock(&init_mutex);
3077
3078 /* now wait for other threads to finish starting */
3079 pthread_mutex_lock(&init_mutex);
3080 while (init_left)
3081 pthread_cond_wait(&init_cond, &init_mutex);
3082 pthread_mutex_unlock(&init_mutex);
3083#endif
Willy Tarreau3078e9f2019-05-20 10:50:43 +02003084
Willy Tarreaua45a8b52019-12-06 16:31:45 +01003085#if defined(PR_SET_NO_NEW_PRIVS) && defined(USE_PRCTL)
3086 /* Let's refrain from using setuid executables. This way the impact of
3087 * an eventual vulnerability in a library remains limited. It may
3088 * impact external checks but who cares about them anyway ? In the
3089 * worst case it's possible to disable the option. Obviously we do this
3090 * in workers only. We can't hard-fail on this one as it really is
3091 * implementation dependent though we're interested in feedback, hence
3092 * the warning.
3093 */
3094 if (!(global.tune.options & GTUNE_INSECURE_SETUID) && !master) {
3095 static int warn_fail;
Willy Tarreau18515722021-04-06 11:57:41 +02003096 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 +01003097 ha_warning("Failed to disable setuid, please report to developers with detailed "
3098 "information about your operating system. You can silence this warning "
3099 "by adding 'insecure-setuid-wanted' in the 'global' section.\n");
3100 }
3101 }
3102#endif
3103
Willy Tarreaud96f1122019-12-03 07:07:36 +01003104#if defined(RLIMIT_NPROC)
3105 /* all threads have started, it's now time to prevent any new thread
3106 * or process from starting. Obviously we do this in workers only. We
3107 * can't hard-fail on this one as it really is implementation dependent
3108 * though we're interested in feedback, hence the warning.
3109 */
3110 if (!(global.tune.options & GTUNE_INSECURE_FORK) && !master) {
3111 struct rlimit limit = { .rlim_cur = 0, .rlim_max = 0 };
3112 static int warn_fail;
3113
Willy Tarreau18515722021-04-06 11:57:41 +02003114 if (setrlimit(RLIMIT_NPROC, &limit) == -1 && !_HA_ATOMIC_FETCH_ADD(&warn_fail, 1)) {
Willy Tarreaud96f1122019-12-03 07:07:36 +01003115 ha_warning("Failed to disable forks, please report to developers with detailed "
3116 "information about your operating system. You can silence this warning "
3117 "by adding 'insecure-fork-wanted' in the 'global' section.\n");
3118 }
3119 }
3120#endif
Christopher Faulet1d17c102017-08-29 15:38:48 +02003121 run_poll_loop();
3122
3123 list_for_each_entry(ptdf, &per_thread_deinit_list, list)
3124 ptdf->fct();
3125
Willy Tarreau082b6282019-05-22 14:42:12 +02003126 list_for_each_entry(ptff, &per_thread_free_list, list)
3127 ptff->fct();
3128
Christopher Fauletcd7879a2017-10-27 13:53:47 +02003129#ifdef USE_THREAD
Willy Tarreau291f6ff2022-07-04 13:36:16 +02003130 if (!_HA_ATOMIC_AND_FETCH(&ha_tgroup_info[ti->tgid-1].threads_enabled, ~ti->ltid_bit))
Willy Tarreaucce203a2022-06-24 15:55:11 +02003131 _HA_ATOMIC_AND(&all_tgroups_mask, ~tg->tgid_bit);
Willy Tarreauad92fdf2022-07-06 10:17:21 +02003132 if (!_HA_ATOMIC_AND_FETCH(&tg_ctx->stopping_threads, ~ti->ltid_bit))
3133 _HA_ATOMIC_AND(&stopping_tgroup_mask, ~tg->tgid_bit);
Christopher Fauletcd7879a2017-10-27 13:53:47 +02003134 if (tid > 0)
3135 pthread_exit(NULL);
Christopher Faulet1d17c102017-08-29 15:38:48 +02003136#endif
Christopher Fauletcd7879a2017-10-27 13:53:47 +02003137 return NULL;
3138}
Christopher Faulet1d17c102017-08-29 15:38:48 +02003139
William Dauchyf9af9d72019-11-17 15:47:16 +01003140/* set uid/gid depending on global settings */
3141static void set_identity(const char *program_name)
3142{
3143 if (global.gid) {
3144 if (getgroups(0, NULL) > 0 && setgroups(0, NULL) == -1)
3145 ha_warning("[%s.main()] Failed to drop supplementary groups. Using 'gid'/'group'"
3146 " without 'uid'/'user' is generally useless.\n", program_name);
3147
3148 if (setgid(global.gid) == -1) {
3149 ha_alert("[%s.main()] Cannot set gid %d.\n", program_name, global.gid);
3150 protocol_unbind_all();
3151 exit(1);
3152 }
3153 }
3154
3155 if (global.uid && setuid(global.uid) == -1) {
3156 ha_alert("[%s.main()] Cannot set uid %d.\n", program_name, global.uid);
3157 protocol_unbind_all();
3158 exit(1);
3159 }
3160}
3161
Willy Tarreaubaaee002006-06-26 02:48:02 +02003162int main(int argc, char **argv)
3163{
3164 int err, retry;
3165 struct rlimit limit;
Willy Tarreau269ab312012-09-05 08:02:48 +02003166 int pidfd = -1;
Willy Tarreau1335da32021-07-14 17:54:01 +02003167 int intovf = (unsigned char)argc + 1; /* let the compiler know it's strictly positive */
3168
Willy Tarreau41afd902022-07-21 09:55:22 +02003169 /* Catch broken toolchains */
3170 if (sizeof(long) != sizeof(void *) || (intovf + 0x7FFFFFFF >= intovf)) {
3171 const char *msg;
3172
3173 if (sizeof(long) != sizeof(void *))
3174 /* Apparently MingW64 was not made for us and can also break openssl */
3175 msg = "The compiler this program was built with uses unsupported integral type sizes.\n"
3176 "Most likely it follows the unsupported LLP64 model. Never try to link HAProxy\n"
3177 "against libraries built with that compiler either! Please only use a compiler\n"
3178 "producing ILP32 or LP64 programs for both programs and libraries.\n";
3179 else if (intovf + 0x7FFFFFFF >= intovf)
3180 /* Catch forced CFLAGS that miss 2-complement integer overflow */
3181 msg = "The source code was miscompiled by the compiler, which usually indicates that\n"
3182 "some of the CFLAGS needed to work around overzealous compiler optimizations\n"
3183 "were overwritten at build time. Please do not force CFLAGS, and read Makefile\n"
3184 "and INSTALL files to decide on the best way to pass your local build options.\n";
3185 else
3186 msg = "Bug in the compiler bug detection code, please report it to developers!\n";
3187
Willy Tarreau1335da32021-07-14 17:54:01 +02003188 fprintf(stderr,
3189 "FATAL ERROR: invalid code detected -- cannot go further, please recompile!\n"
Willy Tarreau41afd902022-07-21 09:55:22 +02003190 "%s"
3191 "\nBuild options :"
Willy Tarreau1335da32021-07-14 17:54:01 +02003192#ifdef BUILD_TARGET
Willy Tarreau41afd902022-07-21 09:55:22 +02003193 "\n TARGET = " BUILD_TARGET
Willy Tarreau1335da32021-07-14 17:54:01 +02003194#endif
3195#ifdef BUILD_CPU
Willy Tarreau41afd902022-07-21 09:55:22 +02003196 "\n CPU = " BUILD_CPU
Willy Tarreau1335da32021-07-14 17:54:01 +02003197#endif
3198#ifdef BUILD_CC
Willy Tarreau41afd902022-07-21 09:55:22 +02003199 "\n CC = " BUILD_CC
Willy Tarreau1335da32021-07-14 17:54:01 +02003200#endif
3201#ifdef BUILD_CFLAGS
Willy Tarreau41afd902022-07-21 09:55:22 +02003202 "\n CFLAGS = " BUILD_CFLAGS
Willy Tarreau1335da32021-07-14 17:54:01 +02003203#endif
3204#ifdef BUILD_OPTIONS
Willy Tarreau41afd902022-07-21 09:55:22 +02003205 "\n OPTIONS = " BUILD_OPTIONS
Willy Tarreau1335da32021-07-14 17:54:01 +02003206#endif
3207#ifdef BUILD_DEBUG
Willy Tarreau41afd902022-07-21 09:55:22 +02003208 "\n DEBUG = " BUILD_DEBUG
Willy Tarreau1335da32021-07-14 17:54:01 +02003209#endif
Willy Tarreau41afd902022-07-21 09:55:22 +02003210 "\n\n", msg);
3211
Willy Tarreau1335da32021-07-14 17:54:01 +02003212 return 1;
3213 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003214
Olivier Houchard5fa300d2018-02-03 15:15:21 +01003215 setvbuf(stdout, NULL, _IONBF, 0);
Willy Tarreau5794fb02018-11-25 18:43:29 +01003216
Willy Tarreaubf696402019-03-01 10:09:28 +01003217 /* take a copy of initial limits before we possibly change them */
3218 getrlimit(RLIMIT_NOFILE, &limit);
Willy Tarreau2bd0f812020-10-13 15:36:08 +02003219
3220 if (limit.rlim_max == RLIM_INFINITY)
3221 limit.rlim_max = limit.rlim_cur;
Willy Tarreaubf696402019-03-01 10:09:28 +01003222 rlim_fd_cur_at_boot = limit.rlim_cur;
3223 rlim_fd_max_at_boot = limit.rlim_max;
3224
Willy Tarreau5794fb02018-11-25 18:43:29 +01003225 /* process all initcalls in order of potential dependency */
3226 RUN_INITCALLS(STG_PREPARE);
3227 RUN_INITCALLS(STG_LOCK);
Willy Tarreau3ebe4d92022-02-18 14:51:49 +01003228 RUN_INITCALLS(STG_REGISTER);
Willy Tarreau34527d52022-02-17 17:45:58 +01003229
3230 /* now's time to initialize early boot variables */
3231 init_early(argc, argv);
3232
Willy Tarreau18f96d02022-02-23 17:25:00 +01003233 /* handles argument parsing */
3234 init_args(argc, argv);
3235
Willy Tarreau5794fb02018-11-25 18:43:29 +01003236 RUN_INITCALLS(STG_ALLOC);
3237 RUN_INITCALLS(STG_POOL);
Willy Tarreau5794fb02018-11-25 18:43:29 +01003238 RUN_INITCALLS(STG_INIT);
3239
Willy Tarreau34527d52022-02-17 17:45:58 +01003240 /* this is the late init where the config is parsed */
Emeric Bruncf20bf12010-10-22 16:06:11 +02003241 init(argc, argv);
Willy Tarreau34527d52022-02-17 17:45:58 +01003242
Willy Tarreau24f4efa2010-08-27 17:56:48 +02003243 signal_register_fct(SIGQUIT, dump, SIGQUIT);
3244 signal_register_fct(SIGUSR1, sig_soft_stop, SIGUSR1);
3245 signal_register_fct(SIGHUP, sig_dump_state, SIGHUP);
William Lallemand73b85e72017-06-01 17:38:51 +02003246 signal_register_fct(SIGUSR2, NULL, 0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003247
Willy Tarreaue437c442010-03-17 18:02:46 +01003248 /* Always catch SIGPIPE even on platforms which define MSG_NOSIGNAL.
3249 * Some recent FreeBSD setups report broken pipes, and MSG_NOSIGNAL
3250 * was defined there, so let's stay on the safe side.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003251 */
Willy Tarreau24f4efa2010-08-27 17:56:48 +02003252 signal_register_fct(SIGPIPE, NULL, 0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003253
Willy Tarreaudc23a922011-02-16 11:10:36 +01003254 /* ulimits */
3255 if (!global.rlimit_nofile)
3256 global.rlimit_nofile = global.maxsock;
3257
3258 if (global.rlimit_nofile) {
Willy Tarreaue5cfdac2019-03-01 10:32:05 +01003259 limit.rlim_cur = global.rlimit_nofile;
3260 limit.rlim_max = MAX(rlim_fd_max_at_boot, limit.rlim_cur);
3261
Willy Tarreau2df1fbf2022-04-25 18:02:03 +02003262 if ((global.fd_hard_limit && limit.rlim_cur > global.fd_hard_limit) ||
Willy Tarreauc06557c2022-09-22 16:12:08 +02003263 raise_rlim_nofile(NULL, &limit) != 0) {
Willy Tarreauef635472016-06-21 11:48:18 +02003264 getrlimit(RLIMIT_NOFILE, &limit);
Willy Tarreau2df1fbf2022-04-25 18:02:03 +02003265 if (global.fd_hard_limit && limit.rlim_cur > global.fd_hard_limit)
3266 limit.rlim_cur = global.fd_hard_limit;
3267
William Dauchy0fec3ab2019-10-27 20:08:11 +01003268 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3269 ha_alert("[%s.main()] Cannot raise FD limit to %d, limit is %d.\n",
3270 argv[0], global.rlimit_nofile, (int)limit.rlim_cur);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003271 exit(1);
William Dauchy0fec3ab2019-10-27 20:08:11 +01003272 }
3273 else {
3274 /* try to set it to the max possible at least */
3275 limit.rlim_cur = limit.rlim_max;
Willy Tarreau2df1fbf2022-04-25 18:02:03 +02003276 if (global.fd_hard_limit && limit.rlim_cur > global.fd_hard_limit)
3277 limit.rlim_cur = global.fd_hard_limit;
3278
Willy Tarreauc06557c2022-09-22 16:12:08 +02003279 if (raise_rlim_nofile(&limit, &limit) == 0)
William Dauchy0fec3ab2019-10-27 20:08:11 +01003280 getrlimit(RLIMIT_NOFILE, &limit);
Willy Tarreau164dd0b2016-06-21 11:51:59 +02003281
William Dauchya5194602020-03-28 19:29:58 +01003282 ha_warning("[%s.main()] Cannot raise FD limit to %d, limit is %d.\n",
William Dauchy0fec3ab2019-10-27 20:08:11 +01003283 argv[0], global.rlimit_nofile, (int)limit.rlim_cur);
3284 global.rlimit_nofile = limit.rlim_cur;
3285 }
Willy Tarreaudc23a922011-02-16 11:10:36 +01003286 }
3287 }
3288
3289 if (global.rlimit_memmax) {
3290 limit.rlim_cur = limit.rlim_max =
Willy Tarreau70060452015-12-14 12:46:07 +01003291 global.rlimit_memmax * 1048576ULL;
Willy Tarreaudc23a922011-02-16 11:10:36 +01003292#ifdef RLIMIT_AS
3293 if (setrlimit(RLIMIT_AS, &limit) == -1) {
William Dauchy0fec3ab2019-10-27 20:08:11 +01003294 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3295 ha_alert("[%s.main()] Cannot fix MEM limit to %d megs.\n",
3296 argv[0], global.rlimit_memmax);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003297 exit(1);
William Dauchy0fec3ab2019-10-27 20:08:11 +01003298 }
3299 else
William Dauchya5194602020-03-28 19:29:58 +01003300 ha_warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
William Dauchy0fec3ab2019-10-27 20:08:11 +01003301 argv[0], global.rlimit_memmax);
Willy Tarreaudc23a922011-02-16 11:10:36 +01003302 }
3303#else
3304 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
William Dauchy0fec3ab2019-10-27 20:08:11 +01003305 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3306 ha_alert("[%s.main()] Cannot fix MEM limit to %d megs.\n",
3307 argv[0], global.rlimit_memmax);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003308 exit(1);
William Dauchy0fec3ab2019-10-27 20:08:11 +01003309 }
3310 else
William Dauchya5194602020-03-28 19:29:58 +01003311 ha_warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
William Dauchy0fec3ab2019-10-27 20:08:11 +01003312 argv[0], global.rlimit_memmax);
Willy Tarreaudc23a922011-02-16 11:10:36 +01003313 }
3314#endif
3315 }
3316
William Lallemandf82afbb2022-01-07 18:19:42 +01003317 /* Try to get the listeners FD from the previous process using
3318 * _getsocks on the stat socket, it must never been done in wait mode
3319 * and check mode
3320 */
3321 if (old_unixsocket &&
3322 !(global.mode & (MODE_MWORKER_WAIT|MODE_CHECK|MODE_CHECK_CONDITION))) {
William Lallemand85b0bd92017-06-01 17:38:53 +02003323 if (strcmp("/dev/null", old_unixsocket) != 0) {
Willy Tarreau42961742020-08-28 18:42:45 +02003324 if (sock_get_old_sockets(old_unixsocket) != 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003325 ha_alert("Failed to get the sockets from the old process!\n");
William Lallemand85b0bd92017-06-01 17:38:53 +02003326 if (!(global.mode & MODE_MWORKER))
3327 exit(1);
3328 }
Olivier Houchardf73629d2017-04-05 22:33:04 +02003329 }
3330 }
William Lallemand85b0bd92017-06-01 17:38:53 +02003331
Willy Tarreaubaaee002006-06-26 02:48:02 +02003332 /* We will loop at most 100 times with 10 ms delay each time.
3333 * That's at most 1 second. We only send a signal to old pids
3334 * if we cannot grab at least one port.
3335 */
3336 retry = MAX_START_RETRIES;
3337 err = ERR_NONE;
3338 while (retry >= 0) {
3339 struct timeval w;
Willy Tarreaue91bff22020-09-02 11:11:43 +02003340 err = protocol_bind_all(retry == 0 || nb_oldpids == 0);
Willy Tarreaue13e9252007-12-20 23:05:50 +01003341 /* exit the loop on no error or fatal error */
3342 if ((err & (ERR_RETRYABLE|ERR_FATAL)) != ERR_RETRYABLE)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003343 break;
Willy Tarreaubb545b42010-08-25 12:58:59 +02003344 if (nb_oldpids == 0 || retry == 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003345 break;
3346
3347 /* FIXME-20060514: Solaris and OpenBSD do not support shutdown() on
3348 * listening sockets. So on those platforms, it would be wiser to
3349 * simply send SIGUSR1, which will not be undoable.
3350 */
Willy Tarreaubb545b42010-08-25 12:58:59 +02003351 if (tell_old_pids(SIGTTOU) == 0) {
3352 /* no need to wait if we can't contact old pids */
3353 retry = 0;
3354 continue;
3355 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003356 /* give some time to old processes to stop listening */
3357 w.tv_sec = 0;
3358 w.tv_usec = 10*1000;
3359 select(0, NULL, NULL, NULL, &w);
3360 retry--;
3361 }
3362
Willy Tarreaue91bff22020-09-02 11:11:43 +02003363 /* Note: protocol_bind_all() sends an alert when it fails. */
Willy Tarreau0a3b9d92009-02-04 17:05:23 +01003364 if ((err & ~ERR_WARN) != ERR_NONE) {
Willy Tarreaue91bff22020-09-02 11:11:43 +02003365 ha_alert("[%s.main()] Some protocols failed to start their listeners! Exiting.\n", argv[0]);
Willy Tarreauf68da462009-06-09 14:36:00 +02003366 if (retry != MAX_START_RETRIES && nb_oldpids) {
3367 protocol_unbind_all(); /* cleanup everything we can */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003368 tell_old_pids(SIGTTIN);
Willy Tarreauf68da462009-06-09 14:36:00 +02003369 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003370 exit(1);
3371 }
3372
William Lallemand944e6192018-11-21 15:48:31 +01003373 if (!(global.mode & MODE_MWORKER_WAIT) && listeners == 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003374 ha_alert("[%s.main()] No enabled listener found (check for 'bind' directives) ! Exiting.\n", argv[0]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003375 /* Note: we don't have to send anything to the old pids because we
3376 * never stopped them. */
3377 exit(1);
3378 }
3379
Willy Tarreaue91bff22020-09-02 11:11:43 +02003380 /* Ok, all listeners should now be bound, close any leftover sockets
Olivier Houchardf73629d2017-04-05 22:33:04 +02003381 * the previous process gave us, we don't need them anymore
3382 */
Willy Tarreaub5101162022-01-28 18:28:18 +01003383 sock_drop_unused_old_sockets();
Willy Tarreaudd815982007-10-16 12:25:14 +02003384
Willy Tarreaubaaee002006-06-26 02:48:02 +02003385 /* prepare pause/play signals */
Willy Tarreau24f4efa2010-08-27 17:56:48 +02003386 signal_register_fct(SIGTTOU, sig_pause, SIGTTOU);
3387 signal_register_fct(SIGTTIN, sig_listen, SIGTTIN);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003388
Willy Tarreaubaaee002006-06-26 02:48:02 +02003389 /* MODE_QUIET can inhibit alerts and warnings below this line */
3390
PiBa-NL149a81a2017-12-25 21:03:31 +01003391 if (getenv("HAPROXY_MWORKER_REEXEC") != NULL) {
3392 /* either stdin/out/err are already closed or should stay as they are. */
3393 if ((global.mode & MODE_DAEMON)) {
3394 /* daemon mode re-executing, stdin/stdout/stderr are already closed so keep quiet */
3395 global.mode &= ~MODE_VERBOSE;
3396 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
3397 }
3398 } else {
3399 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
3400 /* detach from the tty */
William Lallemande1340412017-12-28 16:09:36 +01003401 stdio_quiet(-1);
PiBa-NL149a81a2017-12-25 21:03:31 +01003402 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003403 }
3404
3405 /* open log & pid files before the chroot */
William Lallemand7b820a62022-02-14 09:02:14 +01003406 if ((global.mode & MODE_DAEMON || global.mode & MODE_MWORKER) &&
3407 !(global.mode & MODE_MWORKER_WAIT) && global.pidfile != NULL) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003408 unlink(global.pidfile);
3409 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
3410 if (pidfd < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003411 ha_alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003412 if (nb_oldpids)
3413 tell_old_pids(SIGTTIN);
Willy Tarreaudd815982007-10-16 12:25:14 +02003414 protocol_unbind_all();
Willy Tarreaubaaee002006-06-26 02:48:02 +02003415 exit(1);
3416 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003417 }
3418
Willy Tarreaub38651a2007-03-24 17:24:39 +01003419 if ((global.last_checks & LSTCHK_NETADM) && global.uid) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003420 ha_alert("[%s.main()] Some configuration options require full privileges, so global.uid cannot be changed.\n"
3421 "", argv[0]);
Willy Tarreaudd815982007-10-16 12:25:14 +02003422 protocol_unbind_all();
Willy Tarreaub38651a2007-03-24 17:24:39 +01003423 exit(1);
3424 }
3425
Jackie Tapia749f74c2020-07-22 18:59:40 -05003426 /* If the user is not root, we'll still let them try the configuration
3427 * but we inform them that unexpected behaviour may occur.
Willy Tarreau4e30ed72009-02-04 18:02:48 +01003428 */
3429 if ((global.last_checks & LSTCHK_NETADM) && getuid())
Christopher Faulet767a84b2017-11-24 16:50:31 +01003430 ha_warning("[%s.main()] Some options which require full privileges"
3431 " might not work well.\n"
3432 "", argv[0]);
Willy Tarreau4e30ed72009-02-04 18:02:48 +01003433
William Lallemand095ba4c2017-06-01 17:38:50 +02003434 if ((global.mode & (MODE_MWORKER|MODE_DAEMON)) == 0) {
3435
3436 /* chroot if needed */
3437 if (global.chroot != NULL) {
3438 if (chroot(global.chroot) == -1 || chdir("/") == -1) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003439 ha_alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
William Lallemand095ba4c2017-06-01 17:38:50 +02003440 if (nb_oldpids)
3441 tell_old_pids(SIGTTIN);
3442 protocol_unbind_all();
3443 exit(1);
3444 }
Willy Tarreauf223cc02007-10-15 18:57:08 +02003445 }
Willy Tarreauf223cc02007-10-15 18:57:08 +02003446 }
3447
William Lallemand944e6192018-11-21 15:48:31 +01003448 if (nb_oldpids && !(global.mode & MODE_MWORKER_WAIT))
Willy Tarreaubb545b42010-08-25 12:58:59 +02003449 nb_oldpids = tell_old_pids(oldpids_sig);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003450
William Lallemand27edc4b2019-05-07 17:49:33 +02003451 /* send a SIGTERM to workers who have a too high reloads number */
3452 if ((global.mode & MODE_MWORKER) && !(global.mode & MODE_MWORKER_WAIT))
3453 mworker_kill_max_reloads(SIGTERM);
3454
Willy Tarreaubaaee002006-06-26 02:48:02 +02003455 /* Note that any error at this stage will be fatal because we will not
3456 * be able to restart the old pids.
3457 */
3458
William Dauchyf9af9d72019-11-17 15:47:16 +01003459 if ((global.mode & (MODE_MWORKER | MODE_DAEMON)) == 0)
3460 set_identity(argv[0]);
Willy Tarreau636848a2019-04-15 19:38:50 +02003461
Willy Tarreaubaaee002006-06-26 02:48:02 +02003462 /* check ulimits */
3463 limit.rlim_cur = limit.rlim_max = 0;
3464 getrlimit(RLIMIT_NOFILE, &limit);
3465 if (limit.rlim_cur < global.maxsock) {
William Dauchy0fec3ab2019-10-27 20:08:11 +01003466 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3467 ha_alert("[%s.main()] FD limit (%d) too low for maxconn=%d/maxsock=%d. "
3468 "Please raise 'ulimit-n' to %d or more to avoid any trouble.\n",
3469 argv[0], (int)limit.rlim_cur, global.maxconn, global.maxsock,
3470 global.maxsock);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003471 exit(1);
William Dauchy0fec3ab2019-10-27 20:08:11 +01003472 }
3473 else
3474 ha_alert("[%s.main()] FD limit (%d) too low for maxconn=%d/maxsock=%d. "
William Dauchya5194602020-03-28 19:29:58 +01003475 "Please raise 'ulimit-n' to %d or more to avoid any trouble.\n",
William Dauchy0fec3ab2019-10-27 20:08:11 +01003476 argv[0], (int)limit.rlim_cur, global.maxconn, global.maxsock,
3477 global.maxsock);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003478 }
3479
William Lallemand944e6192018-11-21 15:48:31 +01003480 if (global.mode & (MODE_DAEMON | MODE_MWORKER | MODE_MWORKER_WAIT)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003481 int ret = 0;
Willy Tarreaud67ff342021-06-15 07:58:09 +02003482 int in_parent = 0;
William Lallemande1340412017-12-28 16:09:36 +01003483 int devnullfd = -1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003484
William Lallemand095ba4c2017-06-01 17:38:50 +02003485 /*
3486 * if daemon + mworker: must fork here to let a master
3487 * process live in background before forking children
3488 */
William Lallemand73b85e72017-06-01 17:38:51 +02003489
3490 if ((getenv("HAPROXY_MWORKER_REEXEC") == NULL)
3491 && (global.mode & MODE_MWORKER)
3492 && (global.mode & MODE_DAEMON)) {
William Lallemand095ba4c2017-06-01 17:38:50 +02003493 ret = fork();
3494 if (ret < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003495 ha_alert("[%s.main()] Cannot fork.\n", argv[0]);
William Lallemand095ba4c2017-06-01 17:38:50 +02003496 protocol_unbind_all();
3497 exit(1); /* there has been an error */
William Lallemandbfd8eb52018-07-04 15:31:23 +02003498 } else if (ret > 0) { /* parent leave to daemonize */
William Lallemand095ba4c2017-06-01 17:38:50 +02003499 exit(0);
William Lallemandbfd8eb52018-07-04 15:31:23 +02003500 } else /* change the process group ID in the child (master process) */
3501 setsid();
William Lallemand095ba4c2017-06-01 17:38:50 +02003502 }
William Lallemande20b6a62017-06-01 17:38:55 +02003503
William Lallemande20b6a62017-06-01 17:38:55 +02003504
William Lallemanddeed7802017-11-06 11:00:04 +01003505 /* if in master-worker mode, write the PID of the father */
3506 if (global.mode & MODE_MWORKER) {
3507 char pidstr[100];
Willy Tarreau76a80c72019-06-22 07:41:38 +02003508 snprintf(pidstr, sizeof(pidstr), "%d\n", (int)getpid());
Willy Tarreau46ec48b2018-01-23 19:20:19 +01003509 if (pidfd >= 0)
Willy Tarreau2e8ab6b2020-03-14 11:03:20 +01003510 DISGUISE(write(pidfd, pidstr, strlen(pidstr)));
William Lallemanddeed7802017-11-06 11:00:04 +01003511 }
3512
Willy Tarreaubaaee002006-06-26 02:48:02 +02003513 /* the father launches the required number of processes */
William Lallemand944e6192018-11-21 15:48:31 +01003514 if (!(global.mode & MODE_MWORKER_WAIT)) {
William Lallemandeba6a542022-09-26 12:54:39 +02003515 struct ring *tmp_startup_logs = NULL;
3516
William Lallemand9a1ee7a2019-04-01 11:30:02 +02003517 if (global.mode & MODE_MWORKER)
3518 mworker_ext_launch_all();
Willy Tarreaud67ff342021-06-15 07:58:09 +02003519
William Lallemandeba6a542022-09-26 12:54:39 +02003520 /* at this point the worker must have his own startup_logs buffer */
3521 tmp_startup_logs = startup_logs_dup(startup_logs);
Willy Tarreaud67ff342021-06-15 07:58:09 +02003522 ret = fork();
3523 if (ret < 0) {
3524 ha_alert("[%s.main()] Cannot fork.\n", argv[0]);
3525 protocol_unbind_all();
3526 exit(1); /* there has been an error */
3527 }
3528 else if (ret == 0) { /* child breaks here */
William Lallemandeba6a542022-09-26 12:54:39 +02003529 startup_logs_free(startup_logs);
3530 startup_logs = tmp_startup_logs;
Willy Tarreau3c032f22021-07-21 10:17:02 +02003531 /* This one must not be exported, it's internal! */
3532 unsetenv("HAPROXY_MWORKER_REEXEC");
Willy Tarreaue8422bf2021-06-15 09:08:18 +02003533 ha_random_jump96(1);
Willy Tarreaud67ff342021-06-15 07:58:09 +02003534 }
3535 else { /* parent here */
3536 in_parent = 1;
3537
William Lallemand944e6192018-11-21 15:48:31 +01003538 if (pidfd >= 0 && !(global.mode & MODE_MWORKER)) {
3539 char pidstr[100];
3540 snprintf(pidstr, sizeof(pidstr), "%d\n", ret);
Willy Tarreau2e8ab6b2020-03-14 11:03:20 +01003541 DISGUISE(write(pidfd, pidstr, strlen(pidstr)));
William Lallemand944e6192018-11-21 15:48:31 +01003542 }
3543 if (global.mode & MODE_MWORKER) {
3544 struct mworker_proc *child;
William Lallemandce83b4a2018-10-26 14:47:30 +02003545
William Lallemand5d71a6b2021-11-09 15:25:31 +01003546 ha_notice("New worker (%d) forked\n", ret);
William Lallemand944e6192018-11-21 15:48:31 +01003547 /* find the right mworker_proc */
3548 list_for_each_entry(child, &proc_list, list) {
William Lallemandd4835a92022-07-21 00:52:43 +02003549 if (child->reloads == 0 &&
3550 child->options & PROC_O_TYPE_WORKER &&
3551 child->pid == -1) {
William Lallemand944e6192018-11-21 15:48:31 +01003552 child->timestamp = now.tv_sec;
3553 child->pid = ret;
William Lallemand1dc69632019-06-12 19:11:33 +02003554 child->version = strdup(haproxy_version);
William Lallemand944e6192018-11-21 15:48:31 +01003555 break;
3556 }
William Lallemandce83b4a2018-10-26 14:47:30 +02003557 }
3558 }
William Lallemand944e6192018-11-21 15:48:31 +01003559 }
Willy Tarreaud67ff342021-06-15 07:58:09 +02003560
William Lallemand944e6192018-11-21 15:48:31 +01003561 } else {
3562 /* wait mode */
Willy Tarreaud67ff342021-06-15 07:58:09 +02003563 in_parent = 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003564 }
Willy Tarreaufc6c0322012-11-16 16:12:27 +01003565
3566#ifdef USE_CPU_AFFINITY
Willy Tarreau5b093412022-07-08 09:38:30 +02003567 if (!in_parent && ha_cpuset_count(&cpu_map[0].proc)) { /* only do this if the process has a CPU map */
Olivier Houchard97148f62017-08-16 17:29:11 +02003568
David CARLIERdf91cbd2022-01-06 18:53:50 +00003569#if defined(CPUSET_USE_CPUSET) || defined(__DragonFly__)
Willy Tarreau5b093412022-07-08 09:38:30 +02003570 struct hap_cpuset *set = &cpu_map[0].proc;
Amaury Denoyelle982fb532021-04-21 18:39:58 +02003571 sched_setaffinity(0, sizeof(set->cpuset), &set->cpuset);
David CARLIERdf91cbd2022-01-06 18:53:50 +00003572#elif defined(__FreeBSD__)
Willy Tarreau5b093412022-07-08 09:38:30 +02003573 struct hap_cpuset *set = &cpu_map[0].proc;
David CARLIERdf91cbd2022-01-06 18:53:50 +00003574 ret = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(set->cpuset), &set->cpuset);
Willy Tarreaufc6c0322012-11-16 16:12:27 +01003575#endif
Amaury Denoyelle982fb532021-04-21 18:39:58 +02003576 }
Pieter Baauwcaa6a1b2015-09-17 21:26:40 +02003577#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02003578 /* close the pidfile both in children and father */
Willy Tarreau269ab312012-09-05 08:02:48 +02003579 if (pidfd >= 0) {
3580 //lseek(pidfd, 0, SEEK_SET); /* debug: emulate eglibc bug */
3581 close(pidfd);
3582 }
Willy Tarreaud137dd32010-08-25 12:49:05 +02003583
3584 /* We won't ever use this anymore */
Willy Tarreau61cfdf42021-02-20 10:46:51 +01003585 ha_free(&global.pidfile);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003586
Willy Tarreaud67ff342021-06-15 07:58:09 +02003587 if (in_parent) {
William Lallemand944e6192018-11-21 15:48:31 +01003588 if (global.mode & (MODE_MWORKER|MODE_MWORKER_WAIT)) {
William Lallemandfab0fdc2021-11-09 18:01:22 +01003589 master = 1;
PiBa-NLbaf6ea42017-11-28 23:26:08 +01003590
3591 if ((!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
3592 (global.mode & MODE_DAEMON)) {
3593 /* detach from the tty, this is required to properly daemonize. */
William Lallemande1340412017-12-28 16:09:36 +01003594 if ((getenv("HAPROXY_MWORKER_REEXEC") == NULL))
3595 stdio_quiet(-1);
3596
PiBa-NLbaf6ea42017-11-28 23:26:08 +01003597 global.mode &= ~MODE_VERBOSE;
3598 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
PiBa-NLbaf6ea42017-11-28 23:26:08 +01003599 }
3600
William Lallemandfab0fdc2021-11-09 18:01:22 +01003601 if (global.mode & MODE_MWORKER_WAIT) {
3602 /* only the wait mode handles the master CLI */
3603 mworker_loop();
3604 } else {
3605
William Lallemanda46a99e2022-07-07 14:00:36 +02003606#if defined(USE_SYSTEMD)
3607 if (global.tune.options & GTUNE_USE_SYSTEMD)
3608 sd_notifyf(0, "READY=1\nMAINPID=%lu\nSTATUS=Ready.\n", (unsigned long)getpid());
3609#endif
William Lallemandfab0fdc2021-11-09 18:01:22 +01003610 /* if not in wait mode, reload in wait mode to free the memory */
William Lallemand68192b22022-09-24 15:44:42 +02003611 setenv("HAPROXY_LOAD_SUCCESS", "1", 1);
William Lallemand836bda22021-11-09 18:16:47 +01003612 ha_notice("Loading success.\n");
William Lallemand68836742021-11-10 10:49:06 +01003613 proc_self->failedreloads = 0; /* reset the number of failure */
William Lallemandfab0fdc2021-11-09 18:01:22 +01003614 mworker_reexec_waitmode();
3615 }
William Lallemand1499b9b2017-06-07 15:04:47 +02003616 /* should never get there */
3617 exit(EXIT_FAILURE);
Willy Tarreauedaff0a2015-05-01 17:01:08 +02003618 }
William Lallemandcf4e4962017-06-08 19:05:48 +02003619#if defined(USE_OPENSSL) && !defined(OPENSSL_NO_DH)
Grant Zhang872f9c22017-01-21 01:10:18 +00003620 ssl_free_dh();
3621#endif
William Lallemand1499b9b2017-06-07 15:04:47 +02003622 exit(0); /* parent must leave */
Willy Tarreauedaff0a2015-05-01 17:01:08 +02003623 }
3624
William Lallemandcb11fd22017-06-01 17:38:52 +02003625 /* child must never use the atexit function */
3626 atexit_flag = 0;
3627
William Lallemandbc193052018-09-11 10:06:26 +02003628 /* close useless master sockets */
3629 if (global.mode & MODE_MWORKER) {
3630 struct mworker_proc *child, *it;
3631 master = 0;
3632
William Lallemand309dc9a2018-10-26 14:47:45 +02003633 mworker_cli_proxy_stop();
3634
William Lallemandbc193052018-09-11 10:06:26 +02003635 /* free proc struct of other processes */
3636 list_for_each_entry_safe(child, it, &proc_list, list) {
William Lallemandce83b4a2018-10-26 14:47:30 +02003637 /* close the FD of the master side for all
3638 * workers, we don't need to close the worker
3639 * side of other workers since it's done with
3640 * the bind_proc */
William Lallemand7e018782022-01-28 21:56:24 +01003641 if (child->ipc_fd[0] >= 0) {
Tim Duesterhus742e0f92018-11-25 20:03:39 +01003642 close(child->ipc_fd[0]);
William Lallemand7e018782022-01-28 21:56:24 +01003643 child->ipc_fd[0] = -1;
3644 }
Willy Tarreaue8422bf2021-06-15 09:08:18 +02003645 if (child->options & PROC_O_TYPE_WORKER &&
William Lallemandd4835a92022-07-21 00:52:43 +02003646 child->reloads == 0 &&
3647 child->pid == -1) {
William Lallemandce83b4a2018-10-26 14:47:30 +02003648 /* keep this struct if this is our pid */
3649 proc_self = child;
William Lallemandbc193052018-09-11 10:06:26 +02003650 continue;
William Lallemandce83b4a2018-10-26 14:47:30 +02003651 }
Willy Tarreau2b718102021-04-21 07:32:39 +02003652 LIST_DELETE(&child->list);
Tim Duesterhus9b7a9762019-05-16 20:23:22 +02003653 mworker_free_child(child);
3654 child = NULL;
William Lallemandbc193052018-09-11 10:06:26 +02003655 }
3656 }
Willy Tarreau1605c7a2018-01-23 19:01:49 +01003657
William Lallemande1340412017-12-28 16:09:36 +01003658 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
3659 devnullfd = open("/dev/null", O_RDWR, 0);
3660 if (devnullfd < 0) {
3661 ha_alert("Cannot open /dev/null\n");
3662 exit(EXIT_FAILURE);
3663 }
3664 }
3665
William Lallemand095ba4c2017-06-01 17:38:50 +02003666 /* Must chroot and setgid/setuid in the children */
3667 /* chroot if needed */
3668 if (global.chroot != NULL) {
3669 if (chroot(global.chroot) == -1 || chdir("/") == -1) {
Willy Tarreaue34cf282021-06-15 08:59:19 +02003670 ha_alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
William Lallemand095ba4c2017-06-01 17:38:50 +02003671 if (nb_oldpids)
3672 tell_old_pids(SIGTTIN);
3673 protocol_unbind_all();
3674 exit(1);
3675 }
3676 }
3677
Willy Tarreau61cfdf42021-02-20 10:46:51 +01003678 ha_free(&global.chroot);
William Dauchyf9af9d72019-11-17 15:47:16 +01003679 set_identity(argv[0]);
William Lallemand095ba4c2017-06-01 17:38:50 +02003680
William Lallemand7f80eb22017-05-26 18:19:55 +02003681 /* pass through every cli socket, and check if it's bound to
3682 * the current process and if it exposes listeners sockets.
3683 * Caution: the GTUNE_SOCKET_TRANSFER is now set after the fork.
3684 * */
3685
Willy Tarreau4975d142021-03-13 11:00:33 +01003686 if (global.cli_fe) {
William Lallemand7f80eb22017-05-26 18:19:55 +02003687 struct bind_conf *bind_conf;
3688
Willy Tarreau4975d142021-03-13 11:00:33 +01003689 list_for_each_entry(bind_conf, &global.cli_fe->conf.bind, by_fe) {
William Lallemand7f80eb22017-05-26 18:19:55 +02003690 if (bind_conf->level & ACCESS_FD_LISTENERS) {
Willy Tarreau72faef32021-06-15 08:36:30 +02003691 global.tune.options |= GTUNE_SOCKET_TRANSFER;
3692 break;
William Lallemand7f80eb22017-05-26 18:19:55 +02003693 }
3694 }
Willy Tarreauf83d3fe2015-05-01 19:13:41 +02003695 }
3696
William Lallemand2e8fad92018-11-13 16:18:23 +01003697 /*
3698 * This is only done in daemon mode because we might want the
3699 * logs on stdout in mworker mode. If we're NOT in QUIET mode,
3700 * we should now close the 3 first FDs to ensure that we can
3701 * detach from the TTY. We MUST NOT do it in other cases since
3702 * it would have already be done, and 0-2 would have been
3703 * affected to listening sockets
Willy Tarreaubaaee002006-06-26 02:48:02 +02003704 */
William Lallemand2e8fad92018-11-13 16:18:23 +01003705 if ((global.mode & MODE_DAEMON) &&
3706 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003707 /* detach from the tty */
William Lallemande1340412017-12-28 16:09:36 +01003708 stdio_quiet(devnullfd);
Willy Tarreau106cb762008-11-16 07:40:34 +01003709 global.mode &= ~MODE_VERBOSE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003710 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
3711 }
3712 pid = getpid(); /* update child's pid */
William Lallemandbfd8eb52018-07-04 15:31:23 +02003713 if (!(global.mode & MODE_MWORKER)) /* in mworker mode we don't want a new pgid for the children */
3714 setsid();
Willy Tarreau2ff76222007-04-09 19:29:56 +02003715 fork_poller();
Willy Tarreaubaaee002006-06-26 02:48:02 +02003716 }
3717
William Dauchye039f262019-11-17 15:47:15 +01003718 /* try our best to re-enable core dumps depending on system capabilities.
3719 * What is addressed here :
3720 * - remove file size limits
3721 * - remove core size limits
3722 * - mark the process dumpable again if it lost it due to user/group
3723 */
3724 if (global.tune.options & GTUNE_SET_DUMPABLE) {
3725 limit.rlim_cur = limit.rlim_max = RLIM_INFINITY;
3726
3727#if defined(RLIMIT_FSIZE)
3728 if (setrlimit(RLIMIT_FSIZE, &limit) == -1) {
3729 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3730 ha_alert("[%s.main()] Failed to set the raise the maximum "
3731 "file size.\n", argv[0]);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003732 exit(1);
William Dauchye039f262019-11-17 15:47:15 +01003733 }
3734 else
3735 ha_warning("[%s.main()] Failed to set the raise the maximum "
William Dauchya5194602020-03-28 19:29:58 +01003736 "file size.\n", argv[0]);
William Dauchye039f262019-11-17 15:47:15 +01003737 }
3738#endif
3739
3740#if defined(RLIMIT_CORE)
3741 if (setrlimit(RLIMIT_CORE, &limit) == -1) {
3742 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3743 ha_alert("[%s.main()] Failed to set the raise the core "
3744 "dump size.\n", argv[0]);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003745 exit(1);
William Dauchye039f262019-11-17 15:47:15 +01003746 }
3747 else
3748 ha_warning("[%s.main()] Failed to set the raise the core "
William Dauchya5194602020-03-28 19:29:58 +01003749 "dump size.\n", argv[0]);
William Dauchye039f262019-11-17 15:47:15 +01003750 }
3751#endif
3752
3753#if defined(USE_PRCTL)
3754 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1)
3755 ha_warning("[%s.main()] Failed to set the dumpable flag, "
3756 "no core will be dumped.\n", argv[0]);
devnexen@gmail.com21185972021-08-21 09:13:10 +01003757#elif defined(USE_PROCCTL)
Willy Tarreau28345c62021-10-08 15:55:13 +02003758 {
3759 int traceable = PROC_TRACE_CTL_ENABLE;
3760 if (procctl(P_PID, getpid(), PROC_TRACE_CTL, &traceable) == -1)
3761 ha_warning("[%s.main()] Failed to set the traceable flag, "
3762 "no core will be dumped.\n", argv[0]);
3763 }
William Dauchye039f262019-11-17 15:47:15 +01003764#endif
3765 }
3766
Christopher Faulete3a5e352017-10-24 13:53:54 +02003767 global.mode &= ~MODE_STARTING;
Amaury Denoyelle6af81f82021-05-27 15:45:28 +02003768 reset_usermsgs_ctx();
3769
Willy Tarreau2d5d4e02021-09-28 10:36:57 +02003770 /* start threads 2 and above */
Willy Tarreaud10385a2021-10-06 22:22:40 +02003771 setup_extra_threads(&run_thread_poll_loop);
William Lallemand1aab50b2018-06-07 09:46:01 +02003772
Willy Tarreau2d5d4e02021-09-28 10:36:57 +02003773 /* when multithreading we need to let only the thread 0 handle the signals */
William Lallemandd3801c12018-09-11 10:06:23 +02003774 haproxy_unblock_signals();
Willy Tarreau2d5d4e02021-09-28 10:36:57 +02003775
3776 /* Finally, start the poll loop for the first thread */
Willy Tarreau43ab05b2021-09-28 09:43:11 +02003777 run_thread_poll_loop(&ha_thread_info[0]);
Willy Tarreau2d5d4e02021-09-28 10:36:57 +02003778
3779 /* wait for all threads to terminate */
3780 wait_for_threads_completion();
Christopher Faulet1d17c102017-08-29 15:38:48 +02003781
Tim Duesterhus0a3b43d2020-06-14 00:37:42 +02003782 deinit_and_exit(0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003783}
3784
Willy Tarreaubaaee002006-06-26 02:48:02 +02003785/*
3786 * Local variables:
3787 * c-indent-level: 8
3788 * c-basic-offset: 8
3789 * End:
3790 */