blob: 3def1ed98374c183e63074f047d57414fe4fbd7a [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
Willy Tarreaua5357cd2021-05-09 06:14:25 +02002 * HAProxy : High Availability-enabled HTTP/TCP proxy
Willy Tarreau40c88f92023-01-07 09:45:17 +01003 * Copyright 2000-2023 Willy Tarreau <willy@haproxy.org>.
Willy Tarreaubaaee002006-06-26 02:48:02 +02004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
Ilya Shipitsin46a030c2020-07-05 16:36:08 +050010 * Please refer to RFC7230 - RFC7235 information about HTTP protocol, and
11 * RFC6265 for information about cookies usage. More generally, the IETF HTTP
Willy Tarreaubaaee002006-06-26 02:48:02 +020012 * Working Group's web site should be consulted for protocol related changes :
13 *
14 * http://ftp.ics.uci.edu/pub/ietf/http/
15 *
16 * Pending bugs (may be not fixed because never reproduced) :
17 * - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
18 * the proxy to terminate (no core) if the client breaks the connection during
19 * the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
20 * the snprintf() bug since requests were simple (GET / HTTP/1.0), but may be
21 * related to missing setsid() (fixed in 1.1.15)
22 * - a proxy with an invalid config will prevent the startup even if disabled.
23 *
24 * ChangeLog has moved to the CHANGELOG file.
25 *
Willy Tarreaubaaee002006-06-26 02:48:02 +020026 */
27
David Carlier7ece0962015-12-08 21:43:09 +000028#define _GNU_SOURCE
Willy Tarreaubaaee002006-06-26 02:48:02 +020029#include <stdio.h>
30#include <stdlib.h>
31#include <unistd.h>
32#include <string.h>
33#include <ctype.h>
Maxime de Roucy379d9c72016-05-13 23:52:56 +020034#include <dirent.h>
Maxime de Roucy379d9c72016-05-13 23:52:56 +020035#include <sys/stat.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020036#include <sys/time.h>
37#include <sys/types.h>
38#include <sys/socket.h>
39#include <netinet/tcp.h>
40#include <netinet/in.h>
41#include <arpa/inet.h>
42#include <netdb.h>
43#include <fcntl.h>
44#include <errno.h>
45#include <signal.h>
46#include <stdarg.h>
47#include <sys/resource.h>
Tim Duesterhusdfad6a42020-04-18 16:02:47 +020048#include <sys/utsname.h>
Marc-Antoine Perennou992709b2013-02-12 10:53:52 +010049#include <sys/wait.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020050#include <time.h>
51#include <syslog.h>
Michael Schererab012dd2013-01-12 18:35:19 +010052#include <grp.h>
Willy Tarreaud10385a2021-10-06 22:22:40 +020053
Willy Tarreau5e03dfa2021-10-06 22:53:51 +020054#ifdef USE_THREAD
55#include <pthread.h>
56#endif
57
Willy Tarreaufc6c0322012-11-16 16:12:27 +010058#ifdef USE_CPU_AFFINITY
Willy Tarreaufc6c0322012-11-16 16:12:27 +010059#include <sched.h>
David Carlier42d9e5a2018-11-12 16:22:19 +000060#if defined(__FreeBSD__) || defined(__DragonFly__)
Pieter Baauwcaa6a1b2015-09-17 21:26:40 +020061#include <sys/param.h>
David Carlier42d9e5a2018-11-12 16:22:19 +000062#ifdef __FreeBSD__
Pieter Baauwcaa6a1b2015-09-17 21:26:40 +020063#include <sys/cpuset.h>
David Carlier42d9e5a2018-11-12 16:22:19 +000064#endif
David Carlier5e4c8e22019-09-13 05:12:58 +010065#endif
Willy Tarreaufc6c0322012-11-16 16:12:27 +010066#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +020067
Willy Tarreau636848a2019-04-15 19:38:50 +020068#if defined(USE_PRCTL)
69#include <sys/prctl.h>
70#endif
71
devnexen@gmail.com21185972021-08-21 09:13:10 +010072#if defined(USE_PROCCTL)
73#include <sys/procctl.h>
74#endif
75
Willy Tarreaubaaee002006-06-26 02:48:02 +020076#ifdef DEBUG_FULL
77#include <assert.h>
78#endif
Tim Duesterhusd6942c82017-11-20 15:58:35 +010079#if defined(USE_SYSTEMD)
80#include <systemd/sd-daemon.h>
81#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +020082
Willy Tarreau6c3a6812020-03-06 18:57:15 +010083#include <import/sha1.h>
84
Willy Tarreaub2551052020-06-09 09:07:15 +020085#include <haproxy/acl.h>
Amaury Denoyelle68fd7e42021-03-25 17:15:52 +010086#include <haproxy/action.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020087#include <haproxy/activity.h>
88#include <haproxy/api.h>
89#include <haproxy/arg.h>
90#include <haproxy/auth.h>
Willy Tarreau8d366972020-05-27 16:10:29 +020091#include <haproxy/base64.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020092#include <haproxy/capture-t.h>
Willy Tarreau66243b42021-07-16 15:39:28 +020093#include <haproxy/cfgcond.h>
Amaury Denoyelle5a6926d2021-03-30 17:34:24 +020094#include <haproxy/cfgdiag.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020095#include <haproxy/cfgparse.h>
Willy Tarreauc13ed532020-06-02 10:22:45 +020096#include <haproxy/chunk.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020097#include <haproxy/cli.h>
Willy Tarreau55542642021-10-08 09:33:24 +020098#include <haproxy/clock.h>
Willy Tarreau7ea393d2020-06-04 18:02:10 +020099#include <haproxy/connection.h>
Amaury Denoyellea6f9c5d2021-04-23 16:58:08 +0200100#ifdef USE_CPU_AFFINITY
Amaury Denoyelle982fb532021-04-21 18:39:58 +0200101#include <haproxy/cpuset.h>
Amaury Denoyellea6f9c5d2021-04-23 16:58:08 +0200102#endif
Willy Tarreaueb92deb2020-06-04 10:53:16 +0200103#include <haproxy/dns.h>
Willy Tarreau2741c8c2020-06-02 11:28:02 +0200104#include <haproxy/dynbuf.h>
Willy Tarreau8d366972020-05-27 16:10:29 +0200105#include <haproxy/errors.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200106#include <haproxy/fd.h>
Willy Tarreauc7babd82020-06-04 21:29:29 +0200107#include <haproxy/filters.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200108#include <haproxy/global.h>
Willy Tarreau86416052020-06-04 09:20:54 +0200109#include <haproxy/hlua.h>
Willy Tarreauc761f842020-06-04 11:40:28 +0200110#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +0200111#include <haproxy/list.h>
Willy Tarreau213e9902020-06-04 14:58:24 +0200112#include <haproxy/listener.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +0200113#include <haproxy/log.h>
Willy Tarreaub5abe5b2020-06-04 14:07:37 +0200114#include <haproxy/mworker.h>
Willy Tarreau7a00efb2020-06-02 17:02:59 +0200115#include <haproxy/namespace.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +0200116#include <haproxy/net_helper.h>
Willy Tarreau6019fab2020-05-27 16:26:00 +0200117#include <haproxy/openssl-compat.h>
Amaury Denoyelle5907fed2023-03-08 10:37:45 +0100118#include <haproxy/quic_conn.h>
Frédéric Lécaille1d96d6e2022-05-23 16:38:14 +0200119#include <haproxy/quic_tp-t.h>
Willy Tarreau225a90a2020-06-04 15:06:28 +0200120#include <haproxy/pattern.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +0200121#include <haproxy/peers.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200122#include <haproxy/pool.h>
123#include <haproxy/protocol.h>
Willy Tarreaubf3b06b2020-08-26 10:23:40 +0200124#include <haproxy/proto_tcp.h>
Willy Tarreaua264d962020-06-04 22:29:18 +0200125#include <haproxy/proxy.h>
Willy Tarreau7cd8b6e2020-06-02 17:32:26 +0200126#include <haproxy/regex.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200127#include <haproxy/sample.h>
Willy Tarreau1e56f922020-06-04 23:20:13 +0200128#include <haproxy/server.h>
Willy Tarreau48d25b32020-06-04 18:58:52 +0200129#include <haproxy/session.h>
Willy Tarreau3727a8a2020-06-04 17:37:26 +0200130#include <haproxy/signal.h>
Willy Tarreau063d47d2020-08-28 16:29:53 +0200131#include <haproxy/sock.h>
Willy Tarreau25140cc2020-08-28 15:40:33 +0200132#include <haproxy/sock_inet.h>
Willy Tarreau209108d2020-06-04 20:30:20 +0200133#include <haproxy/ssl_sock.h>
Amaury Denoyelleee63d4b2020-10-05 11:49:42 +0200134#include <haproxy/stats-t.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +0200135#include <haproxy/stream.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +0200136#include <haproxy/task.h>
Willy Tarreau3f567e42020-05-28 15:29:19 +0200137#include <haproxy/thread.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200138#include <haproxy/time.h>
139#include <haproxy/tools.h>
140#include <haproxy/uri_auth-t.h>
Willy Tarreaua1718922020-06-04 16:25:31 +0200141#include <haproxy/vars.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200142#include <haproxy/version.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +0200143
Willy Tarreaubaaee002006-06-26 02:48:02 +0200144
Willy Tarreau7b5654f2019-03-29 21:30:17 +0100145/* array of init calls for older platforms */
146DECLARE_INIT_STAGES;
147
Willy Tarreauf4596402021-04-10 16:53:05 +0200148/* create a read_mostly section to hold variables which are accessed a lot
149 * but which almost never change. The purpose is to isolate them in their
150 * own cache lines where they don't risk to be perturbated by write accesses
151 * to neighbor variables. We need to create an empty aligned variable for
152 * this. The fact that the variable is of size zero means that it will be
153 * eliminated at link time if no other variable uses it, but alignment will
154 * be respected.
155 */
156empty_t __read_mostly_align HA_SECTION("read_mostly") ALIGNED(64);
157
Willy Tarreauf0d3b732021-05-06 16:30:32 +0200158#ifdef BUILD_FEATURES
159const char *build_features = BUILD_FEATURES;
160#else
161const char *build_features = "";
162#endif
163
Willy Tarreau477ecd82010-01-03 21:12:30 +0100164/* list of config files */
165static struct list cfg_cfgfiles = LIST_HEAD_INIT(cfg_cfgfiles);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200166int pid; /* current process id */
167
Willy Tarreauef422ce2022-06-28 19:29:29 +0200168static unsigned long stopping_tgroup_mask; /* Thread groups acknowledging stopping */
Willy Tarreauf8ea00e2020-03-12 17:24:53 +0100169
Willy Tarreaubaaee002006-06-26 02:48:02 +0200170/* global options */
171struct global global = {
Cyril Bonté203ec5a2017-03-23 22:44:13 +0100172 .hard_stop_after = TICK_ETERNITY,
Remi Tricot-Le Bretonb5d968d2022-04-08 18:04:18 +0200173 .close_spread_time = TICK_ETERNITY,
174 .close_spread_end = TICK_ETERNITY,
Amaury Denoyelle0f50cb92021-03-26 18:50:33 +0100175 .numa_cpu_mapping = 1,
Willy Tarreau149ab772019-01-26 14:27:06 +0100176 .nbthread = 0,
William Lallemand5f232402012-04-05 18:02:55 +0200177 .req_count = 0,
William Lallemand0f99e342011-10-12 17:50:54 +0200178 .logsrvs = LIST_HEAD_INIT(global.logsrvs),
Willy Tarreau197715a2022-04-25 19:29:10 +0200179 .maxzlibmem = DEFAULT_MAXZLIBMEM * 1024U * 1024U,
William Lallemandd85f9172012-11-09 17:05:39 +0100180 .comp_rate_lim = 0,
Emeric Brun850efd52014-01-29 12:24:34 +0100181 .ssl_server_verify = SSL_SERVER_VERIFY_REQUIRED,
Emeric Bruned760922010-10-22 17:59:25 +0200182 .unix_bind = {
183 .ux = {
184 .uid = -1,
185 .gid = -1,
186 .mode = 0,
187 }
188 },
Willy Tarreau27a674e2009-08-17 07:23:33 +0200189 .tune = {
Willy Tarreau7ac908b2019-02-27 12:02:18 +0100190 .options = GTUNE_LISTENER_MQ,
Willy Tarreauc77d3642018-12-12 06:19:42 +0100191 .bufsize = (BUFSIZE + 2*sizeof(void *) - 1) & -(2*sizeof(void *)),
Christopher Faulet546c4692020-01-22 14:31:21 +0100192 .maxrewrite = MAXREWRITE,
Willy Tarreaua24adf02014-11-27 01:11:56 +0100193 .reserved_bufs = RESERVED_BUFS,
Willy Tarreauf3045d22015-04-29 16:24:50 +0200194 .pattern_cache = DEFAULT_PAT_LRU_SIZE,
Olivier Houchard88698d92019-04-16 19:07:22 +0200195 .pool_low_ratio = 20,
196 .pool_high_ratio = 25,
Christopher Faulet41ba36f2019-07-19 09:36:45 +0200197 .max_http_hdr = MAX_HTTP_HDR,
Emeric Brunfc32aca2012-09-03 12:10:29 +0200198#ifdef USE_OPENSSL
Emeric Brun46635772012-11-14 11:32:56 +0100199 .sslcachesize = SSLCACHESIZE,
Emeric Brunfc32aca2012-09-03 12:10:29 +0200200#endif
William Lallemandf3747832012-11-09 12:33:10 +0100201 .comp_maxlevel = 1,
Willy Tarreau7e312732014-02-12 16:35:14 +0100202#ifdef DEFAULT_IDLE_TIMER
203 .idle_timer = DEFAULT_IDLE_TIMER,
204#else
205 .idle_timer = 1000, /* 1 second */
206#endif
Willy Tarreau6c011712023-01-06 16:09:58 +0100207 .nb_stk_ctr = MAX_SESS_STKCTR,
Amaury Denoyelle97e84c62022-04-19 18:26:55 +0200208#ifdef USE_QUIC
Frédéric Lécailleaee67572022-05-23 18:29:39 +0200209 .quic_backend_max_idle_timeout = QUIC_TP_DFLT_BACK_MAX_IDLE_TIMEOUT,
210 .quic_frontend_max_idle_timeout = QUIC_TP_DFLT_FRONT_MAX_IDLE_TIMEOUT,
211 .quic_frontend_max_streams_bidi = QUIC_TP_DFLT_FRONT_MAX_STREAMS_BIDI,
Frédéric Lécaille92862102022-05-20 16:29:10 +0200212 .quic_retry_threshold = QUIC_DFLT_RETRY_THRESHOLD,
Amaury Denoyelle24d5b722023-01-31 11:44:50 +0100213 .quic_max_frame_loss = QUIC_DFLT_MAX_FRAME_LOSS,
Amaury Denoyelle97e84c62022-04-19 18:26:55 +0200214 .quic_streams_buf = 30,
215#endif /* USE_QUIC */
Willy Tarreau27a674e2009-08-17 07:23:33 +0200216 },
Emeric Brun76d88952012-10-05 15:47:31 +0200217#ifdef USE_OPENSSL
218#ifdef DEFAULT_MAXSSLCONN
Willy Tarreau403edff2012-09-06 11:58:37 +0200219 .maxsslconn = DEFAULT_MAXSSLCONN,
220#endif
Emeric Brun76d88952012-10-05 15:47:31 +0200221#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +0200222 /* others NULL OK */
223};
224
225/*********************************************************************/
226
227int stopping; /* non zero means stopping in progress */
Cyril Bonté203ec5a2017-03-23 22:44:13 +0100228int killed; /* non zero means a hard-stop is triggered */
Willy Tarreauaf7ad002010-08-31 15:39:26 +0200229int jobs = 0; /* number of active jobs (conns, listeners, active tasks, ...) */
William Lallemanda7199262018-11-16 16:57:20 +0100230int unstoppable_jobs = 0; /* number of active jobs that can't be stopped during a soft stop */
Willy Tarreau199ad242018-11-05 16:31:22 +0100231int active_peers = 0; /* number of active peers (connection attempts and connected) */
Willy Tarreau2d372c22018-11-05 17:12:27 +0100232int connected_peers = 0; /* number of connected peers (verified ones) */
Willy Tarreau392524d2022-02-17 18:10:36 +0100233int arg_mode = 0; /* MODE_DEBUG etc as passed on command line ... */
234char *change_dir = NULL; /* set when -C is passed */
235char *check_condition = NULL; /* check condition passed to -cc */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200236
Ilya Shipitsin46a030c2020-07-05 16:36:08 +0500237/* Here we store information about the pids of the processes we may pause
Willy Tarreaubaaee002006-06-26 02:48:02 +0200238 * or kill. We will send them a signal every 10 ms until we can bind to all
239 * our ports. With 200 retries, that's about 2 seconds.
240 */
241#define MAX_START_RETRIES 200
Willy Tarreaubaaee002006-06-26 02:48:02 +0200242static int *oldpids = NULL;
243static int oldpids_sig; /* use USR1 or TERM */
244
Olivier Houchardf73629d2017-04-05 22:33:04 +0200245/* Path to the unix socket we use to retrieve listener sockets from the old process */
246static const char *old_unixsocket;
247
William Lallemandcb11fd22017-06-01 17:38:52 +0200248int atexit_flag = 0;
249
Willy Tarreaubb545b42010-08-25 12:58:59 +0200250int nb_oldpids = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200251const int zero = 0;
252const int one = 1;
Alexandre Cassen87ea5482007-10-11 20:48:58 +0200253const struct linger nolinger = { .l_onoff = 1, .l_linger = 0 };
Willy Tarreaubaaee002006-06-26 02:48:02 +0200254
Willy Tarreau1d21e0a2010-03-12 21:58:54 +0100255char hostname[MAX_HOSTNAME_LEN];
Dragan Dosen4f014152020-06-18 16:56:47 +0200256char *localpeer = NULL;
Willy Tarreau76871a42022-03-08 16:01:40 +0100257static char *kwd_dump = NULL; // list of keyword dumps to produce
Willy Tarreaubaaee002006-06-26 02:48:02 +0200258
William Lallemand00417412020-06-05 14:08:41 +0200259static char **old_argv = NULL; /* previous argv but cleaned up */
William Lallemand73b85e72017-06-01 17:38:51 +0200260
William Lallemandbc193052018-09-11 10:06:26 +0200261struct list proc_list = LIST_HEAD_INIT(proc_list);
262
263int master = 0; /* 1 if in master, 0 if in child */
Willy Tarreaubf696402019-03-01 10:09:28 +0100264unsigned int rlim_fd_cur_at_boot = 0;
265unsigned int rlim_fd_max_at_boot = 0;
William Lallemandbc193052018-09-11 10:06:26 +0200266
Willy Tarreau6c3a6812020-03-06 18:57:15 +0100267/* per-boot randomness */
268unsigned char boot_seed[20]; /* per-boot random seed (160 bits initially) */
269
Willy Tarreau43ab05b2021-09-28 09:43:11 +0200270/* takes the thread config in argument or NULL for any thread */
William Lallemandb3f2be32018-09-11 10:06:18 +0200271static void *run_thread_poll_loop(void *data);
272
Willy Tarreauff055502014-04-28 22:27:06 +0200273/* bitfield of a few warnings to emit just once (WARN_*) */
274unsigned int warned = 0;
275
Amaury Denoyelle484454d2021-05-05 16:18:45 +0200276/* set if experimental features have been used for the current process */
Willy Tarreauedd42682022-02-25 10:10:00 +0100277unsigned int tainted = 0;
Amaury Denoyelle484454d2021-05-05 16:18:45 +0200278
Amaury Denoyelled2e53cd2021-05-06 16:21:39 +0200279unsigned int experimental_directives_allowed = 0;
280
281int check_kw_experimental(struct cfg_keyword *kw, const char *file, int linenum,
282 char **errmsg)
283{
284 if (kw->flags & KWF_EXPERIMENTAL) {
285 if (!experimental_directives_allowed) {
Amaury Denoyelle86c1d0f2021-05-07 15:07:21 +0200286 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 +0200287 file, linenum, kw->kw);
288 return 1;
289 }
290 mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
291 }
292
293 return 0;
294}
295
William Lallemande7361152018-10-26 14:47:36 +0200296/* master CLI configuration (-S flag) */
297struct list mworker_cli_conf = LIST_HEAD_INIT(mworker_cli_conf);
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100298
299/* These are strings to be reported in the output of "haproxy -vv". They may
300 * either be constants (in which case must_free must be zero) or dynamically
301 * allocated strings to pass to free() on exit, and in this case must_free
302 * must be non-zero.
303 */
304struct list build_opts_list = LIST_HEAD_INIT(build_opts_list);
305struct build_opts_str {
306 struct list list;
307 const char *str;
308 int must_free;
309};
310
Willy Tarreaubaaee002006-06-26 02:48:02 +0200311/*********************************************************************/
312/* general purpose functions ***************************************/
313/*********************************************************************/
314
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100315/* used to register some build option strings at boot. Set must_free to
316 * non-zero if the string must be freed upon exit.
317 */
318void hap_register_build_opts(const char *str, int must_free)
319{
320 struct build_opts_str *b;
321
322 b = calloc(1, sizeof(*b));
323 if (!b) {
324 fprintf(stderr, "out of memory\n");
325 exit(1);
326 }
327 b->str = str;
328 b->must_free = must_free;
Willy Tarreau2b718102021-04-21 07:32:39 +0200329 LIST_APPEND(&build_opts_list, &b->list);
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100330}
331
Willy Tarreaua43dfda2021-05-06 07:43:35 +0200332#define VERSION_MAX_ELTS 7
333
334/* This function splits an haproxy version string into an array of integers.
335 * The syntax of the supported version string is the following:
336 *
337 * <a>[.<b>[.<c>[.<d>]]][-{dev,pre,rc}<f>][-*][-<g>]
338 *
339 * This validates for example:
340 * 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
341 * 2.4-dev18-f6818d-20
342 *
343 * The result is set in a array of <VERSION_MAX_ELTS> elements. Each letter has
344 * one fixed place in the array. The tags take a numeric value called <e> which
345 * defaults to 3. "dev" is 1, "rc" and "pre" are 2. Numbers not encountered are
346 * considered as zero (henxe 1.5 and 1.5.0 are the same).
347 *
348 * The resulting values are:
349 * 1.2.1-pre2 1, 2, 1, 0, 2, 2, 0
350 * 1.2.1 1, 2, 1, 0, 3, 0, 0
351 * 1.2.10.1 1, 2, 10, 1, 3, 0, 0
352 * 1.3.16-rc1 1, 3, 16, 0, 2, 1, 0
353 * 1.4-dev3 1, 4, 0, 0, 1, 3, 0
354 * 1.5-dev18 1, 5, 0, 0, 1, 18, 0
355 * 1.5-dev18-43 1, 5, 0, 0, 1, 18, 43
356 * 2.4-dev18-f6818d-20 2, 4, 0, 0, 1, 18, 20
357 *
358 * The function returns non-zero if the conversion succeeded, or zero if it
359 * failed.
360 */
361int split_version(const char *version, unsigned int *value)
362{
363 const char *p, *s;
364 char *error;
365 int nelts;
366
367 /* Initialize array with zeroes */
368 for (nelts = 0; nelts < VERSION_MAX_ELTS; nelts++)
369 value[nelts] = 0;
370 value[4] = 3;
371
372 p = version;
373
374 /* If the version number is empty, return false */
375 if (*p == '\0')
376 return 0;
377
378 /* Convert first number <a> */
379 value[0] = strtol(p, &error, 10);
380 p = error + 1;
381 if (*error == '\0')
382 return 1;
383 if (*error == '-')
384 goto split_version_tag;
385 if (*error != '.')
386 return 0;
387
388 /* Convert first number <b> */
389 value[1] = strtol(p, &error, 10);
390 p = error + 1;
391 if (*error == '\0')
392 return 1;
393 if (*error == '-')
394 goto split_version_tag;
395 if (*error != '.')
396 return 0;
397
398 /* Convert first number <c> */
399 value[2] = strtol(p, &error, 10);
400 p = error + 1;
401 if (*error == '\0')
402 return 1;
403 if (*error == '-')
404 goto split_version_tag;
405 if (*error != '.')
406 return 0;
407
408 /* Convert first number <d> */
409 value[3] = strtol(p, &error, 10);
410 p = error + 1;
411 if (*error == '\0')
412 return 1;
413 if (*error != '-')
414 return 0;
415
416 split_version_tag:
417 /* Check for commit number */
418 if (*p >= '0' && *p <= '9')
419 goto split_version_commit;
420
421 /* Read tag */
422 if (strncmp(p, "dev", 3) == 0) { value[4] = 1; p += 3; }
423 else if (strncmp(p, "rc", 2) == 0) { value[4] = 2; p += 2; }
424 else if (strncmp(p, "pre", 3) == 0) { value[4] = 2; p += 3; }
425 else
426 goto split_version_commit;
427
428 /* Convert tag number */
429 value[5] = strtol(p, &error, 10);
430 p = error + 1;
431 if (*error == '\0')
432 return 1;
433 if (*error != '-')
434 return 0;
435
436 split_version_commit:
437 /* Search the last "-" */
438 s = strrchr(p, '-');
439 if (s) {
440 s++;
441 if (*s == '\0')
442 return 0;
443 value[6] = strtol(s, &error, 10);
444 if (*error != '\0')
445 value[6] = 0;
446 return 1;
447 }
448
449 /* convert the version */
450 value[6] = strtol(p, &error, 10);
451 if (*error != '\0')
452 value[6] = 0;
453
454 return 1;
455}
456
457/* This function compares the current haproxy version with an arbitrary version
458 * string. It returns:
459 * -1 : the version in argument is older than the current haproxy version
460 * 0 : the version in argument is the same as the current haproxy version
461 * 1 : the version in argument is newer than the current haproxy version
462 *
463 * Or some errors:
464 * -2 : the current haproxy version is not parsable
465 * -3 : the version in argument is not parsable
466 */
467int compare_current_version(const char *version)
468{
469 unsigned int loc[VERSION_MAX_ELTS];
470 unsigned int mod[VERSION_MAX_ELTS];
471 int i;
472
473 /* split versions */
474 if (!split_version(haproxy_version, loc))
475 return -2;
476 if (!split_version(version, mod))
477 return -3;
478
479 /* compare versions */
480 for (i = 0; i < VERSION_MAX_ELTS; i++) {
481 if (mod[i] < loc[i])
482 return -1;
483 else if (mod[i] > loc[i])
484 return 1;
485 }
486 return 0;
487}
488
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100489static void display_version()
Willy Tarreaubaaee002006-06-26 02:48:02 +0200490{
Tim Duesterhusdfad6a42020-04-18 16:02:47 +0200491 struct utsname utsname;
492
Willy Tarreaua5357cd2021-05-09 06:14:25 +0200493 printf("HAProxy version %s %s - https://haproxy.org/\n"
Willy Tarreau08dd2022019-11-21 18:07:30 +0100494 PRODUCT_STATUS "\n", haproxy_version, haproxy_date);
Willy Tarreau47479eb2019-11-21 18:48:20 +0100495
496 if (strlen(PRODUCT_URL_BUGS) > 0) {
497 char base_version[20];
498 int dots = 0;
499 char *del;
500
501 /* only retrieve the base version without distro-specific extensions */
502 for (del = haproxy_version; *del; del++) {
503 if (*del == '.')
504 dots++;
505 else if (*del < '0' || *del > '9')
506 break;
507 }
508
509 strlcpy2(base_version, haproxy_version, del - haproxy_version + 1);
510 if (dots < 2)
511 printf("Known bugs: https://github.com/haproxy/haproxy/issues?q=is:issue+is:open\n");
512 else
513 printf("Known bugs: " PRODUCT_URL_BUGS "\n", base_version);
514 }
Tim Duesterhusdfad6a42020-04-18 16:02:47 +0200515
516 if (uname(&utsname) == 0) {
517 printf("Running on: %s %s %s %s\n", utsname.sysname, utsname.release, utsname.version, utsname.machine);
518 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200519}
520
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100521static void display_build_opts()
Willy Tarreau7b066db2007-12-02 11:28:59 +0100522{
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100523 struct build_opts_str *item;
524
Willy Tarreau7b066db2007-12-02 11:28:59 +0100525 printf("Build options :"
526#ifdef BUILD_TARGET
Willy Tarreau9f2b7302008-01-02 20:48:34 +0100527 "\n TARGET = " BUILD_TARGET
Willy Tarreau7b066db2007-12-02 11:28:59 +0100528#endif
529#ifdef BUILD_CPU
Willy Tarreau9f2b7302008-01-02 20:48:34 +0100530 "\n CPU = " BUILD_CPU
Willy Tarreau7b066db2007-12-02 11:28:59 +0100531#endif
532#ifdef BUILD_CC
Willy Tarreau9f2b7302008-01-02 20:48:34 +0100533 "\n CC = " BUILD_CC
534#endif
535#ifdef BUILD_CFLAGS
536 "\n CFLAGS = " BUILD_CFLAGS
Willy Tarreau7b066db2007-12-02 11:28:59 +0100537#endif
Willy Tarreau9f2b7302008-01-02 20:48:34 +0100538#ifdef BUILD_OPTIONS
539 "\n OPTIONS = " BUILD_OPTIONS
Willy Tarreau7b066db2007-12-02 11:28:59 +0100540#endif
Tim Duesterhusc8d19702020-11-21 18:07:59 +0100541#ifdef BUILD_DEBUG
542 "\n DEBUG = " BUILD_DEBUG
543#endif
Willy Tarreau7728ed32019-03-27 13:20:08 +0100544#ifdef BUILD_FEATURES
545 "\n\nFeature list : " BUILD_FEATURES
546#endif
Willy Tarreau27a674e2009-08-17 07:23:33 +0200547 "\n\nDefault settings :"
Willy Tarreauca783d42019-03-13 10:03:07 +0100548 "\n bufsize = %d, maxrewrite = %d, maxpollevents = %d"
Willy Tarreau27a674e2009-08-17 07:23:33 +0200549 "\n\n",
Willy Tarreauca783d42019-03-13 10:03:07 +0100550 BUFSIZE, MAXREWRITE, MAX_POLL_EVENTS);
Willy Tarreaube5b6852009-10-03 18:57:08 +0200551
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100552 list_for_each_entry(item, &build_opts_list, list) {
553 puts(item->str);
554 }
555
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100556 putchar('\n');
557
Willy Tarreaube5b6852009-10-03 18:57:08 +0200558 list_pollers(stdout);
559 putchar('\n');
Christopher Faulet98d9fe22018-04-10 14:37:32 +0200560 list_mux_proto(stdout);
561 putchar('\n');
Willy Tarreau679bba12019-03-19 08:08:10 +0100562 list_services(stdout);
563 putchar('\n');
Christopher Fauletb3f4e142016-03-07 12:46:38 +0100564 list_filters(stdout);
565 putchar('\n');
Willy Tarreau7b066db2007-12-02 11:28:59 +0100566}
567
Willy Tarreaubaaee002006-06-26 02:48:02 +0200568/*
569 * This function prints the command line usage and exits
570 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100571static void usage(char *name)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200572{
573 display_version();
574 fprintf(stderr,
Maxime de Roucy379d9c72016-05-13 23:52:56 +0200575 "Usage : %s [-f <cfgfile|cfgdir>]* [ -vdV"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200576 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
Willy Tarreaua088d312015-10-08 11:58:48 +0200577 " [ -p <pidfile> ] [ -m <max megs> ] [ -C <dir> ] [-- <cfgfile>*]\n"
Willy Tarreau7b066db2007-12-02 11:28:59 +0100578 " -v displays version ; -vv shows known build options.\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200579 " -d enters debug mode ; -db only disables background mode.\n"
Willy Tarreauf4b79c42022-02-23 15:20:53 +0100580 " -dM[<byte>,help,...] debug memory (default: poison with <byte>/0x50)\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200581 " -V enters verbose mode (disables quiet mode)\n"
Willy Tarreau576132e2011-09-10 19:26:56 +0200582 " -D goes daemon ; -C changes to <dir> before loading files.\n"
William Lallemand095ba4c2017-06-01 17:38:50 +0200583 " -W master-worker mode.\n"
Tim Duesterhusd6942c82017-11-20 15:58:35 +0100584#if defined(USE_SYSTEMD)
585 " -Ws master-worker mode with systemd notify support.\n"
586#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +0200587 " -q quiet mode : don't display messages\n"
Willy Tarreau5d01a632009-06-22 16:02:30 +0200588 " -c check mode : only check config files and exit\n"
Maximilian Maderfc0cceb2021-06-06 00:50:22 +0200589 " -cc check condition : evaluate a condition and exit\n"
Willy Tarreauca783d42019-03-13 10:03:07 +0100590 " -n sets the maximum total # of connections (uses ulimit -n)\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200591 " -m limits the usable amount of memory (in MB)\n"
592 " -N sets the default, per-proxy maximum # of connections (%d)\n"
Emeric Brun2b920a12010-09-23 18:30:22 +0200593 " -L set local peer name (default to hostname)\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200594 " -p writes pids of all children to this file\n"
Erwan Le Goasf30c5d72022-09-29 10:34:04 +0200595 " -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 +0200596#if defined(USE_EPOLL)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200597 " -de disables epoll() usage even when available\n"
598#endif
Willy Tarreaue5733232019-05-22 19:24:06 +0200599#if defined(USE_KQUEUE)
Willy Tarreau1e63130a2007-04-09 12:03:06 +0200600 " -dk disables kqueue() usage even when available\n"
601#endif
Willy Tarreaue5733232019-05-22 19:24:06 +0200602#if defined(USE_EVPORTS)
Emmanuel Hocdet0ba4f482019-04-08 16:53:32 +0000603 " -dv disables event ports usage even when available\n"
604#endif
Willy Tarreaue5733232019-05-22 19:24:06 +0200605#if defined(USE_POLL)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200606 " -dp disables poll() usage even when available\n"
607#endif
Willy Tarreaue5733232019-05-22 19:24:06 +0200608#if defined(USE_LINUX_SPLICE)
Willy Tarreau3ab68cf2009-01-25 16:03:28 +0100609 " -dS disables splice usage (broken on old kernels)\n"
610#endif
Nenad Merdanovic88afe032014-04-14 15:56:58 +0200611#if defined(USE_GETADDRINFO)
612 " -dG disables getaddrinfo() usage\n"
613#endif
Lukas Tribusa0bcbdc2016-09-12 21:42:20 +0000614#if defined(SO_REUSEPORT)
615 " -dR disables SO_REUSEPORT usage\n"
616#endif
Willy Tarreau654726d2021-12-28 15:43:11 +0100617#if defined(HA_HAVE_DUMP_LIBS)
618 " -dL dumps loaded object files after config checks\n"
619#endif
Willy Tarreau76871a42022-03-08 16:01:40 +0100620 " -dK{class[,...]} dump registered keywords (use 'help' for list)\n"
Willy Tarreau3eed10e2016-11-07 21:03:16 +0100621 " -dr ignores server address resolution failures\n"
Emeric Brun850efd52014-01-29 12:24:34 +0100622 " -dV disables SSL verify on servers side\n"
Willy Tarreau3eb10b82020-04-15 16:42:39 +0200623 " -dW fails if any warning is emitted\n"
Amaury Denoyelle7b01a8d2021-03-29 10:29:07 +0200624 " -dD diagnostic mode : warn about suspicious configuration statements\n"
Christopher Faulet678a4ce2023-02-14 16:12:54 +0100625 " -dF disable fast-forward\n"
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +0200626 " -sf/-st [pid ]* finishes/terminates old pids.\n"
Olivier Houchardf73629d2017-04-05 22:33:04 +0200627 " -x <unix_socket> get listening sockets from a unix socket\n"
William Lallemand63329e32019-06-13 17:03:37 +0200628 " -S <bind>[,<bind options>...] new master CLI\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200629 "\n",
Willy Tarreauca783d42019-03-13 10:03:07 +0100630 name, cfg_maxpconn);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200631 exit(1);
632}
633
634
635
636/*********************************************************************/
637/* more specific functions ***************************************/
638/*********************************************************************/
639
William Lallemand73b85e72017-06-01 17:38:51 +0200640/* sends the signal <sig> to all pids found in <oldpids>. Returns the number of
641 * pids the signal was correctly delivered to.
642 */
William Lallemande25473c2019-04-01 11:29:56 +0200643int tell_old_pids(int sig)
William Lallemand73b85e72017-06-01 17:38:51 +0200644{
645 int p;
646 int ret = 0;
647 for (p = 0; p < nb_oldpids; p++)
648 if (kill(oldpids[p], sig) == 0)
649 ret++;
650 return ret;
651}
652
William Lallemand75ea0a02017-11-15 19:02:58 +0100653/*
William Lallemand73b85e72017-06-01 17:38:51 +0200654 * remove a pid forom the olpid array and decrease nb_oldpids
655 * return 1 pid was found otherwise return 0
656 */
657
658int delete_oldpid(int pid)
659{
660 int i;
661
662 for (i = 0; i < nb_oldpids; i++) {
663 if (oldpids[i] == pid) {
664 oldpids[i] = oldpids[nb_oldpids - 1];
665 oldpids[nb_oldpids - 1] = 0;
666 nb_oldpids--;
667 return 1;
668 }
669 }
670 return 0;
671}
672
William Lallemand85b0bd92017-06-01 17:38:53 +0200673
William Lallemand73b85e72017-06-01 17:38:51 +0200674/*
675 * When called, this function reexec haproxy with -sf followed by current
Joseph Herlant03420902018-11-15 10:41:50 -0800676 * children PIDs and possibly old children PIDs if they didn't leave yet.
William Lallemand73b85e72017-06-01 17:38:51 +0200677 */
William Lallemandfab0fdc2021-11-09 18:01:22 +0100678static void mworker_reexec()
William Lallemand73b85e72017-06-01 17:38:51 +0200679{
William Lallemand00417412020-06-05 14:08:41 +0200680 char **next_argv = NULL;
681 int old_argc = 0; /* previous number of argument */
William Lallemand73b85e72017-06-01 17:38:51 +0200682 int next_argc = 0;
William Lallemand00417412020-06-05 14:08:41 +0200683 int i = 0;
William Lallemand73b85e72017-06-01 17:38:51 +0200684 char *msg = NULL;
Willy Tarreau8dca1952019-03-01 10:21:55 +0100685 struct rlimit limit;
William Lallemand2be557f2021-11-24 18:45:37 +0100686 struct mworker_proc *current_child = NULL;
William Lallemand73b85e72017-06-01 17:38:51 +0200687
688 mworker_block_signals();
William Lallemand73b85e72017-06-01 17:38:51 +0200689 setenv("HAPROXY_MWORKER_REEXEC", "1", 1);
690
William Lallemand55a921c2022-01-28 21:17:30 +0100691 mworker_cleanup_proc();
William Lallemandbc193052018-09-11 10:06:26 +0200692 mworker_proc_list_to_env(); /* put the children description in the env */
693
William Lallemandc4810b82021-11-18 10:51:30 +0100694 /* ensure that we close correctly every listeners before reexecuting */
695 mworker_cleanlisteners();
696
William Lallemand7c756a82018-11-26 11:53:40 +0100697 /* during the reload we must ensure that every FDs that can't be
698 * reuse (ie those that are not referenced in the proc_list)
699 * are closed or they will leak. */
700
701 /* close the listeners FD */
702 mworker_cli_proxy_stop();
William Lallemand16866672019-06-24 17:40:48 +0200703
William Lallemand67e371e2021-11-25 10:03:44 +0100704 if (fdtab)
705 deinit_pollers();
William Lallemandefd95472021-11-26 14:43:57 +0100706
Ilya Shipitsin98a9e1b2021-02-19 23:42:53 +0500707#ifdef HAVE_SSL_RAND_KEEP_RANDOM_DEVICES_OPEN
William Lallemand5fdb5b32019-10-15 14:04:08 +0200708 /* close random device FDs */
709 RAND_keep_random_devices_open(0);
Rob Allen56996da2019-05-03 09:11:32 +0100710#endif
William Lallemand7c756a82018-11-26 11:53:40 +0100711
Willy Tarreau8dca1952019-03-01 10:21:55 +0100712 /* restore the initial FD limits */
713 limit.rlim_cur = rlim_fd_cur_at_boot;
714 limit.rlim_max = rlim_fd_max_at_boot;
Willy Tarreauc06557c2022-09-22 16:12:08 +0200715 if (raise_rlim_nofile(&limit, &limit) != 0) {
Willy Tarreau8dca1952019-03-01 10:21:55 +0100716 ha_warning("Failed to restore initial FD limits (cur=%u max=%u), using cur=%u max=%u\n",
717 rlim_fd_cur_at_boot, rlim_fd_max_at_boot,
718 (unsigned int)limit.rlim_cur, (unsigned int)limit.rlim_max);
719 }
720
William Lallemand73b85e72017-06-01 17:38:51 +0200721 /* compute length */
William Lallemand00417412020-06-05 14:08:41 +0200722 while (old_argv[old_argc])
723 old_argc++;
William Lallemand73b85e72017-06-01 17:38:51 +0200724
William Lallemand85b0bd92017-06-01 17:38:53 +0200725 /* 1 for haproxy -sf, 2 for -x /socket */
William Lallemandaba7f8b2021-04-21 16:55:34 +0200726 next_argv = calloc(old_argc + 1 + 2 + mworker_child_nb() + 1,
Tim Duesterhuse52b6e52020-09-12 20:26:43 +0200727 sizeof(*next_argv));
William Lallemand73b85e72017-06-01 17:38:51 +0200728 if (next_argv == NULL)
729 goto alloc_error;
730
William Lallemand00417412020-06-05 14:08:41 +0200731 /* copy the program name */
732 next_argv[next_argc++] = old_argv[0];
733
734 /* insert the new options just after argv[0] in case we have a -- */
735
William Lallemandbefab9e2021-11-25 00:49:19 +0100736 if (getenv("HAPROXY_MWORKER_WAIT_ONLY") == NULL) {
737 /* add -sf <PID>* to argv */
738 if (mworker_child_nb() > 0) {
739 struct mworker_proc *child;
William Lallemand3f128872019-04-01 11:29:59 +0200740
William Lallemandbefab9e2021-11-25 00:49:19 +0100741 next_argv[next_argc++] = "-sf";
William Lallemand3f128872019-04-01 11:29:59 +0200742
William Lallemandbefab9e2021-11-25 00:49:19 +0100743 list_for_each_entry(child, &proc_list, list) {
744 if (!(child->options & PROC_O_LEAVING) && (child->options & PROC_O_TYPE_WORKER))
745 current_child = child;
William Lallemand2be557f2021-11-24 18:45:37 +0100746
William Lallemandbefab9e2021-11-25 00:49:19 +0100747 if (!(child->options & (PROC_O_TYPE_WORKER|PROC_O_TYPE_PROG)) || child->pid <= -1)
748 continue;
749 if ((next_argv[next_argc++] = memprintf(&msg, "%d", child->pid)) == NULL)
750 goto alloc_error;
751 msg = NULL;
752 }
William Lallemand73b85e72017-06-01 17:38:51 +0200753 }
William Lallemand2be557f2021-11-24 18:45:37 +0100754
755 if (current_child) {
756 /* add the -x option with the socketpair of the current worker */
757 next_argv[next_argc++] = "-x";
758 if ((next_argv[next_argc++] = memprintf(&msg, "sockpair@%d", current_child->ipc_fd[0])) == NULL)
759 goto alloc_error;
760 msg = NULL;
761 }
William Lallemand85b0bd92017-06-01 17:38:53 +0200762 }
763
William Lallemand00417412020-06-05 14:08:41 +0200764 /* copy the previous options */
765 for (i = 1; i < old_argc; i++)
766 next_argv[next_argc++] = old_argv[i];
767
Willy Tarreaue0d86e22019-08-26 10:37:39 +0200768 signal(SIGPROF, SIG_IGN);
Tim Duesterhus0436ab72017-11-12 17:39:18 +0100769 execvp(next_argv[0], next_argv);
Christopher Faulet767a84b2017-11-24 16:50:31 +0100770 ha_warning("Failed to reexecute the master process [%d]: %s\n", pid, strerror(errno));
Willy Tarreau61cfdf42021-02-20 10:46:51 +0100771 ha_free(&next_argv);
William Lallemand722d4ca2017-11-15 19:02:55 +0100772 return;
773
William Lallemand73b85e72017-06-01 17:38:51 +0200774alloc_error:
Willy Tarreau61cfdf42021-02-20 10:46:51 +0100775 ha_free(&next_argv);
Joseph Herlant07a08342018-11-15 10:43:05 -0800776 ha_warning("Failed to reexecute the master process [%d]: Cannot allocate memory\n", pid);
William Lallemand73b85e72017-06-01 17:38:51 +0200777 return;
778}
779
William Lallemandfab0fdc2021-11-09 18:01:22 +0100780/* reexec haproxy in waitmode */
781static void mworker_reexec_waitmode()
782{
783 setenv("HAPROXY_MWORKER_WAIT_ONLY", "1", 1);
784 mworker_reexec();
785}
786
787/* reload haproxy and emit a warning */
788void mworker_reload()
789{
William Lallemandad221f42021-11-09 18:43:59 +0100790 struct mworker_proc *child;
William Lallemandefd95472021-11-26 14:43:57 +0100791 struct per_thread_deinit_fct *ptdf;
William Lallemandad221f42021-11-09 18:43:59 +0100792
William Lallemand836bda22021-11-09 18:16:47 +0100793 ha_notice("Reloading HAProxy\n");
William Lallemandad221f42021-11-09 18:43:59 +0100794
William Lallemandefd95472021-11-26 14:43:57 +0100795 /* close the poller FD and the thread waker pipe FD */
796 list_for_each_entry(ptdf, &per_thread_deinit_list, list)
797 ptdf->fct();
798
William Lallemandad221f42021-11-09 18:43:59 +0100799 /* increment the number of reloads */
800 list_for_each_entry(child, &proc_list, list) {
801 child->reloads++;
802 }
803
William Lallemanda46a99e2022-07-07 14:00:36 +0200804#if defined(USE_SYSTEMD)
805 if (global.tune.options & GTUNE_USE_SYSTEMD)
806 sd_notify(0, "RELOADING=1\nSTATUS=Reloading Configuration.\n");
807#endif
William Lallemandfab0fdc2021-11-09 18:01:22 +0100808 mworker_reexec();
809}
810
William Lallemandb3f2be32018-09-11 10:06:18 +0200811static void mworker_loop()
812{
813
Willy Tarreaud83b6c12019-04-18 11:31:36 +0200814 /* Busy polling makes no sense in the master :-) */
815 global.tune.options &= ~GTUNE_BUSY_POLLING;
William Lallemandb3f2be32018-09-11 10:06:18 +0200816
William Lallemandbc193052018-09-11 10:06:26 +0200817
Willy Tarreaud26c9f92019-12-11 14:24:07 +0100818 signal_unregister(SIGTTIN);
819 signal_unregister(SIGTTOU);
William Lallemand0564d412018-11-20 17:36:53 +0100820 signal_unregister(SIGUSR1);
821 signal_unregister(SIGHUP);
822 signal_unregister(SIGQUIT);
823
William Lallemandb3f2be32018-09-11 10:06:18 +0200824 signal_register_fct(SIGTERM, mworker_catch_sigterm, SIGTERM);
825 signal_register_fct(SIGUSR1, mworker_catch_sigterm, SIGUSR1);
Willy Tarreaud26c9f92019-12-11 14:24:07 +0100826 signal_register_fct(SIGTTIN, mworker_broadcast_signal, SIGTTIN);
827 signal_register_fct(SIGTTOU, mworker_broadcast_signal, SIGTTOU);
William Lallemandb3f2be32018-09-11 10:06:18 +0200828 signal_register_fct(SIGINT, mworker_catch_sigterm, SIGINT);
829 signal_register_fct(SIGHUP, mworker_catch_sighup, SIGHUP);
830 signal_register_fct(SIGUSR2, mworker_catch_sighup, SIGUSR2);
831 signal_register_fct(SIGCHLD, mworker_catch_sigchld, SIGCHLD);
832
833 mworker_unblock_signals();
William Lallemand27f3fa52018-12-06 14:05:20 +0100834 mworker_cleantasks();
William Lallemandb3f2be32018-09-11 10:06:18 +0200835
William Lallemandbc193052018-09-11 10:06:26 +0200836 mworker_catch_sigchld(NULL); /* ensure we clean the children in case
837 some SIGCHLD were lost */
838
William Lallemandb3f2be32018-09-11 10:06:18 +0200839 jobs++; /* this is the "master" job, we want to take care of the
840 signals even if there is no listener so the poll loop don't
841 leave */
842
843 fork_poller();
Willy Tarreau43ab05b2021-09-28 09:43:11 +0200844 run_thread_poll_loop(NULL);
William Lallemandb3f2be32018-09-11 10:06:18 +0200845}
William Lallemandcb11fd22017-06-01 17:38:52 +0200846
847/*
848 * Reexec the process in failure mode, instead of exiting
849 */
850void reexec_on_failure()
851{
William Lallemand68836742021-11-10 10:49:06 +0100852 struct mworker_proc *child;
853
William Lallemandcb11fd22017-06-01 17:38:52 +0200854 if (!atexit_flag)
855 return;
William Lallemand68836742021-11-10 10:49:06 +0100856
857 /* get the info of the children in the env */
858 if (mworker_env_to_proc_list() < 0) {
859 exit(EXIT_FAILURE);
860 }
861
862 /* increment the number of failed reloads */
863 list_for_each_entry(child, &proc_list, list) {
864 child->failedreloads++;
865 }
866
Willy Tarreaue08acae2022-01-28 18:40:06 +0100867 /* do not keep unused FDs retrieved from the previous process */
868 sock_drop_unused_old_sockets();
869
William Lallemandfab0fdc2021-11-09 18:01:22 +0100870 usermsgs_clr(NULL);
William Lallemand68192b22022-09-24 15:44:42 +0200871 setenv("HAPROXY_LOAD_SUCCESS", "0", 1);
William Lallemand836bda22021-11-09 18:16:47 +0100872 ha_warning("Loading failure!\n");
William Lallemanda46a99e2022-07-07 14:00:36 +0200873#if defined(USE_SYSTEMD)
874 /* the sd_notify API is not able to send a reload failure signal. So
875 * the READY=1 signal still need to be sent */
876 if (global.tune.options & GTUNE_USE_SYSTEMD)
877 sd_notify(0, "READY=1\nSTATUS=Reload failed!\n");
878#endif
879
William Lallemandfab0fdc2021-11-09 18:01:22 +0100880 mworker_reexec_waitmode();
William Lallemandcb11fd22017-06-01 17:38:52 +0200881}
William Lallemand73b85e72017-06-01 17:38:51 +0200882
William Lallemand40db4ae2022-12-07 15:03:55 +0100883/*
884 * Exit with an error message upon a wait-mode failure.
885 */
886void exit_on_waitmode_failure()
887{
888 if (!atexit_flag)
889 return;
890
891 ha_alert("Non-recoverable mworker wait-mode error, exiting.\n");
892}
893
William Lallemand73b85e72017-06-01 17:38:51 +0200894
895/*
Willy Tarreaud0807c32010-08-27 18:26:11 +0200896 * upon SIGUSR1, let's have a soft stop. Note that soft_stop() broadcasts
897 * a signal zero to all subscribers. This means that it's as easy as
898 * subscribing to signal 0 to get informed about an imminent shutdown.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200899 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100900static void sig_soft_stop(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200901{
902 soft_stop();
Willy Tarreau24f4efa2010-08-27 17:56:48 +0200903 signal_unregister_handler(sh);
Willy Tarreaubafbe012017-11-24 17:34:44 +0100904 pool_gc(NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200905}
906
907/*
908 * upon SIGTTOU, we pause everything
909 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100910static void sig_pause(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200911{
Willy Tarreau775e0012020-09-24 16:36:26 +0200912 if (protocol_pause_all() & ERR_FATAL) {
913 const char *msg = "Some proxies refused to pause, performing soft stop now.\n";
Willy Tarreau0a002df2020-10-09 19:26:27 +0200914 ha_warning("%s", msg);
915 send_log(NULL, LOG_WARNING, "%s", msg);
Willy Tarreau775e0012020-09-24 16:36:26 +0200916 soft_stop();
917 }
Willy Tarreaubafbe012017-11-24 17:34:44 +0100918 pool_gc(NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200919}
920
921/*
922 * upon SIGTTIN, let's have a soft stop.
923 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100924static void sig_listen(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200925{
Willy Tarreau775e0012020-09-24 16:36:26 +0200926 if (protocol_resume_all() & ERR_FATAL) {
927 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 +0200928 ha_warning("%s", msg);
929 send_log(NULL, LOG_WARNING, "%s", msg);
Willy Tarreau775e0012020-09-24 16:36:26 +0200930 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200931}
932
933/*
934 * this function dumps every server's state when the process receives SIGHUP.
935 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100936static void sig_dump_state(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200937{
Olivier Houchardfbc74e82017-11-24 16:54:05 +0100938 struct proxy *p = proxies_list;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200939
Christopher Faulet767a84b2017-11-24 16:50:31 +0100940 ha_warning("SIGHUP received, dumping servers states.\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +0200941 while (p) {
942 struct server *s = p->srv;
943
944 send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
945 while (s) {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100946 chunk_printf(&trash,
947 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %lld tot.",
948 p->id, s->id,
Emeric Brun52a91d32017-08-31 14:41:55 +0200949 (s->cur_state != SRV_ST_STOPPED) ? "UP" : "DOWN",
Willy Tarreaua0570452021-06-18 09:30:30 +0200950 s->cur_sess, s->queue.length, s->counters.cum_sess);
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200951 ha_warning("%s\n", trash.area);
952 send_log(p, LOG_NOTICE, "%s\n", trash.area);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200953 s = s->next;
954 }
955
Willy Tarreau5fcc8f12007-09-17 11:27:09 +0200956 /* FIXME: those info are a bit outdated. We should be able to distinguish between FE and BE. */
957 if (!p->srv) {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100958 chunk_printf(&trash,
959 "SIGHUP: Proxy %s has no servers. Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
960 p->id,
Willy Tarreau7f3c1df2021-06-18 09:22:21 +0200961 p->feconn, p->beconn, p->totpend, p->queue.length, p->fe_counters.cum_conn, p->be_counters.cum_conn);
Willy Tarreau5fcc8f12007-09-17 11:27:09 +0200962 } else if (p->srv_act == 0) {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100963 chunk_printf(&trash,
964 "SIGHUP: Proxy %s %s ! Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
965 p->id,
966 (p->srv_bck) ? "is running on backup servers" : "has no server available",
Willy Tarreau7f3c1df2021-06-18 09:22:21 +0200967 p->feconn, p->beconn, p->totpend, p->queue.length, p->fe_counters.cum_conn, p->be_counters.cum_conn);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200968 } else {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100969 chunk_printf(&trash,
970 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
971 " Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
972 p->id, p->srv_act, p->srv_bck,
Willy Tarreau7f3c1df2021-06-18 09:22:21 +0200973 p->feconn, p->beconn, p->totpend, p->queue.length, p->fe_counters.cum_conn, p->be_counters.cum_conn);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200974 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200975 ha_warning("%s\n", trash.area);
976 send_log(p, LOG_NOTICE, "%s\n", trash.area);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200977
978 p = p->next;
979 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200980}
981
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100982static void dump(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200983{
Willy Tarreauc6ca1a02007-05-13 19:43:47 +0200984 /* dump memory usage then free everything possible */
985 dump_pools();
Willy Tarreaubafbe012017-11-24 17:34:44 +0100986 pool_gc(NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200987}
988
William Lallemande1340412017-12-28 16:09:36 +0100989/*
990 * This function dup2 the stdio FDs (0,1,2) with <fd>, then closes <fd>
991 * If <fd> < 0, it opens /dev/null and use it to dup
992 *
993 * In the case of chrooting, you have to open /dev/null before the chroot, and
994 * pass the <fd> to this function
995 */
996static void stdio_quiet(int fd)
997{
998 if (fd < 0)
999 fd = open("/dev/null", O_RDWR, 0);
1000
1001 if (fd > -1) {
1002 fclose(stdin);
1003 fclose(stdout);
1004 fclose(stderr);
1005
1006 dup2(fd, 0);
1007 dup2(fd, 1);
1008 dup2(fd, 2);
1009 if (fd > 2)
1010 close(fd);
1011 return;
1012 }
1013
1014 ha_alert("Cannot open /dev/null\n");
1015 exit(EXIT_FAILURE);
1016}
1017
1018
Joseph Herlant03420902018-11-15 10:41:50 -08001019/* This function checks if cfg_cfgfiles contains directories.
1020 * If it finds one, it adds all the files (and only files) it contains
1021 * in cfg_cfgfiles in place of the directory (and removes the directory).
1022 * It adds the files in lexical order.
1023 * It adds only files with .cfg extension.
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001024 * It doesn't add files with name starting with '.'
1025 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +01001026static void cfgfiles_expand_directories(void)
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001027{
1028 struct wordlist *wl, *wlb;
1029 char *err = NULL;
1030
1031 list_for_each_entry_safe(wl, wlb, &cfg_cfgfiles, list) {
1032 struct stat file_stat;
1033 struct dirent **dir_entries = NULL;
1034 int dir_entries_nb;
1035 int dir_entries_it;
1036
1037 if (stat(wl->s, &file_stat)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001038 ha_alert("Cannot open configuration file/directory %s : %s\n",
1039 wl->s,
1040 strerror(errno));
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001041 exit(1);
1042 }
1043
1044 if (!S_ISDIR(file_stat.st_mode))
1045 continue;
1046
1047 /* from this point wl->s is a directory */
1048
1049 dir_entries_nb = scandir(wl->s, &dir_entries, NULL, alphasort);
1050 if (dir_entries_nb < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001051 ha_alert("Cannot open configuration directory %s : %s\n",
1052 wl->s,
1053 strerror(errno));
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001054 exit(1);
1055 }
1056
1057 /* for each element in the directory wl->s */
1058 for (dir_entries_it = 0; dir_entries_it < dir_entries_nb; dir_entries_it++) {
1059 struct dirent *dir_entry = dir_entries[dir_entries_it];
1060 char *filename = NULL;
1061 char *d_name_cfgext = strstr(dir_entry->d_name, ".cfg");
1062
1063 /* don't add filename that begin with .
Joseph Herlant03420902018-11-15 10:41:50 -08001064 * only add filename with .cfg extension
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001065 */
1066 if (dir_entry->d_name[0] == '.' ||
1067 !(d_name_cfgext && d_name_cfgext[4] == '\0'))
1068 goto next_dir_entry;
1069
1070 if (!memprintf(&filename, "%s/%s", wl->s, dir_entry->d_name)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001071 ha_alert("Cannot load configuration files %s : out of memory.\n",
1072 filename);
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001073 exit(1);
1074 }
1075
1076 if (stat(filename, &file_stat)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001077 ha_alert("Cannot open configuration file %s : %s\n",
1078 wl->s,
1079 strerror(errno));
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001080 exit(1);
1081 }
1082
1083 /* don't add anything else than regular file in cfg_cfgfiles
1084 * this way we avoid loops
1085 */
1086 if (!S_ISREG(file_stat.st_mode))
1087 goto next_dir_entry;
1088
1089 if (!list_append_word(&wl->list, filename, &err)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001090 ha_alert("Cannot load configuration files %s : %s\n",
1091 filename,
1092 err);
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001093 exit(1);
1094 }
1095
1096next_dir_entry:
1097 free(filename);
1098 free(dir_entry);
1099 }
1100
1101 free(dir_entries);
1102
1103 /* remove the current directory (wl) from cfg_cfgfiles */
1104 free(wl->s);
Willy Tarreau2b718102021-04-21 07:32:39 +02001105 LIST_DELETE(&wl->list);
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001106 free(wl);
1107 }
1108
1109 free(err);
1110}
1111
Willy Tarreaubaaee002006-06-26 02:48:02 +02001112/*
William Lallemand73b85e72017-06-01 17:38:51 +02001113 * copy and cleanup the current argv
William Lallemanddf6c5a82020-06-04 17:40:23 +02001114 * Remove the -sf /-st / -x parameters
William Lallemand73b85e72017-06-01 17:38:51 +02001115 * Return an allocated copy of argv
1116 */
1117
1118static char **copy_argv(int argc, char **argv)
1119{
William Lallemanddf6c5a82020-06-04 17:40:23 +02001120 char **newargv, **retargv;
William Lallemand73b85e72017-06-01 17:38:51 +02001121
Tim Duesterhuse52b6e52020-09-12 20:26:43 +02001122 newargv = calloc(argc + 2, sizeof(*newargv));
William Lallemand73b85e72017-06-01 17:38:51 +02001123 if (newargv == NULL) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001124 ha_warning("Cannot allocate memory\n");
William Lallemand73b85e72017-06-01 17:38:51 +02001125 return NULL;
1126 }
William Lallemanddf6c5a82020-06-04 17:40:23 +02001127 retargv = newargv;
William Lallemand73b85e72017-06-01 17:38:51 +02001128
William Lallemanddf6c5a82020-06-04 17:40:23 +02001129 /* first copy argv[0] */
1130 *newargv++ = *argv++;
1131 argc--;
1132
1133 while (argc > 0) {
1134 if (**argv != '-') {
1135 /* non options are copied but will fail in the argument parser */
1136 *newargv++ = *argv++;
1137 argc--;
1138
1139 } else {
1140 char *flag;
1141
1142 flag = *argv + 1;
1143
1144 if (flag[0] == '-' && flag[1] == 0) {
1145 /* "--\0" copy every arguments till the end of argv */
1146 *newargv++ = *argv++;
1147 argc--;
1148
1149 while (argc > 0) {
1150 *newargv++ = *argv++;
1151 argc--;
1152 }
1153 } else {
1154 switch (*flag) {
1155 case 's':
1156 /* -sf / -st and their parameters are ignored */
1157 if (flag[1] == 'f' || flag[1] == 't') {
1158 argc--;
1159 argv++;
1160 /* The list can't contain a negative value since the only
1161 way to know the end of this list is by looking for the
1162 next option or the end of the options */
1163 while (argc > 0 && argv[0][0] != '-') {
1164 argc--;
1165 argv++;
1166 }
William Lallemand398da622020-09-02 16:12:23 +02001167 } else {
1168 argc--;
1169 argv++;
1170
William Lallemanddf6c5a82020-06-04 17:40:23 +02001171 }
1172 break;
1173
1174 case 'x':
1175 /* this option and its parameter are ignored */
1176 argc--;
1177 argv++;
1178 if (argc > 0) {
1179 argc--;
1180 argv++;
1181 }
1182 break;
1183
1184 case 'C':
1185 case 'n':
1186 case 'm':
1187 case 'N':
1188 case 'L':
1189 case 'f':
1190 case 'p':
1191 case 'S':
1192 /* these options have only 1 parameter which must be copied and can start with a '-' */
1193 *newargv++ = *argv++;
1194 argc--;
1195 if (argc == 0)
1196 goto error;
1197 *newargv++ = *argv++;
1198 argc--;
1199 break;
1200 default:
1201 /* for other options just copy them without parameters, this is also done
1202 * for options like "--foo", but this will fail in the argument parser.
1203 * */
1204 *newargv++ = *argv++;
1205 argc--;
1206 break;
1207 }
William Lallemand73b85e72017-06-01 17:38:51 +02001208 }
1209 }
William Lallemand73b85e72017-06-01 17:38:51 +02001210 }
William Lallemand2bf6d622017-06-20 11:20:23 +02001211
William Lallemanddf6c5a82020-06-04 17:40:23 +02001212 return retargv;
1213
1214error:
1215 free(retargv);
1216 return NULL;
William Lallemand73b85e72017-06-01 17:38:51 +02001217}
1218
Willy Tarreau6c3a6812020-03-06 18:57:15 +01001219
1220/* Performs basic random seed initialization. The main issue with this is that
1221 * srandom_r() only takes 32 bits and purposely provides a reproducible sequence,
1222 * which means that there will only be 4 billion possible random sequences once
1223 * srandom() is called, regardless of the internal state. Not calling it is
1224 * even worse as we'll always produce the same randoms sequences. What we do
1225 * here is to create an initial sequence from various entropy sources, hash it
1226 * using SHA1 and keep the resulting 160 bits available globally.
1227 *
1228 * We initialize the current process with the first 32 bits before starting the
1229 * polling loop, where all this will be changed to have process specific and
1230 * thread specific sequences.
Willy Tarreau52bf8392020-03-08 00:42:37 +01001231 *
1232 * Before starting threads, it's still possible to call random() as srandom()
1233 * is initialized from this, but after threads and/or processes are started,
1234 * only ha_random() is expected to be used to guarantee distinct sequences.
Willy Tarreau6c3a6812020-03-06 18:57:15 +01001235 */
1236static void ha_random_boot(char *const *argv)
1237{
1238 unsigned char message[256];
1239 unsigned char *m = message;
1240 struct timeval tv;
1241 blk_SHA_CTX ctx;
1242 unsigned long l;
1243 int fd;
1244 int i;
1245
1246 /* start with current time as pseudo-random seed */
1247 gettimeofday(&tv, NULL);
1248 write_u32(m, tv.tv_sec); m += 4;
1249 write_u32(m, tv.tv_usec); m += 4;
1250
1251 /* PID and PPID add some OS-based randomness */
1252 write_u16(m, getpid()); m += 2;
1253 write_u16(m, getppid()); m += 2;
1254
1255 /* take up to 160 bits bytes from /dev/urandom if available (non-blocking) */
1256 fd = open("/dev/urandom", O_RDONLY);
1257 if (fd >= 0) {
1258 i = read(fd, m, 20);
1259 if (i > 0)
1260 m += i;
1261 close(fd);
1262 }
1263
1264 /* take up to 160 bits bytes from openssl (non-blocking) */
1265#ifdef USE_OPENSSL
1266 if (RAND_bytes(m, 20) == 1)
1267 m += 20;
1268#endif
1269
1270 /* take 160 bits from existing random in case it was already initialized */
1271 for (i = 0; i < 5; i++) {
1272 write_u32(m, random());
1273 m += 4;
1274 }
1275
1276 /* stack address (benefit form operating system's ASLR) */
1277 l = (unsigned long)&m;
1278 memcpy(m, &l, sizeof(l)); m += sizeof(l);
1279
1280 /* argv address (benefit form operating system's ASLR) */
1281 l = (unsigned long)&argv;
1282 memcpy(m, &l, sizeof(l)); m += sizeof(l);
1283
1284 /* use tv_usec again after all the operations above */
1285 gettimeofday(&tv, NULL);
1286 write_u32(m, tv.tv_usec); m += 4;
1287
1288 /*
1289 * At this point, ~84-92 bytes have been used
1290 */
1291
1292 /* finish with the hostname */
1293 strncpy((char *)m, hostname, message + sizeof(message) - m);
1294 m += strlen(hostname);
1295
1296 /* total message length */
1297 l = m - message;
1298
1299 memset(&ctx, 0, sizeof(ctx));
1300 blk_SHA1_Init(&ctx);
1301 blk_SHA1_Update(&ctx, message, l);
1302 blk_SHA1_Final(boot_seed, &ctx);
1303
1304 srandom(read_u32(boot_seed));
Willy Tarreau52bf8392020-03-08 00:42:37 +01001305 ha_random_seed(boot_seed, sizeof(boot_seed));
Willy Tarreau6c3a6812020-03-06 18:57:15 +01001306}
1307
Willy Tarreau5a023f02019-03-01 14:19:31 +01001308/* considers splicing proxies' maxconn, computes the ideal global.maxpipes
1309 * setting, and returns it. It may return -1 meaning "unlimited" if some
1310 * unlimited proxies have been found and the global.maxconn value is not yet
1311 * set. It may also return a value greater than maxconn if it's not yet set.
1312 * Note that a value of zero means there is no need for pipes. -1 is never
1313 * returned if global.maxconn is valid.
1314 */
1315static int compute_ideal_maxpipes()
1316{
1317 struct proxy *cur;
1318 int nbfe = 0, nbbe = 0;
1319 int unlimited = 0;
1320 int pipes;
1321 int max;
1322
1323 for (cur = proxies_list; cur; cur = cur->next) {
1324 if (cur->options2 & (PR_O2_SPLIC_ANY)) {
1325 if (cur->cap & PR_CAP_FE) {
1326 max = cur->maxconn;
1327 nbfe += max;
1328 if (!max) {
1329 unlimited = 1;
1330 break;
1331 }
1332 }
1333 if (cur->cap & PR_CAP_BE) {
1334 max = cur->fullconn ? cur->fullconn : global.maxconn;
1335 nbbe += max;
1336 if (!max) {
1337 unlimited = 1;
1338 break;
1339 }
1340 }
1341 }
1342 }
1343
1344 pipes = MAX(nbfe, nbbe);
1345 if (global.maxconn) {
1346 if (pipes > global.maxconn || unlimited)
1347 pipes = global.maxconn;
1348 } else if (unlimited) {
1349 pipes = -1;
1350 }
1351
1352 return pipes >= 4 ? pipes / 4 : pipes;
1353}
1354
Willy Tarreauac350932019-03-01 15:43:14 +01001355/* considers global.maxsocks, global.maxpipes, async engines, SSL frontends and
1356 * rlimits and computes an ideal maxconn. It's meant to be called only when
1357 * maxsock contains the sum of listening FDs, before it is updated based on
Willy Tarreaudf23c0c2019-03-13 10:10:49 +01001358 * maxconn and pipes. If there are not enough FDs left, DEFAULT_MAXCONN (by
1359 * default 100) is returned as it is expected that it will even run on tight
1360 * environments, and will maintain compatibility with previous packages that
1361 * used to rely on this value as the default one. The system will emit a
1362 * warning indicating how many FDs are missing anyway if needed.
Willy Tarreauac350932019-03-01 15:43:14 +01001363 */
1364static int compute_ideal_maxconn()
1365{
1366 int ssl_sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
1367 int engine_fds = global.ssl_used_async_engines * ssl_sides;
1368 int pipes = compute_ideal_maxpipes();
Willy Tarreaub1beaa32020-03-06 10:25:31 +01001369 int remain = MAX(rlim_fd_cur_at_boot, rlim_fd_max_at_boot);
Willy Tarreauac350932019-03-01 15:43:14 +01001370 int maxconn;
1371
1372 /* we have to take into account these elements :
1373 * - number of engine_fds, which inflates the number of FD needed per
1374 * connection by this number.
1375 * - number of pipes per connection on average : for the unlimited
1376 * case, this is 0.5 pipe FDs per connection, otherwise it's a
1377 * fixed value of 2*pipes.
1378 * - two FDs per connection
1379 */
1380
Willy Tarreau2df1fbf2022-04-25 18:02:03 +02001381 if (global.fd_hard_limit && remain > global.fd_hard_limit)
1382 remain = global.fd_hard_limit;
1383
Willy Tarreauac350932019-03-01 15:43:14 +01001384 /* subtract listeners and checks */
1385 remain -= global.maxsock;
1386
Willy Tarreau3f200852019-03-14 19:13:17 +01001387 /* one epoll_fd/kqueue_fd per thread */
1388 remain -= global.nbthread;
1389
1390 /* one wake-up pipe (2 fd) per thread */
1391 remain -= 2 * global.nbthread;
1392
Willy Tarreauac350932019-03-01 15:43:14 +01001393 /* Fixed pipes values : we only subtract them if they're not larger
1394 * than the remaining FDs because pipes are optional.
1395 */
1396 if (pipes >= 0 && pipes * 2 < remain)
1397 remain -= pipes * 2;
1398
1399 if (pipes < 0) {
1400 /* maxsock = maxconn * 2 + maxconn/4 * 2 + maxconn * engine_fds.
1401 * = maxconn * (2 + 0.5 + engine_fds)
1402 * = maxconn * (4 + 1 + 2*engine_fds) / 2
1403 */
1404 maxconn = 2 * remain / (5 + 2 * engine_fds);
1405 } else {
1406 /* maxsock = maxconn * 2 + maxconn * engine_fds.
1407 * = maxconn * (2 + engine_fds)
1408 */
1409 maxconn = remain / (2 + engine_fds);
1410 }
1411
Willy Tarreaudf23c0c2019-03-13 10:10:49 +01001412 return MAX(maxconn, DEFAULT_MAXCONN);
Willy Tarreauac350932019-03-01 15:43:14 +01001413}
1414
Willy Tarreaua409f302020-03-10 17:08:53 +01001415/* computes the estimated maxsock value for the given maxconn based on the
1416 * possibly set global.maxpipes and existing partial global.maxsock. It may
1417 * temporarily change global.maxconn for the time needed to propagate the
1418 * computations, and will reset it.
1419 */
1420static int compute_ideal_maxsock(int maxconn)
1421{
1422 int maxpipes = global.maxpipes;
1423 int maxsock = global.maxsock;
1424
1425
1426 if (!maxpipes) {
1427 int old_maxconn = global.maxconn;
1428
1429 global.maxconn = maxconn;
1430 maxpipes = compute_ideal_maxpipes();
1431 global.maxconn = old_maxconn;
1432 }
1433
1434 maxsock += maxconn * 2; /* each connection needs two sockets */
1435 maxsock += maxpipes * 2; /* each pipe needs two FDs */
1436 maxsock += global.nbthread; /* one epoll_fd/kqueue_fd per thread */
1437 maxsock += 2 * global.nbthread; /* one wake-up pipe (2 fd) per thread */
1438
1439 /* compute fd used by async engines */
1440 if (global.ssl_used_async_engines) {
1441 int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
1442
1443 maxsock += maxconn * sides * global.ssl_used_async_engines;
1444 }
1445 return maxsock;
1446}
1447
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07001448/* Tests if it is possible to set the current process's RLIMIT_NOFILE to
Willy Tarreau304e17e2020-03-10 17:54:54 +01001449 * <maxsock>, then sets it back to the previous value. Returns non-zero if the
1450 * value is accepted, non-zero otherwise. This is used to determine if an
1451 * automatic limit may be applied or not. When it is not, the caller knows that
1452 * the highest we can do is the rlim_max at boot. In case of error, we return
1453 * that the setting is possible, so that we defer the error processing to the
1454 * final stage in charge of enforcing this.
1455 */
1456static int check_if_maxsock_permitted(int maxsock)
1457{
1458 struct rlimit orig_limit, test_limit;
1459 int ret;
1460
Willy Tarreau2df1fbf2022-04-25 18:02:03 +02001461 if (global.fd_hard_limit && maxsock > global.fd_hard_limit)
1462 return 0;
1463
Willy Tarreau304e17e2020-03-10 17:54:54 +01001464 if (getrlimit(RLIMIT_NOFILE, &orig_limit) != 0)
1465 return 1;
1466
1467 /* don't go further if we can't even set to what we have */
Willy Tarreauc06557c2022-09-22 16:12:08 +02001468 if (raise_rlim_nofile(NULL, &orig_limit) != 0)
Willy Tarreau304e17e2020-03-10 17:54:54 +01001469 return 1;
1470
1471 test_limit.rlim_max = MAX(maxsock, orig_limit.rlim_max);
1472 test_limit.rlim_cur = test_limit.rlim_max;
Willy Tarreauc06557c2022-09-22 16:12:08 +02001473 ret = raise_rlim_nofile(NULL, &test_limit);
Willy Tarreau304e17e2020-03-10 17:54:54 +01001474
Willy Tarreauc06557c2022-09-22 16:12:08 +02001475 if (raise_rlim_nofile(NULL, &orig_limit) != 0)
Willy Tarreau304e17e2020-03-10 17:54:54 +01001476 return 1;
1477
1478 return ret == 0;
1479}
1480
Willy Tarreau34527d52022-02-17 17:45:58 +01001481/* This performs th every basic early initialization at the end of the PREPARE
1482 * init stage. It may only assume that list heads are initialized, but not that
1483 * anything else is correct. It will initialize a number of variables that
1484 * depend on command line and will pre-parse the command line. If it fails, it
1485 * directly exits.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001486 */
Willy Tarreau34527d52022-02-17 17:45:58 +01001487static void init_early(int argc, char **argv)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001488{
Kevinm48936af2010-12-22 16:08:21 +00001489 char *progname;
Willy Tarreau34527d52022-02-17 17:45:58 +01001490 char *tmp;
1491 int len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001492
William Lallemandd4c0be62023-02-21 14:07:05 +01001493 setenv("HAPROXY_STARTUP_VERSION", HAPROXY_VERSION, 0);
1494
Willy Tarreau34527d52022-02-17 17:45:58 +01001495 /* First, let's initialize most global variables */
1496 totalconn = actconn = listeners = stopping = 0;
1497 killed = pid = 0;
1498
1499 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
1500 global.rlimit_memmax_all = HAPROXY_MEMMAX;
Christopher Faulete3a5e352017-10-24 13:53:54 +02001501 global.mode = MODE_STARTING;
William Lallemand73b85e72017-06-01 17:38:51 +02001502
Willy Tarreau34527d52022-02-17 17:45:58 +01001503 /* if we were in mworker mode, we should restart in mworker mode */
1504 if (getenv("HAPROXY_MWORKER_REEXEC") != NULL)
1505 global.mode |= MODE_MWORKER;
David du Colombier7af46052012-05-16 14:16:48 +02001506
Willy Tarreau34527d52022-02-17 17:45:58 +01001507 /* initialize date, time, and pid */
1508 tzset();
1509 clock_init_process_date();
Willy Tarreau6093ba42023-02-07 15:52:14 +01001510 start_date = date;
1511 start_time = now;
Willy Tarreau34527d52022-02-17 17:45:58 +01001512 pid = getpid();
1513
1514 /* Set local host name and adjust some environment variables.
1515 * NB: POSIX does not make it mandatory for gethostname() to
1516 * NULL-terminate the string in case of truncation, and at least
1517 * FreeBSD appears not to do it.
Emeric Brun2b920a12010-09-23 18:30:22 +02001518 */
1519 memset(hostname, 0, sizeof(hostname));
1520 gethostname(hostname, sizeof(hostname) - 1);
Dragan Dosen4f014152020-06-18 16:56:47 +02001521
Willy Tarreau34527d52022-02-17 17:45:58 +01001522 /* preset some environment variables */
1523 localpeer = strdup(hostname);
1524 if (!localpeer || setenv("HAPROXY_LOCALPEER", localpeer, 1) < 0) {
Dragan Dosen4f014152020-06-18 16:56:47 +02001525 ha_alert("Cannot allocate memory for local peer.\n");
1526 exit(EXIT_FAILURE);
1527 }
Emeric Brun2b920a12010-09-23 18:30:22 +02001528
Willy Tarreau34527d52022-02-17 17:45:58 +01001529 /* Some CPU affinity stuff may have to be initialized */
1530#ifdef USE_CPU_AFFINITY
1531 {
Willy Tarreau5b093412022-07-08 09:38:30 +02001532 int g, i;
1533
1534 for (g = 0; g < MAX_TGROUPS; g++) {
1535 ha_cpuset_zero(&cpu_map[g].proc);
1536 ha_cpuset_zero(&cpu_map[g].proc_t1);
1537 for (i = 0; i < MAX_THREADS_PER_GROUP; ++i) {
1538 ha_cpuset_zero(&cpu_map[g].thread[i]);
1539 }
Willy Tarreau34527d52022-02-17 17:45:58 +01001540 }
1541 }
1542#endif
Christopher Fauletcd7879a2017-10-27 13:53:47 +02001543
Willy Tarreau34527d52022-02-17 17:45:58 +01001544 /* extract the program name from argv[0], it will be used for the logs
1545 * and error messages.
1546 */
1547 progname = *argv;
1548 while ((tmp = strchr(progname, '/')) != NULL)
1549 progname = tmp + 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001550
Willy Tarreau34527d52022-02-17 17:45:58 +01001551 len = strlen(progname);
1552 progname = strdup(progname);
1553 if (!progname) {
1554 ha_alert("Cannot allocate memory for log_tag.\n");
1555 exit(EXIT_FAILURE);
1556 }
Willy Tarreau84310e22014-02-14 11:59:04 +01001557
Willy Tarreau34527d52022-02-17 17:45:58 +01001558 chunk_initlen(&global.log_tag, progname, len, len);
1559}
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001560
Willy Tarreau392524d2022-02-17 18:10:36 +01001561/* handles program arguments. Very minimal parsing is performed, variables are
1562 * fed with some values, and lists are completed with other ones. In case of
1563 * error, it will exit.
Willy Tarreau34527d52022-02-17 17:45:58 +01001564 */
Willy Tarreau392524d2022-02-17 18:10:36 +01001565static void init_args(int argc, char **argv)
Willy Tarreau34527d52022-02-17 17:45:58 +01001566{
Willy Tarreau34527d52022-02-17 17:45:58 +01001567 char *progname = global.log_tag.area;
Willy Tarreau392524d2022-02-17 18:10:36 +01001568 char *err_msg = NULL;
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +01001569
Willy Tarreau34527d52022-02-17 17:45:58 +01001570 /* pre-fill in the global tuning options before we let the cmdline
1571 * change them.
1572 */
Willy Tarreau43b78992009-01-25 15:42:27 +01001573 global.tune.options |= GTUNE_USE_SELECT; /* select() is always available */
Willy Tarreaue5733232019-05-22 19:24:06 +02001574#if defined(USE_POLL)
Willy Tarreau43b78992009-01-25 15:42:27 +01001575 global.tune.options |= GTUNE_USE_POLL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001576#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001577#if defined(USE_EPOLL)
Willy Tarreau43b78992009-01-25 15:42:27 +01001578 global.tune.options |= GTUNE_USE_EPOLL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001579#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001580#if defined(USE_KQUEUE)
Willy Tarreau43b78992009-01-25 15:42:27 +01001581 global.tune.options |= GTUNE_USE_KQUEUE;
Willy Tarreau1e63130a2007-04-09 12:03:06 +02001582#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001583#if defined(USE_EVPORTS)
Emmanuel Hocdet0ba4f482019-04-08 16:53:32 +00001584 global.tune.options |= GTUNE_USE_EVPORTS;
1585#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001586#if defined(USE_LINUX_SPLICE)
Willy Tarreau3ab68cf2009-01-25 16:03:28 +01001587 global.tune.options |= GTUNE_USE_SPLICE;
1588#endif
Nenad Merdanovic88afe032014-04-14 15:56:58 +02001589#if defined(USE_GETADDRINFO)
1590 global.tune.options |= GTUNE_USE_GAI;
1591#endif
Lukas Tribusa0bcbdc2016-09-12 21:42:20 +00001592#if defined(SO_REUSEPORT)
1593 global.tune.options |= GTUNE_USE_REUSEPORT;
1594#endif
Willy Tarreau76cc6992020-07-01 18:49:24 +02001595#ifdef USE_THREAD
1596 global.tune.options |= GTUNE_IDLE_POOL_SHARED;
1597#endif
Amaury Denoyellee30f3782022-11-21 11:54:13 +01001598#ifdef USE_QUIC
1599 global.tune.options |= GTUNE_QUIC_SOCK_PER_CONN;
1600#endif
William Dauchya5194602020-03-28 19:29:58 +01001601 global.tune.options |= GTUNE_STRICT_LIMITS;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001602
Christopher Faulet2f7c82b2023-02-20 14:06:52 +01001603 global.tune.options |= GTUNE_USE_FAST_FWD; /* Use fast-forward by default */
1604
Willy Tarreau392524d2022-02-17 18:10:36 +01001605 /* keep a copy of original arguments for the master process */
1606 old_argv = copy_argv(argc, argv);
1607 if (!old_argv) {
1608 ha_alert("failed to copy argv.\n");
1609 exit(EXIT_FAILURE);
1610 }
1611
1612 /* skip program name and start */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001613 argc--; argv++;
1614 while (argc > 0) {
1615 char *flag;
1616
1617 if (**argv == '-') {
1618 flag = *argv+1;
1619
1620 /* 1 arg */
1621 if (*flag == 'v') {
1622 display_version();
Willy Tarreau7b066db2007-12-02 11:28:59 +01001623 if (flag[1] == 'v') /* -vv */
1624 display_build_opts();
Tim Duesterhus77b3db02022-04-27 00:08:11 +02001625 deinit_and_exit(0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001626 }
Willy Tarreaue5733232019-05-22 19:24:06 +02001627#if defined(USE_EPOLL)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001628 else if (*flag == 'd' && flag[1] == 'e')
Willy Tarreau43b78992009-01-25 15:42:27 +01001629 global.tune.options &= ~GTUNE_USE_EPOLL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001630#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001631#if defined(USE_POLL)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001632 else if (*flag == 'd' && flag[1] == 'p')
Willy Tarreau43b78992009-01-25 15:42:27 +01001633 global.tune.options &= ~GTUNE_USE_POLL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001634#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001635#if defined(USE_KQUEUE)
Willy Tarreau1e63130a2007-04-09 12:03:06 +02001636 else if (*flag == 'd' && flag[1] == 'k')
Willy Tarreau43b78992009-01-25 15:42:27 +01001637 global.tune.options &= ~GTUNE_USE_KQUEUE;
Willy Tarreau1e63130a2007-04-09 12:03:06 +02001638#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001639#if defined(USE_EVPORTS)
Emmanuel Hocdet0ba4f482019-04-08 16:53:32 +00001640 else if (*flag == 'd' && flag[1] == 'v')
1641 global.tune.options &= ~GTUNE_USE_EVPORTS;
1642#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001643#if defined(USE_LINUX_SPLICE)
Willy Tarreau3ab68cf2009-01-25 16:03:28 +01001644 else if (*flag == 'd' && flag[1] == 'S')
1645 global.tune.options &= ~GTUNE_USE_SPLICE;
1646#endif
Nenad Merdanovic88afe032014-04-14 15:56:58 +02001647#if defined(USE_GETADDRINFO)
1648 else if (*flag == 'd' && flag[1] == 'G')
1649 global.tune.options &= ~GTUNE_USE_GAI;
1650#endif
Lukas Tribusa0bcbdc2016-09-12 21:42:20 +00001651#if defined(SO_REUSEPORT)
1652 else if (*flag == 'd' && flag[1] == 'R')
1653 global.tune.options &= ~GTUNE_USE_REUSEPORT;
1654#endif
Christopher Faulet678a4ce2023-02-14 16:12:54 +01001655 else if (*flag == 'd' && flag[1] == 'F')
Christopher Faulet2f7c82b2023-02-20 14:06:52 +01001656 global.tune.options &= ~GTUNE_USE_FAST_FWD;
Emeric Brun850efd52014-01-29 12:24:34 +01001657 else if (*flag == 'd' && flag[1] == 'V')
1658 global.ssl_server_verify = SSL_SERVER_VERIFY_NONE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001659 else if (*flag == 'V')
1660 arg_mode |= MODE_VERBOSE;
Erwan Le Goasb0c05012022-09-14 17:51:55 +02001661 else if (*flag == 'd' && flag[1] == 'C') {
Erwan Le Goasf30c5d72022-09-29 10:34:04 +02001662 char *end;
1663 char *key;
1664
1665 key = flag + 2;
1666 for (;key && *key; key = end) {
1667 end = strchr(key, ',');
1668 if (end)
1669 *(end++) = 0;
1670
1671 if (strcmp(key, "line") == 0)
1672 arg_mode |= MODE_DUMP_NB_L;
1673
1674 }
Erwan Le Goasb0c05012022-09-14 17:51:55 +02001675 arg_mode |= MODE_DUMP_CFG;
1676 HA_ATOMIC_STORE(&global.anon_key, atoll(flag + 2));
1677 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001678 else if (*flag == 'd' && flag[1] == 'b')
1679 arg_mode |= MODE_FOREGROUND;
Amaury Denoyelle7b01a8d2021-03-29 10:29:07 +02001680 else if (*flag == 'd' && flag[1] == 'D')
1681 arg_mode |= MODE_DIAG;
Willy Tarreau3eb10b82020-04-15 16:42:39 +02001682 else if (*flag == 'd' && flag[1] == 'W')
1683 arg_mode |= MODE_ZERO_WARNING;
Willy Tarreauef301b72022-02-23 14:15:18 +01001684 else if (*flag == 'd' && flag[1] == 'M') {
Willy Tarreau1408b1f2022-02-18 18:54:40 +01001685 int ret = pool_parse_debugging(flag + 2, &err_msg);
1686
1687 if (ret <= -1) {
1688 if (ret < -1)
1689 ha_alert("-dM: %s\n", err_msg);
1690 else
1691 printf("%s\n", err_msg);
1692 ha_free(&err_msg);
1693 exit(ret < -1 ? EXIT_FAILURE : 0);
1694 } else if (ret == 0) {
1695 ha_warning("-dM: %s\n", err_msg);
1696 ha_free(&err_msg);
1697 }
Willy Tarreauef301b72022-02-23 14:15:18 +01001698 }
Willy Tarreau3eed10e2016-11-07 21:03:16 +01001699 else if (*flag == 'd' && flag[1] == 'r')
1700 global.tune.options |= GTUNE_RESOLVE_DONTFAIL;
Willy Tarreau654726d2021-12-28 15:43:11 +01001701#if defined(HA_HAVE_DUMP_LIBS)
1702 else if (*flag == 'd' && flag[1] == 'L')
1703 arg_mode |= MODE_DUMP_LIBS;
1704#endif
Willy Tarreau76871a42022-03-08 16:01:40 +01001705 else if (*flag == 'd' && flag[1] == 'K') {
1706 arg_mode |= MODE_DUMP_KWD;
1707 kwd_dump = flag + 2;
1708 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001709 else if (*flag == 'd')
1710 arg_mode |= MODE_DEBUG;
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02001711 else if (*flag == 'c' && flag[1] == 'c') {
1712 arg_mode |= MODE_CHECK_CONDITION;
1713 argv++;
1714 argc--;
1715 check_condition = *argv;
1716 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001717 else if (*flag == 'c')
1718 arg_mode |= MODE_CHECK;
William Lallemand095ba4c2017-06-01 17:38:50 +02001719 else if (*flag == 'D')
Willy Tarreau6bde87b2009-05-18 16:29:51 +02001720 arg_mode |= MODE_DAEMON;
Tim Duesterhusd6942c82017-11-20 15:58:35 +01001721 else if (*flag == 'W' && flag[1] == 's') {
Lukas Tribusf46bf952017-11-21 12:39:34 +01001722 arg_mode |= MODE_MWORKER | MODE_FOREGROUND;
Tim Duesterhusd6942c82017-11-20 15:58:35 +01001723#if defined(USE_SYSTEMD)
1724 global.tune.options |= GTUNE_USE_SYSTEMD;
1725#else
Christopher Faulet767a84b2017-11-24 16:50:31 +01001726 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 +01001727 usage(progname);
1728#endif
1729 }
William Lallemand095ba4c2017-06-01 17:38:50 +02001730 else if (*flag == 'W')
1731 arg_mode |= MODE_MWORKER;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001732 else if (*flag == 'q')
1733 arg_mode |= MODE_QUIET;
Olivier Houchardf73629d2017-04-05 22:33:04 +02001734 else if (*flag == 'x') {
William Lallemand4f71d302020-06-04 23:41:29 +02001735 if (argc <= 1) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001736 ha_alert("Unix socket path expected with the -x flag\n\n");
William Lallemand45eff442017-06-19 15:57:55 +02001737 usage(progname);
Olivier Houchardf73629d2017-04-05 22:33:04 +02001738 }
William Lallemand4fc09692017-06-19 16:37:19 +02001739 if (old_unixsocket)
Christopher Faulet767a84b2017-11-24 16:50:31 +01001740 ha_warning("-x option already set, overwriting the value\n");
Olivier Houchardf73629d2017-04-05 22:33:04 +02001741 old_unixsocket = argv[1];
William Lallemand4fc09692017-06-19 16:37:19 +02001742
Olivier Houchardf73629d2017-04-05 22:33:04 +02001743 argv++;
1744 argc--;
1745 }
William Lallemande7361152018-10-26 14:47:36 +02001746 else if (*flag == 'S') {
1747 struct wordlist *c;
1748
William Lallemanda6b32492020-06-04 23:49:20 +02001749 if (argc <= 1) {
William Lallemande7361152018-10-26 14:47:36 +02001750 ha_alert("Socket and optional bind parameters expected with the -S flag\n");
1751 usage(progname);
1752 }
1753 if ((c = malloc(sizeof(*c))) == NULL || (c->s = strdup(argv[1])) == NULL) {
1754 ha_alert("Cannot allocate memory\n");
1755 exit(EXIT_FAILURE);
1756 }
Willy Tarreau2b718102021-04-21 07:32:39 +02001757 LIST_INSERT(&mworker_cli_conf, &c->list);
William Lallemande7361152018-10-26 14:47:36 +02001758
1759 argv++;
1760 argc--;
1761 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001762 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
1763 /* list of pids to finish ('f') or terminate ('t') */
1764
1765 if (flag[1] == 'f')
1766 oldpids_sig = SIGUSR1; /* finish then exit */
1767 else
1768 oldpids_sig = SIGTERM; /* terminate immediately */
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001769 while (argc > 1 && argv[1][0] != '-') {
Chris Lane236062f2018-02-05 23:15:44 +00001770 char * endptr = NULL;
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001771 oldpids = realloc(oldpids, (nb_oldpids + 1) * sizeof(int));
1772 if (!oldpids) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001773 ha_alert("Cannot allocate old pid : out of memory.\n");
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001774 exit(1);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001775 }
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001776 argc--; argv++;
Chris Lane236062f2018-02-05 23:15:44 +00001777 errno = 0;
1778 oldpids[nb_oldpids] = strtol(*argv, &endptr, 10);
1779 if (errno) {
1780 ha_alert("-%2s option: failed to parse {%s}: %s\n",
1781 flag,
1782 *argv, strerror(errno));
1783 exit(1);
1784 } else if (endptr && strlen(endptr)) {
Willy Tarreau90807112020-02-25 08:16:33 +01001785 while (isspace((unsigned char)*endptr)) endptr++;
Aurélien Nephtali39b89882018-02-17 20:53:11 +01001786 if (*endptr != 0) {
Chris Lane236062f2018-02-05 23:15:44 +00001787 ha_alert("-%2s option: some bytes unconsumed in PID list {%s}\n",
1788 flag, endptr);
1789 exit(1);
Aurélien Nephtali39b89882018-02-17 20:53:11 +01001790 }
Chris Lane236062f2018-02-05 23:15:44 +00001791 }
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001792 if (oldpids[nb_oldpids] <= 0)
1793 usage(progname);
1794 nb_oldpids++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001795 }
1796 }
Willy Tarreaua088d312015-10-08 11:58:48 +02001797 else if (flag[0] == '-' && flag[1] == 0) { /* "--" */
1798 /* now that's a cfgfile list */
1799 argv++; argc--;
1800 while (argc > 0) {
Maxime de Roucy0f503922016-05-13 23:52:55 +02001801 if (!list_append_word(&cfg_cfgfiles, *argv, &err_msg)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001802 ha_alert("Cannot load configuration file/directory %s : %s\n",
1803 *argv,
1804 err_msg);
Willy Tarreaua088d312015-10-08 11:58:48 +02001805 exit(1);
1806 }
Willy Tarreaua088d312015-10-08 11:58:48 +02001807 argv++; argc--;
1808 }
1809 break;
1810 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001811 else { /* >=2 args */
1812 argv++; argc--;
1813 if (argc == 0)
Willy Tarreau3bafcdc2011-09-10 19:20:23 +02001814 usage(progname);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001815
1816 switch (*flag) {
Willy Tarreau576132e2011-09-10 19:26:56 +02001817 case 'C' : change_dir = *argv; break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001818 case 'n' : cfg_maxconn = atol(*argv); break;
Willy Tarreau70060452015-12-14 12:46:07 +01001819 case 'm' : global.rlimit_memmax_all = atol(*argv); break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001820 case 'N' : cfg_maxpconn = atol(*argv); break;
William Lallemanddaf4cd22018-04-17 16:46:13 +02001821 case 'L' :
Dragan Dosen4f014152020-06-18 16:56:47 +02001822 free(localpeer);
1823 if ((localpeer = strdup(*argv)) == NULL) {
1824 ha_alert("Cannot allocate memory for local peer.\n");
1825 exit(EXIT_FAILURE);
1826 }
William Lallemanddaf4cd22018-04-17 16:46:13 +02001827 setenv("HAPROXY_LOCALPEER", localpeer, 1);
Dragan Dosen13cd54c2020-06-18 18:24:05 +02001828 global.localpeer_cmdline = 1;
William Lallemanddaf4cd22018-04-17 16:46:13 +02001829 break;
Willy Tarreau5d01a632009-06-22 16:02:30 +02001830 case 'f' :
Maxime de Roucy0f503922016-05-13 23:52:55 +02001831 if (!list_append_word(&cfg_cfgfiles, *argv, &err_msg)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001832 ha_alert("Cannot load configuration file/directory %s : %s\n",
1833 *argv,
1834 err_msg);
Willy Tarreau5d01a632009-06-22 16:02:30 +02001835 exit(1);
1836 }
Willy Tarreau5d01a632009-06-22 16:02:30 +02001837 break;
Willy Tarreau392524d2022-02-17 18:10:36 +01001838 case 'p' :
1839 free(global.pidfile);
1840 if ((global.pidfile = strdup(*argv)) == NULL) {
1841 ha_alert("Cannot allocate memory for pidfile.\n");
1842 exit(EXIT_FAILURE);
1843 }
1844 break;
Willy Tarreau3bafcdc2011-09-10 19:20:23 +02001845 default: usage(progname);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001846 }
1847 }
1848 }
1849 else
Willy Tarreau3bafcdc2011-09-10 19:20:23 +02001850 usage(progname);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001851 argv++; argc--;
1852 }
Willy Tarreau392524d2022-02-17 18:10:36 +01001853 free(err_msg);
1854}
1855
Willy Tarreau76871a42022-03-08 16:01:40 +01001856/* call the various keyword dump functions based on the comma-delimited list of
1857 * classes in kwd_dump.
1858 */
1859static void dump_registered_keywords(void)
1860{
1861 char *end;
1862 int all __maybe_unused = 0;
1863
1864 for (; kwd_dump && *kwd_dump; kwd_dump = end) {
1865 end = strchr(kwd_dump, ',');
1866 if (end)
1867 *(end++) = 0;
1868
1869 if (strcmp(kwd_dump, "help") == 0) {
1870 printf("# List of supported keyword classes:\n");
1871 printf("all: list all keywords\n");
Willy Tarreau6ff7d1b2022-03-29 15:36:56 +02001872 printf("acl: ACL keywords\n");
Willy Tarreauca1acd62022-03-29 15:02:44 +02001873 printf("cfg: configuration keywords\n");
Willy Tarreau06d0e2e2022-03-29 15:25:30 +02001874 printf("cli: CLI keywords\n");
Willy Tarreau29d799d2022-03-29 16:59:49 +02001875 printf("cnv: sample converter keywords\n");
Willy Tarreau3b65e142022-03-29 15:03:09 +02001876 printf("flt: filter names\n");
Willy Tarreauf78813f2022-03-29 16:51:29 +02001877 printf("smp: sample fetch functions\n");
Willy Tarreau5fcc1002022-03-29 15:10:44 +02001878 printf("svc: service names\n");
Willy Tarreau76871a42022-03-08 16:01:40 +01001879 continue;
1880 }
1881 else if (strcmp(kwd_dump, "all") == 0) {
1882 all = 1;
1883 }
Willy Tarreauca1acd62022-03-29 15:02:44 +02001884
Willy Tarreau6ff7d1b2022-03-29 15:36:56 +02001885 if (all || strcmp(kwd_dump, "acl") == 0) {
1886 printf("# List of registered ACL keywords:\n");
1887 acl_dump_kwd();
1888 }
1889
Willy Tarreauca1acd62022-03-29 15:02:44 +02001890 if (all || strcmp(kwd_dump, "cfg") == 0) {
1891 printf("# List of registered configuration keywords:\n");
1892 cfg_dump_registered_keywords();
1893 }
Willy Tarreau3b65e142022-03-29 15:03:09 +02001894
Willy Tarreau06d0e2e2022-03-29 15:25:30 +02001895 if (all || strcmp(kwd_dump, "cli") == 0) {
1896 printf("# List of registered CLI keywords:\n");
1897 cli_list_keywords();
1898 }
1899
Willy Tarreau29d799d2022-03-29 16:59:49 +02001900 if (all || strcmp(kwd_dump, "cnv") == 0) {
1901 printf("# List of registered sample converter functions:\n");
1902 smp_dump_conv_kw();
1903 }
1904
Willy Tarreau3b65e142022-03-29 15:03:09 +02001905 if (all || strcmp(kwd_dump, "flt") == 0) {
1906 printf("# List of registered filter names:\n");
1907 flt_dump_kws(NULL);
1908 }
Willy Tarreau5fcc1002022-03-29 15:10:44 +02001909
Willy Tarreauf78813f2022-03-29 16:51:29 +02001910 if (all || strcmp(kwd_dump, "smp") == 0) {
1911 printf("# List of registered sample fetch functions:\n");
1912 smp_dump_fetch_kw();
1913 }
1914
Willy Tarreau5fcc1002022-03-29 15:10:44 +02001915 if (all || strcmp(kwd_dump, "svc") == 0) {
1916 printf("# List of registered service names:\n");
1917 list_services(NULL);
1918 }
Willy Tarreau76871a42022-03-08 16:01:40 +01001919 }
1920}
1921
Amaury Denoyelle28ea31c2022-11-14 16:18:46 +01001922/* Generate a random cluster-secret in case the setting is not provided in the
1923 * configuration. This allows to use features which rely on it albeit with some
1924 * limitations.
1925 */
1926static void generate_random_cluster_secret()
1927{
1928 /* used as a default random cluster-secret if none defined. */
1929 uint64_t rand = ha_random64();
1930
1931 /* The caller must not overwrite an already defined secret. */
1932 BUG_ON(global.cluster_secret);
1933
1934 global.cluster_secret = malloc(8);
1935 if (!global.cluster_secret)
1936 return;
1937
1938 memcpy(global.cluster_secret, &rand, sizeof(rand));
1939 global.cluster_secret[7] = '\0';
1940}
1941
Willy Tarreau392524d2022-02-17 18:10:36 +01001942/*
1943 * This function initializes all the necessary variables. It only returns
1944 * if everything is OK. If something fails, it exits.
1945 */
1946static void init(int argc, char **argv)
1947{
1948 char *progname = global.log_tag.area;
1949 int err_code = 0;
1950 struct wordlist *wl;
1951 struct proxy *px;
1952 struct post_check_fct *pcf;
William Lallemandb53eb872022-04-21 18:02:53 +02001953 struct pre_check_fct *prcf;
Willy Tarreau392524d2022-02-17 18:10:36 +01001954 int ideal_maxconn;
1955
William Lallemand151dbbe2022-12-02 17:17:43 +01001956#ifdef USE_OPENSSL
1957#ifdef USE_OPENSSL_WOLFSSL
1958 wolfSSL_Init();
1959 wolfSSL_Debugging_ON();
1960#endif
1961#if (HA_OPENSSL_VERSION_NUMBER < 0x1010000fL)
William Lallemand44c80ce2022-12-02 17:06:59 +01001962 /* Initialize the error strings of OpenSSL
1963 * It only needs to be done explicitly with older versions of the SSL
1964 * library. On newer versions, errors strings are loaded during start
1965 * up. */
1966 SSL_load_error_strings();
1967#endif
William Lallemand151dbbe2022-12-02 17:17:43 +01001968#endif
William Lallemand44c80ce2022-12-02 17:06:59 +01001969
William Lallemandeba6a542022-09-26 12:54:39 +02001970 startup_logs_init();
1971
Willy Tarreau392524d2022-02-17 18:10:36 +01001972 if (!init_trash_buffers(1)) {
1973 ha_alert("failed to initialize trash buffers.\n");
1974 exit(1);
1975 }
1976
1977 if (init_acl() != 0)
1978 exit(1);
1979
1980 /* Initialise lua. */
1981 hlua_init();
Willy Tarreaubaaee002006-06-26 02:48:02 +02001982
Christopher Faulete3a5e352017-10-24 13:53:54 +02001983 global.mode |= (arg_mode & (MODE_DAEMON | MODE_MWORKER | MODE_FOREGROUND | MODE_VERBOSE
Amaury Denoyelle7b01a8d2021-03-29 10:29:07 +02001984 | MODE_QUIET | MODE_CHECK | MODE_DEBUG | MODE_ZERO_WARNING
Erwan Le Goasf30c5d72022-09-29 10:34:04 +02001985 | MODE_DIAG | MODE_CHECK_CONDITION | MODE_DUMP_LIBS | MODE_DUMP_KWD
1986 | MODE_DUMP_CFG | MODE_DUMP_NB_L));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001987
William Lallemand944e6192018-11-21 15:48:31 +01001988 if (getenv("HAPROXY_MWORKER_WAIT_ONLY")) {
William Lallemandcb11fd22017-06-01 17:38:52 +02001989 unsetenv("HAPROXY_MWORKER_WAIT_ONLY");
William Lallemand944e6192018-11-21 15:48:31 +01001990 global.mode |= MODE_MWORKER_WAIT;
1991 global.mode &= ~MODE_MWORKER;
William Lallemandcb11fd22017-06-01 17:38:52 +02001992 }
1993
William Lallemand40db4ae2022-12-07 15:03:55 +01001994 /* set the atexit functions when not doing configuration check */
1995 if (!(global.mode & (MODE_CHECK | MODE_CHECK_CONDITION))
1996 && (getenv("HAPROXY_MWORKER_REEXEC") != NULL)) {
1997
1998 if (global.mode & MODE_MWORKER) {
1999 atexit_flag = 1;
2000 atexit(reexec_on_failure);
2001 } else if (global.mode & MODE_MWORKER_WAIT) {
2002 atexit_flag = 1;
2003 atexit(exit_on_waitmode_failure);
2004 }
William Lallemandcb11fd22017-06-01 17:38:52 +02002005 }
2006
Willy Tarreau576132e2011-09-10 19:26:56 +02002007 if (change_dir && chdir(change_dir) < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002008 ha_alert("Could not change to directory %s : %s\n", change_dir, strerror(errno));
Willy Tarreau576132e2011-09-10 19:26:56 +02002009 exit(1);
2010 }
2011
Amaury Denoyelle11124302021-06-04 18:22:08 +02002012 usermsgs_clr("config");
2013
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02002014 if (global.mode & MODE_CHECK_CONDITION) {
2015 int result;
2016
2017 uint32_t err;
2018 const char *errptr;
2019 char *errmsg = NULL;
2020
2021 char *args[MAX_LINE_ARGS+1];
2022 int arg = sizeof(args) / sizeof(*args);
William Lallemand89e236f2022-05-06 17:22:36 +02002023 size_t outlen;
Willy Tarreauc8194c32021-07-16 16:38:58 +02002024 char *w;
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02002025
William Lallemand89e236f2022-05-06 17:22:36 +02002026 if (!check_condition)
2027 usage(progname);
2028
2029 outlen = strlen(check_condition) + 1;
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02002030 err = parse_line(check_condition, check_condition, &outlen, args, &arg,
Willy Tarreaua87e7822021-07-16 19:14:54 +02002031 PARSE_OPT_ENV | PARSE_OPT_WORD_EXPAND | PARSE_OPT_DQUOTE | PARSE_OPT_SQUOTE | PARSE_OPT_BKSLASH,
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02002032 &errptr);
2033
2034 if (err & PARSE_ERR_QUOTE) {
2035 ha_alert("Syntax Error in condition: Unmatched quote.\n");
2036 exit(2);
2037 }
2038
2039 if (err & PARSE_ERR_HEX) {
2040 ha_alert("Syntax Error in condition: Truncated or invalid hexadecimal sequence.\n");
2041 exit(2);
2042 }
2043
2044 if (err & (PARSE_ERR_TOOLARGE|PARSE_ERR_OVERLAP)) {
2045 ha_alert("Error in condition: Line too long.\n");
2046 exit(2);
2047 }
2048
Willy Tarreauc8194c32021-07-16 16:38:58 +02002049 if (err & PARSE_ERR_TOOMANY) {
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02002050 ha_alert("Error in condition: Too many words.\n");
2051 exit(2);
2052 }
2053
2054 if (err) {
2055 ha_alert("Unhandled error in condition, please report this to the developers.\n");
2056 exit(2);
2057 }
2058
Willy Tarreauc8194c32021-07-16 16:38:58 +02002059 /* remerge all words into a single expression */
2060 for (w = *args; (w += strlen(w)) < check_condition + outlen - 1; *w = ' ')
2061 ;
2062
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02002063 result = cfg_eval_condition(args, &errmsg, &errptr);
2064
2065 if (result < 0) {
2066 if (errmsg)
2067 ha_alert("Failed to evaluate condition: %s\n", errmsg);
2068
2069 exit(2);
2070 }
2071
2072 exit(result ? 0 : 1);
2073 }
2074
William Lallemand944e6192018-11-21 15:48:31 +01002075 /* in wait mode, we don't try to read the configuration files */
2076 if (!(global.mode & MODE_MWORKER_WAIT)) {
Christopher Faulet4e366822021-01-12 18:57:38 +01002077 char *env_cfgfiles = NULL;
2078 int env_err = 0;
Willy Tarreauc4382422009-12-06 13:10:44 +01002079
William Lallemand944e6192018-11-21 15:48:31 +01002080 /* handle cfgfiles that are actually directories */
2081 cfgfiles_expand_directories();
2082
2083 if (LIST_ISEMPTY(&cfg_cfgfiles))
2084 usage(progname);
2085
Sébastien Gross537b9e72022-11-30 22:36:50 +01002086 /* temporary create environment variables with default
2087 * values to ease user configuration. Do not forget to
2088 * unset them after the list_for_each_entry loop.
2089 */
2090 setenv("HAPROXY_HTTP_LOG_FMT", default_http_log_format, 1);
2091 setenv("HAPROXY_HTTPS_LOG_FMT", default_https_log_format, 1);
2092 setenv("HAPROXY_TCP_LOG_FMT", default_tcp_log_format, 1);
Sébaastien Gross2a1bcf12023-02-23 12:54:25 -05002093 setenv("HAPROXY_BRANCH", PRODUCT_BRANCH, 1);
William Lallemand944e6192018-11-21 15:48:31 +01002094 list_for_each_entry(wl, &cfg_cfgfiles, list) {
2095 int ret;
2096
Christopher Faulet4e366822021-01-12 18:57:38 +01002097 if (env_err == 0) {
2098 if (!memprintf(&env_cfgfiles, "%s%s%s",
2099 (env_cfgfiles ? env_cfgfiles : ""),
2100 (env_cfgfiles ? ";" : ""), wl->s))
2101 env_err = 1;
2102 }
William Lallemand7b302d82019-05-20 11:15:37 +02002103
William Lallemand944e6192018-11-21 15:48:31 +01002104 ret = readcfgfile(wl->s);
2105 if (ret == -1) {
2106 ha_alert("Could not open configuration file %s : %s\n",
2107 wl->s, strerror(errno));
Christopher Faulet4e366822021-01-12 18:57:38 +01002108 free(env_cfgfiles);
William Lallemand944e6192018-11-21 15:48:31 +01002109 exit(1);
2110 }
2111 if (ret & (ERR_ABORT|ERR_FATAL))
2112 ha_alert("Error(s) found in configuration file : %s\n", wl->s);
2113 err_code |= ret;
Christopher Faulet4e366822021-01-12 18:57:38 +01002114 if (err_code & ERR_ABORT) {
2115 free(env_cfgfiles);
William Lallemand944e6192018-11-21 15:48:31 +01002116 exit(1);
Christopher Faulet4e366822021-01-12 18:57:38 +01002117 }
Willy Tarreauc4382422009-12-06 13:10:44 +01002118 }
Sébastien Gross537b9e72022-11-30 22:36:50 +01002119 /* remove temporary environment variables. */
Sébaastien Gross2a1bcf12023-02-23 12:54:25 -05002120 unsetenv("HAPROXY_BRANCH");
Sébastien Gross537b9e72022-11-30 22:36:50 +01002121 unsetenv("HAPROXY_HTTP_LOG_FMT");
2122 unsetenv("HAPROXY_HTTPS_LOG_FMT");
2123 unsetenv("HAPROXY_TCP_LOG_FMT");
Krzysztof Oledzkib304dc72007-10-14 23:40:01 +02002124
William Lallemand944e6192018-11-21 15:48:31 +01002125 /* do not try to resolve arguments nor to spot inconsistencies when
2126 * the configuration contains fatal errors caused by files not found
2127 * or failed memory allocations.
2128 */
2129 if (err_code & (ERR_ABORT|ERR_FATAL)) {
2130 ha_alert("Fatal errors found in configuration.\n");
Christopher Faulet4e366822021-01-12 18:57:38 +01002131 free(env_cfgfiles);
William Lallemand944e6192018-11-21 15:48:31 +01002132 exit(1);
2133 }
Christopher Faulet4e366822021-01-12 18:57:38 +01002134 if (env_err) {
2135 ha_alert("Could not allocate memory for HAPROXY_CFGFILES env variable\n");
2136 exit(1);
2137 }
2138 setenv("HAPROXY_CFGFILES", env_cfgfiles, 1);
2139 free(env_cfgfiles);
William Lallemand7b302d82019-05-20 11:15:37 +02002140
Willy Tarreaub83dc3d2017-04-19 11:24:07 +02002141 }
William Lallemandce83b4a2018-10-26 14:47:30 +02002142 if (global.mode & MODE_MWORKER) {
William Lallemand16dd1b32018-11-19 18:46:18 +01002143 struct mworker_proc *tmproc;
2144
William Lallemand482f9a92019-04-12 16:15:00 +02002145 setenv("HAPROXY_MWORKER", "1", 1);
2146
William Lallemand16dd1b32018-11-19 18:46:18 +01002147 if (getenv("HAPROXY_MWORKER_REEXEC") == NULL) {
2148
William Lallemand56be0e02022-01-28 21:11:41 +01002149 tmproc = mworker_proc_new();
William Lallemand16dd1b32018-11-19 18:46:18 +01002150 if (!tmproc) {
2151 ha_alert("Cannot allocate process structures.\n");
2152 exit(EXIT_FAILURE);
2153 }
William Lallemand8f7069a2019-04-12 16:09:23 +02002154 tmproc->options |= PROC_O_TYPE_MASTER; /* master */
William Lallemand16dd1b32018-11-19 18:46:18 +01002155 tmproc->pid = pid;
William Lallemand5a7f83a2023-02-17 16:23:52 +01002156 tmproc->timestamp = start_date.tv_sec;
William Lallemand16dd1b32018-11-19 18:46:18 +01002157 proc_self = tmproc;
2158
Willy Tarreau2b718102021-04-21 07:32:39 +02002159 LIST_APPEND(&proc_list, &tmproc->list);
William Lallemand16dd1b32018-11-19 18:46:18 +01002160 }
William Lallemandce83b4a2018-10-26 14:47:30 +02002161
William Lallemand56be0e02022-01-28 21:11:41 +01002162 tmproc = mworker_proc_new();
Willy Tarreau6185a032021-06-15 08:02:06 +02002163 if (!tmproc) {
2164 ha_alert("Cannot allocate process structures.\n");
2165 exit(EXIT_FAILURE);
2166 }
Willy Tarreau6185a032021-06-15 08:02:06 +02002167 tmproc->options |= PROC_O_TYPE_WORKER; /* worker */
William Lallemandce83b4a2018-10-26 14:47:30 +02002168
Willy Tarreau6185a032021-06-15 08:02:06 +02002169 if (mworker_cli_sockpair_new(tmproc, 0) < 0) {
2170 exit(EXIT_FAILURE);
William Lallemandce83b4a2018-10-26 14:47:30 +02002171 }
Willy Tarreau6185a032021-06-15 08:02:06 +02002172
2173 LIST_APPEND(&proc_list, &tmproc->list);
William Lallemand944e6192018-11-21 15:48:31 +01002174 }
Willy Tarreau53bfac82022-07-22 17:35:49 +02002175
2176 if (global.mode & MODE_MWORKER_WAIT) {
2177 /* in exec mode, there's always exactly one thread. Failure to
2178 * set these ones now will result in nbthread being detected
2179 * automatically.
2180 */
2181 global.nbtgroups = 1;
2182 global.nbthread = 1;
2183 }
2184
William Lallemand944e6192018-11-21 15:48:31 +01002185 if (global.mode & (MODE_MWORKER|MODE_MWORKER_WAIT)) {
2186 struct wordlist *it, *c;
2187
Remi Tricot-Le Breton1f4fa902021-05-19 10:45:12 +02002188 /* get the info of the children in the env */
2189 if (mworker_env_to_proc_list() < 0) {
2190 exit(EXIT_FAILURE);
2191 }
William Lallemande7361152018-10-26 14:47:36 +02002192
William Lallemand550db6d2018-11-06 17:37:12 +01002193 if (!LIST_ISEMPTY(&mworker_cli_conf)) {
William Lallemandec059c22022-09-22 17:26:23 +02002194 char *path = NULL;
William Lallemande7361152018-10-26 14:47:36 +02002195
William Lallemand550db6d2018-11-06 17:37:12 +01002196 if (mworker_cli_proxy_create() < 0) {
William Lallemande7361152018-10-26 14:47:36 +02002197 ha_alert("Can't create the master's CLI.\n");
2198 exit(EXIT_FAILURE);
2199 }
William Lallemande7361152018-10-26 14:47:36 +02002200
William Lallemand550db6d2018-11-06 17:37:12 +01002201 list_for_each_entry_safe(c, it, &mworker_cli_conf, list) {
2202
William Lallemand21623b52022-09-24 15:51:27 +02002203 if (mworker_cli_proxy_new_listener(c->s) == NULL) {
William Lallemand550db6d2018-11-06 17:37:12 +01002204 ha_alert("Can't create the master's CLI.\n");
2205 exit(EXIT_FAILURE);
2206 }
Willy Tarreau2b718102021-04-21 07:32:39 +02002207 LIST_DELETE(&c->list);
William Lallemand550db6d2018-11-06 17:37:12 +01002208 free(c->s);
2209 free(c);
2210 }
William Lallemande57b7022022-12-07 14:25:41 +01002211 /* Creates the mcli_reload listener, which is the listener used
2212 * to retrieve the master CLI session which asked for the reload.
2213 *
2214 * ipc_fd[1] will be used as a listener, and ipc_fd[0]
2215 * will be used to send the FD of the session.
2216 *
2217 * Both FDs will be kept in the master. The sockets are
2218 * created only if they weren't inherited.
2219 */
2220 if ((proc_self->ipc_fd[1] == -1) &&
2221 socketpair(AF_UNIX, SOCK_STREAM, 0, proc_self->ipc_fd) < 0) {
2222 ha_alert("cannot create the mcli_reload socketpair.\n");
2223 exit(EXIT_FAILURE);
2224 }
2225
William Lallemandec059c22022-09-22 17:26:23 +02002226 /* Create the mcli_reload listener from the proc_self struct */
2227 memprintf(&path, "sockpair@%d", proc_self->ipc_fd[1]);
William Lallemand56f73b22022-09-24 15:56:25 +02002228 mcli_reload_bind_conf = mworker_cli_proxy_new_listener(path);
2229 if (mcli_reload_bind_conf == NULL) {
William Lallemandec059c22022-09-22 17:26:23 +02002230 ha_alert("Cannot create the mcli_reload listener.\n");
2231 exit(EXIT_FAILURE);
2232 }
2233 ha_free(&path);
William Lallemand550db6d2018-11-06 17:37:12 +01002234 }
William Lallemandce83b4a2018-10-26 14:47:30 +02002235 }
2236
Eric Salama5ba83352021-03-16 15:11:17 +01002237 if (!LIST_ISEMPTY(&mworker_cli_conf) && !(arg_mode & MODE_MWORKER)) {
2238 ha_warning("a master CLI socket was defined, but master-worker mode (-W) is not enabled.\n");
2239 }
2240
Christopher Faulet27c8d202021-10-13 09:50:53 +02002241 /* destroy unreferenced defaults proxies */
2242 proxy_destroy_all_unref_defaults();
2243
William Lallemandb53eb872022-04-21 18:02:53 +02002244 list_for_each_entry(prcf, &pre_check_list, list)
2245 err_code |= prcf->fct();
Willy Tarreaue90904d2021-02-12 14:08:31 +01002246
William Lallemand8b9a2df2022-05-04 14:29:46 +02002247 if (err_code & (ERR_ABORT|ERR_FATAL)) {
2248 ha_alert("Fatal errors found in configuration.\n");
2249 exit(1);
2250 }
2251
Willy Tarreau57c3e752022-12-08 08:13:20 +01002252 /* Note: global.nbthread will be initialized as part of this call */
Willy Tarreaubb925012009-07-23 13:36:36 +02002253 err_code |= check_config_validity();
Christopher Fauletc1692962019-08-12 09:51:07 +02002254 for (px = proxies_list; px; px = px->next) {
2255 struct server *srv;
2256 struct post_proxy_check_fct *ppcf;
2257 struct post_server_check_fct *pscf;
2258
Christopher Fauletdfd10ab2021-10-06 14:24:19 +02002259 if (px->flags & (PR_FL_DISABLED|PR_FL_STOPPED))
Christopher Fauletd5bd8242020-11-02 16:20:13 +01002260 continue;
2261
Christopher Fauletc1692962019-08-12 09:51:07 +02002262 list_for_each_entry(pscf, &post_server_check_list, list) {
2263 for (srv = px->srv; srv; srv = srv->next)
2264 err_code |= pscf->fct(srv);
2265 }
2266 list_for_each_entry(ppcf, &post_proxy_check_list, list)
2267 err_code |= ppcf->fct(px);
2268 }
Willy Tarreaubb925012009-07-23 13:36:36 +02002269 if (err_code & (ERR_ABORT|ERR_FATAL)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002270 ha_alert("Fatal errors found in configuration.\n");
Willy Tarreau915e1eb2009-06-22 15:48:36 +02002271 exit(1);
2272 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002273
Carl Henrik Lundef91ac192020-02-27 16:45:50 +01002274 err_code |= pattern_finalize_config();
2275 if (err_code & (ERR_ABORT|ERR_FATAL)) {
2276 ha_alert("Failed to finalize pattern config.\n");
2277 exit(1);
2278 }
Willy Tarreau0f936722019-04-11 14:47:08 +02002279
Willy Tarreau79c9bdf2021-07-17 12:31:08 +02002280 if (global.rlimit_memmax_all)
2281 global.rlimit_memmax = global.rlimit_memmax_all;
2282
Willy Tarreaue5733232019-05-22 19:24:06 +02002283#ifdef USE_NS
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01002284 err_code |= netns_init();
2285 if (err_code & (ERR_ABORT|ERR_FATAL)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002286 ha_alert("Failed to initialize namespace support.\n");
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01002287 exit(1);
2288 }
2289#endif
2290
Baptiste Assmann4215d7d2016-11-02 15:33:15 +01002291 /* Apply server states */
2292 apply_server_state();
2293
Olivier Houchardfbc74e82017-11-24 16:54:05 +01002294 for (px = proxies_list; px; px = px->next)
Baptiste Assmann4215d7d2016-11-02 15:33:15 +01002295 srv_compute_all_admin_states(px);
2296
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01002297 /* Apply servers' configured address */
2298 err_code |= srv_init_addr();
2299 if (err_code & (ERR_ABORT|ERR_FATAL)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002300 ha_alert("Failed to initialize server(s) addr.\n");
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01002301 exit(1);
2302 }
2303
Willy Tarreau3eb10b82020-04-15 16:42:39 +02002304 if (warned & WARN_ANY && global.mode & MODE_ZERO_WARNING) {
2305 ha_alert("Some warnings were found and 'zero-warning' is set. Aborting.\n");
2306 exit(1);
2307 }
2308
Willy Tarreau654726d2021-12-28 15:43:11 +01002309#if defined(HA_HAVE_DUMP_LIBS)
2310 if (global.mode & MODE_DUMP_LIBS) {
2311 qfprintf(stdout, "List of loaded object files:\n");
2312 chunk_reset(&trash);
2313 if (dump_libs(&trash, 0))
2314 printf("%s", trash.area);
2315 }
2316#endif
2317
Willy Tarreau76871a42022-03-08 16:01:40 +01002318 if (global.mode & MODE_DUMP_KWD)
2319 dump_registered_keywords();
2320
Willy Tarreaubaaee002006-06-26 02:48:02 +02002321 if (global.mode & MODE_CHECK) {
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002322 struct peers *pr;
2323 struct proxy *px;
2324
Willy Tarreaubebd2122020-04-15 16:06:11 +02002325 if (warned & WARN_ANY)
2326 qfprintf(stdout, "Warnings were found.\n");
2327
Frédéric Lécailleed2b4a62017-07-13 09:07:09 +02002328 for (pr = cfg_peers; pr; pr = pr->next)
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002329 if (pr->peers_fe)
2330 break;
2331
Olivier Houchardfbc74e82017-11-24 16:54:05 +01002332 for (px = proxies_list; px; px = px->next)
Christopher Fauletdfd10ab2021-10-06 14:24:19 +02002333 if (!(px->flags & (PR_FL_DISABLED|PR_FL_STOPPED)) && px->li_all)
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002334 break;
2335
Emeric Brunbc5c8212021-08-13 09:32:50 +02002336 if (!px) {
2337 /* We may only have log-forward section */
2338 for (px = cfg_log_forward; px; px = px->next)
Christopher Fauletdfd10ab2021-10-06 14:24:19 +02002339 if (!(px->flags & (PR_FL_DISABLED|PR_FL_STOPPED)) && px->li_all)
Emeric Brunbc5c8212021-08-13 09:32:50 +02002340 break;
2341 }
2342
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002343 if (pr || px) {
2344 /* At least one peer or one listener has been found */
2345 qfprintf(stdout, "Configuration file is valid\n");
Tim Duesterhus0a3b43d2020-06-14 00:37:42 +02002346 deinit_and_exit(0);
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002347 }
2348 qfprintf(stdout, "Configuration file has no error but will not start (no listener) => exit(2).\n");
2349 exit(2);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002350 }
Willy Tarreaue9b26022011-08-01 20:57:55 +02002351
Erwan Le Goasb0c05012022-09-14 17:51:55 +02002352 if (global.mode & MODE_DUMP_CFG)
2353 deinit_and_exit(0);
2354
Amaury Denoyelle5a6926d2021-03-30 17:34:24 +02002355 if (global.mode & MODE_DIAG) {
2356 cfg_run_diagnostics();
2357 }
2358
Remi Tricot-Le Breton51944462022-05-16 16:24:31 +02002359#ifdef USE_OPENSSL
William Lallemand3b8bafd2022-07-19 18:13:29 +02002360
Remi Tricot-Le Breton51944462022-05-16 16:24:31 +02002361 /* Initialize SSL random generator. Must be called before chroot for
2362 * access to /dev/urandom, and before ha_random_boot() which may use
2363 * RAND_bytes().
2364 */
2365 if (!ssl_initialize_random()) {
2366 ha_alert("OpenSSL random data generator initialization failed.\n");
2367 exit(EXIT_FAILURE);
2368 }
2369#endif
2370 ha_random_boot(argv); // the argv pointer brings some kernel-fed entropy
2371
Willy Tarreau8263d2b2012-08-28 00:06:31 +02002372 /* now we know the buffer size, we can initialize the channels and buffers */
Willy Tarreau9b28e032012-10-12 23:49:43 +02002373 init_buffer();
Willy Tarreau8280d642009-09-23 23:37:52 +02002374
Willy Tarreaue6945732016-12-21 19:57:00 +01002375 list_for_each_entry(pcf, &post_check_list, list) {
2376 err_code |= pcf->fct();
2377 if (err_code & (ERR_ABORT|ERR_FATAL))
2378 exit(1);
2379 }
2380
William Lallemand0a012aa2022-06-21 11:11:50 +02002381 /* set the default maxconn in the master, but let it be rewritable with -n */
2382 if (global.mode & MODE_MWORKER_WAIT)
William Lallemand2078d4b2023-03-09 14:28:44 +01002383 global.maxconn = MASTER_MAXCONN;
William Lallemand0a012aa2022-06-21 11:11:50 +02002384
Willy Tarreaubaaee002006-06-26 02:48:02 +02002385 if (cfg_maxconn > 0)
2386 global.maxconn = cfg_maxconn;
2387
Willy Tarreau4975d142021-03-13 11:00:33 +01002388 if (global.cli_fe)
2389 global.maxsock += global.cli_fe->maxconn;
Willy Tarreau8d687d82019-03-01 09:39:42 +01002390
2391 if (cfg_peers) {
2392 /* peers also need to bypass global maxconn */
2393 struct peers *p = cfg_peers;
2394
2395 for (p = cfg_peers; p; p = p->next)
2396 if (p->peers_fe)
2397 global.maxsock += p->peers_fe->maxconn;
2398 }
2399
Willy Tarreaud0256482015-01-15 21:45:22 +01002400 /* Now we want to compute the maxconn and possibly maxsslconn values.
Willy Tarreauac350932019-03-01 15:43:14 +01002401 * It's a bit tricky. Maxconn defaults to the pre-computed value based
2402 * on rlim_fd_cur and the number of FDs in use due to the configuration,
2403 * and maxsslconn defaults to DEFAULT_MAXSSLCONN. On top of that we can
2404 * enforce a lower limit based on memmax.
Willy Tarreaud0256482015-01-15 21:45:22 +01002405 *
2406 * If memmax is set, then it depends on which values are set. If
2407 * maxsslconn is set, we use memmax to determine how many cleartext
2408 * connections may be added, and set maxconn to the sum of the two.
2409 * If maxconn is set and not maxsslconn, maxsslconn is computed from
2410 * the remaining amount of memory between memmax and the cleartext
2411 * connections. If neither are set, then it is considered that all
2412 * connections are SSL-capable, and maxconn is computed based on this,
2413 * then maxsslconn accordingly. We need to know if SSL is used on the
2414 * frontends, backends, or both, because when it's used on both sides,
2415 * we need twice the value for maxsslconn, but we only count the
2416 * handshake once since it is not performed on the two sides at the
2417 * same time (frontend-side is terminated before backend-side begins).
2418 * The SSL stack is supposed to have filled ssl_session_cost and
Willy Tarreau474b96a2015-01-28 19:03:21 +01002419 * ssl_handshake_cost during its initialization. In any case, if
2420 * SYSTEM_MAXCONN is set, we still enforce it as an upper limit for
2421 * maxconn in order to protect the system.
Willy Tarreaud0256482015-01-15 21:45:22 +01002422 */
Willy Tarreauac350932019-03-01 15:43:14 +01002423 ideal_maxconn = compute_ideal_maxconn();
2424
Willy Tarreaud0256482015-01-15 21:45:22 +01002425 if (!global.rlimit_memmax) {
2426 if (global.maxconn == 0) {
Willy Tarreauac350932019-03-01 15:43:14 +01002427 global.maxconn = ideal_maxconn;
Willy Tarreaud0256482015-01-15 21:45:22 +01002428 if (global.mode & (MODE_VERBOSE|MODE_DEBUG))
2429 fprintf(stderr, "Note: setting global.maxconn to %d.\n", global.maxconn);
2430 }
2431 }
2432#ifdef USE_OPENSSL
2433 else if (!global.maxconn && !global.maxsslconn &&
2434 (global.ssl_used_frontend || global.ssl_used_backend)) {
2435 /* memmax is set, compute everything automatically. Here we want
2436 * to ensure that all SSL connections will be served. We take
2437 * care of the number of sides where SSL is used, and consider
2438 * the worst case : SSL used on both sides and doing a handshake
2439 * simultaneously. Note that we can't have more than maxconn
2440 * handshakes at a time by definition, so for the worst case of
2441 * two SSL conns per connection, we count a single handshake.
2442 */
2443 int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
2444 int64_t mem = global.rlimit_memmax * 1048576ULL;
Willy Tarreau304e17e2020-03-10 17:54:54 +01002445 int retried = 0;
Willy Tarreaud0256482015-01-15 21:45:22 +01002446
Willy Tarreau2cb3be72022-05-24 07:43:57 +02002447 mem -= global.tune.sslcachesize * 200ULL; // about 200 bytes per SSL cache entry
Willy Tarreaud0256482015-01-15 21:45:22 +01002448 mem -= global.maxzlibmem;
2449 mem = mem * MEM_USABLE_RATIO;
2450
Willy Tarreau304e17e2020-03-10 17:54:54 +01002451 /* Principle: we test once to set maxconn according to the free
2452 * memory. If it results in values the system rejects, we try a
2453 * second time by respecting rlim_fd_max. If it fails again, we
2454 * go back to the initial value and will let the final code
2455 * dealing with rlimit report the error. That's up to 3 attempts.
2456 */
2457 do {
2458 global.maxconn = mem /
2459 ((STREAM_MAX_COST + 2 * global.tune.bufsize) + // stream + 2 buffers per stream
2460 sides * global.ssl_session_max_cost + // SSL buffers, one per side
2461 global.ssl_handshake_max_cost); // 1 handshake per connection max
Willy Tarreaud0256482015-01-15 21:45:22 +01002462
Willy Tarreau304e17e2020-03-10 17:54:54 +01002463 if (retried == 1)
2464 global.maxconn = MIN(global.maxconn, ideal_maxconn);
2465 global.maxconn = round_2dig(global.maxconn);
Willy Tarreau474b96a2015-01-28 19:03:21 +01002466#ifdef SYSTEM_MAXCONN
Willy Tarreau304e17e2020-03-10 17:54:54 +01002467 if (global.maxconn > SYSTEM_MAXCONN)
2468 global.maxconn = SYSTEM_MAXCONN;
Willy Tarreau474b96a2015-01-28 19:03:21 +01002469#endif /* SYSTEM_MAXCONN */
Willy Tarreau304e17e2020-03-10 17:54:54 +01002470 global.maxsslconn = sides * global.maxconn;
2471
2472 if (check_if_maxsock_permitted(compute_ideal_maxsock(global.maxconn)))
2473 break;
2474 } while (retried++ < 2);
2475
Willy Tarreaud0256482015-01-15 21:45:22 +01002476 if (global.mode & (MODE_VERBOSE|MODE_DEBUG))
2477 fprintf(stderr, "Note: setting global.maxconn to %d and global.maxsslconn to %d.\n",
2478 global.maxconn, global.maxsslconn);
2479 }
2480 else if (!global.maxsslconn &&
2481 (global.ssl_used_frontend || global.ssl_used_backend)) {
2482 /* memmax and maxconn are known, compute maxsslconn automatically.
2483 * maxsslconn being forced, we don't know how many of it will be
2484 * on each side if both sides are being used. The worst case is
2485 * when all connections use only one SSL instance because
2486 * handshakes may be on two sides at the same time.
2487 */
2488 int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
2489 int64_t mem = global.rlimit_memmax * 1048576ULL;
2490 int64_t sslmem;
2491
Willy Tarreau8e5b9582022-05-26 08:55:05 +02002492 mem -= global.tune.sslcachesize * 200ULL; // about 200 bytes per SSL cache entry
Willy Tarreaud0256482015-01-15 21:45:22 +01002493 mem -= global.maxzlibmem;
2494 mem = mem * MEM_USABLE_RATIO;
2495
Willy Tarreau87b09662015-04-03 00:22:06 +02002496 sslmem = mem - global.maxconn * (int64_t)(STREAM_MAX_COST + 2 * global.tune.bufsize);
Willy Tarreaud0256482015-01-15 21:45:22 +01002497 global.maxsslconn = sslmem / (global.ssl_session_max_cost + global.ssl_handshake_max_cost);
2498 global.maxsslconn = round_2dig(global.maxsslconn);
2499
2500 if (sslmem <= 0 || global.maxsslconn < sides) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002501 ha_alert("Cannot compute the automatic maxsslconn because global.maxconn is already too "
2502 "high for the global.memmax value (%d MB). The absolute maximum possible value "
2503 "without SSL is %d, but %d was found and SSL is in use.\n",
2504 global.rlimit_memmax,
2505 (int)(mem / (STREAM_MAX_COST + 2 * global.tune.bufsize)),
2506 global.maxconn);
Willy Tarreaud0256482015-01-15 21:45:22 +01002507 exit(1);
2508 }
2509
2510 if (global.maxsslconn > sides * global.maxconn)
2511 global.maxsslconn = sides * global.maxconn;
2512
2513 if (global.mode & (MODE_VERBOSE|MODE_DEBUG))
2514 fprintf(stderr, "Note: setting global.maxsslconn to %d\n", global.maxsslconn);
2515 }
2516#endif
2517 else if (!global.maxconn) {
2518 /* memmax and maxsslconn are known/unused, compute maxconn automatically */
2519 int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
2520 int64_t mem = global.rlimit_memmax * 1048576ULL;
2521 int64_t clearmem;
Willy Tarreau304e17e2020-03-10 17:54:54 +01002522 int retried = 0;
Willy Tarreaud0256482015-01-15 21:45:22 +01002523
2524 if (global.ssl_used_frontend || global.ssl_used_backend)
Willy Tarreau8e5b9582022-05-26 08:55:05 +02002525 mem -= global.tune.sslcachesize * 200ULL; // about 200 bytes per SSL cache entry
Willy Tarreaud0256482015-01-15 21:45:22 +01002526
2527 mem -= global.maxzlibmem;
2528 mem = mem * MEM_USABLE_RATIO;
2529
2530 clearmem = mem;
2531 if (sides)
2532 clearmem -= (global.ssl_session_max_cost + global.ssl_handshake_max_cost) * (int64_t)global.maxsslconn;
2533
Willy Tarreau304e17e2020-03-10 17:54:54 +01002534 /* Principle: we test once to set maxconn according to the free
2535 * memory. If it results in values the system rejects, we try a
2536 * second time by respecting rlim_fd_max. If it fails again, we
2537 * go back to the initial value and will let the final code
2538 * dealing with rlimit report the error. That's up to 3 attempts.
2539 */
2540 do {
2541 global.maxconn = clearmem / (STREAM_MAX_COST + 2 * global.tune.bufsize);
2542 if (retried == 1)
2543 global.maxconn = MIN(global.maxconn, ideal_maxconn);
2544 global.maxconn = round_2dig(global.maxconn);
Willy Tarreau474b96a2015-01-28 19:03:21 +01002545#ifdef SYSTEM_MAXCONN
Willy Tarreau304e17e2020-03-10 17:54:54 +01002546 if (global.maxconn > SYSTEM_MAXCONN)
2547 global.maxconn = SYSTEM_MAXCONN;
Willy Tarreau474b96a2015-01-28 19:03:21 +01002548#endif /* SYSTEM_MAXCONN */
Willy Tarreaud0256482015-01-15 21:45:22 +01002549
Willy Tarreau304e17e2020-03-10 17:54:54 +01002550 if (clearmem <= 0 || !global.maxconn) {
2551 ha_alert("Cannot compute the automatic maxconn because global.maxsslconn is already too "
2552 "high for the global.memmax value (%d MB). The absolute maximum possible value "
2553 "is %d, but %d was found.\n",
2554 global.rlimit_memmax,
Christopher Faulet767a84b2017-11-24 16:50:31 +01002555 (int)(mem / (global.ssl_session_max_cost + global.ssl_handshake_max_cost)),
Willy Tarreau304e17e2020-03-10 17:54:54 +01002556 global.maxsslconn);
2557 exit(1);
2558 }
2559
2560 if (check_if_maxsock_permitted(compute_ideal_maxsock(global.maxconn)))
2561 break;
2562 } while (retried++ < 2);
Willy Tarreaud0256482015-01-15 21:45:22 +01002563
2564 if (global.mode & (MODE_VERBOSE|MODE_DEBUG)) {
2565 if (sides && global.maxsslconn > sides * global.maxconn) {
2566 fprintf(stderr, "Note: global.maxsslconn is forced to %d which causes global.maxconn "
2567 "to be limited to %d. Better reduce global.maxsslconn to get more "
2568 "room for extra connections.\n", global.maxsslconn, global.maxconn);
2569 }
2570 fprintf(stderr, "Note: setting global.maxconn to %d\n", global.maxconn);
2571 }
Willy Tarreau66aa61f2009-01-18 21:44:07 +01002572 }
2573
Willy Tarreaua409f302020-03-10 17:08:53 +01002574 global.maxsock = compute_ideal_maxsock(global.maxconn);
2575 global.hardmaxconn = global.maxconn;
Willy Tarreaua4818db2020-06-19 16:20:59 +02002576 if (!global.maxpipes)
2577 global.maxpipes = compute_ideal_maxpipes();
Willy Tarreaubaaee002006-06-26 02:48:02 +02002578
Olivier Houchard88698d92019-04-16 19:07:22 +02002579 /* update connection pool thresholds */
2580 global.tune.pool_low_count = ((long long)global.maxsock * global.tune.pool_low_ratio + 99) / 100;
2581 global.tune.pool_high_count = ((long long)global.maxsock * global.tune.pool_high_ratio + 99) / 100;
2582
Willy Tarreauc8d5b952019-02-27 17:25:52 +01002583 proxy_adjust_all_maxconn();
2584
Willy Tarreau1db37712007-06-03 17:16:49 +02002585 if (global.tune.maxpollevents <= 0)
2586 global.tune.maxpollevents = MAX_POLL_EVENTS;
2587
Willy Tarreau060a7612021-03-10 11:06:26 +01002588 if (global.tune.runqueue_depth <= 0) {
2589 /* tests on various thread counts from 1 to 64 have shown an
2590 * optimal queue depth following roughly 1/sqrt(threads).
2591 */
2592 int s = my_flsl(global.nbthread);
2593 s += (global.nbthread / s); // roughly twice the sqrt.
2594 global.tune.runqueue_depth = RUNQUEUE_DEPTH * 2 / s;
2595 }
Olivier Houchard1599b802018-05-24 18:59:04 +02002596
Willy Tarreau6f4a82c2009-03-21 20:43:57 +01002597 if (global.tune.recv_enough == 0)
2598 global.tune.recv_enough = MIN_RECV_AT_ONCE_ENOUGH;
2599
Willy Tarreau27a674e2009-08-17 07:23:33 +02002600 if (global.tune.maxrewrite >= global.tune.bufsize / 2)
2601 global.tune.maxrewrite = global.tune.bufsize / 2;
2602
Amaury Denoyelle11124302021-06-04 18:22:08 +02002603 usermsgs_clr(NULL);
2604
Willy Tarreaubaaee002006-06-26 02:48:02 +02002605 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
2606 /* command line debug mode inhibits configuration mode */
William Lallemand095ba4c2017-06-01 17:38:50 +02002607 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
Willy Tarreau772f0dd2012-10-26 16:04:28 +02002608 global.mode |= (arg_mode & (MODE_DEBUG | MODE_FOREGROUND));
2609 }
2610
William Lallemand095ba4c2017-06-01 17:38:50 +02002611 if (arg_mode & MODE_DAEMON) {
Willy Tarreau772f0dd2012-10-26 16:04:28 +02002612 /* command line daemon mode inhibits foreground and debug modes mode */
2613 global.mode &= ~(MODE_DEBUG | MODE_FOREGROUND);
William Lallemand095ba4c2017-06-01 17:38:50 +02002614 global.mode |= arg_mode & MODE_DAEMON;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002615 }
Willy Tarreau772f0dd2012-10-26 16:04:28 +02002616
2617 global.mode |= (arg_mode & (MODE_QUIET | MODE_VERBOSE));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002618
William Lallemand095ba4c2017-06-01 17:38:50 +02002619 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002620 ha_warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
William Lallemand095ba4c2017-06-01 17:38:50 +02002621 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002622 }
2623
Christopher Faulet3ef26392017-08-29 16:46:57 +02002624 /* Realloc trash buffers because global.tune.bufsize may have changed */
Christopher Fauletcd7879a2017-10-27 13:53:47 +02002625 if (!init_trash_buffers(0)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002626 ha_alert("failed to initialize trash buffers.\n");
Christopher Faulet3ef26392017-08-29 16:46:57 +02002627 exit(1);
2628 }
2629
Christopher Faulet96d44832017-11-14 22:02:30 +01002630 if (!init_log_buffers()) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002631 ha_alert("failed to initialize log buffers.\n");
Christopher Faulet96d44832017-11-14 22:02:30 +01002632 exit(1);
2633 }
2634
Amaury Denoyelle28ea31c2022-11-14 16:18:46 +01002635 if (!global.cluster_secret)
2636 generate_random_cluster_secret();
2637
Willy Tarreauef1d1f82007-04-16 00:25:25 +02002638 /*
2639 * Note: we could register external pollers here.
2640 * Built-in pollers have been registered before main().
2641 */
Willy Tarreau4f60f162007-04-08 16:39:58 +02002642
Willy Tarreau43b78992009-01-25 15:42:27 +01002643 if (!(global.tune.options & GTUNE_USE_KQUEUE))
Willy Tarreau1e63130a2007-04-09 12:03:06 +02002644 disable_poller("kqueue");
2645
Emmanuel Hocdet0ba4f482019-04-08 16:53:32 +00002646 if (!(global.tune.options & GTUNE_USE_EVPORTS))
2647 disable_poller("evports");
2648
Willy Tarreau43b78992009-01-25 15:42:27 +01002649 if (!(global.tune.options & GTUNE_USE_EPOLL))
Willy Tarreau4f60f162007-04-08 16:39:58 +02002650 disable_poller("epoll");
2651
Willy Tarreau43b78992009-01-25 15:42:27 +01002652 if (!(global.tune.options & GTUNE_USE_POLL))
Willy Tarreau4f60f162007-04-08 16:39:58 +02002653 disable_poller("poll");
2654
Willy Tarreau43b78992009-01-25 15:42:27 +01002655 if (!(global.tune.options & GTUNE_USE_SELECT))
Willy Tarreau4f60f162007-04-08 16:39:58 +02002656 disable_poller("select");
2657
2658 /* Note: we could disable any poller by name here */
2659
Christopher Fauletb3f4e142016-03-07 12:46:38 +01002660 if (global.mode & (MODE_VERBOSE|MODE_DEBUG)) {
Willy Tarreau2ff76222007-04-09 19:29:56 +02002661 list_pollers(stderr);
Christopher Fauletb3f4e142016-03-07 12:46:38 +01002662 fprintf(stderr, "\n");
2663 list_filters(stderr);
2664 }
Willy Tarreau2ff76222007-04-09 19:29:56 +02002665
Willy Tarreau4f60f162007-04-08 16:39:58 +02002666 if (!init_pollers()) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002667 ha_alert("No polling mechanism available.\n"
Willy Tarreaue5715bf2022-07-09 23:38:46 +02002668 " This may happen when using thread-groups with old pollers (poll/select), or\n"
2669 " it is possible that haproxy was built with TARGET=generic and that FD_SETSIZE\n"
Christopher Faulet767a84b2017-11-24 16:50:31 +01002670 " is too low on this platform to support maxconn and the number of listeners\n"
2671 " and servers. You should rebuild haproxy specifying your system using TARGET=\n"
2672 " in order to support other polling systems (poll, epoll, kqueue) or reduce the\n"
2673 " global maxconn setting to accommodate the system's limitation. For reference,\n"
2674 " FD_SETSIZE=%d on this system, global.maxconn=%d resulting in a maximum of\n"
2675 " %d file descriptors. You should thus reduce global.maxconn by %d. Also,\n"
2676 " check build settings using 'haproxy -vv'.\n\n",
2677 FD_SETSIZE, global.maxconn, global.maxsock, (global.maxsock + 1 - FD_SETSIZE) / 2);
Willy Tarreau4f60f162007-04-08 16:39:58 +02002678 exit(1);
2679 }
Willy Tarreau2ff76222007-04-09 19:29:56 +02002680 if (global.mode & (MODE_VERBOSE|MODE_DEBUG)) {
2681 printf("Using %s() as the polling mechanism.\n", cur_poller.name);
Willy Tarreau4f60f162007-04-08 16:39:58 +02002682 }
2683
Krzysztof Piotr Oledzki48cb2ae2009-10-02 22:51:14 +02002684 if (!global.node)
2685 global.node = strdup(hostname);
2686
Willy Tarreau02b092f2020-10-07 18:36:54 +02002687 /* stop disabled proxies */
2688 for (px = proxies_list; px; px = px->next) {
Christopher Fauletdfd10ab2021-10-06 14:24:19 +02002689 if (px->flags & (PR_FL_DISABLED|PR_FL_STOPPED))
Willy Tarreau02b092f2020-10-07 18:36:54 +02002690 stop_proxy(px);
2691 }
2692
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01002693 if (!hlua_post_init())
2694 exit(1);
Willy Tarreau284cfc62022-12-19 08:15:57 +01002695
2696 /* Set the per-thread pool cache size to the default value if not set.
2697 * This is the right place to decide to automatically adjust it (e.g.
2698 * check L2 cache size, thread counts or take into account certain
2699 * expensive pools).
2700 */
2701 if (!global.tune.pool_cache_size)
2702 global.tune.pool_cache_size = CONFIG_HAP_POOL_CACHE_SIZE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002703}
2704
Cyril Bonté203ec5a2017-03-23 22:44:13 +01002705void deinit(void)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002706{
Olivier Houchardfbc74e82017-11-24 16:54:05 +01002707 struct proxy *p = proxies_list, *p0;
Willy Tarreaudeb9ed82010-01-03 21:03:22 +01002708 struct wordlist *wl, *wlb;
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002709 struct uri_auth *uap, *ua = NULL;
William Lallemand0f99e342011-10-12 17:50:54 +02002710 struct logsrv *log, *logb;
Willy Tarreaucdb737e2016-12-21 18:43:10 +01002711 struct build_opts_str *bol, *bolb;
Tim Duesterhusfdf904a2020-07-04 11:49:48 +02002712 struct post_deinit_fct *pdf, *pdfb;
Tim Duesterhus17e363f2020-07-04 11:49:47 +02002713 struct proxy_deinit_fct *pxdf, *pxdfb;
Tim Duesterhus0837eb12020-07-04 11:49:49 +02002714 struct server_deinit_fct *srvdf, *srvdfb;
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002715 struct per_thread_init_fct *tif, *tifb;
2716 struct per_thread_deinit_fct *tdf, *tdfb;
2717 struct per_thread_alloc_fct *taf, *tafb;
2718 struct per_thread_free_fct *tff, *tffb;
Tim Duesterhus34bef072020-07-04 11:49:50 +02002719 struct post_server_check_fct *pscf, *pscfb;
Tim Duesterhusfc854942020-09-10 19:46:42 +02002720 struct post_check_fct *pcf, *pcfb;
Tim Duesterhus53508d62020-09-10 19:46:40 +02002721 struct post_proxy_check_fct *ppcf, *ppcfb;
Willy Tarreau65009eb2022-04-27 18:02:54 +02002722 struct pre_check_fct *prcf, *prcfb;
Willy Tarreau226866e2022-04-27 18:07:24 +02002723 struct cfg_postparser *pprs, *pprsb;
Willy Tarreauae7bc4a2020-09-23 16:46:22 +02002724 int cur_fd;
2725
Willy Tarreaue98d3852022-11-15 09:34:07 +01002726 /* the user may want to skip this phase */
2727 if (global.tune.options & GTUNE_QUICK_EXIT)
2728 return;
2729
Willy Tarreauae7bc4a2020-09-23 16:46:22 +02002730 /* At this point the listeners state is weird:
2731 * - most listeners are still bound and referenced in their protocol
2732 * - some might be zombies that are not in their proto anymore, but
2733 * still appear in their proxy's listeners with a valid FD.
2734 * - some might be stopped and still appear in their proxy as FD #-1
2735 * - among all of them, some might be inherited hence shared and we're
2736 * not allowed to pause them or whatever, we must just close them.
2737 * - finally some are not listeners (pipes, logs, stdout, etc) and
2738 * must be left intact.
2739 *
2740 * The safe way to proceed is to unbind (and close) whatever is not yet
2741 * unbound so that no more receiver/listener remains alive. Then close
2742 * remaining listener FDs, which correspond to zombie listeners (those
2743 * belonging to disabled proxies that were in another process).
2744 * objt_listener() would be cleaner here but not converted yet.
2745 */
2746 protocol_unbind_all();
2747
2748 for (cur_fd = 0; cur_fd < global.maxsock; cur_fd++) {
Willy Tarreau1a3770c2020-10-14 12:13:51 +02002749 if (!fdtab || !fdtab[cur_fd].owner)
Willy Tarreauae7bc4a2020-09-23 16:46:22 +02002750 continue;
2751
Willy Tarreaua74cb382020-10-15 21:29:49 +02002752 if (fdtab[cur_fd].iocb == &sock_accept_iocb) {
Willy Tarreauae7bc4a2020-09-23 16:46:22 +02002753 struct listener *l = fdtab[cur_fd].owner;
2754
2755 BUG_ON(l->state != LI_INIT);
2756 unbind_listener(l);
2757 }
2758 }
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002759
Willy Tarreau24f4efa2010-08-27 17:56:48 +02002760 deinit_signals();
Willy Tarreaubaaee002006-06-26 02:48:02 +02002761 while (p) {
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002762 /* build a list of unique uri_auths */
2763 if (!ua)
2764 ua = p->uri_auth;
2765 else {
2766 /* check if p->uri_auth is unique */
2767 for (uap = ua; uap; uap=uap->next)
2768 if (uap == p->uri_auth)
2769 break;
2770
Willy Tarreauaccc4e12008-06-24 11:14:45 +02002771 if (!uap && p->uri_auth) {
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002772 /* add it, if it is */
2773 p->uri_auth->next = ua;
2774 ua = p->uri_auth;
2775 }
William Lallemand0f99e342011-10-12 17:50:54 +02002776 }
2777
Willy Tarreau4d2d0982007-05-14 00:39:29 +02002778 p0 = p;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002779 p = p->next;
Amaury Denoyelle27fefa12021-03-24 16:13:20 +01002780 free_proxy(p0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002781 }/* end while(p) */
Willy Tarreaudd815982007-10-16 12:25:14 +02002782
Christopher Faulet27c8d202021-10-13 09:50:53 +02002783 /* destroy all referenced defaults proxies */
2784 proxy_destroy_all_unref_defaults();
2785
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002786 while (ua) {
Tim Duesterhus00f00cf2020-09-10 19:46:38 +02002787 struct stat_scope *scope, *scopep;
2788
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002789 uap = ua;
2790 ua = ua->next;
2791
Willy Tarreaua534fea2008-08-03 12:19:50 +02002792 free(uap->uri_prefix);
2793 free(uap->auth_realm);
Krzysztof Piotr Oledzki48cb2ae2009-10-02 22:51:14 +02002794 free(uap->node);
2795 free(uap->desc);
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002796
Krzysztof Piotr Oledzki8c8bd452010-01-29 19:29:32 +01002797 userlist_free(uap->userlist);
Amaury Denoyelle68fd7e42021-03-25 17:15:52 +01002798 free_act_rules(&uap->http_req_rules);
Krzysztof Piotr Oledzki8c8bd452010-01-29 19:29:32 +01002799
Tim Duesterhus00f00cf2020-09-10 19:46:38 +02002800 scope = uap->scope;
2801 while (scope) {
2802 scopep = scope;
2803 scope = scope->next;
2804
2805 free(scopep->px_id);
2806 free(scopep);
2807 }
2808
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002809 free(uap);
2810 }
2811
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +01002812 userlist_free(userlist);
2813
David Carlier834cb2e2015-09-25 12:02:25 +01002814 cfg_unregister_sections();
2815
Christopher Faulet0132d062017-07-26 15:33:35 +02002816 deinit_log_buffers();
David Carlier834cb2e2015-09-25 12:02:25 +01002817
Willy Tarreau05554e62016-12-21 20:46:26 +01002818 list_for_each_entry(pdf, &post_deinit_list, list)
2819 pdf->fct();
2820
Willy Tarreau61cfdf42021-02-20 10:46:51 +01002821 ha_free(&global.log_send_hostname);
Dragan Dosen43885c72015-10-01 13:18:13 +02002822 chunk_destroy(&global.log_tag);
Willy Tarreau61cfdf42021-02-20 10:46:51 +01002823 ha_free(&global.chroot);
Frédéric Lécaille372508c2022-05-06 08:53:16 +02002824 ha_free(&global.cluster_secret);
Willy Tarreau61cfdf42021-02-20 10:46:51 +01002825 ha_free(&global.pidfile);
2826 ha_free(&global.node);
2827 ha_free(&global.desc);
2828 ha_free(&oldpids);
2829 ha_free(&old_argv);
2830 ha_free(&localpeer);
2831 ha_free(&global.server_state_base);
2832 ha_free(&global.server_state_file);
Olivier Houchard3f795f72019-04-17 22:51:06 +02002833 task_destroy(idle_conn_task);
Olivier Houchard9ea5d362019-02-14 18:29:09 +01002834 idle_conn_task = NULL;
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002835
William Lallemand0f99e342011-10-12 17:50:54 +02002836 list_for_each_entry_safe(log, logb, &global.logsrvs, list) {
Willy Tarreau2c701db2023-01-26 15:32:12 +01002837 LIST_DEL_INIT(&log->list);
2838 free_logsrv(log);
2839 }
2840
Willy Tarreau477ecd82010-01-03 21:12:30 +01002841 list_for_each_entry_safe(wl, wlb, &cfg_cfgfiles, list) {
Maxime de Roucy0f503922016-05-13 23:52:55 +02002842 free(wl->s);
Willy Tarreau2b718102021-04-21 07:32:39 +02002843 LIST_DELETE(&wl->list);
Willy Tarreau477ecd82010-01-03 21:12:30 +01002844 free(wl);
2845 }
2846
Willy Tarreaucdb737e2016-12-21 18:43:10 +01002847 list_for_each_entry_safe(bol, bolb, &build_opts_list, list) {
2848 if (bol->must_free)
2849 free((void *)bol->str);
Willy Tarreau2b718102021-04-21 07:32:39 +02002850 LIST_DELETE(&bol->list);
Willy Tarreaucdb737e2016-12-21 18:43:10 +01002851 free(bol);
2852 }
2853
Tim Duesterhus17e363f2020-07-04 11:49:47 +02002854 list_for_each_entry_safe(pxdf, pxdfb, &proxy_deinit_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002855 LIST_DELETE(&pxdf->list);
Tim Duesterhus17e363f2020-07-04 11:49:47 +02002856 free(pxdf);
2857 }
2858
Tim Duesterhusfdf904a2020-07-04 11:49:48 +02002859 list_for_each_entry_safe(pdf, pdfb, &post_deinit_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002860 LIST_DELETE(&pdf->list);
Tim Duesterhusfdf904a2020-07-04 11:49:48 +02002861 free(pdf);
2862 }
2863
Tim Duesterhus0837eb12020-07-04 11:49:49 +02002864 list_for_each_entry_safe(srvdf, srvdfb, &server_deinit_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002865 LIST_DELETE(&srvdf->list);
Tim Duesterhus0837eb12020-07-04 11:49:49 +02002866 free(srvdf);
2867 }
2868
Tim Duesterhusfc854942020-09-10 19:46:42 +02002869 list_for_each_entry_safe(pcf, pcfb, &post_check_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002870 LIST_DELETE(&pcf->list);
Tim Duesterhusfc854942020-09-10 19:46:42 +02002871 free(pcf);
2872 }
2873
Tim Duesterhus34bef072020-07-04 11:49:50 +02002874 list_for_each_entry_safe(pscf, pscfb, &post_server_check_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002875 LIST_DELETE(&pscf->list);
Tim Duesterhus34bef072020-07-04 11:49:50 +02002876 free(pscf);
2877 }
2878
Tim Duesterhus53508d62020-09-10 19:46:40 +02002879 list_for_each_entry_safe(ppcf, ppcfb, &post_proxy_check_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002880 LIST_DELETE(&ppcf->list);
Tim Duesterhus53508d62020-09-10 19:46:40 +02002881 free(ppcf);
2882 }
2883
Willy Tarreau65009eb2022-04-27 18:02:54 +02002884 list_for_each_entry_safe(prcf, prcfb, &pre_check_list, list) {
2885 LIST_DELETE(&prcf->list);
2886 free(prcf);
2887 }
2888
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002889 list_for_each_entry_safe(tif, tifb, &per_thread_init_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002890 LIST_DELETE(&tif->list);
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002891 free(tif);
2892 }
2893
2894 list_for_each_entry_safe(tdf, tdfb, &per_thread_deinit_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002895 LIST_DELETE(&tdf->list);
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002896 free(tdf);
2897 }
2898
2899 list_for_each_entry_safe(taf, tafb, &per_thread_alloc_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002900 LIST_DELETE(&taf->list);
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002901 free(taf);
2902 }
2903
2904 list_for_each_entry_safe(tff, tffb, &per_thread_free_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002905 LIST_DELETE(&tff->list);
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002906 free(tff);
2907 }
2908
Willy Tarreau226866e2022-04-27 18:07:24 +02002909 list_for_each_entry_safe(pprs, pprsb, &postparsers, list) {
2910 LIST_DELETE(&pprs->list);
2911 free(pprs);
2912 }
2913
Willy Tarreaucfc4f242021-05-08 11:41:28 +02002914 vars_prune(&proc_vars, NULL, NULL);
Willy Tarreau2455ceb2018-11-26 15:57:34 +01002915 pool_destroy_all();
Krzysztof Piotr Oledzkia643baf2008-05-29 23:53:44 +02002916 deinit_pollers();
Willy Tarreaubaaee002006-06-26 02:48:02 +02002917} /* end deinit() */
2918
Willy Tarreauf3ca5a02020-06-15 18:43:46 +02002919__attribute__((noreturn)) void deinit_and_exit(int status)
Tim Duesterhus26540552020-06-14 00:37:41 +02002920{
Amaury Denoyelle7afa5c12021-08-09 15:02:56 +02002921 global.mode |= MODE_STOPPING;
Tim Duesterhus26540552020-06-14 00:37:41 +02002922 deinit();
2923 exit(status);
2924}
William Lallemand72160322018-11-06 17:37:16 +01002925
Willy Tarreau918ff602011-07-25 16:33:49 +02002926/* Runs the polling loop */
Willy Tarreau3ebd55e2020-03-03 14:59:56 +01002927void run_poll_loop()
Willy Tarreau4f60f162007-04-08 16:39:58 +02002928{
Willy Tarreau2ae84e42019-05-28 16:44:05 +02002929 int next, wake;
Willy Tarreau4f60f162007-04-08 16:39:58 +02002930
Willy Tarreau3e820a12023-02-17 08:36:42 +01002931 _HA_ATOMIC_OR(&th_ctx->flags, TH_FL_IN_LOOP);
2932
Willy Tarreau55542642021-10-08 09:33:24 +02002933 clock_update_date(0,1);
Willy Tarreau4f60f162007-04-08 16:39:58 +02002934 while (1) {
Willy Tarreauc49ba522019-12-11 08:12:23 +01002935 wake_expired_tasks();
2936
William Lallemand1aab50b2018-06-07 09:46:01 +02002937 /* check if we caught some signals and process them in the
2938 first thread */
Willy Tarreaua7ad4ae2020-06-19 12:06:34 +02002939 if (signal_queue_len && tid == 0) {
2940 activity[tid].wake_signal++;
William Lallemand1aab50b2018-06-07 09:46:01 +02002941 signal_process_queue();
Willy Tarreaua7ad4ae2020-06-19 12:06:34 +02002942 }
2943
2944 /* Process a few tasks */
2945 process_runnable_tasks();
Willy Tarreau29857942009-05-10 09:01:21 +02002946
Willy Tarreau7067b3a2019-06-02 11:11:29 +02002947 /* also stop if we failed to cleanly stop all tasks */
2948 if (killed > 1)
2949 break;
2950
Matthias Wirtheea152e2022-09-09 10:21:00 +02002951 /* expire immediately if events or signals are pending */
Willy Tarreau2ae84e42019-05-28 16:44:05 +02002952 wake = 1;
Olivier Houchard305d5ab2019-07-24 18:07:06 +02002953 if (thread_has_tasks())
Willy Tarreaud80cb4e2018-01-20 19:30:13 +01002954 activity[tid].wake_tasks++;
Olivier Houchard79321b92018-07-26 17:55:11 +02002955 else {
Willy Tarreaue7475c82022-06-20 09:23:24 +02002956 _HA_ATOMIC_OR(&th_ctx->flags, TH_FL_SLEEPING);
Willy Tarreaudce4ad72022-06-22 15:38:38 +02002957 _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_NOTIFIED);
Olivier Houchardb23a61f2019-03-08 18:51:17 +01002958 __ha_barrier_atomic_store();
Willy Tarreau95abd5b2020-03-23 09:33:32 +01002959 if (thread_has_tasks()) {
Olivier Houchard79321b92018-07-26 17:55:11 +02002960 activity[tid].wake_tasks++;
Willy Tarreaue7475c82022-06-20 09:23:24 +02002961 _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_SLEEPING);
Matthias Wirtheea152e2022-09-09 10:21:00 +02002962 } else if (signal_queue_len) {
2963 /* this check is required after setting TH_FL_SLEEPING to avoid
2964 * a race with wakeup on signals using wake_threads() */
2965 _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_SLEEPING);
Olivier Houchard79321b92018-07-26 17:55:11 +02002966 } else
Willy Tarreau2ae84e42019-05-28 16:44:05 +02002967 wake = 0;
Olivier Houchard79321b92018-07-26 17:55:11 +02002968 }
Willy Tarreau10146c92015-04-13 20:44:19 +02002969
Willy Tarreau4f46a352020-03-23 09:27:28 +01002970 if (!wake) {
Willy Tarreaud7a6b2f2020-05-13 13:51:01 +02002971 int i;
2972
2973 if (stopping) {
Amaury Denoyelle5907fed2023-03-08 10:37:45 +01002974 /* stop muxes/quic-conns before acknowledging stopping */
Willy Tarreau24cfc9f2022-07-04 14:07:29 +02002975 if (!(tg_ctx->stopping_threads & ti->ltid_bit)) {
Amaury Denoyelled3a88c12021-05-03 10:47:51 +02002976 task_wakeup(mux_stopping_data[tid].task, TASK_WOKEN_OTHER);
Amaury Denoyelle5907fed2023-03-08 10:37:45 +01002977#ifdef USE_QUIC
2978 quic_handle_stopping();
2979#endif
Amaury Denoyelled3a88c12021-05-03 10:47:51 +02002980 wake = 1;
2981 }
2982
Willy Tarreauef422ce2022-06-28 19:29:29 +02002983 if (_HA_ATOMIC_OR_FETCH(&tg_ctx->stopping_threads, ti->ltid_bit) == ti->ltid_bit &&
2984 _HA_ATOMIC_OR_FETCH(&stopping_tgroup_mask, tg->tgid_bit) == tg->tgid_bit) {
2985 /* first one to detect it, notify all threads that stopping was just set */
2986 for (i = 0; i < global.nbthread; i++) {
Willy Tarreaub2f38c12023-01-19 19:14:18 +01002987 if (_HA_ATOMIC_LOAD(&ha_thread_info[i].tg->threads_enabled) &
Willy Tarreauef422ce2022-06-28 19:29:29 +02002988 ha_thread_info[i].ltid_bit &
2989 ~_HA_ATOMIC_LOAD(&ha_thread_info[i].tg_ctx->stopping_threads))
Willy Tarreaud6455742020-05-13 14:30:25 +02002990 wake_thread(i);
Willy Tarreauef422ce2022-06-28 19:29:29 +02002991 }
Willy Tarreaud6455742020-05-13 14:30:25 +02002992 }
Willy Tarreaud7a6b2f2020-05-13 13:51:01 +02002993 }
Willy Tarreau4f46a352020-03-23 09:27:28 +01002994
2995 /* stop when there's nothing left to do */
2996 if ((jobs - unstoppable_jobs) == 0 &&
Willy Tarreauef422ce2022-06-28 19:29:29 +02002997 (_HA_ATOMIC_LOAD(&stopping_tgroup_mask) & all_tgroups_mask) == all_tgroups_mask) {
2998 /* check that all threads are aware of the stopping status */
2999 for (i = 0; i < global.nbtgroups; i++)
Willy Tarreaub2f38c12023-01-19 19:14:18 +01003000 if ((_HA_ATOMIC_LOAD(&ha_tgroup_ctx[i].stopping_threads) &
3001 _HA_ATOMIC_LOAD(&ha_tgroup_info[i].threads_enabled)) !=
3002 _HA_ATOMIC_LOAD(&ha_tgroup_info[i].threads_enabled))
Willy Tarreauef422ce2022-06-28 19:29:29 +02003003 break;
3004#ifdef USE_THREAD
3005 if (i == global.nbtgroups) {
3006 /* all are OK, let's wake them all and stop */
3007 for (i = 0; i < global.nbthread; i++)
Willy Tarreaub2f38c12023-01-19 19:14:18 +01003008 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 +02003009 wake_thread(i);
3010 break;
3011 }
3012#endif
Willy Tarreaud7a6b2f2020-05-13 13:51:01 +02003013 }
Willy Tarreau4f46a352020-03-23 09:27:28 +01003014 }
3015
Willy Tarreauc49ba522019-12-11 08:12:23 +01003016 /* If we have to sleep, measure how long */
3017 next = wake ? TICK_ETERNITY : next_timer_expiry();
3018
Willy Tarreau58b458d2008-06-29 22:40:23 +02003019 /* The poller will ensure it returns around <next> */
Willy Tarreau2ae84e42019-05-28 16:44:05 +02003020 cur_poller.poll(&cur_poller, next, wake);
Emeric Brun64cc49c2017-10-03 14:46:45 +02003021
Willy Tarreaud80cb4e2018-01-20 19:30:13 +01003022 activity[tid].loops++;
Willy Tarreau4f60f162007-04-08 16:39:58 +02003023 }
Willy Tarreau3e820a12023-02-17 08:36:42 +01003024
3025 _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_IN_LOOP);
Willy Tarreau4f60f162007-04-08 16:39:58 +02003026}
3027
Christopher Faulet1d17c102017-08-29 15:38:48 +02003028static void *run_thread_poll_loop(void *data)
3029{
Willy Tarreau082b6282019-05-22 14:42:12 +02003030 struct per_thread_alloc_fct *ptaf;
Christopher Faulet1d17c102017-08-29 15:38:48 +02003031 struct per_thread_init_fct *ptif;
3032 struct per_thread_deinit_fct *ptdf;
Willy Tarreau082b6282019-05-22 14:42:12 +02003033 struct per_thread_free_fct *ptff;
Willy Tarreau34a150c2019-06-11 09:16:41 +02003034 static int init_left = 0;
Willy Tarreauaf613e82020-06-05 08:40:51 +02003035 __decl_thread(static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER);
3036 __decl_thread(static pthread_cond_t init_cond = PTHREAD_COND_INITIALIZER);
Christopher Faulet1d17c102017-08-29 15:38:48 +02003037
Willy Tarreau43ab05b2021-09-28 09:43:11 +02003038 ha_set_thread(data);
Willy Tarreaufb641d72021-09-28 10:15:47 +02003039 set_thread_cpu_affinity();
Willy Tarreau44c58da2021-10-08 12:27:54 +02003040 clock_set_local_source();
Aurelien DARRAGON739281b2023-01-27 15:13:28 +01003041 /* thread is started, from now on it is not idle nor harmless */
3042 thread_harmless_end();
3043 thread_idle_end();
Willy Tarreau3e820a12023-02-17 08:36:42 +01003044 _HA_ATOMIC_OR(&th_ctx->flags, TH_FL_STARTED);
Willy Tarreau91e6df02019-05-03 17:21:18 +02003045
Willy Tarreau6ec902a2019-06-07 14:41:11 +02003046 /* Now, initialize one thread init at a time. This is better since
3047 * some init code is a bit tricky and may release global resources
3048 * after reallocating them locally. This will also ensure there is
3049 * no race on file descriptors allocation.
3050 */
Willy Tarreau34a150c2019-06-11 09:16:41 +02003051#ifdef USE_THREAD
3052 pthread_mutex_lock(&init_mutex);
3053#endif
3054 /* The first thread must set the number of threads left */
3055 if (!init_left)
3056 init_left = global.nbthread;
3057 init_left--;
Willy Tarreau91e6df02019-05-03 17:21:18 +02003058
Willy Tarreau55542642021-10-08 09:33:24 +02003059 clock_init_thread_date();
Christopher Faulet1d17c102017-08-29 15:38:48 +02003060
Willy Tarreau082b6282019-05-22 14:42:12 +02003061 /* per-thread alloc calls performed here are not allowed to snoop on
3062 * other threads, so they are free to initialize at their own rhythm
3063 * as long as they act as if they were alone. None of them may rely
3064 * on resources initialized by the other ones.
3065 */
3066 list_for_each_entry(ptaf, &per_thread_alloc_list, list) {
3067 if (!ptaf->fct()) {
3068 ha_alert("failed to allocate resources for thread %u.\n", tid);
Willy Tarreaub3c4a8f2021-07-22 14:42:32 +02003069#ifdef USE_THREAD
jenny-cheung048368e2021-07-18 16:40:57 +08003070 pthread_mutex_unlock(&init_mutex);
Willy Tarreaub3c4a8f2021-07-22 14:42:32 +02003071#endif
Willy Tarreau082b6282019-05-22 14:42:12 +02003072 exit(1);
3073 }
3074 }
3075
Willy Tarreau3078e9f2019-05-20 10:50:43 +02003076 /* per-thread init calls performed here are not allowed to snoop on
3077 * other threads, so they are free to initialize at their own rhythm
3078 * as long as they act as if they were alone.
3079 */
Christopher Faulet1d17c102017-08-29 15:38:48 +02003080 list_for_each_entry(ptif, &per_thread_init_list, list) {
3081 if (!ptif->fct()) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003082 ha_alert("failed to initialize thread %u.\n", tid);
Willy Tarreaub3c4a8f2021-07-22 14:42:32 +02003083#ifdef USE_THREAD
jenny-cheung048368e2021-07-18 16:40:57 +08003084 pthread_mutex_unlock(&init_mutex);
Willy Tarreaub3c4a8f2021-07-22 14:42:32 +02003085#endif
Christopher Faulet1d17c102017-08-29 15:38:48 +02003086 exit(1);
3087 }
3088 }
3089
Willy Tarreau71092822019-06-10 09:51:04 +02003090 /* enabling protocols will result in fd_insert() calls to be performed,
3091 * we want all threads to have already allocated their local fd tables
Willy Tarreau34a150c2019-06-11 09:16:41 +02003092 * before doing so, thus only the last thread does it.
Willy Tarreau71092822019-06-10 09:51:04 +02003093 */
Willy Tarreau34a150c2019-06-11 09:16:41 +02003094 if (init_left == 0)
Willy Tarreaue4d7c9d2019-06-10 10:14:52 +02003095 protocol_enable_all();
Willy Tarreau6ec902a2019-06-07 14:41:11 +02003096
Willy Tarreau34a150c2019-06-11 09:16:41 +02003097#ifdef USE_THREAD
3098 pthread_cond_broadcast(&init_cond);
3099 pthread_mutex_unlock(&init_mutex);
3100
3101 /* now wait for other threads to finish starting */
3102 pthread_mutex_lock(&init_mutex);
3103 while (init_left)
3104 pthread_cond_wait(&init_cond, &init_mutex);
3105 pthread_mutex_unlock(&init_mutex);
3106#endif
Willy Tarreau3078e9f2019-05-20 10:50:43 +02003107
Willy Tarreaua45a8b52019-12-06 16:31:45 +01003108#if defined(PR_SET_NO_NEW_PRIVS) && defined(USE_PRCTL)
3109 /* Let's refrain from using setuid executables. This way the impact of
3110 * an eventual vulnerability in a library remains limited. It may
3111 * impact external checks but who cares about them anyway ? In the
3112 * worst case it's possible to disable the option. Obviously we do this
3113 * in workers only. We can't hard-fail on this one as it really is
3114 * implementation dependent though we're interested in feedback, hence
3115 * the warning.
3116 */
3117 if (!(global.tune.options & GTUNE_INSECURE_SETUID) && !master) {
3118 static int warn_fail;
Willy Tarreau18515722021-04-06 11:57:41 +02003119 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 +01003120 ha_warning("Failed to disable setuid, please report to developers with detailed "
3121 "information about your operating system. You can silence this warning "
3122 "by adding 'insecure-setuid-wanted' in the 'global' section.\n");
3123 }
3124 }
3125#endif
3126
Willy Tarreaud96f1122019-12-03 07:07:36 +01003127#if defined(RLIMIT_NPROC)
3128 /* all threads have started, it's now time to prevent any new thread
3129 * or process from starting. Obviously we do this in workers only. We
3130 * can't hard-fail on this one as it really is implementation dependent
3131 * though we're interested in feedback, hence the warning.
3132 */
3133 if (!(global.tune.options & GTUNE_INSECURE_FORK) && !master) {
3134 struct rlimit limit = { .rlim_cur = 0, .rlim_max = 0 };
3135 static int warn_fail;
3136
Willy Tarreau18515722021-04-06 11:57:41 +02003137 if (setrlimit(RLIMIT_NPROC, &limit) == -1 && !_HA_ATOMIC_FETCH_ADD(&warn_fail, 1)) {
Willy Tarreaud96f1122019-12-03 07:07:36 +01003138 ha_warning("Failed to disable forks, please report to developers with detailed "
3139 "information about your operating system. You can silence this warning "
3140 "by adding 'insecure-fork-wanted' in the 'global' section.\n");
3141 }
3142 }
3143#endif
Christopher Faulet1d17c102017-08-29 15:38:48 +02003144 run_poll_loop();
3145
3146 list_for_each_entry(ptdf, &per_thread_deinit_list, list)
3147 ptdf->fct();
3148
Willy Tarreau082b6282019-05-22 14:42:12 +02003149 list_for_each_entry(ptff, &per_thread_free_list, list)
3150 ptff->fct();
3151
Christopher Fauletcd7879a2017-10-27 13:53:47 +02003152#ifdef USE_THREAD
Willy Tarreau291f6ff2022-07-04 13:36:16 +02003153 if (!_HA_ATOMIC_AND_FETCH(&ha_tgroup_info[ti->tgid-1].threads_enabled, ~ti->ltid_bit))
Willy Tarreaucce203a2022-06-24 15:55:11 +02003154 _HA_ATOMIC_AND(&all_tgroups_mask, ~tg->tgid_bit);
Willy Tarreauad92fdf2022-07-06 10:17:21 +02003155 if (!_HA_ATOMIC_AND_FETCH(&tg_ctx->stopping_threads, ~ti->ltid_bit))
3156 _HA_ATOMIC_AND(&stopping_tgroup_mask, ~tg->tgid_bit);
Christopher Fauletcd7879a2017-10-27 13:53:47 +02003157 if (tid > 0)
3158 pthread_exit(NULL);
Christopher Faulet1d17c102017-08-29 15:38:48 +02003159#endif
Christopher Fauletcd7879a2017-10-27 13:53:47 +02003160 return NULL;
3161}
Christopher Faulet1d17c102017-08-29 15:38:48 +02003162
William Dauchyf9af9d72019-11-17 15:47:16 +01003163/* set uid/gid depending on global settings */
3164static void set_identity(const char *program_name)
3165{
3166 if (global.gid) {
3167 if (getgroups(0, NULL) > 0 && setgroups(0, NULL) == -1)
3168 ha_warning("[%s.main()] Failed to drop supplementary groups. Using 'gid'/'group'"
3169 " without 'uid'/'user' is generally useless.\n", program_name);
3170
3171 if (setgid(global.gid) == -1) {
3172 ha_alert("[%s.main()] Cannot set gid %d.\n", program_name, global.gid);
3173 protocol_unbind_all();
3174 exit(1);
3175 }
3176 }
3177
3178 if (global.uid && setuid(global.uid) == -1) {
3179 ha_alert("[%s.main()] Cannot set uid %d.\n", program_name, global.uid);
3180 protocol_unbind_all();
3181 exit(1);
3182 }
3183}
3184
Willy Tarreaubaaee002006-06-26 02:48:02 +02003185int main(int argc, char **argv)
3186{
3187 int err, retry;
3188 struct rlimit limit;
Willy Tarreau269ab312012-09-05 08:02:48 +02003189 int pidfd = -1;
Willy Tarreau1335da32021-07-14 17:54:01 +02003190 int intovf = (unsigned char)argc + 1; /* let the compiler know it's strictly positive */
3191
Willy Tarreau41afd902022-07-21 09:55:22 +02003192 /* Catch broken toolchains */
3193 if (sizeof(long) != sizeof(void *) || (intovf + 0x7FFFFFFF >= intovf)) {
3194 const char *msg;
3195
3196 if (sizeof(long) != sizeof(void *))
3197 /* Apparently MingW64 was not made for us and can also break openssl */
3198 msg = "The compiler this program was built with uses unsupported integral type sizes.\n"
3199 "Most likely it follows the unsupported LLP64 model. Never try to link HAProxy\n"
3200 "against libraries built with that compiler either! Please only use a compiler\n"
3201 "producing ILP32 or LP64 programs for both programs and libraries.\n";
3202 else if (intovf + 0x7FFFFFFF >= intovf)
3203 /* Catch forced CFLAGS that miss 2-complement integer overflow */
3204 msg = "The source code was miscompiled by the compiler, which usually indicates that\n"
3205 "some of the CFLAGS needed to work around overzealous compiler optimizations\n"
3206 "were overwritten at build time. Please do not force CFLAGS, and read Makefile\n"
3207 "and INSTALL files to decide on the best way to pass your local build options.\n";
3208 else
3209 msg = "Bug in the compiler bug detection code, please report it to developers!\n";
3210
Willy Tarreau1335da32021-07-14 17:54:01 +02003211 fprintf(stderr,
3212 "FATAL ERROR: invalid code detected -- cannot go further, please recompile!\n"
Willy Tarreau41afd902022-07-21 09:55:22 +02003213 "%s"
3214 "\nBuild options :"
Willy Tarreau1335da32021-07-14 17:54:01 +02003215#ifdef BUILD_TARGET
Willy Tarreau41afd902022-07-21 09:55:22 +02003216 "\n TARGET = " BUILD_TARGET
Willy Tarreau1335da32021-07-14 17:54:01 +02003217#endif
3218#ifdef BUILD_CPU
Willy Tarreau41afd902022-07-21 09:55:22 +02003219 "\n CPU = " BUILD_CPU
Willy Tarreau1335da32021-07-14 17:54:01 +02003220#endif
3221#ifdef BUILD_CC
Willy Tarreau41afd902022-07-21 09:55:22 +02003222 "\n CC = " BUILD_CC
Willy Tarreau1335da32021-07-14 17:54:01 +02003223#endif
3224#ifdef BUILD_CFLAGS
Willy Tarreau41afd902022-07-21 09:55:22 +02003225 "\n CFLAGS = " BUILD_CFLAGS
Willy Tarreau1335da32021-07-14 17:54:01 +02003226#endif
3227#ifdef BUILD_OPTIONS
Willy Tarreau41afd902022-07-21 09:55:22 +02003228 "\n OPTIONS = " BUILD_OPTIONS
Willy Tarreau1335da32021-07-14 17:54:01 +02003229#endif
3230#ifdef BUILD_DEBUG
Willy Tarreau41afd902022-07-21 09:55:22 +02003231 "\n DEBUG = " BUILD_DEBUG
Willy Tarreau1335da32021-07-14 17:54:01 +02003232#endif
Willy Tarreau41afd902022-07-21 09:55:22 +02003233 "\n\n", msg);
3234
Willy Tarreau1335da32021-07-14 17:54:01 +02003235 return 1;
3236 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003237
Olivier Houchard5fa300d2018-02-03 15:15:21 +01003238 setvbuf(stdout, NULL, _IONBF, 0);
Willy Tarreau5794fb02018-11-25 18:43:29 +01003239
Willy Tarreaubf696402019-03-01 10:09:28 +01003240 /* take a copy of initial limits before we possibly change them */
3241 getrlimit(RLIMIT_NOFILE, &limit);
Willy Tarreau2bd0f812020-10-13 15:36:08 +02003242
3243 if (limit.rlim_max == RLIM_INFINITY)
3244 limit.rlim_max = limit.rlim_cur;
Willy Tarreaubf696402019-03-01 10:09:28 +01003245 rlim_fd_cur_at_boot = limit.rlim_cur;
3246 rlim_fd_max_at_boot = limit.rlim_max;
3247
Willy Tarreau5794fb02018-11-25 18:43:29 +01003248 /* process all initcalls in order of potential dependency */
3249 RUN_INITCALLS(STG_PREPARE);
3250 RUN_INITCALLS(STG_LOCK);
Willy Tarreau3ebe4d92022-02-18 14:51:49 +01003251 RUN_INITCALLS(STG_REGISTER);
Willy Tarreau34527d52022-02-17 17:45:58 +01003252
3253 /* now's time to initialize early boot variables */
3254 init_early(argc, argv);
3255
Willy Tarreau18f96d02022-02-23 17:25:00 +01003256 /* handles argument parsing */
3257 init_args(argc, argv);
3258
Willy Tarreau5794fb02018-11-25 18:43:29 +01003259 RUN_INITCALLS(STG_ALLOC);
3260 RUN_INITCALLS(STG_POOL);
Willy Tarreau5794fb02018-11-25 18:43:29 +01003261 RUN_INITCALLS(STG_INIT);
3262
Willy Tarreau34527d52022-02-17 17:45:58 +01003263 /* this is the late init where the config is parsed */
Emeric Bruncf20bf12010-10-22 16:06:11 +02003264 init(argc, argv);
Willy Tarreau34527d52022-02-17 17:45:58 +01003265
Willy Tarreau24f4efa2010-08-27 17:56:48 +02003266 signal_register_fct(SIGQUIT, dump, SIGQUIT);
3267 signal_register_fct(SIGUSR1, sig_soft_stop, SIGUSR1);
3268 signal_register_fct(SIGHUP, sig_dump_state, SIGHUP);
William Lallemand73b85e72017-06-01 17:38:51 +02003269 signal_register_fct(SIGUSR2, NULL, 0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003270
Willy Tarreaue437c442010-03-17 18:02:46 +01003271 /* Always catch SIGPIPE even on platforms which define MSG_NOSIGNAL.
3272 * Some recent FreeBSD setups report broken pipes, and MSG_NOSIGNAL
3273 * was defined there, so let's stay on the safe side.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003274 */
Willy Tarreau24f4efa2010-08-27 17:56:48 +02003275 signal_register_fct(SIGPIPE, NULL, 0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003276
Willy Tarreaudc23a922011-02-16 11:10:36 +01003277 /* ulimits */
3278 if (!global.rlimit_nofile)
3279 global.rlimit_nofile = global.maxsock;
3280
3281 if (global.rlimit_nofile) {
Willy Tarreaue5cfdac2019-03-01 10:32:05 +01003282 limit.rlim_cur = global.rlimit_nofile;
3283 limit.rlim_max = MAX(rlim_fd_max_at_boot, limit.rlim_cur);
3284
Willy Tarreau2df1fbf2022-04-25 18:02:03 +02003285 if ((global.fd_hard_limit && limit.rlim_cur > global.fd_hard_limit) ||
Willy Tarreauc06557c2022-09-22 16:12:08 +02003286 raise_rlim_nofile(NULL, &limit) != 0) {
Willy Tarreauef635472016-06-21 11:48:18 +02003287 getrlimit(RLIMIT_NOFILE, &limit);
Willy Tarreau2df1fbf2022-04-25 18:02:03 +02003288 if (global.fd_hard_limit && limit.rlim_cur > global.fd_hard_limit)
3289 limit.rlim_cur = global.fd_hard_limit;
3290
William Dauchy0fec3ab2019-10-27 20:08:11 +01003291 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3292 ha_alert("[%s.main()] Cannot raise FD limit to %d, limit is %d.\n",
3293 argv[0], global.rlimit_nofile, (int)limit.rlim_cur);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003294 exit(1);
William Dauchy0fec3ab2019-10-27 20:08:11 +01003295 }
3296 else {
3297 /* try to set it to the max possible at least */
3298 limit.rlim_cur = limit.rlim_max;
Willy Tarreau2df1fbf2022-04-25 18:02:03 +02003299 if (global.fd_hard_limit && limit.rlim_cur > global.fd_hard_limit)
3300 limit.rlim_cur = global.fd_hard_limit;
3301
Willy Tarreauc06557c2022-09-22 16:12:08 +02003302 if (raise_rlim_nofile(&limit, &limit) == 0)
William Dauchy0fec3ab2019-10-27 20:08:11 +01003303 getrlimit(RLIMIT_NOFILE, &limit);
Willy Tarreau164dd0b2016-06-21 11:51:59 +02003304
William Dauchya5194602020-03-28 19:29:58 +01003305 ha_warning("[%s.main()] Cannot raise FD limit to %d, limit is %d.\n",
William Dauchy0fec3ab2019-10-27 20:08:11 +01003306 argv[0], global.rlimit_nofile, (int)limit.rlim_cur);
3307 global.rlimit_nofile = limit.rlim_cur;
3308 }
Willy Tarreaudc23a922011-02-16 11:10:36 +01003309 }
3310 }
3311
3312 if (global.rlimit_memmax) {
3313 limit.rlim_cur = limit.rlim_max =
Willy Tarreau70060452015-12-14 12:46:07 +01003314 global.rlimit_memmax * 1048576ULL;
Willy Tarreaudc23a922011-02-16 11:10:36 +01003315#ifdef RLIMIT_AS
3316 if (setrlimit(RLIMIT_AS, &limit) == -1) {
William Dauchy0fec3ab2019-10-27 20:08:11 +01003317 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3318 ha_alert("[%s.main()] Cannot fix MEM limit to %d megs.\n",
3319 argv[0], global.rlimit_memmax);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003320 exit(1);
William Dauchy0fec3ab2019-10-27 20:08:11 +01003321 }
3322 else
William Dauchya5194602020-03-28 19:29:58 +01003323 ha_warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
William Dauchy0fec3ab2019-10-27 20:08:11 +01003324 argv[0], global.rlimit_memmax);
Willy Tarreaudc23a922011-02-16 11:10:36 +01003325 }
3326#else
3327 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
William Dauchy0fec3ab2019-10-27 20:08:11 +01003328 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3329 ha_alert("[%s.main()] Cannot fix MEM limit to %d megs.\n",
3330 argv[0], global.rlimit_memmax);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003331 exit(1);
William Dauchy0fec3ab2019-10-27 20:08:11 +01003332 }
3333 else
William Dauchya5194602020-03-28 19:29:58 +01003334 ha_warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
William Dauchy0fec3ab2019-10-27 20:08:11 +01003335 argv[0], global.rlimit_memmax);
Willy Tarreaudc23a922011-02-16 11:10:36 +01003336 }
3337#endif
3338 }
3339
William Lallemandf82afbb2022-01-07 18:19:42 +01003340 /* Try to get the listeners FD from the previous process using
3341 * _getsocks on the stat socket, it must never been done in wait mode
3342 * and check mode
3343 */
3344 if (old_unixsocket &&
3345 !(global.mode & (MODE_MWORKER_WAIT|MODE_CHECK|MODE_CHECK_CONDITION))) {
William Lallemand85b0bd92017-06-01 17:38:53 +02003346 if (strcmp("/dev/null", old_unixsocket) != 0) {
Willy Tarreau42961742020-08-28 18:42:45 +02003347 if (sock_get_old_sockets(old_unixsocket) != 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003348 ha_alert("Failed to get the sockets from the old process!\n");
William Lallemand85b0bd92017-06-01 17:38:53 +02003349 if (!(global.mode & MODE_MWORKER))
3350 exit(1);
3351 }
Olivier Houchardf73629d2017-04-05 22:33:04 +02003352 }
3353 }
William Lallemand85b0bd92017-06-01 17:38:53 +02003354
Willy Tarreaubaaee002006-06-26 02:48:02 +02003355 /* We will loop at most 100 times with 10 ms delay each time.
3356 * That's at most 1 second. We only send a signal to old pids
3357 * if we cannot grab at least one port.
3358 */
3359 retry = MAX_START_RETRIES;
3360 err = ERR_NONE;
3361 while (retry >= 0) {
3362 struct timeval w;
Willy Tarreaue91bff22020-09-02 11:11:43 +02003363 err = protocol_bind_all(retry == 0 || nb_oldpids == 0);
Willy Tarreaue13e9252007-12-20 23:05:50 +01003364 /* exit the loop on no error or fatal error */
3365 if ((err & (ERR_RETRYABLE|ERR_FATAL)) != ERR_RETRYABLE)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003366 break;
Willy Tarreaubb545b42010-08-25 12:58:59 +02003367 if (nb_oldpids == 0 || retry == 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003368 break;
3369
3370 /* FIXME-20060514: Solaris and OpenBSD do not support shutdown() on
3371 * listening sockets. So on those platforms, it would be wiser to
3372 * simply send SIGUSR1, which will not be undoable.
3373 */
Willy Tarreaubb545b42010-08-25 12:58:59 +02003374 if (tell_old_pids(SIGTTOU) == 0) {
3375 /* no need to wait if we can't contact old pids */
3376 retry = 0;
3377 continue;
3378 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003379 /* give some time to old processes to stop listening */
3380 w.tv_sec = 0;
3381 w.tv_usec = 10*1000;
3382 select(0, NULL, NULL, NULL, &w);
3383 retry--;
3384 }
3385
Willy Tarreaue91bff22020-09-02 11:11:43 +02003386 /* Note: protocol_bind_all() sends an alert when it fails. */
Willy Tarreau0a3b9d92009-02-04 17:05:23 +01003387 if ((err & ~ERR_WARN) != ERR_NONE) {
Willy Tarreaue91bff22020-09-02 11:11:43 +02003388 ha_alert("[%s.main()] Some protocols failed to start their listeners! Exiting.\n", argv[0]);
Aurelien DARRAGON28a6d482023-01-17 16:30:52 +01003389 if (retry != MAX_START_RETRIES && nb_oldpids)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003390 tell_old_pids(SIGTTIN);
Aurelien DARRAGON28a6d482023-01-17 16:30:52 +01003391 protocol_unbind_all(); /* cleanup everything we can */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003392 exit(1);
3393 }
3394
William Lallemand944e6192018-11-21 15:48:31 +01003395 if (!(global.mode & MODE_MWORKER_WAIT) && listeners == 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003396 ha_alert("[%s.main()] No enabled listener found (check for 'bind' directives) ! Exiting.\n", argv[0]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003397 /* Note: we don't have to send anything to the old pids because we
3398 * never stopped them. */
3399 exit(1);
3400 }
3401
Willy Tarreaue91bff22020-09-02 11:11:43 +02003402 /* Ok, all listeners should now be bound, close any leftover sockets
Olivier Houchardf73629d2017-04-05 22:33:04 +02003403 * the previous process gave us, we don't need them anymore
3404 */
Willy Tarreaub5101162022-01-28 18:28:18 +01003405 sock_drop_unused_old_sockets();
Willy Tarreaudd815982007-10-16 12:25:14 +02003406
Willy Tarreaubaaee002006-06-26 02:48:02 +02003407 /* prepare pause/play signals */
Willy Tarreau24f4efa2010-08-27 17:56:48 +02003408 signal_register_fct(SIGTTOU, sig_pause, SIGTTOU);
3409 signal_register_fct(SIGTTIN, sig_listen, SIGTTIN);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003410
Willy Tarreaubaaee002006-06-26 02:48:02 +02003411 /* MODE_QUIET can inhibit alerts and warnings below this line */
3412
PiBa-NL149a81a2017-12-25 21:03:31 +01003413 if (getenv("HAPROXY_MWORKER_REEXEC") != NULL) {
3414 /* either stdin/out/err are already closed or should stay as they are. */
3415 if ((global.mode & MODE_DAEMON)) {
3416 /* daemon mode re-executing, stdin/stdout/stderr are already closed so keep quiet */
3417 global.mode &= ~MODE_VERBOSE;
3418 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
3419 }
3420 } else {
3421 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
3422 /* detach from the tty */
William Lallemande1340412017-12-28 16:09:36 +01003423 stdio_quiet(-1);
PiBa-NL149a81a2017-12-25 21:03:31 +01003424 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003425 }
3426
3427 /* open log & pid files before the chroot */
William Lallemand7b820a62022-02-14 09:02:14 +01003428 if ((global.mode & MODE_DAEMON || global.mode & MODE_MWORKER) &&
3429 !(global.mode & MODE_MWORKER_WAIT) && global.pidfile != NULL) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003430 unlink(global.pidfile);
3431 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
3432 if (pidfd < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003433 ha_alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003434 if (nb_oldpids)
3435 tell_old_pids(SIGTTIN);
Willy Tarreaudd815982007-10-16 12:25:14 +02003436 protocol_unbind_all();
Willy Tarreaubaaee002006-06-26 02:48:02 +02003437 exit(1);
3438 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003439 }
3440
Willy Tarreaub38651a2007-03-24 17:24:39 +01003441 if ((global.last_checks & LSTCHK_NETADM) && global.uid) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003442 ha_alert("[%s.main()] Some configuration options require full privileges, so global.uid cannot be changed.\n"
3443 "", argv[0]);
Willy Tarreaudd815982007-10-16 12:25:14 +02003444 protocol_unbind_all();
Willy Tarreaub38651a2007-03-24 17:24:39 +01003445 exit(1);
3446 }
3447
Jackie Tapia749f74c2020-07-22 18:59:40 -05003448 /* If the user is not root, we'll still let them try the configuration
3449 * but we inform them that unexpected behaviour may occur.
Willy Tarreau4e30ed72009-02-04 18:02:48 +01003450 */
3451 if ((global.last_checks & LSTCHK_NETADM) && getuid())
Christopher Faulet767a84b2017-11-24 16:50:31 +01003452 ha_warning("[%s.main()] Some options which require full privileges"
3453 " might not work well.\n"
3454 "", argv[0]);
Willy Tarreau4e30ed72009-02-04 18:02:48 +01003455
William Lallemand095ba4c2017-06-01 17:38:50 +02003456 if ((global.mode & (MODE_MWORKER|MODE_DAEMON)) == 0) {
3457
3458 /* chroot if needed */
3459 if (global.chroot != NULL) {
3460 if (chroot(global.chroot) == -1 || chdir("/") == -1) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003461 ha_alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
William Lallemand095ba4c2017-06-01 17:38:50 +02003462 if (nb_oldpids)
3463 tell_old_pids(SIGTTIN);
3464 protocol_unbind_all();
3465 exit(1);
3466 }
Willy Tarreauf223cc02007-10-15 18:57:08 +02003467 }
Willy Tarreauf223cc02007-10-15 18:57:08 +02003468 }
3469
William Lallemand944e6192018-11-21 15:48:31 +01003470 if (nb_oldpids && !(global.mode & MODE_MWORKER_WAIT))
Willy Tarreaubb545b42010-08-25 12:58:59 +02003471 nb_oldpids = tell_old_pids(oldpids_sig);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003472
William Lallemand27edc4b2019-05-07 17:49:33 +02003473 /* send a SIGTERM to workers who have a too high reloads number */
3474 if ((global.mode & MODE_MWORKER) && !(global.mode & MODE_MWORKER_WAIT))
3475 mworker_kill_max_reloads(SIGTERM);
3476
Willy Tarreaubaaee002006-06-26 02:48:02 +02003477 /* Note that any error at this stage will be fatal because we will not
3478 * be able to restart the old pids.
3479 */
3480
William Dauchyf9af9d72019-11-17 15:47:16 +01003481 if ((global.mode & (MODE_MWORKER | MODE_DAEMON)) == 0)
3482 set_identity(argv[0]);
Willy Tarreau636848a2019-04-15 19:38:50 +02003483
Willy Tarreaubaaee002006-06-26 02:48:02 +02003484 /* check ulimits */
3485 limit.rlim_cur = limit.rlim_max = 0;
3486 getrlimit(RLIMIT_NOFILE, &limit);
3487 if (limit.rlim_cur < global.maxsock) {
William Dauchy0fec3ab2019-10-27 20:08:11 +01003488 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3489 ha_alert("[%s.main()] FD limit (%d) too low for maxconn=%d/maxsock=%d. "
3490 "Please raise 'ulimit-n' to %d or more to avoid any trouble.\n",
3491 argv[0], (int)limit.rlim_cur, global.maxconn, global.maxsock,
3492 global.maxsock);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003493 exit(1);
William Dauchy0fec3ab2019-10-27 20:08:11 +01003494 }
3495 else
3496 ha_alert("[%s.main()] FD limit (%d) too low for maxconn=%d/maxsock=%d. "
William Dauchya5194602020-03-28 19:29:58 +01003497 "Please raise 'ulimit-n' to %d or more to avoid any trouble.\n",
William Dauchy0fec3ab2019-10-27 20:08:11 +01003498 argv[0], (int)limit.rlim_cur, global.maxconn, global.maxsock,
3499 global.maxsock);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003500 }
3501
William Lallemand944e6192018-11-21 15:48:31 +01003502 if (global.mode & (MODE_DAEMON | MODE_MWORKER | MODE_MWORKER_WAIT)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003503 int ret = 0;
Willy Tarreaud67ff342021-06-15 07:58:09 +02003504 int in_parent = 0;
William Lallemande1340412017-12-28 16:09:36 +01003505 int devnullfd = -1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003506
William Lallemand095ba4c2017-06-01 17:38:50 +02003507 /*
3508 * if daemon + mworker: must fork here to let a master
3509 * process live in background before forking children
3510 */
William Lallemand73b85e72017-06-01 17:38:51 +02003511
3512 if ((getenv("HAPROXY_MWORKER_REEXEC") == NULL)
3513 && (global.mode & MODE_MWORKER)
3514 && (global.mode & MODE_DAEMON)) {
William Lallemand095ba4c2017-06-01 17:38:50 +02003515 ret = fork();
3516 if (ret < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003517 ha_alert("[%s.main()] Cannot fork.\n", argv[0]);
William Lallemand095ba4c2017-06-01 17:38:50 +02003518 protocol_unbind_all();
3519 exit(1); /* there has been an error */
William Lallemandbfd8eb52018-07-04 15:31:23 +02003520 } else if (ret > 0) { /* parent leave to daemonize */
William Lallemand095ba4c2017-06-01 17:38:50 +02003521 exit(0);
William Lallemandbfd8eb52018-07-04 15:31:23 +02003522 } else /* change the process group ID in the child (master process) */
3523 setsid();
William Lallemand095ba4c2017-06-01 17:38:50 +02003524 }
William Lallemande20b6a62017-06-01 17:38:55 +02003525
William Lallemande20b6a62017-06-01 17:38:55 +02003526
William Lallemanddeed7802017-11-06 11:00:04 +01003527 /* if in master-worker mode, write the PID of the father */
3528 if (global.mode & MODE_MWORKER) {
3529 char pidstr[100];
Willy Tarreau76a80c72019-06-22 07:41:38 +02003530 snprintf(pidstr, sizeof(pidstr), "%d\n", (int)getpid());
Willy Tarreau46ec48b2018-01-23 19:20:19 +01003531 if (pidfd >= 0)
Willy Tarreau2e8ab6b2020-03-14 11:03:20 +01003532 DISGUISE(write(pidfd, pidstr, strlen(pidstr)));
William Lallemanddeed7802017-11-06 11:00:04 +01003533 }
3534
Willy Tarreaubaaee002006-06-26 02:48:02 +02003535 /* the father launches the required number of processes */
William Lallemand944e6192018-11-21 15:48:31 +01003536 if (!(global.mode & MODE_MWORKER_WAIT)) {
William Lallemandeba6a542022-09-26 12:54:39 +02003537 struct ring *tmp_startup_logs = NULL;
3538
William Lallemand9a1ee7a2019-04-01 11:30:02 +02003539 if (global.mode & MODE_MWORKER)
3540 mworker_ext_launch_all();
Willy Tarreaud67ff342021-06-15 07:58:09 +02003541
William Lallemandeba6a542022-09-26 12:54:39 +02003542 /* at this point the worker must have his own startup_logs buffer */
3543 tmp_startup_logs = startup_logs_dup(startup_logs);
Willy Tarreaud67ff342021-06-15 07:58:09 +02003544 ret = fork();
3545 if (ret < 0) {
3546 ha_alert("[%s.main()] Cannot fork.\n", argv[0]);
3547 protocol_unbind_all();
3548 exit(1); /* there has been an error */
3549 }
3550 else if (ret == 0) { /* child breaks here */
William Lallemandeba6a542022-09-26 12:54:39 +02003551 startup_logs_free(startup_logs);
3552 startup_logs = tmp_startup_logs;
Willy Tarreau3c032f22021-07-21 10:17:02 +02003553 /* This one must not be exported, it's internal! */
3554 unsetenv("HAPROXY_MWORKER_REEXEC");
Willy Tarreaue8422bf2021-06-15 09:08:18 +02003555 ha_random_jump96(1);
Willy Tarreaud67ff342021-06-15 07:58:09 +02003556 }
3557 else { /* parent here */
3558 in_parent = 1;
3559
William Lallemand944e6192018-11-21 15:48:31 +01003560 if (pidfd >= 0 && !(global.mode & MODE_MWORKER)) {
3561 char pidstr[100];
3562 snprintf(pidstr, sizeof(pidstr), "%d\n", ret);
Willy Tarreau2e8ab6b2020-03-14 11:03:20 +01003563 DISGUISE(write(pidfd, pidstr, strlen(pidstr)));
William Lallemand944e6192018-11-21 15:48:31 +01003564 }
3565 if (global.mode & MODE_MWORKER) {
3566 struct mworker_proc *child;
William Lallemandce83b4a2018-10-26 14:47:30 +02003567
William Lallemand5d71a6b2021-11-09 15:25:31 +01003568 ha_notice("New worker (%d) forked\n", ret);
William Lallemand944e6192018-11-21 15:48:31 +01003569 /* find the right mworker_proc */
3570 list_for_each_entry(child, &proc_list, list) {
William Lallemandd4835a92022-07-21 00:52:43 +02003571 if (child->reloads == 0 &&
3572 child->options & PROC_O_TYPE_WORKER &&
3573 child->pid == -1) {
William Lallemand5a7f83a2023-02-17 16:23:52 +01003574 child->timestamp = date.tv_sec;
William Lallemand944e6192018-11-21 15:48:31 +01003575 child->pid = ret;
William Lallemand1dc69632019-06-12 19:11:33 +02003576 child->version = strdup(haproxy_version);
William Lallemand944e6192018-11-21 15:48:31 +01003577 break;
3578 }
William Lallemandce83b4a2018-10-26 14:47:30 +02003579 }
3580 }
William Lallemand944e6192018-11-21 15:48:31 +01003581 }
Willy Tarreaud67ff342021-06-15 07:58:09 +02003582
William Lallemand944e6192018-11-21 15:48:31 +01003583 } else {
3584 /* wait mode */
Willy Tarreaud67ff342021-06-15 07:58:09 +02003585 in_parent = 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003586 }
Willy Tarreaufc6c0322012-11-16 16:12:27 +01003587
3588#ifdef USE_CPU_AFFINITY
Willy Tarreau5b093412022-07-08 09:38:30 +02003589 if (!in_parent && ha_cpuset_count(&cpu_map[0].proc)) { /* only do this if the process has a CPU map */
Olivier Houchard97148f62017-08-16 17:29:11 +02003590
David CARLIERdf91cbd2022-01-06 18:53:50 +00003591#if defined(CPUSET_USE_CPUSET) || defined(__DragonFly__)
Willy Tarreau5b093412022-07-08 09:38:30 +02003592 struct hap_cpuset *set = &cpu_map[0].proc;
Amaury Denoyelle982fb532021-04-21 18:39:58 +02003593 sched_setaffinity(0, sizeof(set->cpuset), &set->cpuset);
David CARLIERdf91cbd2022-01-06 18:53:50 +00003594#elif defined(__FreeBSD__)
Willy Tarreau5b093412022-07-08 09:38:30 +02003595 struct hap_cpuset *set = &cpu_map[0].proc;
David CARLIERdf91cbd2022-01-06 18:53:50 +00003596 ret = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(set->cpuset), &set->cpuset);
Willy Tarreaufc6c0322012-11-16 16:12:27 +01003597#endif
Amaury Denoyelle982fb532021-04-21 18:39:58 +02003598 }
Pieter Baauwcaa6a1b2015-09-17 21:26:40 +02003599#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02003600 /* close the pidfile both in children and father */
Willy Tarreau269ab312012-09-05 08:02:48 +02003601 if (pidfd >= 0) {
3602 //lseek(pidfd, 0, SEEK_SET); /* debug: emulate eglibc bug */
3603 close(pidfd);
3604 }
Willy Tarreaud137dd32010-08-25 12:49:05 +02003605
3606 /* We won't ever use this anymore */
Willy Tarreau61cfdf42021-02-20 10:46:51 +01003607 ha_free(&global.pidfile);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003608
Willy Tarreaud67ff342021-06-15 07:58:09 +02003609 if (in_parent) {
William Lallemand944e6192018-11-21 15:48:31 +01003610 if (global.mode & (MODE_MWORKER|MODE_MWORKER_WAIT)) {
William Lallemandfab0fdc2021-11-09 18:01:22 +01003611 master = 1;
PiBa-NLbaf6ea42017-11-28 23:26:08 +01003612
3613 if ((!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
3614 (global.mode & MODE_DAEMON)) {
3615 /* detach from the tty, this is required to properly daemonize. */
William Lallemande1340412017-12-28 16:09:36 +01003616 if ((getenv("HAPROXY_MWORKER_REEXEC") == NULL))
3617 stdio_quiet(-1);
3618
PiBa-NLbaf6ea42017-11-28 23:26:08 +01003619 global.mode &= ~MODE_VERBOSE;
3620 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
PiBa-NLbaf6ea42017-11-28 23:26:08 +01003621 }
3622
William Lallemandfab0fdc2021-11-09 18:01:22 +01003623 if (global.mode & MODE_MWORKER_WAIT) {
3624 /* only the wait mode handles the master CLI */
3625 mworker_loop();
3626 } else {
3627
William Lallemanda46a99e2022-07-07 14:00:36 +02003628#if defined(USE_SYSTEMD)
3629 if (global.tune.options & GTUNE_USE_SYSTEMD)
3630 sd_notifyf(0, "READY=1\nMAINPID=%lu\nSTATUS=Ready.\n", (unsigned long)getpid());
3631#endif
William Lallemandfab0fdc2021-11-09 18:01:22 +01003632 /* if not in wait mode, reload in wait mode to free the memory */
William Lallemand68192b22022-09-24 15:44:42 +02003633 setenv("HAPROXY_LOAD_SUCCESS", "1", 1);
William Lallemand836bda22021-11-09 18:16:47 +01003634 ha_notice("Loading success.\n");
William Lallemand68836742021-11-10 10:49:06 +01003635 proc_self->failedreloads = 0; /* reset the number of failure */
William Lallemandfab0fdc2021-11-09 18:01:22 +01003636 mworker_reexec_waitmode();
3637 }
William Lallemand1499b9b2017-06-07 15:04:47 +02003638 /* should never get there */
3639 exit(EXIT_FAILURE);
Willy Tarreauedaff0a2015-05-01 17:01:08 +02003640 }
William Lallemandcf4e4962017-06-08 19:05:48 +02003641#if defined(USE_OPENSSL) && !defined(OPENSSL_NO_DH)
Grant Zhang872f9c22017-01-21 01:10:18 +00003642 ssl_free_dh();
3643#endif
William Lallemand1499b9b2017-06-07 15:04:47 +02003644 exit(0); /* parent must leave */
Willy Tarreauedaff0a2015-05-01 17:01:08 +02003645 }
3646
William Lallemandcb11fd22017-06-01 17:38:52 +02003647 /* child must never use the atexit function */
3648 atexit_flag = 0;
3649
William Lallemandbc193052018-09-11 10:06:26 +02003650 /* close useless master sockets */
3651 if (global.mode & MODE_MWORKER) {
3652 struct mworker_proc *child, *it;
3653 master = 0;
3654
William Lallemand309dc9a2018-10-26 14:47:45 +02003655 mworker_cli_proxy_stop();
3656
William Lallemandbc193052018-09-11 10:06:26 +02003657 /* free proc struct of other processes */
3658 list_for_each_entry_safe(child, it, &proc_list, list) {
William Lallemandce83b4a2018-10-26 14:47:30 +02003659 /* close the FD of the master side for all
3660 * workers, we don't need to close the worker
3661 * side of other workers since it's done with
3662 * the bind_proc */
William Lallemand7e018782022-01-28 21:56:24 +01003663 if (child->ipc_fd[0] >= 0) {
Tim Duesterhus742e0f92018-11-25 20:03:39 +01003664 close(child->ipc_fd[0]);
William Lallemand7e018782022-01-28 21:56:24 +01003665 child->ipc_fd[0] = -1;
3666 }
Willy Tarreaue8422bf2021-06-15 09:08:18 +02003667 if (child->options & PROC_O_TYPE_WORKER &&
William Lallemandd4835a92022-07-21 00:52:43 +02003668 child->reloads == 0 &&
3669 child->pid == -1) {
William Lallemandce83b4a2018-10-26 14:47:30 +02003670 /* keep this struct if this is our pid */
3671 proc_self = child;
William Lallemandbc193052018-09-11 10:06:26 +02003672 continue;
William Lallemandce83b4a2018-10-26 14:47:30 +02003673 }
Willy Tarreau2b718102021-04-21 07:32:39 +02003674 LIST_DELETE(&child->list);
Tim Duesterhus9b7a9762019-05-16 20:23:22 +02003675 mworker_free_child(child);
3676 child = NULL;
William Lallemandbc193052018-09-11 10:06:26 +02003677 }
3678 }
Willy Tarreau1605c7a2018-01-23 19:01:49 +01003679
William Lallemande1340412017-12-28 16:09:36 +01003680 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
3681 devnullfd = open("/dev/null", O_RDWR, 0);
3682 if (devnullfd < 0) {
3683 ha_alert("Cannot open /dev/null\n");
3684 exit(EXIT_FAILURE);
3685 }
3686 }
3687
William Lallemand095ba4c2017-06-01 17:38:50 +02003688 /* Must chroot and setgid/setuid in the children */
3689 /* chroot if needed */
3690 if (global.chroot != NULL) {
3691 if (chroot(global.chroot) == -1 || chdir("/") == -1) {
Willy Tarreaue34cf282021-06-15 08:59:19 +02003692 ha_alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
William Lallemand095ba4c2017-06-01 17:38:50 +02003693 if (nb_oldpids)
3694 tell_old_pids(SIGTTIN);
3695 protocol_unbind_all();
3696 exit(1);
3697 }
3698 }
3699
Willy Tarreau61cfdf42021-02-20 10:46:51 +01003700 ha_free(&global.chroot);
William Dauchyf9af9d72019-11-17 15:47:16 +01003701 set_identity(argv[0]);
William Lallemand095ba4c2017-06-01 17:38:50 +02003702
William Lallemand7f80eb22017-05-26 18:19:55 +02003703 /* pass through every cli socket, and check if it's bound to
3704 * the current process and if it exposes listeners sockets.
3705 * Caution: the GTUNE_SOCKET_TRANSFER is now set after the fork.
3706 * */
3707
Willy Tarreau4975d142021-03-13 11:00:33 +01003708 if (global.cli_fe) {
William Lallemand7f80eb22017-05-26 18:19:55 +02003709 struct bind_conf *bind_conf;
3710
Willy Tarreau4975d142021-03-13 11:00:33 +01003711 list_for_each_entry(bind_conf, &global.cli_fe->conf.bind, by_fe) {
William Lallemand7f80eb22017-05-26 18:19:55 +02003712 if (bind_conf->level & ACCESS_FD_LISTENERS) {
Willy Tarreau72faef32021-06-15 08:36:30 +02003713 global.tune.options |= GTUNE_SOCKET_TRANSFER;
3714 break;
William Lallemand7f80eb22017-05-26 18:19:55 +02003715 }
3716 }
Willy Tarreauf83d3fe2015-05-01 19:13:41 +02003717 }
3718
William Lallemand2e8fad92018-11-13 16:18:23 +01003719 /*
3720 * This is only done in daemon mode because we might want the
3721 * logs on stdout in mworker mode. If we're NOT in QUIET mode,
3722 * we should now close the 3 first FDs to ensure that we can
3723 * detach from the TTY. We MUST NOT do it in other cases since
3724 * it would have already be done, and 0-2 would have been
3725 * affected to listening sockets
Willy Tarreaubaaee002006-06-26 02:48:02 +02003726 */
William Lallemand2e8fad92018-11-13 16:18:23 +01003727 if ((global.mode & MODE_DAEMON) &&
3728 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003729 /* detach from the tty */
William Lallemande1340412017-12-28 16:09:36 +01003730 stdio_quiet(devnullfd);
Willy Tarreau106cb762008-11-16 07:40:34 +01003731 global.mode &= ~MODE_VERBOSE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003732 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
3733 }
3734 pid = getpid(); /* update child's pid */
William Lallemandbfd8eb52018-07-04 15:31:23 +02003735 if (!(global.mode & MODE_MWORKER)) /* in mworker mode we don't want a new pgid for the children */
3736 setsid();
Willy Tarreau2ff76222007-04-09 19:29:56 +02003737 fork_poller();
Willy Tarreaubaaee002006-06-26 02:48:02 +02003738 }
3739
William Dauchye039f262019-11-17 15:47:15 +01003740 /* try our best to re-enable core dumps depending on system capabilities.
3741 * What is addressed here :
3742 * - remove file size limits
3743 * - remove core size limits
3744 * - mark the process dumpable again if it lost it due to user/group
3745 */
3746 if (global.tune.options & GTUNE_SET_DUMPABLE) {
3747 limit.rlim_cur = limit.rlim_max = RLIM_INFINITY;
3748
3749#if defined(RLIMIT_FSIZE)
3750 if (setrlimit(RLIMIT_FSIZE, &limit) == -1) {
3751 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3752 ha_alert("[%s.main()] Failed to set the raise the maximum "
3753 "file size.\n", argv[0]);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003754 exit(1);
William Dauchye039f262019-11-17 15:47:15 +01003755 }
3756 else
3757 ha_warning("[%s.main()] Failed to set the raise the maximum "
William Dauchya5194602020-03-28 19:29:58 +01003758 "file size.\n", argv[0]);
William Dauchye039f262019-11-17 15:47:15 +01003759 }
3760#endif
3761
3762#if defined(RLIMIT_CORE)
3763 if (setrlimit(RLIMIT_CORE, &limit) == -1) {
3764 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3765 ha_alert("[%s.main()] Failed to set the raise the core "
3766 "dump size.\n", argv[0]);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003767 exit(1);
William Dauchye039f262019-11-17 15:47:15 +01003768 }
3769 else
3770 ha_warning("[%s.main()] Failed to set the raise the core "
William Dauchya5194602020-03-28 19:29:58 +01003771 "dump size.\n", argv[0]);
William Dauchye039f262019-11-17 15:47:15 +01003772 }
3773#endif
3774
3775#if defined(USE_PRCTL)
3776 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1)
3777 ha_warning("[%s.main()] Failed to set the dumpable flag, "
3778 "no core will be dumped.\n", argv[0]);
devnexen@gmail.com21185972021-08-21 09:13:10 +01003779#elif defined(USE_PROCCTL)
Willy Tarreau28345c62021-10-08 15:55:13 +02003780 {
3781 int traceable = PROC_TRACE_CTL_ENABLE;
3782 if (procctl(P_PID, getpid(), PROC_TRACE_CTL, &traceable) == -1)
3783 ha_warning("[%s.main()] Failed to set the traceable flag, "
3784 "no core will be dumped.\n", argv[0]);
3785 }
William Dauchye039f262019-11-17 15:47:15 +01003786#endif
3787 }
3788
Christopher Faulete3a5e352017-10-24 13:53:54 +02003789 global.mode &= ~MODE_STARTING;
Amaury Denoyelle6af81f82021-05-27 15:45:28 +02003790 reset_usermsgs_ctx();
3791
Willy Tarreau2d5d4e02021-09-28 10:36:57 +02003792 /* start threads 2 and above */
Willy Tarreaud10385a2021-10-06 22:22:40 +02003793 setup_extra_threads(&run_thread_poll_loop);
William Lallemand1aab50b2018-06-07 09:46:01 +02003794
Willy Tarreau2d5d4e02021-09-28 10:36:57 +02003795 /* when multithreading we need to let only the thread 0 handle the signals */
William Lallemandd3801c12018-09-11 10:06:23 +02003796 haproxy_unblock_signals();
Willy Tarreau2d5d4e02021-09-28 10:36:57 +02003797
3798 /* Finally, start the poll loop for the first thread */
Willy Tarreau43ab05b2021-09-28 09:43:11 +02003799 run_thread_poll_loop(&ha_thread_info[0]);
Willy Tarreau2d5d4e02021-09-28 10:36:57 +02003800
3801 /* wait for all threads to terminate */
3802 wait_for_threads_completion();
Christopher Faulet1d17c102017-08-29 15:38:48 +02003803
Tim Duesterhus0a3b43d2020-06-14 00:37:42 +02003804 deinit_and_exit(0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003805}
3806
Willy Tarreaubaaee002006-06-26 02:48:02 +02003807/*
3808 * Local variables:
3809 * c-indent-level: 8
3810 * c-basic-offset: 8
3811 * End:
3812 */