2006-06-25 20:48:02 -04:00
|
|
|
/*
|
|
|
|
|
* HA-Proxy : High Availability-enabled HTTP/TCP proxy
|
2014-02-02 18:41:29 -05:00
|
|
|
* Copyright 2000-2014 Willy Tarreau <w@1wt.eu>.
|
2006-06-25 20:48:02 -04:00
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
|
* as published by the Free Software Foundation; either version
|
|
|
|
|
* 2 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* Please refer to RFC2068 or RFC2616 for informations about HTTP protocol, and
|
|
|
|
|
* RFC2965 for informations about cookies usage. More generally, the IETF HTTP
|
|
|
|
|
* Working Group's web site should be consulted for protocol related changes :
|
|
|
|
|
*
|
|
|
|
|
* http://ftp.ics.uci.edu/pub/ietf/http/
|
|
|
|
|
*
|
|
|
|
|
* Pending bugs (may be not fixed because never reproduced) :
|
|
|
|
|
* - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
|
|
|
|
|
* the proxy to terminate (no core) if the client breaks the connection during
|
|
|
|
|
* the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
|
|
|
|
|
* the snprintf() bug since requests were simple (GET / HTTP/1.0), but may be
|
|
|
|
|
* related to missing setsid() (fixed in 1.1.15)
|
|
|
|
|
* - a proxy with an invalid config will prevent the startup even if disabled.
|
|
|
|
|
*
|
|
|
|
|
* ChangeLog has moved to the CHANGELOG file.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <netinet/tcp.h>
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
#include <netdb.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <sys/resource.h>
|
2013-02-12 04:53:52 -05:00
|
|
|
#include <sys/wait.h>
|
2006-06-25 20:48:02 -04:00
|
|
|
#include <time.h>
|
|
|
|
|
#include <syslog.h>
|
BUG/MEDIUM: remove supplementary groups when changing gid
Without it, haproxy will retain the group membership of root, which may
give more access than intended to the process. For example, haproxy would
still be in the wheel group on Fedora 18, as seen with :
# haproxy -f /etc/haproxy/haproxy.cfg
# ps a -o pid,user,group,command | grep hapr
3545 haproxy haproxy haproxy -f /etc/haproxy/haproxy.cfg
4356 root root grep --color=auto hapr
# grep Group /proc/3545/status
Groups: 0 1 2 3 4 6 10
# getent group wheel
wheel:x:10:root,misc
[WT: The issue has been investigated by independent security research team
and realized by itself not being able to allow security exploitation.
Additionally, dropping groups is not allowed to unprivileged users,
though this mode of deployment is quite common. Thus a warning is
emitted in this case to inform the user. The fix could be backported
into all supported versions as the issue has always been there. ]
2013-01-12 12:35:19 -05:00
|
|
|
#include <grp.h>
|
2012-11-16 10:12:27 -05:00
|
|
|
#ifdef USE_CPU_AFFINITY
|
|
|
|
|
#define __USE_GNU
|
|
|
|
|
#include <sched.h>
|
|
|
|
|
#undef __USE_GNU
|
|
|
|
|
#endif
|
2006-06-25 20:48:02 -04:00
|
|
|
|
|
|
|
|
#ifdef DEBUG_FULL
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2006-06-29 11:53:05 -04:00
|
|
|
#include <common/appsession.h>
|
|
|
|
|
#include <common/base64.h>
|
|
|
|
|
#include <common/cfgparse.h>
|
2012-08-24 13:22:53 -04:00
|
|
|
#include <common/chunk.h>
|
2006-06-29 11:53:05 -04:00
|
|
|
#include <common/compat.h>
|
|
|
|
|
#include <common/config.h>
|
|
|
|
|
#include <common/defaults.h>
|
2007-10-28 06:14:07 -04:00
|
|
|
#include <common/errors.h>
|
2006-06-29 11:53:05 -04:00
|
|
|
#include <common/memory.h>
|
|
|
|
|
#include <common/mini-clist.h>
|
2014-11-17 09:11:45 -05:00
|
|
|
#include <common/namespace.h>
|
2006-06-29 11:53:05 -04:00
|
|
|
#include <common/regex.h>
|
|
|
|
|
#include <common/standard.h>
|
|
|
|
|
#include <common/time.h>
|
|
|
|
|
#include <common/uri_auth.h>
|
|
|
|
|
#include <common/version.h>
|
2006-06-25 20:48:02 -04:00
|
|
|
|
|
|
|
|
#include <types/capture.h>
|
|
|
|
|
#include <types/global.h>
|
2011-07-15 00:14:09 -04:00
|
|
|
#include <types/proto_tcp.h>
|
|
|
|
|
#include <types/acl.h>
|
2011-09-07 12:00:47 -04:00
|
|
|
#include <types/peers.h>
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2007-06-16 18:36:03 -04:00
|
|
|
#include <proto/acl.h>
|
2015-04-19 03:59:31 -04:00
|
|
|
#include <proto/applet.h>
|
2012-10-19 13:49:09 -04:00
|
|
|
#include <proto/arg.h>
|
2015-04-19 03:59:31 -04:00
|
|
|
#include <proto/auth.h>
|
2006-06-25 20:48:02 -04:00
|
|
|
#include <proto/backend.h>
|
2012-08-24 13:22:53 -04:00
|
|
|
#include <proto/channel.h>
|
2007-10-14 17:40:01 -04:00
|
|
|
#include <proto/checks.h>
|
2012-10-26 14:10:28 -04:00
|
|
|
#include <proto/connection.h>
|
2006-06-25 20:48:02 -04:00
|
|
|
#include <proto/fd.h>
|
2011-10-24 12:15:04 -04:00
|
|
|
#include <proto/hdr_idx.h>
|
2015-01-23 08:06:13 -05:00
|
|
|
#include <proto/hlua.h>
|
2012-09-12 16:58:11 -04:00
|
|
|
#include <proto/listener.h>
|
2006-06-25 20:48:02 -04:00
|
|
|
#include <proto/log.h>
|
2014-03-11 09:29:22 -04:00
|
|
|
#include <proto/pattern.h>
|
2012-09-12 16:58:11 -04:00
|
|
|
#include <proto/protocol.h>
|
2006-12-24 11:47:20 -05:00
|
|
|
#include <proto/proto_http.h>
|
2006-06-25 20:48:02 -04:00
|
|
|
#include <proto/proxy.h>
|
|
|
|
|
#include <proto/queue.h>
|
|
|
|
|
#include <proto/server.h>
|
2015-04-03 07:53:24 -04:00
|
|
|
#include <proto/session.h>
|
REORG/MAJOR: session: rename the "session" entity to "stream"
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.
In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.
The files stream.{c,h} were added and session.{c,h} removed.
The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.
Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.
Once all changes are completed, we should see approximately this :
L7 - http_txn
L6 - stream
L5 - session
L4 - connection | applet
There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.
Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
2015-04-02 18:22:06 -04:00
|
|
|
#include <proto/stream.h>
|
2009-05-10 03:01:21 -04:00
|
|
|
#include <proto/signal.h>
|
2006-06-25 20:48:02 -04:00
|
|
|
#include <proto/task.h>
|
|
|
|
|
|
2007-03-24 12:24:39 -04:00
|
|
|
#ifdef CONFIG_HAP_CTTPROXY
|
|
|
|
|
#include <proto/cttproxy.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2012-09-07 11:30:07 -04:00
|
|
|
#ifdef USE_OPENSSL
|
|
|
|
|
#include <proto/ssl_sock.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2006-06-25 20:48:02 -04:00
|
|
|
/*********************************************************************/
|
|
|
|
|
|
2012-11-10 13:27:47 -05:00
|
|
|
extern const struct comp_algo comp_algos[];
|
|
|
|
|
|
2006-06-25 20:48:02 -04:00
|
|
|
/*********************************************************************/
|
|
|
|
|
|
2010-01-03 15:12:30 -05:00
|
|
|
/* list of config files */
|
|
|
|
|
static struct list cfg_cfgfiles = LIST_HEAD_INIT(cfg_cfgfiles);
|
2006-06-25 20:48:02 -04:00
|
|
|
int pid; /* current process id */
|
2007-11-26 10:13:36 -05:00
|
|
|
int relative_pid = 1; /* process id starting at 1 */
|
2006-06-25 20:48:02 -04:00
|
|
|
|
|
|
|
|
/* global options */
|
|
|
|
|
struct global global = {
|
2012-11-15 11:38:15 -05:00
|
|
|
.nbproc = 1,
|
2012-04-05 12:02:55 -04:00
|
|
|
.req_count = 0,
|
2011-10-12 11:50:54 -04:00
|
|
|
.logsrvs = LIST_HEAD_INIT(global.logsrvs),
|
2012-11-12 09:52:53 -05:00
|
|
|
#ifdef DEFAULT_MAXZLIBMEM
|
2012-12-03 06:10:45 -05:00
|
|
|
.maxzlibmem = DEFAULT_MAXZLIBMEM * 1024U * 1024U,
|
2012-11-12 09:52:53 -05:00
|
|
|
#else
|
2012-11-07 10:12:57 -05:00
|
|
|
.maxzlibmem = 0,
|
2012-11-12 09:52:53 -05:00
|
|
|
#endif
|
2012-11-09 11:05:39 -05:00
|
|
|
.comp_rate_lim = 0,
|
2014-01-29 06:24:34 -05:00
|
|
|
.ssl_server_verify = SSL_SERVER_VERIFY_REQUIRED,
|
2010-10-22 11:59:25 -04:00
|
|
|
.unix_bind = {
|
|
|
|
|
.ux = {
|
|
|
|
|
.uid = -1,
|
|
|
|
|
.gid = -1,
|
|
|
|
|
.mode = 0,
|
|
|
|
|
}
|
|
|
|
|
},
|
2009-08-17 01:23:33 -04:00
|
|
|
.tune = {
|
|
|
|
|
.bufsize = BUFSIZE,
|
|
|
|
|
.maxrewrite = MAXREWRITE,
|
2010-10-04 14:39:20 -04:00
|
|
|
.chksize = BUFSIZE,
|
MAJOR: session: only wake up as many sessions as available buffers permit
We've already experimented with three wake up algorithms when releasing
buffers : the first naive one used to wake up far too many sessions,
causing many of them not to get any buffer. The second approach which
was still in use prior to this patch consisted in waking up either 1
or 2 sessions depending on the number of FDs we had released. And this
was still inaccurate. The third one tried to cover the accuracy issues
of the second and took into consideration the number of FDs the sessions
would be willing to use, but most of the time we ended up waking up too
many of them for nothing, or deadlocking by lack of buffers.
This patch completely removes the need to allocate two buffers at once.
Instead it splits allocations into critical and non-critical ones and
implements a reserve in the pool for this. The deadlock situation happens
when all buffers are be allocated for requests pending in a maxconn-limited
server queue, because then there's no more way to allocate buffers for
responses, and these responses are critical to release the servers's
connection in order to release the pending requests. In fact maxconn on
a server creates a dependence between sessions and particularly between
oldest session's responses and latest session's requests. Thus, it is
mandatory to get a free buffer for a response in order to release a
server connection which will permit to release a request buffer.
Since we definitely have non-symmetrical buffers, we need to implement
this logic in the buffer allocation mechanism. What this commit does is
implement a reserve of buffers which can only be allocated for responses
and that will never be allocated for requests. This is made possible by
the requester indicating how much margin it wants to leave after the
allocation succeeds. Thus it is a cooperative allocation mechanism : the
requester (process_session() in general) prefers not to get a buffer in
order to respect other's need for response buffers. The session management
code always knows if a buffer will be used for requests or responses, so
that is not difficult :
- either there's an applet on the initiator side and we really need
the request buffer (since currently the applet is called in the
context of the session)
- or we have a connection and we really need the response buffer (in
order to support building and sending an error message back)
This reserve ensures that we don't take all allocatable buffers for
requests waiting in a queue. The downside is that all the extra buffers
are really allocated to ensure they can be allocated. But with small
values it is not an issue.
With this change, we don't observe any more deadlocks even when running
with maxconn 1 on a server under severely constrained memory conditions.
The code becomes a bit tricky, it relies on the scheduler's run queue to
estimate how many sessions are already expected to run so that it doesn't
wake up everyone with too few resources. A better solution would probably
consist in having two queues, one for urgent requests and one for normal
requests. A failed allocation for a session dealing with an error, a
connection event, or the need for a response (or request when there's an
applet on the left) would go to the urgent request queue, while other
requests would go to the other queue. Urgent requests would be served
from 1 entry in the pool, while the regular ones would be served only
according to the reserve. Despite not yet having this, it works
remarkably well.
This mechanism is quite efficient, we don't perform too many wake up calls
anymore. For 1 million sessions elapsed during massive memory contention,
we observe about 4.5M calls to process_session() compared to 4.0M without
memory constraints. Previously we used to observe up to 16M calls, which
rougly means 12M failures.
During a test run under high memory constraints (limit enforced to 27 MB
instead of the 58 MB normally needed), performance used to drop by 53% prior
to this patch. Now with this patch instead it *increases* by about 1.5%.
The best effect of this change is that by limiting the memory usage to about
2/3 to 3/4 of what is needed by default, it's possible to increase performance
by up to about 18% mainly due to the fact that pools are reused more often
and remain hot in the CPU cache (observed on regular HTTP traffic with 20k
objects, buffers.limit = maxconn/10, buffers.reserve = limit/2).
Below is an example of scenario which used to cause a deadlock previously :
- connection is received
- two buffers are allocated in process_session() then released
- one is allocated when receiving an HTTP request
- the second buffer is allocated then released in process_session()
for request parsing then connection establishment.
- poll() says we can send, so the request buffer is sent and released
- process session gets notified that the connection is now established
and allocates two buffers then releases them
- all other sessions do the same till one cannot get the request buffer
without hitting the margin
- and now the server responds. stream_interface allocates the response
buffer and manages to get it since it's higher priority being for a
response.
- but process_session() cannot allocate the request buffer anymore
=> We could end up with all buffers used by responses so that none may
be allocated for a request in process_session().
When the applet processing leaves the session context, the test will have
to be changed so that we always allocate a response buffer regardless of
the left side (eg: H2->H1 gateway). A final improvement would consists in
being able to only retry the failed I/O operation without waking up a
task, but to date all experiments to achieve this have proven not to be
reliable enough.
2014-11-26 19:11:56 -05:00
|
|
|
.reserved_bufs = RESERVED_BUFS,
|
2015-04-29 10:24:50 -04:00
|
|
|
.pattern_cache = DEFAULT_PAT_LRU_SIZE,
|
2012-09-03 06:10:29 -04:00
|
|
|
#ifdef USE_OPENSSL
|
2012-11-14 05:32:56 -05:00
|
|
|
.sslcachesize = SSLCACHESIZE,
|
2014-06-12 08:58:40 -04:00
|
|
|
.ssl_default_dh_param = SSL_DEFAULT_DH_PARAM,
|
2014-02-12 08:55:41 -05:00
|
|
|
#ifdef DEFAULT_SSL_MAX_RECORD
|
|
|
|
|
.ssl_max_record = DEFAULT_SSL_MAX_RECORD,
|
|
|
|
|
#endif
|
2012-09-03 06:10:29 -04:00
|
|
|
#endif
|
2012-11-07 10:54:34 -05:00
|
|
|
#ifdef USE_ZLIB
|
|
|
|
|
.zlibmemlevel = 8,
|
|
|
|
|
.zlibwindowsize = MAX_WBITS,
|
|
|
|
|
#endif
|
2012-11-09 06:33:10 -05:00
|
|
|
.comp_maxlevel = 1,
|
2014-02-12 10:35:14 -05:00
|
|
|
#ifdef DEFAULT_IDLE_TIMER
|
|
|
|
|
.idle_timer = DEFAULT_IDLE_TIMER,
|
|
|
|
|
#else
|
|
|
|
|
.idle_timer = 1000, /* 1 second */
|
|
|
|
|
#endif
|
2009-08-17 01:23:33 -04:00
|
|
|
},
|
2012-10-05 09:47:31 -04:00
|
|
|
#ifdef USE_OPENSSL
|
|
|
|
|
#ifdef DEFAULT_MAXSSLCONN
|
2012-09-06 05:58:37 -04:00
|
|
|
.maxsslconn = DEFAULT_MAXSSLCONN,
|
2012-10-05 09:47:31 -04:00
|
|
|
#endif
|
2012-09-06 05:58:37 -04:00
|
|
|
#endif
|
2006-06-25 20:48:02 -04:00
|
|
|
/* others NULL OK */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
|
|
|
|
int stopping; /* non zero means stopping in progress */
|
2010-08-31 09:39:26 -04:00
|
|
|
int jobs = 0; /* number of active jobs (conns, listeners, active tasks, ...) */
|
2006-06-25 20:48:02 -04:00
|
|
|
|
|
|
|
|
/* Here we store informations about the pids of the processes we may pause
|
|
|
|
|
* or kill. We will send them a signal every 10 ms until we can bind to all
|
|
|
|
|
* our ports. With 200 retries, that's about 2 seconds.
|
|
|
|
|
*/
|
|
|
|
|
#define MAX_START_RETRIES 200
|
|
|
|
|
static int *oldpids = NULL;
|
|
|
|
|
static int oldpids_sig; /* use USR1 or TERM */
|
|
|
|
|
|
|
|
|
|
/* this is used to drain data, and as a temporary buffer for sprintf()... */
|
2012-10-29 11:51:55 -04:00
|
|
|
struct chunk trash = { };
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2010-02-26 05:12:27 -05:00
|
|
|
/* this buffer is always the same size as standard buffers and is used for
|
|
|
|
|
* swapping data inside a buffer.
|
|
|
|
|
*/
|
|
|
|
|
char *swap_buffer = NULL;
|
|
|
|
|
|
2010-08-25 06:58:59 -04:00
|
|
|
int nb_oldpids = 0;
|
2006-06-25 20:48:02 -04:00
|
|
|
const int zero = 0;
|
|
|
|
|
const int one = 1;
|
2007-10-11 14:48:58 -04:00
|
|
|
const struct linger nolinger = { .l_onoff = 1, .l_linger = 0 };
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2010-03-12 15:58:54 -05:00
|
|
|
char hostname[MAX_HOSTNAME_LEN];
|
2010-09-23 12:30:22 -04:00
|
|
|
char localpeer[MAX_HOSTNAME_LEN];
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2013-12-13 09:14:55 -05:00
|
|
|
/* used from everywhere just to drain results we don't want to read and which
|
|
|
|
|
* recent versions of gcc increasingly and annoyingly complain about.
|
|
|
|
|
*/
|
|
|
|
|
int shut_your_big_mouth_gcc_int = 0;
|
|
|
|
|
|
2011-07-24 16:58:00 -04:00
|
|
|
/* list of the temporarily limited listeners because of lack of resource */
|
|
|
|
|
struct list global_listener_queue = LIST_HEAD_INIT(global_listener_queue);
|
2011-08-01 14:57:55 -04:00
|
|
|
struct task *global_listener_queue_task;
|
|
|
|
|
static struct task *manage_global_listener_queue(struct task *t);
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2014-04-28 16:27:06 -04:00
|
|
|
/* bitfield of a few warnings to emit just once (WARN_*) */
|
|
|
|
|
unsigned int warned = 0;
|
|
|
|
|
|
2006-06-25 20:48:02 -04:00
|
|
|
/*********************************************************************/
|
|
|
|
|
/* general purpose functions ***************************************/
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
|
|
|
|
void display_version()
|
|
|
|
|
{
|
|
|
|
|
printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
|
[RELEASE] Released version 1.6-dev1
Released version 1.6-dev1 with the following main changes :
- CLEANUP: extract temporary $CFG to eliminate duplication
- CLEANUP: extract temporary $BIN to eliminate duplication
- CLEANUP: extract temporary $PIDFILE to eliminate duplication
- CLEANUP: extract temporary $LOCKFILE to eliminate duplication
- CLEANUP: extract quiet_check() to avoid duplication
- BUG/MINOR: don't start haproxy on reload
- DOC: Address issue where documentation is excluded due to a gitignore rule.
- BUG/MEDIUM: systemd: set KillMode to 'mixed'
- BUILD: fix "make install" to support spaces in the install dirs
- BUG/MINOR: config: http-request replace-header arg typo
- BUG: config: error in http-response replace-header number of arguments
- DOC: missing track-sc* in http-request rules
- BUILD: lua: missing ifdef related to SSL when enabling LUA
- BUG/MEDIUM: regex: fix pcre_study error handling
- MEDIUM: regex: Use pcre_study always when PCRE is used, regardless of JIT
- BUG/MINOR: Fix search for -p argument in systemd wrapper.
- MEDIUM: Improve signal handling in systemd wrapper.
- DOC: fix typo in Unix Socket commands
- BUG/MEDIUM: checks: external checks can't change server status to UP
- BUG/MEDIUM: checks: segfault with external checks in a backend section
- BUG/MINOR: checks: external checks shouldn't wait for timeout to return the result
- BUG/MEDIUM: auth: fix segfault with http-auth and a configuration with an unknown encryption algorithm
- BUG/MEDIUM: config: userlists should ensure that encrypted passwords are supported
- BUG/MINOR: config: don't propagate process binding for dynamic use_backend
- BUG/MINOR: log: fix request flags when keep-alive is enabled
- BUG/MEDIUM: checks: fix conflicts between agent checks and ssl healthchecks
- MINOR: checks: allow external checks in backend sections
- MEDIUM: checks: provide environment variables to the external checks
- MINOR: checks: update dynamic environment variables in external checks
- DOC: checks: environment variables used by "external-check command"
- BUG/MEDIUM: backend: correctly detect the domain when use_domain_only is used
- MINOR: ssl: load certificates in alphabetical order
- BUG/MINOR: checks: prevent http keep-alive with http-check expect
- MINOR: lua: typo in an error message
- MINOR: report the Lua version in -vv
- MINOR: lua: add a compilation error message when compiled with an incompatible version
- BUG/MEDIUM: lua: segfault when calling haproxy sample fetches from lua
- BUILD: try to automatically detect the Lua library name
- BUILD/CLEANUP: systemd: avoid a warning due to mixed code and declaration
- BUG/MEDIUM: backend: Update hash to use unsigned int throughout
- BUG/MEDIUM: connection: fix memory corruption when building a proxy v2 header
- MEDIUM: connection: add new bit in Proxy Protocol V2
- BUG/MINOR: ssl: rejects OCSP response without nextupdate.
- BUG/MEDIUM: ssl: Fix to not serve expired OCSP responses.
- BUG/MINOR: ssl: Fix OCSP resp update fails with the same certificate configured twice.
- BUG/MINOR: ssl: Fix external function in order not to return a pointer on an internal trash buffer.
- MINOR: add fetchs 'ssl_c_der' and 'ssl_f_der' to return DER formatted certs
- MINOR: ssl: add statement to force some ssl options in global.
- BUG/MINOR: ssl: correctly initialize ssl ctx for invalid certificates
- BUG/MEDIUM: ssl: fix bad ssl context init can cause segfault in case of OOM.
- BUG/MINOR: samples: fix unnecessary memcopy converting binary to string.
- MINOR: samples: adds the bytes converter.
- MINOR: samples: adds the field converter.
- MINOR: samples: add the word converter.
- BUG/MINOR: server: move the directive #endif to the end of file
- BUG/MAJOR: buffer: check the space left is enough or not when input data in a buffer is wrapped
- DOC: fix a few typos
- CLEANUP: epoll: epoll_events should be allocated according to global.tune.maxpollevents
- BUG/MINOR: http: fix typo: "401 Unauthorized" => "407 Unauthorized"
- BUG/MINOR: parse: refer curproxy instead of proxy
- BUG/MINOR: parse: check the validity of size string in a more strict way
- BUILD: add new target 'make uninstall' to support uninstalling haproxy from OS
- DOC: expand the docs for the provided stats.
- BUG/MEDIUM: unix: do not unlink() abstract namespace sockets upon failure.
- MEDIUM: ssl: Certificate Transparency support
- MEDIUM: stats: proxied stats admin forms fix
- MEDIUM: http: Compress HTTP responses with status codes 201,202,203 in addition to 200
- BUG/MEDIUM: connection: sanitize PPv2 header length before parsing address information
- MAJOR: namespace: add Linux network namespace support
- MINOR: systemd: Check configuration before start
- BUILD: ssl: handle boringssl in openssl version detection
- BUILD: ssl: disable OCSP when using boringssl
- BUILD: ssl: don't call get_rfc2409_prime when using boringssl
- MINOR: ssl: don't use boringssl's cipher_list
- BUILD: ssl: use OPENSSL_NO_OCSP to detect OCSP support
- MINOR: stats: fix minor typo in HTML page
- MINOR: Also accept SIGHUP/SIGTERM in systemd-wrapper
- MEDIUM: Add support for configurable TLS ticket keys
- DOC: Document the new tls-ticket-keys bind keyword
- DOC: clearly state that the "show sess" output format is not fixed
- MINOR: stats: fix minor typo fix in stats_dump_errors_to_buffer()
- DOC: httplog does not support 'no'
- BUG/MEDIUM: ssl: Fix a memory leak in DHE key exchange
- MINOR: ssl: use SSL_get_ciphers() instead of directly accessing the cipher list.
- BUG/MEDIUM: Consistently use 'check' in process_chk
- MEDIUM: Add external check
- BUG/MEDIUM: Do not set agent health to zero if server is disabled in config
- MEDIUM/BUG: Only explicitly report "DOWN (agent)" if the agent health is zero
- MEDIUM: Remove connect_chk
- MEDIUM: Refactor init_check and move to checks.c
- MEDIUM: Add free_check() helper
- MEDIUM: Move proto and addr fields struct check
- MEDIUM: Attach tcpcheck_rules to check
- MEDIUM: Add parsing of mailers section
- MEDIUM: Allow configuration of email alerts
- MEDIUM: Support sending email alerts
- DOC: Document email alerts
- MINOR: Remove trailing '.' from email alert messages
- MEDIUM: Allow suppression of email alerts by log level
- BUG/MEDIUM: Do not consider an agent check as failed on L7 error
- MINOR: deinit: fix memory leak
- MINOR: http: export the function 'smp_fetch_base32'
- BUG/MEDIUM: http: tarpit timeout is reset
- MINOR: sample: add "json" converter
- BUG/MEDIUM: pattern: don't load more than once a pattern list.
- MINOR: map/acl/dumpstats: remove the "Done." message
- BUG/MAJOR: ns: HAProxy segfault if the cli_conn is not from a network connection
- BUG/MINOR: pattern: error message missing
- BUG/MEDIUM: pattern: some entries are not deleted with case insensitive match
- BUG/MINOR: ARG6 and ARG7 don't fit in a 32 bits word
- MAJOR: poll: only rely on wake_expired_tasks() to compute the wait delay
- MEDIUM: task: call session analyzers if the task is woken by a message.
- MEDIUM: protocol: automatically pick the proto associated to the connection.
- MEDIUM: channel: wake up any request analyzer on response activity
- MINOR: converters: add a "void *private" argument to converters
- MINOR: converters: give the session pointer as converter argument
- MINOR: sample: add private argument to the struct sample_fetch
- MINOR: global: export function and permits to not resolve DNS names
- MINOR: sample: add function for browsing samples.
- MINOR: global: export many symbols.
- MINOR: includes: fix a lot of missing or useless includes
- MEDIUM: tcp: add register keyword system.
- MEDIUM: buffer: make bo_putblk/bo_putstr/bo_putchk return the number of bytes copied.
- MEDIUM: http: change the code returned by the response processing rule functions
- MEDIUM: http/tcp: permit to resume http and tcp custom actions
- MINOR: channel: functions to get data from a buffer without copy
- MEDIUM: lua: lua integration in the build and init system.
- MINOR: lua: add ease functions
- MINOR: lua: add runtime execution context
- MEDIUM: lua: "com" signals
- MINOR: lua: add the configuration directive "lua-load"
- MINOR: lua: core: create "core" class and object
- MINOR: lua: post initialisation bindings
- MEDIUM: lua: add coroutine as tasks.
- MINOR: lua: add sample and args type converters
- MINOR: lua: txn: create class TXN associated with the transaction.
- MINOR: lua: add shared context in the lua stack
- MINOR: lua: txn: import existing sample-fetches in the class TXN
- MINOR: lua: txn: add lua function in TXN that returns an array of http headers
- MINOR: lua: register and execute sample-fetches in LUA
- MINOR: lua: register and execute converters in LUA
- MINOR: lua: add bindings for tcp and http actions
- MINOR: lua: core: add sleep functions
- MEDIUM: lua: socket: add "socket" class for TCP I/O
- MINOR: lua: core: pattern and acl manipulation
- MINOR: lua: channel: add "channel" class
- MINOR: lua: txn: object "txn" provides two objects "channel"
- MINOR: lua: core: can set the nice of the current task
- MINOR: lua: core: can yield an execution stack
- MINOR: lua: txn: add binding for closing the client connection.
- MEDIUM: lua: Lua initialisation "on demand"
- BUG/MAJOR: lua: send function fails and return bad bytes
- MINOR: remove unused declaration.
- MINOR: lua: remove some #define
- MINOR: lua: use bitfield and macro in place of integer and enum
- MINOR: lua: set skeleton for Lua execution expiration
- MEDIUM: lua: each yielding function returns a wake up time.
- MINOR: lua: adds "forced yield" flag
- MEDIUM: lua: interrupt the Lua execution for running other process
- MEDIUM: lua: change the sleep function core
- BUG/MEDIUM: lua: the execution timeout is ignored in yield case
- DOC: lua: Lua configuration documentation
- MINOR: lua: add the struct session in the lua channel struct
- BUG/MINOR: lua: set buffer if it is nnot avalaible.
- BUG/MEDIUM: lua: reset flags before resuming execution
- BUG/MEDIUM: lua: fix infinite loop about channel
- BUG/MEDIUM: lua: the Lua process is not waked up after sending data on requests side
- BUG/MEDIUM: lua: many errors when we try to send data with the channel API
- MEDIUM: lua: use the Lua-5.3 version of the library
- BUG/MAJOR: lua: some function are not yieldable, the forced yield causes errors
- BUG/MEDIUM: lua: can't handle the response bytes
- BUG/MEDIUM: lua: segfault with buffer_replace2
- BUG/MINOR: lua: check buffers before initializing socket
- BUG/MINOR: log: segfault if there are no proxy reference
- BUG/MEDIUM: lua: sockets don't have buffer to write data
- BUG/MEDIUM: lua: cannot connect socket
- BUG/MINOR: lua: sockets receive behavior doesn't follows the specs
- BUG/BUILD: lua: The strict Lua 5.3 version check is not done.
- BUG/MEDIUM: buffer: one byte miss in buffer free space check
- MEDIUM: lua: make the functions hlua_gethlua() and hlua_sethlua() faster
- MINOR: replace the Core object by a simple model.
- MEDIUM: lua: change the objects configuration
- MEDIUM: lua: create a namespace for the fetches
- MINOR: converters: add function to browse converters
- MINOR: lua: wrapper for converters
- MINOR: lua: replace function (req|get)_channel by a variable
- MINOR: lua: fetches and converters can return an empty string in place of nil
- DOC: lua api
- BUG/MEDIUM: sample: fix random number upper-bound
- BUG/MINOR: stats:Fix incorrect printf type.
- BUG/MAJOR: session: revert all the crappy client-side timeout changes
- BUG/MINOR: logs: properly initialize and count log sockets
- BUG/MEDIUM: http: fetch "base" is not compatible with set-header
- BUG/MINOR: counters: do not untrack counters before logging
- BUG/MAJOR: sample: correctly reinitialize sample fetch context before calling sample_process()
- MINOR: stick-table: make stktable_fetch_key() indicate why it failed
- BUG/MEDIUM: counters: fix track-sc* to wait on unstable contents
- BUILD: remove TODO from the spec file and add README
- MINOR: log: make MAX_SYSLOG_LEN overridable at build time
- MEDIUM: log: support a user-configurable max log line length
- DOC: provide an example of how to use ssl_c_sha1
- BUILD: checks: external checker needs signal.h
- BUILD: checks: kill a minor warning on Solaris in external checks
- BUILD: http: fix isdigit & isspace warnings on Solaris
- BUG/MINOR: listener: set the listener's fd to -1 after deletion
- BUG/MEDIUM: unix: failed abstract socket binding is retryable
- MEDIUM: listener: implement a per-protocol pause() function
- MEDIUM: listener: support rebinding during resume()
- BUG/MEDIUM: unix: completely unbind abstract sockets during a pause()
- DOC: explicitly mention the limits of abstract namespace sockets
- DOC: minor fix on {sc,src}_kbytes_{in,out}
- DOC: fix alphabetical sort of converters
- MEDIUM: stick-table: implement lookup from a sample fetch
- MEDIUM: stick-table: add new converters to fetch table data
- MINOR: samples: add two converters for the date format
- BUG/MAJOR: http: correctly rewind the request body after start of forwarding
- DOC: remove references to CPU=native in the README
- DOC: mention that "compression offload" is ignored in defaults section
- DOC: mention that Squid correctly responds 400 to PPv2 header
- BUILD: fix dependencies between config and compat.h
- MINOR: session: export the function 'smp_fetch_sc_stkctr'
- MEDIUM: stick-table: make it easier to register extra data types
- BUG/MINOR: http: base32+src should use the big endian version of base32
- MINOR: sample: allow IP address to cast to binary
- MINOR: sample: add new converters to hash input
- MINOR: sample: allow integers to cast to binary
- BUILD: report commit ID in git versions as well
- CLEANUP: session: move the stick counters declarations to stick_table.h
- MEDIUM: http: add the track-sc* actions to http-request rules
- BUG/MEDIUM: connection: fix proxy v2 header again!
- BUG/MAJOR: tcp: fix a possible busy spinning loop in content track-sc*
- OPTIM/MINOR: proxy: reduce struct proxy by 48 bytes on 64-bit archs
- MINOR: log: add a new field "%lc" to implement a per-frontend log counter
- BUG/MEDIUM: http: fix inverted condition in pat_match_meth()
- BUG/MEDIUM: http: fix improper parsing of HTTP methods for use with ACLs
- BUG/MINOR: pattern: remove useless allocation of unused trash in pat_parse_reg()
- BUG/MEDIUM: acl: correctly compute the output type when a converter is used
- CLEANUP: acl: cleanup some of the redundancy and spaghetti after last fix
- BUG/CRITICAL: http: don't update msg->sov once data start to leave the buffer
- MEDIUM: http: enable header manipulation for 101 responses
- BUG/MEDIUM: config: propagate frontend to backend process binding again.
- MEDIUM: config: properly propagate process binding between proxies
- MEDIUM: config: make the frontends automatically bind to the listeners' processes
- MEDIUM: config: compute the exact bind-process before listener's maxaccept
- MEDIUM: config: only warn if stats are attached to multi-process bind directives
- MEDIUM: config: report it when tcp-request rules are misplaced
- DOC: indicate in the doc that track-sc* can wait if data are missing
- MINOR: config: detect the case where a tcp-request content rule has no inspect-delay
- MEDIUM: systemd-wrapper: support multiple executable versions and names
- BUG/MEDIUM: remove debugging code from systemd-wrapper
- BUG/MEDIUM: http: adjust close mode when switching to backend
- BUG/MINOR: config: don't propagate process binding on fatal errors.
- BUG/MEDIUM: check: rule-less tcp-check must detect connect failures
- BUG/MINOR: tcp-check: report the correct failed step in the status
- DOC: indicate that weight zero is reported as DRAIN
- BUG/MEDIUM: config: avoid skipping disabled proxies
- BUG/MINOR: config: do not accept more track-sc than configured
- BUG/MEDIUM: backend: fix URI hash when a query string is present
- BUG/MEDIUM: http: don't dump debug headers on MSG_ERROR
- BUG/MAJOR: cli: explicitly call cli_release_handler() upon error
- BUG/MEDIUM: tcp: fix outgoing polling based on proxy protocol
- BUILD/MINOR: ssl: de-constify "ciphers" to avoid a warning on openssl-0.9.8
- BUG/MEDIUM: tcp: don't use SO_ORIGINAL_DST on non-AF_INET sockets
- BUG/BUILD: revert accidental change in the makefile from latest SSL fix
- BUG/MEDIUM: ssl: force a full GC in case of memory shortage
- MEDIUM: ssl: add support for smaller SSL records
- MINOR: session: release a few other pools when stopping
- MINOR: task: release the task pool when stopping
- BUG/MINOR: config: don't inherit the default balance algorithm in frontends
- BUG/MAJOR: frontend: initialize capture pointers earlier
- BUG/MINOR: stats: correctly set the request/response analysers
- MAJOR: polling: centralize calls to I/O callbacks
- DOC: fix typo in the body parser documentation for msg.sov
- BUG/MINOR: peers: the buffer size is global.tune.bufsize, not trash.size
- MINOR: sample: add a few basic internal fetches (nbproc, proc, stopping)
- DEBUG: pools: apply poisonning on every allocated pool
- BUG/MAJOR: sessions: unlink session from list on out of memory
- BUG/MEDIUM: patterns: previous fix was incomplete
- BUG/MEDIUM: payload: ensure that a request channel is available
- BUG/MINOR: tcp-check: don't condition data polling on check type
- BUG/MEDIUM: tcp-check: don't rely on random memory contents
- BUG/MEDIUM: tcp-checks: disable quick-ack unless next rule is an expect
- BUG/MINOR: config: fix typo in condition when propagating process binding
- BUG/MEDIUM: config: do not propagate processes between stopped processes
- BUG/MAJOR: stream-int: properly check the memory allocation return
- BUG/MEDIUM: memory: fix freeing logic in pool_gc2()
- BUG/MAJOR: namespaces: conn->target is not necessarily a server
- BUG/MEDIUM: compression: correctly report zlib_mem
- CLEANUP: lists: remove dead code
- CLEANUP: memory: remove dead code
- CLEANUP: memory: replace macros pool_alloc2/pool_free2 with functions
- MINOR: memory: cut pool allocator in 3 layers
- MEDIUM: memory: improve pool_refill_alloc() to pass a refill count
- MINOR: stream-int: retrieve session pointer from stream-int
- MINOR: buffer: reset a buffer in b_reset() and not channel_init()
- MEDIUM: buffer: use b_alloc() to allocate and initialize a buffer
- MINOR: buffer: move buffer initialization after channel initialization
- MINOR: buffer: only use b_free to release buffers
- MEDIUM: buffer: always assign a dummy empty buffer to channels
- MEDIUM: buffer: add a new buf_wanted dummy buffer to report failed allocations
- MEDIUM: channel: do not report full when buf_empty is present on a channel
- MINOR: session: group buffer allocations together
- MINOR: buffer: implement b_alloc_fast()
- MEDIUM: buffer: implement b_alloc_margin()
- MEDIUM: session: implement a basic atomic buffer allocator
- MAJOR: session: implement a wait-queue for sessions who need a buffer
- MAJOR: session: only allocate buffers when needed
- MINOR: stats: report a "waiting" flags for sessions
- MAJOR: session: only wake up as many sessions as available buffers permit
- MINOR: config: implement global setting tune.buffers.reserve
- MINOR: config: implement global setting tune.buffers.limit
- MEDIUM: channel: implement a zero-copy buffer transfer
- MEDIUM: stream-int: support splicing from applets
- OPTIM: stream-int: try to send pending spliced data
- CLEANUP: session: remove session_from_task()
- DOC: add missing entry for log-format and clarify the text
- MINOR: logs: add a new per-proxy "log-tag" directive
- BUG/MEDIUM: http: fix header removal when previous header ends with pure LF
- MINOR: config: extend the default max hostname length to 64 and beyond
- BUG/MEDIUM: channel: fix possible integer overflow on reserved size computation
- BUG/MINOR: channel: compare to_forward with buf->i, not buf->size
- MINOR: channel: add channel_in_transit()
- MEDIUM: channel: make buffer_reserved() use channel_in_transit()
- MEDIUM: channel: make bi_avail() use channel_in_transit()
- BUG/MEDIUM: channel: don't schedule data in transit for leaving until connected
- CLEANUP: channel: rename channel_reserved -> channel_is_rewritable
- MINOR: channel: rename channel_full() to !channel_may_recv()
- MINOR: channel: rename buffer_reserved() to channel_reserved()
- MINOR: channel: rename buffer_max_len() to channel_recv_limit()
- MINOR: channel: rename bi_avail() to channel_recv_max()
- MINOR: channel: rename bi_erase() to channel_truncate()
- BUG/MAJOR: log: don't try to emit a log if no logger is set
- MINOR: tools: add new round_2dig() function to round integers
- MINOR: global: always export some SSL-specific metrics
- MINOR: global: report information about the cost of SSL connections
- MAJOR: init: automatically set maxconn and/or maxsslconn when possible
- MINOR: http: add a new fetch "query" to extract the request's query string
- MINOR: hash: add new function hash_crc32
- MINOR: samples: provide a "crc32" converter
- MEDIUM: backend: add the crc32 hash algorithm for load balancing
- BUG/MINOR: args: add missing entry for ARGT_MAP in arg_type_names
- BUG/MEDIUM: http: make http-request set-header compute the string before removal
- MEDIUM: args: use #define to specify the number of bits used by arg types and counts
- MEDIUM: args: increase arg type to 5 bits and limit arg count to 5
- MINOR: args: add type-specific flags for each arg in a list
- MINOR: args: implement a new arg type for regex : ARGT_REG
- MEDIUM: regex: add support for passing regex flags to regex_exec_match()
- MEDIUM: samples: add a regsub converter to perform regex-based transformations
- BUG/MINOR: sample: fix case sensitivity for the regsub converter
- MEDIUM: http: implement http-request set-{method,path,query,uri}
- DOC: fix missing closing brackend on regsub
- MEDIUM: samples: provide basic arithmetic and bitwise operators
- MEDIUM: init: continue to enforce SYSTEM_MAXCONN with auto settings if set
- BUG/MINOR: http: fix incorrect header value offset in replace-hdr/replace-value
- BUG/MINOR: http: abort request processing on filter failure
- MEDIUM: tcp: implement tcp-ut bind option to set TCP_USER_TIMEOUT
- MINOR: ssl/server: add the "no-ssl-reuse" server option
- BUG/MAJOR: peers: initialize s->buffer_wait when creating the session
- MINOR: http: add a new function to iterate over each header line
- MINOR: http: add the new sample fetches req.hdr_names and res.hdr_names
- MEDIUM: task: always ensure that the run queue is consistent
- BUILD: Makefile: add -Wdeclaration-after-statement
- BUILD/CLEANUP: ssl: avoid a warning due to mixed code and declaration
- BUILD/CLEANUP: config: silent 3 warnings about mixed declarations with code
- MEDIUM: protocol: use a family array to index the protocol handlers
- BUILD: lua: cleanup many mixed occurrences declarations & code
- BUG/MEDIUM: task: fix recently introduced scheduler skew
- BUG/MINOR: lua: report the correct function name in an error message
- BUG/MAJOR: http: fix stats regression consecutive to HTTP_RULE_RES_YIELD
- Revert "BUG/MEDIUM: lua: can't handle the response bytes"
- MINOR: lua: convert IP addresses to type string
- CLEANUP: lua: use the same function names in C and Lua
- REORG/MAJOR: move session's req and resp channels back into the session
- CLEANUP: remove now unused channel pool
- REORG/MEDIUM: stream-int: introduce si_ic/si_oc to access channels
- MEDIUM: stream-int: add a flag indicating which side the SI is on
- MAJOR: stream-int: only rely on SI_FL_ISBACK to find the requested channel
- MEDIUM: stream-interface: remove now unused pointers to channels
- MEDIUM: stream-int: make si_sess() use the stream int's side
- MEDIUM: stream-int: use si_task() to retrieve the task from the stream int
- MEDIUM: stream-int: remove any reference to the owner
- CLEANUP: stream-int: add si_ib/si_ob to dereference the buffers
- CLEANUP: stream-int: add si_opposite() to find the other stream interface
- REORG/MEDIUM: channel: only use chn_prod / chn_cons to find stream-interfaces
- MEDIUM: channel: add a new flag "CF_ISRESP" for the response channel
- MAJOR: channel: only rely on the new CF_ISRESP flag to find the SI
- MEDIUM: channel: remove now unused ->prod and ->cons pointers
- CLEANUP: session: simplify references to chn_{prod,cons}(&s->{req,res})
- CLEANUP: session: use local variables to access channels / stream ints
- CLEANUP: session: don't needlessly pass a pointer to the stream-int
- CLEANUP: session: don't use si_{ic,oc} when we know the session.
- CLEANUP: stream-int: limit usage of si_ic/si_oc
- CLEANUP: lua: limit usage of si_ic/si_oc
- MINOR: channel: add chn_sess() helper to retrieve session from channel
- MEDIUM: session: simplify receive buffer allocator to only use the channel
- MEDIUM: lua: use CF_ISRESP to detect the channel's side
- CLEANUP: lua: remove the session pointer from hlua_channel
- CLEANUP: lua: hlua_channel_new() doesn't need the pointer to the session anymore
- MEDIUM: lua: remove struct hlua_channel
- MEDIUM: lua: remove hlua_sample_fetch
2015-03-11 18:57:23 -04:00
|
|
|
printf("Copyright 2000-2015 Willy Tarreau <w@1wt.eu>\n\n");
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
|
|
|
|
|
2007-12-02 05:28:59 -05:00
|
|
|
void display_build_opts()
|
|
|
|
|
{
|
|
|
|
|
printf("Build options :"
|
|
|
|
|
#ifdef BUILD_TARGET
|
2008-01-02 14:48:34 -05:00
|
|
|
"\n TARGET = " BUILD_TARGET
|
2007-12-02 05:28:59 -05:00
|
|
|
#endif
|
|
|
|
|
#ifdef BUILD_CPU
|
2008-01-02 14:48:34 -05:00
|
|
|
"\n CPU = " BUILD_CPU
|
2007-12-02 05:28:59 -05:00
|
|
|
#endif
|
|
|
|
|
#ifdef BUILD_CC
|
2008-01-02 14:48:34 -05:00
|
|
|
"\n CC = " BUILD_CC
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef BUILD_CFLAGS
|
|
|
|
|
"\n CFLAGS = " BUILD_CFLAGS
|
2007-12-02 05:28:59 -05:00
|
|
|
#endif
|
2008-01-02 14:48:34 -05:00
|
|
|
#ifdef BUILD_OPTIONS
|
|
|
|
|
"\n OPTIONS = " BUILD_OPTIONS
|
2007-12-02 05:28:59 -05:00
|
|
|
#endif
|
2009-08-17 01:23:33 -04:00
|
|
|
"\n\nDefault settings :"
|
|
|
|
|
"\n maxconn = %d, bufsize = %d, maxrewrite = %d, maxpollevents = %d"
|
|
|
|
|
"\n\n",
|
|
|
|
|
DEFAULT_MAXCONN, BUFSIZE, MAXREWRITE, MAX_POLL_EVENTS);
|
2009-10-03 12:57:08 -04:00
|
|
|
|
2010-01-29 11:50:44 -05:00
|
|
|
printf("Encrypted password support via crypt(3): "
|
|
|
|
|
#ifdef CONFIG_HAP_CRYPT
|
|
|
|
|
"yes"
|
|
|
|
|
#else
|
|
|
|
|
"no"
|
|
|
|
|
#endif
|
|
|
|
|
"\n");
|
|
|
|
|
|
2012-11-10 13:27:47 -05:00
|
|
|
#ifdef USE_ZLIB
|
|
|
|
|
printf("Built with zlib version : " ZLIB_VERSION "\n");
|
|
|
|
|
#else /* USE_ZLIB */
|
|
|
|
|
printf("Built without zlib support (USE_ZLIB not set)\n");
|
|
|
|
|
#endif
|
|
|
|
|
printf("Compression algorithms supported :");
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
2015-03-28 11:40:46 -04:00
|
|
|
for (i = 0; comp_algos[i].cfg_name; i++) {
|
|
|
|
|
printf("%s %s(\"%s\")", (i == 0 ? "" : ","), comp_algos[i].cfg_name, comp_algos[i].ua_name);
|
2012-11-10 13:27:47 -05:00
|
|
|
}
|
|
|
|
|
if (i == 0) {
|
|
|
|
|
printf("none");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
printf("\n");
|
|
|
|
|
|
2012-09-10 01:16:05 -04:00
|
|
|
#ifdef USE_OPENSSL
|
2014-08-17 18:56:30 -04:00
|
|
|
printf("Built with OpenSSL version : "
|
|
|
|
|
#ifdef OPENSSL_IS_BORINGSSL
|
|
|
|
|
"BoringSSL\n");
|
|
|
|
|
#else /* OPENSSL_IS_BORINGSSL */
|
|
|
|
|
OPENSSL_VERSION_TEXT "\n");
|
2013-04-26 12:16:13 -04:00
|
|
|
printf("Running on OpenSSL version : %s%s\n",
|
|
|
|
|
SSLeay_version(SSLEAY_VERSION),
|
|
|
|
|
((OPENSSL_VERSION_NUMBER ^ SSLeay()) >> 8) ? " (VERSIONS DIFFER!)" : "");
|
2014-08-17 18:56:30 -04:00
|
|
|
#endif
|
2012-09-10 01:16:05 -04:00
|
|
|
printf("OpenSSL library supports TLS extensions : "
|
|
|
|
|
#if OPENSSL_VERSION_NUMBER < 0x00907000L
|
|
|
|
|
"no (library version too old)"
|
|
|
|
|
#elif defined(OPENSSL_NO_TLSEXT)
|
|
|
|
|
"no (disabled via OPENSSL_NO_TLSEXT)"
|
|
|
|
|
#else
|
|
|
|
|
"yes"
|
|
|
|
|
#endif
|
|
|
|
|
"\n");
|
|
|
|
|
printf("OpenSSL library supports SNI : "
|
|
|
|
|
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
|
|
|
|
"yes"
|
|
|
|
|
#else
|
|
|
|
|
#ifdef OPENSSL_NO_TLSEXT
|
|
|
|
|
"no (because of OPENSSL_NO_TLSEXT)"
|
|
|
|
|
#else
|
|
|
|
|
"no (version might be too old, 0.9.8f min needed)"
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
"\n");
|
|
|
|
|
printf("OpenSSL library supports prefer-server-ciphers : "
|
|
|
|
|
#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
|
|
|
|
|
"yes"
|
|
|
|
|
#else
|
|
|
|
|
"no (0.9.7 or later needed)"
|
|
|
|
|
#endif
|
|
|
|
|
"\n");
|
|
|
|
|
#else /* USE_OPENSSL */
|
|
|
|
|
printf("Built without OpenSSL support (USE_OPENSSL not set)\n");
|
|
|
|
|
#endif
|
2013-04-04 06:24:16 -04:00
|
|
|
|
|
|
|
|
#ifdef USE_PCRE
|
|
|
|
|
printf("Built with PCRE version : %s", pcre_version());
|
2013-04-14 18:41:40 -04:00
|
|
|
printf("\nPCRE library supports JIT : ");
|
|
|
|
|
#ifdef USE_PCRE_JIT
|
|
|
|
|
{
|
|
|
|
|
int r;
|
|
|
|
|
pcre_config(PCRE_CONFIG_JIT, &r);
|
|
|
|
|
if (r)
|
|
|
|
|
printf("yes");
|
|
|
|
|
else
|
|
|
|
|
printf("no (libpcre build without JIT?)");
|
|
|
|
|
}
|
2013-04-04 06:24:16 -04:00
|
|
|
#else
|
2013-04-14 18:41:40 -04:00
|
|
|
printf("no (USE_PCRE_JIT not set)");
|
2013-04-04 06:24:16 -04:00
|
|
|
#endif
|
2013-04-14 18:41:40 -04:00
|
|
|
printf("\n");
|
2013-04-04 06:24:16 -04:00
|
|
|
#else
|
|
|
|
|
printf("Built without PCRE support (using libc's regex instead)\n");
|
|
|
|
|
#endif
|
|
|
|
|
|
2015-03-01 18:08:39 -05:00
|
|
|
#ifdef USE_LUA
|
|
|
|
|
printf("Built with Lua version : %s\n", LUA_RELEASE);
|
|
|
|
|
#else
|
|
|
|
|
printf("Built without Lua support\n");
|
|
|
|
|
#endif
|
|
|
|
|
|
2013-05-08 16:49:23 -04:00
|
|
|
#if defined(CONFIG_HAP_TRANSPARENT) || defined(CONFIG_HAP_CTTPROXY)
|
|
|
|
|
printf("Built with transparent proxy support using:"
|
|
|
|
|
#if defined(CONFIG_HAP_CTTPROXY)
|
|
|
|
|
" CTTPROXY"
|
|
|
|
|
#endif
|
|
|
|
|
#if defined(IP_TRANSPARENT)
|
|
|
|
|
" IP_TRANSPARENT"
|
|
|
|
|
#endif
|
|
|
|
|
#if defined(IPV6_TRANSPARENT)
|
|
|
|
|
" IPV6_TRANSPARENT"
|
|
|
|
|
#endif
|
|
|
|
|
#if defined(IP_FREEBIND)
|
|
|
|
|
" IP_FREEBIND"
|
2013-05-08 17:22:39 -04:00
|
|
|
#endif
|
|
|
|
|
#if defined(IP_BINDANY)
|
|
|
|
|
" IP_BINDANY"
|
|
|
|
|
#endif
|
|
|
|
|
#if defined(IPV6_BINDANY)
|
|
|
|
|
" IPV6_BINDANY"
|
2013-05-08 17:30:23 -04:00
|
|
|
#endif
|
|
|
|
|
#if defined(SO_BINDANY)
|
|
|
|
|
" SO_BINDANY"
|
2013-05-08 16:49:23 -04:00
|
|
|
#endif
|
|
|
|
|
"\n");
|
|
|
|
|
#endif
|
2014-11-17 09:11:45 -05:00
|
|
|
|
|
|
|
|
#if defined(CONFIG_HAP_NS)
|
|
|
|
|
printf("Built with network namespace support\n");
|
|
|
|
|
#endif
|
2010-01-29 11:50:44 -05:00
|
|
|
putchar('\n');
|
|
|
|
|
|
2009-10-03 12:57:08 -04:00
|
|
|
list_pollers(stdout);
|
|
|
|
|
putchar('\n');
|
2007-12-02 05:28:59 -05:00
|
|
|
}
|
|
|
|
|
|
2006-06-25 20:48:02 -04:00
|
|
|
/*
|
|
|
|
|
* This function prints the command line usage and exits
|
|
|
|
|
*/
|
|
|
|
|
void usage(char *name)
|
|
|
|
|
{
|
|
|
|
|
display_version();
|
|
|
|
|
fprintf(stderr,
|
2009-06-22 10:02:30 -04:00
|
|
|
"Usage : %s [-f <cfgfile>]* [ -vdV"
|
2006-06-25 20:48:02 -04:00
|
|
|
"D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
|
2011-09-10 13:26:56 -04:00
|
|
|
" [ -p <pidfile> ] [ -m <max megs> ] [ -C <dir> ]\n"
|
2007-12-02 05:28:59 -05:00
|
|
|
" -v displays version ; -vv shows known build options.\n"
|
2006-06-25 20:48:02 -04:00
|
|
|
" -d enters debug mode ; -db only disables background mode.\n"
|
2012-05-08 09:40:42 -04:00
|
|
|
" -dM[<byte>] poisons memory with <byte> (defaults to 0x50)\n"
|
2006-06-25 20:48:02 -04:00
|
|
|
" -V enters verbose mode (disables quiet mode)\n"
|
2011-09-10 13:26:56 -04:00
|
|
|
" -D goes daemon ; -C changes to <dir> before loading files.\n"
|
2006-06-25 20:48:02 -04:00
|
|
|
" -q quiet mode : don't display messages\n"
|
2009-06-22 10:02:30 -04:00
|
|
|
" -c check mode : only check config files and exit\n"
|
2006-06-25 20:48:02 -04:00
|
|
|
" -n sets the maximum total # of connections (%d)\n"
|
|
|
|
|
" -m limits the usable amount of memory (in MB)\n"
|
|
|
|
|
" -N sets the default, per-proxy maximum # of connections (%d)\n"
|
2010-09-23 12:30:22 -04:00
|
|
|
" -L set local peer name (default to hostname)\n"
|
2006-06-25 20:48:02 -04:00
|
|
|
" -p writes pids of all children to this file\n"
|
|
|
|
|
#if defined(ENABLE_EPOLL)
|
|
|
|
|
" -de disables epoll() usage even when available\n"
|
|
|
|
|
#endif
|
2007-04-09 06:03:06 -04:00
|
|
|
#if defined(ENABLE_KQUEUE)
|
|
|
|
|
" -dk disables kqueue() usage even when available\n"
|
|
|
|
|
#endif
|
2006-06-25 20:48:02 -04:00
|
|
|
#if defined(ENABLE_POLL)
|
|
|
|
|
" -dp disables poll() usage even when available\n"
|
2009-01-25 10:03:28 -05:00
|
|
|
#endif
|
2009-08-16 07:20:32 -04:00
|
|
|
#if defined(CONFIG_HAP_LINUX_SPLICE)
|
2009-01-25 10:03:28 -05:00
|
|
|
" -dS disables splice usage (broken on old kernels)\n"
|
2014-04-14 09:56:58 -04:00
|
|
|
#endif
|
|
|
|
|
#if defined(USE_GETADDRINFO)
|
|
|
|
|
" -dG disables getaddrinfo() usage\n"
|
2006-06-25 20:48:02 -04:00
|
|
|
#endif
|
2014-01-29 06:24:34 -05:00
|
|
|
" -dV disables SSL verify on servers side\n"
|
2006-06-25 20:48:02 -04:00
|
|
|
" -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
|
|
|
|
|
"\n",
|
|
|
|
|
name, DEFAULT_MAXCONN, cfg_maxpconn);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
/* more specific functions ***************************************/
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
|
|
|
|
/*
|
2010-08-27 12:26:11 -04:00
|
|
|
* upon SIGUSR1, let's have a soft stop. Note that soft_stop() broadcasts
|
|
|
|
|
* a signal zero to all subscribers. This means that it's as easy as
|
|
|
|
|
* subscribing to signal 0 to get informed about an imminent shutdown.
|
2006-06-25 20:48:02 -04:00
|
|
|
*/
|
2010-08-27 11:56:48 -04:00
|
|
|
void sig_soft_stop(struct sig_handler *sh)
|
2006-06-25 20:48:02 -04:00
|
|
|
{
|
|
|
|
|
soft_stop();
|
2010-08-27 11:56:48 -04:00
|
|
|
signal_unregister_handler(sh);
|
2007-05-13 18:39:29 -04:00
|
|
|
pool_gc2();
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* upon SIGTTOU, we pause everything
|
|
|
|
|
*/
|
2010-08-27 11:56:48 -04:00
|
|
|
void sig_pause(struct sig_handler *sh)
|
2006-06-25 20:48:02 -04:00
|
|
|
{
|
|
|
|
|
pause_proxies();
|
2007-05-13 18:39:29 -04:00
|
|
|
pool_gc2();
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* upon SIGTTIN, let's have a soft stop.
|
|
|
|
|
*/
|
2010-08-27 11:56:48 -04:00
|
|
|
void sig_listen(struct sig_handler *sh)
|
2006-06-25 20:48:02 -04:00
|
|
|
{
|
2011-07-24 12:28:10 -04:00
|
|
|
resume_proxies();
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* this function dumps every server's state when the process receives SIGHUP.
|
|
|
|
|
*/
|
2010-08-27 11:56:48 -04:00
|
|
|
void sig_dump_state(struct sig_handler *sh)
|
2006-06-25 20:48:02 -04:00
|
|
|
{
|
|
|
|
|
struct proxy *p = proxy;
|
|
|
|
|
|
|
|
|
|
Warning("SIGHUP received, dumping servers states.\n");
|
|
|
|
|
while (p) {
|
|
|
|
|
struct server *s = p->srv;
|
|
|
|
|
|
|
|
|
|
send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
|
|
|
|
|
while (s) {
|
2012-10-29 11:51:55 -04:00
|
|
|
chunk_printf(&trash,
|
|
|
|
|
"SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %lld tot.",
|
|
|
|
|
p->id, s->id,
|
2014-05-13 17:41:20 -04:00
|
|
|
(s->state != SRV_ST_STOPPED) ? "UP" : "DOWN",
|
2012-10-29 11:51:55 -04:00
|
|
|
s->cur_sess, s->nbpend, s->counters.cum_sess);
|
|
|
|
|
Warning("%s\n", trash.str);
|
|
|
|
|
send_log(p, LOG_NOTICE, "%s\n", trash.str);
|
2006-06-25 20:48:02 -04:00
|
|
|
s = s->next;
|
|
|
|
|
}
|
|
|
|
|
|
2007-09-17 05:27:09 -04:00
|
|
|
/* FIXME: those info are a bit outdated. We should be able to distinguish between FE and BE. */
|
|
|
|
|
if (!p->srv) {
|
2012-10-29 11:51:55 -04:00
|
|
|
chunk_printf(&trash,
|
|
|
|
|
"SIGHUP: Proxy %s has no servers. Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
|
|
|
|
|
p->id,
|
|
|
|
|
p->feconn, p->beconn, p->totpend, p->nbpend, p->fe_counters.cum_conn, p->be_counters.cum_conn);
|
2007-09-17 05:27:09 -04:00
|
|
|
} else if (p->srv_act == 0) {
|
2012-10-29 11:51:55 -04:00
|
|
|
chunk_printf(&trash,
|
|
|
|
|
"SIGHUP: Proxy %s %s ! Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
|
|
|
|
|
p->id,
|
|
|
|
|
(p->srv_bck) ? "is running on backup servers" : "has no server available",
|
|
|
|
|
p->feconn, p->beconn, p->totpend, p->nbpend, p->fe_counters.cum_conn, p->be_counters.cum_conn);
|
2006-06-25 20:48:02 -04:00
|
|
|
} else {
|
2012-10-29 11:51:55 -04:00
|
|
|
chunk_printf(&trash,
|
|
|
|
|
"SIGHUP: Proxy %s has %d active servers and %d backup servers available."
|
|
|
|
|
" Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
|
|
|
|
|
p->id, p->srv_act, p->srv_bck,
|
|
|
|
|
p->feconn, p->beconn, p->totpend, p->nbpend, p->fe_counters.cum_conn, p->be_counters.cum_conn);
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
2012-10-29 11:51:55 -04:00
|
|
|
Warning("%s\n", trash.str);
|
|
|
|
|
send_log(p, LOG_NOTICE, "%s\n", trash.str);
|
2006-06-25 20:48:02 -04:00
|
|
|
|
|
|
|
|
p = p->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-27 11:56:48 -04:00
|
|
|
void dump(struct sig_handler *sh)
|
2006-06-25 20:48:02 -04:00
|
|
|
{
|
2007-05-13 13:43:47 -04:00
|
|
|
/* dump memory usage then free everything possible */
|
|
|
|
|
dump_pools();
|
|
|
|
|
pool_gc2();
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This function initializes all the necessary variables. It only returns
|
|
|
|
|
* if everything is OK. If something fails, it exits.
|
|
|
|
|
*/
|
|
|
|
|
void init(int argc, char **argv)
|
|
|
|
|
{
|
|
|
|
|
int arg_mode = 0; /* MODE_DEBUG, ... */
|
|
|
|
|
char *tmp;
|
|
|
|
|
char *cfg_pidfile = NULL;
|
2009-07-20 03:30:05 -04:00
|
|
|
int err_code = 0;
|
2010-01-03 15:12:30 -05:00
|
|
|
struct wordlist *wl;
|
2010-12-22 11:08:21 -05:00
|
|
|
char *progname;
|
2011-09-10 13:26:56 -04:00
|
|
|
char *change_dir = NULL;
|
2012-10-18 22:36:09 -04:00
|
|
|
struct tm curtime;
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2012-10-29 11:51:55 -04:00
|
|
|
chunk_init(&trash, malloc(global.tune.bufsize), global.tune.bufsize);
|
2013-12-13 08:41:10 -05:00
|
|
|
alloc_trash_buffers(global.tune.bufsize);
|
2012-05-16 08:16:48 -04:00
|
|
|
|
2010-09-23 12:30:22 -04:00
|
|
|
/* NB: POSIX does not make it mandatory for gethostname() to NULL-terminate
|
|
|
|
|
* the string in case of truncation, and at least FreeBSD appears not to do
|
|
|
|
|
* it.
|
|
|
|
|
*/
|
|
|
|
|
memset(hostname, 0, sizeof(hostname));
|
|
|
|
|
gethostname(hostname, sizeof(hostname) - 1);
|
|
|
|
|
memset(localpeer, 0, sizeof(localpeer));
|
|
|
|
|
memcpy(localpeer, hostname, (sizeof(hostname) > sizeof(localpeer) ? sizeof(localpeer) : sizeof(hostname)) - 1);
|
|
|
|
|
|
2006-06-25 20:48:02 -04:00
|
|
|
/*
|
|
|
|
|
* Initialize the previously static variables.
|
|
|
|
|
*/
|
|
|
|
|
|
2009-01-25 07:56:13 -05:00
|
|
|
totalconn = actconn = maxfd = listeners = stopping = 0;
|
2006-06-25 20:48:02 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef HAPROXY_MEMMAX
|
|
|
|
|
global.rlimit_memmax = HAPROXY_MEMMAX;
|
|
|
|
|
#endif
|
|
|
|
|
|
2008-06-23 08:00:57 -04:00
|
|
|
tv_update_date(-1,-1);
|
2006-06-25 20:48:02 -04:00
|
|
|
start_date = now;
|
|
|
|
|
|
2014-02-14 05:59:04 -05:00
|
|
|
srandom(now_ms - getpid());
|
|
|
|
|
|
2012-10-18 22:36:09 -04:00
|
|
|
/* Get the numeric timezone. */
|
|
|
|
|
get_localtime(start_date.tv_sec, &curtime);
|
|
|
|
|
strftime(localtimezone, 6, "%z", &curtime);
|
|
|
|
|
|
2009-05-10 03:01:21 -04:00
|
|
|
signal_init();
|
2013-01-11 09:49:37 -05:00
|
|
|
if (init_acl() != 0)
|
|
|
|
|
exit(1);
|
2007-05-13 13:43:47 -04:00
|
|
|
init_task();
|
REORG/MAJOR: session: rename the "session" entity to "stream"
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.
In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.
The files stream.{c,h} were added and session.{c,h} removed.
The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.
Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.
Once all changes are completed, we should see approximately this :
L7 - http_txn
L6 - stream
L5 - session
L4 - connection | applet
There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.
Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
2015-04-02 18:22:06 -04:00
|
|
|
init_stream();
|
2015-04-03 07:53:24 -04:00
|
|
|
init_session();
|
2012-10-26 14:10:28 -04:00
|
|
|
init_connection();
|
2009-09-23 17:37:52 -04:00
|
|
|
/* warning, we init buffers later */
|
2007-05-13 14:19:55 -04:00
|
|
|
init_pendconn();
|
2006-12-24 11:47:20 -05:00
|
|
|
init_proto_http();
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2015-01-23 08:06:13 -05:00
|
|
|
/* Initialise lua. */
|
|
|
|
|
hlua_init();
|
|
|
|
|
|
2009-01-25 09:42:27 -05:00
|
|
|
global.tune.options |= GTUNE_USE_SELECT; /* select() is always available */
|
2006-06-25 20:48:02 -04:00
|
|
|
#if defined(ENABLE_POLL)
|
2009-01-25 09:42:27 -05:00
|
|
|
global.tune.options |= GTUNE_USE_POLL;
|
2006-06-25 20:48:02 -04:00
|
|
|
#endif
|
|
|
|
|
#if defined(ENABLE_EPOLL)
|
2009-01-25 09:42:27 -05:00
|
|
|
global.tune.options |= GTUNE_USE_EPOLL;
|
2006-06-25 20:48:02 -04:00
|
|
|
#endif
|
2007-04-09 06:03:06 -04:00
|
|
|
#if defined(ENABLE_KQUEUE)
|
2009-01-25 09:42:27 -05:00
|
|
|
global.tune.options |= GTUNE_USE_KQUEUE;
|
2007-04-09 06:03:06 -04:00
|
|
|
#endif
|
2009-08-16 07:20:32 -04:00
|
|
|
#if defined(CONFIG_HAP_LINUX_SPLICE)
|
2009-01-25 10:03:28 -05:00
|
|
|
global.tune.options |= GTUNE_USE_SPLICE;
|
|
|
|
|
#endif
|
2014-04-14 09:56:58 -04:00
|
|
|
#if defined(USE_GETADDRINFO)
|
|
|
|
|
global.tune.options |= GTUNE_USE_GAI;
|
|
|
|
|
#endif
|
2006-06-25 20:48:02 -04:00
|
|
|
|
|
|
|
|
pid = getpid();
|
|
|
|
|
progname = *argv;
|
|
|
|
|
while ((tmp = strchr(progname, '/')) != NULL)
|
|
|
|
|
progname = tmp + 1;
|
|
|
|
|
|
2010-12-22 11:08:21 -05:00
|
|
|
/* the process name is used for the logs only */
|
|
|
|
|
global.log_tag = strdup(progname);
|
|
|
|
|
|
2006-06-25 20:48:02 -04:00
|
|
|
argc--; argv++;
|
|
|
|
|
while (argc > 0) {
|
|
|
|
|
char *flag;
|
|
|
|
|
|
|
|
|
|
if (**argv == '-') {
|
|
|
|
|
flag = *argv+1;
|
|
|
|
|
|
|
|
|
|
/* 1 arg */
|
|
|
|
|
if (*flag == 'v') {
|
|
|
|
|
display_version();
|
2007-12-02 05:28:59 -05:00
|
|
|
if (flag[1] == 'v') /* -vv */
|
|
|
|
|
display_build_opts();
|
2006-06-25 20:48:02 -04:00
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
#if defined(ENABLE_EPOLL)
|
|
|
|
|
else if (*flag == 'd' && flag[1] == 'e')
|
2009-01-25 09:42:27 -05:00
|
|
|
global.tune.options &= ~GTUNE_USE_EPOLL;
|
2006-06-25 20:48:02 -04:00
|
|
|
#endif
|
|
|
|
|
#if defined(ENABLE_POLL)
|
|
|
|
|
else if (*flag == 'd' && flag[1] == 'p')
|
2009-01-25 09:42:27 -05:00
|
|
|
global.tune.options &= ~GTUNE_USE_POLL;
|
2007-04-09 06:03:06 -04:00
|
|
|
#endif
|
2007-04-10 16:45:11 -04:00
|
|
|
#if defined(ENABLE_KQUEUE)
|
2007-04-09 06:03:06 -04:00
|
|
|
else if (*flag == 'd' && flag[1] == 'k')
|
2009-01-25 09:42:27 -05:00
|
|
|
global.tune.options &= ~GTUNE_USE_KQUEUE;
|
2009-01-25 10:03:28 -05:00
|
|
|
#endif
|
2009-08-16 07:20:32 -04:00
|
|
|
#if defined(CONFIG_HAP_LINUX_SPLICE)
|
2009-01-25 10:03:28 -05:00
|
|
|
else if (*flag == 'd' && flag[1] == 'S')
|
|
|
|
|
global.tune.options &= ~GTUNE_USE_SPLICE;
|
2014-04-14 09:56:58 -04:00
|
|
|
#endif
|
|
|
|
|
#if defined(USE_GETADDRINFO)
|
|
|
|
|
else if (*flag == 'd' && flag[1] == 'G')
|
|
|
|
|
global.tune.options &= ~GTUNE_USE_GAI;
|
2006-06-25 20:48:02 -04:00
|
|
|
#endif
|
2014-01-29 06:24:34 -05:00
|
|
|
else if (*flag == 'd' && flag[1] == 'V')
|
|
|
|
|
global.ssl_server_verify = SSL_SERVER_VERIFY_NONE;
|
2006-06-25 20:48:02 -04:00
|
|
|
else if (*flag == 'V')
|
|
|
|
|
arg_mode |= MODE_VERBOSE;
|
|
|
|
|
else if (*flag == 'd' && flag[1] == 'b')
|
|
|
|
|
arg_mode |= MODE_FOREGROUND;
|
2012-05-08 09:40:42 -04:00
|
|
|
else if (*flag == 'd' && flag[1] == 'M')
|
|
|
|
|
mem_poison_byte = flag[2] ? strtol(flag + 2, NULL, 0) : 'P';
|
2006-06-25 20:48:02 -04:00
|
|
|
else if (*flag == 'd')
|
|
|
|
|
arg_mode |= MODE_DEBUG;
|
|
|
|
|
else if (*flag == 'c')
|
|
|
|
|
arg_mode |= MODE_CHECK;
|
2013-02-12 04:53:52 -05:00
|
|
|
else if (*flag == 'D') {
|
2009-05-18 10:29:51 -04:00
|
|
|
arg_mode |= MODE_DAEMON;
|
2013-02-12 04:53:52 -05:00
|
|
|
if (flag[1] == 's') /* -Ds */
|
|
|
|
|
arg_mode |= MODE_SYSTEMD;
|
|
|
|
|
}
|
2006-06-25 20:48:02 -04:00
|
|
|
else if (*flag == 'q')
|
|
|
|
|
arg_mode |= MODE_QUIET;
|
|
|
|
|
else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
|
|
|
|
|
/* list of pids to finish ('f') or terminate ('t') */
|
|
|
|
|
|
|
|
|
|
if (flag[1] == 'f')
|
|
|
|
|
oldpids_sig = SIGUSR1; /* finish then exit */
|
|
|
|
|
else
|
|
|
|
|
oldpids_sig = SIGTERM; /* terminate immediately */
|
|
|
|
|
argv++; argc--;
|
|
|
|
|
|
|
|
|
|
if (argc > 0) {
|
|
|
|
|
oldpids = calloc(argc, sizeof(int));
|
|
|
|
|
while (argc > 0) {
|
|
|
|
|
oldpids[nb_oldpids] = atol(*argv);
|
|
|
|
|
if (oldpids[nb_oldpids] <= 0)
|
2011-09-10 13:20:23 -04:00
|
|
|
usage(progname);
|
2006-06-25 20:48:02 -04:00
|
|
|
argc--; argv++;
|
|
|
|
|
nb_oldpids++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else { /* >=2 args */
|
|
|
|
|
argv++; argc--;
|
|
|
|
|
if (argc == 0)
|
2011-09-10 13:20:23 -04:00
|
|
|
usage(progname);
|
2006-06-25 20:48:02 -04:00
|
|
|
|
|
|
|
|
switch (*flag) {
|
2011-09-10 13:26:56 -04:00
|
|
|
case 'C' : change_dir = *argv; break;
|
2006-06-25 20:48:02 -04:00
|
|
|
case 'n' : cfg_maxconn = atol(*argv); break;
|
|
|
|
|
case 'm' : global.rlimit_memmax = atol(*argv); break;
|
|
|
|
|
case 'N' : cfg_maxpconn = atol(*argv); break;
|
2010-09-23 12:30:22 -04:00
|
|
|
case 'L' : strncpy(localpeer, *argv, sizeof(localpeer) - 1); break;
|
2009-06-22 10:02:30 -04:00
|
|
|
case 'f' :
|
2010-01-03 15:12:30 -05:00
|
|
|
wl = (struct wordlist *)calloc(1, sizeof(*wl));
|
|
|
|
|
if (!wl) {
|
|
|
|
|
Alert("Cannot load configuration file %s : out of memory.\n", *argv);
|
2009-06-22 10:02:30 -04:00
|
|
|
exit(1);
|
|
|
|
|
}
|
2010-01-03 15:12:30 -05:00
|
|
|
wl->s = *argv;
|
|
|
|
|
LIST_ADDQ(&cfg_cfgfiles, &wl->list);
|
2009-06-22 10:02:30 -04:00
|
|
|
break;
|
2006-06-25 20:48:02 -04:00
|
|
|
case 'p' : cfg_pidfile = *argv; break;
|
2011-09-10 13:20:23 -04:00
|
|
|
default: usage(progname);
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2011-09-10 13:20:23 -04:00
|
|
|
usage(progname);
|
2006-06-25 20:48:02 -04:00
|
|
|
argv++; argc--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
|
2013-02-12 04:53:52 -05:00
|
|
|
(arg_mode & (MODE_DAEMON | MODE_SYSTEMD | MODE_FOREGROUND | MODE_VERBOSE
|
2006-06-25 20:48:02 -04:00
|
|
|
| MODE_QUIET | MODE_CHECK | MODE_DEBUG));
|
|
|
|
|
|
2010-01-03 15:12:30 -05:00
|
|
|
if (LIST_ISEMPTY(&cfg_cfgfiles))
|
2011-09-10 13:20:23 -04:00
|
|
|
usage(progname);
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2011-09-10 13:26:56 -04:00
|
|
|
if (change_dir && chdir(change_dir) < 0) {
|
|
|
|
|
Alert("Could not change to directory %s : %s\n", change_dir, strerror(errno));
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
2006-06-25 20:48:02 -04:00
|
|
|
have_appsession = 0;
|
|
|
|
|
global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
|
2009-06-22 09:48:36 -04:00
|
|
|
|
|
|
|
|
init_default_instance();
|
|
|
|
|
|
2010-01-03 15:12:30 -05:00
|
|
|
list_for_each_entry(wl, &cfg_cfgfiles, list) {
|
2009-12-06 07:10:44 -05:00
|
|
|
int ret;
|
|
|
|
|
|
2010-01-03 15:12:30 -05:00
|
|
|
ret = readcfgfile(wl->s);
|
2009-12-06 07:10:44 -05:00
|
|
|
if (ret == -1) {
|
|
|
|
|
Alert("Could not open configuration file %s : %s\n",
|
2010-01-03 15:12:30 -05:00
|
|
|
wl->s, strerror(errno));
|
2009-12-06 07:10:44 -05:00
|
|
|
exit(1);
|
|
|
|
|
}
|
2009-12-15 15:46:25 -05:00
|
|
|
if (ret & (ERR_ABORT|ERR_FATAL))
|
2010-01-03 15:12:30 -05:00
|
|
|
Alert("Error(s) found in configuration file : %s\n", wl->s);
|
2009-12-15 15:46:25 -05:00
|
|
|
err_code |= ret;
|
2009-07-20 03:30:05 -04:00
|
|
|
if (err_code & ERR_ABORT)
|
2009-06-22 10:02:30 -04:00
|
|
|
exit(1);
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
2007-10-14 17:40:01 -04:00
|
|
|
|
2014-03-11 09:29:22 -04:00
|
|
|
pattern_finalize_config();
|
|
|
|
|
|
2009-07-23 07:36:36 -04:00
|
|
|
err_code |= check_config_validity();
|
|
|
|
|
if (err_code & (ERR_ABORT|ERR_FATAL)) {
|
|
|
|
|
Alert("Fatal errors found in configuration.\n");
|
2009-06-22 09:48:36 -04:00
|
|
|
exit(1);
|
|
|
|
|
}
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2014-11-17 09:11:45 -05:00
|
|
|
#ifdef CONFIG_HAP_NS
|
|
|
|
|
err_code |= netns_init();
|
|
|
|
|
if (err_code & (ERR_ABORT|ERR_FATAL)) {
|
|
|
|
|
Alert("Failed to initialize namespace support.\n");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2006-06-25 20:48:02 -04:00
|
|
|
if (global.mode & MODE_CHECK) {
|
2012-02-02 11:48:18 -05:00
|
|
|
struct peers *pr;
|
|
|
|
|
struct proxy *px;
|
|
|
|
|
|
|
|
|
|
for (pr = peers; pr; pr = pr->next)
|
|
|
|
|
if (pr->peers_fe)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
for (px = proxy; px; px = px->next)
|
2012-09-20 10:48:07 -04:00
|
|
|
if (px->state == PR_STNEW && !LIST_ISEMPTY(&px->conf.listeners))
|
2012-02-02 11:48:18 -05:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (pr || px) {
|
|
|
|
|
/* At least one peer or one listener has been found */
|
|
|
|
|
qfprintf(stdout, "Configuration file is valid\n");
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
qfprintf(stdout, "Configuration file has no error but will not start (no listener) => exit(2).\n");
|
|
|
|
|
exit(2);
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
|
|
|
|
|
2011-08-01 14:57:55 -04:00
|
|
|
global_listener_queue_task = task_new();
|
|
|
|
|
if (!global_listener_queue_task) {
|
|
|
|
|
Alert("Out of memory when initializing global task\n");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
/* very simple initialization, users will queue the task if needed */
|
|
|
|
|
global_listener_queue_task->context = NULL; /* not even a context! */
|
|
|
|
|
global_listener_queue_task->process = manage_global_listener_queue;
|
|
|
|
|
global_listener_queue_task->expire = TICK_ETERNITY;
|
|
|
|
|
|
2012-08-27 18:06:31 -04:00
|
|
|
/* now we know the buffer size, we can initialize the channels and buffers */
|
2012-10-12 17:49:43 -04:00
|
|
|
init_buffer();
|
2009-09-23 17:37:52 -04:00
|
|
|
|
2009-06-22 09:48:36 -04:00
|
|
|
if (have_appsession)
|
|
|
|
|
appsession_init();
|
|
|
|
|
|
2007-10-14 17:40:01 -04:00
|
|
|
if (start_checks() < 0)
|
|
|
|
|
exit(1);
|
|
|
|
|
|
2006-06-25 20:48:02 -04:00
|
|
|
if (cfg_maxconn > 0)
|
|
|
|
|
global.maxconn = cfg_maxconn;
|
|
|
|
|
|
|
|
|
|
if (cfg_pidfile) {
|
2008-08-03 06:19:50 -04:00
|
|
|
free(global.pidfile);
|
2006-06-25 20:48:02 -04:00
|
|
|
global.pidfile = strdup(cfg_pidfile);
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-15 15:45:22 -05:00
|
|
|
/* Now we want to compute the maxconn and possibly maxsslconn values.
|
|
|
|
|
* It's a bit tricky. If memmax is not set, maxconn defaults to
|
|
|
|
|
* DEFAULT_MAXCONN and maxsslconn defaults to DEFAULT_MAXSSLCONN.
|
|
|
|
|
*
|
|
|
|
|
* If memmax is set, then it depends on which values are set. If
|
|
|
|
|
* maxsslconn is set, we use memmax to determine how many cleartext
|
|
|
|
|
* connections may be added, and set maxconn to the sum of the two.
|
|
|
|
|
* If maxconn is set and not maxsslconn, maxsslconn is computed from
|
|
|
|
|
* the remaining amount of memory between memmax and the cleartext
|
|
|
|
|
* connections. If neither are set, then it is considered that all
|
|
|
|
|
* connections are SSL-capable, and maxconn is computed based on this,
|
|
|
|
|
* then maxsslconn accordingly. We need to know if SSL is used on the
|
|
|
|
|
* frontends, backends, or both, because when it's used on both sides,
|
|
|
|
|
* we need twice the value for maxsslconn, but we only count the
|
|
|
|
|
* handshake once since it is not performed on the two sides at the
|
|
|
|
|
* same time (frontend-side is terminated before backend-side begins).
|
|
|
|
|
* The SSL stack is supposed to have filled ssl_session_cost and
|
2015-01-28 13:03:21 -05:00
|
|
|
* ssl_handshake_cost during its initialization. In any case, if
|
|
|
|
|
* SYSTEM_MAXCONN is set, we still enforce it as an upper limit for
|
|
|
|
|
* maxconn in order to protect the system.
|
2015-01-15 15:45:22 -05:00
|
|
|
*/
|
|
|
|
|
if (!global.rlimit_memmax) {
|
|
|
|
|
if (global.maxconn == 0) {
|
|
|
|
|
global.maxconn = DEFAULT_MAXCONN;
|
|
|
|
|
if (global.mode & (MODE_VERBOSE|MODE_DEBUG))
|
|
|
|
|
fprintf(stderr, "Note: setting global.maxconn to %d.\n", global.maxconn);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#ifdef USE_OPENSSL
|
|
|
|
|
else if (!global.maxconn && !global.maxsslconn &&
|
|
|
|
|
(global.ssl_used_frontend || global.ssl_used_backend)) {
|
|
|
|
|
/* memmax is set, compute everything automatically. Here we want
|
|
|
|
|
* to ensure that all SSL connections will be served. We take
|
|
|
|
|
* care of the number of sides where SSL is used, and consider
|
|
|
|
|
* the worst case : SSL used on both sides and doing a handshake
|
|
|
|
|
* simultaneously. Note that we can't have more than maxconn
|
|
|
|
|
* handshakes at a time by definition, so for the worst case of
|
|
|
|
|
* two SSL conns per connection, we count a single handshake.
|
|
|
|
|
*/
|
|
|
|
|
int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
|
|
|
|
|
int64_t mem = global.rlimit_memmax * 1048576ULL;
|
|
|
|
|
|
|
|
|
|
mem -= global.tune.sslcachesize * 200; // about 200 bytes per SSL cache entry
|
|
|
|
|
mem -= global.maxzlibmem;
|
|
|
|
|
mem = mem * MEM_USABLE_RATIO;
|
|
|
|
|
|
|
|
|
|
global.maxconn = mem /
|
REORG/MAJOR: session: rename the "session" entity to "stream"
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.
In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.
The files stream.{c,h} were added and session.{c,h} removed.
The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.
Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.
Once all changes are completed, we should see approximately this :
L7 - http_txn
L6 - stream
L5 - session
L4 - connection | applet
There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.
Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
2015-04-02 18:22:06 -04:00
|
|
|
((STREAM_MAX_COST + 2 * global.tune.bufsize) + // stream + 2 buffers per stream
|
2015-01-15 15:45:22 -05:00
|
|
|
sides * global.ssl_session_max_cost + // SSL buffers, one per side
|
|
|
|
|
global.ssl_handshake_max_cost); // 1 handshake per connection max
|
|
|
|
|
|
|
|
|
|
global.maxconn = round_2dig(global.maxconn);
|
2015-01-28 13:03:21 -05:00
|
|
|
#ifdef SYSTEM_MAXCONN
|
|
|
|
|
if (global.maxconn > DEFAULT_MAXCONN)
|
|
|
|
|
global.maxconn = DEFAULT_MAXCONN;
|
|
|
|
|
#endif /* SYSTEM_MAXCONN */
|
2015-01-15 15:45:22 -05:00
|
|
|
global.maxsslconn = sides * global.maxconn;
|
|
|
|
|
if (global.mode & (MODE_VERBOSE|MODE_DEBUG))
|
|
|
|
|
fprintf(stderr, "Note: setting global.maxconn to %d and global.maxsslconn to %d.\n",
|
|
|
|
|
global.maxconn, global.maxsslconn);
|
|
|
|
|
}
|
|
|
|
|
else if (!global.maxsslconn &&
|
|
|
|
|
(global.ssl_used_frontend || global.ssl_used_backend)) {
|
|
|
|
|
/* memmax and maxconn are known, compute maxsslconn automatically.
|
|
|
|
|
* maxsslconn being forced, we don't know how many of it will be
|
|
|
|
|
* on each side if both sides are being used. The worst case is
|
|
|
|
|
* when all connections use only one SSL instance because
|
|
|
|
|
* handshakes may be on two sides at the same time.
|
|
|
|
|
*/
|
|
|
|
|
int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
|
|
|
|
|
int64_t mem = global.rlimit_memmax * 1048576ULL;
|
|
|
|
|
int64_t sslmem;
|
|
|
|
|
|
|
|
|
|
mem -= global.tune.sslcachesize * 200; // about 200 bytes per SSL cache entry
|
|
|
|
|
mem -= global.maxzlibmem;
|
|
|
|
|
mem = mem * MEM_USABLE_RATIO;
|
|
|
|
|
|
REORG/MAJOR: session: rename the "session" entity to "stream"
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.
In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.
The files stream.{c,h} were added and session.{c,h} removed.
The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.
Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.
Once all changes are completed, we should see approximately this :
L7 - http_txn
L6 - stream
L5 - session
L4 - connection | applet
There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.
Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
2015-04-02 18:22:06 -04:00
|
|
|
sslmem = mem - global.maxconn * (int64_t)(STREAM_MAX_COST + 2 * global.tune.bufsize);
|
2015-01-15 15:45:22 -05:00
|
|
|
global.maxsslconn = sslmem / (global.ssl_session_max_cost + global.ssl_handshake_max_cost);
|
|
|
|
|
global.maxsslconn = round_2dig(global.maxsslconn);
|
|
|
|
|
|
|
|
|
|
if (sslmem <= 0 || global.maxsslconn < sides) {
|
|
|
|
|
Alert("Cannot compute the automatic maxsslconn because global.maxconn is already too "
|
|
|
|
|
"high for the global.memmax value (%d MB). The absolute maximum possible value "
|
|
|
|
|
"without SSL is %d, but %d was found and SSL is in use.\n",
|
|
|
|
|
global.rlimit_memmax,
|
REORG/MAJOR: session: rename the "session" entity to "stream"
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.
In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.
The files stream.{c,h} were added and session.{c,h} removed.
The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.
Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.
Once all changes are completed, we should see approximately this :
L7 - http_txn
L6 - stream
L5 - session
L4 - connection | applet
There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.
Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
2015-04-02 18:22:06 -04:00
|
|
|
(int)(mem / (STREAM_MAX_COST + 2 * global.tune.bufsize)),
|
2015-01-15 15:45:22 -05:00
|
|
|
global.maxconn);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (global.maxsslconn > sides * global.maxconn)
|
|
|
|
|
global.maxsslconn = sides * global.maxconn;
|
|
|
|
|
|
|
|
|
|
if (global.mode & (MODE_VERBOSE|MODE_DEBUG))
|
|
|
|
|
fprintf(stderr, "Note: setting global.maxsslconn to %d\n", global.maxsslconn);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
else if (!global.maxconn) {
|
|
|
|
|
/* memmax and maxsslconn are known/unused, compute maxconn automatically */
|
|
|
|
|
int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
|
|
|
|
|
int64_t mem = global.rlimit_memmax * 1048576ULL;
|
|
|
|
|
int64_t clearmem;
|
|
|
|
|
|
|
|
|
|
if (global.ssl_used_frontend || global.ssl_used_backend)
|
|
|
|
|
mem -= global.tune.sslcachesize * 200; // about 200 bytes per SSL cache entry
|
|
|
|
|
|
|
|
|
|
mem -= global.maxzlibmem;
|
|
|
|
|
mem = mem * MEM_USABLE_RATIO;
|
|
|
|
|
|
|
|
|
|
clearmem = mem;
|
|
|
|
|
if (sides)
|
|
|
|
|
clearmem -= (global.ssl_session_max_cost + global.ssl_handshake_max_cost) * (int64_t)global.maxsslconn;
|
|
|
|
|
|
REORG/MAJOR: session: rename the "session" entity to "stream"
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.
In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.
The files stream.{c,h} were added and session.{c,h} removed.
The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.
Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.
Once all changes are completed, we should see approximately this :
L7 - http_txn
L6 - stream
L5 - session
L4 - connection | applet
There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.
Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
2015-04-02 18:22:06 -04:00
|
|
|
global.maxconn = clearmem / (STREAM_MAX_COST + 2 * global.tune.bufsize);
|
2015-01-15 15:45:22 -05:00
|
|
|
global.maxconn = round_2dig(global.maxconn);
|
2015-01-28 13:03:21 -05:00
|
|
|
#ifdef SYSTEM_MAXCONN
|
|
|
|
|
if (global.maxconn > DEFAULT_MAXCONN)
|
|
|
|
|
global.maxconn = DEFAULT_MAXCONN;
|
|
|
|
|
#endif /* SYSTEM_MAXCONN */
|
2015-01-15 15:45:22 -05:00
|
|
|
|
|
|
|
|
if (clearmem <= 0 || !global.maxconn) {
|
|
|
|
|
Alert("Cannot compute the automatic maxconn because global.maxsslconn is already too "
|
|
|
|
|
"high for the global.memmax value (%d MB). The absolute maximum possible value "
|
|
|
|
|
"is %d, but %d was found.\n",
|
|
|
|
|
global.rlimit_memmax,
|
|
|
|
|
(int)(mem / (global.ssl_session_max_cost + global.ssl_handshake_max_cost)),
|
|
|
|
|
global.maxsslconn);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (global.mode & (MODE_VERBOSE|MODE_DEBUG)) {
|
|
|
|
|
if (sides && global.maxsslconn > sides * global.maxconn) {
|
|
|
|
|
fprintf(stderr, "Note: global.maxsslconn is forced to %d which causes global.maxconn "
|
|
|
|
|
"to be limited to %d. Better reduce global.maxsslconn to get more "
|
|
|
|
|
"room for extra connections.\n", global.maxsslconn, global.maxconn);
|
|
|
|
|
}
|
|
|
|
|
fprintf(stderr, "Note: setting global.maxconn to %d\n", global.maxconn);
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2009-01-18 15:44:07 -05:00
|
|
|
if (!global.maxpipes) {
|
|
|
|
|
/* maxpipes not specified. Count how many frontends and backends
|
|
|
|
|
* may be using splicing, and bound that to maxconn.
|
|
|
|
|
*/
|
|
|
|
|
struct proxy *cur;
|
|
|
|
|
int nbfe = 0, nbbe = 0;
|
|
|
|
|
|
|
|
|
|
for (cur = proxy; cur; cur = cur->next) {
|
|
|
|
|
if (cur->options2 & (PR_O2_SPLIC_ANY)) {
|
|
|
|
|
if (cur->cap & PR_CAP_FE)
|
|
|
|
|
nbfe += cur->maxconn;
|
|
|
|
|
if (cur->cap & PR_CAP_BE)
|
2009-01-25 04:42:05 -05:00
|
|
|
nbbe += cur->fullconn ? cur->fullconn : global.maxconn;
|
2009-01-18 15:44:07 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
global.maxpipes = MAX(nbfe, nbbe);
|
|
|
|
|
if (global.maxpipes > global.maxconn)
|
|
|
|
|
global.maxpipes = global.maxconn;
|
2009-01-25 08:06:58 -05:00
|
|
|
global.maxpipes /= 4;
|
2009-01-18 15:44:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-09-07 08:26:33 -04:00
|
|
|
global.hardmaxconn = global.maxconn; /* keep this max value */
|
2006-06-25 20:48:02 -04:00
|
|
|
global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
|
2009-01-18 14:39:42 -05:00
|
|
|
global.maxsock += global.maxpipes * 2; /* each pipe needs two FDs */
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2011-09-07 12:00:47 -04:00
|
|
|
if (global.stats_fe)
|
|
|
|
|
global.maxsock += global.stats_fe->maxconn;
|
|
|
|
|
|
|
|
|
|
if (peers) {
|
|
|
|
|
/* peers also need to bypass global maxconn */
|
|
|
|
|
struct peers *p = peers;
|
|
|
|
|
|
|
|
|
|
for (p = peers; p; p = p->next)
|
|
|
|
|
if (p->peers_fe)
|
|
|
|
|
global.maxsock += p->peers_fe->maxconn;
|
|
|
|
|
}
|
|
|
|
|
|
2007-06-03 11:16:49 -04:00
|
|
|
if (global.tune.maxpollevents <= 0)
|
|
|
|
|
global.tune.maxpollevents = MAX_POLL_EVENTS;
|
|
|
|
|
|
2009-03-21 15:43:57 -04:00
|
|
|
if (global.tune.recv_enough == 0)
|
|
|
|
|
global.tune.recv_enough = MIN_RECV_AT_ONCE_ENOUGH;
|
|
|
|
|
|
2009-08-17 01:23:33 -04:00
|
|
|
if (global.tune.maxrewrite >= global.tune.bufsize / 2)
|
|
|
|
|
global.tune.maxrewrite = global.tune.bufsize / 2;
|
|
|
|
|
|
2006-06-25 20:48:02 -04:00
|
|
|
if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
|
|
|
|
|
/* command line debug mode inhibits configuration mode */
|
2013-02-12 04:53:52 -05:00
|
|
|
global.mode &= ~(MODE_DAEMON | MODE_SYSTEMD | MODE_QUIET);
|
2012-10-26 10:04:28 -04:00
|
|
|
global.mode |= (arg_mode & (MODE_DEBUG | MODE_FOREGROUND));
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
2012-10-26 10:04:28 -04:00
|
|
|
|
2013-02-12 04:53:52 -05:00
|
|
|
if (arg_mode & (MODE_DAEMON | MODE_SYSTEMD)) {
|
2012-10-26 10:04:28 -04:00
|
|
|
/* command line daemon mode inhibits foreground and debug modes mode */
|
|
|
|
|
global.mode &= ~(MODE_DEBUG | MODE_FOREGROUND);
|
2013-02-12 04:53:52 -05:00
|
|
|
global.mode |= (arg_mode & (MODE_DAEMON | MODE_SYSTEMD));
|
2012-10-26 10:04:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
global.mode |= (arg_mode & (MODE_QUIET | MODE_VERBOSE));
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2013-02-12 04:53:52 -05:00
|
|
|
if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_SYSTEMD | MODE_QUIET))) {
|
|
|
|
|
Warning("<debug> mode incompatible with <quiet>, <daemon> and <systemd>. Keeping <debug> only.\n");
|
|
|
|
|
global.mode &= ~(MODE_DAEMON | MODE_SYSTEMD | MODE_QUIET);
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
|
|
|
|
|
2013-02-12 04:53:52 -05:00
|
|
|
if ((global.nbproc > 1) && !(global.mode & (MODE_DAEMON | MODE_SYSTEMD))) {
|
2006-06-25 20:48:02 -04:00
|
|
|
if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
|
|
|
|
|
Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
|
|
|
|
|
global.nbproc = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (global.nbproc < 1)
|
|
|
|
|
global.nbproc = 1;
|
|
|
|
|
|
2010-02-26 05:12:27 -05:00
|
|
|
swap_buffer = (char *)calloc(1, global.tune.bufsize);
|
2012-10-29 15:44:36 -04:00
|
|
|
get_http_auth_buff = (char *)calloc(1, global.tune.bufsize);
|
2012-10-29 16:56:59 -04:00
|
|
|
static_table_key = calloc(1, sizeof(*static_table_key) + global.tune.bufsize);
|
2010-02-26 05:12:27 -05:00
|
|
|
|
2009-10-18 01:25:52 -04:00
|
|
|
fdinfo = (struct fdinfo *)calloc(1,
|
|
|
|
|
sizeof(struct fdinfo) * (global.maxsock));
|
2006-06-25 20:48:02 -04:00
|
|
|
fdtab = (struct fdtab *)calloc(1,
|
|
|
|
|
sizeof(struct fdtab) * (global.maxsock));
|
2007-04-15 18:25:25 -04:00
|
|
|
/*
|
|
|
|
|
* Note: we could register external pollers here.
|
|
|
|
|
* Built-in pollers have been registered before main().
|
|
|
|
|
*/
|
2007-04-08 10:39:58 -04:00
|
|
|
|
2009-01-25 09:42:27 -05:00
|
|
|
if (!(global.tune.options & GTUNE_USE_KQUEUE))
|
2007-04-09 06:03:06 -04:00
|
|
|
disable_poller("kqueue");
|
|
|
|
|
|
2009-01-25 09:42:27 -05:00
|
|
|
if (!(global.tune.options & GTUNE_USE_EPOLL))
|
2007-04-08 10:39:58 -04:00
|
|
|
disable_poller("epoll");
|
|
|
|
|
|
2009-01-25 09:42:27 -05:00
|
|
|
if (!(global.tune.options & GTUNE_USE_POLL))
|
2007-04-08 10:39:58 -04:00
|
|
|
disable_poller("poll");
|
|
|
|
|
|
2009-01-25 09:42:27 -05:00
|
|
|
if (!(global.tune.options & GTUNE_USE_SELECT))
|
2007-04-08 10:39:58 -04:00
|
|
|
disable_poller("select");
|
|
|
|
|
|
|
|
|
|
/* Note: we could disable any poller by name here */
|
|
|
|
|
|
2007-04-09 13:29:56 -04:00
|
|
|
if (global.mode & (MODE_VERBOSE|MODE_DEBUG))
|
|
|
|
|
list_pollers(stderr);
|
|
|
|
|
|
2007-04-08 10:39:58 -04:00
|
|
|
if (!init_pollers()) {
|
2013-03-31 08:41:15 -04:00
|
|
|
Alert("No polling mechanism available.\n"
|
|
|
|
|
" It is likely that haproxy was built with TARGET=generic and that FD_SETSIZE\n"
|
|
|
|
|
" is too low on this platform to support maxconn and the number of listeners\n"
|
|
|
|
|
" and servers. You should rebuild haproxy specifying your system using TARGET=\n"
|
|
|
|
|
" in order to support other polling systems (poll, epoll, kqueue) or reduce the\n"
|
2013-05-14 14:56:28 -04:00
|
|
|
" global maxconn setting to accommodate the system's limitation. For reference,\n"
|
2013-03-31 08:41:15 -04:00
|
|
|
" FD_SETSIZE=%d on this system, global.maxconn=%d resulting in a maximum of\n"
|
|
|
|
|
" %d file descriptors. You should thus reduce global.maxconn by %d. Also,\n"
|
|
|
|
|
" check build settings using 'haproxy -vv'.\n\n",
|
|
|
|
|
FD_SETSIZE, global.maxconn, global.maxsock, (global.maxsock + 1 - FD_SETSIZE) / 2);
|
2007-04-08 10:39:58 -04:00
|
|
|
exit(1);
|
|
|
|
|
}
|
2007-04-09 13:29:56 -04:00
|
|
|
if (global.mode & (MODE_VERBOSE|MODE_DEBUG)) {
|
|
|
|
|
printf("Using %s() as the polling mechanism.\n", cur_poller.name);
|
2007-04-08 10:39:58 -04:00
|
|
|
}
|
|
|
|
|
|
2009-10-02 16:51:14 -04:00
|
|
|
if (!global.node)
|
|
|
|
|
global.node = strdup(hostname);
|
|
|
|
|
|
2015-01-23 06:08:30 -05:00
|
|
|
if (!hlua_post_init())
|
|
|
|
|
exit(1);
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
|
|
|
|
|
2011-07-15 00:14:11 -04:00
|
|
|
static void deinit_acl_cond(struct acl_cond *cond)
|
2011-07-15 00:14:09 -04:00
|
|
|
{
|
|
|
|
|
struct acl_term_suite *suite, *suiteb;
|
|
|
|
|
struct acl_term *term, *termb;
|
|
|
|
|
|
2011-07-15 00:14:11 -04:00
|
|
|
if (!cond)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
list_for_each_entry_safe(suite, suiteb, &cond->suites, list) {
|
|
|
|
|
list_for_each_entry_safe(term, termb, &suite->terms, list) {
|
|
|
|
|
LIST_DEL(&term->list);
|
|
|
|
|
free(term);
|
2011-07-15 00:14:09 -04:00
|
|
|
}
|
2011-07-15 00:14:11 -04:00
|
|
|
LIST_DEL(&suite->list);
|
|
|
|
|
free(suite);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(cond);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void deinit_tcp_rules(struct list *rules)
|
|
|
|
|
{
|
|
|
|
|
struct tcp_rule *trule, *truleb;
|
|
|
|
|
|
|
|
|
|
list_for_each_entry_safe(trule, truleb, rules, list) {
|
2011-07-15 00:14:09 -04:00
|
|
|
LIST_DEL(&trule->list);
|
2011-07-15 00:14:11 -04:00
|
|
|
deinit_acl_cond(trule->cond);
|
2011-07-15 00:14:09 -04:00
|
|
|
free(trule);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-27 15:37:17 -04:00
|
|
|
static void deinit_sample_arg(struct arg *p)
|
2011-07-15 00:14:11 -04:00
|
|
|
{
|
2012-04-20 08:03:29 -04:00
|
|
|
struct arg *p_back = p;
|
|
|
|
|
|
2011-07-15 00:14:11 -04:00
|
|
|
if (!p)
|
|
|
|
|
return;
|
|
|
|
|
|
2012-04-20 08:03:29 -04:00
|
|
|
while (p->type != ARGT_STOP) {
|
2012-06-01 04:38:29 -04:00
|
|
|
if (p->type == ARGT_STR || p->unresolved) {
|
2012-04-20 08:03:29 -04:00
|
|
|
free(p->data.str.str);
|
|
|
|
|
p->data.str.str = NULL;
|
2012-06-01 04:38:29 -04:00
|
|
|
p->unresolved = 0;
|
2012-04-20 06:29:52 -04:00
|
|
|
}
|
2015-01-19 13:00:58 -05:00
|
|
|
else if (p->type == ARGT_REG) {
|
|
|
|
|
if (p->data.reg) {
|
|
|
|
|
regex_free(p->data.reg);
|
|
|
|
|
free(p->data.reg);
|
|
|
|
|
p->data.reg = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-04-20 08:03:29 -04:00
|
|
|
p++;
|
2012-04-20 06:29:52 -04:00
|
|
|
}
|
2011-07-15 00:14:11 -04:00
|
|
|
|
2012-10-19 13:49:09 -04:00
|
|
|
if (p_back != empty_arg_list)
|
|
|
|
|
free(p_back);
|
2011-07-15 00:14:11 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void deinit_stick_rules(struct list *rules)
|
|
|
|
|
{
|
|
|
|
|
struct sticking_rule *rule, *ruleb;
|
|
|
|
|
|
|
|
|
|
list_for_each_entry_safe(rule, ruleb, rules, list) {
|
|
|
|
|
LIST_DEL(&rule->list);
|
|
|
|
|
deinit_acl_cond(rule->cond);
|
|
|
|
|
if (rule->expr) {
|
2012-04-27 15:37:17 -04:00
|
|
|
struct sample_conv_expr *conv_expr, *conv_exprb;
|
2011-07-15 00:14:11 -04:00
|
|
|
list_for_each_entry_safe(conv_expr, conv_exprb, &rule->expr->conv_exprs, list)
|
2012-04-27 15:37:17 -04:00
|
|
|
deinit_sample_arg(conv_expr->arg_p);
|
|
|
|
|
deinit_sample_arg(rule->expr->arg_p);
|
2011-07-15 00:14:11 -04:00
|
|
|
free(rule->expr);
|
|
|
|
|
}
|
|
|
|
|
free(rule);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-06-25 20:48:02 -04:00
|
|
|
void deinit(void)
|
|
|
|
|
{
|
2007-05-13 18:39:29 -04:00
|
|
|
struct proxy *p = proxy, *p0;
|
2006-06-25 20:48:02 -04:00
|
|
|
struct cap_hdr *h,*h_next;
|
|
|
|
|
struct server *s,*s_next;
|
|
|
|
|
struct listener *l,*l_next;
|
2007-06-16 18:36:03 -04:00
|
|
|
struct acl_cond *cond, *condb;
|
|
|
|
|
struct hdr_exp *exp, *expb;
|
[MEDIUM] Fix memory freeing at exit
New functions implemented:
- deinit_pollers: called at the end of deinit())
- prune_acl: called via list_for_each_entry_safe
Add missing pool_destroy2 calls:
- p->hdr_idx_pool
- pool2_tree64
Implement all task stopping:
- health-check: needs new "struct task" in the struct server
- queue processing: queue_mgt
- appsess_refresh: appsession_refresh
before (idle system):
==6079== LEAK SUMMARY:
==6079== definitely lost: 1,112 bytes in 75 blocks.
==6079== indirectly lost: 53,356 bytes in 2,090 blocks.
==6079== possibly lost: 52 bytes in 1 blocks.
==6079== still reachable: 150,996 bytes in 504 blocks.
==6079== suppressed: 0 bytes in 0 blocks.
after (idle system):
==6945== LEAK SUMMARY:
==6945== definitely lost: 7,644 bytes in 137 blocks.
==6945== indirectly lost: 9,913 bytes in 587 blocks.
==6945== possibly lost: 0 bytes in 0 blocks.
==6945== still reachable: 0 bytes in 0 blocks.
==6945== suppressed: 0 bytes in 0 blocks.
before (running system for ~2m):
==9343== LEAK SUMMARY:
==9343== definitely lost: 1,112 bytes in 75 blocks.
==9343== indirectly lost: 54,199 bytes in 2,122 blocks.
==9343== possibly lost: 52 bytes in 1 blocks.
==9343== still reachable: 151,128 bytes in 509 blocks.
==9343== suppressed: 0 bytes in 0 blocks.
after (running system for ~2m):
==11616== LEAK SUMMARY:
==11616== definitely lost: 7,644 bytes in 137 blocks.
==11616== indirectly lost: 9,981 bytes in 591 blocks.
==11616== possibly lost: 0 bytes in 0 blocks.
==11616== still reachable: 4 bytes in 1 blocks.
==11616== suppressed: 0 bytes in 0 blocks.
Still not perfect but significant improvement.
2008-05-29 17:53:44 -04:00
|
|
|
struct acl *acl, *aclb;
|
2008-05-31 07:53:23 -04:00
|
|
|
struct switching_rule *rule, *ruleb;
|
2012-04-05 15:09:48 -04:00
|
|
|
struct server_rule *srule, *sruleb;
|
2008-06-07 17:08:56 -04:00
|
|
|
struct redirect_rule *rdr, *rdrb;
|
2010-01-03 15:03:22 -05:00
|
|
|
struct wordlist *wl, *wlb;
|
2010-01-28 12:10:50 -05:00
|
|
|
struct cond_wordlist *cwl, *cwlb;
|
2008-05-31 07:53:23 -04:00
|
|
|
struct uri_auth *uap, *ua = NULL;
|
2011-10-12 11:50:54 -04:00
|
|
|
struct logsrv *log, *logb;
|
2012-02-08 10:37:49 -05:00
|
|
|
struct logformat_node *lf, *lfb;
|
2012-09-13 11:54:29 -04:00
|
|
|
struct bind_conf *bind_conf, *bind_back;
|
2007-06-16 18:36:03 -04:00
|
|
|
int i;
|
2008-05-31 07:53:23 -04:00
|
|
|
|
2010-08-27 11:56:48 -04:00
|
|
|
deinit_signals();
|
2006-06-25 20:48:02 -04:00
|
|
|
while (p) {
|
2012-10-04 02:01:43 -04:00
|
|
|
free(p->conf.file);
|
2008-08-03 06:19:50 -04:00
|
|
|
free(p->id);
|
|
|
|
|
free(p->check_req);
|
|
|
|
|
free(p->cookie_name);
|
|
|
|
|
free(p->cookie_domain);
|
|
|
|
|
free(p->url_param_name);
|
|
|
|
|
free(p->capture_name);
|
|
|
|
|
free(p->monitor_uri);
|
2011-07-15 00:14:08 -04:00
|
|
|
free(p->rdp_cookie_name);
|
2013-04-12 12:13:46 -04:00
|
|
|
if (p->conf.logformat_string != default_http_log_format &&
|
|
|
|
|
p->conf.logformat_string != default_tcp_log_format &&
|
|
|
|
|
p->conf.logformat_string != clf_http_log_format)
|
|
|
|
|
free(p->conf.logformat_string);
|
|
|
|
|
|
|
|
|
|
free(p->conf.lfs_file);
|
|
|
|
|
free(p->conf.uniqueid_format_string);
|
|
|
|
|
free(p->conf.uif_file);
|
2013-10-02 05:10:11 -04:00
|
|
|
free(p->lbprm.map.srv);
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2008-08-03 06:19:50 -04:00
|
|
|
for (i = 0; i < HTTP_ERR_SIZE; i++)
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_destroy(&p->errmsg[i]);
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2010-01-28 12:10:50 -05:00
|
|
|
list_for_each_entry_safe(cwl, cwlb, &p->req_add, list) {
|
|
|
|
|
LIST_DEL(&cwl->list);
|
|
|
|
|
free(cwl->s);
|
|
|
|
|
free(cwl);
|
2010-01-03 15:03:22 -05:00
|
|
|
}
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2010-01-28 12:10:50 -05:00
|
|
|
list_for_each_entry_safe(cwl, cwlb, &p->rsp_add, list) {
|
|
|
|
|
LIST_DEL(&cwl->list);
|
|
|
|
|
free(cwl->s);
|
|
|
|
|
free(cwl);
|
2010-01-03 15:03:22 -05:00
|
|
|
}
|
2007-06-16 18:36:03 -04:00
|
|
|
|
2014-04-28 16:05:31 -04:00
|
|
|
list_for_each_entry_safe(cond, condb, &p->block_rules, list) {
|
2007-06-16 18:36:03 -04:00
|
|
|
LIST_DEL(&cond->list);
|
|
|
|
|
prune_acl_cond(cond);
|
|
|
|
|
free(cond);
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-30 14:51:32 -05:00
|
|
|
list_for_each_entry_safe(cond, condb, &p->mon_fail_cond, list) {
|
|
|
|
|
LIST_DEL(&cond->list);
|
|
|
|
|
prune_acl_cond(cond);
|
|
|
|
|
free(cond);
|
|
|
|
|
}
|
|
|
|
|
|
2007-06-16 18:36:03 -04:00
|
|
|
for (exp = p->req_exp; exp != NULL; ) {
|
2008-05-31 07:53:23 -04:00
|
|
|
if (exp->preg) {
|
2014-06-18 05:35:54 -04:00
|
|
|
regex_free(exp->preg);
|
|
|
|
|
free(exp->preg);
|
2008-05-31 07:53:23 -04:00
|
|
|
}
|
|
|
|
|
|
2007-06-16 18:36:03 -04:00
|
|
|
if (exp->replace && exp->action != ACT_SETBE)
|
|
|
|
|
free((char *)exp->replace);
|
|
|
|
|
expb = exp;
|
|
|
|
|
exp = exp->next;
|
|
|
|
|
free(expb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (exp = p->rsp_exp; exp != NULL; ) {
|
2008-05-31 07:53:23 -04:00
|
|
|
if (exp->preg) {
|
2014-06-18 05:35:54 -04:00
|
|
|
regex_free(exp->preg);
|
|
|
|
|
free(exp->preg);
|
2008-05-31 07:53:23 -04:00
|
|
|
}
|
|
|
|
|
|
2007-06-16 18:36:03 -04:00
|
|
|
if (exp->replace && exp->action != ACT_SETBE)
|
|
|
|
|
free((char *)exp->replace);
|
|
|
|
|
expb = exp;
|
|
|
|
|
exp = exp->next;
|
|
|
|
|
free(expb);
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-31 07:53:23 -04:00
|
|
|
/* build a list of unique uri_auths */
|
|
|
|
|
if (!ua)
|
|
|
|
|
ua = p->uri_auth;
|
|
|
|
|
else {
|
|
|
|
|
/* check if p->uri_auth is unique */
|
|
|
|
|
for (uap = ua; uap; uap=uap->next)
|
|
|
|
|
if (uap == p->uri_auth)
|
|
|
|
|
break;
|
|
|
|
|
|
2008-06-24 05:14:45 -04:00
|
|
|
if (!uap && p->uri_auth) {
|
2008-05-31 07:53:23 -04:00
|
|
|
/* add it, if it is */
|
|
|
|
|
p->uri_auth->next = ua;
|
|
|
|
|
ua = p->uri_auth;
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-06-16 18:36:03 -04:00
|
|
|
|
[MEDIUM] Fix memory freeing at exit
New functions implemented:
- deinit_pollers: called at the end of deinit())
- prune_acl: called via list_for_each_entry_safe
Add missing pool_destroy2 calls:
- p->hdr_idx_pool
- pool2_tree64
Implement all task stopping:
- health-check: needs new "struct task" in the struct server
- queue processing: queue_mgt
- appsess_refresh: appsession_refresh
before (idle system):
==6079== LEAK SUMMARY:
==6079== definitely lost: 1,112 bytes in 75 blocks.
==6079== indirectly lost: 53,356 bytes in 2,090 blocks.
==6079== possibly lost: 52 bytes in 1 blocks.
==6079== still reachable: 150,996 bytes in 504 blocks.
==6079== suppressed: 0 bytes in 0 blocks.
after (idle system):
==6945== LEAK SUMMARY:
==6945== definitely lost: 7,644 bytes in 137 blocks.
==6945== indirectly lost: 9,913 bytes in 587 blocks.
==6945== possibly lost: 0 bytes in 0 blocks.
==6945== still reachable: 0 bytes in 0 blocks.
==6945== suppressed: 0 bytes in 0 blocks.
before (running system for ~2m):
==9343== LEAK SUMMARY:
==9343== definitely lost: 1,112 bytes in 75 blocks.
==9343== indirectly lost: 54,199 bytes in 2,122 blocks.
==9343== possibly lost: 52 bytes in 1 blocks.
==9343== still reachable: 151,128 bytes in 509 blocks.
==9343== suppressed: 0 bytes in 0 blocks.
after (running system for ~2m):
==11616== LEAK SUMMARY:
==11616== definitely lost: 7,644 bytes in 137 blocks.
==11616== indirectly lost: 9,981 bytes in 591 blocks.
==11616== possibly lost: 0 bytes in 0 blocks.
==11616== still reachable: 4 bytes in 1 blocks.
==11616== suppressed: 0 bytes in 0 blocks.
Still not perfect but significant improvement.
2008-05-29 17:53:44 -04:00
|
|
|
list_for_each_entry_safe(acl, aclb, &p->acl, list) {
|
|
|
|
|
LIST_DEL(&acl->list);
|
|
|
|
|
prune_acl(acl);
|
|
|
|
|
free(acl);
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-05 15:09:48 -04:00
|
|
|
list_for_each_entry_safe(srule, sruleb, &p->server_rules, list) {
|
|
|
|
|
LIST_DEL(&srule->list);
|
|
|
|
|
prune_acl_cond(srule->cond);
|
|
|
|
|
free(srule->cond);
|
|
|
|
|
free(srule);
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-31 07:53:23 -04:00
|
|
|
list_for_each_entry_safe(rule, ruleb, &p->switching_rules, list) {
|
|
|
|
|
LIST_DEL(&rule->list);
|
2014-04-22 19:21:56 -04:00
|
|
|
if (rule->cond) {
|
|
|
|
|
prune_acl_cond(rule->cond);
|
|
|
|
|
free(rule->cond);
|
|
|
|
|
}
|
2008-05-31 07:53:23 -04:00
|
|
|
free(rule);
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-07 17:08:56 -04:00
|
|
|
list_for_each_entry_safe(rdr, rdrb, &p->redirect_rules, list) {
|
|
|
|
|
LIST_DEL(&rdr->list);
|
2010-01-03 14:03:03 -05:00
|
|
|
if (rdr->cond) {
|
|
|
|
|
prune_acl_cond(rdr->cond);
|
|
|
|
|
free(rdr->cond);
|
|
|
|
|
}
|
2008-06-07 17:08:56 -04:00
|
|
|
free(rdr->rdr_str);
|
2013-11-29 06:15:45 -05:00
|
|
|
list_for_each_entry_safe(lf, lfb, &rdr->rdr_fmt, list) {
|
|
|
|
|
LIST_DEL(&lf->list);
|
|
|
|
|
free(lf);
|
|
|
|
|
}
|
2008-06-07 17:08:56 -04:00
|
|
|
free(rdr);
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-12 11:50:54 -04:00
|
|
|
list_for_each_entry_safe(log, logb, &p->logsrvs, list) {
|
|
|
|
|
LIST_DEL(&log->list);
|
|
|
|
|
free(log);
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-08 10:37:49 -05:00
|
|
|
list_for_each_entry_safe(lf, lfb, &p->logformat, list) {
|
|
|
|
|
LIST_DEL(&lf->list);
|
|
|
|
|
free(lf);
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-15 00:14:09 -04:00
|
|
|
deinit_tcp_rules(&p->tcp_req.inspect_rules);
|
|
|
|
|
deinit_tcp_rules(&p->tcp_req.l4_rules);
|
|
|
|
|
|
2011-07-15 00:14:11 -04:00
|
|
|
deinit_stick_rules(&p->storersp_rules);
|
|
|
|
|
deinit_stick_rules(&p->sticking_rules);
|
|
|
|
|
|
2008-08-03 06:19:50 -04:00
|
|
|
free(p->appsession_name);
|
2006-06-25 20:48:02 -04:00
|
|
|
|
|
|
|
|
h = p->req_cap;
|
|
|
|
|
while (h) {
|
|
|
|
|
h_next = h->next;
|
2008-08-03 06:19:50 -04:00
|
|
|
free(h->name);
|
2007-05-13 16:46:04 -04:00
|
|
|
pool_destroy2(h->pool);
|
2006-06-25 20:48:02 -04:00
|
|
|
free(h);
|
|
|
|
|
h = h_next;
|
|
|
|
|
}/* end while(h) */
|
|
|
|
|
|
|
|
|
|
h = p->rsp_cap;
|
|
|
|
|
while (h) {
|
|
|
|
|
h_next = h->next;
|
2008-08-03 06:19:50 -04:00
|
|
|
free(h->name);
|
2007-05-13 16:46:04 -04:00
|
|
|
pool_destroy2(h->pool);
|
2006-06-25 20:48:02 -04:00
|
|
|
free(h);
|
|
|
|
|
h = h_next;
|
|
|
|
|
}/* end while(h) */
|
[MEDIUM] Fix memory freeing at exit
New functions implemented:
- deinit_pollers: called at the end of deinit())
- prune_acl: called via list_for_each_entry_safe
Add missing pool_destroy2 calls:
- p->hdr_idx_pool
- pool2_tree64
Implement all task stopping:
- health-check: needs new "struct task" in the struct server
- queue processing: queue_mgt
- appsess_refresh: appsession_refresh
before (idle system):
==6079== LEAK SUMMARY:
==6079== definitely lost: 1,112 bytes in 75 blocks.
==6079== indirectly lost: 53,356 bytes in 2,090 blocks.
==6079== possibly lost: 52 bytes in 1 blocks.
==6079== still reachable: 150,996 bytes in 504 blocks.
==6079== suppressed: 0 bytes in 0 blocks.
after (idle system):
==6945== LEAK SUMMARY:
==6945== definitely lost: 7,644 bytes in 137 blocks.
==6945== indirectly lost: 9,913 bytes in 587 blocks.
==6945== possibly lost: 0 bytes in 0 blocks.
==6945== still reachable: 0 bytes in 0 blocks.
==6945== suppressed: 0 bytes in 0 blocks.
before (running system for ~2m):
==9343== LEAK SUMMARY:
==9343== definitely lost: 1,112 bytes in 75 blocks.
==9343== indirectly lost: 54,199 bytes in 2,122 blocks.
==9343== possibly lost: 52 bytes in 1 blocks.
==9343== still reachable: 151,128 bytes in 509 blocks.
==9343== suppressed: 0 bytes in 0 blocks.
after (running system for ~2m):
==11616== LEAK SUMMARY:
==11616== definitely lost: 7,644 bytes in 137 blocks.
==11616== indirectly lost: 9,981 bytes in 591 blocks.
==11616== possibly lost: 0 bytes in 0 blocks.
==11616== still reachable: 4 bytes in 1 blocks.
==11616== suppressed: 0 bytes in 0 blocks.
Still not perfect but significant improvement.
2008-05-29 17:53:44 -04:00
|
|
|
|
2006-06-25 20:48:02 -04:00
|
|
|
s = p->srv;
|
|
|
|
|
while (s) {
|
|
|
|
|
s_next = s->next;
|
[MEDIUM] Fix memory freeing at exit
New functions implemented:
- deinit_pollers: called at the end of deinit())
- prune_acl: called via list_for_each_entry_safe
Add missing pool_destroy2 calls:
- p->hdr_idx_pool
- pool2_tree64
Implement all task stopping:
- health-check: needs new "struct task" in the struct server
- queue processing: queue_mgt
- appsess_refresh: appsession_refresh
before (idle system):
==6079== LEAK SUMMARY:
==6079== definitely lost: 1,112 bytes in 75 blocks.
==6079== indirectly lost: 53,356 bytes in 2,090 blocks.
==6079== possibly lost: 52 bytes in 1 blocks.
==6079== still reachable: 150,996 bytes in 504 blocks.
==6079== suppressed: 0 bytes in 0 blocks.
after (idle system):
==6945== LEAK SUMMARY:
==6945== definitely lost: 7,644 bytes in 137 blocks.
==6945== indirectly lost: 9,913 bytes in 587 blocks.
==6945== possibly lost: 0 bytes in 0 blocks.
==6945== still reachable: 0 bytes in 0 blocks.
==6945== suppressed: 0 bytes in 0 blocks.
before (running system for ~2m):
==9343== LEAK SUMMARY:
==9343== definitely lost: 1,112 bytes in 75 blocks.
==9343== indirectly lost: 54,199 bytes in 2,122 blocks.
==9343== possibly lost: 52 bytes in 1 blocks.
==9343== still reachable: 151,128 bytes in 509 blocks.
==9343== suppressed: 0 bytes in 0 blocks.
after (running system for ~2m):
==11616== LEAK SUMMARY:
==11616== definitely lost: 7,644 bytes in 137 blocks.
==11616== indirectly lost: 9,981 bytes in 591 blocks.
==11616== possibly lost: 0 bytes in 0 blocks.
==11616== still reachable: 4 bytes in 1 blocks.
==11616== suppressed: 0 bytes in 0 blocks.
Still not perfect but significant improvement.
2008-05-29 17:53:44 -04:00
|
|
|
|
2012-09-28 09:01:02 -04:00
|
|
|
if (s->check.task) {
|
|
|
|
|
task_delete(s->check.task);
|
|
|
|
|
task_free(s->check.task);
|
[MEDIUM] Fix memory freeing at exit
New functions implemented:
- deinit_pollers: called at the end of deinit())
- prune_acl: called via list_for_each_entry_safe
Add missing pool_destroy2 calls:
- p->hdr_idx_pool
- pool2_tree64
Implement all task stopping:
- health-check: needs new "struct task" in the struct server
- queue processing: queue_mgt
- appsess_refresh: appsession_refresh
before (idle system):
==6079== LEAK SUMMARY:
==6079== definitely lost: 1,112 bytes in 75 blocks.
==6079== indirectly lost: 53,356 bytes in 2,090 blocks.
==6079== possibly lost: 52 bytes in 1 blocks.
==6079== still reachable: 150,996 bytes in 504 blocks.
==6079== suppressed: 0 bytes in 0 blocks.
after (idle system):
==6945== LEAK SUMMARY:
==6945== definitely lost: 7,644 bytes in 137 blocks.
==6945== indirectly lost: 9,913 bytes in 587 blocks.
==6945== possibly lost: 0 bytes in 0 blocks.
==6945== still reachable: 0 bytes in 0 blocks.
==6945== suppressed: 0 bytes in 0 blocks.
before (running system for ~2m):
==9343== LEAK SUMMARY:
==9343== definitely lost: 1,112 bytes in 75 blocks.
==9343== indirectly lost: 54,199 bytes in 2,122 blocks.
==9343== possibly lost: 52 bytes in 1 blocks.
==9343== still reachable: 151,128 bytes in 509 blocks.
==9343== suppressed: 0 bytes in 0 blocks.
after (running system for ~2m):
==11616== LEAK SUMMARY:
==11616== definitely lost: 7,644 bytes in 137 blocks.
==11616== indirectly lost: 9,981 bytes in 591 blocks.
==11616== possibly lost: 0 bytes in 0 blocks.
==11616== still reachable: 4 bytes in 1 blocks.
==11616== suppressed: 0 bytes in 0 blocks.
Still not perfect but significant improvement.
2008-05-29 17:53:44 -04:00
|
|
|
}
|
2013-11-24 20:46:36 -05:00
|
|
|
if (s->agent.task) {
|
|
|
|
|
task_delete(s->agent.task);
|
|
|
|
|
task_free(s->agent.task);
|
|
|
|
|
}
|
[MEDIUM] Fix memory freeing at exit
New functions implemented:
- deinit_pollers: called at the end of deinit())
- prune_acl: called via list_for_each_entry_safe
Add missing pool_destroy2 calls:
- p->hdr_idx_pool
- pool2_tree64
Implement all task stopping:
- health-check: needs new "struct task" in the struct server
- queue processing: queue_mgt
- appsess_refresh: appsession_refresh
before (idle system):
==6079== LEAK SUMMARY:
==6079== definitely lost: 1,112 bytes in 75 blocks.
==6079== indirectly lost: 53,356 bytes in 2,090 blocks.
==6079== possibly lost: 52 bytes in 1 blocks.
==6079== still reachable: 150,996 bytes in 504 blocks.
==6079== suppressed: 0 bytes in 0 blocks.
after (idle system):
==6945== LEAK SUMMARY:
==6945== definitely lost: 7,644 bytes in 137 blocks.
==6945== indirectly lost: 9,913 bytes in 587 blocks.
==6945== possibly lost: 0 bytes in 0 blocks.
==6945== still reachable: 0 bytes in 0 blocks.
==6945== suppressed: 0 bytes in 0 blocks.
before (running system for ~2m):
==9343== LEAK SUMMARY:
==9343== definitely lost: 1,112 bytes in 75 blocks.
==9343== indirectly lost: 54,199 bytes in 2,122 blocks.
==9343== possibly lost: 52 bytes in 1 blocks.
==9343== still reachable: 151,128 bytes in 509 blocks.
==9343== suppressed: 0 bytes in 0 blocks.
after (running system for ~2m):
==11616== LEAK SUMMARY:
==11616== definitely lost: 7,644 bytes in 137 blocks.
==11616== indirectly lost: 9,981 bytes in 591 blocks.
==11616== possibly lost: 0 bytes in 0 blocks.
==11616== still reachable: 4 bytes in 1 blocks.
==11616== suppressed: 0 bytes in 0 blocks.
Still not perfect but significant improvement.
2008-05-29 17:53:44 -04:00
|
|
|
|
2011-10-31 06:53:20 -04:00
|
|
|
if (s->warmup) {
|
|
|
|
|
task_delete(s->warmup);
|
|
|
|
|
task_free(s->warmup);
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 06:19:50 -04:00
|
|
|
free(s->id);
|
|
|
|
|
free(s->cookie);
|
2012-09-28 09:28:30 -04:00
|
|
|
free(s->check.bi);
|
|
|
|
|
free(s->check.bo);
|
2013-11-24 20:46:36 -05:00
|
|
|
free(s->agent.bi);
|
|
|
|
|
free(s->agent.bo);
|
2014-09-05 04:08:23 -04:00
|
|
|
free((char*)s->conf.file);
|
2006-06-25 20:48:02 -04:00
|
|
|
free(s);
|
|
|
|
|
s = s_next;
|
|
|
|
|
}/* end while(s) */
|
[MEDIUM] Fix memory freeing at exit
New functions implemented:
- deinit_pollers: called at the end of deinit())
- prune_acl: called via list_for_each_entry_safe
Add missing pool_destroy2 calls:
- p->hdr_idx_pool
- pool2_tree64
Implement all task stopping:
- health-check: needs new "struct task" in the struct server
- queue processing: queue_mgt
- appsess_refresh: appsession_refresh
before (idle system):
==6079== LEAK SUMMARY:
==6079== definitely lost: 1,112 bytes in 75 blocks.
==6079== indirectly lost: 53,356 bytes in 2,090 blocks.
==6079== possibly lost: 52 bytes in 1 blocks.
==6079== still reachable: 150,996 bytes in 504 blocks.
==6079== suppressed: 0 bytes in 0 blocks.
after (idle system):
==6945== LEAK SUMMARY:
==6945== definitely lost: 7,644 bytes in 137 blocks.
==6945== indirectly lost: 9,913 bytes in 587 blocks.
==6945== possibly lost: 0 bytes in 0 blocks.
==6945== still reachable: 0 bytes in 0 blocks.
==6945== suppressed: 0 bytes in 0 blocks.
before (running system for ~2m):
==9343== LEAK SUMMARY:
==9343== definitely lost: 1,112 bytes in 75 blocks.
==9343== indirectly lost: 54,199 bytes in 2,122 blocks.
==9343== possibly lost: 52 bytes in 1 blocks.
==9343== still reachable: 151,128 bytes in 509 blocks.
==9343== suppressed: 0 bytes in 0 blocks.
after (running system for ~2m):
==11616== LEAK SUMMARY:
==11616== definitely lost: 7,644 bytes in 137 blocks.
==11616== indirectly lost: 9,981 bytes in 591 blocks.
==11616== possibly lost: 0 bytes in 0 blocks.
==11616== still reachable: 4 bytes in 1 blocks.
==11616== suppressed: 0 bytes in 0 blocks.
Still not perfect but significant improvement.
2008-05-29 17:53:44 -04:00
|
|
|
|
2012-09-20 10:48:07 -04:00
|
|
|
list_for_each_entry_safe(l, l_next, &p->conf.listeners, by_fe) {
|
2010-09-03 04:38:17 -04:00
|
|
|
unbind_listener(l);
|
|
|
|
|
delete_listener(l);
|
2012-09-20 10:48:07 -04:00
|
|
|
LIST_DEL(&l->by_fe);
|
|
|
|
|
LIST_DEL(&l->by_bind);
|
2010-02-05 14:31:44 -05:00
|
|
|
free(l->name);
|
|
|
|
|
free(l->counters);
|
2006-06-25 20:48:02 -04:00
|
|
|
free(l);
|
2012-09-20 10:48:07 -04:00
|
|
|
}
|
[MEDIUM] Fix memory freeing at exit
New functions implemented:
- deinit_pollers: called at the end of deinit())
- prune_acl: called via list_for_each_entry_safe
Add missing pool_destroy2 calls:
- p->hdr_idx_pool
- pool2_tree64
Implement all task stopping:
- health-check: needs new "struct task" in the struct server
- queue processing: queue_mgt
- appsess_refresh: appsession_refresh
before (idle system):
==6079== LEAK SUMMARY:
==6079== definitely lost: 1,112 bytes in 75 blocks.
==6079== indirectly lost: 53,356 bytes in 2,090 blocks.
==6079== possibly lost: 52 bytes in 1 blocks.
==6079== still reachable: 150,996 bytes in 504 blocks.
==6079== suppressed: 0 bytes in 0 blocks.
after (idle system):
==6945== LEAK SUMMARY:
==6945== definitely lost: 7,644 bytes in 137 blocks.
==6945== indirectly lost: 9,913 bytes in 587 blocks.
==6945== possibly lost: 0 bytes in 0 blocks.
==6945== still reachable: 0 bytes in 0 blocks.
==6945== suppressed: 0 bytes in 0 blocks.
before (running system for ~2m):
==9343== LEAK SUMMARY:
==9343== definitely lost: 1,112 bytes in 75 blocks.
==9343== indirectly lost: 54,199 bytes in 2,122 blocks.
==9343== possibly lost: 52 bytes in 1 blocks.
==9343== still reachable: 151,128 bytes in 509 blocks.
==9343== suppressed: 0 bytes in 0 blocks.
after (running system for ~2m):
==11616== LEAK SUMMARY:
==11616== definitely lost: 7,644 bytes in 137 blocks.
==11616== indirectly lost: 9,981 bytes in 591 blocks.
==11616== possibly lost: 0 bytes in 0 blocks.
==11616== still reachable: 4 bytes in 1 blocks.
==11616== suppressed: 0 bytes in 0 blocks.
Still not perfect but significant improvement.
2008-05-29 17:53:44 -04:00
|
|
|
|
2012-09-20 10:48:07 -04:00
|
|
|
/* Release unused SSL configs. */
|
2012-09-13 11:54:29 -04:00
|
|
|
list_for_each_entry_safe(bind_conf, bind_back, &p->conf.bind, by_fe) {
|
|
|
|
|
#ifdef USE_OPENSSL
|
|
|
|
|
ssl_sock_free_all_ctx(bind_conf);
|
2012-10-05 06:00:26 -04:00
|
|
|
free(bind_conf->ca_file);
|
2012-09-13 11:54:29 -04:00
|
|
|
free(bind_conf->ciphers);
|
2012-09-20 11:10:03 -04:00
|
|
|
free(bind_conf->ecdhe);
|
2012-10-05 06:00:26 -04:00
|
|
|
free(bind_conf->crl_file);
|
2012-09-07 10:58:00 -04:00
|
|
|
#endif /* USE_OPENSSL */
|
2012-09-13 11:54:29 -04:00
|
|
|
free(bind_conf->file);
|
|
|
|
|
free(bind_conf->arg);
|
|
|
|
|
LIST_DEL(&bind_conf->by_fe);
|
|
|
|
|
free(bind_conf);
|
|
|
|
|
}
|
2012-09-07 10:58:00 -04:00
|
|
|
|
2010-02-05 14:31:44 -05:00
|
|
|
free(p->desc);
|
|
|
|
|
free(p->fwdfor_hdr_name);
|
|
|
|
|
|
2011-01-06 11:51:27 -05:00
|
|
|
free_http_req_rules(&p->http_req_rules);
|
2014-06-16 14:05:59 -04:00
|
|
|
free_http_res_rules(&p->http_res_rules);
|
2011-07-25 10:33:49 -04:00
|
|
|
free(p->task);
|
2010-01-29 11:58:21 -05:00
|
|
|
|
2007-05-13 16:46:04 -04:00
|
|
|
pool_destroy2(p->req_cap_pool);
|
|
|
|
|
pool_destroy2(p->rsp_cap_pool);
|
2011-07-15 00:14:10 -04:00
|
|
|
pool_destroy2(p->table.pool);
|
2010-01-29 11:50:44 -05:00
|
|
|
|
2007-05-13 18:39:29 -04:00
|
|
|
p0 = p;
|
2006-06-25 20:48:02 -04:00
|
|
|
p = p->next;
|
2007-05-13 18:39:29 -04:00
|
|
|
free(p0);
|
2006-06-25 20:48:02 -04:00
|
|
|
}/* end while(p) */
|
2007-10-16 06:25:14 -04:00
|
|
|
|
2008-05-31 07:53:23 -04:00
|
|
|
while (ua) {
|
|
|
|
|
uap = ua;
|
|
|
|
|
ua = ua->next;
|
|
|
|
|
|
2008-08-03 06:19:50 -04:00
|
|
|
free(uap->uri_prefix);
|
|
|
|
|
free(uap->auth_realm);
|
2009-10-02 16:51:14 -04:00
|
|
|
free(uap->node);
|
|
|
|
|
free(uap->desc);
|
2008-05-31 07:53:23 -04:00
|
|
|
|
2010-01-29 13:29:32 -05:00
|
|
|
userlist_free(uap->userlist);
|
2011-01-06 11:51:27 -05:00
|
|
|
free_http_req_rules(&uap->http_req_rules);
|
2010-01-29 13:29:32 -05:00
|
|
|
|
2008-05-31 07:53:23 -04:00
|
|
|
free(uap);
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-29 11:50:44 -05:00
|
|
|
userlist_free(userlist);
|
|
|
|
|
|
2007-10-16 06:25:14 -04:00
|
|
|
protocol_unbind_all();
|
|
|
|
|
|
2010-12-29 11:05:48 -05:00
|
|
|
free(global.log_send_hostname); global.log_send_hostname = NULL;
|
2010-12-22 11:08:21 -05:00
|
|
|
free(global.log_tag); global.log_tag = NULL;
|
2008-08-03 06:19:50 -04:00
|
|
|
free(global.chroot); global.chroot = NULL;
|
|
|
|
|
free(global.pidfile); global.pidfile = NULL;
|
2009-10-02 16:51:14 -04:00
|
|
|
free(global.node); global.node = NULL;
|
|
|
|
|
free(global.desc); global.desc = NULL;
|
2013-06-26 04:49:51 -04:00
|
|
|
free(fdinfo); fdinfo = NULL;
|
2008-08-03 06:19:50 -04:00
|
|
|
free(fdtab); fdtab = NULL;
|
|
|
|
|
free(oldpids); oldpids = NULL;
|
2011-08-01 14:57:55 -04:00
|
|
|
free(global_listener_queue_task); global_listener_queue_task = NULL;
|
2008-05-31 07:53:23 -04:00
|
|
|
|
2011-10-12 11:50:54 -04:00
|
|
|
list_for_each_entry_safe(log, logb, &global.logsrvs, list) {
|
|
|
|
|
LIST_DEL(&log->list);
|
|
|
|
|
free(log);
|
|
|
|
|
}
|
2010-01-03 15:12:30 -05:00
|
|
|
list_for_each_entry_safe(wl, wlb, &cfg_cfgfiles, list) {
|
|
|
|
|
LIST_DEL(&wl->list);
|
|
|
|
|
free(wl);
|
|
|
|
|
}
|
|
|
|
|
|
REORG/MAJOR: session: rename the "session" entity to "stream"
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.
In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.
The files stream.{c,h} were added and session.{c,h} removed.
The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.
Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.
Once all changes are completed, we should see approximately this :
L7 - http_txn
L6 - stream
L5 - session
L4 - connection | applet
There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.
Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
2015-04-02 18:22:06 -04:00
|
|
|
pool_destroy2(pool2_stream);
|
2015-04-03 08:10:06 -04:00
|
|
|
pool_destroy2(pool2_session);
|
2012-10-26 14:10:28 -04:00
|
|
|
pool_destroy2(pool2_connection);
|
2012-10-12 17:49:43 -04:00
|
|
|
pool_destroy2(pool2_buffer);
|
2007-05-13 15:36:56 -04:00
|
|
|
pool_destroy2(pool2_requri);
|
2007-05-13 13:43:47 -04:00
|
|
|
pool_destroy2(pool2_task);
|
2007-05-13 15:45:51 -04:00
|
|
|
pool_destroy2(pool2_capture);
|
2007-05-13 15:29:55 -04:00
|
|
|
pool_destroy2(pool2_appsess);
|
2007-05-13 14:19:55 -04:00
|
|
|
pool_destroy2(pool2_pendconn);
|
2010-08-27 11:56:48 -04:00
|
|
|
pool_destroy2(pool2_sig_handlers);
|
2011-10-24 12:15:04 -04:00
|
|
|
pool_destroy2(pool2_hdr_idx);
|
2015-04-03 16:55:33 -04:00
|
|
|
pool_destroy2(pool2_http_txn);
|
2006-06-25 20:48:02 -04:00
|
|
|
|
|
|
|
|
if (have_appsession) {
|
2007-05-13 15:29:55 -04:00
|
|
|
pool_destroy2(apools.serverid);
|
|
|
|
|
pool_destroy2(apools.sessid);
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
[MEDIUM] Fix memory freeing at exit
New functions implemented:
- deinit_pollers: called at the end of deinit())
- prune_acl: called via list_for_each_entry_safe
Add missing pool_destroy2 calls:
- p->hdr_idx_pool
- pool2_tree64
Implement all task stopping:
- health-check: needs new "struct task" in the struct server
- queue processing: queue_mgt
- appsess_refresh: appsession_refresh
before (idle system):
==6079== LEAK SUMMARY:
==6079== definitely lost: 1,112 bytes in 75 blocks.
==6079== indirectly lost: 53,356 bytes in 2,090 blocks.
==6079== possibly lost: 52 bytes in 1 blocks.
==6079== still reachable: 150,996 bytes in 504 blocks.
==6079== suppressed: 0 bytes in 0 blocks.
after (idle system):
==6945== LEAK SUMMARY:
==6945== definitely lost: 7,644 bytes in 137 blocks.
==6945== indirectly lost: 9,913 bytes in 587 blocks.
==6945== possibly lost: 0 bytes in 0 blocks.
==6945== still reachable: 0 bytes in 0 blocks.
==6945== suppressed: 0 bytes in 0 blocks.
before (running system for ~2m):
==9343== LEAK SUMMARY:
==9343== definitely lost: 1,112 bytes in 75 blocks.
==9343== indirectly lost: 54,199 bytes in 2,122 blocks.
==9343== possibly lost: 52 bytes in 1 blocks.
==9343== still reachable: 151,128 bytes in 509 blocks.
==9343== suppressed: 0 bytes in 0 blocks.
after (running system for ~2m):
==11616== LEAK SUMMARY:
==11616== definitely lost: 7,644 bytes in 137 blocks.
==11616== indirectly lost: 9,981 bytes in 591 blocks.
==11616== possibly lost: 0 bytes in 0 blocks.
==11616== still reachable: 4 bytes in 1 blocks.
==11616== suppressed: 0 bytes in 0 blocks.
Still not perfect but significant improvement.
2008-05-29 17:53:44 -04:00
|
|
|
|
|
|
|
|
deinit_pollers();
|
2006-06-25 20:48:02 -04:00
|
|
|
} /* end deinit() */
|
|
|
|
|
|
2010-08-25 06:58:59 -04:00
|
|
|
/* sends the signal <sig> to all pids found in <oldpids>. Returns the number of
|
|
|
|
|
* pids the signal was correctly delivered to.
|
|
|
|
|
*/
|
|
|
|
|
static int tell_old_pids(int sig)
|
2006-06-25 20:48:02 -04:00
|
|
|
{
|
|
|
|
|
int p;
|
2010-08-25 06:58:59 -04:00
|
|
|
int ret = 0;
|
2006-06-25 20:48:02 -04:00
|
|
|
for (p = 0; p < nb_oldpids; p++)
|
2010-08-25 06:58:59 -04:00
|
|
|
if (kill(oldpids[p], sig) == 0)
|
|
|
|
|
ret++;
|
|
|
|
|
return ret;
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
|
|
|
|
|
2011-07-25 10:33:49 -04:00
|
|
|
/* Runs the polling loop */
|
2007-04-08 10:39:58 -04:00
|
|
|
void run_poll_loop()
|
|
|
|
|
{
|
2008-07-06 18:09:58 -04:00
|
|
|
int next;
|
2007-04-08 10:39:58 -04:00
|
|
|
|
2008-06-23 08:00:57 -04:00
|
|
|
tv_update_date(0,1);
|
2007-04-08 10:39:58 -04:00
|
|
|
while (1) {
|
2014-12-15 07:26:01 -05:00
|
|
|
/* Process a few tasks */
|
|
|
|
|
process_runnable_tasks();
|
|
|
|
|
|
2009-05-10 03:01:21 -04:00
|
|
|
/* check if we caught some signals and process them */
|
|
|
|
|
signal_process_queue();
|
|
|
|
|
|
2008-06-29 16:40:23 -04:00
|
|
|
/* Check if we can expire some tasks */
|
2014-12-15 07:26:01 -05:00
|
|
|
next = wake_expired_tasks();
|
2007-04-08 10:39:58 -04:00
|
|
|
|
2010-08-31 09:39:26 -04:00
|
|
|
/* stop when there's nothing left to do */
|
|
|
|
|
if (jobs == 0)
|
2007-04-08 10:39:58 -04:00
|
|
|
break;
|
|
|
|
|
|
2015-04-13 14:44:19 -04:00
|
|
|
/* expire immediately if events are pending */
|
2015-04-19 03:59:31 -04:00
|
|
|
if (fd_cache_num || run_queue || signal_queue_len || !LIST_ISEMPTY(&applet_runq))
|
2015-04-13 14:44:19 -04:00
|
|
|
next = now_ms;
|
|
|
|
|
|
2008-06-29 16:40:23 -04:00
|
|
|
/* The poller will ensure it returns around <next> */
|
2008-07-06 18:09:58 -04:00
|
|
|
cur_poller.poll(&cur_poller, next);
|
2014-01-25 13:24:15 -05:00
|
|
|
fd_process_cached_events();
|
2015-04-19 03:59:31 -04:00
|
|
|
applet_run_active();
|
2007-04-08 10:39:58 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-01 14:57:55 -04:00
|
|
|
/* This is the global management task for listeners. It enables listeners waiting
|
|
|
|
|
* for global resources when there are enough free resource, or at least once in
|
|
|
|
|
* a while. It is designed to be called as a task.
|
|
|
|
|
*/
|
|
|
|
|
static struct task *manage_global_listener_queue(struct task *t)
|
|
|
|
|
{
|
|
|
|
|
int next = TICK_ETERNITY;
|
|
|
|
|
/* queue is empty, nothing to do */
|
|
|
|
|
if (LIST_ISEMPTY(&global_listener_queue))
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
/* If there are still too many concurrent connections, let's wait for
|
|
|
|
|
* some of them to go away. We don't need to re-arm the timer because
|
|
|
|
|
* each of them will scan the queue anyway.
|
|
|
|
|
*/
|
|
|
|
|
if (unlikely(actconn >= global.maxconn))
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
/* We should periodically try to enable listeners waiting for a global
|
|
|
|
|
* resource here, because it is possible, though very unlikely, that
|
|
|
|
|
* they have been blocked by a temporary lack of global resource such
|
|
|
|
|
* as a file descriptor or memory and that the temporary condition has
|
|
|
|
|
* disappeared.
|
|
|
|
|
*/
|
2011-09-07 08:26:33 -04:00
|
|
|
dequeue_all_listeners(&global_listener_queue);
|
2011-08-01 14:57:55 -04:00
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
t->expire = next;
|
|
|
|
|
task_queue(t);
|
|
|
|
|
return t;
|
|
|
|
|
}
|
2007-04-08 10:39:58 -04:00
|
|
|
|
2006-06-25 20:48:02 -04:00
|
|
|
int main(int argc, char **argv)
|
|
|
|
|
{
|
|
|
|
|
int err, retry;
|
|
|
|
|
struct rlimit limit;
|
2010-10-22 10:06:11 -04:00
|
|
|
char errmsg[100];
|
2012-09-05 02:02:48 -04:00
|
|
|
int pidfd = -1;
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2010-10-22 10:06:11 -04:00
|
|
|
init(argc, argv);
|
2010-08-27 11:56:48 -04:00
|
|
|
signal_register_fct(SIGQUIT, dump, SIGQUIT);
|
|
|
|
|
signal_register_fct(SIGUSR1, sig_soft_stop, SIGUSR1);
|
|
|
|
|
signal_register_fct(SIGHUP, sig_dump_state, SIGHUP);
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2010-03-17 13:02:46 -04:00
|
|
|
/* Always catch SIGPIPE even on platforms which define MSG_NOSIGNAL.
|
|
|
|
|
* Some recent FreeBSD setups report broken pipes, and MSG_NOSIGNAL
|
|
|
|
|
* was defined there, so let's stay on the safe side.
|
2006-06-25 20:48:02 -04:00
|
|
|
*/
|
2010-08-27 11:56:48 -04:00
|
|
|
signal_register_fct(SIGPIPE, NULL, 0);
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2011-02-16 05:10:36 -05:00
|
|
|
/* ulimits */
|
|
|
|
|
if (!global.rlimit_nofile)
|
|
|
|
|
global.rlimit_nofile = global.maxsock;
|
|
|
|
|
|
|
|
|
|
if (global.rlimit_nofile) {
|
|
|
|
|
limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
|
|
|
|
|
if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
|
|
|
|
|
Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (global.rlimit_memmax) {
|
|
|
|
|
limit.rlim_cur = limit.rlim_max =
|
|
|
|
|
global.rlimit_memmax * 1048576 / global.nbproc;
|
|
|
|
|
#ifdef RLIMIT_AS
|
|
|
|
|
if (setrlimit(RLIMIT_AS, &limit) == -1) {
|
|
|
|
|
Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
|
|
|
|
|
argv[0], global.rlimit_memmax);
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
if (setrlimit(RLIMIT_DATA, &limit) == -1) {
|
|
|
|
|
Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
|
|
|
|
|
argv[0], global.rlimit_memmax);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2006-06-25 20:48:02 -04:00
|
|
|
/* We will loop at most 100 times with 10 ms delay each time.
|
|
|
|
|
* That's at most 1 second. We only send a signal to old pids
|
|
|
|
|
* if we cannot grab at least one port.
|
|
|
|
|
*/
|
|
|
|
|
retry = MAX_START_RETRIES;
|
|
|
|
|
err = ERR_NONE;
|
|
|
|
|
while (retry >= 0) {
|
|
|
|
|
struct timeval w;
|
|
|
|
|
err = start_proxies(retry == 0 || nb_oldpids == 0);
|
2007-12-20 17:05:50 -05:00
|
|
|
/* exit the loop on no error or fatal error */
|
|
|
|
|
if ((err & (ERR_RETRYABLE|ERR_FATAL)) != ERR_RETRYABLE)
|
2006-06-25 20:48:02 -04:00
|
|
|
break;
|
2010-08-25 06:58:59 -04:00
|
|
|
if (nb_oldpids == 0 || retry == 0)
|
2006-06-25 20:48:02 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* FIXME-20060514: Solaris and OpenBSD do not support shutdown() on
|
|
|
|
|
* listening sockets. So on those platforms, it would be wiser to
|
|
|
|
|
* simply send SIGUSR1, which will not be undoable.
|
|
|
|
|
*/
|
2010-08-25 06:58:59 -04:00
|
|
|
if (tell_old_pids(SIGTTOU) == 0) {
|
|
|
|
|
/* no need to wait if we can't contact old pids */
|
|
|
|
|
retry = 0;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2006-06-25 20:48:02 -04:00
|
|
|
/* give some time to old processes to stop listening */
|
|
|
|
|
w.tv_sec = 0;
|
|
|
|
|
w.tv_usec = 10*1000;
|
|
|
|
|
select(0, NULL, NULL, NULL, &w);
|
|
|
|
|
retry--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Note: start_proxies() sends an alert when it fails. */
|
2009-02-04 11:05:23 -05:00
|
|
|
if ((err & ~ERR_WARN) != ERR_NONE) {
|
2009-06-09 08:36:00 -04:00
|
|
|
if (retry != MAX_START_RETRIES && nb_oldpids) {
|
|
|
|
|
protocol_unbind_all(); /* cleanup everything we can */
|
2006-06-25 20:48:02 -04:00
|
|
|
tell_old_pids(SIGTTIN);
|
2009-06-09 08:36:00 -04:00
|
|
|
}
|
2006-06-25 20:48:02 -04:00
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (listeners == 0) {
|
|
|
|
|
Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
|
|
|
|
|
/* Note: we don't have to send anything to the old pids because we
|
|
|
|
|
* never stopped them. */
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-22 10:06:11 -04:00
|
|
|
err = protocol_bind_all(errmsg, sizeof(errmsg));
|
|
|
|
|
if ((err & ~ERR_WARN) != ERR_NONE) {
|
|
|
|
|
if ((err & ERR_ALERT) || (err & ERR_WARN))
|
|
|
|
|
Alert("[%s.main()] %s.\n", argv[0], errmsg);
|
|
|
|
|
|
2007-10-16 06:25:14 -04:00
|
|
|
Alert("[%s.main()] Some protocols failed to start their listeners! Exiting.\n", argv[0]);
|
|
|
|
|
protocol_unbind_all(); /* cleanup everything we can */
|
|
|
|
|
if (nb_oldpids)
|
|
|
|
|
tell_old_pids(SIGTTIN);
|
|
|
|
|
exit(1);
|
2010-10-22 10:06:11 -04:00
|
|
|
} else if (err & ERR_WARN) {
|
|
|
|
|
Alert("[%s.main()] %s.\n", argv[0], errmsg);
|
2007-10-16 06:25:14 -04:00
|
|
|
}
|
|
|
|
|
|
2006-06-25 20:48:02 -04:00
|
|
|
/* prepare pause/play signals */
|
2010-08-27 11:56:48 -04:00
|
|
|
signal_register_fct(SIGTTOU, sig_pause, SIGTTOU);
|
|
|
|
|
signal_register_fct(SIGTTIN, sig_listen, SIGTTIN);
|
2006-06-25 20:48:02 -04:00
|
|
|
|
|
|
|
|
/* MODE_QUIET can inhibit alerts and warnings below this line */
|
|
|
|
|
|
|
|
|
|
global.mode &= ~MODE_STARTING;
|
|
|
|
|
if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
|
|
|
|
|
/* detach from the tty */
|
|
|
|
|
fclose(stdin); fclose(stdout); fclose(stderr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* open log & pid files before the chroot */
|
2013-02-12 04:53:52 -05:00
|
|
|
if (global.mode & (MODE_DAEMON | MODE_SYSTEMD) && global.pidfile != NULL) {
|
2006-06-25 20:48:02 -04:00
|
|
|
unlink(global.pidfile);
|
|
|
|
|
pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
|
|
|
|
|
if (pidfd < 0) {
|
|
|
|
|
Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
|
|
|
|
|
if (nb_oldpids)
|
|
|
|
|
tell_old_pids(SIGTTIN);
|
2007-10-16 06:25:14 -04:00
|
|
|
protocol_unbind_all();
|
2006-06-25 20:48:02 -04:00
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-03-24 12:24:39 -04:00
|
|
|
#ifdef CONFIG_HAP_CTTPROXY
|
|
|
|
|
if (global.last_checks & LSTCHK_CTTPROXY) {
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
ret = check_cttproxy_version();
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
Alert("[%s.main()] Cannot enable cttproxy.\n%s",
|
|
|
|
|
argv[0],
|
|
|
|
|
(ret == -1) ? " Incorrect module version.\n"
|
|
|
|
|
: " Make sure you have enough permissions and that the module is loaded.\n");
|
2007-10-16 06:25:14 -04:00
|
|
|
protocol_unbind_all();
|
2007-03-24 12:24:39 -04:00
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if ((global.last_checks & LSTCHK_NETADM) && global.uid) {
|
|
|
|
|
Alert("[%s.main()] Some configuration options require full privileges, so global.uid cannot be changed.\n"
|
2009-02-04 12:02:48 -05:00
|
|
|
"", argv[0]);
|
2007-10-16 06:25:14 -04:00
|
|
|
protocol_unbind_all();
|
2007-03-24 12:24:39 -04:00
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-04 12:02:48 -05:00
|
|
|
/* If the user is not root, we'll still let him try the configuration
|
|
|
|
|
* but we inform him that unexpected behaviour may occur.
|
|
|
|
|
*/
|
|
|
|
|
if ((global.last_checks & LSTCHK_NETADM) && getuid())
|
|
|
|
|
Warning("[%s.main()] Some options which require full privileges"
|
|
|
|
|
" might not work well.\n"
|
|
|
|
|
"", argv[0]);
|
|
|
|
|
|
2007-10-15 12:57:08 -04:00
|
|
|
/* chroot if needed */
|
|
|
|
|
if (global.chroot != NULL) {
|
2012-04-29 08:11:38 -04:00
|
|
|
if (chroot(global.chroot) == -1 || chdir("/") == -1) {
|
2007-10-15 12:57:08 -04:00
|
|
|
Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
|
|
|
|
|
if (nb_oldpids)
|
|
|
|
|
tell_old_pids(SIGTTIN);
|
2007-10-16 06:25:14 -04:00
|
|
|
protocol_unbind_all();
|
2007-10-15 12:57:08 -04:00
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-06-25 20:48:02 -04:00
|
|
|
if (nb_oldpids)
|
2010-08-25 06:58:59 -04:00
|
|
|
nb_oldpids = tell_old_pids(oldpids_sig);
|
2006-06-25 20:48:02 -04:00
|
|
|
|
|
|
|
|
/* Note that any error at this stage will be fatal because we will not
|
|
|
|
|
* be able to restart the old pids.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* setgid / setuid */
|
BUG/MEDIUM: remove supplementary groups when changing gid
Without it, haproxy will retain the group membership of root, which may
give more access than intended to the process. For example, haproxy would
still be in the wheel group on Fedora 18, as seen with :
# haproxy -f /etc/haproxy/haproxy.cfg
# ps a -o pid,user,group,command | grep hapr
3545 haproxy haproxy haproxy -f /etc/haproxy/haproxy.cfg
4356 root root grep --color=auto hapr
# grep Group /proc/3545/status
Groups: 0 1 2 3 4 6 10
# getent group wheel
wheel:x:10:root,misc
[WT: The issue has been investigated by independent security research team
and realized by itself not being able to allow security exploitation.
Additionally, dropping groups is not allowed to unprivileged users,
though this mode of deployment is quite common. Thus a warning is
emitted in this case to inform the user. The fix could be backported
into all supported versions as the issue has always been there. ]
2013-01-12 12:35:19 -05:00
|
|
|
if (global.gid) {
|
|
|
|
|
if (getgroups(0, NULL) > 0 && setgroups(0, NULL) == -1)
|
|
|
|
|
Warning("[%s.main()] Failed to drop supplementary groups. Using 'gid'/'group'"
|
|
|
|
|
" without 'uid'/'user' is generally useless.\n", argv[0]);
|
|
|
|
|
|
|
|
|
|
if (setgid(global.gid) == -1) {
|
|
|
|
|
Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
|
|
|
|
|
protocol_unbind_all();
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (global.uid && setuid(global.uid) == -1) {
|
|
|
|
|
Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
|
2007-10-16 06:25:14 -04:00
|
|
|
protocol_unbind_all();
|
2006-06-25 20:48:02 -04:00
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* check ulimits */
|
|
|
|
|
limit.rlim_cur = limit.rlim_max = 0;
|
|
|
|
|
getrlimit(RLIMIT_NOFILE, &limit);
|
|
|
|
|
if (limit.rlim_cur < global.maxsock) {
|
|
|
|
|
Warning("[%s.main()] FD limit (%d) too low for maxconn=%d/maxsock=%d. Please raise 'ulimit-n' to %d or more to avoid any trouble.\n",
|
2009-04-03 08:49:12 -04:00
|
|
|
argv[0], (int)limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
|
|
|
|
|
2013-02-12 04:53:52 -05:00
|
|
|
if (global.mode & (MODE_DAEMON | MODE_SYSTEMD)) {
|
2009-02-04 16:05:05 -05:00
|
|
|
struct proxy *px;
|
2006-06-25 20:48:02 -04:00
|
|
|
int ret = 0;
|
2013-02-12 04:53:52 -05:00
|
|
|
int *children = calloc(global.nbproc, sizeof(int));
|
2006-06-25 20:48:02 -04:00
|
|
|
int proc;
|
|
|
|
|
|
|
|
|
|
/* the father launches the required number of processes */
|
|
|
|
|
for (proc = 0; proc < global.nbproc; proc++) {
|
|
|
|
|
ret = fork();
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
Alert("[%s.main()] Cannot fork.\n", argv[0]);
|
2007-10-16 06:25:14 -04:00
|
|
|
protocol_unbind_all();
|
2007-10-16 01:44:56 -04:00
|
|
|
exit(1); /* there has been an error */
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
|
|
|
|
else if (ret == 0) /* child breaks here */
|
|
|
|
|
break;
|
2013-02-12 04:53:52 -05:00
|
|
|
children[proc] = ret;
|
2012-09-05 02:02:48 -04:00
|
|
|
if (pidfd >= 0) {
|
|
|
|
|
char pidstr[100];
|
|
|
|
|
snprintf(pidstr, sizeof(pidstr), "%d\n", ret);
|
2013-12-13 09:14:55 -05:00
|
|
|
shut_your_big_mouth_gcc(write(pidfd, pidstr, strlen(pidstr)));
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
2007-11-04 17:35:08 -05:00
|
|
|
relative_pid++; /* each child will get a different one */
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
2012-11-16 10:12:27 -05:00
|
|
|
|
|
|
|
|
#ifdef USE_CPU_AFFINITY
|
|
|
|
|
if (proc < global.nbproc && /* child */
|
2015-04-20 05:36:57 -04:00
|
|
|
proc < LONGBITS && /* only the first 32/64 processes may be pinned */
|
2012-11-16 10:12:27 -05:00
|
|
|
global.cpu_map[proc]) /* only do this if the process has a CPU map */
|
|
|
|
|
sched_setaffinity(0, sizeof(unsigned long), (void *)&global.cpu_map[proc]);
|
|
|
|
|
#endif
|
2006-06-25 20:48:02 -04:00
|
|
|
/* close the pidfile both in children and father */
|
2012-09-05 02:02:48 -04:00
|
|
|
if (pidfd >= 0) {
|
|
|
|
|
//lseek(pidfd, 0, SEEK_SET); /* debug: emulate eglibc bug */
|
|
|
|
|
close(pidfd);
|
|
|
|
|
}
|
2010-08-25 06:49:05 -04:00
|
|
|
|
|
|
|
|
/* We won't ever use this anymore */
|
|
|
|
|
free(oldpids); oldpids = NULL;
|
|
|
|
|
free(global.chroot); global.chroot = NULL;
|
|
|
|
|
free(global.pidfile); global.pidfile = NULL;
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2009-02-04 16:05:05 -05:00
|
|
|
/* we might have to unbind some proxies from some processes */
|
|
|
|
|
px = proxy;
|
|
|
|
|
while (px != NULL) {
|
|
|
|
|
if (px->bind_proc && px->state != PR_STSTOPPED) {
|
2013-01-18 05:29:29 -05:00
|
|
|
if (!(px->bind_proc & (1UL << proc)))
|
2009-02-04 16:05:05 -05:00
|
|
|
stop_proxy(px);
|
|
|
|
|
}
|
|
|
|
|
px = px->next;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-12 04:53:52 -05:00
|
|
|
if (proc == global.nbproc) {
|
|
|
|
|
if (global.mode & MODE_SYSTEMD) {
|
BUG/MEDIUM: Fix unhandled connections problem with systemd daemon mode and SO_REUSEPORT.
Using the systemd daemon mode the parent doesn't exits but waits for
his childs without closing its listening sockets.
As linux 3.9 introduced a SO_REUSEPORT option (always enabled in
haproxy if available) this will give unhandled connections problems
after an haproxy reload with open connections.
The problem is that when on reload a new parent is started (-Ds
$oldchildspids), in haproxy.c main there's a call to start_proxies
that, without SO_REUSEPORT, should fail (as the old processes are
already listening) and so a SIGTOU is sent to old processes. On this
signal the old childs will call (in pause_listener) a shutdown() on
the listening fd. From my tests (if I understand it correctly) this
affects the in kernel file (so the listen is really disabled for all
the processes, also the parent).
Instead, with SO_REUSEPORT, the call to start_proxies doesn't fail and
so SIGTOU is never sent. Only SIGUSR1 is sent and the listen isn't
disabled for the parent but only the childs will stop listening (with
a call to close())
So, with SO_REUSEPORT, the old childs will close their listening
sockets but will wait for the current connections to finish or
timeout, and, as their parent has its listening socket open, the
kernel will schedule some connections on it. These connections will
never be accepted by the parent as it's in the waitpid loop.
This fix will close all the listeners on the parent before entering the
waitpid loop.
Signed-off-by: Simone Gotti <simone.gotti@gmail.com>
2014-06-10 18:15:51 -04:00
|
|
|
protocol_unbind_all();
|
2013-02-12 04:53:52 -05:00
|
|
|
for (proc = 0; proc < global.nbproc; proc++)
|
|
|
|
|
while (waitpid(children[proc], NULL, 0) == -1 && errno == EINTR);
|
|
|
|
|
}
|
2006-06-25 20:48:02 -04:00
|
|
|
exit(0); /* parent must leave */
|
2013-02-12 04:53:52 -05:00
|
|
|
}
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2014-04-28 18:57:16 -04:00
|
|
|
free(children);
|
|
|
|
|
children = NULL;
|
2006-06-25 20:48:02 -04:00
|
|
|
/* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
|
|
|
|
|
* that we can detach from the TTY. We MUST NOT do it in other cases since
|
|
|
|
|
* it would have already be done, and 0-2 would have been affected to listening
|
|
|
|
|
* sockets
|
|
|
|
|
*/
|
2008-11-16 01:40:34 -05:00
|
|
|
if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
|
2006-06-25 20:48:02 -04:00
|
|
|
/* detach from the tty */
|
|
|
|
|
fclose(stdin); fclose(stdout); fclose(stderr);
|
2008-11-16 01:40:34 -05:00
|
|
|
global.mode &= ~MODE_VERBOSE;
|
2006-06-25 20:48:02 -04:00
|
|
|
global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
|
|
|
|
|
}
|
|
|
|
|
pid = getpid(); /* update child's pid */
|
|
|
|
|
setsid();
|
2007-04-09 13:29:56 -04:00
|
|
|
fork_poller();
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
|
|
|
|
|
2007-10-16 06:25:14 -04:00
|
|
|
protocol_enable_all();
|
2007-04-08 10:39:58 -04:00
|
|
|
/*
|
|
|
|
|
* That's it : the central polling loop. Run until we stop.
|
|
|
|
|
*/
|
|
|
|
|
run_poll_loop();
|
2006-06-25 20:48:02 -04:00
|
|
|
|
|
|
|
|
/* Free all Hash Keys and all Hash elements */
|
|
|
|
|
appsession_cleanup();
|
|
|
|
|
/* Do some cleanup */
|
|
|
|
|
deinit();
|
|
|
|
|
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Local variables:
|
|
|
|
|
* c-indent-level: 8
|
|
|
|
|
* c-basic-offset: 8
|
|
|
|
|
* End:
|
|
|
|
|
*/
|