blob: 8b984d0ad280fa9cd0bff7c9a3bdc97bfac85cbd [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 Tarreauf6bd0112024-02-15 14:53:26 +01003 * Copyright 2000-2024 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 Tarreaua547a212023-08-29 10:24:26 +0200111#if defined(USE_LINUX_CAP)
112#include <haproxy/linuxcap.h>
113#endif
Willy Tarreau853b2972020-05-27 18:01:47 +0200114#include <haproxy/list.h>
Willy Tarreau213e9902020-06-04 14:58:24 +0200115#include <haproxy/listener.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +0200116#include <haproxy/log.h>
Willy Tarreaub5abe5b2020-06-04 14:07:37 +0200117#include <haproxy/mworker.h>
Willy Tarreau7a00efb2020-06-02 17:02:59 +0200118#include <haproxy/namespace.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +0200119#include <haproxy/net_helper.h>
Willy Tarreau6019fab2020-05-27 16:26:00 +0200120#include <haproxy/openssl-compat.h>
Amaury Denoyelle5907fed2023-03-08 10:37:45 +0100121#include <haproxy/quic_conn.h>
Frédéric Lécaille1d96d6e2022-05-23 16:38:14 +0200122#include <haproxy/quic_tp-t.h>
Willy Tarreau225a90a2020-06-04 15:06:28 +0200123#include <haproxy/pattern.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +0200124#include <haproxy/peers.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200125#include <haproxy/pool.h>
126#include <haproxy/protocol.h>
Willy Tarreaubf3b06b2020-08-26 10:23:40 +0200127#include <haproxy/proto_tcp.h>
Willy Tarreaua264d962020-06-04 22:29:18 +0200128#include <haproxy/proxy.h>
Willy Tarreau7cd8b6e2020-06-02 17:32:26 +0200129#include <haproxy/regex.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200130#include <haproxy/sample.h>
Willy Tarreau1e56f922020-06-04 23:20:13 +0200131#include <haproxy/server.h>
Willy Tarreau48d25b32020-06-04 18:58:52 +0200132#include <haproxy/session.h>
Willy Tarreau3727a8a2020-06-04 17:37:26 +0200133#include <haproxy/signal.h>
Willy Tarreau063d47d2020-08-28 16:29:53 +0200134#include <haproxy/sock.h>
Willy Tarreau25140cc2020-08-28 15:40:33 +0200135#include <haproxy/sock_inet.h>
Willy Tarreau209108d2020-06-04 20:30:20 +0200136#include <haproxy/ssl_sock.h>
Amaury Denoyelleee63d4b2020-10-05 11:49:42 +0200137#include <haproxy/stats-t.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +0200138#include <haproxy/stream.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +0200139#include <haproxy/task.h>
Willy Tarreau3f567e42020-05-28 15:29:19 +0200140#include <haproxy/thread.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200141#include <haproxy/time.h>
142#include <haproxy/tools.h>
143#include <haproxy/uri_auth-t.h>
Willy Tarreaua1718922020-06-04 16:25:31 +0200144#include <haproxy/vars.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200145#include <haproxy/version.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +0200146
Willy Tarreaubaaee002006-06-26 02:48:02 +0200147
Willy Tarreau7b5654f2019-03-29 21:30:17 +0100148/* array of init calls for older platforms */
149DECLARE_INIT_STAGES;
150
Willy Tarreauf4596402021-04-10 16:53:05 +0200151/* create a read_mostly section to hold variables which are accessed a lot
152 * but which almost never change. The purpose is to isolate them in their
153 * own cache lines where they don't risk to be perturbated by write accesses
154 * to neighbor variables. We need to create an empty aligned variable for
155 * this. The fact that the variable is of size zero means that it will be
156 * eliminated at link time if no other variable uses it, but alignment will
157 * be respected.
158 */
159empty_t __read_mostly_align HA_SECTION("read_mostly") ALIGNED(64);
160
Willy Tarreauf0d3b732021-05-06 16:30:32 +0200161#ifdef BUILD_FEATURES
162const char *build_features = BUILD_FEATURES;
163#else
164const char *build_features = "";
165#endif
166
Willy Tarreau477ecd82010-01-03 21:12:30 +0100167/* list of config files */
168static struct list cfg_cfgfiles = LIST_HEAD_INIT(cfg_cfgfiles);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200169int pid; /* current process id */
170
Willy Tarreauef422ce2022-06-28 19:29:29 +0200171static unsigned long stopping_tgroup_mask; /* Thread groups acknowledging stopping */
Willy Tarreauf8ea00e2020-03-12 17:24:53 +0100172
Willy Tarreaubaaee002006-06-26 02:48:02 +0200173/* global options */
174struct global global = {
Cyril Bonté203ec5a2017-03-23 22:44:13 +0100175 .hard_stop_after = TICK_ETERNITY,
Remi Tricot-Le Bretonb5d968d2022-04-08 18:04:18 +0200176 .close_spread_time = TICK_ETERNITY,
177 .close_spread_end = TICK_ETERNITY,
Amaury Denoyelle0f50cb92021-03-26 18:50:33 +0100178 .numa_cpu_mapping = 1,
Willy Tarreau149ab772019-01-26 14:27:06 +0100179 .nbthread = 0,
William Lallemand5f232402012-04-05 18:02:55 +0200180 .req_count = 0,
William Lallemand0f99e342011-10-12 17:50:54 +0200181 .logsrvs = LIST_HEAD_INIT(global.logsrvs),
Willy Tarreau197715a2022-04-25 19:29:10 +0200182 .maxzlibmem = DEFAULT_MAXZLIBMEM * 1024U * 1024U,
William Lallemandd85f9172012-11-09 17:05:39 +0100183 .comp_rate_lim = 0,
Emeric Brun850efd52014-01-29 12:24:34 +0100184 .ssl_server_verify = SSL_SERVER_VERIFY_REQUIRED,
Emeric Bruned760922010-10-22 17:59:25 +0200185 .unix_bind = {
186 .ux = {
187 .uid = -1,
188 .gid = -1,
189 .mode = 0,
190 }
191 },
Willy Tarreau27a674e2009-08-17 07:23:33 +0200192 .tune = {
Willy Tarreau84fe1f42023-04-20 15:40:38 +0200193 .options = GTUNE_LISTENER_MQ_OPT,
Willy Tarreauc77d3642018-12-12 06:19:42 +0100194 .bufsize = (BUFSIZE + 2*sizeof(void *) - 1) & -(2*sizeof(void *)),
Christopher Faulet546c4692020-01-22 14:31:21 +0100195 .maxrewrite = MAXREWRITE,
Willy Tarreaua24adf02014-11-27 01:11:56 +0100196 .reserved_bufs = RESERVED_BUFS,
Willy Tarreauf3045d22015-04-29 16:24:50 +0200197 .pattern_cache = DEFAULT_PAT_LRU_SIZE,
Olivier Houchard88698d92019-04-16 19:07:22 +0200198 .pool_low_ratio = 20,
199 .pool_high_ratio = 25,
Christopher Faulet41ba36f2019-07-19 09:36:45 +0200200 .max_http_hdr = MAX_HTTP_HDR,
Emeric Brunfc32aca2012-09-03 12:10:29 +0200201#ifdef USE_OPENSSL
Emeric Brun46635772012-11-14 11:32:56 +0100202 .sslcachesize = SSLCACHESIZE,
Emeric Brunfc32aca2012-09-03 12:10:29 +0200203#endif
William Lallemandf3747832012-11-09 12:33:10 +0100204 .comp_maxlevel = 1,
Willy Tarreau7e312732014-02-12 16:35:14 +0100205#ifdef DEFAULT_IDLE_TIMER
206 .idle_timer = DEFAULT_IDLE_TIMER,
207#else
208 .idle_timer = 1000, /* 1 second */
209#endif
Willy Tarreau6c011712023-01-06 16:09:58 +0100210 .nb_stk_ctr = MAX_SESS_STKCTR,
Willy Tarreau0e875cf2023-04-23 00:51:59 +0200211 .default_shards = -2, /* by-group */
Amaury Denoyelle97e84c62022-04-19 18:26:55 +0200212#ifdef USE_QUIC
Frédéric Lécailleaee67572022-05-23 18:29:39 +0200213 .quic_backend_max_idle_timeout = QUIC_TP_DFLT_BACK_MAX_IDLE_TIMEOUT,
214 .quic_frontend_max_idle_timeout = QUIC_TP_DFLT_FRONT_MAX_IDLE_TIMEOUT,
215 .quic_frontend_max_streams_bidi = QUIC_TP_DFLT_FRONT_MAX_STREAMS_BIDI,
Frederic Lecaillef1724f42024-02-13 19:38:46 +0100216 .quic_reorder_ratio = QUIC_DFLT_REORDER_RATIO,
Frédéric Lécaille92862102022-05-20 16:29:10 +0200217 .quic_retry_threshold = QUIC_DFLT_RETRY_THRESHOLD,
Amaury Denoyelle24d5b722023-01-31 11:44:50 +0100218 .quic_max_frame_loss = QUIC_DFLT_MAX_FRAME_LOSS,
Amaury Denoyelle97e84c62022-04-19 18:26:55 +0200219 .quic_streams_buf = 30,
220#endif /* USE_QUIC */
Willy Tarreau27a674e2009-08-17 07:23:33 +0200221 },
Emeric Brun76d88952012-10-05 15:47:31 +0200222#ifdef USE_OPENSSL
223#ifdef DEFAULT_MAXSSLCONN
Willy Tarreau403edff2012-09-06 11:58:37 +0200224 .maxsslconn = DEFAULT_MAXSSLCONN,
225#endif
Emeric Brun76d88952012-10-05 15:47:31 +0200226#endif
Amaury Denoyelle1125d052024-05-22 14:21:16 +0200227 /* by default do not protect against clients using privileged port */
228 .clt_privileged_ports = HA_PROTO_ANY,
Willy Tarreaubaaee002006-06-26 02:48:02 +0200229 /* others NULL OK */
230};
231
232/*********************************************************************/
233
234int stopping; /* non zero means stopping in progress */
Cyril Bonté203ec5a2017-03-23 22:44:13 +0100235int killed; /* non zero means a hard-stop is triggered */
Willy Tarreauaf7ad002010-08-31 15:39:26 +0200236int jobs = 0; /* number of active jobs (conns, listeners, active tasks, ...) */
William Lallemanda7199262018-11-16 16:57:20 +0100237int unstoppable_jobs = 0; /* number of active jobs that can't be stopped during a soft stop */
Willy Tarreau199ad242018-11-05 16:31:22 +0100238int active_peers = 0; /* number of active peers (connection attempts and connected) */
Willy Tarreau2d372c22018-11-05 17:12:27 +0100239int connected_peers = 0; /* number of connected peers (verified ones) */
Willy Tarreau392524d2022-02-17 18:10:36 +0100240int arg_mode = 0; /* MODE_DEBUG etc as passed on command line ... */
241char *change_dir = NULL; /* set when -C is passed */
242char *check_condition = NULL; /* check condition passed to -cc */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200243
Ilya Shipitsin46a030c2020-07-05 16:36:08 +0500244/* Here we store information about the pids of the processes we may pause
Willy Tarreaubaaee002006-06-26 02:48:02 +0200245 * or kill. We will send them a signal every 10 ms until we can bind to all
246 * our ports. With 200 retries, that's about 2 seconds.
247 */
248#define MAX_START_RETRIES 200
Willy Tarreaubaaee002006-06-26 02:48:02 +0200249static int *oldpids = NULL;
250static int oldpids_sig; /* use USR1 or TERM */
251
Olivier Houchardf73629d2017-04-05 22:33:04 +0200252/* Path to the unix socket we use to retrieve listener sockets from the old process */
253static const char *old_unixsocket;
254
William Lallemandcb11fd22017-06-01 17:38:52 +0200255int atexit_flag = 0;
256
Willy Tarreaubb545b42010-08-25 12:58:59 +0200257int nb_oldpids = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200258const int zero = 0;
259const int one = 1;
Alexandre Cassen87ea5482007-10-11 20:48:58 +0200260const struct linger nolinger = { .l_onoff = 1, .l_linger = 0 };
Willy Tarreaubaaee002006-06-26 02:48:02 +0200261
Willy Tarreau1d21e0a2010-03-12 21:58:54 +0100262char hostname[MAX_HOSTNAME_LEN];
Dragan Dosen4f014152020-06-18 16:56:47 +0200263char *localpeer = NULL;
Willy Tarreau76871a42022-03-08 16:01:40 +0100264static char *kwd_dump = NULL; // list of keyword dumps to produce
Willy Tarreaubaaee002006-06-26 02:48:02 +0200265
William Lallemand00417412020-06-05 14:08:41 +0200266static char **old_argv = NULL; /* previous argv but cleaned up */
William Lallemand73b85e72017-06-01 17:38:51 +0200267
William Lallemandbc193052018-09-11 10:06:26 +0200268struct list proc_list = LIST_HEAD_INIT(proc_list);
269
270int master = 0; /* 1 if in master, 0 if in child */
Willy Tarreaubf696402019-03-01 10:09:28 +0100271unsigned int rlim_fd_cur_at_boot = 0;
272unsigned int rlim_fd_max_at_boot = 0;
William Lallemandbc193052018-09-11 10:06:26 +0200273
Willy Tarreau6c3a6812020-03-06 18:57:15 +0100274/* per-boot randomness */
275unsigned char boot_seed[20]; /* per-boot random seed (160 bits initially) */
276
Willy Tarreau43ab05b2021-09-28 09:43:11 +0200277/* takes the thread config in argument or NULL for any thread */
William Lallemandb3f2be32018-09-11 10:06:18 +0200278static void *run_thread_poll_loop(void *data);
279
Willy Tarreauff055502014-04-28 22:27:06 +0200280/* bitfield of a few warnings to emit just once (WARN_*) */
281unsigned int warned = 0;
282
Amaury Denoyelle484454d2021-05-05 16:18:45 +0200283/* set if experimental features have been used for the current process */
Willy Tarreauedd42682022-02-25 10:10:00 +0100284unsigned int tainted = 0;
Amaury Denoyelle484454d2021-05-05 16:18:45 +0200285
Amaury Denoyelled2e53cd2021-05-06 16:21:39 +0200286unsigned int experimental_directives_allowed = 0;
287
288int check_kw_experimental(struct cfg_keyword *kw, const char *file, int linenum,
289 char **errmsg)
290{
291 if (kw->flags & KWF_EXPERIMENTAL) {
292 if (!experimental_directives_allowed) {
Amaury Denoyelle86c1d0f2021-05-07 15:07:21 +0200293 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 +0200294 file, linenum, kw->kw);
295 return 1;
296 }
297 mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
298 }
299
300 return 0;
301}
302
William Lallemande7361152018-10-26 14:47:36 +0200303/* master CLI configuration (-S flag) */
304struct list mworker_cli_conf = LIST_HEAD_INIT(mworker_cli_conf);
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100305
306/* These are strings to be reported in the output of "haproxy -vv". They may
307 * either be constants (in which case must_free must be zero) or dynamically
308 * allocated strings to pass to free() on exit, and in this case must_free
309 * must be non-zero.
310 */
311struct list build_opts_list = LIST_HEAD_INIT(build_opts_list);
312struct build_opts_str {
313 struct list list;
314 const char *str;
315 int must_free;
316};
317
Willy Tarreaubaaee002006-06-26 02:48:02 +0200318/*********************************************************************/
319/* general purpose functions ***************************************/
320/*********************************************************************/
321
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100322/* used to register some build option strings at boot. Set must_free to
323 * non-zero if the string must be freed upon exit.
324 */
325void hap_register_build_opts(const char *str, int must_free)
326{
327 struct build_opts_str *b;
328
329 b = calloc(1, sizeof(*b));
330 if (!b) {
331 fprintf(stderr, "out of memory\n");
332 exit(1);
333 }
334 b->str = str;
335 b->must_free = must_free;
Willy Tarreau2b718102021-04-21 07:32:39 +0200336 LIST_APPEND(&build_opts_list, &b->list);
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100337}
338
Willy Tarreaua43dfda2021-05-06 07:43:35 +0200339#define VERSION_MAX_ELTS 7
340
341/* This function splits an haproxy version string into an array of integers.
342 * The syntax of the supported version string is the following:
343 *
344 * <a>[.<b>[.<c>[.<d>]]][-{dev,pre,rc}<f>][-*][-<g>]
345 *
346 * This validates for example:
347 * 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
348 * 2.4-dev18-f6818d-20
349 *
350 * The result is set in a array of <VERSION_MAX_ELTS> elements. Each letter has
351 * one fixed place in the array. The tags take a numeric value called <e> which
352 * defaults to 3. "dev" is 1, "rc" and "pre" are 2. Numbers not encountered are
353 * considered as zero (henxe 1.5 and 1.5.0 are the same).
354 *
355 * The resulting values are:
356 * 1.2.1-pre2 1, 2, 1, 0, 2, 2, 0
357 * 1.2.1 1, 2, 1, 0, 3, 0, 0
358 * 1.2.10.1 1, 2, 10, 1, 3, 0, 0
359 * 1.3.16-rc1 1, 3, 16, 0, 2, 1, 0
360 * 1.4-dev3 1, 4, 0, 0, 1, 3, 0
361 * 1.5-dev18 1, 5, 0, 0, 1, 18, 0
362 * 1.5-dev18-43 1, 5, 0, 0, 1, 18, 43
363 * 2.4-dev18-f6818d-20 2, 4, 0, 0, 1, 18, 20
364 *
365 * The function returns non-zero if the conversion succeeded, or zero if it
366 * failed.
367 */
368int split_version(const char *version, unsigned int *value)
369{
370 const char *p, *s;
371 char *error;
372 int nelts;
373
374 /* Initialize array with zeroes */
375 for (nelts = 0; nelts < VERSION_MAX_ELTS; nelts++)
376 value[nelts] = 0;
377 value[4] = 3;
378
379 p = version;
380
381 /* If the version number is empty, return false */
382 if (*p == '\0')
383 return 0;
384
385 /* Convert first number <a> */
386 value[0] = strtol(p, &error, 10);
387 p = error + 1;
388 if (*error == '\0')
389 return 1;
390 if (*error == '-')
391 goto split_version_tag;
392 if (*error != '.')
393 return 0;
394
395 /* Convert first number <b> */
396 value[1] = strtol(p, &error, 10);
397 p = error + 1;
398 if (*error == '\0')
399 return 1;
400 if (*error == '-')
401 goto split_version_tag;
402 if (*error != '.')
403 return 0;
404
405 /* Convert first number <c> */
406 value[2] = strtol(p, &error, 10);
407 p = error + 1;
408 if (*error == '\0')
409 return 1;
410 if (*error == '-')
411 goto split_version_tag;
412 if (*error != '.')
413 return 0;
414
415 /* Convert first number <d> */
416 value[3] = strtol(p, &error, 10);
417 p = error + 1;
418 if (*error == '\0')
419 return 1;
420 if (*error != '-')
421 return 0;
422
423 split_version_tag:
424 /* Check for commit number */
425 if (*p >= '0' && *p <= '9')
426 goto split_version_commit;
427
428 /* Read tag */
429 if (strncmp(p, "dev", 3) == 0) { value[4] = 1; p += 3; }
430 else if (strncmp(p, "rc", 2) == 0) { value[4] = 2; p += 2; }
431 else if (strncmp(p, "pre", 3) == 0) { value[4] = 2; p += 3; }
432 else
433 goto split_version_commit;
434
435 /* Convert tag number */
436 value[5] = strtol(p, &error, 10);
437 p = error + 1;
438 if (*error == '\0')
439 return 1;
440 if (*error != '-')
441 return 0;
442
443 split_version_commit:
444 /* Search the last "-" */
445 s = strrchr(p, '-');
446 if (s) {
447 s++;
448 if (*s == '\0')
449 return 0;
450 value[6] = strtol(s, &error, 10);
451 if (*error != '\0')
452 value[6] = 0;
453 return 1;
454 }
455
456 /* convert the version */
457 value[6] = strtol(p, &error, 10);
458 if (*error != '\0')
459 value[6] = 0;
460
461 return 1;
462}
463
464/* This function compares the current haproxy version with an arbitrary version
465 * string. It returns:
466 * -1 : the version in argument is older than the current haproxy version
467 * 0 : the version in argument is the same as the current haproxy version
468 * 1 : the version in argument is newer than the current haproxy version
469 *
470 * Or some errors:
471 * -2 : the current haproxy version is not parsable
472 * -3 : the version in argument is not parsable
473 */
474int compare_current_version(const char *version)
475{
476 unsigned int loc[VERSION_MAX_ELTS];
477 unsigned int mod[VERSION_MAX_ELTS];
478 int i;
479
480 /* split versions */
481 if (!split_version(haproxy_version, loc))
482 return -2;
483 if (!split_version(version, mod))
484 return -3;
485
486 /* compare versions */
487 for (i = 0; i < VERSION_MAX_ELTS; i++) {
488 if (mod[i] < loc[i])
489 return -1;
490 else if (mod[i] > loc[i])
491 return 1;
492 }
493 return 0;
494}
495
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100496static void display_version()
Willy Tarreaubaaee002006-06-26 02:48:02 +0200497{
Tim Duesterhusdfad6a42020-04-18 16:02:47 +0200498 struct utsname utsname;
499
Willy Tarreaua5357cd2021-05-09 06:14:25 +0200500 printf("HAProxy version %s %s - https://haproxy.org/\n"
Willy Tarreau08dd2022019-11-21 18:07:30 +0100501 PRODUCT_STATUS "\n", haproxy_version, haproxy_date);
Willy Tarreau47479eb2019-11-21 18:48:20 +0100502
503 if (strlen(PRODUCT_URL_BUGS) > 0) {
504 char base_version[20];
505 int dots = 0;
506 char *del;
507
508 /* only retrieve the base version without distro-specific extensions */
509 for (del = haproxy_version; *del; del++) {
510 if (*del == '.')
511 dots++;
512 else if (*del < '0' || *del > '9')
513 break;
514 }
515
516 strlcpy2(base_version, haproxy_version, del - haproxy_version + 1);
517 if (dots < 2)
518 printf("Known bugs: https://github.com/haproxy/haproxy/issues?q=is:issue+is:open\n");
519 else
520 printf("Known bugs: " PRODUCT_URL_BUGS "\n", base_version);
521 }
Tim Duesterhusdfad6a42020-04-18 16:02:47 +0200522
523 if (uname(&utsname) == 0) {
524 printf("Running on: %s %s %s %s\n", utsname.sysname, utsname.release, utsname.version, utsname.machine);
525 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200526}
527
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100528static void display_build_opts()
Willy Tarreau7b066db2007-12-02 11:28:59 +0100529{
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100530 struct build_opts_str *item;
531
Willy Tarreau7b066db2007-12-02 11:28:59 +0100532 printf("Build options :"
533#ifdef BUILD_TARGET
Willy Tarreau9f2b7302008-01-02 20:48:34 +0100534 "\n TARGET = " BUILD_TARGET
Willy Tarreau7b066db2007-12-02 11:28:59 +0100535#endif
536#ifdef BUILD_CPU
Willy Tarreau9f2b7302008-01-02 20:48:34 +0100537 "\n CPU = " BUILD_CPU
Willy Tarreau7b066db2007-12-02 11:28:59 +0100538#endif
539#ifdef BUILD_CC
Willy Tarreau9f2b7302008-01-02 20:48:34 +0100540 "\n CC = " BUILD_CC
541#endif
542#ifdef BUILD_CFLAGS
543 "\n CFLAGS = " BUILD_CFLAGS
Willy Tarreau7b066db2007-12-02 11:28:59 +0100544#endif
Willy Tarreau9f2b7302008-01-02 20:48:34 +0100545#ifdef BUILD_OPTIONS
546 "\n OPTIONS = " BUILD_OPTIONS
Willy Tarreau7b066db2007-12-02 11:28:59 +0100547#endif
Tim Duesterhusc8d19702020-11-21 18:07:59 +0100548#ifdef BUILD_DEBUG
549 "\n DEBUG = " BUILD_DEBUG
550#endif
Willy Tarreau7728ed32019-03-27 13:20:08 +0100551#ifdef BUILD_FEATURES
552 "\n\nFeature list : " BUILD_FEATURES
553#endif
Willy Tarreau27a674e2009-08-17 07:23:33 +0200554 "\n\nDefault settings :"
Willy Tarreauca783d42019-03-13 10:03:07 +0100555 "\n bufsize = %d, maxrewrite = %d, maxpollevents = %d"
Willy Tarreau27a674e2009-08-17 07:23:33 +0200556 "\n\n",
Willy Tarreauca783d42019-03-13 10:03:07 +0100557 BUFSIZE, MAXREWRITE, MAX_POLL_EVENTS);
Willy Tarreaube5b6852009-10-03 18:57:08 +0200558
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100559 list_for_each_entry(item, &build_opts_list, list) {
560 puts(item->str);
561 }
562
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100563 putchar('\n');
564
Willy Tarreaube5b6852009-10-03 18:57:08 +0200565 list_pollers(stdout);
566 putchar('\n');
Christopher Faulet98d9fe22018-04-10 14:37:32 +0200567 list_mux_proto(stdout);
568 putchar('\n');
Willy Tarreau679bba12019-03-19 08:08:10 +0100569 list_services(stdout);
570 putchar('\n');
Christopher Fauletb3f4e142016-03-07 12:46:38 +0100571 list_filters(stdout);
572 putchar('\n');
Willy Tarreau7b066db2007-12-02 11:28:59 +0100573}
574
Willy Tarreaubaaee002006-06-26 02:48:02 +0200575/*
576 * This function prints the command line usage and exits
577 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100578static void usage(char *name)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200579{
580 display_version();
581 fprintf(stderr,
Maxime de Roucy379d9c72016-05-13 23:52:56 +0200582 "Usage : %s [-f <cfgfile|cfgdir>]* [ -vdV"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200583 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
Willy Tarreaua088d312015-10-08 11:58:48 +0200584 " [ -p <pidfile> ] [ -m <max megs> ] [ -C <dir> ] [-- <cfgfile>*]\n"
Willy Tarreau7b066db2007-12-02 11:28:59 +0100585 " -v displays version ; -vv shows known build options.\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200586 " -d enters debug mode ; -db only disables background mode.\n"
Willy Tarreauf4b79c42022-02-23 15:20:53 +0100587 " -dM[<byte>,help,...] debug memory (default: poison with <byte>/0x50)\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200588 " -V enters verbose mode (disables quiet mode)\n"
Willy Tarreau576132e2011-09-10 19:26:56 +0200589 " -D goes daemon ; -C changes to <dir> before loading files.\n"
William Lallemand095ba4c2017-06-01 17:38:50 +0200590 " -W master-worker mode.\n"
Tim Duesterhusd6942c82017-11-20 15:58:35 +0100591#if defined(USE_SYSTEMD)
592 " -Ws master-worker mode with systemd notify support.\n"
593#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +0200594 " -q quiet mode : don't display messages\n"
Willy Tarreau5d01a632009-06-22 16:02:30 +0200595 " -c check mode : only check config files and exit\n"
Maximilian Maderfc0cceb2021-06-06 00:50:22 +0200596 " -cc check condition : evaluate a condition and exit\n"
Willy Tarreauca783d42019-03-13 10:03:07 +0100597 " -n sets the maximum total # of connections (uses ulimit -n)\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200598 " -m limits the usable amount of memory (in MB)\n"
599 " -N sets the default, per-proxy maximum # of connections (%d)\n"
Emeric Brun2b920a12010-09-23 18:30:22 +0200600 " -L set local peer name (default to hostname)\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200601 " -p writes pids of all children to this file\n"
Erwan Le Goasf30c5d72022-09-29 10:34:04 +0200602 " -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 +0200603#if defined(USE_EPOLL)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200604 " -de disables epoll() usage even when available\n"
605#endif
Willy Tarreaue5733232019-05-22 19:24:06 +0200606#if defined(USE_KQUEUE)
Willy Tarreau1e63130a2007-04-09 12:03:06 +0200607 " -dk disables kqueue() usage even when available\n"
608#endif
Willy Tarreaue5733232019-05-22 19:24:06 +0200609#if defined(USE_EVPORTS)
Emmanuel Hocdet0ba4f482019-04-08 16:53:32 +0000610 " -dv disables event ports usage even when available\n"
611#endif
Willy Tarreaue5733232019-05-22 19:24:06 +0200612#if defined(USE_POLL)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200613 " -dp disables poll() usage even when available\n"
614#endif
Willy Tarreaue5733232019-05-22 19:24:06 +0200615#if defined(USE_LINUX_SPLICE)
Willy Tarreau3ab68cf2009-01-25 16:03:28 +0100616 " -dS disables splice usage (broken on old kernels)\n"
617#endif
Nenad Merdanovic88afe032014-04-14 15:56:58 +0200618#if defined(USE_GETADDRINFO)
619 " -dG disables getaddrinfo() usage\n"
620#endif
Lukas Tribusa0bcbdc2016-09-12 21:42:20 +0000621#if defined(SO_REUSEPORT)
622 " -dR disables SO_REUSEPORT usage\n"
623#endif
Willy Tarreau654726d2021-12-28 15:43:11 +0100624#if defined(HA_HAVE_DUMP_LIBS)
625 " -dL dumps loaded object files after config checks\n"
626#endif
Willy Tarreau76871a42022-03-08 16:01:40 +0100627 " -dK{class[,...]} dump registered keywords (use 'help' for list)\n"
Willy Tarreau3eed10e2016-11-07 21:03:16 +0100628 " -dr ignores server address resolution failures\n"
Emeric Brun850efd52014-01-29 12:24:34 +0100629 " -dV disables SSL verify on servers side\n"
Willy Tarreau3eb10b82020-04-15 16:42:39 +0200630 " -dW fails if any warning is emitted\n"
Amaury Denoyelle7b01a8d2021-03-29 10:29:07 +0200631 " -dD diagnostic mode : warn about suspicious configuration statements\n"
Christopher Faulet678a4ce2023-02-14 16:12:54 +0100632 " -dF disable fast-forward\n"
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +0200633 " -sf/-st [pid ]* finishes/terminates old pids.\n"
Olivier Houchardf73629d2017-04-05 22:33:04 +0200634 " -x <unix_socket> get listening sockets from a unix socket\n"
William Lallemand63329e32019-06-13 17:03:37 +0200635 " -S <bind>[,<bind options>...] new master CLI\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200636 "\n",
Willy Tarreauca783d42019-03-13 10:03:07 +0100637 name, cfg_maxpconn);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200638 exit(1);
639}
640
641
642
643/*********************************************************************/
644/* more specific functions ***************************************/
645/*********************************************************************/
646
William Lallemand73b85e72017-06-01 17:38:51 +0200647/* sends the signal <sig> to all pids found in <oldpids>. Returns the number of
648 * pids the signal was correctly delivered to.
649 */
William Lallemande25473c2019-04-01 11:29:56 +0200650int tell_old_pids(int sig)
William Lallemand73b85e72017-06-01 17:38:51 +0200651{
652 int p;
653 int ret = 0;
654 for (p = 0; p < nb_oldpids; p++)
655 if (kill(oldpids[p], sig) == 0)
656 ret++;
657 return ret;
658}
659
William Lallemand75ea0a02017-11-15 19:02:58 +0100660/*
William Lallemand73b85e72017-06-01 17:38:51 +0200661 * remove a pid forom the olpid array and decrease nb_oldpids
662 * return 1 pid was found otherwise return 0
663 */
664
665int delete_oldpid(int pid)
666{
667 int i;
668
669 for (i = 0; i < nb_oldpids; i++) {
670 if (oldpids[i] == pid) {
671 oldpids[i] = oldpids[nb_oldpids - 1];
672 oldpids[nb_oldpids - 1] = 0;
673 nb_oldpids--;
674 return 1;
675 }
676 }
677 return 0;
678}
679
William Lallemand85b0bd92017-06-01 17:38:53 +0200680
William Lallemand73b85e72017-06-01 17:38:51 +0200681/*
682 * When called, this function reexec haproxy with -sf followed by current
Joseph Herlant03420902018-11-15 10:41:50 -0800683 * children PIDs and possibly old children PIDs if they didn't leave yet.
William Lallemand73b85e72017-06-01 17:38:51 +0200684 */
William Lallemandfab0fdc2021-11-09 18:01:22 +0100685static void mworker_reexec()
William Lallemand73b85e72017-06-01 17:38:51 +0200686{
William Lallemand00417412020-06-05 14:08:41 +0200687 char **next_argv = NULL;
688 int old_argc = 0; /* previous number of argument */
William Lallemand73b85e72017-06-01 17:38:51 +0200689 int next_argc = 0;
William Lallemand00417412020-06-05 14:08:41 +0200690 int i = 0;
William Lallemand73b85e72017-06-01 17:38:51 +0200691 char *msg = NULL;
Willy Tarreau8dca1952019-03-01 10:21:55 +0100692 struct rlimit limit;
William Lallemand2be557f2021-11-24 18:45:37 +0100693 struct mworker_proc *current_child = NULL;
William Lallemandb6760952024-04-26 15:08:31 +0200694 int x_off = 0; /* disable -x by putting -x /dev/null */
William Lallemand73b85e72017-06-01 17:38:51 +0200695
696 mworker_block_signals();
William Lallemand73b85e72017-06-01 17:38:51 +0200697 setenv("HAPROXY_MWORKER_REEXEC", "1", 1);
698
William Lallemand55a921c2022-01-28 21:17:30 +0100699 mworker_cleanup_proc();
William Lallemandbc193052018-09-11 10:06:26 +0200700 mworker_proc_list_to_env(); /* put the children description in the env */
701
William Lallemandc4810b82021-11-18 10:51:30 +0100702 /* ensure that we close correctly every listeners before reexecuting */
703 mworker_cleanlisteners();
704
William Lallemand7c756a82018-11-26 11:53:40 +0100705 /* during the reload we must ensure that every FDs that can't be
706 * reuse (ie those that are not referenced in the proc_list)
707 * are closed or they will leak. */
708
709 /* close the listeners FD */
710 mworker_cli_proxy_stop();
William Lallemand16866672019-06-24 17:40:48 +0200711
William Lallemand67e371e2021-11-25 10:03:44 +0100712 if (fdtab)
713 deinit_pollers();
William Lallemandefd95472021-11-26 14:43:57 +0100714
Ilya Shipitsin98a9e1b2021-02-19 23:42:53 +0500715#ifdef HAVE_SSL_RAND_KEEP_RANDOM_DEVICES_OPEN
William Lallemand5fdb5b32019-10-15 14:04:08 +0200716 /* close random device FDs */
717 RAND_keep_random_devices_open(0);
Rob Allen56996da2019-05-03 09:11:32 +0100718#endif
William Lallemand7c756a82018-11-26 11:53:40 +0100719
Willy Tarreau8dca1952019-03-01 10:21:55 +0100720 /* restore the initial FD limits */
721 limit.rlim_cur = rlim_fd_cur_at_boot;
722 limit.rlim_max = rlim_fd_max_at_boot;
Willy Tarreauc06557c2022-09-22 16:12:08 +0200723 if (raise_rlim_nofile(&limit, &limit) != 0) {
Willy Tarreau8dca1952019-03-01 10:21:55 +0100724 ha_warning("Failed to restore initial FD limits (cur=%u max=%u), using cur=%u max=%u\n",
725 rlim_fd_cur_at_boot, rlim_fd_max_at_boot,
726 (unsigned int)limit.rlim_cur, (unsigned int)limit.rlim_max);
727 }
728
William Lallemand73b85e72017-06-01 17:38:51 +0200729 /* compute length */
William Lallemand00417412020-06-05 14:08:41 +0200730 while (old_argv[old_argc])
731 old_argc++;
William Lallemand73b85e72017-06-01 17:38:51 +0200732
William Lallemand85b0bd92017-06-01 17:38:53 +0200733 /* 1 for haproxy -sf, 2 for -x /socket */
William Lallemandaba7f8b2021-04-21 16:55:34 +0200734 next_argv = calloc(old_argc + 1 + 2 + mworker_child_nb() + 1,
Tim Duesterhuse52b6e52020-09-12 20:26:43 +0200735 sizeof(*next_argv));
William Lallemand73b85e72017-06-01 17:38:51 +0200736 if (next_argv == NULL)
737 goto alloc_error;
738
William Lallemand00417412020-06-05 14:08:41 +0200739 /* copy the program name */
740 next_argv[next_argc++] = old_argv[0];
741
William Lallemandb6760952024-04-26 15:08:31 +0200742 /* we need to reintroduce /dev/null everytime */
743 if (old_unixsocket && strcmp(old_unixsocket, "/dev/null") == 0)
744 x_off = 1;
745
William Lallemand00417412020-06-05 14:08:41 +0200746 /* insert the new options just after argv[0] in case we have a -- */
747
William Lallemandbefab9e2021-11-25 00:49:19 +0100748 if (getenv("HAPROXY_MWORKER_WAIT_ONLY") == NULL) {
749 /* add -sf <PID>* to argv */
750 if (mworker_child_nb() > 0) {
751 struct mworker_proc *child;
William Lallemand3f128872019-04-01 11:29:59 +0200752
William Lallemandbefab9e2021-11-25 00:49:19 +0100753 next_argv[next_argc++] = "-sf";
William Lallemand3f128872019-04-01 11:29:59 +0200754
William Lallemandbefab9e2021-11-25 00:49:19 +0100755 list_for_each_entry(child, &proc_list, list) {
756 if (!(child->options & PROC_O_LEAVING) && (child->options & PROC_O_TYPE_WORKER))
757 current_child = child;
William Lallemand2be557f2021-11-24 18:45:37 +0100758
William Lallemandbefab9e2021-11-25 00:49:19 +0100759 if (!(child->options & (PROC_O_TYPE_WORKER|PROC_O_TYPE_PROG)) || child->pid <= -1)
760 continue;
761 if ((next_argv[next_argc++] = memprintf(&msg, "%d", child->pid)) == NULL)
762 goto alloc_error;
763 msg = NULL;
764 }
William Lallemand73b85e72017-06-01 17:38:51 +0200765 }
William Lallemandb6760952024-04-26 15:08:31 +0200766 if (!x_off && current_child) {
William Lallemand2be557f2021-11-24 18:45:37 +0100767 /* add the -x option with the socketpair of the current worker */
768 next_argv[next_argc++] = "-x";
769 if ((next_argv[next_argc++] = memprintf(&msg, "sockpair@%d", current_child->ipc_fd[0])) == NULL)
770 goto alloc_error;
771 msg = NULL;
772 }
William Lallemand85b0bd92017-06-01 17:38:53 +0200773 }
774
William Lallemandb6760952024-04-26 15:08:31 +0200775 if (x_off) {
776 /* if the cmdline contained a -x /dev/null, continue to use it */
777 next_argv[next_argc++] = "-x";
778 next_argv[next_argc++] = "/dev/null";
779 }
780
William Lallemand00417412020-06-05 14:08:41 +0200781 /* copy the previous options */
782 for (i = 1; i < old_argc; i++)
783 next_argv[next_argc++] = old_argv[i];
784
Willy Tarreaue0d86e22019-08-26 10:37:39 +0200785 signal(SIGPROF, SIG_IGN);
Tim Duesterhus0436ab72017-11-12 17:39:18 +0100786 execvp(next_argv[0], next_argv);
Christopher Faulet767a84b2017-11-24 16:50:31 +0100787 ha_warning("Failed to reexecute the master process [%d]: %s\n", pid, strerror(errno));
Willy Tarreau61cfdf42021-02-20 10:46:51 +0100788 ha_free(&next_argv);
William Lallemand722d4ca2017-11-15 19:02:55 +0100789 return;
790
William Lallemand73b85e72017-06-01 17:38:51 +0200791alloc_error:
Willy Tarreau61cfdf42021-02-20 10:46:51 +0100792 ha_free(&next_argv);
Joseph Herlant07a08342018-11-15 10:43:05 -0800793 ha_warning("Failed to reexecute the master process [%d]: Cannot allocate memory\n", pid);
William Lallemand73b85e72017-06-01 17:38:51 +0200794 return;
795}
796
William Lallemandfab0fdc2021-11-09 18:01:22 +0100797/* reexec haproxy in waitmode */
798static void mworker_reexec_waitmode()
799{
800 setenv("HAPROXY_MWORKER_WAIT_ONLY", "1", 1);
801 mworker_reexec();
802}
803
804/* reload haproxy and emit a warning */
805void mworker_reload()
806{
William Lallemandad221f42021-11-09 18:43:59 +0100807 struct mworker_proc *child;
William Lallemandefd95472021-11-26 14:43:57 +0100808 struct per_thread_deinit_fct *ptdf;
William Lallemandad221f42021-11-09 18:43:59 +0100809
William Lallemand836bda22021-11-09 18:16:47 +0100810 ha_notice("Reloading HAProxy\n");
William Lallemandad221f42021-11-09 18:43:59 +0100811
William Lallemandefd95472021-11-26 14:43:57 +0100812 /* close the poller FD and the thread waker pipe FD */
813 list_for_each_entry(ptdf, &per_thread_deinit_list, list)
814 ptdf->fct();
815
William Lallemandad221f42021-11-09 18:43:59 +0100816 /* increment the number of reloads */
817 list_for_each_entry(child, &proc_list, list) {
818 child->reloads++;
819 }
820
William Lallemanda46a99e2022-07-07 14:00:36 +0200821#if defined(USE_SYSTEMD)
822 if (global.tune.options & GTUNE_USE_SYSTEMD)
823 sd_notify(0, "RELOADING=1\nSTATUS=Reloading Configuration.\n");
824#endif
William Lallemandfab0fdc2021-11-09 18:01:22 +0100825 mworker_reexec();
826}
827
William Lallemandb3f2be32018-09-11 10:06:18 +0200828static void mworker_loop()
829{
830
Willy Tarreaud83b6c12019-04-18 11:31:36 +0200831 /* Busy polling makes no sense in the master :-) */
832 global.tune.options &= ~GTUNE_BUSY_POLLING;
William Lallemandb3f2be32018-09-11 10:06:18 +0200833
William Lallemandbc193052018-09-11 10:06:26 +0200834
Willy Tarreaud26c9f92019-12-11 14:24:07 +0100835 signal_unregister(SIGTTIN);
836 signal_unregister(SIGTTOU);
William Lallemand0564d412018-11-20 17:36:53 +0100837 signal_unregister(SIGUSR1);
838 signal_unregister(SIGHUP);
839 signal_unregister(SIGQUIT);
840
William Lallemandb3f2be32018-09-11 10:06:18 +0200841 signal_register_fct(SIGTERM, mworker_catch_sigterm, SIGTERM);
842 signal_register_fct(SIGUSR1, mworker_catch_sigterm, SIGUSR1);
Willy Tarreaud26c9f92019-12-11 14:24:07 +0100843 signal_register_fct(SIGTTIN, mworker_broadcast_signal, SIGTTIN);
844 signal_register_fct(SIGTTOU, mworker_broadcast_signal, SIGTTOU);
William Lallemandb3f2be32018-09-11 10:06:18 +0200845 signal_register_fct(SIGINT, mworker_catch_sigterm, SIGINT);
846 signal_register_fct(SIGHUP, mworker_catch_sighup, SIGHUP);
847 signal_register_fct(SIGUSR2, mworker_catch_sighup, SIGUSR2);
848 signal_register_fct(SIGCHLD, mworker_catch_sigchld, SIGCHLD);
849
850 mworker_unblock_signals();
William Lallemand27f3fa52018-12-06 14:05:20 +0100851 mworker_cleantasks();
William Lallemandb3f2be32018-09-11 10:06:18 +0200852
William Lallemandbc193052018-09-11 10:06:26 +0200853 mworker_catch_sigchld(NULL); /* ensure we clean the children in case
854 some SIGCHLD were lost */
855
William Lallemandb3f2be32018-09-11 10:06:18 +0200856 jobs++; /* this is the "master" job, we want to take care of the
857 signals even if there is no listener so the poll loop don't
858 leave */
859
860 fork_poller();
Willy Tarreau43ab05b2021-09-28 09:43:11 +0200861 run_thread_poll_loop(NULL);
William Lallemandb3f2be32018-09-11 10:06:18 +0200862}
William Lallemandcb11fd22017-06-01 17:38:52 +0200863
864/*
865 * Reexec the process in failure mode, instead of exiting
866 */
867void reexec_on_failure()
868{
William Lallemand68836742021-11-10 10:49:06 +0100869 struct mworker_proc *child;
870
William Lallemandcb11fd22017-06-01 17:38:52 +0200871 if (!atexit_flag)
872 return;
William Lallemand68836742021-11-10 10:49:06 +0100873
874 /* get the info of the children in the env */
875 if (mworker_env_to_proc_list() < 0) {
876 exit(EXIT_FAILURE);
877 }
878
879 /* increment the number of failed reloads */
880 list_for_each_entry(child, &proc_list, list) {
881 child->failedreloads++;
882 }
883
Willy Tarreaue08acae2022-01-28 18:40:06 +0100884 /* do not keep unused FDs retrieved from the previous process */
885 sock_drop_unused_old_sockets();
886
William Lallemandfab0fdc2021-11-09 18:01:22 +0100887 usermsgs_clr(NULL);
William Lallemand68192b22022-09-24 15:44:42 +0200888 setenv("HAPROXY_LOAD_SUCCESS", "0", 1);
William Lallemand836bda22021-11-09 18:16:47 +0100889 ha_warning("Loading failure!\n");
William Lallemanda46a99e2022-07-07 14:00:36 +0200890#if defined(USE_SYSTEMD)
891 /* the sd_notify API is not able to send a reload failure signal. So
892 * the READY=1 signal still need to be sent */
893 if (global.tune.options & GTUNE_USE_SYSTEMD)
894 sd_notify(0, "READY=1\nSTATUS=Reload failed!\n");
895#endif
896
William Lallemandfab0fdc2021-11-09 18:01:22 +0100897 mworker_reexec_waitmode();
William Lallemandcb11fd22017-06-01 17:38:52 +0200898}
William Lallemand73b85e72017-06-01 17:38:51 +0200899
William Lallemand40db4ae2022-12-07 15:03:55 +0100900/*
901 * Exit with an error message upon a wait-mode failure.
902 */
903void exit_on_waitmode_failure()
904{
905 if (!atexit_flag)
906 return;
907
908 ha_alert("Non-recoverable mworker wait-mode error, exiting.\n");
909}
910
William Lallemand73b85e72017-06-01 17:38:51 +0200911
912/*
Willy Tarreaud0807c32010-08-27 18:26:11 +0200913 * upon SIGUSR1, let's have a soft stop. Note that soft_stop() broadcasts
914 * a signal zero to all subscribers. This means that it's as easy as
915 * subscribing to signal 0 to get informed about an imminent shutdown.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200916 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100917static void sig_soft_stop(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200918{
919 soft_stop();
Willy Tarreau24f4efa2010-08-27 17:56:48 +0200920 signal_unregister_handler(sh);
Willy Tarreaubafbe012017-11-24 17:34:44 +0100921 pool_gc(NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200922}
923
924/*
925 * upon SIGTTOU, we pause everything
926 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100927static void sig_pause(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200928{
Willy Tarreau775e0012020-09-24 16:36:26 +0200929 if (protocol_pause_all() & ERR_FATAL) {
930 const char *msg = "Some proxies refused to pause, performing soft stop now.\n";
Willy Tarreau0a002df2020-10-09 19:26:27 +0200931 ha_warning("%s", msg);
932 send_log(NULL, LOG_WARNING, "%s", msg);
Willy Tarreau775e0012020-09-24 16:36:26 +0200933 soft_stop();
934 }
Willy Tarreaubafbe012017-11-24 17:34:44 +0100935 pool_gc(NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200936}
937
938/*
939 * upon SIGTTIN, let's have a soft stop.
940 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100941static void sig_listen(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200942{
Willy Tarreau775e0012020-09-24 16:36:26 +0200943 if (protocol_resume_all() & ERR_FATAL) {
944 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 +0200945 ha_warning("%s", msg);
946 send_log(NULL, LOG_WARNING, "%s", msg);
Willy Tarreau775e0012020-09-24 16:36:26 +0200947 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200948}
949
950/*
951 * this function dumps every server's state when the process receives SIGHUP.
952 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100953static void sig_dump_state(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200954{
Olivier Houchardfbc74e82017-11-24 16:54:05 +0100955 struct proxy *p = proxies_list;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200956
Christopher Faulet767a84b2017-11-24 16:50:31 +0100957 ha_warning("SIGHUP received, dumping servers states.\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +0200958 while (p) {
959 struct server *s = p->srv;
960
961 send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
962 while (s) {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100963 chunk_printf(&trash,
964 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %lld tot.",
965 p->id, s->id,
Emeric Brun52a91d32017-08-31 14:41:55 +0200966 (s->cur_state != SRV_ST_STOPPED) ? "UP" : "DOWN",
Willy Tarreaua0570452021-06-18 09:30:30 +0200967 s->cur_sess, s->queue.length, s->counters.cum_sess);
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200968 ha_warning("%s\n", trash.area);
969 send_log(p, LOG_NOTICE, "%s\n", trash.area);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200970 s = s->next;
971 }
972
Willy Tarreau5fcc8f12007-09-17 11:27:09 +0200973 /* FIXME: those info are a bit outdated. We should be able to distinguish between FE and BE. */
974 if (!p->srv) {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100975 chunk_printf(&trash,
976 "SIGHUP: Proxy %s has no servers. Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
977 p->id,
Amaury Denoyelle1c8372b2024-04-04 18:08:46 +0200978 p->feconn, p->beconn, p->totpend, p->queue.length, p->fe_counters.cum_conn, p->be_counters.cum_sess);
Willy Tarreau5fcc8f12007-09-17 11:27:09 +0200979 } else if (p->srv_act == 0) {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100980 chunk_printf(&trash,
981 "SIGHUP: Proxy %s %s ! Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
982 p->id,
983 (p->srv_bck) ? "is running on backup servers" : "has no server available",
Amaury Denoyelle1c8372b2024-04-04 18:08:46 +0200984 p->feconn, p->beconn, p->totpend, p->queue.length, p->fe_counters.cum_conn, p->be_counters.cum_sess);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200985 } else {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100986 chunk_printf(&trash,
987 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
988 " Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
989 p->id, p->srv_act, p->srv_bck,
Amaury Denoyelle1c8372b2024-04-04 18:08:46 +0200990 p->feconn, p->beconn, p->totpend, p->queue.length, p->fe_counters.cum_conn, p->be_counters.cum_sess);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200991 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200992 ha_warning("%s\n", trash.area);
993 send_log(p, LOG_NOTICE, "%s\n", trash.area);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200994
995 p = p->next;
996 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200997}
998
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100999static void dump(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001000{
Willy Tarreauc6ca1a02007-05-13 19:43:47 +02001001 /* dump memory usage then free everything possible */
1002 dump_pools();
Willy Tarreaubafbe012017-11-24 17:34:44 +01001003 pool_gc(NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001004}
1005
William Lallemande1340412017-12-28 16:09:36 +01001006/*
1007 * This function dup2 the stdio FDs (0,1,2) with <fd>, then closes <fd>
1008 * If <fd> < 0, it opens /dev/null and use it to dup
1009 *
1010 * In the case of chrooting, you have to open /dev/null before the chroot, and
1011 * pass the <fd> to this function
1012 */
1013static void stdio_quiet(int fd)
1014{
1015 if (fd < 0)
1016 fd = open("/dev/null", O_RDWR, 0);
1017
1018 if (fd > -1) {
1019 fclose(stdin);
1020 fclose(stdout);
1021 fclose(stderr);
1022
1023 dup2(fd, 0);
1024 dup2(fd, 1);
1025 dup2(fd, 2);
1026 if (fd > 2)
1027 close(fd);
1028 return;
1029 }
1030
1031 ha_alert("Cannot open /dev/null\n");
1032 exit(EXIT_FAILURE);
1033}
1034
1035
Joseph Herlant03420902018-11-15 10:41:50 -08001036/* This function checks if cfg_cfgfiles contains directories.
1037 * If it finds one, it adds all the files (and only files) it contains
1038 * in cfg_cfgfiles in place of the directory (and removes the directory).
1039 * It adds the files in lexical order.
1040 * It adds only files with .cfg extension.
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001041 * It doesn't add files with name starting with '.'
1042 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +01001043static void cfgfiles_expand_directories(void)
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001044{
1045 struct wordlist *wl, *wlb;
1046 char *err = NULL;
1047
1048 list_for_each_entry_safe(wl, wlb, &cfg_cfgfiles, list) {
1049 struct stat file_stat;
1050 struct dirent **dir_entries = NULL;
1051 int dir_entries_nb;
1052 int dir_entries_it;
1053
1054 if (stat(wl->s, &file_stat)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001055 ha_alert("Cannot open configuration file/directory %s : %s\n",
1056 wl->s,
1057 strerror(errno));
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001058 exit(1);
1059 }
1060
1061 if (!S_ISDIR(file_stat.st_mode))
1062 continue;
1063
1064 /* from this point wl->s is a directory */
1065
1066 dir_entries_nb = scandir(wl->s, &dir_entries, NULL, alphasort);
1067 if (dir_entries_nb < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001068 ha_alert("Cannot open configuration directory %s : %s\n",
1069 wl->s,
1070 strerror(errno));
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001071 exit(1);
1072 }
1073
1074 /* for each element in the directory wl->s */
1075 for (dir_entries_it = 0; dir_entries_it < dir_entries_nb; dir_entries_it++) {
1076 struct dirent *dir_entry = dir_entries[dir_entries_it];
1077 char *filename = NULL;
1078 char *d_name_cfgext = strstr(dir_entry->d_name, ".cfg");
1079
1080 /* don't add filename that begin with .
Joseph Herlant03420902018-11-15 10:41:50 -08001081 * only add filename with .cfg extension
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001082 */
1083 if (dir_entry->d_name[0] == '.' ||
1084 !(d_name_cfgext && d_name_cfgext[4] == '\0'))
1085 goto next_dir_entry;
1086
1087 if (!memprintf(&filename, "%s/%s", wl->s, dir_entry->d_name)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001088 ha_alert("Cannot load configuration files %s : out of memory.\n",
1089 filename);
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001090 exit(1);
1091 }
1092
1093 if (stat(filename, &file_stat)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001094 ha_alert("Cannot open configuration file %s : %s\n",
1095 wl->s,
1096 strerror(errno));
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001097 exit(1);
1098 }
1099
1100 /* don't add anything else than regular file in cfg_cfgfiles
1101 * this way we avoid loops
1102 */
1103 if (!S_ISREG(file_stat.st_mode))
1104 goto next_dir_entry;
1105
1106 if (!list_append_word(&wl->list, filename, &err)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001107 ha_alert("Cannot load configuration files %s : %s\n",
1108 filename,
1109 err);
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001110 exit(1);
1111 }
1112
1113next_dir_entry:
1114 free(filename);
1115 free(dir_entry);
1116 }
1117
1118 free(dir_entries);
1119
1120 /* remove the current directory (wl) from cfg_cfgfiles */
1121 free(wl->s);
Willy Tarreau2b718102021-04-21 07:32:39 +02001122 LIST_DELETE(&wl->list);
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001123 free(wl);
1124 }
1125
1126 free(err);
1127}
1128
Willy Tarreaubaaee002006-06-26 02:48:02 +02001129/*
William Lallemand73b85e72017-06-01 17:38:51 +02001130 * copy and cleanup the current argv
William Lallemanddf6c5a82020-06-04 17:40:23 +02001131 * Remove the -sf /-st / -x parameters
William Lallemand73b85e72017-06-01 17:38:51 +02001132 * Return an allocated copy of argv
1133 */
1134
1135static char **copy_argv(int argc, char **argv)
1136{
William Lallemanddf6c5a82020-06-04 17:40:23 +02001137 char **newargv, **retargv;
William Lallemand73b85e72017-06-01 17:38:51 +02001138
Tim Duesterhuse52b6e52020-09-12 20:26:43 +02001139 newargv = calloc(argc + 2, sizeof(*newargv));
William Lallemand73b85e72017-06-01 17:38:51 +02001140 if (newargv == NULL) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001141 ha_warning("Cannot allocate memory\n");
William Lallemand73b85e72017-06-01 17:38:51 +02001142 return NULL;
1143 }
William Lallemanddf6c5a82020-06-04 17:40:23 +02001144 retargv = newargv;
William Lallemand73b85e72017-06-01 17:38:51 +02001145
William Lallemanddf6c5a82020-06-04 17:40:23 +02001146 /* first copy argv[0] */
1147 *newargv++ = *argv++;
1148 argc--;
1149
1150 while (argc > 0) {
1151 if (**argv != '-') {
1152 /* non options are copied but will fail in the argument parser */
1153 *newargv++ = *argv++;
1154 argc--;
1155
1156 } else {
1157 char *flag;
1158
1159 flag = *argv + 1;
1160
1161 if (flag[0] == '-' && flag[1] == 0) {
1162 /* "--\0" copy every arguments till the end of argv */
1163 *newargv++ = *argv++;
1164 argc--;
1165
1166 while (argc > 0) {
1167 *newargv++ = *argv++;
1168 argc--;
1169 }
1170 } else {
1171 switch (*flag) {
1172 case 's':
1173 /* -sf / -st and their parameters are ignored */
1174 if (flag[1] == 'f' || flag[1] == 't') {
1175 argc--;
1176 argv++;
1177 /* The list can't contain a negative value since the only
1178 way to know the end of this list is by looking for the
1179 next option or the end of the options */
1180 while (argc > 0 && argv[0][0] != '-') {
1181 argc--;
1182 argv++;
1183 }
William Lallemand398da622020-09-02 16:12:23 +02001184 } else {
1185 argc--;
1186 argv++;
1187
William Lallemanddf6c5a82020-06-04 17:40:23 +02001188 }
1189 break;
1190
1191 case 'x':
1192 /* this option and its parameter are ignored */
1193 argc--;
1194 argv++;
1195 if (argc > 0) {
1196 argc--;
1197 argv++;
1198 }
1199 break;
1200
1201 case 'C':
1202 case 'n':
1203 case 'm':
1204 case 'N':
1205 case 'L':
1206 case 'f':
1207 case 'p':
1208 case 'S':
1209 /* these options have only 1 parameter which must be copied and can start with a '-' */
1210 *newargv++ = *argv++;
1211 argc--;
1212 if (argc == 0)
1213 goto error;
1214 *newargv++ = *argv++;
1215 argc--;
1216 break;
1217 default:
1218 /* for other options just copy them without parameters, this is also done
1219 * for options like "--foo", but this will fail in the argument parser.
1220 * */
1221 *newargv++ = *argv++;
1222 argc--;
1223 break;
1224 }
William Lallemand73b85e72017-06-01 17:38:51 +02001225 }
1226 }
William Lallemand73b85e72017-06-01 17:38:51 +02001227 }
William Lallemand2bf6d622017-06-20 11:20:23 +02001228
William Lallemanddf6c5a82020-06-04 17:40:23 +02001229 return retargv;
1230
1231error:
1232 free(retargv);
1233 return NULL;
William Lallemand73b85e72017-06-01 17:38:51 +02001234}
1235
Willy Tarreau6c3a6812020-03-06 18:57:15 +01001236
1237/* Performs basic random seed initialization. The main issue with this is that
1238 * srandom_r() only takes 32 bits and purposely provides a reproducible sequence,
1239 * which means that there will only be 4 billion possible random sequences once
1240 * srandom() is called, regardless of the internal state. Not calling it is
1241 * even worse as we'll always produce the same randoms sequences. What we do
1242 * here is to create an initial sequence from various entropy sources, hash it
1243 * using SHA1 and keep the resulting 160 bits available globally.
1244 *
1245 * We initialize the current process with the first 32 bits before starting the
1246 * polling loop, where all this will be changed to have process specific and
1247 * thread specific sequences.
Willy Tarreau52bf8392020-03-08 00:42:37 +01001248 *
1249 * Before starting threads, it's still possible to call random() as srandom()
1250 * is initialized from this, but after threads and/or processes are started,
1251 * only ha_random() is expected to be used to guarantee distinct sequences.
Willy Tarreau6c3a6812020-03-06 18:57:15 +01001252 */
1253static void ha_random_boot(char *const *argv)
1254{
1255 unsigned char message[256];
1256 unsigned char *m = message;
1257 struct timeval tv;
1258 blk_SHA_CTX ctx;
1259 unsigned long l;
1260 int fd;
1261 int i;
1262
1263 /* start with current time as pseudo-random seed */
1264 gettimeofday(&tv, NULL);
1265 write_u32(m, tv.tv_sec); m += 4;
1266 write_u32(m, tv.tv_usec); m += 4;
1267
1268 /* PID and PPID add some OS-based randomness */
1269 write_u16(m, getpid()); m += 2;
1270 write_u16(m, getppid()); m += 2;
1271
1272 /* take up to 160 bits bytes from /dev/urandom if available (non-blocking) */
1273 fd = open("/dev/urandom", O_RDONLY);
1274 if (fd >= 0) {
1275 i = read(fd, m, 20);
1276 if (i > 0)
1277 m += i;
1278 close(fd);
1279 }
1280
1281 /* take up to 160 bits bytes from openssl (non-blocking) */
1282#ifdef USE_OPENSSL
1283 if (RAND_bytes(m, 20) == 1)
1284 m += 20;
1285#endif
1286
1287 /* take 160 bits from existing random in case it was already initialized */
1288 for (i = 0; i < 5; i++) {
1289 write_u32(m, random());
1290 m += 4;
1291 }
1292
1293 /* stack address (benefit form operating system's ASLR) */
1294 l = (unsigned long)&m;
1295 memcpy(m, &l, sizeof(l)); m += sizeof(l);
1296
1297 /* argv address (benefit form operating system's ASLR) */
1298 l = (unsigned long)&argv;
1299 memcpy(m, &l, sizeof(l)); m += sizeof(l);
1300
1301 /* use tv_usec again after all the operations above */
1302 gettimeofday(&tv, NULL);
1303 write_u32(m, tv.tv_usec); m += 4;
1304
1305 /*
1306 * At this point, ~84-92 bytes have been used
1307 */
1308
1309 /* finish with the hostname */
1310 strncpy((char *)m, hostname, message + sizeof(message) - m);
1311 m += strlen(hostname);
1312
1313 /* total message length */
1314 l = m - message;
1315
1316 memset(&ctx, 0, sizeof(ctx));
1317 blk_SHA1_Init(&ctx);
1318 blk_SHA1_Update(&ctx, message, l);
1319 blk_SHA1_Final(boot_seed, &ctx);
1320
1321 srandom(read_u32(boot_seed));
Willy Tarreau52bf8392020-03-08 00:42:37 +01001322 ha_random_seed(boot_seed, sizeof(boot_seed));
Willy Tarreau6c3a6812020-03-06 18:57:15 +01001323}
1324
Willy Tarreau5a023f02019-03-01 14:19:31 +01001325/* considers splicing proxies' maxconn, computes the ideal global.maxpipes
1326 * setting, and returns it. It may return -1 meaning "unlimited" if some
1327 * unlimited proxies have been found and the global.maxconn value is not yet
1328 * set. It may also return a value greater than maxconn if it's not yet set.
1329 * Note that a value of zero means there is no need for pipes. -1 is never
1330 * returned if global.maxconn is valid.
1331 */
1332static int compute_ideal_maxpipes()
1333{
1334 struct proxy *cur;
1335 int nbfe = 0, nbbe = 0;
1336 int unlimited = 0;
1337 int pipes;
1338 int max;
1339
1340 for (cur = proxies_list; cur; cur = cur->next) {
1341 if (cur->options2 & (PR_O2_SPLIC_ANY)) {
1342 if (cur->cap & PR_CAP_FE) {
1343 max = cur->maxconn;
1344 nbfe += max;
1345 if (!max) {
1346 unlimited = 1;
1347 break;
1348 }
1349 }
1350 if (cur->cap & PR_CAP_BE) {
1351 max = cur->fullconn ? cur->fullconn : global.maxconn;
1352 nbbe += max;
1353 if (!max) {
1354 unlimited = 1;
1355 break;
1356 }
1357 }
1358 }
1359 }
1360
1361 pipes = MAX(nbfe, nbbe);
1362 if (global.maxconn) {
1363 if (pipes > global.maxconn || unlimited)
1364 pipes = global.maxconn;
1365 } else if (unlimited) {
1366 pipes = -1;
1367 }
1368
1369 return pipes >= 4 ? pipes / 4 : pipes;
1370}
1371
Willy Tarreauac350932019-03-01 15:43:14 +01001372/* considers global.maxsocks, global.maxpipes, async engines, SSL frontends and
1373 * rlimits and computes an ideal maxconn. It's meant to be called only when
1374 * maxsock contains the sum of listening FDs, before it is updated based on
Willy Tarreaudf23c0c2019-03-13 10:10:49 +01001375 * maxconn and pipes. If there are not enough FDs left, DEFAULT_MAXCONN (by
1376 * default 100) is returned as it is expected that it will even run on tight
1377 * environments, and will maintain compatibility with previous packages that
1378 * used to rely on this value as the default one. The system will emit a
1379 * warning indicating how many FDs are missing anyway if needed.
Willy Tarreauac350932019-03-01 15:43:14 +01001380 */
1381static int compute_ideal_maxconn()
1382{
1383 int ssl_sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
1384 int engine_fds = global.ssl_used_async_engines * ssl_sides;
1385 int pipes = compute_ideal_maxpipes();
Willy Tarreaub1beaa32020-03-06 10:25:31 +01001386 int remain = MAX(rlim_fd_cur_at_boot, rlim_fd_max_at_boot);
Willy Tarreauac350932019-03-01 15:43:14 +01001387 int maxconn;
1388
1389 /* we have to take into account these elements :
1390 * - number of engine_fds, which inflates the number of FD needed per
1391 * connection by this number.
1392 * - number of pipes per connection on average : for the unlimited
1393 * case, this is 0.5 pipe FDs per connection, otherwise it's a
1394 * fixed value of 2*pipes.
1395 * - two FDs per connection
1396 */
1397
Valentine Krasnobaeva130f4562024-07-05 20:42:09 +02001398 /* on some modern distros for archs like amd64 fs.nr_open (kernel max)
1399 * could be in order of 1 billion. Systemd since the version 256~rc3-3
1400 * bumped fs.nr_open as the hard RLIMIT_NOFILE (rlim_fd_max_at_boot).
1401 * If we are started without any limits, we risk to finish with computed
1402 * maxconn = ~500000000, maxsock = ~2*maxconn. So, fdtab will be
1403 * extremely large and watchdog will kill the process, when it will try
1404 * to loop over the fdtab (see fd_reregister_all). Please note, that
1405 * fd_hard_limit is taken in account implicitly via 'ideal_maxconn'
1406 * value in all global.maxconn adjustements, when global.rlimit_memmax
1407 * is set:
1408 *
1409 * MIN(global.maxconn, capped by global.rlimit_memmax, ideal_maxconn);
1410 *
1411 * It also caps global.rlimit_nofile, if it couldn't be set as rlim_cur
1412 * and as rlim_max. So, fd_hard_limitit is a good parameter to serve as
1413 * a safeguard, when no haproxy-specific limits are set, i.e.
1414 * rlimit_memmax, maxconn, rlimit_nofile. But it must be kept as a zero,
1415 * if only one of these ha-specific limits is presented in config or in
1416 * the cmdline.
Valentine Krasnobaevabff527b2024-07-03 18:45:35 +02001417 */
Valentine Krasnobaeva130f4562024-07-05 20:42:09 +02001418 if (!global.fd_hard_limit && !global.maxconn && !global.rlimit_nofile
1419 && !global.rlimit_memmax)
Valentine Krasnobaevabff527b2024-07-03 18:45:35 +02001420 global.fd_hard_limit = DEFAULT_MAXFD;
1421
1422 if (remain > global.fd_hard_limit)
Willy Tarreau2df1fbf2022-04-25 18:02:03 +02001423 remain = global.fd_hard_limit;
1424
Willy Tarreauac350932019-03-01 15:43:14 +01001425 /* subtract listeners and checks */
1426 remain -= global.maxsock;
1427
Willy Tarreau3f200852019-03-14 19:13:17 +01001428 /* one epoll_fd/kqueue_fd per thread */
1429 remain -= global.nbthread;
1430
1431 /* one wake-up pipe (2 fd) per thread */
1432 remain -= 2 * global.nbthread;
1433
Willy Tarreauac350932019-03-01 15:43:14 +01001434 /* Fixed pipes values : we only subtract them if they're not larger
1435 * than the remaining FDs because pipes are optional.
1436 */
1437 if (pipes >= 0 && pipes * 2 < remain)
1438 remain -= pipes * 2;
1439
1440 if (pipes < 0) {
1441 /* maxsock = maxconn * 2 + maxconn/4 * 2 + maxconn * engine_fds.
1442 * = maxconn * (2 + 0.5 + engine_fds)
1443 * = maxconn * (4 + 1 + 2*engine_fds) / 2
1444 */
1445 maxconn = 2 * remain / (5 + 2 * engine_fds);
1446 } else {
1447 /* maxsock = maxconn * 2 + maxconn * engine_fds.
1448 * = maxconn * (2 + engine_fds)
1449 */
1450 maxconn = remain / (2 + engine_fds);
1451 }
1452
Willy Tarreaudf23c0c2019-03-13 10:10:49 +01001453 return MAX(maxconn, DEFAULT_MAXCONN);
Willy Tarreauac350932019-03-01 15:43:14 +01001454}
1455
Willy Tarreaua409f302020-03-10 17:08:53 +01001456/* computes the estimated maxsock value for the given maxconn based on the
1457 * possibly set global.maxpipes and existing partial global.maxsock. It may
1458 * temporarily change global.maxconn for the time needed to propagate the
1459 * computations, and will reset it.
1460 */
1461static int compute_ideal_maxsock(int maxconn)
1462{
1463 int maxpipes = global.maxpipes;
1464 int maxsock = global.maxsock;
1465
1466
1467 if (!maxpipes) {
1468 int old_maxconn = global.maxconn;
1469
1470 global.maxconn = maxconn;
1471 maxpipes = compute_ideal_maxpipes();
1472 global.maxconn = old_maxconn;
1473 }
1474
1475 maxsock += maxconn * 2; /* each connection needs two sockets */
1476 maxsock += maxpipes * 2; /* each pipe needs two FDs */
1477 maxsock += global.nbthread; /* one epoll_fd/kqueue_fd per thread */
1478 maxsock += 2 * global.nbthread; /* one wake-up pipe (2 fd) per thread */
1479
1480 /* compute fd used by async engines */
1481 if (global.ssl_used_async_engines) {
1482 int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
1483
1484 maxsock += maxconn * sides * global.ssl_used_async_engines;
1485 }
1486 return maxsock;
1487}
1488
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07001489/* Tests if it is possible to set the current process's RLIMIT_NOFILE to
Willy Tarreau304e17e2020-03-10 17:54:54 +01001490 * <maxsock>, then sets it back to the previous value. Returns non-zero if the
1491 * value is accepted, non-zero otherwise. This is used to determine if an
1492 * automatic limit may be applied or not. When it is not, the caller knows that
1493 * the highest we can do is the rlim_max at boot. In case of error, we return
1494 * that the setting is possible, so that we defer the error processing to the
1495 * final stage in charge of enforcing this.
1496 */
1497static int check_if_maxsock_permitted(int maxsock)
1498{
1499 struct rlimit orig_limit, test_limit;
1500 int ret;
1501
Willy Tarreau2df1fbf2022-04-25 18:02:03 +02001502 if (global.fd_hard_limit && maxsock > global.fd_hard_limit)
1503 return 0;
1504
Willy Tarreau304e17e2020-03-10 17:54:54 +01001505 if (getrlimit(RLIMIT_NOFILE, &orig_limit) != 0)
1506 return 1;
1507
1508 /* don't go further if we can't even set to what we have */
Willy Tarreauc06557c2022-09-22 16:12:08 +02001509 if (raise_rlim_nofile(NULL, &orig_limit) != 0)
Willy Tarreau304e17e2020-03-10 17:54:54 +01001510 return 1;
1511
1512 test_limit.rlim_max = MAX(maxsock, orig_limit.rlim_max);
1513 test_limit.rlim_cur = test_limit.rlim_max;
Willy Tarreauc06557c2022-09-22 16:12:08 +02001514 ret = raise_rlim_nofile(NULL, &test_limit);
Willy Tarreau304e17e2020-03-10 17:54:54 +01001515
Willy Tarreauc06557c2022-09-22 16:12:08 +02001516 if (raise_rlim_nofile(NULL, &orig_limit) != 0)
Willy Tarreau304e17e2020-03-10 17:54:54 +01001517 return 1;
1518
1519 return ret == 0;
1520}
1521
Willy Tarreau34527d52022-02-17 17:45:58 +01001522/* This performs th every basic early initialization at the end of the PREPARE
1523 * init stage. It may only assume that list heads are initialized, but not that
1524 * anything else is correct. It will initialize a number of variables that
1525 * depend on command line and will pre-parse the command line. If it fails, it
1526 * directly exits.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001527 */
Willy Tarreau34527d52022-02-17 17:45:58 +01001528static void init_early(int argc, char **argv)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001529{
Kevinm48936af2010-12-22 16:08:21 +00001530 char *progname;
Willy Tarreau34527d52022-02-17 17:45:58 +01001531 char *tmp;
1532 int len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001533
William Lallemandd4c0be62023-02-21 14:07:05 +01001534 setenv("HAPROXY_STARTUP_VERSION", HAPROXY_VERSION, 0);
1535
Willy Tarreau34527d52022-02-17 17:45:58 +01001536 /* First, let's initialize most global variables */
1537 totalconn = actconn = listeners = stopping = 0;
1538 killed = pid = 0;
1539
1540 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
1541 global.rlimit_memmax_all = HAPROXY_MEMMAX;
Christopher Faulete3a5e352017-10-24 13:53:54 +02001542 global.mode = MODE_STARTING;
William Lallemand73b85e72017-06-01 17:38:51 +02001543
Willy Tarreau34527d52022-02-17 17:45:58 +01001544 /* if we were in mworker mode, we should restart in mworker mode */
1545 if (getenv("HAPROXY_MWORKER_REEXEC") != NULL)
1546 global.mode |= MODE_MWORKER;
David du Colombier7af46052012-05-16 14:16:48 +02001547
Willy Tarreau34527d52022-02-17 17:45:58 +01001548 /* initialize date, time, and pid */
1549 tzset();
1550 clock_init_process_date();
Willy Tarreau6093ba42023-02-07 15:52:14 +01001551 start_date = date;
Willy Tarreauc05d30e2023-04-28 14:50:29 +02001552 start_time_ns = now_ns;
Willy Tarreau34527d52022-02-17 17:45:58 +01001553 pid = getpid();
1554
1555 /* Set local host name and adjust some environment variables.
1556 * NB: POSIX does not make it mandatory for gethostname() to
1557 * NULL-terminate the string in case of truncation, and at least
1558 * FreeBSD appears not to do it.
Emeric Brun2b920a12010-09-23 18:30:22 +02001559 */
1560 memset(hostname, 0, sizeof(hostname));
1561 gethostname(hostname, sizeof(hostname) - 1);
Dragan Dosen4f014152020-06-18 16:56:47 +02001562
Willy Tarreau34527d52022-02-17 17:45:58 +01001563 /* preset some environment variables */
1564 localpeer = strdup(hostname);
1565 if (!localpeer || setenv("HAPROXY_LOCALPEER", localpeer, 1) < 0) {
Dragan Dosen4f014152020-06-18 16:56:47 +02001566 ha_alert("Cannot allocate memory for local peer.\n");
1567 exit(EXIT_FAILURE);
1568 }
Emeric Brun2b920a12010-09-23 18:30:22 +02001569
Willy Tarreau34527d52022-02-17 17:45:58 +01001570 /* Some CPU affinity stuff may have to be initialized */
1571#ifdef USE_CPU_AFFINITY
1572 {
Willy Tarreau5b093412022-07-08 09:38:30 +02001573 int g, i;
1574
1575 for (g = 0; g < MAX_TGROUPS; g++) {
Willy Tarreau5b093412022-07-08 09:38:30 +02001576 ha_cpuset_zero(&cpu_map[g].proc_t1);
1577 for (i = 0; i < MAX_THREADS_PER_GROUP; ++i) {
1578 ha_cpuset_zero(&cpu_map[g].thread[i]);
1579 }
Willy Tarreau34527d52022-02-17 17:45:58 +01001580 }
1581 }
1582#endif
Christopher Fauletcd7879a2017-10-27 13:53:47 +02001583
Willy Tarreau34527d52022-02-17 17:45:58 +01001584 /* extract the program name from argv[0], it will be used for the logs
1585 * and error messages.
1586 */
1587 progname = *argv;
1588 while ((tmp = strchr(progname, '/')) != NULL)
1589 progname = tmp + 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001590
Willy Tarreau34527d52022-02-17 17:45:58 +01001591 len = strlen(progname);
1592 progname = strdup(progname);
1593 if (!progname) {
1594 ha_alert("Cannot allocate memory for log_tag.\n");
1595 exit(EXIT_FAILURE);
1596 }
Willy Tarreau84310e22014-02-14 11:59:04 +01001597
Willy Tarreau34527d52022-02-17 17:45:58 +01001598 chunk_initlen(&global.log_tag, progname, len, len);
1599}
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001600
Willy Tarreau392524d2022-02-17 18:10:36 +01001601/* handles program arguments. Very minimal parsing is performed, variables are
1602 * fed with some values, and lists are completed with other ones. In case of
1603 * error, it will exit.
Willy Tarreau34527d52022-02-17 17:45:58 +01001604 */
Willy Tarreau392524d2022-02-17 18:10:36 +01001605static void init_args(int argc, char **argv)
Willy Tarreau34527d52022-02-17 17:45:58 +01001606{
Willy Tarreau34527d52022-02-17 17:45:58 +01001607 char *progname = global.log_tag.area;
Willy Tarreau392524d2022-02-17 18:10:36 +01001608 char *err_msg = NULL;
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +01001609
Willy Tarreau34527d52022-02-17 17:45:58 +01001610 /* pre-fill in the global tuning options before we let the cmdline
1611 * change them.
1612 */
Willy Tarreau43b78992009-01-25 15:42:27 +01001613 global.tune.options |= GTUNE_USE_SELECT; /* select() is always available */
Willy Tarreaue5733232019-05-22 19:24:06 +02001614#if defined(USE_POLL)
Willy Tarreau43b78992009-01-25 15:42:27 +01001615 global.tune.options |= GTUNE_USE_POLL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001616#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001617#if defined(USE_EPOLL)
Willy Tarreau43b78992009-01-25 15:42:27 +01001618 global.tune.options |= GTUNE_USE_EPOLL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001619#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001620#if defined(USE_KQUEUE)
Willy Tarreau43b78992009-01-25 15:42:27 +01001621 global.tune.options |= GTUNE_USE_KQUEUE;
Willy Tarreau1e63130a2007-04-09 12:03:06 +02001622#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001623#if defined(USE_EVPORTS)
Emmanuel Hocdet0ba4f482019-04-08 16:53:32 +00001624 global.tune.options |= GTUNE_USE_EVPORTS;
1625#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001626#if defined(USE_LINUX_SPLICE)
Willy Tarreau3ab68cf2009-01-25 16:03:28 +01001627 global.tune.options |= GTUNE_USE_SPLICE;
1628#endif
Nenad Merdanovic88afe032014-04-14 15:56:58 +02001629#if defined(USE_GETADDRINFO)
1630 global.tune.options |= GTUNE_USE_GAI;
1631#endif
Willy Tarreau76cc6992020-07-01 18:49:24 +02001632#ifdef USE_THREAD
1633 global.tune.options |= GTUNE_IDLE_POOL_SHARED;
1634#endif
Amaury Denoyellee30f3782022-11-21 11:54:13 +01001635#ifdef USE_QUIC
1636 global.tune.options |= GTUNE_QUIC_SOCK_PER_CONN;
1637#endif
William Dauchya5194602020-03-28 19:29:58 +01001638 global.tune.options |= GTUNE_STRICT_LIMITS;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001639
Christopher Faulet2f7c82b2023-02-20 14:06:52 +01001640 global.tune.options |= GTUNE_USE_FAST_FWD; /* Use fast-forward by default */
1641
Willy Tarreau392524d2022-02-17 18:10:36 +01001642 /* keep a copy of original arguments for the master process */
1643 old_argv = copy_argv(argc, argv);
1644 if (!old_argv) {
1645 ha_alert("failed to copy argv.\n");
1646 exit(EXIT_FAILURE);
1647 }
1648
1649 /* skip program name and start */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001650 argc--; argv++;
1651 while (argc > 0) {
1652 char *flag;
1653
1654 if (**argv == '-') {
1655 flag = *argv+1;
1656
1657 /* 1 arg */
1658 if (*flag == 'v') {
1659 display_version();
Willy Tarreau7b066db2007-12-02 11:28:59 +01001660 if (flag[1] == 'v') /* -vv */
1661 display_build_opts();
Tim Duesterhus77b3db02022-04-27 00:08:11 +02001662 deinit_and_exit(0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001663 }
Willy Tarreaue5733232019-05-22 19:24:06 +02001664#if defined(USE_EPOLL)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001665 else if (*flag == 'd' && flag[1] == 'e')
Willy Tarreau43b78992009-01-25 15:42:27 +01001666 global.tune.options &= ~GTUNE_USE_EPOLL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001667#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001668#if defined(USE_POLL)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001669 else if (*flag == 'd' && flag[1] == 'p')
Willy Tarreau43b78992009-01-25 15:42:27 +01001670 global.tune.options &= ~GTUNE_USE_POLL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001671#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001672#if defined(USE_KQUEUE)
Willy Tarreau1e63130a2007-04-09 12:03:06 +02001673 else if (*flag == 'd' && flag[1] == 'k')
Willy Tarreau43b78992009-01-25 15:42:27 +01001674 global.tune.options &= ~GTUNE_USE_KQUEUE;
Willy Tarreau1e63130a2007-04-09 12:03:06 +02001675#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001676#if defined(USE_EVPORTS)
Emmanuel Hocdet0ba4f482019-04-08 16:53:32 +00001677 else if (*flag == 'd' && flag[1] == 'v')
1678 global.tune.options &= ~GTUNE_USE_EVPORTS;
1679#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001680#if defined(USE_LINUX_SPLICE)
Willy Tarreau3ab68cf2009-01-25 16:03:28 +01001681 else if (*flag == 'd' && flag[1] == 'S')
1682 global.tune.options &= ~GTUNE_USE_SPLICE;
1683#endif
Nenad Merdanovic88afe032014-04-14 15:56:58 +02001684#if defined(USE_GETADDRINFO)
1685 else if (*flag == 'd' && flag[1] == 'G')
1686 global.tune.options &= ~GTUNE_USE_GAI;
1687#endif
Lukas Tribusa0bcbdc2016-09-12 21:42:20 +00001688#if defined(SO_REUSEPORT)
1689 else if (*flag == 'd' && flag[1] == 'R')
Willy Tarreau785b89f2023-04-22 15:09:07 +02001690 protocol_clrf_all(PROTO_F_REUSEPORT_SUPPORTED);
Lukas Tribusa0bcbdc2016-09-12 21:42:20 +00001691#endif
Christopher Faulet678a4ce2023-02-14 16:12:54 +01001692 else if (*flag == 'd' && flag[1] == 'F')
Christopher Faulet2f7c82b2023-02-20 14:06:52 +01001693 global.tune.options &= ~GTUNE_USE_FAST_FWD;
Emeric Brun850efd52014-01-29 12:24:34 +01001694 else if (*flag == 'd' && flag[1] == 'V')
1695 global.ssl_server_verify = SSL_SERVER_VERIFY_NONE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001696 else if (*flag == 'V')
1697 arg_mode |= MODE_VERBOSE;
Erwan Le Goasb0c05012022-09-14 17:51:55 +02001698 else if (*flag == 'd' && flag[1] == 'C') {
Erwan Le Goasf30c5d72022-09-29 10:34:04 +02001699 char *end;
1700 char *key;
1701
1702 key = flag + 2;
1703 for (;key && *key; key = end) {
1704 end = strchr(key, ',');
1705 if (end)
1706 *(end++) = 0;
1707
1708 if (strcmp(key, "line") == 0)
1709 arg_mode |= MODE_DUMP_NB_L;
1710
1711 }
Erwan Le Goasb0c05012022-09-14 17:51:55 +02001712 arg_mode |= MODE_DUMP_CFG;
1713 HA_ATOMIC_STORE(&global.anon_key, atoll(flag + 2));
1714 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001715 else if (*flag == 'd' && flag[1] == 'b')
1716 arg_mode |= MODE_FOREGROUND;
Amaury Denoyelle7b01a8d2021-03-29 10:29:07 +02001717 else if (*flag == 'd' && flag[1] == 'D')
1718 arg_mode |= MODE_DIAG;
Willy Tarreau3eb10b82020-04-15 16:42:39 +02001719 else if (*flag == 'd' && flag[1] == 'W')
1720 arg_mode |= MODE_ZERO_WARNING;
Willy Tarreauef301b72022-02-23 14:15:18 +01001721 else if (*flag == 'd' && flag[1] == 'M') {
Willy Tarreau1408b1f2022-02-18 18:54:40 +01001722 int ret = pool_parse_debugging(flag + 2, &err_msg);
1723
1724 if (ret <= -1) {
1725 if (ret < -1)
1726 ha_alert("-dM: %s\n", err_msg);
1727 else
1728 printf("%s\n", err_msg);
1729 ha_free(&err_msg);
1730 exit(ret < -1 ? EXIT_FAILURE : 0);
1731 } else if (ret == 0) {
1732 ha_warning("-dM: %s\n", err_msg);
1733 ha_free(&err_msg);
1734 }
Willy Tarreauef301b72022-02-23 14:15:18 +01001735 }
Willy Tarreau3eed10e2016-11-07 21:03:16 +01001736 else if (*flag == 'd' && flag[1] == 'r')
1737 global.tune.options |= GTUNE_RESOLVE_DONTFAIL;
Willy Tarreau654726d2021-12-28 15:43:11 +01001738#if defined(HA_HAVE_DUMP_LIBS)
1739 else if (*flag == 'd' && flag[1] == 'L')
1740 arg_mode |= MODE_DUMP_LIBS;
1741#endif
Willy Tarreau76871a42022-03-08 16:01:40 +01001742 else if (*flag == 'd' && flag[1] == 'K') {
1743 arg_mode |= MODE_DUMP_KWD;
1744 kwd_dump = flag + 2;
1745 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001746 else if (*flag == 'd')
1747 arg_mode |= MODE_DEBUG;
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02001748 else if (*flag == 'c' && flag[1] == 'c') {
1749 arg_mode |= MODE_CHECK_CONDITION;
1750 argv++;
1751 argc--;
1752 check_condition = *argv;
1753 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001754 else if (*flag == 'c')
1755 arg_mode |= MODE_CHECK;
William Lallemand095ba4c2017-06-01 17:38:50 +02001756 else if (*flag == 'D')
Willy Tarreau6bde87b2009-05-18 16:29:51 +02001757 arg_mode |= MODE_DAEMON;
Tim Duesterhusd6942c82017-11-20 15:58:35 +01001758 else if (*flag == 'W' && flag[1] == 's') {
Lukas Tribusf46bf952017-11-21 12:39:34 +01001759 arg_mode |= MODE_MWORKER | MODE_FOREGROUND;
Tim Duesterhusd6942c82017-11-20 15:58:35 +01001760#if defined(USE_SYSTEMD)
1761 global.tune.options |= GTUNE_USE_SYSTEMD;
1762#else
Christopher Faulet767a84b2017-11-24 16:50:31 +01001763 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 +01001764 usage(progname);
1765#endif
1766 }
William Lallemand095ba4c2017-06-01 17:38:50 +02001767 else if (*flag == 'W')
1768 arg_mode |= MODE_MWORKER;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001769 else if (*flag == 'q')
1770 arg_mode |= MODE_QUIET;
Olivier Houchardf73629d2017-04-05 22:33:04 +02001771 else if (*flag == 'x') {
William Lallemand4f71d302020-06-04 23:41:29 +02001772 if (argc <= 1) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001773 ha_alert("Unix socket path expected with the -x flag\n\n");
William Lallemand45eff442017-06-19 15:57:55 +02001774 usage(progname);
Olivier Houchardf73629d2017-04-05 22:33:04 +02001775 }
William Lallemand4fc09692017-06-19 16:37:19 +02001776 if (old_unixsocket)
Christopher Faulet767a84b2017-11-24 16:50:31 +01001777 ha_warning("-x option already set, overwriting the value\n");
Olivier Houchardf73629d2017-04-05 22:33:04 +02001778 old_unixsocket = argv[1];
William Lallemand4fc09692017-06-19 16:37:19 +02001779
Olivier Houchardf73629d2017-04-05 22:33:04 +02001780 argv++;
1781 argc--;
1782 }
William Lallemande7361152018-10-26 14:47:36 +02001783 else if (*flag == 'S') {
1784 struct wordlist *c;
1785
William Lallemanda6b32492020-06-04 23:49:20 +02001786 if (argc <= 1) {
William Lallemande7361152018-10-26 14:47:36 +02001787 ha_alert("Socket and optional bind parameters expected with the -S flag\n");
1788 usage(progname);
1789 }
1790 if ((c = malloc(sizeof(*c))) == NULL || (c->s = strdup(argv[1])) == NULL) {
1791 ha_alert("Cannot allocate memory\n");
1792 exit(EXIT_FAILURE);
1793 }
Willy Tarreau2b718102021-04-21 07:32:39 +02001794 LIST_INSERT(&mworker_cli_conf, &c->list);
William Lallemande7361152018-10-26 14:47:36 +02001795
1796 argv++;
1797 argc--;
1798 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001799 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
1800 /* list of pids to finish ('f') or terminate ('t') */
1801
1802 if (flag[1] == 'f')
1803 oldpids_sig = SIGUSR1; /* finish then exit */
1804 else
1805 oldpids_sig = SIGTERM; /* terminate immediately */
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001806 while (argc > 1 && argv[1][0] != '-') {
Chris Lane236062f2018-02-05 23:15:44 +00001807 char * endptr = NULL;
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001808 oldpids = realloc(oldpids, (nb_oldpids + 1) * sizeof(int));
1809 if (!oldpids) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001810 ha_alert("Cannot allocate old pid : out of memory.\n");
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001811 exit(1);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001812 }
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001813 argc--; argv++;
Chris Lane236062f2018-02-05 23:15:44 +00001814 errno = 0;
1815 oldpids[nb_oldpids] = strtol(*argv, &endptr, 10);
1816 if (errno) {
1817 ha_alert("-%2s option: failed to parse {%s}: %s\n",
1818 flag,
1819 *argv, strerror(errno));
1820 exit(1);
1821 } else if (endptr && strlen(endptr)) {
Willy Tarreau90807112020-02-25 08:16:33 +01001822 while (isspace((unsigned char)*endptr)) endptr++;
Aurélien Nephtali39b89882018-02-17 20:53:11 +01001823 if (*endptr != 0) {
Chris Lane236062f2018-02-05 23:15:44 +00001824 ha_alert("-%2s option: some bytes unconsumed in PID list {%s}\n",
1825 flag, endptr);
1826 exit(1);
Aurélien Nephtali39b89882018-02-17 20:53:11 +01001827 }
Chris Lane236062f2018-02-05 23:15:44 +00001828 }
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001829 if (oldpids[nb_oldpids] <= 0)
1830 usage(progname);
1831 nb_oldpids++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001832 }
1833 }
Willy Tarreaua088d312015-10-08 11:58:48 +02001834 else if (flag[0] == '-' && flag[1] == 0) { /* "--" */
1835 /* now that's a cfgfile list */
1836 argv++; argc--;
1837 while (argc > 0) {
Maxime de Roucy0f503922016-05-13 23:52:55 +02001838 if (!list_append_word(&cfg_cfgfiles, *argv, &err_msg)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001839 ha_alert("Cannot load configuration file/directory %s : %s\n",
1840 *argv,
1841 err_msg);
Willy Tarreaua088d312015-10-08 11:58:48 +02001842 exit(1);
1843 }
Willy Tarreaua088d312015-10-08 11:58:48 +02001844 argv++; argc--;
1845 }
1846 break;
1847 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001848 else { /* >=2 args */
1849 argv++; argc--;
1850 if (argc == 0)
Willy Tarreau3bafcdc2011-09-10 19:20:23 +02001851 usage(progname);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001852
1853 switch (*flag) {
Willy Tarreau576132e2011-09-10 19:26:56 +02001854 case 'C' : change_dir = *argv; break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001855 case 'n' : cfg_maxconn = atol(*argv); break;
Willy Tarreau70060452015-12-14 12:46:07 +01001856 case 'm' : global.rlimit_memmax_all = atol(*argv); break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001857 case 'N' : cfg_maxpconn = atol(*argv); break;
William Lallemanddaf4cd22018-04-17 16:46:13 +02001858 case 'L' :
Dragan Dosen4f014152020-06-18 16:56:47 +02001859 free(localpeer);
1860 if ((localpeer = strdup(*argv)) == NULL) {
1861 ha_alert("Cannot allocate memory for local peer.\n");
1862 exit(EXIT_FAILURE);
1863 }
William Lallemanddaf4cd22018-04-17 16:46:13 +02001864 setenv("HAPROXY_LOCALPEER", localpeer, 1);
Dragan Dosen13cd54c2020-06-18 18:24:05 +02001865 global.localpeer_cmdline = 1;
William Lallemanddaf4cd22018-04-17 16:46:13 +02001866 break;
Willy Tarreau5d01a632009-06-22 16:02:30 +02001867 case 'f' :
Maxime de Roucy0f503922016-05-13 23:52:55 +02001868 if (!list_append_word(&cfg_cfgfiles, *argv, &err_msg)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001869 ha_alert("Cannot load configuration file/directory %s : %s\n",
1870 *argv,
1871 err_msg);
Willy Tarreau5d01a632009-06-22 16:02:30 +02001872 exit(1);
1873 }
Willy Tarreau5d01a632009-06-22 16:02:30 +02001874 break;
Willy Tarreau392524d2022-02-17 18:10:36 +01001875 case 'p' :
1876 free(global.pidfile);
1877 if ((global.pidfile = strdup(*argv)) == NULL) {
1878 ha_alert("Cannot allocate memory for pidfile.\n");
1879 exit(EXIT_FAILURE);
1880 }
1881 break;
Willy Tarreau3bafcdc2011-09-10 19:20:23 +02001882 default: usage(progname);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001883 }
1884 }
1885 }
1886 else
Willy Tarreau3bafcdc2011-09-10 19:20:23 +02001887 usage(progname);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001888 argv++; argc--;
1889 }
Willy Tarreau392524d2022-02-17 18:10:36 +01001890 free(err_msg);
1891}
1892
Willy Tarreau76871a42022-03-08 16:01:40 +01001893/* call the various keyword dump functions based on the comma-delimited list of
1894 * classes in kwd_dump.
1895 */
1896static void dump_registered_keywords(void)
1897{
1898 char *end;
1899 int all __maybe_unused = 0;
1900
1901 for (; kwd_dump && *kwd_dump; kwd_dump = end) {
1902 end = strchr(kwd_dump, ',');
1903 if (end)
1904 *(end++) = 0;
1905
1906 if (strcmp(kwd_dump, "help") == 0) {
1907 printf("# List of supported keyword classes:\n");
1908 printf("all: list all keywords\n");
Willy Tarreau6ff7d1b2022-03-29 15:36:56 +02001909 printf("acl: ACL keywords\n");
Willy Tarreauca1acd62022-03-29 15:02:44 +02001910 printf("cfg: configuration keywords\n");
Willy Tarreau06d0e2e2022-03-29 15:25:30 +02001911 printf("cli: CLI keywords\n");
Willy Tarreau29d799d2022-03-29 16:59:49 +02001912 printf("cnv: sample converter keywords\n");
Willy Tarreau3b65e142022-03-29 15:03:09 +02001913 printf("flt: filter names\n");
Willy Tarreauf78813f2022-03-29 16:51:29 +02001914 printf("smp: sample fetch functions\n");
Willy Tarreau5fcc1002022-03-29 15:10:44 +02001915 printf("svc: service names\n");
Willy Tarreau76871a42022-03-08 16:01:40 +01001916 continue;
1917 }
1918 else if (strcmp(kwd_dump, "all") == 0) {
1919 all = 1;
1920 }
Willy Tarreauca1acd62022-03-29 15:02:44 +02001921
Willy Tarreau6ff7d1b2022-03-29 15:36:56 +02001922 if (all || strcmp(kwd_dump, "acl") == 0) {
1923 printf("# List of registered ACL keywords:\n");
1924 acl_dump_kwd();
1925 }
1926
Willy Tarreauca1acd62022-03-29 15:02:44 +02001927 if (all || strcmp(kwd_dump, "cfg") == 0) {
1928 printf("# List of registered configuration keywords:\n");
1929 cfg_dump_registered_keywords();
1930 }
Willy Tarreau3b65e142022-03-29 15:03:09 +02001931
Willy Tarreau06d0e2e2022-03-29 15:25:30 +02001932 if (all || strcmp(kwd_dump, "cli") == 0) {
1933 printf("# List of registered CLI keywords:\n");
1934 cli_list_keywords();
1935 }
1936
Willy Tarreau29d799d2022-03-29 16:59:49 +02001937 if (all || strcmp(kwd_dump, "cnv") == 0) {
1938 printf("# List of registered sample converter functions:\n");
1939 smp_dump_conv_kw();
1940 }
1941
Willy Tarreau3b65e142022-03-29 15:03:09 +02001942 if (all || strcmp(kwd_dump, "flt") == 0) {
1943 printf("# List of registered filter names:\n");
1944 flt_dump_kws(NULL);
1945 }
Willy Tarreau5fcc1002022-03-29 15:10:44 +02001946
Willy Tarreauf78813f2022-03-29 16:51:29 +02001947 if (all || strcmp(kwd_dump, "smp") == 0) {
1948 printf("# List of registered sample fetch functions:\n");
1949 smp_dump_fetch_kw();
1950 }
1951
Willy Tarreau5fcc1002022-03-29 15:10:44 +02001952 if (all || strcmp(kwd_dump, "svc") == 0) {
1953 printf("# List of registered service names:\n");
1954 list_services(NULL);
1955 }
Willy Tarreau76871a42022-03-08 16:01:40 +01001956 }
1957}
1958
Amaury Denoyelle28ea31c2022-11-14 16:18:46 +01001959/* Generate a random cluster-secret in case the setting is not provided in the
1960 * configuration. This allows to use features which rely on it albeit with some
1961 * limitations.
1962 */
1963static void generate_random_cluster_secret()
1964{
1965 /* used as a default random cluster-secret if none defined. */
Frédéric Lécaille0499db42023-09-07 18:43:52 +02001966 uint64_t rand;
Amaury Denoyelle28ea31c2022-11-14 16:18:46 +01001967
1968 /* The caller must not overwrite an already defined secret. */
Frédéric Lécaille0499db42023-09-07 18:43:52 +02001969 BUG_ON(cluster_secret_isset);
Amaury Denoyelle28ea31c2022-11-14 16:18:46 +01001970
Frédéric Lécaille0499db42023-09-07 18:43:52 +02001971 rand = ha_random64();
Amaury Denoyelle28ea31c2022-11-14 16:18:46 +01001972 memcpy(global.cluster_secret, &rand, sizeof(rand));
Frédéric Lécaille0499db42023-09-07 18:43:52 +02001973 rand = ha_random64();
1974 memcpy(global.cluster_secret + sizeof(rand), &rand, sizeof(rand));
1975 cluster_secret_isset = 1;
Amaury Denoyelle28ea31c2022-11-14 16:18:46 +01001976}
1977
Willy Tarreau392524d2022-02-17 18:10:36 +01001978/*
1979 * This function initializes all the necessary variables. It only returns
1980 * if everything is OK. If something fails, it exits.
1981 */
1982static void init(int argc, char **argv)
1983{
1984 char *progname = global.log_tag.area;
1985 int err_code = 0;
1986 struct wordlist *wl;
1987 struct proxy *px;
1988 struct post_check_fct *pcf;
William Lallemandb53eb872022-04-21 18:02:53 +02001989 struct pre_check_fct *prcf;
Willy Tarreau392524d2022-02-17 18:10:36 +01001990 int ideal_maxconn;
1991
William Lallemand151dbbe2022-12-02 17:17:43 +01001992#ifdef USE_OPENSSL
1993#ifdef USE_OPENSSL_WOLFSSL
1994 wolfSSL_Init();
1995 wolfSSL_Debugging_ON();
1996#endif
1997#if (HA_OPENSSL_VERSION_NUMBER < 0x1010000fL)
William Lallemand44c80ce2022-12-02 17:06:59 +01001998 /* Initialize the error strings of OpenSSL
1999 * It only needs to be done explicitly with older versions of the SSL
2000 * library. On newer versions, errors strings are loaded during start
2001 * up. */
2002 SSL_load_error_strings();
2003#endif
William Lallemand151dbbe2022-12-02 17:17:43 +01002004#endif
William Lallemand44c80ce2022-12-02 17:06:59 +01002005
William Lallemandeba6a542022-09-26 12:54:39 +02002006 startup_logs_init();
2007
Willy Tarreau392524d2022-02-17 18:10:36 +01002008 if (!init_trash_buffers(1)) {
2009 ha_alert("failed to initialize trash buffers.\n");
2010 exit(1);
2011 }
2012
2013 if (init_acl() != 0)
2014 exit(1);
2015
2016 /* Initialise lua. */
2017 hlua_init();
Willy Tarreaubaaee002006-06-26 02:48:02 +02002018
Christopher Faulete3a5e352017-10-24 13:53:54 +02002019 global.mode |= (arg_mode & (MODE_DAEMON | MODE_MWORKER | MODE_FOREGROUND | MODE_VERBOSE
Amaury Denoyelle7b01a8d2021-03-29 10:29:07 +02002020 | MODE_QUIET | MODE_CHECK | MODE_DEBUG | MODE_ZERO_WARNING
Erwan Le Goasf30c5d72022-09-29 10:34:04 +02002021 | MODE_DIAG | MODE_CHECK_CONDITION | MODE_DUMP_LIBS | MODE_DUMP_KWD
2022 | MODE_DUMP_CFG | MODE_DUMP_NB_L));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002023
William Lallemand944e6192018-11-21 15:48:31 +01002024 if (getenv("HAPROXY_MWORKER_WAIT_ONLY")) {
William Lallemandcb11fd22017-06-01 17:38:52 +02002025 unsetenv("HAPROXY_MWORKER_WAIT_ONLY");
William Lallemand944e6192018-11-21 15:48:31 +01002026 global.mode |= MODE_MWORKER_WAIT;
2027 global.mode &= ~MODE_MWORKER;
William Lallemandcb11fd22017-06-01 17:38:52 +02002028 }
2029
William Lallemand40db4ae2022-12-07 15:03:55 +01002030 /* set the atexit functions when not doing configuration check */
2031 if (!(global.mode & (MODE_CHECK | MODE_CHECK_CONDITION))
2032 && (getenv("HAPROXY_MWORKER_REEXEC") != NULL)) {
2033
2034 if (global.mode & MODE_MWORKER) {
2035 atexit_flag = 1;
2036 atexit(reexec_on_failure);
2037 } else if (global.mode & MODE_MWORKER_WAIT) {
2038 atexit_flag = 1;
2039 atexit(exit_on_waitmode_failure);
2040 }
William Lallemandcb11fd22017-06-01 17:38:52 +02002041 }
2042
Willy Tarreau576132e2011-09-10 19:26:56 +02002043 if (change_dir && chdir(change_dir) < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002044 ha_alert("Could not change to directory %s : %s\n", change_dir, strerror(errno));
Willy Tarreau576132e2011-09-10 19:26:56 +02002045 exit(1);
2046 }
2047
Amaury Denoyelle11124302021-06-04 18:22:08 +02002048 usermsgs_clr("config");
2049
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02002050 if (global.mode & MODE_CHECK_CONDITION) {
2051 int result;
2052
2053 uint32_t err;
2054 const char *errptr;
2055 char *errmsg = NULL;
2056
2057 char *args[MAX_LINE_ARGS+1];
2058 int arg = sizeof(args) / sizeof(*args);
William Lallemand89e236f2022-05-06 17:22:36 +02002059 size_t outlen;
Willy Tarreauc8194c32021-07-16 16:38:58 +02002060 char *w;
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02002061
William Lallemand89e236f2022-05-06 17:22:36 +02002062 if (!check_condition)
2063 usage(progname);
2064
2065 outlen = strlen(check_condition) + 1;
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02002066 err = parse_line(check_condition, check_condition, &outlen, args, &arg,
Willy Tarreaua87e7822021-07-16 19:14:54 +02002067 PARSE_OPT_ENV | PARSE_OPT_WORD_EXPAND | PARSE_OPT_DQUOTE | PARSE_OPT_SQUOTE | PARSE_OPT_BKSLASH,
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02002068 &errptr);
2069
2070 if (err & PARSE_ERR_QUOTE) {
2071 ha_alert("Syntax Error in condition: Unmatched quote.\n");
2072 exit(2);
2073 }
2074
2075 if (err & PARSE_ERR_HEX) {
2076 ha_alert("Syntax Error in condition: Truncated or invalid hexadecimal sequence.\n");
2077 exit(2);
2078 }
2079
2080 if (err & (PARSE_ERR_TOOLARGE|PARSE_ERR_OVERLAP)) {
2081 ha_alert("Error in condition: Line too long.\n");
2082 exit(2);
2083 }
2084
Willy Tarreauc8194c32021-07-16 16:38:58 +02002085 if (err & PARSE_ERR_TOOMANY) {
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02002086 ha_alert("Error in condition: Too many words.\n");
2087 exit(2);
2088 }
2089
2090 if (err) {
2091 ha_alert("Unhandled error in condition, please report this to the developers.\n");
2092 exit(2);
2093 }
2094
Willy Tarreauc8194c32021-07-16 16:38:58 +02002095 /* remerge all words into a single expression */
2096 for (w = *args; (w += strlen(w)) < check_condition + outlen - 1; *w = ' ')
2097 ;
2098
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02002099 result = cfg_eval_condition(args, &errmsg, &errptr);
2100
2101 if (result < 0) {
2102 if (errmsg)
2103 ha_alert("Failed to evaluate condition: %s\n", errmsg);
2104
2105 exit(2);
2106 }
2107
2108 exit(result ? 0 : 1);
2109 }
2110
William Lallemand944e6192018-11-21 15:48:31 +01002111 /* in wait mode, we don't try to read the configuration files */
2112 if (!(global.mode & MODE_MWORKER_WAIT)) {
Christopher Faulet4e366822021-01-12 18:57:38 +01002113 char *env_cfgfiles = NULL;
2114 int env_err = 0;
Willy Tarreauc4382422009-12-06 13:10:44 +01002115
William Lallemand944e6192018-11-21 15:48:31 +01002116 /* handle cfgfiles that are actually directories */
2117 cfgfiles_expand_directories();
2118
2119 if (LIST_ISEMPTY(&cfg_cfgfiles))
2120 usage(progname);
2121
Sébastien Gross537b9e72022-11-30 22:36:50 +01002122 /* temporary create environment variables with default
2123 * values to ease user configuration. Do not forget to
2124 * unset them after the list_for_each_entry loop.
2125 */
2126 setenv("HAPROXY_HTTP_LOG_FMT", default_http_log_format, 1);
2127 setenv("HAPROXY_HTTPS_LOG_FMT", default_https_log_format, 1);
2128 setenv("HAPROXY_TCP_LOG_FMT", default_tcp_log_format, 1);
Sébaastien Gross2a1bcf12023-02-23 12:54:25 -05002129 setenv("HAPROXY_BRANCH", PRODUCT_BRANCH, 1);
William Lallemand944e6192018-11-21 15:48:31 +01002130 list_for_each_entry(wl, &cfg_cfgfiles, list) {
2131 int ret;
2132
Christopher Faulet4e366822021-01-12 18:57:38 +01002133 if (env_err == 0) {
2134 if (!memprintf(&env_cfgfiles, "%s%s%s",
2135 (env_cfgfiles ? env_cfgfiles : ""),
2136 (env_cfgfiles ? ";" : ""), wl->s))
2137 env_err = 1;
2138 }
William Lallemand7b302d82019-05-20 11:15:37 +02002139
William Lallemand944e6192018-11-21 15:48:31 +01002140 ret = readcfgfile(wl->s);
2141 if (ret == -1) {
2142 ha_alert("Could not open configuration file %s : %s\n",
2143 wl->s, strerror(errno));
Christopher Faulet4e366822021-01-12 18:57:38 +01002144 free(env_cfgfiles);
William Lallemand944e6192018-11-21 15:48:31 +01002145 exit(1);
2146 }
2147 if (ret & (ERR_ABORT|ERR_FATAL))
2148 ha_alert("Error(s) found in configuration file : %s\n", wl->s);
2149 err_code |= ret;
Christopher Faulet4e366822021-01-12 18:57:38 +01002150 if (err_code & ERR_ABORT) {
2151 free(env_cfgfiles);
William Lallemand944e6192018-11-21 15:48:31 +01002152 exit(1);
Christopher Faulet4e366822021-01-12 18:57:38 +01002153 }
Willy Tarreauc4382422009-12-06 13:10:44 +01002154 }
Sébastien Gross537b9e72022-11-30 22:36:50 +01002155 /* remove temporary environment variables. */
Sébaastien Gross2a1bcf12023-02-23 12:54:25 -05002156 unsetenv("HAPROXY_BRANCH");
Sébastien Gross537b9e72022-11-30 22:36:50 +01002157 unsetenv("HAPROXY_HTTP_LOG_FMT");
2158 unsetenv("HAPROXY_HTTPS_LOG_FMT");
2159 unsetenv("HAPROXY_TCP_LOG_FMT");
Krzysztof Oledzkib304dc72007-10-14 23:40:01 +02002160
William Lallemand944e6192018-11-21 15:48:31 +01002161 /* do not try to resolve arguments nor to spot inconsistencies when
2162 * the configuration contains fatal errors caused by files not found
2163 * or failed memory allocations.
2164 */
2165 if (err_code & (ERR_ABORT|ERR_FATAL)) {
2166 ha_alert("Fatal errors found in configuration.\n");
Christopher Faulet4e366822021-01-12 18:57:38 +01002167 free(env_cfgfiles);
William Lallemand944e6192018-11-21 15:48:31 +01002168 exit(1);
2169 }
Christopher Faulet4e366822021-01-12 18:57:38 +01002170 if (env_err) {
2171 ha_alert("Could not allocate memory for HAPROXY_CFGFILES env variable\n");
2172 exit(1);
2173 }
2174 setenv("HAPROXY_CFGFILES", env_cfgfiles, 1);
2175 free(env_cfgfiles);
William Lallemand7b302d82019-05-20 11:15:37 +02002176
Willy Tarreaub83dc3d2017-04-19 11:24:07 +02002177 }
William Lallemandce83b4a2018-10-26 14:47:30 +02002178 if (global.mode & MODE_MWORKER) {
William Lallemand16dd1b32018-11-19 18:46:18 +01002179 struct mworker_proc *tmproc;
2180
William Lallemand482f9a92019-04-12 16:15:00 +02002181 setenv("HAPROXY_MWORKER", "1", 1);
2182
William Lallemand16dd1b32018-11-19 18:46:18 +01002183 if (getenv("HAPROXY_MWORKER_REEXEC") == NULL) {
2184
William Lallemand56be0e02022-01-28 21:11:41 +01002185 tmproc = mworker_proc_new();
William Lallemand16dd1b32018-11-19 18:46:18 +01002186 if (!tmproc) {
2187 ha_alert("Cannot allocate process structures.\n");
2188 exit(EXIT_FAILURE);
2189 }
William Lallemand8f7069a2019-04-12 16:09:23 +02002190 tmproc->options |= PROC_O_TYPE_MASTER; /* master */
William Lallemand16dd1b32018-11-19 18:46:18 +01002191 tmproc->pid = pid;
William Lallemand5a7f83a2023-02-17 16:23:52 +01002192 tmproc->timestamp = start_date.tv_sec;
William Lallemand16dd1b32018-11-19 18:46:18 +01002193 proc_self = tmproc;
2194
Willy Tarreau2b718102021-04-21 07:32:39 +02002195 LIST_APPEND(&proc_list, &tmproc->list);
William Lallemand16dd1b32018-11-19 18:46:18 +01002196 }
William Lallemandce83b4a2018-10-26 14:47:30 +02002197
William Lallemand56be0e02022-01-28 21:11:41 +01002198 tmproc = mworker_proc_new();
Willy Tarreau6185a032021-06-15 08:02:06 +02002199 if (!tmproc) {
2200 ha_alert("Cannot allocate process structures.\n");
2201 exit(EXIT_FAILURE);
2202 }
Willy Tarreau6185a032021-06-15 08:02:06 +02002203 tmproc->options |= PROC_O_TYPE_WORKER; /* worker */
William Lallemandce83b4a2018-10-26 14:47:30 +02002204
Willy Tarreau6185a032021-06-15 08:02:06 +02002205 if (mworker_cli_sockpair_new(tmproc, 0) < 0) {
2206 exit(EXIT_FAILURE);
William Lallemandce83b4a2018-10-26 14:47:30 +02002207 }
Willy Tarreau6185a032021-06-15 08:02:06 +02002208
2209 LIST_APPEND(&proc_list, &tmproc->list);
William Lallemand944e6192018-11-21 15:48:31 +01002210 }
Willy Tarreau53bfac82022-07-22 17:35:49 +02002211
2212 if (global.mode & MODE_MWORKER_WAIT) {
2213 /* in exec mode, there's always exactly one thread. Failure to
2214 * set these ones now will result in nbthread being detected
2215 * automatically.
2216 */
2217 global.nbtgroups = 1;
2218 global.nbthread = 1;
2219 }
2220
William Lallemand944e6192018-11-21 15:48:31 +01002221 if (global.mode & (MODE_MWORKER|MODE_MWORKER_WAIT)) {
2222 struct wordlist *it, *c;
2223
William Lallemand63f43ff2023-11-14 13:58:53 +01002224 master = 1;
Remi Tricot-Le Breton1f4fa902021-05-19 10:45:12 +02002225 /* get the info of the children in the env */
2226 if (mworker_env_to_proc_list() < 0) {
2227 exit(EXIT_FAILURE);
2228 }
William Lallemande7361152018-10-26 14:47:36 +02002229
William Lallemand550db6d2018-11-06 17:37:12 +01002230 if (!LIST_ISEMPTY(&mworker_cli_conf)) {
William Lallemandec059c22022-09-22 17:26:23 +02002231 char *path = NULL;
William Lallemande7361152018-10-26 14:47:36 +02002232
William Lallemand550db6d2018-11-06 17:37:12 +01002233 if (mworker_cli_proxy_create() < 0) {
William Lallemande7361152018-10-26 14:47:36 +02002234 ha_alert("Can't create the master's CLI.\n");
2235 exit(EXIT_FAILURE);
2236 }
William Lallemande7361152018-10-26 14:47:36 +02002237
William Lallemand550db6d2018-11-06 17:37:12 +01002238 list_for_each_entry_safe(c, it, &mworker_cli_conf, list) {
2239
William Lallemand21623b52022-09-24 15:51:27 +02002240 if (mworker_cli_proxy_new_listener(c->s) == NULL) {
William Lallemand550db6d2018-11-06 17:37:12 +01002241 ha_alert("Can't create the master's CLI.\n");
2242 exit(EXIT_FAILURE);
2243 }
Willy Tarreau2b718102021-04-21 07:32:39 +02002244 LIST_DELETE(&c->list);
William Lallemand550db6d2018-11-06 17:37:12 +01002245 free(c->s);
2246 free(c);
2247 }
William Lallemande57b7022022-12-07 14:25:41 +01002248 /* Creates the mcli_reload listener, which is the listener used
2249 * to retrieve the master CLI session which asked for the reload.
2250 *
2251 * ipc_fd[1] will be used as a listener, and ipc_fd[0]
2252 * will be used to send the FD of the session.
2253 *
2254 * Both FDs will be kept in the master. The sockets are
2255 * created only if they weren't inherited.
2256 */
2257 if ((proc_self->ipc_fd[1] == -1) &&
2258 socketpair(AF_UNIX, SOCK_STREAM, 0, proc_self->ipc_fd) < 0) {
2259 ha_alert("cannot create the mcli_reload socketpair.\n");
2260 exit(EXIT_FAILURE);
2261 }
2262
William Lallemandec059c22022-09-22 17:26:23 +02002263 /* Create the mcli_reload listener from the proc_self struct */
2264 memprintf(&path, "sockpair@%d", proc_self->ipc_fd[1]);
William Lallemand56f73b22022-09-24 15:56:25 +02002265 mcli_reload_bind_conf = mworker_cli_proxy_new_listener(path);
2266 if (mcli_reload_bind_conf == NULL) {
William Lallemandec059c22022-09-22 17:26:23 +02002267 ha_alert("Cannot create the mcli_reload listener.\n");
2268 exit(EXIT_FAILURE);
2269 }
2270 ha_free(&path);
William Lallemand550db6d2018-11-06 17:37:12 +01002271 }
William Lallemandce83b4a2018-10-26 14:47:30 +02002272 }
2273
Eric Salama5ba83352021-03-16 15:11:17 +01002274 if (!LIST_ISEMPTY(&mworker_cli_conf) && !(arg_mode & MODE_MWORKER)) {
2275 ha_warning("a master CLI socket was defined, but master-worker mode (-W) is not enabled.\n");
2276 }
2277
Christopher Faulet27c8d202021-10-13 09:50:53 +02002278 /* destroy unreferenced defaults proxies */
2279 proxy_destroy_all_unref_defaults();
2280
William Lallemandb53eb872022-04-21 18:02:53 +02002281 list_for_each_entry(prcf, &pre_check_list, list)
2282 err_code |= prcf->fct();
Willy Tarreaue90904d2021-02-12 14:08:31 +01002283
William Lallemand8b9a2df2022-05-04 14:29:46 +02002284 if (err_code & (ERR_ABORT|ERR_FATAL)) {
2285 ha_alert("Fatal errors found in configuration.\n");
2286 exit(1);
2287 }
2288
Willy Tarreauda4aa692023-05-17 09:02:21 +02002289 /* update the ready date that will be used to count the startup time
2290 * during config checks (e.g. to schedule certain tasks if needed)
2291 */
2292 clock_update_date(0, 1);
Willy Tarreauc7b93082023-05-16 19:19:36 +02002293 clock_adjust_now_offset();
Willy Tarreauda4aa692023-05-17 09:02:21 +02002294 ready_date = date;
2295
Willy Tarreauc7b93082023-05-16 19:19:36 +02002296
Willy Tarreau57c3e752022-12-08 08:13:20 +01002297 /* Note: global.nbthread will be initialized as part of this call */
Willy Tarreaubb925012009-07-23 13:36:36 +02002298 err_code |= check_config_validity();
Willy Tarreauda4aa692023-05-17 09:02:21 +02002299
2300 /* update the ready date to also account for the check time */
2301 clock_update_date(0, 1);
Willy Tarreauc7b93082023-05-16 19:19:36 +02002302 clock_adjust_now_offset();
Willy Tarreauda4aa692023-05-17 09:02:21 +02002303 ready_date = date;
2304
Christopher Fauletc1692962019-08-12 09:51:07 +02002305 for (px = proxies_list; px; px = px->next) {
2306 struct server *srv;
2307 struct post_proxy_check_fct *ppcf;
2308 struct post_server_check_fct *pscf;
2309
Christopher Fauletdfd10ab2021-10-06 14:24:19 +02002310 if (px->flags & (PR_FL_DISABLED|PR_FL_STOPPED))
Christopher Fauletd5bd8242020-11-02 16:20:13 +01002311 continue;
2312
Christopher Fauletc1692962019-08-12 09:51:07 +02002313 list_for_each_entry(pscf, &post_server_check_list, list) {
2314 for (srv = px->srv; srv; srv = srv->next)
2315 err_code |= pscf->fct(srv);
2316 }
2317 list_for_each_entry(ppcf, &post_proxy_check_list, list)
2318 err_code |= ppcf->fct(px);
2319 }
Willy Tarreaubb925012009-07-23 13:36:36 +02002320 if (err_code & (ERR_ABORT|ERR_FATAL)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002321 ha_alert("Fatal errors found in configuration.\n");
Willy Tarreau915e1eb2009-06-22 15:48:36 +02002322 exit(1);
2323 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002324
Carl Henrik Lundef91ac192020-02-27 16:45:50 +01002325 err_code |= pattern_finalize_config();
2326 if (err_code & (ERR_ABORT|ERR_FATAL)) {
2327 ha_alert("Failed to finalize pattern config.\n");
2328 exit(1);
2329 }
Willy Tarreau0f936722019-04-11 14:47:08 +02002330
Willy Tarreau79c9bdf2021-07-17 12:31:08 +02002331 if (global.rlimit_memmax_all)
2332 global.rlimit_memmax = global.rlimit_memmax_all;
2333
Willy Tarreaue5733232019-05-22 19:24:06 +02002334#ifdef USE_NS
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01002335 err_code |= netns_init();
2336 if (err_code & (ERR_ABORT|ERR_FATAL)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002337 ha_alert("Failed to initialize namespace support.\n");
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01002338 exit(1);
2339 }
2340#endif
2341
Baptiste Assmann4215d7d2016-11-02 15:33:15 +01002342 /* Apply server states */
2343 apply_server_state();
2344
Olivier Houchardfbc74e82017-11-24 16:54:05 +01002345 for (px = proxies_list; px; px = px->next)
Baptiste Assmann4215d7d2016-11-02 15:33:15 +01002346 srv_compute_all_admin_states(px);
2347
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01002348 /* Apply servers' configured address */
2349 err_code |= srv_init_addr();
2350 if (err_code & (ERR_ABORT|ERR_FATAL)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002351 ha_alert("Failed to initialize server(s) addr.\n");
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01002352 exit(1);
2353 }
2354
Willy Tarreau3eb10b82020-04-15 16:42:39 +02002355 if (warned & WARN_ANY && global.mode & MODE_ZERO_WARNING) {
2356 ha_alert("Some warnings were found and 'zero-warning' is set. Aborting.\n");
2357 exit(1);
2358 }
2359
Willy Tarreau654726d2021-12-28 15:43:11 +01002360#if defined(HA_HAVE_DUMP_LIBS)
2361 if (global.mode & MODE_DUMP_LIBS) {
2362 qfprintf(stdout, "List of loaded object files:\n");
2363 chunk_reset(&trash);
Willy Tarreau9ef27422023-03-22 11:37:54 +01002364 if (dump_libs(&trash, ((arg_mode & (MODE_QUIET|MODE_VERBOSE)) == MODE_VERBOSE)))
Willy Tarreau654726d2021-12-28 15:43:11 +01002365 printf("%s", trash.area);
2366 }
2367#endif
2368
Willy Tarreau76871a42022-03-08 16:01:40 +01002369 if (global.mode & MODE_DUMP_KWD)
2370 dump_registered_keywords();
2371
Willy Tarreaub9bed312024-02-03 12:05:08 +01002372 if (global.mode & MODE_DIAG) {
2373 cfg_run_diagnostics();
2374 }
2375
Willy Tarreaubaaee002006-06-26 02:48:02 +02002376 if (global.mode & MODE_CHECK) {
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002377 struct peers *pr;
2378 struct proxy *px;
2379
Willy Tarreaubebd2122020-04-15 16:06:11 +02002380 if (warned & WARN_ANY)
2381 qfprintf(stdout, "Warnings were found.\n");
2382
Frédéric Lécailleed2b4a62017-07-13 09:07:09 +02002383 for (pr = cfg_peers; pr; pr = pr->next)
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002384 if (pr->peers_fe)
2385 break;
2386
Olivier Houchardfbc74e82017-11-24 16:54:05 +01002387 for (px = proxies_list; px; px = px->next)
Christopher Fauletdfd10ab2021-10-06 14:24:19 +02002388 if (!(px->flags & (PR_FL_DISABLED|PR_FL_STOPPED)) && px->li_all)
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002389 break;
2390
Emeric Brunbc5c8212021-08-13 09:32:50 +02002391 if (!px) {
2392 /* We may only have log-forward section */
2393 for (px = cfg_log_forward; px; px = px->next)
Christopher Fauletdfd10ab2021-10-06 14:24:19 +02002394 if (!(px->flags & (PR_FL_DISABLED|PR_FL_STOPPED)) && px->li_all)
Emeric Brunbc5c8212021-08-13 09:32:50 +02002395 break;
2396 }
2397
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002398 if (pr || px) {
2399 /* At least one peer or one listener has been found */
2400 qfprintf(stdout, "Configuration file is valid\n");
Tim Duesterhus0a3b43d2020-06-14 00:37:42 +02002401 deinit_and_exit(0);
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002402 }
2403 qfprintf(stdout, "Configuration file has no error but will not start (no listener) => exit(2).\n");
2404 exit(2);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002405 }
Willy Tarreaue9b26022011-08-01 20:57:55 +02002406
Erwan Le Goasb0c05012022-09-14 17:51:55 +02002407 if (global.mode & MODE_DUMP_CFG)
2408 deinit_and_exit(0);
2409
Remi Tricot-Le Breton51944462022-05-16 16:24:31 +02002410#ifdef USE_OPENSSL
William Lallemand3b8bafd2022-07-19 18:13:29 +02002411
Remi Tricot-Le Breton51944462022-05-16 16:24:31 +02002412 /* Initialize SSL random generator. Must be called before chroot for
2413 * access to /dev/urandom, and before ha_random_boot() which may use
2414 * RAND_bytes().
2415 */
2416 if (!ssl_initialize_random()) {
2417 ha_alert("OpenSSL random data generator initialization failed.\n");
2418 exit(EXIT_FAILURE);
2419 }
2420#endif
2421 ha_random_boot(argv); // the argv pointer brings some kernel-fed entropy
2422
Willy Tarreau8263d2b2012-08-28 00:06:31 +02002423 /* now we know the buffer size, we can initialize the channels and buffers */
Willy Tarreau9b28e032012-10-12 23:49:43 +02002424 init_buffer();
Willy Tarreau8280d642009-09-23 23:37:52 +02002425
Willy Tarreaue6945732016-12-21 19:57:00 +01002426 list_for_each_entry(pcf, &post_check_list, list) {
2427 err_code |= pcf->fct();
2428 if (err_code & (ERR_ABORT|ERR_FATAL))
2429 exit(1);
2430 }
2431
William Lallemand0a012aa2022-06-21 11:11:50 +02002432 /* set the default maxconn in the master, but let it be rewritable with -n */
2433 if (global.mode & MODE_MWORKER_WAIT)
William Lallemand2078d4b2023-03-09 14:28:44 +01002434 global.maxconn = MASTER_MAXCONN;
William Lallemand0a012aa2022-06-21 11:11:50 +02002435
Willy Tarreaubaaee002006-06-26 02:48:02 +02002436 if (cfg_maxconn > 0)
2437 global.maxconn = cfg_maxconn;
2438
Willy Tarreau4975d142021-03-13 11:00:33 +01002439 if (global.cli_fe)
2440 global.maxsock += global.cli_fe->maxconn;
Willy Tarreau8d687d82019-03-01 09:39:42 +01002441
2442 if (cfg_peers) {
2443 /* peers also need to bypass global maxconn */
2444 struct peers *p = cfg_peers;
2445
2446 for (p = cfg_peers; p; p = p->next)
2447 if (p->peers_fe)
2448 global.maxsock += p->peers_fe->maxconn;
2449 }
2450
Willy Tarreaud0256482015-01-15 21:45:22 +01002451 /* Now we want to compute the maxconn and possibly maxsslconn values.
Willy Tarreauac350932019-03-01 15:43:14 +01002452 * It's a bit tricky. Maxconn defaults to the pre-computed value based
2453 * on rlim_fd_cur and the number of FDs in use due to the configuration,
2454 * and maxsslconn defaults to DEFAULT_MAXSSLCONN. On top of that we can
2455 * enforce a lower limit based on memmax.
Willy Tarreaud0256482015-01-15 21:45:22 +01002456 *
2457 * If memmax is set, then it depends on which values are set. If
2458 * maxsslconn is set, we use memmax to determine how many cleartext
2459 * connections may be added, and set maxconn to the sum of the two.
2460 * If maxconn is set and not maxsslconn, maxsslconn is computed from
2461 * the remaining amount of memory between memmax and the cleartext
2462 * connections. If neither are set, then it is considered that all
2463 * connections are SSL-capable, and maxconn is computed based on this,
2464 * then maxsslconn accordingly. We need to know if SSL is used on the
2465 * frontends, backends, or both, because when it's used on both sides,
2466 * we need twice the value for maxsslconn, but we only count the
2467 * handshake once since it is not performed on the two sides at the
2468 * same time (frontend-side is terminated before backend-side begins).
2469 * The SSL stack is supposed to have filled ssl_session_cost and
Willy Tarreau474b96a2015-01-28 19:03:21 +01002470 * ssl_handshake_cost during its initialization. In any case, if
2471 * SYSTEM_MAXCONN is set, we still enforce it as an upper limit for
2472 * maxconn in order to protect the system.
Willy Tarreaud0256482015-01-15 21:45:22 +01002473 */
Willy Tarreauac350932019-03-01 15:43:14 +01002474 ideal_maxconn = compute_ideal_maxconn();
2475
Willy Tarreaud0256482015-01-15 21:45:22 +01002476 if (!global.rlimit_memmax) {
2477 if (global.maxconn == 0) {
Willy Tarreauac350932019-03-01 15:43:14 +01002478 global.maxconn = ideal_maxconn;
Willy Tarreaud0256482015-01-15 21:45:22 +01002479 if (global.mode & (MODE_VERBOSE|MODE_DEBUG))
2480 fprintf(stderr, "Note: setting global.maxconn to %d.\n", global.maxconn);
2481 }
2482 }
2483#ifdef USE_OPENSSL
2484 else if (!global.maxconn && !global.maxsslconn &&
2485 (global.ssl_used_frontend || global.ssl_used_backend)) {
2486 /* memmax is set, compute everything automatically. Here we want
2487 * to ensure that all SSL connections will be served. We take
2488 * care of the number of sides where SSL is used, and consider
2489 * the worst case : SSL used on both sides and doing a handshake
2490 * simultaneously. Note that we can't have more than maxconn
2491 * handshakes at a time by definition, so for the worst case of
2492 * two SSL conns per connection, we count a single handshake.
2493 */
2494 int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
2495 int64_t mem = global.rlimit_memmax * 1048576ULL;
Willy Tarreau304e17e2020-03-10 17:54:54 +01002496 int retried = 0;
Willy Tarreaud0256482015-01-15 21:45:22 +01002497
Willy Tarreau2cb3be72022-05-24 07:43:57 +02002498 mem -= global.tune.sslcachesize * 200ULL; // about 200 bytes per SSL cache entry
Willy Tarreaud0256482015-01-15 21:45:22 +01002499 mem -= global.maxzlibmem;
2500 mem = mem * MEM_USABLE_RATIO;
2501
Willy Tarreau304e17e2020-03-10 17:54:54 +01002502 /* Principle: we test once to set maxconn according to the free
2503 * memory. If it results in values the system rejects, we try a
2504 * second time by respecting rlim_fd_max. If it fails again, we
2505 * go back to the initial value and will let the final code
2506 * dealing with rlimit report the error. That's up to 3 attempts.
2507 */
2508 do {
2509 global.maxconn = mem /
2510 ((STREAM_MAX_COST + 2 * global.tune.bufsize) + // stream + 2 buffers per stream
2511 sides * global.ssl_session_max_cost + // SSL buffers, one per side
2512 global.ssl_handshake_max_cost); // 1 handshake per connection max
Willy Tarreaud0256482015-01-15 21:45:22 +01002513
Willy Tarreau304e17e2020-03-10 17:54:54 +01002514 if (retried == 1)
2515 global.maxconn = MIN(global.maxconn, ideal_maxconn);
2516 global.maxconn = round_2dig(global.maxconn);
Willy Tarreau474b96a2015-01-28 19:03:21 +01002517#ifdef SYSTEM_MAXCONN
Willy Tarreau304e17e2020-03-10 17:54:54 +01002518 if (global.maxconn > SYSTEM_MAXCONN)
2519 global.maxconn = SYSTEM_MAXCONN;
Willy Tarreau474b96a2015-01-28 19:03:21 +01002520#endif /* SYSTEM_MAXCONN */
Willy Tarreau304e17e2020-03-10 17:54:54 +01002521 global.maxsslconn = sides * global.maxconn;
2522
2523 if (check_if_maxsock_permitted(compute_ideal_maxsock(global.maxconn)))
2524 break;
2525 } while (retried++ < 2);
2526
Willy Tarreaud0256482015-01-15 21:45:22 +01002527 if (global.mode & (MODE_VERBOSE|MODE_DEBUG))
2528 fprintf(stderr, "Note: setting global.maxconn to %d and global.maxsslconn to %d.\n",
2529 global.maxconn, global.maxsslconn);
2530 }
2531 else if (!global.maxsslconn &&
2532 (global.ssl_used_frontend || global.ssl_used_backend)) {
2533 /* memmax and maxconn are known, compute maxsslconn automatically.
2534 * maxsslconn being forced, we don't know how many of it will be
2535 * on each side if both sides are being used. The worst case is
2536 * when all connections use only one SSL instance because
2537 * handshakes may be on two sides at the same time.
2538 */
2539 int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
2540 int64_t mem = global.rlimit_memmax * 1048576ULL;
2541 int64_t sslmem;
2542
Willy Tarreau8e5b9582022-05-26 08:55:05 +02002543 mem -= global.tune.sslcachesize * 200ULL; // about 200 bytes per SSL cache entry
Willy Tarreaud0256482015-01-15 21:45:22 +01002544 mem -= global.maxzlibmem;
2545 mem = mem * MEM_USABLE_RATIO;
2546
Willy Tarreau87b09662015-04-03 00:22:06 +02002547 sslmem = mem - global.maxconn * (int64_t)(STREAM_MAX_COST + 2 * global.tune.bufsize);
Willy Tarreaud0256482015-01-15 21:45:22 +01002548 global.maxsslconn = sslmem / (global.ssl_session_max_cost + global.ssl_handshake_max_cost);
2549 global.maxsslconn = round_2dig(global.maxsslconn);
2550
2551 if (sslmem <= 0 || global.maxsslconn < sides) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002552 ha_alert("Cannot compute the automatic maxsslconn because global.maxconn is already too "
2553 "high for the global.memmax value (%d MB). The absolute maximum possible value "
2554 "without SSL is %d, but %d was found and SSL is in use.\n",
2555 global.rlimit_memmax,
2556 (int)(mem / (STREAM_MAX_COST + 2 * global.tune.bufsize)),
2557 global.maxconn);
Willy Tarreaud0256482015-01-15 21:45:22 +01002558 exit(1);
2559 }
2560
2561 if (global.maxsslconn > sides * global.maxconn)
2562 global.maxsslconn = sides * global.maxconn;
2563
2564 if (global.mode & (MODE_VERBOSE|MODE_DEBUG))
2565 fprintf(stderr, "Note: setting global.maxsslconn to %d\n", global.maxsslconn);
2566 }
2567#endif
2568 else if (!global.maxconn) {
2569 /* memmax and maxsslconn are known/unused, compute maxconn automatically */
2570 int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
2571 int64_t mem = global.rlimit_memmax * 1048576ULL;
2572 int64_t clearmem;
Willy Tarreau304e17e2020-03-10 17:54:54 +01002573 int retried = 0;
Willy Tarreaud0256482015-01-15 21:45:22 +01002574
2575 if (global.ssl_used_frontend || global.ssl_used_backend)
Willy Tarreau8e5b9582022-05-26 08:55:05 +02002576 mem -= global.tune.sslcachesize * 200ULL; // about 200 bytes per SSL cache entry
Willy Tarreaud0256482015-01-15 21:45:22 +01002577
2578 mem -= global.maxzlibmem;
2579 mem = mem * MEM_USABLE_RATIO;
2580
2581 clearmem = mem;
2582 if (sides)
2583 clearmem -= (global.ssl_session_max_cost + global.ssl_handshake_max_cost) * (int64_t)global.maxsslconn;
2584
Willy Tarreau304e17e2020-03-10 17:54:54 +01002585 /* Principle: we test once to set maxconn according to the free
2586 * memory. If it results in values the system rejects, we try a
2587 * second time by respecting rlim_fd_max. If it fails again, we
2588 * go back to the initial value and will let the final code
2589 * dealing with rlimit report the error. That's up to 3 attempts.
2590 */
2591 do {
2592 global.maxconn = clearmem / (STREAM_MAX_COST + 2 * global.tune.bufsize);
2593 if (retried == 1)
2594 global.maxconn = MIN(global.maxconn, ideal_maxconn);
2595 global.maxconn = round_2dig(global.maxconn);
Willy Tarreau474b96a2015-01-28 19:03:21 +01002596#ifdef SYSTEM_MAXCONN
Willy Tarreau304e17e2020-03-10 17:54:54 +01002597 if (global.maxconn > SYSTEM_MAXCONN)
2598 global.maxconn = SYSTEM_MAXCONN;
Willy Tarreau474b96a2015-01-28 19:03:21 +01002599#endif /* SYSTEM_MAXCONN */
Willy Tarreaud0256482015-01-15 21:45:22 +01002600
Willy Tarreau304e17e2020-03-10 17:54:54 +01002601 if (clearmem <= 0 || !global.maxconn) {
2602 ha_alert("Cannot compute the automatic maxconn because global.maxsslconn is already too "
2603 "high for the global.memmax value (%d MB). The absolute maximum possible value "
2604 "is %d, but %d was found.\n",
2605 global.rlimit_memmax,
Christopher Faulet767a84b2017-11-24 16:50:31 +01002606 (int)(mem / (global.ssl_session_max_cost + global.ssl_handshake_max_cost)),
Willy Tarreau304e17e2020-03-10 17:54:54 +01002607 global.maxsslconn);
2608 exit(1);
2609 }
2610
2611 if (check_if_maxsock_permitted(compute_ideal_maxsock(global.maxconn)))
2612 break;
2613 } while (retried++ < 2);
Willy Tarreaud0256482015-01-15 21:45:22 +01002614
2615 if (global.mode & (MODE_VERBOSE|MODE_DEBUG)) {
2616 if (sides && global.maxsslconn > sides * global.maxconn) {
2617 fprintf(stderr, "Note: global.maxsslconn is forced to %d which causes global.maxconn "
2618 "to be limited to %d. Better reduce global.maxsslconn to get more "
2619 "room for extra connections.\n", global.maxsslconn, global.maxconn);
2620 }
2621 fprintf(stderr, "Note: setting global.maxconn to %d\n", global.maxconn);
2622 }
Willy Tarreau66aa61f2009-01-18 21:44:07 +01002623 }
2624
Willy Tarreaua409f302020-03-10 17:08:53 +01002625 global.maxsock = compute_ideal_maxsock(global.maxconn);
2626 global.hardmaxconn = global.maxconn;
Willy Tarreaua4818db2020-06-19 16:20:59 +02002627 if (!global.maxpipes)
2628 global.maxpipes = compute_ideal_maxpipes();
Willy Tarreaubaaee002006-06-26 02:48:02 +02002629
Olivier Houchard88698d92019-04-16 19:07:22 +02002630 /* update connection pool thresholds */
2631 global.tune.pool_low_count = ((long long)global.maxsock * global.tune.pool_low_ratio + 99) / 100;
2632 global.tune.pool_high_count = ((long long)global.maxsock * global.tune.pool_high_ratio + 99) / 100;
2633
Willy Tarreauc8d5b952019-02-27 17:25:52 +01002634 proxy_adjust_all_maxconn();
2635
Willy Tarreau1db37712007-06-03 17:16:49 +02002636 if (global.tune.maxpollevents <= 0)
2637 global.tune.maxpollevents = MAX_POLL_EVENTS;
2638
Willy Tarreau060a7612021-03-10 11:06:26 +01002639 if (global.tune.runqueue_depth <= 0) {
2640 /* tests on various thread counts from 1 to 64 have shown an
2641 * optimal queue depth following roughly 1/sqrt(threads).
2642 */
2643 int s = my_flsl(global.nbthread);
2644 s += (global.nbthread / s); // roughly twice the sqrt.
2645 global.tune.runqueue_depth = RUNQUEUE_DEPTH * 2 / s;
2646 }
Olivier Houchard1599b802018-05-24 18:59:04 +02002647
Willy Tarreau6f4a82c2009-03-21 20:43:57 +01002648 if (global.tune.recv_enough == 0)
2649 global.tune.recv_enough = MIN_RECV_AT_ONCE_ENOUGH;
2650
Willy Tarreau27a674e2009-08-17 07:23:33 +02002651 if (global.tune.maxrewrite >= global.tune.bufsize / 2)
2652 global.tune.maxrewrite = global.tune.bufsize / 2;
2653
Amaury Denoyelle11124302021-06-04 18:22:08 +02002654 usermsgs_clr(NULL);
2655
Willy Tarreaubaaee002006-06-26 02:48:02 +02002656 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
2657 /* command line debug mode inhibits configuration mode */
William Lallemand095ba4c2017-06-01 17:38:50 +02002658 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
Willy Tarreau772f0dd2012-10-26 16:04:28 +02002659 global.mode |= (arg_mode & (MODE_DEBUG | MODE_FOREGROUND));
2660 }
2661
William Lallemand095ba4c2017-06-01 17:38:50 +02002662 if (arg_mode & MODE_DAEMON) {
Willy Tarreau772f0dd2012-10-26 16:04:28 +02002663 /* command line daemon mode inhibits foreground and debug modes mode */
2664 global.mode &= ~(MODE_DEBUG | MODE_FOREGROUND);
William Lallemand095ba4c2017-06-01 17:38:50 +02002665 global.mode |= arg_mode & MODE_DAEMON;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002666 }
Willy Tarreau772f0dd2012-10-26 16:04:28 +02002667
2668 global.mode |= (arg_mode & (MODE_QUIET | MODE_VERBOSE));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002669
William Lallemand095ba4c2017-06-01 17:38:50 +02002670 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002671 ha_warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
William Lallemand095ba4c2017-06-01 17:38:50 +02002672 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002673 }
2674
Christopher Faulet3ef26392017-08-29 16:46:57 +02002675 /* Realloc trash buffers because global.tune.bufsize may have changed */
Christopher Fauletcd7879a2017-10-27 13:53:47 +02002676 if (!init_trash_buffers(0)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002677 ha_alert("failed to initialize trash buffers.\n");
Christopher Faulet3ef26392017-08-29 16:46:57 +02002678 exit(1);
2679 }
2680
Christopher Faulet96d44832017-11-14 22:02:30 +01002681 if (!init_log_buffers()) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002682 ha_alert("failed to initialize log buffers.\n");
Christopher Faulet96d44832017-11-14 22:02:30 +01002683 exit(1);
2684 }
2685
Frédéric Lécaille0499db42023-09-07 18:43:52 +02002686 if (!cluster_secret_isset)
Amaury Denoyelle28ea31c2022-11-14 16:18:46 +01002687 generate_random_cluster_secret();
2688
Willy Tarreauef1d1f82007-04-16 00:25:25 +02002689 /*
2690 * Note: we could register external pollers here.
2691 * Built-in pollers have been registered before main().
2692 */
Willy Tarreau4f60f162007-04-08 16:39:58 +02002693
Willy Tarreau43b78992009-01-25 15:42:27 +01002694 if (!(global.tune.options & GTUNE_USE_KQUEUE))
Willy Tarreau1e63130a2007-04-09 12:03:06 +02002695 disable_poller("kqueue");
2696
Emmanuel Hocdet0ba4f482019-04-08 16:53:32 +00002697 if (!(global.tune.options & GTUNE_USE_EVPORTS))
2698 disable_poller("evports");
2699
Willy Tarreau43b78992009-01-25 15:42:27 +01002700 if (!(global.tune.options & GTUNE_USE_EPOLL))
Willy Tarreau4f60f162007-04-08 16:39:58 +02002701 disable_poller("epoll");
2702
Willy Tarreau43b78992009-01-25 15:42:27 +01002703 if (!(global.tune.options & GTUNE_USE_POLL))
Willy Tarreau4f60f162007-04-08 16:39:58 +02002704 disable_poller("poll");
2705
Willy Tarreau43b78992009-01-25 15:42:27 +01002706 if (!(global.tune.options & GTUNE_USE_SELECT))
Willy Tarreau4f60f162007-04-08 16:39:58 +02002707 disable_poller("select");
2708
2709 /* Note: we could disable any poller by name here */
2710
Christopher Fauletb3f4e142016-03-07 12:46:38 +01002711 if (global.mode & (MODE_VERBOSE|MODE_DEBUG)) {
Willy Tarreau2ff76222007-04-09 19:29:56 +02002712 list_pollers(stderr);
Christopher Fauletb3f4e142016-03-07 12:46:38 +01002713 fprintf(stderr, "\n");
2714 list_filters(stderr);
2715 }
Willy Tarreau2ff76222007-04-09 19:29:56 +02002716
Willy Tarreau4f60f162007-04-08 16:39:58 +02002717 if (!init_pollers()) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002718 ha_alert("No polling mechanism available.\n"
Willy Tarreaue5715bf2022-07-09 23:38:46 +02002719 " This may happen when using thread-groups with old pollers (poll/select), or\n"
2720 " it is possible that haproxy was built with TARGET=generic and that FD_SETSIZE\n"
Christopher Faulet767a84b2017-11-24 16:50:31 +01002721 " is too low on this platform to support maxconn and the number of listeners\n"
2722 " and servers. You should rebuild haproxy specifying your system using TARGET=\n"
2723 " in order to support other polling systems (poll, epoll, kqueue) or reduce the\n"
2724 " global maxconn setting to accommodate the system's limitation. For reference,\n"
2725 " FD_SETSIZE=%d on this system, global.maxconn=%d resulting in a maximum of\n"
2726 " %d file descriptors. You should thus reduce global.maxconn by %d. Also,\n"
2727 " check build settings using 'haproxy -vv'.\n\n",
2728 FD_SETSIZE, global.maxconn, global.maxsock, (global.maxsock + 1 - FD_SETSIZE) / 2);
Willy Tarreau4f60f162007-04-08 16:39:58 +02002729 exit(1);
2730 }
Willy Tarreau2ff76222007-04-09 19:29:56 +02002731 if (global.mode & (MODE_VERBOSE|MODE_DEBUG)) {
2732 printf("Using %s() as the polling mechanism.\n", cur_poller.name);
Willy Tarreau4f60f162007-04-08 16:39:58 +02002733 }
2734
Krzysztof Piotr Oledzki48cb2ae2009-10-02 22:51:14 +02002735 if (!global.node)
2736 global.node = strdup(hostname);
2737
Willy Tarreau02b092f2020-10-07 18:36:54 +02002738 /* stop disabled proxies */
2739 for (px = proxies_list; px; px = px->next) {
Christopher Fauletdfd10ab2021-10-06 14:24:19 +02002740 if (px->flags & (PR_FL_DISABLED|PR_FL_STOPPED))
Willy Tarreau02b092f2020-10-07 18:36:54 +02002741 stop_proxy(px);
2742 }
2743
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01002744 if (!hlua_post_init())
2745 exit(1);
Willy Tarreau284cfc62022-12-19 08:15:57 +01002746
2747 /* Set the per-thread pool cache size to the default value if not set.
2748 * This is the right place to decide to automatically adjust it (e.g.
2749 * check L2 cache size, thread counts or take into account certain
2750 * expensive pools).
2751 */
2752 if (!global.tune.pool_cache_size)
2753 global.tune.pool_cache_size = CONFIG_HAP_POOL_CACHE_SIZE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002754}
2755
Cyril Bonté203ec5a2017-03-23 22:44:13 +01002756void deinit(void)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002757{
Olivier Houchardfbc74e82017-11-24 16:54:05 +01002758 struct proxy *p = proxies_list, *p0;
Willy Tarreaudeb9ed82010-01-03 21:03:22 +01002759 struct wordlist *wl, *wlb;
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002760 struct uri_auth *uap, *ua = NULL;
William Lallemand0f99e342011-10-12 17:50:54 +02002761 struct logsrv *log, *logb;
Willy Tarreaucdb737e2016-12-21 18:43:10 +01002762 struct build_opts_str *bol, *bolb;
Tim Duesterhusfdf904a2020-07-04 11:49:48 +02002763 struct post_deinit_fct *pdf, *pdfb;
Tim Duesterhus17e363f2020-07-04 11:49:47 +02002764 struct proxy_deinit_fct *pxdf, *pxdfb;
Tim Duesterhus0837eb12020-07-04 11:49:49 +02002765 struct server_deinit_fct *srvdf, *srvdfb;
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002766 struct per_thread_init_fct *tif, *tifb;
2767 struct per_thread_deinit_fct *tdf, *tdfb;
2768 struct per_thread_alloc_fct *taf, *tafb;
2769 struct per_thread_free_fct *tff, *tffb;
Tim Duesterhus34bef072020-07-04 11:49:50 +02002770 struct post_server_check_fct *pscf, *pscfb;
Tim Duesterhusfc854942020-09-10 19:46:42 +02002771 struct post_check_fct *pcf, *pcfb;
Tim Duesterhus53508d62020-09-10 19:46:40 +02002772 struct post_proxy_check_fct *ppcf, *ppcfb;
Willy Tarreau65009eb2022-04-27 18:02:54 +02002773 struct pre_check_fct *prcf, *prcfb;
Willy Tarreau226866e2022-04-27 18:07:24 +02002774 struct cfg_postparser *pprs, *pprsb;
Willy Tarreauae7bc4a2020-09-23 16:46:22 +02002775 int cur_fd;
2776
Willy Tarreaue98d3852022-11-15 09:34:07 +01002777 /* the user may want to skip this phase */
2778 if (global.tune.options & GTUNE_QUICK_EXIT)
2779 return;
2780
Willy Tarreauae7bc4a2020-09-23 16:46:22 +02002781 /* At this point the listeners state is weird:
2782 * - most listeners are still bound and referenced in their protocol
2783 * - some might be zombies that are not in their proto anymore, but
2784 * still appear in their proxy's listeners with a valid FD.
2785 * - some might be stopped and still appear in their proxy as FD #-1
2786 * - among all of them, some might be inherited hence shared and we're
2787 * not allowed to pause them or whatever, we must just close them.
2788 * - finally some are not listeners (pipes, logs, stdout, etc) and
2789 * must be left intact.
2790 *
2791 * The safe way to proceed is to unbind (and close) whatever is not yet
2792 * unbound so that no more receiver/listener remains alive. Then close
2793 * remaining listener FDs, which correspond to zombie listeners (those
2794 * belonging to disabled proxies that were in another process).
2795 * objt_listener() would be cleaner here but not converted yet.
2796 */
2797 protocol_unbind_all();
2798
2799 for (cur_fd = 0; cur_fd < global.maxsock; cur_fd++) {
Willy Tarreau1a3770c2020-10-14 12:13:51 +02002800 if (!fdtab || !fdtab[cur_fd].owner)
Willy Tarreauae7bc4a2020-09-23 16:46:22 +02002801 continue;
2802
Willy Tarreaua74cb382020-10-15 21:29:49 +02002803 if (fdtab[cur_fd].iocb == &sock_accept_iocb) {
Willy Tarreauae7bc4a2020-09-23 16:46:22 +02002804 struct listener *l = fdtab[cur_fd].owner;
2805
2806 BUG_ON(l->state != LI_INIT);
2807 unbind_listener(l);
2808 }
2809 }
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002810
Willy Tarreau24f4efa2010-08-27 17:56:48 +02002811 deinit_signals();
Willy Tarreaubaaee002006-06-26 02:48:02 +02002812 while (p) {
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002813 /* build a list of unique uri_auths */
2814 if (!ua)
2815 ua = p->uri_auth;
2816 else {
2817 /* check if p->uri_auth is unique */
2818 for (uap = ua; uap; uap=uap->next)
2819 if (uap == p->uri_auth)
2820 break;
2821
Willy Tarreauaccc4e12008-06-24 11:14:45 +02002822 if (!uap && p->uri_auth) {
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002823 /* add it, if it is */
2824 p->uri_auth->next = ua;
2825 ua = p->uri_auth;
2826 }
William Lallemand0f99e342011-10-12 17:50:54 +02002827 }
2828
Willy Tarreau4d2d0982007-05-14 00:39:29 +02002829 p0 = p;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002830 p = p->next;
Amaury Denoyelle27fefa12021-03-24 16:13:20 +01002831 free_proxy(p0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002832 }/* end while(p) */
Willy Tarreaudd815982007-10-16 12:25:14 +02002833
Aurelien DARRAGON9b1d15f2023-03-09 12:07:09 +01002834 /* we don't need to free sink_proxies_list proxies since it is
2835 * already handled in sink_deinit()
2836 */
Aurelien DARRAGONcca33552023-03-09 12:21:12 +01002837 p = cfg_log_forward;
2838 /* we need to manually clean cfg_log_forward proxy list */
2839 while (p) {
2840 p0 = p;
2841 p = p->next;
2842 free_proxy(p0);
2843 }
Aurelien DARRAGON9b1d15f2023-03-09 12:07:09 +01002844
Christopher Faulet27c8d202021-10-13 09:50:53 +02002845 /* destroy all referenced defaults proxies */
2846 proxy_destroy_all_unref_defaults();
2847
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002848 while (ua) {
Tim Duesterhus00f00cf2020-09-10 19:46:38 +02002849 struct stat_scope *scope, *scopep;
2850
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002851 uap = ua;
2852 ua = ua->next;
2853
Willy Tarreaua534fea2008-08-03 12:19:50 +02002854 free(uap->uri_prefix);
2855 free(uap->auth_realm);
Krzysztof Piotr Oledzki48cb2ae2009-10-02 22:51:14 +02002856 free(uap->node);
2857 free(uap->desc);
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002858
Krzysztof Piotr Oledzki8c8bd452010-01-29 19:29:32 +01002859 userlist_free(uap->userlist);
Amaury Denoyelle68fd7e42021-03-25 17:15:52 +01002860 free_act_rules(&uap->http_req_rules);
Krzysztof Piotr Oledzki8c8bd452010-01-29 19:29:32 +01002861
Tim Duesterhus00f00cf2020-09-10 19:46:38 +02002862 scope = uap->scope;
2863 while (scope) {
2864 scopep = scope;
2865 scope = scope->next;
2866
2867 free(scopep->px_id);
2868 free(scopep);
2869 }
2870
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002871 free(uap);
2872 }
2873
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +01002874 userlist_free(userlist);
2875
David Carlier834cb2e2015-09-25 12:02:25 +01002876 cfg_unregister_sections();
2877
Christopher Faulet0132d062017-07-26 15:33:35 +02002878 deinit_log_buffers();
David Carlier834cb2e2015-09-25 12:02:25 +01002879
Willy Tarreau05554e62016-12-21 20:46:26 +01002880 list_for_each_entry(pdf, &post_deinit_list, list)
2881 pdf->fct();
2882
Willy Tarreau61cfdf42021-02-20 10:46:51 +01002883 ha_free(&global.log_send_hostname);
Dragan Dosen43885c72015-10-01 13:18:13 +02002884 chunk_destroy(&global.log_tag);
Willy Tarreau61cfdf42021-02-20 10:46:51 +01002885 ha_free(&global.chroot);
2886 ha_free(&global.pidfile);
2887 ha_free(&global.node);
2888 ha_free(&global.desc);
2889 ha_free(&oldpids);
2890 ha_free(&old_argv);
2891 ha_free(&localpeer);
2892 ha_free(&global.server_state_base);
2893 ha_free(&global.server_state_file);
Olivier Houchard3f795f72019-04-17 22:51:06 +02002894 task_destroy(idle_conn_task);
Olivier Houchard9ea5d362019-02-14 18:29:09 +01002895 idle_conn_task = NULL;
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002896
William Lallemand0f99e342011-10-12 17:50:54 +02002897 list_for_each_entry_safe(log, logb, &global.logsrvs, list) {
Willy Tarreau2c701db2023-01-26 15:32:12 +01002898 LIST_DEL_INIT(&log->list);
2899 free_logsrv(log);
2900 }
2901
Willy Tarreau477ecd82010-01-03 21:12:30 +01002902 list_for_each_entry_safe(wl, wlb, &cfg_cfgfiles, list) {
Maxime de Roucy0f503922016-05-13 23:52:55 +02002903 free(wl->s);
Willy Tarreau2b718102021-04-21 07:32:39 +02002904 LIST_DELETE(&wl->list);
Willy Tarreau477ecd82010-01-03 21:12:30 +01002905 free(wl);
2906 }
2907
Willy Tarreaucdb737e2016-12-21 18:43:10 +01002908 list_for_each_entry_safe(bol, bolb, &build_opts_list, list) {
2909 if (bol->must_free)
2910 free((void *)bol->str);
Willy Tarreau2b718102021-04-21 07:32:39 +02002911 LIST_DELETE(&bol->list);
Willy Tarreaucdb737e2016-12-21 18:43:10 +01002912 free(bol);
2913 }
2914
Tim Duesterhus17e363f2020-07-04 11:49:47 +02002915 list_for_each_entry_safe(pxdf, pxdfb, &proxy_deinit_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002916 LIST_DELETE(&pxdf->list);
Tim Duesterhus17e363f2020-07-04 11:49:47 +02002917 free(pxdf);
2918 }
2919
Tim Duesterhusfdf904a2020-07-04 11:49:48 +02002920 list_for_each_entry_safe(pdf, pdfb, &post_deinit_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002921 LIST_DELETE(&pdf->list);
Tim Duesterhusfdf904a2020-07-04 11:49:48 +02002922 free(pdf);
2923 }
2924
Tim Duesterhus0837eb12020-07-04 11:49:49 +02002925 list_for_each_entry_safe(srvdf, srvdfb, &server_deinit_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002926 LIST_DELETE(&srvdf->list);
Tim Duesterhus0837eb12020-07-04 11:49:49 +02002927 free(srvdf);
2928 }
2929
Tim Duesterhusfc854942020-09-10 19:46:42 +02002930 list_for_each_entry_safe(pcf, pcfb, &post_check_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002931 LIST_DELETE(&pcf->list);
Tim Duesterhusfc854942020-09-10 19:46:42 +02002932 free(pcf);
2933 }
2934
Tim Duesterhus34bef072020-07-04 11:49:50 +02002935 list_for_each_entry_safe(pscf, pscfb, &post_server_check_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002936 LIST_DELETE(&pscf->list);
Tim Duesterhus34bef072020-07-04 11:49:50 +02002937 free(pscf);
2938 }
2939
Tim Duesterhus53508d62020-09-10 19:46:40 +02002940 list_for_each_entry_safe(ppcf, ppcfb, &post_proxy_check_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002941 LIST_DELETE(&ppcf->list);
Tim Duesterhus53508d62020-09-10 19:46:40 +02002942 free(ppcf);
2943 }
2944
Willy Tarreau65009eb2022-04-27 18:02:54 +02002945 list_for_each_entry_safe(prcf, prcfb, &pre_check_list, list) {
2946 LIST_DELETE(&prcf->list);
2947 free(prcf);
2948 }
2949
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002950 list_for_each_entry_safe(tif, tifb, &per_thread_init_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002951 LIST_DELETE(&tif->list);
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002952 free(tif);
2953 }
2954
2955 list_for_each_entry_safe(tdf, tdfb, &per_thread_deinit_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002956 LIST_DELETE(&tdf->list);
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002957 free(tdf);
2958 }
2959
2960 list_for_each_entry_safe(taf, tafb, &per_thread_alloc_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002961 LIST_DELETE(&taf->list);
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002962 free(taf);
2963 }
2964
2965 list_for_each_entry_safe(tff, tffb, &per_thread_free_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002966 LIST_DELETE(&tff->list);
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002967 free(tff);
2968 }
2969
Willy Tarreau226866e2022-04-27 18:07:24 +02002970 list_for_each_entry_safe(pprs, pprsb, &postparsers, list) {
2971 LIST_DELETE(&pprs->list);
2972 free(pprs);
2973 }
2974
Willy Tarreaucfc4f242021-05-08 11:41:28 +02002975 vars_prune(&proc_vars, NULL, NULL);
Willy Tarreau2455ceb2018-11-26 15:57:34 +01002976 pool_destroy_all();
Krzysztof Piotr Oledzkia643baf2008-05-29 23:53:44 +02002977 deinit_pollers();
Willy Tarreaubaaee002006-06-26 02:48:02 +02002978} /* end deinit() */
2979
Willy Tarreauf3ca5a02020-06-15 18:43:46 +02002980__attribute__((noreturn)) void deinit_and_exit(int status)
Tim Duesterhus26540552020-06-14 00:37:41 +02002981{
Amaury Denoyelle7afa5c12021-08-09 15:02:56 +02002982 global.mode |= MODE_STOPPING;
Tim Duesterhus26540552020-06-14 00:37:41 +02002983 deinit();
2984 exit(status);
2985}
William Lallemand72160322018-11-06 17:37:16 +01002986
Willy Tarreau918ff602011-07-25 16:33:49 +02002987/* Runs the polling loop */
Willy Tarreau3ebd55e2020-03-03 14:59:56 +01002988void run_poll_loop()
Willy Tarreau4f60f162007-04-08 16:39:58 +02002989{
Willy Tarreau2ae84e42019-05-28 16:44:05 +02002990 int next, wake;
Willy Tarreau4f60f162007-04-08 16:39:58 +02002991
Willy Tarreau3e820a12023-02-17 08:36:42 +01002992 _HA_ATOMIC_OR(&th_ctx->flags, TH_FL_IN_LOOP);
2993
Willy Tarreau55542642021-10-08 09:33:24 +02002994 clock_update_date(0,1);
Willy Tarreau4f60f162007-04-08 16:39:58 +02002995 while (1) {
Willy Tarreauc49ba522019-12-11 08:12:23 +01002996 wake_expired_tasks();
2997
William Lallemand1aab50b2018-06-07 09:46:01 +02002998 /* check if we caught some signals and process them in the
2999 first thread */
Willy Tarreaua7ad4ae2020-06-19 12:06:34 +02003000 if (signal_queue_len && tid == 0) {
3001 activity[tid].wake_signal++;
William Lallemand1aab50b2018-06-07 09:46:01 +02003002 signal_process_queue();
Willy Tarreaua7ad4ae2020-06-19 12:06:34 +02003003 }
3004
3005 /* Process a few tasks */
3006 process_runnable_tasks();
Willy Tarreau29857942009-05-10 09:01:21 +02003007
Willy Tarreau7067b3a2019-06-02 11:11:29 +02003008 /* also stop if we failed to cleanly stop all tasks */
3009 if (killed > 1)
3010 break;
3011
Matthias Wirtheea152e2022-09-09 10:21:00 +02003012 /* expire immediately if events or signals are pending */
Willy Tarreau2ae84e42019-05-28 16:44:05 +02003013 wake = 1;
Olivier Houchard305d5ab2019-07-24 18:07:06 +02003014 if (thread_has_tasks())
Willy Tarreaud80cb4e2018-01-20 19:30:13 +01003015 activity[tid].wake_tasks++;
Olivier Houchard79321b92018-07-26 17:55:11 +02003016 else {
Willy Tarreaue7475c82022-06-20 09:23:24 +02003017 _HA_ATOMIC_OR(&th_ctx->flags, TH_FL_SLEEPING);
Willy Tarreaudce4ad72022-06-22 15:38:38 +02003018 _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_NOTIFIED);
Olivier Houchardb23a61f2019-03-08 18:51:17 +01003019 __ha_barrier_atomic_store();
Willy Tarreau95abd5b2020-03-23 09:33:32 +01003020 if (thread_has_tasks()) {
Olivier Houchard79321b92018-07-26 17:55:11 +02003021 activity[tid].wake_tasks++;
Willy Tarreaue7475c82022-06-20 09:23:24 +02003022 _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_SLEEPING);
Valentine Krasnobaevac58e4a42024-05-06 14:24:41 +02003023 } else if (signal_queue_len && tid == 0) {
Matthias Wirtheea152e2022-09-09 10:21:00 +02003024 /* this check is required after setting TH_FL_SLEEPING to avoid
3025 * a race with wakeup on signals using wake_threads() */
3026 _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_SLEEPING);
Olivier Houchard79321b92018-07-26 17:55:11 +02003027 } else
Willy Tarreau2ae84e42019-05-28 16:44:05 +02003028 wake = 0;
Olivier Houchard79321b92018-07-26 17:55:11 +02003029 }
Willy Tarreau10146c92015-04-13 20:44:19 +02003030
Willy Tarreau4f46a352020-03-23 09:27:28 +01003031 if (!wake) {
Willy Tarreaud7a6b2f2020-05-13 13:51:01 +02003032 int i;
3033
3034 if (stopping) {
Amaury Denoyelle5907fed2023-03-08 10:37:45 +01003035 /* stop muxes/quic-conns before acknowledging stopping */
Willy Tarreau24cfc9f2022-07-04 14:07:29 +02003036 if (!(tg_ctx->stopping_threads & ti->ltid_bit)) {
Amaury Denoyelled3a88c12021-05-03 10:47:51 +02003037 task_wakeup(mux_stopping_data[tid].task, TASK_WOKEN_OTHER);
Amaury Denoyelle5907fed2023-03-08 10:37:45 +01003038#ifdef USE_QUIC
3039 quic_handle_stopping();
3040#endif
Amaury Denoyelled3a88c12021-05-03 10:47:51 +02003041 wake = 1;
3042 }
3043
Willy Tarreauef422ce2022-06-28 19:29:29 +02003044 if (_HA_ATOMIC_OR_FETCH(&tg_ctx->stopping_threads, ti->ltid_bit) == ti->ltid_bit &&
3045 _HA_ATOMIC_OR_FETCH(&stopping_tgroup_mask, tg->tgid_bit) == tg->tgid_bit) {
3046 /* first one to detect it, notify all threads that stopping was just set */
3047 for (i = 0; i < global.nbthread; i++) {
Willy Tarreaub2f38c12023-01-19 19:14:18 +01003048 if (_HA_ATOMIC_LOAD(&ha_thread_info[i].tg->threads_enabled) &
Willy Tarreauef422ce2022-06-28 19:29:29 +02003049 ha_thread_info[i].ltid_bit &
3050 ~_HA_ATOMIC_LOAD(&ha_thread_info[i].tg_ctx->stopping_threads))
Willy Tarreaud6455742020-05-13 14:30:25 +02003051 wake_thread(i);
Willy Tarreauef422ce2022-06-28 19:29:29 +02003052 }
Willy Tarreaud6455742020-05-13 14:30:25 +02003053 }
Willy Tarreaud7a6b2f2020-05-13 13:51:01 +02003054 }
Willy Tarreau4f46a352020-03-23 09:27:28 +01003055
3056 /* stop when there's nothing left to do */
3057 if ((jobs - unstoppable_jobs) == 0 &&
Willy Tarreauef422ce2022-06-28 19:29:29 +02003058 (_HA_ATOMIC_LOAD(&stopping_tgroup_mask) & all_tgroups_mask) == all_tgroups_mask) {
3059 /* check that all threads are aware of the stopping status */
3060 for (i = 0; i < global.nbtgroups; i++)
Willy Tarreaub2f38c12023-01-19 19:14:18 +01003061 if ((_HA_ATOMIC_LOAD(&ha_tgroup_ctx[i].stopping_threads) &
3062 _HA_ATOMIC_LOAD(&ha_tgroup_info[i].threads_enabled)) !=
3063 _HA_ATOMIC_LOAD(&ha_tgroup_info[i].threads_enabled))
Willy Tarreauef422ce2022-06-28 19:29:29 +02003064 break;
3065#ifdef USE_THREAD
3066 if (i == global.nbtgroups) {
3067 /* all are OK, let's wake them all and stop */
3068 for (i = 0; i < global.nbthread; i++)
Willy Tarreaub2f38c12023-01-19 19:14:18 +01003069 if (i != tid && _HA_ATOMIC_LOAD(&ha_thread_info[i].tg->threads_enabled) & ha_thread_info[i].ltid_bit)
Willy Tarreauef422ce2022-06-28 19:29:29 +02003070 wake_thread(i);
3071 break;
3072 }
3073#endif
Willy Tarreaud7a6b2f2020-05-13 13:51:01 +02003074 }
Willy Tarreau4f46a352020-03-23 09:27:28 +01003075 }
3076
Willy Tarreauc49ba522019-12-11 08:12:23 +01003077 /* If we have to sleep, measure how long */
3078 next = wake ? TICK_ETERNITY : next_timer_expiry();
3079
Willy Tarreau58b458d2008-06-29 22:40:23 +02003080 /* The poller will ensure it returns around <next> */
Willy Tarreau2ae84e42019-05-28 16:44:05 +02003081 cur_poller.poll(&cur_poller, next, wake);
Emeric Brun64cc49c2017-10-03 14:46:45 +02003082
Willy Tarreaud80cb4e2018-01-20 19:30:13 +01003083 activity[tid].loops++;
Willy Tarreau4f60f162007-04-08 16:39:58 +02003084 }
Willy Tarreau3e820a12023-02-17 08:36:42 +01003085
3086 _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_IN_LOOP);
Willy Tarreau4f60f162007-04-08 16:39:58 +02003087}
3088
Christopher Faulet1d17c102017-08-29 15:38:48 +02003089static void *run_thread_poll_loop(void *data)
3090{
Willy Tarreau082b6282019-05-22 14:42:12 +02003091 struct per_thread_alloc_fct *ptaf;
Christopher Faulet1d17c102017-08-29 15:38:48 +02003092 struct per_thread_init_fct *ptif;
3093 struct per_thread_deinit_fct *ptdf;
Willy Tarreau082b6282019-05-22 14:42:12 +02003094 struct per_thread_free_fct *ptff;
Willy Tarreau34a150c2019-06-11 09:16:41 +02003095 static int init_left = 0;
Willy Tarreauaf613e82020-06-05 08:40:51 +02003096 __decl_thread(static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER);
3097 __decl_thread(static pthread_cond_t init_cond = PTHREAD_COND_INITIALIZER);
Christopher Faulet1d17c102017-08-29 15:38:48 +02003098
Willy Tarreau43ab05b2021-09-28 09:43:11 +02003099 ha_set_thread(data);
Willy Tarreaufb641d72021-09-28 10:15:47 +02003100 set_thread_cpu_affinity();
Willy Tarreau44c58da2021-10-08 12:27:54 +02003101 clock_set_local_source();
Aurelien DARRAGON739281b2023-01-27 15:13:28 +01003102 /* thread is started, from now on it is not idle nor harmless */
3103 thread_harmless_end();
3104 thread_idle_end();
Willy Tarreau3e820a12023-02-17 08:36:42 +01003105 _HA_ATOMIC_OR(&th_ctx->flags, TH_FL_STARTED);
Willy Tarreau91e6df02019-05-03 17:21:18 +02003106
Willy Tarreau6ec902a2019-06-07 14:41:11 +02003107 /* Now, initialize one thread init at a time. This is better since
3108 * some init code is a bit tricky and may release global resources
3109 * after reallocating them locally. This will also ensure there is
3110 * no race on file descriptors allocation.
3111 */
Willy Tarreau34a150c2019-06-11 09:16:41 +02003112#ifdef USE_THREAD
3113 pthread_mutex_lock(&init_mutex);
3114#endif
3115 /* The first thread must set the number of threads left */
3116 if (!init_left)
3117 init_left = global.nbthread;
3118 init_left--;
Willy Tarreau91e6df02019-05-03 17:21:18 +02003119
Willy Tarreau55542642021-10-08 09:33:24 +02003120 clock_init_thread_date();
Christopher Faulet1d17c102017-08-29 15:38:48 +02003121
Willy Tarreau082b6282019-05-22 14:42:12 +02003122 /* per-thread alloc calls performed here are not allowed to snoop on
3123 * other threads, so they are free to initialize at their own rhythm
3124 * as long as they act as if they were alone. None of them may rely
3125 * on resources initialized by the other ones.
3126 */
3127 list_for_each_entry(ptaf, &per_thread_alloc_list, list) {
3128 if (!ptaf->fct()) {
3129 ha_alert("failed to allocate resources for thread %u.\n", tid);
Willy Tarreaub3c4a8f2021-07-22 14:42:32 +02003130#ifdef USE_THREAD
jenny-cheung048368e2021-07-18 16:40:57 +08003131 pthread_mutex_unlock(&init_mutex);
Willy Tarreaub3c4a8f2021-07-22 14:42:32 +02003132#endif
Willy Tarreau082b6282019-05-22 14:42:12 +02003133 exit(1);
3134 }
3135 }
3136
Willy Tarreau3078e9f2019-05-20 10:50:43 +02003137 /* per-thread init calls performed here are not allowed to snoop on
3138 * other threads, so they are free to initialize at their own rhythm
3139 * as long as they act as if they were alone.
3140 */
Christopher Faulet1d17c102017-08-29 15:38:48 +02003141 list_for_each_entry(ptif, &per_thread_init_list, list) {
3142 if (!ptif->fct()) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003143 ha_alert("failed to initialize thread %u.\n", tid);
Willy Tarreaub3c4a8f2021-07-22 14:42:32 +02003144#ifdef USE_THREAD
jenny-cheung048368e2021-07-18 16:40:57 +08003145 pthread_mutex_unlock(&init_mutex);
Willy Tarreaub3c4a8f2021-07-22 14:42:32 +02003146#endif
Christopher Faulet1d17c102017-08-29 15:38:48 +02003147 exit(1);
3148 }
3149 }
3150
Willy Tarreau71092822019-06-10 09:51:04 +02003151 /* enabling protocols will result in fd_insert() calls to be performed,
3152 * we want all threads to have already allocated their local fd tables
Willy Tarreau34a150c2019-06-11 09:16:41 +02003153 * before doing so, thus only the last thread does it.
Willy Tarreau71092822019-06-10 09:51:04 +02003154 */
Willy Tarreau34a150c2019-06-11 09:16:41 +02003155 if (init_left == 0)
Willy Tarreaue4d7c9d2019-06-10 10:14:52 +02003156 protocol_enable_all();
Willy Tarreau6ec902a2019-06-07 14:41:11 +02003157
Willy Tarreau34a150c2019-06-11 09:16:41 +02003158#ifdef USE_THREAD
3159 pthread_cond_broadcast(&init_cond);
3160 pthread_mutex_unlock(&init_mutex);
3161
3162 /* now wait for other threads to finish starting */
3163 pthread_mutex_lock(&init_mutex);
3164 while (init_left)
3165 pthread_cond_wait(&init_cond, &init_mutex);
3166 pthread_mutex_unlock(&init_mutex);
3167#endif
Willy Tarreau3078e9f2019-05-20 10:50:43 +02003168
Willy Tarreaua45a8b52019-12-06 16:31:45 +01003169#if defined(PR_SET_NO_NEW_PRIVS) && defined(USE_PRCTL)
3170 /* Let's refrain from using setuid executables. This way the impact of
3171 * an eventual vulnerability in a library remains limited. It may
3172 * impact external checks but who cares about them anyway ? In the
3173 * worst case it's possible to disable the option. Obviously we do this
3174 * in workers only. We can't hard-fail on this one as it really is
3175 * implementation dependent though we're interested in feedback, hence
3176 * the warning.
3177 */
3178 if (!(global.tune.options & GTUNE_INSECURE_SETUID) && !master) {
3179 static int warn_fail;
Willy Tarreau18515722021-04-06 11:57:41 +02003180 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 +01003181 ha_warning("Failed to disable setuid, please report to developers with detailed "
3182 "information about your operating system. You can silence this warning "
3183 "by adding 'insecure-setuid-wanted' in the 'global' section.\n");
3184 }
3185 }
3186#endif
3187
Willy Tarreaud96f1122019-12-03 07:07:36 +01003188#if defined(RLIMIT_NPROC)
3189 /* all threads have started, it's now time to prevent any new thread
3190 * or process from starting. Obviously we do this in workers only. We
3191 * can't hard-fail on this one as it really is implementation dependent
3192 * though we're interested in feedback, hence the warning.
3193 */
3194 if (!(global.tune.options & GTUNE_INSECURE_FORK) && !master) {
3195 struct rlimit limit = { .rlim_cur = 0, .rlim_max = 0 };
3196 static int warn_fail;
3197
Willy Tarreau18515722021-04-06 11:57:41 +02003198 if (setrlimit(RLIMIT_NPROC, &limit) == -1 && !_HA_ATOMIC_FETCH_ADD(&warn_fail, 1)) {
Willy Tarreaud96f1122019-12-03 07:07:36 +01003199 ha_warning("Failed to disable forks, please report to developers with detailed "
3200 "information about your operating system. You can silence this warning "
3201 "by adding 'insecure-fork-wanted' in the 'global' section.\n");
3202 }
3203 }
3204#endif
Christopher Faulet1d17c102017-08-29 15:38:48 +02003205 run_poll_loop();
3206
3207 list_for_each_entry(ptdf, &per_thread_deinit_list, list)
3208 ptdf->fct();
3209
Willy Tarreau082b6282019-05-22 14:42:12 +02003210 list_for_each_entry(ptff, &per_thread_free_list, list)
3211 ptff->fct();
3212
Christopher Fauletcd7879a2017-10-27 13:53:47 +02003213#ifdef USE_THREAD
Willy Tarreau291f6ff2022-07-04 13:36:16 +02003214 if (!_HA_ATOMIC_AND_FETCH(&ha_tgroup_info[ti->tgid-1].threads_enabled, ~ti->ltid_bit))
Willy Tarreaucce203a2022-06-24 15:55:11 +02003215 _HA_ATOMIC_AND(&all_tgroups_mask, ~tg->tgid_bit);
Willy Tarreauad92fdf2022-07-06 10:17:21 +02003216 if (!_HA_ATOMIC_AND_FETCH(&tg_ctx->stopping_threads, ~ti->ltid_bit))
3217 _HA_ATOMIC_AND(&stopping_tgroup_mask, ~tg->tgid_bit);
Christopher Fauletcd7879a2017-10-27 13:53:47 +02003218 if (tid > 0)
3219 pthread_exit(NULL);
Christopher Faulet1d17c102017-08-29 15:38:48 +02003220#endif
Christopher Fauletcd7879a2017-10-27 13:53:47 +02003221 return NULL;
3222}
Christopher Faulet1d17c102017-08-29 15:38:48 +02003223
William Dauchyf9af9d72019-11-17 15:47:16 +01003224/* set uid/gid depending on global settings */
3225static void set_identity(const char *program_name)
3226{
Willy Tarreaua547a212023-08-29 10:24:26 +02003227 int from_uid __maybe_unused = geteuid();
3228
William Dauchyf9af9d72019-11-17 15:47:16 +01003229 if (global.gid) {
3230 if (getgroups(0, NULL) > 0 && setgroups(0, NULL) == -1)
3231 ha_warning("[%s.main()] Failed to drop supplementary groups. Using 'gid'/'group'"
3232 " without 'uid'/'user' is generally useless.\n", program_name);
3233
3234 if (setgid(global.gid) == -1) {
3235 ha_alert("[%s.main()] Cannot set gid %d.\n", program_name, global.gid);
3236 protocol_unbind_all();
3237 exit(1);
3238 }
3239 }
Willy Tarreaua547a212023-08-29 10:24:26 +02003240
3241#if defined(USE_LINUX_CAP)
3242 if (prepare_caps_for_setuid(from_uid, global.uid) < 0) {
3243 ha_alert("[%s.main()] Cannot switch uid to %d.\n", program_name, global.uid);
3244 protocol_unbind_all();
3245 exit(1);
3246 }
3247#endif
William Dauchyf9af9d72019-11-17 15:47:16 +01003248
3249 if (global.uid && setuid(global.uid) == -1) {
3250 ha_alert("[%s.main()] Cannot set uid %d.\n", program_name, global.uid);
3251 protocol_unbind_all();
3252 exit(1);
3253 }
Willy Tarreaua547a212023-08-29 10:24:26 +02003254
3255#if defined(USE_LINUX_CAP)
3256 if (finalize_caps_after_setuid(from_uid, global.uid) < 0) {
3257 ha_alert("[%s.main()] Cannot switch uid to %d.\n", program_name, global.uid);
3258 protocol_unbind_all();
3259 exit(1);
3260 }
3261#endif
William Dauchyf9af9d72019-11-17 15:47:16 +01003262}
3263
Willy Tarreaubaaee002006-06-26 02:48:02 +02003264int main(int argc, char **argv)
3265{
3266 int err, retry;
3267 struct rlimit limit;
Willy Tarreau269ab312012-09-05 08:02:48 +02003268 int pidfd = -1;
Willy Tarreau1335da32021-07-14 17:54:01 +02003269 int intovf = (unsigned char)argc + 1; /* let the compiler know it's strictly positive */
3270
Willy Tarreau41afd902022-07-21 09:55:22 +02003271 /* Catch broken toolchains */
3272 if (sizeof(long) != sizeof(void *) || (intovf + 0x7FFFFFFF >= intovf)) {
3273 const char *msg;
3274
3275 if (sizeof(long) != sizeof(void *))
3276 /* Apparently MingW64 was not made for us and can also break openssl */
3277 msg = "The compiler this program was built with uses unsupported integral type sizes.\n"
3278 "Most likely it follows the unsupported LLP64 model. Never try to link HAProxy\n"
3279 "against libraries built with that compiler either! Please only use a compiler\n"
3280 "producing ILP32 or LP64 programs for both programs and libraries.\n";
3281 else if (intovf + 0x7FFFFFFF >= intovf)
3282 /* Catch forced CFLAGS that miss 2-complement integer overflow */
3283 msg = "The source code was miscompiled by the compiler, which usually indicates that\n"
3284 "some of the CFLAGS needed to work around overzealous compiler optimizations\n"
3285 "were overwritten at build time. Please do not force CFLAGS, and read Makefile\n"
3286 "and INSTALL files to decide on the best way to pass your local build options.\n";
3287 else
3288 msg = "Bug in the compiler bug detection code, please report it to developers!\n";
3289
Willy Tarreau1335da32021-07-14 17:54:01 +02003290 fprintf(stderr,
3291 "FATAL ERROR: invalid code detected -- cannot go further, please recompile!\n"
Willy Tarreau41afd902022-07-21 09:55:22 +02003292 "%s"
3293 "\nBuild options :"
Willy Tarreau1335da32021-07-14 17:54:01 +02003294#ifdef BUILD_TARGET
Willy Tarreau41afd902022-07-21 09:55:22 +02003295 "\n TARGET = " BUILD_TARGET
Willy Tarreau1335da32021-07-14 17:54:01 +02003296#endif
3297#ifdef BUILD_CPU
Willy Tarreau41afd902022-07-21 09:55:22 +02003298 "\n CPU = " BUILD_CPU
Willy Tarreau1335da32021-07-14 17:54:01 +02003299#endif
3300#ifdef BUILD_CC
Willy Tarreau41afd902022-07-21 09:55:22 +02003301 "\n CC = " BUILD_CC
Willy Tarreau1335da32021-07-14 17:54:01 +02003302#endif
3303#ifdef BUILD_CFLAGS
Willy Tarreau41afd902022-07-21 09:55:22 +02003304 "\n CFLAGS = " BUILD_CFLAGS
Willy Tarreau1335da32021-07-14 17:54:01 +02003305#endif
3306#ifdef BUILD_OPTIONS
Willy Tarreau41afd902022-07-21 09:55:22 +02003307 "\n OPTIONS = " BUILD_OPTIONS
Willy Tarreau1335da32021-07-14 17:54:01 +02003308#endif
3309#ifdef BUILD_DEBUG
Willy Tarreau41afd902022-07-21 09:55:22 +02003310 "\n DEBUG = " BUILD_DEBUG
Willy Tarreau1335da32021-07-14 17:54:01 +02003311#endif
Willy Tarreau41afd902022-07-21 09:55:22 +02003312 "\n\n", msg);
3313
Willy Tarreau1335da32021-07-14 17:54:01 +02003314 return 1;
3315 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003316
Olivier Houchard5fa300d2018-02-03 15:15:21 +01003317 setvbuf(stdout, NULL, _IONBF, 0);
Willy Tarreau5794fb02018-11-25 18:43:29 +01003318
Willy Tarreaubf696402019-03-01 10:09:28 +01003319 /* take a copy of initial limits before we possibly change them */
3320 getrlimit(RLIMIT_NOFILE, &limit);
Willy Tarreau2bd0f812020-10-13 15:36:08 +02003321
3322 if (limit.rlim_max == RLIM_INFINITY)
3323 limit.rlim_max = limit.rlim_cur;
Willy Tarreaubf696402019-03-01 10:09:28 +01003324 rlim_fd_cur_at_boot = limit.rlim_cur;
3325 rlim_fd_max_at_boot = limit.rlim_max;
3326
Willy Tarreau5794fb02018-11-25 18:43:29 +01003327 /* process all initcalls in order of potential dependency */
3328 RUN_INITCALLS(STG_PREPARE);
3329 RUN_INITCALLS(STG_LOCK);
Willy Tarreau3ebe4d92022-02-18 14:51:49 +01003330 RUN_INITCALLS(STG_REGISTER);
Willy Tarreau34527d52022-02-17 17:45:58 +01003331
3332 /* now's time to initialize early boot variables */
3333 init_early(argc, argv);
3334
Willy Tarreau18f96d02022-02-23 17:25:00 +01003335 /* handles argument parsing */
3336 init_args(argc, argv);
3337
Willy Tarreau5794fb02018-11-25 18:43:29 +01003338 RUN_INITCALLS(STG_ALLOC);
3339 RUN_INITCALLS(STG_POOL);
Willy Tarreau5794fb02018-11-25 18:43:29 +01003340 RUN_INITCALLS(STG_INIT);
3341
Willy Tarreau34527d52022-02-17 17:45:58 +01003342 /* this is the late init where the config is parsed */
Emeric Bruncf20bf12010-10-22 16:06:11 +02003343 init(argc, argv);
Willy Tarreau34527d52022-02-17 17:45:58 +01003344
Willy Tarreau24f4efa2010-08-27 17:56:48 +02003345 signal_register_fct(SIGQUIT, dump, SIGQUIT);
3346 signal_register_fct(SIGUSR1, sig_soft_stop, SIGUSR1);
3347 signal_register_fct(SIGHUP, sig_dump_state, SIGHUP);
William Lallemand73b85e72017-06-01 17:38:51 +02003348 signal_register_fct(SIGUSR2, NULL, 0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003349
Willy Tarreaue437c442010-03-17 18:02:46 +01003350 /* Always catch SIGPIPE even on platforms which define MSG_NOSIGNAL.
3351 * Some recent FreeBSD setups report broken pipes, and MSG_NOSIGNAL
3352 * was defined there, so let's stay on the safe side.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003353 */
Willy Tarreau24f4efa2010-08-27 17:56:48 +02003354 signal_register_fct(SIGPIPE, NULL, 0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003355
Willy Tarreaudc23a922011-02-16 11:10:36 +01003356 /* ulimits */
3357 if (!global.rlimit_nofile)
3358 global.rlimit_nofile = global.maxsock;
3359
3360 if (global.rlimit_nofile) {
Willy Tarreaue5cfdac2019-03-01 10:32:05 +01003361 limit.rlim_cur = global.rlimit_nofile;
3362 limit.rlim_max = MAX(rlim_fd_max_at_boot, limit.rlim_cur);
3363
Willy Tarreau2df1fbf2022-04-25 18:02:03 +02003364 if ((global.fd_hard_limit && limit.rlim_cur > global.fd_hard_limit) ||
Willy Tarreauc06557c2022-09-22 16:12:08 +02003365 raise_rlim_nofile(NULL, &limit) != 0) {
Willy Tarreauef635472016-06-21 11:48:18 +02003366 getrlimit(RLIMIT_NOFILE, &limit);
Willy Tarreau2df1fbf2022-04-25 18:02:03 +02003367 if (global.fd_hard_limit && limit.rlim_cur > global.fd_hard_limit)
3368 limit.rlim_cur = global.fd_hard_limit;
3369
William Dauchy0fec3ab2019-10-27 20:08:11 +01003370 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3371 ha_alert("[%s.main()] Cannot raise FD limit to %d, limit is %d.\n",
3372 argv[0], global.rlimit_nofile, (int)limit.rlim_cur);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003373 exit(1);
William Dauchy0fec3ab2019-10-27 20:08:11 +01003374 }
3375 else {
3376 /* try to set it to the max possible at least */
3377 limit.rlim_cur = limit.rlim_max;
Willy Tarreau2df1fbf2022-04-25 18:02:03 +02003378 if (global.fd_hard_limit && limit.rlim_cur > global.fd_hard_limit)
3379 limit.rlim_cur = global.fd_hard_limit;
3380
Willy Tarreauc06557c2022-09-22 16:12:08 +02003381 if (raise_rlim_nofile(&limit, &limit) == 0)
William Dauchy0fec3ab2019-10-27 20:08:11 +01003382 getrlimit(RLIMIT_NOFILE, &limit);
Willy Tarreau164dd0b2016-06-21 11:51:59 +02003383
William Dauchya5194602020-03-28 19:29:58 +01003384 ha_warning("[%s.main()] Cannot raise FD limit to %d, limit is %d.\n",
William Dauchy0fec3ab2019-10-27 20:08:11 +01003385 argv[0], global.rlimit_nofile, (int)limit.rlim_cur);
3386 global.rlimit_nofile = limit.rlim_cur;
3387 }
Willy Tarreaudc23a922011-02-16 11:10:36 +01003388 }
3389 }
3390
3391 if (global.rlimit_memmax) {
3392 limit.rlim_cur = limit.rlim_max =
Willy Tarreau70060452015-12-14 12:46:07 +01003393 global.rlimit_memmax * 1048576ULL;
Willy Tarreaudc23a922011-02-16 11:10:36 +01003394#ifdef RLIMIT_AS
3395 if (setrlimit(RLIMIT_AS, &limit) == -1) {
William Dauchy0fec3ab2019-10-27 20:08:11 +01003396 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3397 ha_alert("[%s.main()] Cannot fix MEM limit to %d megs.\n",
3398 argv[0], global.rlimit_memmax);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003399 exit(1);
William Dauchy0fec3ab2019-10-27 20:08:11 +01003400 }
3401 else
William Dauchya5194602020-03-28 19:29:58 +01003402 ha_warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
William Dauchy0fec3ab2019-10-27 20:08:11 +01003403 argv[0], global.rlimit_memmax);
Willy Tarreaudc23a922011-02-16 11:10:36 +01003404 }
3405#else
3406 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
William Dauchy0fec3ab2019-10-27 20:08:11 +01003407 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3408 ha_alert("[%s.main()] Cannot fix MEM limit to %d megs.\n",
3409 argv[0], global.rlimit_memmax);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003410 exit(1);
William Dauchy0fec3ab2019-10-27 20:08:11 +01003411 }
3412 else
William Dauchya5194602020-03-28 19:29:58 +01003413 ha_warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
William Dauchy0fec3ab2019-10-27 20:08:11 +01003414 argv[0], global.rlimit_memmax);
Willy Tarreaudc23a922011-02-16 11:10:36 +01003415 }
3416#endif
3417 }
3418
William Lallemandf82afbb2022-01-07 18:19:42 +01003419 /* Try to get the listeners FD from the previous process using
3420 * _getsocks on the stat socket, it must never been done in wait mode
3421 * and check mode
3422 */
3423 if (old_unixsocket &&
3424 !(global.mode & (MODE_MWORKER_WAIT|MODE_CHECK|MODE_CHECK_CONDITION))) {
William Lallemand85b0bd92017-06-01 17:38:53 +02003425 if (strcmp("/dev/null", old_unixsocket) != 0) {
Willy Tarreau42961742020-08-28 18:42:45 +02003426 if (sock_get_old_sockets(old_unixsocket) != 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003427 ha_alert("Failed to get the sockets from the old process!\n");
William Lallemand85b0bd92017-06-01 17:38:53 +02003428 if (!(global.mode & MODE_MWORKER))
3429 exit(1);
3430 }
Olivier Houchardf73629d2017-04-05 22:33:04 +02003431 }
3432 }
William Lallemand85b0bd92017-06-01 17:38:53 +02003433
Willy Tarreaubaaee002006-06-26 02:48:02 +02003434 /* We will loop at most 100 times with 10 ms delay each time.
3435 * That's at most 1 second. We only send a signal to old pids
3436 * if we cannot grab at least one port.
3437 */
3438 retry = MAX_START_RETRIES;
3439 err = ERR_NONE;
3440 while (retry >= 0) {
3441 struct timeval w;
Willy Tarreaue91bff22020-09-02 11:11:43 +02003442 err = protocol_bind_all(retry == 0 || nb_oldpids == 0);
Willy Tarreaue13e9252007-12-20 23:05:50 +01003443 /* exit the loop on no error or fatal error */
3444 if ((err & (ERR_RETRYABLE|ERR_FATAL)) != ERR_RETRYABLE)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003445 break;
Willy Tarreaubb545b42010-08-25 12:58:59 +02003446 if (nb_oldpids == 0 || retry == 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003447 break;
3448
3449 /* FIXME-20060514: Solaris and OpenBSD do not support shutdown() on
3450 * listening sockets. So on those platforms, it would be wiser to
3451 * simply send SIGUSR1, which will not be undoable.
3452 */
Willy Tarreaubb545b42010-08-25 12:58:59 +02003453 if (tell_old_pids(SIGTTOU) == 0) {
3454 /* no need to wait if we can't contact old pids */
3455 retry = 0;
3456 continue;
3457 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003458 /* give some time to old processes to stop listening */
3459 w.tv_sec = 0;
3460 w.tv_usec = 10*1000;
3461 select(0, NULL, NULL, NULL, &w);
3462 retry--;
3463 }
3464
Willy Tarreaue91bff22020-09-02 11:11:43 +02003465 /* Note: protocol_bind_all() sends an alert when it fails. */
Willy Tarreau0a3b9d92009-02-04 17:05:23 +01003466 if ((err & ~ERR_WARN) != ERR_NONE) {
Willy Tarreaue91bff22020-09-02 11:11:43 +02003467 ha_alert("[%s.main()] Some protocols failed to start their listeners! Exiting.\n", argv[0]);
Aurelien DARRAGON28a6d482023-01-17 16:30:52 +01003468 if (retry != MAX_START_RETRIES && nb_oldpids)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003469 tell_old_pids(SIGTTIN);
Aurelien DARRAGON28a6d482023-01-17 16:30:52 +01003470 protocol_unbind_all(); /* cleanup everything we can */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003471 exit(1);
3472 }
3473
William Lallemand944e6192018-11-21 15:48:31 +01003474 if (!(global.mode & MODE_MWORKER_WAIT) && listeners == 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003475 ha_alert("[%s.main()] No enabled listener found (check for 'bind' directives) ! Exiting.\n", argv[0]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003476 /* Note: we don't have to send anything to the old pids because we
3477 * never stopped them. */
3478 exit(1);
3479 }
3480
Willy Tarreaue91bff22020-09-02 11:11:43 +02003481 /* Ok, all listeners should now be bound, close any leftover sockets
Olivier Houchardf73629d2017-04-05 22:33:04 +02003482 * the previous process gave us, we don't need them anymore
3483 */
Willy Tarreaub5101162022-01-28 18:28:18 +01003484 sock_drop_unused_old_sockets();
Willy Tarreaudd815982007-10-16 12:25:14 +02003485
Willy Tarreaubaaee002006-06-26 02:48:02 +02003486 /* prepare pause/play signals */
Willy Tarreau24f4efa2010-08-27 17:56:48 +02003487 signal_register_fct(SIGTTOU, sig_pause, SIGTTOU);
3488 signal_register_fct(SIGTTIN, sig_listen, SIGTTIN);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003489
Willy Tarreaubaaee002006-06-26 02:48:02 +02003490 /* MODE_QUIET can inhibit alerts and warnings below this line */
3491
PiBa-NL149a81a2017-12-25 21:03:31 +01003492 if (getenv("HAPROXY_MWORKER_REEXEC") != NULL) {
3493 /* either stdin/out/err are already closed or should stay as they are. */
3494 if ((global.mode & MODE_DAEMON)) {
3495 /* daemon mode re-executing, stdin/stdout/stderr are already closed so keep quiet */
3496 global.mode &= ~MODE_VERBOSE;
3497 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
3498 }
3499 } else {
3500 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
3501 /* detach from the tty */
William Lallemande1340412017-12-28 16:09:36 +01003502 stdio_quiet(-1);
PiBa-NL149a81a2017-12-25 21:03:31 +01003503 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003504 }
3505
3506 /* open log & pid files before the chroot */
William Lallemand7b820a62022-02-14 09:02:14 +01003507 if ((global.mode & MODE_DAEMON || global.mode & MODE_MWORKER) &&
3508 !(global.mode & MODE_MWORKER_WAIT) && global.pidfile != NULL) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003509 unlink(global.pidfile);
3510 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
3511 if (pidfd < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003512 ha_alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003513 if (nb_oldpids)
3514 tell_old_pids(SIGTTIN);
Willy Tarreaudd815982007-10-16 12:25:14 +02003515 protocol_unbind_all();
Willy Tarreaubaaee002006-06-26 02:48:02 +02003516 exit(1);
3517 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003518 }
3519
Willy Tarreaub38651a2007-03-24 17:24:39 +01003520 if ((global.last_checks & LSTCHK_NETADM) && global.uid) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003521 ha_alert("[%s.main()] Some configuration options require full privileges, so global.uid cannot be changed.\n"
3522 "", argv[0]);
Willy Tarreaudd815982007-10-16 12:25:14 +02003523 protocol_unbind_all();
Willy Tarreaub38651a2007-03-24 17:24:39 +01003524 exit(1);
3525 }
3526
Jackie Tapia749f74c2020-07-22 18:59:40 -05003527 /* If the user is not root, we'll still let them try the configuration
3528 * but we inform them that unexpected behaviour may occur.
Willy Tarreau4e30ed72009-02-04 18:02:48 +01003529 */
3530 if ((global.last_checks & LSTCHK_NETADM) && getuid())
Christopher Faulet767a84b2017-11-24 16:50:31 +01003531 ha_warning("[%s.main()] Some options which require full privileges"
3532 " might not work well.\n"
3533 "", argv[0]);
Willy Tarreau4e30ed72009-02-04 18:02:48 +01003534
William Lallemand095ba4c2017-06-01 17:38:50 +02003535 if ((global.mode & (MODE_MWORKER|MODE_DAEMON)) == 0) {
3536
3537 /* chroot if needed */
3538 if (global.chroot != NULL) {
3539 if (chroot(global.chroot) == -1 || chdir("/") == -1) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003540 ha_alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
William Lallemand095ba4c2017-06-01 17:38:50 +02003541 if (nb_oldpids)
3542 tell_old_pids(SIGTTIN);
3543 protocol_unbind_all();
3544 exit(1);
3545 }
Willy Tarreauf223cc02007-10-15 18:57:08 +02003546 }
Willy Tarreauf223cc02007-10-15 18:57:08 +02003547 }
3548
William Lallemand944e6192018-11-21 15:48:31 +01003549 if (nb_oldpids && !(global.mode & MODE_MWORKER_WAIT))
Willy Tarreaubb545b42010-08-25 12:58:59 +02003550 nb_oldpids = tell_old_pids(oldpids_sig);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003551
William Lallemand27edc4b2019-05-07 17:49:33 +02003552 /* send a SIGTERM to workers who have a too high reloads number */
3553 if ((global.mode & MODE_MWORKER) && !(global.mode & MODE_MWORKER_WAIT))
3554 mworker_kill_max_reloads(SIGTERM);
3555
Willy Tarreaubaaee002006-06-26 02:48:02 +02003556 /* Note that any error at this stage will be fatal because we will not
3557 * be able to restart the old pids.
3558 */
3559
William Dauchyf9af9d72019-11-17 15:47:16 +01003560 if ((global.mode & (MODE_MWORKER | MODE_DAEMON)) == 0)
3561 set_identity(argv[0]);
Willy Tarreau636848a2019-04-15 19:38:50 +02003562
Willy Tarreaubaaee002006-06-26 02:48:02 +02003563 /* check ulimits */
3564 limit.rlim_cur = limit.rlim_max = 0;
3565 getrlimit(RLIMIT_NOFILE, &limit);
3566 if (limit.rlim_cur < global.maxsock) {
William Dauchy0fec3ab2019-10-27 20:08:11 +01003567 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3568 ha_alert("[%s.main()] FD limit (%d) too low for maxconn=%d/maxsock=%d. "
3569 "Please raise 'ulimit-n' to %d or more to avoid any trouble.\n",
3570 argv[0], (int)limit.rlim_cur, global.maxconn, global.maxsock,
3571 global.maxsock);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003572 exit(1);
William Dauchy0fec3ab2019-10-27 20:08:11 +01003573 }
3574 else
3575 ha_alert("[%s.main()] FD limit (%d) too low for maxconn=%d/maxsock=%d. "
William Dauchya5194602020-03-28 19:29:58 +01003576 "Please raise 'ulimit-n' to %d or more to avoid any trouble.\n",
William Dauchy0fec3ab2019-10-27 20:08:11 +01003577 argv[0], (int)limit.rlim_cur, global.maxconn, global.maxsock,
3578 global.maxsock);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003579 }
3580
Patrick Hemmer425d7ad2023-05-23 13:02:08 -04003581 if (global.prealloc_fd && fcntl((int)limit.rlim_cur - 1, F_GETFD) == -1) {
3582 if (dup2(0, (int)limit.rlim_cur - 1) == -1)
Aurelien DARRAGON33bbeec2023-05-26 14:04:18 +02003583 ha_warning("[%s.main()] Unable to preallocate file descriptor %d : %s",
3584 argv[0], (int)limit.rlim_cur - 1, strerror(errno));
Patrick Hemmer425d7ad2023-05-23 13:02:08 -04003585 else
3586 close((int)limit.rlim_cur - 1);
3587 }
3588
Willy Tarreauda4aa692023-05-17 09:02:21 +02003589 /* update the ready date a last time to also account for final setup time */
3590 clock_update_date(0, 1);
Willy Tarreauc7b93082023-05-16 19:19:36 +02003591 clock_adjust_now_offset();
Willy Tarreauda4aa692023-05-17 09:02:21 +02003592 ready_date = date;
3593
William Lallemand944e6192018-11-21 15:48:31 +01003594 if (global.mode & (MODE_DAEMON | MODE_MWORKER | MODE_MWORKER_WAIT)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003595 int ret = 0;
Willy Tarreaud67ff342021-06-15 07:58:09 +02003596 int in_parent = 0;
William Lallemande1340412017-12-28 16:09:36 +01003597 int devnullfd = -1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003598
William Lallemand095ba4c2017-06-01 17:38:50 +02003599 /*
3600 * if daemon + mworker: must fork here to let a master
3601 * process live in background before forking children
3602 */
William Lallemand73b85e72017-06-01 17:38:51 +02003603
3604 if ((getenv("HAPROXY_MWORKER_REEXEC") == NULL)
3605 && (global.mode & MODE_MWORKER)
3606 && (global.mode & MODE_DAEMON)) {
William Lallemand095ba4c2017-06-01 17:38:50 +02003607 ret = fork();
3608 if (ret < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003609 ha_alert("[%s.main()] Cannot fork.\n", argv[0]);
William Lallemand095ba4c2017-06-01 17:38:50 +02003610 protocol_unbind_all();
3611 exit(1); /* there has been an error */
William Lallemandbfd8eb52018-07-04 15:31:23 +02003612 } else if (ret > 0) { /* parent leave to daemonize */
William Lallemand095ba4c2017-06-01 17:38:50 +02003613 exit(0);
William Lallemandbfd8eb52018-07-04 15:31:23 +02003614 } else /* change the process group ID in the child (master process) */
3615 setsid();
William Lallemand095ba4c2017-06-01 17:38:50 +02003616 }
William Lallemande20b6a62017-06-01 17:38:55 +02003617
William Lallemande20b6a62017-06-01 17:38:55 +02003618
William Lallemanddeed7802017-11-06 11:00:04 +01003619 /* if in master-worker mode, write the PID of the father */
3620 if (global.mode & MODE_MWORKER) {
3621 char pidstr[100];
Willy Tarreau76a80c72019-06-22 07:41:38 +02003622 snprintf(pidstr, sizeof(pidstr), "%d\n", (int)getpid());
Willy Tarreau46ec48b2018-01-23 19:20:19 +01003623 if (pidfd >= 0)
Willy Tarreau2e8ab6b2020-03-14 11:03:20 +01003624 DISGUISE(write(pidfd, pidstr, strlen(pidstr)));
William Lallemanddeed7802017-11-06 11:00:04 +01003625 }
3626
Willy Tarreaubaaee002006-06-26 02:48:02 +02003627 /* the father launches the required number of processes */
William Lallemand944e6192018-11-21 15:48:31 +01003628 if (!(global.mode & MODE_MWORKER_WAIT)) {
William Lallemandeba6a542022-09-26 12:54:39 +02003629 struct ring *tmp_startup_logs = NULL;
3630
William Lallemand9a1ee7a2019-04-01 11:30:02 +02003631 if (global.mode & MODE_MWORKER)
3632 mworker_ext_launch_all();
Willy Tarreaud67ff342021-06-15 07:58:09 +02003633
William Lallemandeba6a542022-09-26 12:54:39 +02003634 /* at this point the worker must have his own startup_logs buffer */
3635 tmp_startup_logs = startup_logs_dup(startup_logs);
Willy Tarreaud67ff342021-06-15 07:58:09 +02003636 ret = fork();
3637 if (ret < 0) {
3638 ha_alert("[%s.main()] Cannot fork.\n", argv[0]);
3639 protocol_unbind_all();
3640 exit(1); /* there has been an error */
3641 }
3642 else if (ret == 0) { /* child breaks here */
William Lallemandeba6a542022-09-26 12:54:39 +02003643 startup_logs_free(startup_logs);
3644 startup_logs = tmp_startup_logs;
Willy Tarreau3c032f22021-07-21 10:17:02 +02003645 /* This one must not be exported, it's internal! */
3646 unsetenv("HAPROXY_MWORKER_REEXEC");
Willy Tarreaue8422bf2021-06-15 09:08:18 +02003647 ha_random_jump96(1);
Willy Tarreaud67ff342021-06-15 07:58:09 +02003648 }
3649 else { /* parent here */
3650 in_parent = 1;
3651
William Lallemand944e6192018-11-21 15:48:31 +01003652 if (pidfd >= 0 && !(global.mode & MODE_MWORKER)) {
3653 char pidstr[100];
3654 snprintf(pidstr, sizeof(pidstr), "%d\n", ret);
Willy Tarreau2e8ab6b2020-03-14 11:03:20 +01003655 DISGUISE(write(pidfd, pidstr, strlen(pidstr)));
William Lallemand944e6192018-11-21 15:48:31 +01003656 }
3657 if (global.mode & MODE_MWORKER) {
3658 struct mworker_proc *child;
William Lallemandce83b4a2018-10-26 14:47:30 +02003659
William Lallemand5d71a6b2021-11-09 15:25:31 +01003660 ha_notice("New worker (%d) forked\n", ret);
William Lallemand944e6192018-11-21 15:48:31 +01003661 /* find the right mworker_proc */
3662 list_for_each_entry(child, &proc_list, list) {
William Lallemandd4835a92022-07-21 00:52:43 +02003663 if (child->reloads == 0 &&
3664 child->options & PROC_O_TYPE_WORKER &&
3665 child->pid == -1) {
William Lallemand5a7f83a2023-02-17 16:23:52 +01003666 child->timestamp = date.tv_sec;
William Lallemand944e6192018-11-21 15:48:31 +01003667 child->pid = ret;
William Lallemand1dc69632019-06-12 19:11:33 +02003668 child->version = strdup(haproxy_version);
William Lallemand8ee9a502023-06-21 09:44:18 +02003669 /* at this step the fd is bound for the worker, set it to -1 so
3670 * it could be close in case of errors in mworker_cleanup_proc() */
3671 child->ipc_fd[1] = -1;
William Lallemand944e6192018-11-21 15:48:31 +01003672 break;
3673 }
William Lallemandce83b4a2018-10-26 14:47:30 +02003674 }
3675 }
William Lallemand944e6192018-11-21 15:48:31 +01003676 }
Willy Tarreaud67ff342021-06-15 07:58:09 +02003677
William Lallemand944e6192018-11-21 15:48:31 +01003678 } else {
3679 /* wait mode */
Willy Tarreaud67ff342021-06-15 07:58:09 +02003680 in_parent = 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003681 }
Willy Tarreaufc6c0322012-11-16 16:12:27 +01003682
Willy Tarreaubaaee002006-06-26 02:48:02 +02003683 /* close the pidfile both in children and father */
Willy Tarreau269ab312012-09-05 08:02:48 +02003684 if (pidfd >= 0) {
3685 //lseek(pidfd, 0, SEEK_SET); /* debug: emulate eglibc bug */
3686 close(pidfd);
3687 }
Willy Tarreaud137dd32010-08-25 12:49:05 +02003688
3689 /* We won't ever use this anymore */
Willy Tarreau61cfdf42021-02-20 10:46:51 +01003690 ha_free(&global.pidfile);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003691
Willy Tarreaud67ff342021-06-15 07:58:09 +02003692 if (in_parent) {
William Lallemand944e6192018-11-21 15:48:31 +01003693 if (global.mode & (MODE_MWORKER|MODE_MWORKER_WAIT)) {
William Lallemandfab0fdc2021-11-09 18:01:22 +01003694 master = 1;
PiBa-NLbaf6ea42017-11-28 23:26:08 +01003695
3696 if ((!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
3697 (global.mode & MODE_DAEMON)) {
3698 /* detach from the tty, this is required to properly daemonize. */
William Lallemande1340412017-12-28 16:09:36 +01003699 if ((getenv("HAPROXY_MWORKER_REEXEC") == NULL))
3700 stdio_quiet(-1);
3701
PiBa-NLbaf6ea42017-11-28 23:26:08 +01003702 global.mode &= ~MODE_VERBOSE;
3703 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
PiBa-NLbaf6ea42017-11-28 23:26:08 +01003704 }
3705
William Lallemandfab0fdc2021-11-09 18:01:22 +01003706 if (global.mode & MODE_MWORKER_WAIT) {
3707 /* only the wait mode handles the master CLI */
3708 mworker_loop();
3709 } else {
3710
William Lallemanda46a99e2022-07-07 14:00:36 +02003711#if defined(USE_SYSTEMD)
3712 if (global.tune.options & GTUNE_USE_SYSTEMD)
3713 sd_notifyf(0, "READY=1\nMAINPID=%lu\nSTATUS=Ready.\n", (unsigned long)getpid());
3714#endif
William Lallemandfab0fdc2021-11-09 18:01:22 +01003715 /* if not in wait mode, reload in wait mode to free the memory */
William Lallemand68192b22022-09-24 15:44:42 +02003716 setenv("HAPROXY_LOAD_SUCCESS", "1", 1);
William Lallemand836bda22021-11-09 18:16:47 +01003717 ha_notice("Loading success.\n");
William Lallemand68836742021-11-10 10:49:06 +01003718 proc_self->failedreloads = 0; /* reset the number of failure */
William Lallemandfab0fdc2021-11-09 18:01:22 +01003719 mworker_reexec_waitmode();
3720 }
William Lallemand1499b9b2017-06-07 15:04:47 +02003721 /* should never get there */
3722 exit(EXIT_FAILURE);
Willy Tarreauedaff0a2015-05-01 17:01:08 +02003723 }
William Lallemandcf4e4962017-06-08 19:05:48 +02003724#if defined(USE_OPENSSL) && !defined(OPENSSL_NO_DH)
Grant Zhang872f9c22017-01-21 01:10:18 +00003725 ssl_free_dh();
3726#endif
William Lallemand1499b9b2017-06-07 15:04:47 +02003727 exit(0); /* parent must leave */
Willy Tarreauedaff0a2015-05-01 17:01:08 +02003728 }
3729
William Lallemandcb11fd22017-06-01 17:38:52 +02003730 /* child must never use the atexit function */
3731 atexit_flag = 0;
3732
William Lallemandbc193052018-09-11 10:06:26 +02003733 /* close useless master sockets */
3734 if (global.mode & MODE_MWORKER) {
3735 struct mworker_proc *child, *it;
3736 master = 0;
3737
William Lallemand309dc9a2018-10-26 14:47:45 +02003738 mworker_cli_proxy_stop();
3739
William Lallemandbc193052018-09-11 10:06:26 +02003740 /* free proc struct of other processes */
3741 list_for_each_entry_safe(child, it, &proc_list, list) {
William Lallemandce83b4a2018-10-26 14:47:30 +02003742 /* close the FD of the master side for all
3743 * workers, we don't need to close the worker
3744 * side of other workers since it's done with
3745 * the bind_proc */
William Lallemand7e018782022-01-28 21:56:24 +01003746 if (child->ipc_fd[0] >= 0) {
Tim Duesterhus742e0f92018-11-25 20:03:39 +01003747 close(child->ipc_fd[0]);
William Lallemand7e018782022-01-28 21:56:24 +01003748 child->ipc_fd[0] = -1;
3749 }
Willy Tarreaue8422bf2021-06-15 09:08:18 +02003750 if (child->options & PROC_O_TYPE_WORKER &&
William Lallemandd4835a92022-07-21 00:52:43 +02003751 child->reloads == 0 &&
3752 child->pid == -1) {
William Lallemandce83b4a2018-10-26 14:47:30 +02003753 /* keep this struct if this is our pid */
3754 proc_self = child;
William Lallemandbc193052018-09-11 10:06:26 +02003755 continue;
William Lallemandce83b4a2018-10-26 14:47:30 +02003756 }
Willy Tarreau2b718102021-04-21 07:32:39 +02003757 LIST_DELETE(&child->list);
Tim Duesterhus9b7a9762019-05-16 20:23:22 +02003758 mworker_free_child(child);
3759 child = NULL;
William Lallemandbc193052018-09-11 10:06:26 +02003760 }
3761 }
Willy Tarreau1605c7a2018-01-23 19:01:49 +01003762
William Lallemande1340412017-12-28 16:09:36 +01003763 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
3764 devnullfd = open("/dev/null", O_RDWR, 0);
3765 if (devnullfd < 0) {
3766 ha_alert("Cannot open /dev/null\n");
3767 exit(EXIT_FAILURE);
3768 }
3769 }
3770
William Lallemand095ba4c2017-06-01 17:38:50 +02003771 /* Must chroot and setgid/setuid in the children */
3772 /* chroot if needed */
3773 if (global.chroot != NULL) {
3774 if (chroot(global.chroot) == -1 || chdir("/") == -1) {
Willy Tarreaue34cf282021-06-15 08:59:19 +02003775 ha_alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
William Lallemand095ba4c2017-06-01 17:38:50 +02003776 if (nb_oldpids)
3777 tell_old_pids(SIGTTIN);
3778 protocol_unbind_all();
3779 exit(1);
3780 }
3781 }
3782
Willy Tarreau61cfdf42021-02-20 10:46:51 +01003783 ha_free(&global.chroot);
William Dauchyf9af9d72019-11-17 15:47:16 +01003784 set_identity(argv[0]);
William Lallemand095ba4c2017-06-01 17:38:50 +02003785
William Lallemand2e8fad92018-11-13 16:18:23 +01003786 /*
3787 * This is only done in daemon mode because we might want the
3788 * logs on stdout in mworker mode. If we're NOT in QUIET mode,
3789 * we should now close the 3 first FDs to ensure that we can
3790 * detach from the TTY. We MUST NOT do it in other cases since
3791 * it would have already be done, and 0-2 would have been
3792 * affected to listening sockets
Willy Tarreaubaaee002006-06-26 02:48:02 +02003793 */
William Lallemand2e8fad92018-11-13 16:18:23 +01003794 if ((global.mode & MODE_DAEMON) &&
3795 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003796 /* detach from the tty */
William Lallemande1340412017-12-28 16:09:36 +01003797 stdio_quiet(devnullfd);
Willy Tarreau106cb762008-11-16 07:40:34 +01003798 global.mode &= ~MODE_VERBOSE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003799 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
3800 }
3801 pid = getpid(); /* update child's pid */
William Lallemandbfd8eb52018-07-04 15:31:23 +02003802 if (!(global.mode & MODE_MWORKER)) /* in mworker mode we don't want a new pgid for the children */
3803 setsid();
Willy Tarreau2ff76222007-04-09 19:29:56 +02003804 fork_poller();
Willy Tarreaubaaee002006-06-26 02:48:02 +02003805 }
3806
William Lallemanda51c3e12023-11-20 10:49:05 +01003807 /* pass through every cli socket, and check if it's bound to
3808 * the current process and if it exposes listeners sockets.
3809 * Caution: the GTUNE_SOCKET_TRANSFER is now set after the fork.
3810 * */
3811
3812 if (global.cli_fe) {
3813 struct bind_conf *bind_conf;
3814
3815 list_for_each_entry(bind_conf, &global.cli_fe->conf.bind, by_fe) {
3816 if (bind_conf->level & ACCESS_FD_LISTENERS) {
3817 global.tune.options |= GTUNE_SOCKET_TRANSFER;
3818 break;
3819 }
3820 }
3821 }
3822
Willy Tarreauadb7e4a2023-07-19 18:39:32 +02003823 /* Note that here we can't be in the parent/master anymore */
3824#if !defined(USE_THREAD) && defined(USE_CPU_AFFINITY)
3825 if (ha_cpuset_count(&cpu_map[0].thread[0])) { /* only do this if the process has a CPU map */
3826
3827#if defined(CPUSET_USE_CPUSET) || defined(__DragonFly__)
3828 struct hap_cpuset *set = &cpu_map[0].thread[0];
3829 sched_setaffinity(0, sizeof(set->cpuset), &set->cpuset);
3830#elif defined(__FreeBSD__)
3831 struct hap_cpuset *set = &cpu_map[0].thread[0];
3832 ret = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(set->cpuset), &set->cpuset);
3833#endif
3834 }
3835#endif
William Dauchye039f262019-11-17 15:47:15 +01003836 /* try our best to re-enable core dumps depending on system capabilities.
3837 * What is addressed here :
3838 * - remove file size limits
3839 * - remove core size limits
3840 * - mark the process dumpable again if it lost it due to user/group
3841 */
3842 if (global.tune.options & GTUNE_SET_DUMPABLE) {
3843 limit.rlim_cur = limit.rlim_max = RLIM_INFINITY;
3844
3845#if defined(RLIMIT_FSIZE)
3846 if (setrlimit(RLIMIT_FSIZE, &limit) == -1) {
3847 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3848 ha_alert("[%s.main()] Failed to set the raise the maximum "
3849 "file size.\n", argv[0]);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003850 exit(1);
William Dauchye039f262019-11-17 15:47:15 +01003851 }
3852 else
3853 ha_warning("[%s.main()] Failed to set the raise the maximum "
William Dauchya5194602020-03-28 19:29:58 +01003854 "file size.\n", argv[0]);
William Dauchye039f262019-11-17 15:47:15 +01003855 }
3856#endif
3857
3858#if defined(RLIMIT_CORE)
3859 if (setrlimit(RLIMIT_CORE, &limit) == -1) {
3860 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3861 ha_alert("[%s.main()] Failed to set the raise the core "
3862 "dump size.\n", argv[0]);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003863 exit(1);
William Dauchye039f262019-11-17 15:47:15 +01003864 }
3865 else
3866 ha_warning("[%s.main()] Failed to set the raise the core "
William Dauchya5194602020-03-28 19:29:58 +01003867 "dump size.\n", argv[0]);
William Dauchye039f262019-11-17 15:47:15 +01003868 }
3869#endif
3870
3871#if defined(USE_PRCTL)
3872 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1)
3873 ha_warning("[%s.main()] Failed to set the dumpable flag, "
3874 "no core will be dumped.\n", argv[0]);
devnexen@gmail.com21185972021-08-21 09:13:10 +01003875#elif defined(USE_PROCCTL)
Willy Tarreau28345c62021-10-08 15:55:13 +02003876 {
3877 int traceable = PROC_TRACE_CTL_ENABLE;
3878 if (procctl(P_PID, getpid(), PROC_TRACE_CTL, &traceable) == -1)
3879 ha_warning("[%s.main()] Failed to set the traceable flag, "
3880 "no core will be dumped.\n", argv[0]);
3881 }
William Dauchye039f262019-11-17 15:47:15 +01003882#endif
3883 }
3884
Christopher Faulete3a5e352017-10-24 13:53:54 +02003885 global.mode &= ~MODE_STARTING;
Amaury Denoyelle6af81f82021-05-27 15:45:28 +02003886 reset_usermsgs_ctx();
3887
Willy Tarreau2d5d4e02021-09-28 10:36:57 +02003888 /* start threads 2 and above */
Willy Tarreaud10385a2021-10-06 22:22:40 +02003889 setup_extra_threads(&run_thread_poll_loop);
William Lallemand1aab50b2018-06-07 09:46:01 +02003890
Willy Tarreau2d5d4e02021-09-28 10:36:57 +02003891 /* when multithreading we need to let only the thread 0 handle the signals */
William Lallemandd3801c12018-09-11 10:06:23 +02003892 haproxy_unblock_signals();
Willy Tarreau2d5d4e02021-09-28 10:36:57 +02003893
3894 /* Finally, start the poll loop for the first thread */
Willy Tarreau43ab05b2021-09-28 09:43:11 +02003895 run_thread_poll_loop(&ha_thread_info[0]);
Willy Tarreau2d5d4e02021-09-28 10:36:57 +02003896
3897 /* wait for all threads to terminate */
3898 wait_for_threads_completion();
Christopher Faulet1d17c102017-08-29 15:38:48 +02003899
Tim Duesterhus0a3b43d2020-06-14 00:37:42 +02003900 deinit_and_exit(0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003901}
3902
Willy Tarreaubaaee002006-06-26 02:48:02 +02003903/*
3904 * Local variables:
3905 * c-indent-level: 8
3906 * c-basic-offset: 8
3907 * End:
3908 */