Commit Graph

4675 Commits

Author SHA1 Message Date
William Lallemand
933efcd01a REORG: cli: move 'show backend' to proxy.c
Move 'show backend' CLI functions to proxy.c and use the cli keyword API
to register it on the CLI.
2016-11-24 16:59:27 +01:00
William Lallemand
4c5b4d531c REORG: cli: move 'show sess' to stream.c
Move 'show sess' CLI functions to stream.c and use the cli keyword API
to register it on the CLI.

[wt: the choice of stream vs session makes sense because since 1.6 these
 really are streams that we're dumping and not sessions anymore]
2016-11-24 16:59:27 +01:00
William Lallemand
a6c5f3372d REORG: cli: move 'show servers' to proxy.c
Move 'show servers' CLI functions to proxy.c and use the cli keyword
API to register it on the CLI.
2016-11-24 16:59:27 +01:00
William Lallemand
e7ed8855de REORG: cli: move 'show pools' to memory.c
Move 'show pools' CLI functions to memory.c and use the cli keyword
API to register it on the CLI.
2016-11-24 16:59:27 +01:00
William Lallemand
222baf20da REORG: cli: move 'set server' to server.c
Move 'set server' CLI functions to server.c and use the cli keyword API
to register it on the CLI.
2016-11-24 16:59:27 +01:00
Willy Tarreau
960f2cb056 MINOR: proxy: create new function cli_find_frontend() to find a frontend
Several CLI commands require a frontend, so let's have a function to
look this one up and prepare the appropriate error message and the
appctx's state in case of failure.
2016-11-24 16:59:27 +01:00
Willy Tarreau
21b069dca8 MINOR: server: create new function cli_find_server() to find a server
Several CLI commands require a server, so let's have a function to
look this one up and prepare the appropriate error message and the
appctx's state in case of failure.
2016-11-24 16:59:27 +01:00
Willy Tarreau
de57a578ba MINOR: cli: create new function cli_has_level() to validate permissions
This function is used to check that the CLI features the appropriate
level of permissions or to prepare the adequate error message.
2016-11-24 16:59:27 +01:00
William Lallemand
69e9644e35 REORG: cli: move show stat resolvers to dns.c
Move dns CLI functions to dns.c and use the cli keyword API to register
actions on the CLI.
2016-11-24 16:59:27 +01:00
William Lallemand
ad8be61c7e REORG: cli: move map and acl code to map.c
Move map and acl CLI functions to map.c and use the cli keyword API to
register actions on the CLI. Then remove the now unused individual
"add" and "del" keywords.
2016-11-24 16:59:27 +01:00
William Lallemand
32af203b75 REORG: cli: move ssl CLI functions to ssl_sock.c
Move ssl CLI functions to ssl_sock.c and use the cli keyword API to
register ssl actions on the CLI.
2016-11-24 16:59:27 +01:00
William Lallemand
9ed6203aef REORG: cli: split dumpstats.h in stats.h and cli.h
proto/dumpstats.h has been split in 4 files:

  * proto/cli.h  contains protypes for the CLI
  * proto/stats.h contains prototypes for the stats
  * types/cli.h contains definition for the CLI
  * types/stats.h contains definition for the stats
2016-11-24 16:59:27 +01:00
William Lallemand
74c24fb071 REORG: cli: split dumpstats.c in src/cli.c and src/stats.c
dumpstats.c was containing either the stats code and the CLI code.
The cli code has been moved to cli.c and the stats code to stats.c
2016-11-24 16:59:27 +01:00
Willy Tarreau
8e0bb0ae16 MINOR: connection: add names for transport and data layers
This makes debugging easier and avoids having to put ugly checks
against certain well-known internal struct pointers.
2016-11-24 16:58:12 +01:00
Willy Tarreau
2b5e6315a3 BUG/MINOR: cli: wake up the CLI's task after a timeout update
When the CLI's timeout is reduced, nothing was done to take the task
up to update it. In the past it used to run inside process_stream()
so it used to be refreshed. This is not the case anymore since we have
the appctx so the task needs to be woken up in order to recompute the
new expiration date.

This fix needs to be backported to 1.6.
2016-11-24 15:35:16 +01:00
Willy Tarreau
74a5a9828b BUG/MINOR: cli: dequeue from the proxy when changing a maxconn
The "set maxconn frontend" statement on the CLI tries to dequeue possibly
pending requests, but due to a copy-paste error, they're dequeued on the
CLI's frontend instead of the one being changed.

The impact is very minor as it only means that possibly pending connections
will still have to wait for a previous one to complete before being accepted
when a limit is raised.

This fix has to be backported to 1.6 and 1.5.
2016-11-24 15:34:34 +01:00
Willy Tarreau
578fa0259f BUG/MINOR: cli: fix pointer size when reporting data/transport layer name
In dumpstats.c we have get_conn_xprt_name() and get_conn_data_name() to
report the name of the data and transport layers used on a connection.
But when the name is not known, its pointer is reported instead. But the
static char used to report the pointer is too small as it doesn't leave
room for '0x'. Fortunately all subsystems are known so we never trigger
this case.

This fix needs to be backported to 1.6 and 1.5.
2016-11-24 15:21:26 +01:00
David Carlier
327298c215 BUILD: fix build on Solaris 10/11
uint16_t instead of u_int16_t
None ISO fields of struct tm are not present, but
by zeroyfing it, on GNU and BSD systems tm_gmtoff
field will be set.

[wt: moved the memset into each of the date functions]
2016-11-22 12:04:19 +01:00
Christopher Faulet
985532d1d8 MINOR: spoe: Add "option set-on-error" statement
It defines the variable to set when an error occurred during an event
processing. It will only be set when an error occurred in the scope of the
transaction. As for all other variables define by the SPOE, it will be
prefixed. So, if your variable name is "error" and your prefix is "my_spoe_pfx",
the variable will be "txn.my_spoe_pfx.error".

When set, the variable is the boolean "true". Note that if "option
continue-on-error" is set, the variable is not automatically removed between
events processing.
2016-11-21 15:29:59 +01:00
Christopher Faulet
4802672274 MINOR: spoe: Add "maxconnrate" and "maxerrrate" statements
"maxconnrate" is the maximum number of connections per second. The SPOE will
stop to open new connections if the maximum is reached and will wait to acquire
an existing one.

"maxerrrate" is the maximum number of errors per second. The SPOE will stop its
processing if the maximum is reached.

These options replace hardcoded macros MAX_NEW_SPOE_APPLETS and
MAX_NEW_SPOE_APPLET_ERRS. We use it to limit SPOE activity, especially when
servers are down..
2016-11-21 15:29:59 +01:00
Christopher Faulet
ea62c2a345 MINOR: spoe: Add 'option continue-on-error' statement in spoe-agent section
By default, for a specific stream, when an abnormal/unexpected error occurs, the
SPOE is disabled for all the transaction. So if you have several events
configured, such error on an event will disabled all followings. For TCP
streams, this will disable the SPOE for the whole session. For HTTP streams,
this will disable it for the transaction (request and response).

To bypass this behaviour, you can set 'continue-on-error' option in 'spoe-agent'
section. With this option, only the current event will be ignored.
2016-11-21 15:29:59 +01:00
Christopher Faulet
03a3449e1a MINOR: spoe: Remove useless 'timeout ack' option
To limit the time to process an event, you should set 'timeout processing'
option. So 'timeout ack' option is redundant and useless.
2016-11-21 15:29:59 +01:00
Christopher Faulet
f7a3092512 MINOR: spoe: Add 'timeout processing' option to limit time to process an event
It is a way to set the maximum time to wait for a stream to process an event,
i.e to acquire a stream to talk with an agent, to encode all messages, to send
the NOTIFY frame, to receive the corrsponding acknowledgement and to process all
actions. It is applied on the stream that handle the client and the server
sessions.
2016-11-21 15:29:59 +01:00
Christopher Faulet
a00d817aba MINOR: filters: Add check_timeouts callback to handle timers expiration on streams
A filter can now be notified when a stream is woken up because of an expired
timer.

The documentation and the TRACE filter have been updated.
2016-11-21 15:29:58 +01:00
Thierry FOURNIER / OZON.IO
8dc7316a6f BUG/MEDIUM: lua: In some case, the return of sample-fetche is ignored
When:

 - A Lua action return data and close the channel. The request status
   is set to HTTP_MSG_CLOSED for the request and HTTP_MSG_DONE for the
   response.

 - HAProxy sets the state HTTP_MSG_ERROR. I don't known why, because
   there are many line which sets this state.

 - A Lua sample-fetch is executed, typically for building the log
   line.

 - When the Lua sample fetch exits, a control of the data is
   executed. If HAProxy is currently parsing the request, the request
   is aborted in order to prevent a segfault or sending corrupted
   data.

This ast control is executed comparing the state HTTP_MSG_BODY. When
this state is reached, the request is parsed and no error are
possible. When the state is < than HTTP_MSG_BODY, the parser is
running.

Unfortunately, the code HTTP_MSG_ERROR is just < HTTP_MSG_BODY. When
we are in error, we want to terminate the execution of Lua without
error.

This patch changes the comparaison level.

This patch must be backported in 1.6
2016-11-19 00:29:19 +01:00
Willy Tarreau
2fe1b92163 BUG/MINOR: cli: properly decrement ref count on tables during failed dumps
Gernot Prner reported some constant leak of ref counts for stick tables
entries. It happens that this leak was not at all in the regular traffic
path but on the "show table" path. An extra ref count was taken during
the dump if the output had to be paused, and it was released upon clean
termination or an error detected in the I/O handler. But the release
handler didn't do it, while it used to properly do it for the sessions
dump.

This fix needs to be backported to 1.6.
2016-11-18 19:20:09 +01:00
Willy Tarreau
5179146fa3 BUG/MEDIUM: stick-table: fix regression caused by recent fix for out-of-memory
Commit ef8f4fe ("BUG/MINOR: stick-table: handle out-of-memory condition
gracefully") unfortunately got trapped by a pointer operation. Replacing

    ts = poll_alloc() + size;

with :

    ts = poll_alloc();
    ts += size;

Doesn't give the same result because pool_alloc() is void while ts is a
struct stksess*. So now we don't access the same places, which is visible
in certain stick-table scenarios causing a crash.

This must be backported to 1.6 and 1.5.
2016-11-18 18:21:39 +01:00
Willy Tarreau
733b1327a6 DEBUG: connection: mark the closed FDs with a value that is easier to detect
Setting an FD to -1 when closed isn't the most easily noticeable thing
to do when we're chasing accidental reuse of a stale file descriptor.
Instead set it to that large a negative value that it will overflow the
fdtab and provide an analysable core at the moment the issue happens.
Care was taken to ensure it doesn't overflow nor change sign on 32-bit
machines when multiplied by fdtab, and that it also remains negative for
the various checks that exist. The value equals 0xFDDEADFD which happens
to be easily spotted in a debugger.
2016-11-18 15:00:42 +01:00
Willy Tarreau
350135cf49 BUG/MEDIUM: connection: check the control layer before stopping polling
The bug described in commit 568743a ("BUG/MEDIUM: stream-int: completely
detach connection on connect error") was not a stream-interface layer bug
but a connection layer bug. There was exactly one place in the code where
we could change a file descriptor's status without first checking whether
it is valid or not, it was in conn_stop_polling(). This one is called when
the polling status is changed after an update, and calls fd_stop_both even
if we had already closed the file descriptor :

1479388298.484240 ->->->->->   conn_fd_handler > conn_cond_update_polling
1479388298.484240 ->->->->->->   conn_cond_update_polling > conn_stop_polling
1479388298.484241 ->->->->->->->   conn_stop_polling > conn_ctrl_ready
1479388298.484241                  conn_stop_polling < conn_ctrl_ready
1479388298.484241 ->->->->->->->   conn_stop_polling > fd_stop_both
1479388298.484242 ->->->->->->->->   fd_stop_both > fd_update_cache
1479388298.484242 ->->->->->->->->->   fd_update_cache > fd_release_cache_entry
1479388298.484242                      fd_update_cache < fd_release_cache_entry
1479388298.484243                    fd_stop_both < fd_update_cache
1479388298.484243                  conn_stop_polling < fd_stop_both
1479388298.484243                conn_cond_update_polling < conn_stop_polling
1479388298.484243              conn_fd_handler < conn_cond_update_polling

The problem with the previous fix above is that it break the http_proxy mode
and possibly even some Lua parts and peers to a certain extent ; all outgoing
connections where the target address is initially copied into the outgoing
connection which experience a retry would use a random outgoing address after
the retry because closing and detaching the connection causes the target
address to be lost. This was attempted to be addressed by commit 0857d7a
("BUG/MAJOR: stream: properly mark the server address as unset on connect
retry") but it used to only solve the most visible effect and not the root
cause.

Prior to this fix, it was possible to cause this config to keep CLOSE_WAIT
for as long as it takes to expire a client or server timeout (note the
missing client timeout) :

   listen test
        mode http
        bind :8002
        server s1 127.0.0.1:8001

   $ tcploop 8001 L0 W N20 A R P100 S:"HTTP/1.1 200 OK\r\nContent-length: 0\r\n\r\n" &
   $ tcploop 8002 N200 C T W S:"GET / HTTP/1.0\r\n\r\n" O P10000 K

With this patch, these CLOSE_WAIT properly vanish when both processes leave.

This commit reverts the two fixes above and replaces them with the proper
fix in connection.h. It must be backported to 1.6 and 1.5. Thanks to
Robson Roberto Souza Peixoto for providing very detailed traces showing
some obvious inconsistencies leading to finding this bug.
2016-11-18 14:48:52 +01:00
Thierry FOURNIER / OZON.IO
a44fdd95f9 MEDIUM: lua: Add cli handler for Lua
Now, HAProxy allows to register some keys in the "cli". This patch allows
to handle these keys with Lua code.
2016-11-18 14:32:03 +01:00
Thierry FOURNIER / OZON.IO
6a22dcbe27 MINOR: cli: add private pointer and release function
This pointer will be used for storing private context. With this,
the same executed function can handle more than one keyword. This
will be very useful for creation Lua cli bindings.

The release function is called when the command is terminated (give
back the hand to the prompt) or when the session is broken (timeout
or client closed).
2016-11-18 14:32:03 +01:00
Vincent Bernat
ef8f4fe12d BUG/MINOR: stick-table: handle out-of-memory condition gracefully
In case `pool_alloc2()` returns NULL, propagate the condition to the
caller. This could happen when limiting the amount of memory available
for HAProxy with `-m`.

[wt: backport to 1.6 and 1.5 needed]
2016-11-17 16:00:16 +01:00
Willy Tarreau
a71f642b62 CLEANUP: lua: avoid directly calling getsockname/getpeername()
We already have per-protocol functions for this, and they already
take care of properly setting the CO_FL_ADDR_*_SET flags.
2016-11-16 17:32:57 +01:00
Bertrand Jacquin
ff13c06a17 CLEANUP: ssl: Fix bind keywords name in comments
Along with a whitespace cleanup and a grammar typo
2016-11-14 18:15:20 +01:00
Bertrand Jacquin
5a8fc2d45f CLEANUP: ssl: Remove goto after return dead code
This code can never be reached.
2016-11-14 18:15:20 +01:00
Bertrand Jacquin
5424ee08de BUG/MINOR: ssl: Print correct filename when error occurs reading OCSP
When Multi-Cert bundle are used, error is throwned regarding certificate
filename without including certifcate type extension.
2016-11-14 18:15:20 +01:00
Bertrand Jacquin
3342309572 BUG/MEDIUM: ssl: Store certificate filename in a variable
Before this change, trash is being used to create certificate filename
to read in care Mutli-Cert are in used. But then ssl_sock_load_ocsp()
modify trash leading to potential wrong information given in later error
message.

This also blocks any further use of certificate filename for other
usage, like ongoing patch to support Certificate Transparency handling
in Multi-Cert bundle.
2016-11-14 18:15:20 +01:00
Thierry FOURNIER / OZON.IO
b41f22f59c CLEANUP: lua: control executed twice
The availaible size in the stack is check two times. This patch removes
this double check.

Must be backported in 1.6
2016-11-14 15:23:17 +01:00
Thierry FOURNIER / OZON.IO
02564fd153 CLEANUP: lua: move comment
Old comment is misplaced. Certainly due to a bad copy/paste

Must be backported in 1.6
2016-11-14 15:23:17 +01:00
Thierry FOURNIER / OZON.IO
500d11e65d BUG/MEDIUM: channel: bad unlikely macro
The unlikely macro doesn't take in acount the condition, but only one
variable.

Must be backported in 1.6

[wt: with gcc 3.x, unlikely(x) is defined as __builtin_expect((x) != 0, 0)
 so the condition is wrong for negative numbers, which correspond to the
 case where bi_getblk_nc() has reached the end of the buffer and the
 channel is already closed. With gcc 4.x, the output is cast to unsigned long
 so the <=0 will not match negative values either. This is only used in Lua
 for now so that may explain why it hasn't hit yet]
2016-11-14 15:23:17 +01:00
Thierry FOURNIER / OZON.IO
62fec75183 MINOR: lua: add ip addresses and network manipulation function
Add two functions core.parse_addr() and core.match_addr() where are used
for matching networks.
2016-11-12 10:42:30 +01:00
Thierry FOURNIER / OZON.IO
65192f35d2 MINOR: lua: add function which return true if the channel is full.
Add function which return true if the channel is full. It is
useful for triggering some process when the buffer is full.
2016-11-12 10:42:25 +01:00
Christopher Faulet
ba7bc164f7 MINOR: spoe/checks: Add support for SPOP health checks
A new "option spop-check" statement has been added to enable server health
checks based on SPOP HELLO handshake. SPOP is the protocol used by SPOE filters
to talk to servers.
2016-11-09 22:57:02 +01:00
Christopher Faulet
f7e4e7e096 MAJOR: spoe: Add an experimental Stream Processing Offload Engine
SPOE makes possible the communication with external components to retrieve some
info using an in-house binary protocol, the Stream Processing Offload Protocol
(SPOP). In the long term, its aim is to allow any kind of offloading on the
streams. This first version, besides being experimental, won't do lot of
things. The most important today is to validate the protocol design and lay the
foundations of what will, one day, be a full offload engine for the stream
processing.

So, for now, the SPOE can offload the stream processing before "tcp-request
content", "tcp-response content", "http-request" and "http-response" rules. And
it only supports variables creation/suppression. But, in spite of these limited
features, we can easily imagine to implement a SSO solution, an ip reputation
service or an ip geolocation service.

Internally, the SPOE is implemented as a filter. So, to use it, you must use
following line in a proxy proxy section:

  frontend my-front
      ...
      filter spoe [engine <name>] config <file>
      ...

It uses its own configuration file to keep the HAProxy configuration clean. It
is also a easy way to disable it by commenting out the filter line.

See "doc/SPOE.txt" for all details about the SPOE configuration.
2016-11-09 22:57:01 +01:00
Christopher Faulet
85d79c94a9 MINOR: vars: Add 'unset-var' action/converter
It does the opposite of 'set-var' action/converter. It is really useful for
per-process variables. But, it can be used for any scope.

The lua function 'unset_var' has also been added.
2016-11-09 22:57:01 +01:00
Christopher Faulet
ff2613ed7a MEDIUM: vars: Add a per-process scope for variables
Now it is possible to use variables attached to a process. The scope name is
'proc'. These variables are released only when HAProxy is stopped.

'tune.vars.proc-max-size' directive has been added to confiure the maximum
amount of memory used by "proc" variables. And because memory accounting is
hierachical for variables, memory for "proc" vars includes memory for "sess"
vars.
2016-11-09 22:57:00 +01:00
Christopher Faulet
09c9df286b MINOR: vars: Add vars_set_by_name_ifexist function
This function, unsurprisingly, sets a variable value only if it already
exists. In other words, this function will succeed only if the variable was
found somewhere in the configuration during HAProxy startup.

It will be used by SPOE filter. So an agent will be able to set a value only for
existing variables. This prevents an agent to create a very large number of
unused variables to flood HAProxy and exhaust the memory reserved to variables..
2016-11-09 22:57:00 +01:00
Christopher Faulet
b71557a98b MINOR: vars: Allow '.' in variable names
This is required to have implicit prefix or scope. SPOE filter will use it to
keep variables set by an agent in its own namespace.
2016-11-09 22:57:00 +01:00
Christopher Faulet
476e5d0e03 REORG: sample: move code to release a sample expression in sample.c
This code has been moved from haproxy.c to sample.c and the function
release_sample_expr can now be called from anywhere to release a sample
expression. This function will be used by the stream processing offload engine
(SPOE).
2016-11-09 22:57:00 +01:00
Christopher Faulet
79bdef3cad MINOR: cfgparse: Parse scope lines and save the last one parsed
A scope is a section name between square bracket, alone on its line, ie:

  [scope-name]
  ...

The spaces at the beginning and at the end of the line are skipped. Comments at
the end of the line are also skipped.

When a scope is parsed, its name is saved in the global variable
cfg_scope. Initially, cfg_scope is NULL and it remains NULL until a valid scope
line is parsed.

This feature remains unused in the HAProxy configuration file and
undocumented. However, it will be used during SPOE configuration parsing.
2016-11-09 22:56:59 +01:00
Christopher Faulet
7110b40d06 MINOR: cfgparse: Add functions to backup and restore registered sections
This feature will be used by the stream processing offload engine (SPOE) to
parse dedicated configuration files without mixing HAProxy sections with SPOE
sections.

So, here we can back up all sections known by HAProxy, unregister all of them
and add new ones, dedicted to the SPOE. Once the SPOE configuration file parsed,
we can roll back all changes by restoring HAProxy sections.
2016-11-09 22:56:59 +01:00
Christopher Faulet
fcd99f8eec MINOR: flt_trace: Add hexdump option to dump forwarded data
This is pretty verbose, but it can be handy to have it in HAProxy.
2016-11-09 22:56:59 +01:00
Christopher Faulet
c6062be1e1 MINOR: filters: Remove backend filters attached to a stream only for HTTP streams
Now, for TCP streams, backend filters are released when the stream is
destroyed. But, for HTTP streams, these filters are released when the
transaction analyze ends, in flt_end_analyze callback.
2016-11-09 22:50:55 +01:00
Christopher Faulet
4117904ffd MINOR: filters: Call stream_set_backend callbacks before updating backend stats
So if an internal error is returned, the number of cumulated connections on the
backend is not incremented.
2016-11-09 22:50:55 +01:00
Christopher Faulet
31ed32dce4 MEDIUM: filters: Add attch/detach and stream_set_backend callbacks
New callbacks have been added to handle creation and destruction of filter
instances:

* 'attach' callback is called after a filter instance creation, when it is
  attached to a stream. This happens when the stream is started for filters
  defined on the stream's frontend and when the backend is set for filters
  declared on the stream's backend. It is possible to ignore the filter, if
  needed, by returning 0. This could be useful to have conditional filtering.

* 'detach' callback is called when a filter instance is detached from a stream,
  before its destruction. This happens when the stream is stopped for filters
  defined on the stream's frontend and when the analyze ends for filters defined
  on the stream's backend.

In addition, the callback 'stream_set_backend' has been added to know when a
backend is set for a stream. It is only called when the frontend and the backend
are not the same. And it is called for all filters attached to a stream
(frontend and backend).

Finally, the TRACE filter has been updated.
2016-11-09 22:50:54 +01:00
Christopher Faulet
898566e7e6 CLEANUP: remove last references to 'ruleset' section 2016-11-09 22:50:54 +01:00
Christopher Faulet
0099a8ca9d BUG: vars: Fix 'set-var' converter because of a typo
The 'set-var' converter uses function smp_conv_store (vars.c). In this function,
we should use the first argument (index 0) to retrieve the variable name and its
scope. But because of a typo, we get the scope of the second argument (index
1). In this case, there is no second argument. So the scope used was always 0
(SCOPE_SESS), always setting the variable in the session scope.

So, due to this bug, this rules

  tcp-request content accept if { src,set-var(txn.foo) -m found }

always set the variable 'sess.foo' instead of 'txn.foo'.
2016-11-09 22:50:54 +01:00
Willy Tarreau
e5a60688a4 MEDIUM: server: do not restrict anymore usage of IP address from the state file
Now that it is possible to decide whether we prefer to use libc or the
state file to resolve the server's IP address and it is possible to change
a server's IP address at run time on the CLI, let's not restrict the reuse
of the address from the state file anymore to the DNS only.

The impact is that by default the state file will be considered first
(which matches its purpose) and only then the libc. This way any address
change performed at run time over the CLI will be preserved regardless
of DNS usage or not.
2016-11-09 15:33:52 +01:00
Willy Tarreau
3eed10e54b MINOR: init: add -dr to ignore server address resolution failures
It is very common when validating a configuration out of production not to
have access to the same resolvers and to fail on server address resolution,
making it difficult to test a configuration. This option simply appends the
"none" method to the list of address resolution methods for all servers,
ensuring that even if the libc fails to resolve an address, the startup
sequence is not interrupted.
2016-11-09 15:33:52 +01:00
Willy Tarreau
4310d36a7e MINOR: server: add support for explicit numeric address in init-addr
This will allow a server to automatically fall back to an explicit numeric
IP address when all other methods fail. The address is simply specified in
the address list.
2016-11-09 15:30:47 +01:00
Willy Tarreau
465b6e5463 MEDIUM: server: make libc resolution failure non-fatal
Now that we have "init-addr none", it becomes possible to recover on
libc resolver's failures. Thus it's preferable not to alert nor fail
at the moment the libc is called, and instead process the failure at
the end of the list. This allows "none" to be set after libc to
provide a smooth fallback in case of resolver issues.
2016-11-09 15:30:47 +01:00
Willy Tarreau
37ebe1212b MINOR: server: implement init-addr none
The server is put into the "no address" maintenance state in this case.
2016-11-09 15:30:47 +01:00
Willy Tarreau
25e515235a MEDIUM: server: make use of init-addr
It is now supported. If not set, we default to the legacy methods list
which is "last,libc".
2016-11-09 15:30:47 +01:00
Baptiste Assmann
25938278b7 MEDIUM: server: add a new init-addr server line setting
This new setting supports a comma-delimited list of methods used to
resolve the server's FQDN to an IP address. Currently supported methods
are "libc" (use the regular libc's resolver) and "last" (use the last
known valid address found in the state file).

The list is implemented in a 32-bit integer, because each init-addr
method only requires 3 bits. The last one must always be SRV_IADDR_END
(0), allowing to store up to 10 methods in a single 32 bit integer.

Note: the doc is provided at the end of this series.
2016-11-09 15:30:47 +01:00
Willy Tarreau
a33ec24683 MEDIUM: cli: leave the RMAINT state when setting an IP address on the CLI
The RMAINT state happens when a server doesn't get a valid DNS response
past the hold time. If the address is forced on the CLI, we must use it
and leave the RMAINT state.
2016-11-09 15:30:47 +01:00
Baptiste Assmann
3b9fe9f8f4 MAJOR: dns: runtime resolution can change server admin state
WARNING: this is a MAJOR (and disruptive) change with previous HAProxy's
behavior: before, HAProxy never ever used to change a server administrative
status when the DNS resolution failed at run time.

This patch gives HAProxy the ability to change the administrative status
of a server to MAINT (RMAINT actually) when an error is encountered for
a period longer than its own allowed by the corresponding 'hold'
parameter.

IE if the configuration sets "hold nx 10s" and a server's hostname
points to a NX for more than 10s, then the server will be set to RMAINT,
hence in MAINTENANCE mode.
2016-11-09 15:30:47 +01:00
Baptiste Assmann
987e16d6f4 MINOR: dns: implement extra 'hold' timers.
This adds new "hold" timers : nx, refused, timeout, other. This timers
will be used to tell HAProxy to keep an erroneous response as valid for
the corresponding period. For now they're only configured, not enforced.
2016-11-09 15:30:47 +01:00
Willy Tarreau
8b42848a44 MINOR: server: make srv_set_admin_state() capable of telling why this happens
It will be important to help debugging some DNS resolution issues to
know why a server was marked down, so let's make  the function support
a 3rd argument with an indication of the reason. Passing NULL will keep
the message as-is.
2016-11-09 15:30:47 +01:00
Willy Tarreau
b96dd28477 MINOR: stats: indicate it when a server is down due to resolution
The server's state is now "MAINT (resolution)" just like we also have
"MAINT (via x/y)" when servers are tracked. The HTML stats page reports
"resolution" in the checks field similarly to what is done for the "via"
entry.
2016-11-09 15:30:47 +01:00
Willy Tarreau
e659973bfe MINOR: server: indicate in the logs when RMAINT is cleared
It's important to report in the server state change logs that RMAINT was
cleared, as it's not the regular maintenance mode, it's specific to name
resolution, and it's important to report the new state (which can be DRAIN
or READY).
2016-11-09 15:23:37 +01:00
Baptiste Assmann
83cbaa531f MAJOR: server: postpone address resolution
Server addresses are not resolved anymore upon the first pass so that we
don't fail if an address cannot be resolved by the libc. Instead they are
processed all at once after the configuration is fully loaded, by the new
function srv_init_addr(). This function only acts on the server's address
if this address uses an FQDN, which appears in server->hostname.

For now the function does two things, to followup with HAProxy's historical
default behavior:

  1. apply server IP address found in server-state file if runtime DNS
     resolution is enabled for this server

  2. use the DNS resolver provided by the libc

If none of the 2 options above can find an IP address, then an error is
returned.

All of this will be needed to support the new server parameter "init-addr".
For now, the biggest user-visible change is that all server resolution errors
are dumped at once instead of causing a startup failure one by one.
2016-11-09 14:24:20 +01:00
Baptiste Assmann
4215d7d033 MINOR: init: move apply_server_state in haproxy.c before MODE_CHECK
Currently, the function which applies server states provided by the
"old" process is applied after configuration sanity check. This results
in the impossibility to check the validity of the state file during a
regular config check, implying a full start is required, which can be
a problem sometimes.

This patch moves the loading of server_state file before MODE_CHECK.
2016-11-09 14:24:20 +01:00
Willy Tarreau
ceccdd78a7 MEDIUM: tools: make str2sa_range() return the FQDN even when not resolving
This will be needed to later postpone server address resolution. We need the
FQDN even when it doesn't resolve. The caller then needs to check if fqdn was
set when resolve is null to detect that the address couldn't be parsed and
needs later resolution.
2016-11-09 14:24:20 +01:00
Willy Tarreau
def0d22cc5 MINOR: stream: make option contstats usable again
Quite a lot of people have been complaining about option contstats not
working correctly anymore since about 1.4. The reason was that one reason
for the significant performance boost between 1.3 and 1.4 was the ability
to forward data between a server and a client without waking up the stream
manager. And we couldn't afford to force sessions to constantly wake it
up given that most of the people interested in contstats are also those
interested in high performance transmission.

An idea was experimented with in the past, consisting in limiting the
amount of transmissible data before waking it up, but it was not usable
on slow connections (eg: FTP over modem lines, RDP, SSH) as stats would
be updated too rarely if at all, so that idea was dropped.

During a discussion today another idea came up : ensure that stats are
updated once in a while, since it's the only thing that matters. It
happens that we have the request channel's analyse_exp timeout that is
used to wake the stream up after a configured delay, and that by
definition this timeout is not used when there's no more analyser
(otherwise the stream would wake up and the stats would be updated).

Thus here the idea is to reuse this timeout when there's no analyser
and set it to now+5 seconds so that a stream wakes up at least once
every 5 seconds to update its stats. It should be short enough to
provide smooth traffic graphs and to allow to debug outputs of "show
sess" more easily without inflicting too much load even for very large
number of concurrent connections.

This patch is simple enough and safe enough to be backportable to 1.6
if there is some demand.
2016-11-08 22:03:00 +01:00
Dirkjan Bussink
1866d6d8f1 MEDIUM: ssl: Add support for OpenSSL 1.1.0
In the last release a lot of the structures have become opaque for an
end user. This means the code using these needs to be changed to use the
proper functions to interact with these structures instead of trying to
manipulate them directly.

This does not fix any deprecations yet that are part of 1.1.0, it only
ensures that it can be compiled against that version and is still
compatible with older ones.

[wt: openssl-0.9.8 doesn't build with it, there are conflicts on certain
     function prototypes which we declare as inline here and which are
     defined differently there. But openssl-0.9.8 is not supported anymore
     so probably it's OK to go without it for now and we'll see later if
     some users still need it. Emeric has reviewed this change and didn't
     spot anything obvious which requires special care. Let's try it for
     real now]
2016-11-08 20:54:41 +01:00
Willy Tarreau
e5d3169e1c CLEANUP: wurfl: reduce exposure in the rest of the code
The only reason wurfl/wurfl.h was needed outside of wurfl.c was to expose
wurfl_handle which is a pointer to a structure, referenced by global.h.
By just storing a void* there instead, we can confine all wurfl code to
wurfl.c, which is really nice.
2016-11-08 18:47:25 +01:00
scientiamobile
d0027ed5b1 MEDIUM: wurfl: add Scientiamobile WURFL device detection module
WURFL is a high-performance and low-memory footprint mobile device
detection software component that can quickly and accurately detect
over 500 capabilities of visiting devices. It can differentiate between
portable mobile devices, desktop devices, SmartTVs and any other types
of devices on which a web browser can be installed.

In order to add WURFL device detection support, you would need to
download Scientiamobile InFuze C API and install it on your system.
Refer to www.scientiamobile.com to obtain a valid InFuze license.

Any useful information on how to configure HAProxy working with WURFL
may be found in:

  doc/WURFL-device-detection.txt
  doc/configuration.txt
  examples/wurfl-example.cfg

Please find more information about WURFL device detection API detection
at https://docs.scientiamobile.com/documentation/infuze/infuze-c-api-user-guide
2016-11-08 14:21:43 +01:00
Willy Tarreau
757478e900 BUG/MEDIUM: servers: properly propagate the maintenance states during startup
Right now there is an issue with the way the maintenance flags are
propagated upon startup. They are not propagate, just copied from the
tracked server. This implies that depending on the server's order, some
tracking servers may not be marked down. For example this configuration
does not work as expected :

        server s1 1.1.1.1:8000 track s2
        server s2 1.1.1.1:8000 track s3
        server s3 1.1.1.1:8000 track s4
        server s4 wtap:8000 check inter 1s disabled

It results in s1/s2 being up, and s3/s4 being down, while all of them
should be down.

The only clean way to process this is to run through all "root" servers
(those not tracking any other server), and to propagate their state down
to all their trackers. This is the same algorithm used to propagate the
state changes. It has to be done both to compute the IDRAIN flag and the
IMAINT flag. However, doing so requires that tracking servers are not
marked as inherited maintenance anymore while parsing the configuration
(and given that it is wrong, better drop it).

This fix also addresses another side effect of the bug above which is
that the IDRAIN/IMAINT flags are stored in the state files, and if
restored while the tracked server doesn't have the equivalent flag,
the servers may end up in a situation where it's impossible to remove
these flags. For example in the configuration above, after removing
"disabled" on server s4, the other servers would have remained down,
and not anymore with this fix. Similarly, the combination of IMAINT
or IDRAIN with their respective forced modes was not accepted on
reload, which is wrong as well.

This bug has been present at least since 1.5, maybe even 1.4 (it came
with tracking support). The fix needs to be backported there, though
the srv-state parts are irrelevant.

This commit relies on previous patch to silence warnings on startup.
2016-11-07 14:31:52 +01:00
Willy Tarreau
6fb8dc1a5a MINOR: server: do not emit warnings/logs/alerts on server state changes at boot
We'll have to use srv_set_admin_flag() to propagate some server flags
during the startup, and we don't want the resulting actions to cause
warnings, logs nor e-mail alerts to be generated since we're just applying
the config or a state file. So let's condition these notifications to the
fact that we're starting.
2016-11-07 14:31:45 +01:00
Willy Tarreau
e1bde1492a BUG/MINOR: srv-state: allow to have both CMAINT and FDRAIN flags
CMAINT indicates that the server was *initially* disabled in the
configuration via the "disabled" keyword. FDRAIN indicates that the
server was switched to the DRAIN state from the CLI or the agent.
This it's perfectly valid to have both of them in the state file,
so the parser must not reject this combination.

This fix must be backported to 1.6.
2016-11-07 14:30:19 +01:00
Willy Tarreau
22cace2f4c BUG/MEDIUM: srv-state: properly restore the DRAIN state
There were seveal reports about the DRAIN state not being properly
restored upon reload.

It happens that the condition in the code does exactly the opposite
of what the comment says, and the comment is right so the code is
wrong.

It's worth noting that the conditions are complex here due to the 2
available methods to set the drain state (CLI/agent, and config's
weight). To paraphrase the updated comment in the code, there are
two possible reasons for FDRAIN to have been present :
  - previous config weight was zero
  - "set server b/s drain" was sent to the CLI

In the first case, we simply want to drop this drain state if the new
weight is not zero anymore, meaning the administrator has intentionally
turned the weight back to a positive value to enable the server again
after an operation. In the second case, the drain state was forced on
the CLI regardless of the config's weight so we don't want a change to
the config weight to lose this status. What this means is :
  - if previous weight was 0 and new one is >0, drop the DRAIN state.
  - if the previous weight was >0, keep it.

This fix must be backported to 1.6.
2016-11-07 14:30:19 +01:00
Willy Tarreau
e6d9c21059 OPTIM: http: optimize lookup of comma and quote in header values
http_find_header2() relies on find_hdr_value_end() to find the comma
delimiting a header field value, which also properly handles double
quotes and backslashes within quotes. In fact double quotes are very
rare, and commas happen once every multiple characters, especially
with cookies where a full block can be found at once. So it makes
sense to optimize this function to speed up the lookup of the first
block before the quote.

This change increases the performance from 212k to 217k req/s when
requests contain a 1kB cookie (+2.5%). We don't care about going
back into the fast parser after the first quote, as it may
needlessly make the parser more complex for very marginal gains.
2016-11-05 18:23:38 +01:00
Willy Tarreau
5f10ea30f4 OPTIM: http: improve parsing performance of long URIs
Searching the trailing space in long URIs takes some time. This can
happen especially on static files and some blogs. By skipping valid
character ranges by 32-bit blocks, it's possible to increase the
HTTP performance from 212k to 216k req/s on requests features a
100-character URI, which is an increase of 2%. This is done for
architectures supporting unaligned accesses (x86_64, x86, armv7a).
There's only a 32-bit version because URIs are rarely long and very
often short, so it's more efficient to limit the systematic overhead
than to try to optimize for the rarest requests.
2016-11-05 18:00:35 +01:00
Willy Tarreau
0431f9d476 OPTIM: http: improve parsing performance of long header lines
A performance test with 1kB cookies was capping at 194k req/s. After
implementing multi-byte skipping, the performance increased to 212k req/s,
or 9.2% faster. This patch implements this for architectures supporting
unaligned accesses (x86_64, x86, armv7a). Maybe other architectures can
benefit from this but they were not tested yet.
2016-11-05 18:00:17 +01:00
Willy Tarreau
2235b261b6 OPTIM: http: move all http character classs tables into a single one
We used to have 7 different character classes, each was 256 bytes long,
resulting in almost 2kB being used in the L1 cache. It's as cheap to
test a bit than to check the byte is not null, so let's store a 7-bit
composite value and check for the respective bits there instead.

The executable is now 4 kB smaller and the performance on small
objects increased by about 1% to 222k requests/second with a config
involving 4 http-request rules including 1 header lookup, one header
replacement, and 2 variable assignments.
2016-11-05 15:58:08 +01:00
Willy Tarreau
dc3a9e830c CLEANUP: tools: make ipcpy() preserve the original port
ipcpy() is used to replace an IP address with another one, but it
doesn't preserve the original port so all callers have to do it
manually while it's trivial to do there. Better do it inside the
function.
2016-11-05 13:56:04 +01:00
Willy Tarreau
ecde7df11b MEDIUM: tools: make str2ip2() preserve existing ports
Often we need to call str2ip2() on an address which already contains a
port without replacing it, so let's ensure we preserve it even if the
family changes.
2016-11-05 13:56:04 +01:00
Willy Tarreau
f7659cb10c BUG/MEDIUM: systemd-wrapper: return correct exit codes
Gabriele Cerami reported the the exit codes of the systemd-wrapper are
wrong. In short, it directly returns the output of the wait syscall's
status, which is a composite value made of error code an signal numbers.
In general it contains the signal number on the lower bits and the error
code on the higher bits, but exit() truncates it to the lowest 8 bits,
causing config validations to incorrectly report a success. Example :

  $ ./haproxy-systemd-wrapper -c -f /dev/null
  <7>haproxy-systemd-wrapper: executing /tmp/haproxy -c -f /dev/null -Ds
  Configuration file has no error but will not start (no listener) => exit(2).
  <5>haproxy-systemd-wrapper: exit, haproxy RC=512
  $ echo $?
  0

If the process is killed however, the signal number is directly reported
in the exit code.

Let's fix all this to ensure that the exit code matches what the shell does,
which means that codes 0..127 are for exit codes, codes 128..254 for signals,
and code 255 for unknown exit code. Now the return code is correct :

  $ ./haproxy-systemd-wrapper -c -f /dev/null
  <7>haproxy-systemd-wrapper: executing /tmp/haproxy -c -f /dev/null -Ds
  Configuration file has no error but will not start (no listener) => exit(2).
  <5>haproxy-systemd-wrapper: exit, haproxy RC=2
  $ echo $?
  2

  $ ./haproxy-systemd-wrapper -f /tmp/cfg.conf
  <7>haproxy-systemd-wrapper: executing /tmp/haproxy -f /dev/null -Ds
  ^C
  <5>haproxy-systemd-wrapper: exit, haproxy RC=130
  $ echo $?
  130

This fix must be backported to 1.6 and 1.5.
2016-11-03 20:34:20 +01:00
Willy Tarreau
9df94c2b25 MINOR: peers: remove the pointer to the stream
There's no reason to use the stream anymore, only the appctx should be
used by a peer. This was a leftover from the migration to appctx and it
caused some confusion, so let's totally drop it now. Note that half of
the patch are just comment updates.
2016-10-31 20:07:01 +01:00
Willy Tarreau
81bc3b062b MINOR: peers: make peer_session_forceshutdown() use the appctx and not the stream
It was inherited from initial code but we must only manipulate the appctx
and never the stream, otherwise we always risk shooting ourselves in the
foot.
2016-10-31 20:07:01 +01:00
Willy Tarreau
b21d08e249 BUG/MEDIUM: peers: fix use after free in peer_session_create()
In case of resource allocation error, peer_session_create() frees
everything allocated and returns a pointer to the stream/session that
was put back into the free pool. This stream/session is then assigned
to ps->{stream,session} with no error control. This means that it is
perfectly possible to have a new stream or session being both used for
a regular communication and for a peer at the same time.

In fact it is the only way (for now) to explain a CLOSE_WAIT on peers
connections that was caught in this dump with the stream interface in
SI_ST_CON state while the error field proves the state ought to have
been SI_ST_DIS, very likely indicating two concurrent accesses on the
same area :

  0x7dbd50: [31/Oct/2016:17:53:41.267510] id=0 proto=tcpv4
    flags=0x23006, conn_retries=0, srv_conn=(nil), pend_pos=(nil)
    frontend=myhost2 (id=4294967295 mode=tcp), listener=? (id=0)
    backend=<NONE> (id=-1 mode=-) addr=127.0.0.1:41432
    server=<NONE> (id=-1) addr=127.0.0.1:8521
    task=0x7dbcd8 (state=0x08 nice=0 calls=2 exp=<NEVER> age=1m5s)
    si[0]=0x7dbf48 (state=CLO flags=0x4040 endp0=APPCTX:0x7d99c8 exp=<NEVER>, et=0x000)
    si[1]=0x7dbf68 (state=CON flags=0x50 endp1=CONN:0x7dc0b8 exp=<NEVER>, et=0x020)
    app0=0x7d99c8 st0=11 st1=0 st2=0 applet=<PEER>
    co1=0x7dc0b8 ctrl=tcpv4 xprt=RAW data=STRM target=PROXY:0x7fe62028a010
        flags=0x0020b310 fd=7 fd.state=22 fd.cache=0 updt=0
    req=0x7dbd60 (f=0x80a020 an=0x0 pipe=0 tofwd=0 total=0)
        an_exp=<NEVER> rex=<NEVER> wex=<NEVER>
        buf=0x78a3c0 data=0x78a3d4 o=0 p=0 req.next=0 i=0 size=0
    res=0x7dbda0 (f=0x80402020 an=0x0 pipe=0 tofwd=0 total=0)
        an_exp=<NEVER> rex=<NEVER> wex=<NEVER>
        buf=0x78a3c0 data=0x78a3d4 o=0 p=0 rsp.next=0 i=0 size=0

Special thanks to Arnaud Gavara who provided lots of valuable input and
ran some validation testing on this patch.

This fix must be backported to 1.6 and 1.5. Note that in 1.5 the
session is not assigned from within the function so some extra checks
may be needed in the callers.
2016-10-31 20:02:05 +01:00
Willy Tarreau
78c0c50705 BUG/MEDIUM: peers: on shutdown, wake up the appctx, not the stream
This part was missed when peers were ported to the new applet
infrastructure in 1.6, the main stream is woken up instead of the
appctx. This creates a race condition by which it is possible to
wake the stream at the wrong moment and miss an event. This bug
might be at least partially responsible for some of the CLOSE_WAIT
that were reported on peers session upon reload in version 1.6.

This fix must be backported to 1.6.
2016-10-31 20:01:42 +01:00
Ian Miell
71c432e937 CLEANUP: cfgparse: Very minor spelling correction
'optionnally' changed to 'optionally'
2016-10-26 18:46:01 +02:00
Chad Lavoie
1666930f03 MINOR: stats: Escape equals sign on socket dump
Greetings,

Was recently working with a stick table storing URL's and one had an
equals sign in it (e.g. 127.0.0.1/f=ab) which made it difficult to
easily split the key and value without a regex.

This patch will change it so that the key looks like
"key=127.0.0.1/f\=ab" instead of "key=127.0.0.1/f=ab".

Not very important given that there are ways to work around it.

Thanks,

- Chad
2016-10-25 22:15:22 +02:00
Andrew Rodland
4f88c63609 MEDIUM: server: Implement bounded-load hash algorithm
The consistent hash lookup is done as normal, then if balancing is
enabled, we progress through the hash ring until we find a server that
doesn't have "too much" load. In the case of equal weights for all
servers, the allowed number of requests for a server is either the
floor or the ceil of (num_requests * hash-balance-factor / num_servers);
with unequal weights things are somewhat more complicated, but the
spirit is the same -- a server should not be able to go too far above
(its relative weight times) the average load. Using the hash ring to
make the second/third/etc. choice maintains as much locality as
possible given the load limit.

Signed-off-by: Andrew Rodland <andrewr@vimeo.com>
2016-10-25 20:21:32 +02:00
Andrew Rodland
13d5ebb913 MINOR: server: compute a "cumulative weight" to allow chash balancing to hit its target
For active servers, this is the sum of the eweights of all active
servers before this one in the backend, and
[srv->cumulative_weight .. srv_cumulative_weight + srv_eweight) is a
space occupied by this server in the range [0 .. lbprm.tot_wact), and
likewise for backup servers with tot_wbck. This allows choosing a
server or a range of servers proportional to their weight, by simple
integer comparison.

Signed-off-by: Andrew Rodland <andrewr@vimeo.com>
2016-10-25 20:21:32 +02:00
Andrew Rodland
b1f48e3161 MINOR: backend: add hash-balance-factor option for hash-type consistent
0 will mean no balancing occurs; otherwise it represents the ratio
between the highest-loaded server and the average load, times 100 (i.e.
a value of 150 means a 1.5x ratio), assuming equal weights.

Signed-off-by: Andrew Rodland <andrewr@vimeo.com>
2016-10-25 20:21:32 +02:00
Andrew Rodland
e168feb4a8 MINOR: proxy: add 'served' field to proxy, equal to total of all servers'
This will allow lb_chash to determine the total active sessions for a
proxy without any computation.

Signed-off-by: Andrew Rodland <andrewr@vimeo.com>
2016-10-25 20:21:32 +02:00
Willy Tarreau
b957109727 BUG/MEDIUM: systemd: let the wrapper know that haproxy has completed or failed
Pierre Cheynier found that there's a persistent issue with the systemd
wrapper. Too fast reloads can lead to certain old processes not being
signaled at all and continuing to run. The problem was tracked down as
a race between the startup and the signal processing : nothing prevents
the wrapper from starting new processes while others are still starting,
and the resulting pid file will only contain the latest pids in this
case. This can happen with large configs and/or when a lot of SSL
certificates are involved.

In order to solve this we want the wrapper to wait for the new processes
to complete their startup. But we also want to ensure it doesn't wait for
nothing in case of error.

The solution found here is to create a pipe between the wrapper and the
sub-processes. The wrapper waits on the pipe and the sub-processes are
expected to close this pipe once they completed their startup. That way
we don't queue up new processes until the previous ones have registered
their pids to the pid file. And if anything goes wrong, the wrapper is
immediately released. The only thing is that we need the sub-processes
to know the pipe's file descriptor. We pass it in an environment variable
called HAPROXY_WRAPPER_FD.

It was confirmed both by Pierre and myself that this completely solves
the "zombie" process issue so that only the new processes continue to
listen on the sockets.

It seems that in the future this stuff could be moved to the haproxy
master process, also getting rid of an environment variable.

This fix needs to be backported to 1.6 and 1.5.
2016-10-25 17:43:45 +02:00
Willy Tarreau
a785269b4e MINOR: systemd: report it when execve() fails
It's important to know that a signal sent to the wrapper had no effect
because something failed during execve(). Ideally more info (strerror)
should be reported. It would be nice to backport this to 1.6 and 1.5.
2016-10-25 17:36:40 +02:00