371 Commits

Author SHA1 Message Date
Olivier Houchard
9aaf778129 MAJOR: connection : Split struct connection into struct connection and struct conn_stream.
All the references to connections in the data path from streams and
stream_interfaces were changed to use conn_streams. Most functions named
"something_conn" were renamed to "something_cs" for this. Sometimes the
connection still is what matters (eg during a connection establishment)
and were not always renamed. The change is significant and minimal at the
same time, and was quite thoroughly tested now. As of this patch, all
accesses to the connection from upper layers go through the pass-through
mux.
2017-10-31 18:03:23 +01:00
Willy Tarreau
5f4a47b701 CLEANUP: threads: replace the last few 1UL<<tid with tid_bit
There were a few occurences left, better replace them now.
2017-10-31 15:59:32 +01:00
Thierry FOURNIER
952939d294 MEDIUM: threads/xref: Convert xref function to a thread safe model
Ensure that the unlink is done safely between thread and that
the peer struct will not destroy between the usage of the peer.
2017-10-31 13:58:32 +01:00
Thierry FOURNIER
94a6bfce9b MEDIUM: threads/lua: Cannot acces to the socket if we try to access from another thread.
We have two y for nsuring that the data is not concurently manipulated:
 - locks
 - running task on the same thread.
locks are expensives, it is better to avoid it.

This patch cecks that the Lua task run on the same thread that
the stream associated to the coprocess.

TODO: in a next version, the error should be replaced by a yield
and thread migration request.
2017-10-31 13:58:32 +01:00
Thierry FOURNIER
4325ab727c MEDIUM: threads/lua: Ensure that the launched tasks runs on the same threads than me
The applet manipulates the session and its buffers. We have two methods for
ensuring that the memory of the session will not change during its manipulation
by the task:
 1 - adding mutex
 2 - running on the same threads than the task.
The second point is smart because it cannot lock the execution of another thread.
2017-10-31 13:58:32 +01:00
Thierry FOURNIER
61ba0e2b6d MEDIUM: threads/lua: Add locks around the Lua execution parts.
Note that the Lua processing is not really thread safe. It provides
heavy system which consists to add our own lock function in the Lua
code and recompile the library. This system will probably not accepted
by maintainers of various distribs.

Our main excution point of the Lua is the function lua_resume(). A
quick looking on the Lua sources displays a lua_lock() a the start
of function and a lua_unlock() at the end of the function. So I
conclude that the Lua thread safe mode just perform a mutex around
all execution. So I prefer to do this in the HAProxy code, it will be
easier for distro maintainers.

Note that the HAProxy lua functions rounded by the macro SET_SAFE_LJMP
and RESET_SAFE_LJMP manipulates the Lua stack, so it will be careful
to set mutex around these functions.
2017-10-31 13:58:32 +01:00
Thierry FOURNIER
ffbad79027 MEDIUM: threads/lua: Makes the jmpbuf and some other buffers local to the current thread.
The jmpbuf contains pointer on the stack memory address currently use
when the jmpbuf is set. So the information is local to each thread.

The struct field is too big to put it in the stack, but it is used
as buffer for retriving stats values. So, this buffer si local to each
threads. Each function using this buffer, use it whithout break (yield)
so, the consistency of local buffer is ensured.
2017-10-31 13:58:32 +01:00
Emeric Brun
1138fd0c57 MAJOR: threads/applet: Handle multithreading for applets
A global lock has been added to protect accesses to the list of active
applets. A process mask has also been added on each applet. Like for FDs and
tasks, it is used to know which threads are allowed to process an
applet. Because applets are, most of time, linked to a session, it should be
sticky on the same thread. But in all cases, it is the responsibility of the
applet handler to lock what have to be protected in the applet context.
2017-10-31 13:58:31 +01:00
Christopher Faulet
40a007cf2a MEDIUM: threads/server: Make connection list (priv/idle/safe) thread-safe
For now, we have a list of each type per thread. So there is no need to lock
them. This is the easiest solution for now, but not the best one because there
is no sharing between threads. An idle connection on a thread will not be able
be used by a stream on another thread. So it could be a good idea to rework this
patch later.
2017-10-31 13:58:30 +01:00
Emeric Brun
c60def8368 MAJOR: threads/task: handle multithread on task scheduler
2 global locks have been added to protect, respectively, the run queue and the
wait queue. And a process mask has been added on each task. Like for FDs, this
mask is used to know which threads are allowed to process a task.

For many tasks, all threads are granted. And this must be your first intension
when you create a new task, else you have a good reason to make a task sticky on
some threads. This is then the responsibility to the process callback to lock
what have to be locked in the task context.

Nevertheless, all tasks linked to a session must be sticky on the thread
creating the session. It is important that I/O handlers processing session FDs
and these tasks run on the same thread to avoid conflicts.
2017-10-31 13:58:30 +01:00
Willy Tarreau
06d80a9a9c REORG: channel: finally rename the last bi_* / bo_* functions
For HTTP/2 we'll need some buffer-only equivalent functions to some of
the ones applying to channels and still squatting the bi_* / bo_*
namespace. Since these names have kept being misleading for quite some
time now and are really getting annoying, it's time to rename them. This
commit will use "ci/co" as the prefix (for "channel in", "channel out")
instead of "bi/bo". The following ones were renamed :

  bi_getblk_nc, bi_getline_nc, bi_putblk, bi_putchr,
  bo_getblk, bo_getblk_nc, bo_getline, bo_getline_nc, bo_inject,
  bi_putchk, bi_putstr, bo_getchr, bo_skip, bi_swpbuf
2017-10-19 15:01:08 +02:00
Emeric Brun
253e53e661 BUG/MAJOR: lua: scheduled task is freezing.
Since commit 'MAJOR: task: task scheduler rework'
0194897e540cec67d7d1e9281648b70efe403f08. LUA's
scheduling tasks are freezing.

A running task should not handle the scheduling itself
but let the task scheduler to handle it based on the
'expire' field.

[wt: no backport needed]
2017-10-18 19:23:33 +02:00
Willy Tarreau
0bf6fa5e40 MEDIUM: session: count the frontend's connections at a single place
There are several places where we see feconn++, feconn--, totalconn++ and
an increment on the frontend's number of connections and connection rate.
This is done exactly once per session in each direction, so better take
care of this counter in the session and simplify the callers. At least it
ensures a better symmetry. It also ensures consistency as till now the
lua/spoe/peers frontend didn't have these counters properly set, which can
be useful at least for troubleshooting.
2017-09-15 11:49:52 +02:00
Willy Tarreau
6f5e4b98df MEDIUM: session: take care of incrementing/decrementing jobs
Each user of a session increments/decrements the jobs variable at its
own place, resulting in a real mess and inconsistencies between them.
Let's have session_new() increment jobs and session_free() decrement
it.
2017-09-15 11:49:52 +02:00
Thierry FOURNIER
d697596c6c MINOR: tasks: Move Lua notification from Lua to tasks
These notification management function and structs are generic and
it will be better to move in common parts.

The notification management functions and structs have names
containing some "lua" references because it was written for
the Lua. This patch removes also these references.
2017-09-11 18:59:40 +02:00
Thierry FOURNIER
2da788e755 MEDIUM: xref/lua: Use xref for referencing cosocket relation between stream and lua
This relation will ensure that each was informed about death of another one.
2017-09-11 18:59:40 +02:00
Thierry FOURNIER
b01d28f976 BUG/MINOR: Lua: The socket may be destroyed when we try to access.
When we try to access to other proxy context, we must check
its existence because haproxy can kill it between the creation
and the usage.

This patch should be backported in 1.6 and 1.7
2017-09-11 18:59:40 +02:00
Emeric Brun
52a91d3d48 MEDIUM: check: server states and weight propagation re-work
The server state and weight was reworked to handle
"pending" values updated by checks/CLI/LUA/agent.
These values are commited to be propagated to the
LB stack.

In further dev related to multi-thread, the commit
will be handled into a sync point.

Pending values are named using the prefix 'next_'
Current values used by the LB stack are named 'cur_'
2017-09-05 15:23:16 +02:00
Willy Tarreau
87787acf72 MEDIUM: stream: make stream_new() allocate its own task
Currently a task is allocated in session_new() and serves two purposes :
  - either the handshake is complete and it is offered to the stream via
    the second arg of stream_new()

  - or the handshake is not complete and it's diverted to be used as a
    timeout handler for the embryonic session and repurposed once we land
    into conn_complete_session()

Furthermore, the task's process() function was taken from the listener's
handler in conn_complete_session() prior to being replaced by a call to
stream_new(). This will become a serious mess with the mux.

Since it's impossible to have a stream without a task, this patch removes
the second arg from stream_new() and make this function allocate its own
task. In session_accept_fd(), we now only allocate the task if needed for
the embryonic session and delete it later.
2017-08-30 07:05:04 +02:00
Willy Tarreau
585744bf2e REORG/MEDIUM: connection: introduce the notion of connection handle
Till now connections used to rely exclusively on file descriptors. It
was planned in the past that alternative solutions would be implemented,
leading to member "union t" presenting sock.fd only for now.

With QUIC, the connection will need to continue to exist but will not
rely on a file descriptor but a connection ID.

So this patch introduces a "connection handle" which is either a file
descriptor or a connection ID, to replace the existing "union t". We've
now removed the intermediate "struct sock" which was never used. There
is no functional change at all, though the struct connection was inflated
by 32 bits on 64-bit platforms due to alignment.
2017-08-24 19:30:04 +02:00
Willy Tarreau
ee1bdd5a03 OPTIM: lua: don't add "Connection: close" on the response
Haproxy doesn't need this anymore, we're wasting cycles checking for
a Connection header in order to add "Connection: close" only in the
1.1 case so that haproxy sees it and removes it. All tests were run
in 1.0 and 1.1, with/without the request header, and in the various
keep-alive/close modes, with/without compression, and everything works
fine. It's worth noting that this header was inherited from the stats
applet and that the same cleanup probably ought to be done there as
well.
2017-08-23 16:11:38 +02:00
Willy Tarreau
a329463655 OPTIM: lua: don't use expensive functions to parse headers in the HTTP applet
In the HTTP applet, we have to parse the response headers provided by
the application and to produce a response. strcasecmp() is expensive,
and chunk_append() even more as it uses a format string.

Here we check the string length before calling strcasecmp(), which
results in strcasecmp() being called only on the relevant header in
practise due to very few collisions on the name lengths, effectively
dividing the number of calls by 3, and we replace chunk_appendf()
with memcpy() as we already know the string lengths.

Doing just this makes the "hello-world" applet 5% faster, reaching
41400 requests/s on a core i5-3320M.
2017-08-23 16:11:38 +02:00
Willy Tarreau
c9f4ea0f61 MINOR: lua: properly process the contents of the content-length field
The header's value was parsed with atoi() then compared against -1,
meaning that all the unparsable stuff returning zero was not considered
and that all multiples of 2^32 + 0xFFFFFFFF would continue to emit a
chunk.

Now instead we parse the value using a long long, only accept positive
values and consider all unparsable values as incorrect and switch to
either close or chunked encoding. This is more in line with what a
client (including haproxy's parser) would expect.

This may be backported as a cleanup to stable versions, though it's
really unlikely that Lua applications are facing side effects of this.
2017-08-23 16:11:38 +02:00
Willy Tarreau
06c75fec17 BUG/MEDIUM: lua: HTTP services must take care of body-less status codes
The following Lua code causes emission of a final chunk after the body,
which is wrong :

core.register_service("send204", "http", function(applet)
   applet:set_status(204)
   applet:start_response()
end)

Indeed, responses with status codes 1xx, 204 and 304 do not contain any
body and the message ends immediately after the empty header (cf RFC7230)
so by emitting a 0<CR><LF> we're disturbing keep-alive responses. There's
a workaround against this for now which consists in always emitting
"Content-length: 0" but it may not be cool with 304 when clients use
the headers to update their cache.

This fix must be backported to stable versions back to 1.6.
2017-08-23 16:11:38 +02:00
Willy Tarreau
d958741886 BUG/MAJOR: lua: fix the impact of the scheduler changes again
Commit d1aa41f ("BUG/MAJOR: lua: properly dequeue hlua_applet_wakeup()
for new scheduler") tried to address the side effects of the scheduler
changes on Lua, but it was not enough. Having some Lua code send data
in chunks separated by one second each clearly shows busy polling being
done.

The issue was tracked down to hlua_applet_wakeup() being woken up on
timer expiration, and returning itself without clearing the timeout,
causing the task to be re-inserted with an expiration date in the past,
thus firing again. In the past it was not a problem, as returning NULL
was enough to clear the timer. Now we can't rely on this anymore so
it's important to clear this timeout.

No backport is needed, this issue is specific to 1.8-dev and results
from an incomplete fix in the commit above.
2017-08-23 16:07:33 +02:00
Willy Tarreau
d1aa41f83b BUG/MAJOR: lua: properly dequeue hlua_applet_wakeup() for new scheduler
The recent scheduler change broke the Lua co-sockets due to
hlua_applet_wakeup() returning NULL after waking the applet up. With the
previous scheduler, returning NULL was a way to do nothing on return.

With the new one it keeps TASK_RUNNING set, causing all new notifications
to end up into t->pending_state instead of t->state, and prevents the
task from being added into the run queue again, so and it's never woken
up anymore.

The applet keeps waking up, causing hlua_socket_handler() to do nothing
new, then si_applet_wake_cb() calling stream_int_notify() to try to wake
the task up, which it can't do due to the TASK_RUNNING flag, then decide
that since the associated task is not in the run queue, it needs to call
stream_int_update_applet() to propagate the update. This last one finds
that the applet needs to be woken up to deal with the last reported events
and calling appctx_wakeup() again. Previously, this situation didn't exist
because the task was always added in the run queue despite the TASK_RUNNING
flag.

By returning the task instead in hlua_applet_wakeup(), we can ensure its
flag is properly cleared and the task is requeued if needed or just sits
waiting for new events to happen.

This fix requires the previous ones ("BUG/MINOR: lua: always detach the
tcp/http tasks before freeing them") and MINOR: task: always preinitialize
the task's timeout in task_init().

Thanks to Thierry, Christopher and Emeric for the long head-scratching
session!

No backport is needed as the bug doesn't appear in older versions and
it's unsure whether we'll not break something by backporting it.
2017-07-24 18:14:49 +02:00
Willy Tarreau
bd7fc95edb BUG/MINOR: lua: always detach the tcp/http tasks before freeing them
In hlua_{http,tcp}_applet_release(), a call to task_free() is performed
to release the task, but no task_delete() is made on these tasks. Till
now it wasn't much of a problem because this was normally not done with
the task in the run queue, and the task was never put into the wait queue
since it doesn't have any timer. But with threading it will become an
issue. And not having this already prevents another bug from being fixed.

Thanks to Christopher for spotting this one. A backport to 1.7 and 1.6 is
preferred for safety.
2017-07-24 17:35:27 +02:00
Thierry FOURNIER
6b546a6048 BUG/MINOR: Lua: variable already initialized
The variable strm->hlua is already initilized by the function stream_new().
2017-07-18 06:41:58 +02:00
Thierry FOURNIER
7bd10d58d3 BUG/MEDIUM: lua: bad memory access
We cannot perform garbage collection on unreferenced thread.
This memory is now free and another Lua process can use it for
other things.

HAProxy is monothread, so this bug doesn't cause crash.

This patch must be backported in 1.6 and 1.7
2017-07-18 06:41:38 +02:00
Thierry FOURNIER
b13b20a19a BUG/MAJOR: lua/socket: resources not detroyed when the socket is aborted
In some cases, the socket is misused. The user can open socket and never
close it, or open the socket and close it without sending data. This
causes resources leak on all resources associated to the stream (buffer,
spoe, ...)

This is caused by the stream_shutdown function which is called outside
of the stream execution process. Sometimes, the shtudown is required
while the stream is not started, so the cleanup is ignored.

This patch change the shutdown mode of the session. Now if the session is
no longer used and the Lua want to destroy it, it just set a destroy flag
and the session kill itself.

This patch should be backported in 1.6 and 1.7
2017-07-18 06:41:33 +02:00
Thierry FOURNIER
75d0208009 BUG/MINOR: lua: executes the function destroying the Lua session in safe mode
When we destroy the Lua session, we manipulates Lua stack,
so errors can raises. It will be better to catch these errors.

This patch should be backported in 1.6 and 1.7
2017-07-18 06:41:28 +02:00
Thierry FOURNIER
0a97620c08 BUG/MINOR: lua: In error case, the safe mode is not removed
Just forgot of reset the safe mode. This have not consequences
the safe mode just set a pointer on fucntion which is called only
and initialises a longjmp.

Out of lua execution, this longjmp is never executed and the
function is never called.

This patch should be backported in 1.6 and 1.7
2017-07-18 06:41:19 +02:00
Emeric Brun
5f77fef34e MINOR: task/stream: tasks related to a stream must be init by the caller.
The task_wakeup was called on stream_new, but the task/stream
wasn't fully initialized yet. The task_wakeup must be called
explicitly by the caller once the task/stream is initialized.
2017-06-27 14:38:02 +02:00
Thierry FOURNIER
fd80df11c3 BUG/MEDIUM: lua: segfault if a converter or a sample doesn't return anything
In the case of a Lua sample-fetch or converter doesn't return any
value, an acces outside the Lua stack can be performed. This patch
check the stack size before converting the top value to a HAProxy
internal sample.

A workaround consist to check that a value value is always returned
with sample fetches and converters.

This patch should be backported in the version 1.6 and 1.7
2017-05-12 16:46:26 +02:00
Thierry FOURNIER
e068b60605 CLEANUP: lua: remove test
The man of "luaL_unref" says "If ref is LUA_NOREF or LUA_REFNIL,
luaL_unref does nothing.", so I remove the check.
2017-04-26 15:13:18 +02:00
Thierry FOURNIER
f326767711 BUG/MEDIUM: lua: memory leak
The priv context is not cleaned when we set a new priv context.
This is caused by a stupid swap between two parameter of the
luaL_unref() function.

workaround: use set_priv only once when we process a stream.

This patch should be backported in version 1.7 and 1.6
2017-04-26 15:13:18 +02:00
Willy Tarreau
42ef75fb84 MINOR: lua: ensure the memory allocator is used all the time
luaL_setstate() uses malloc() to initialize the first objects, and only
after this we replace the allocator. This creates trouble when replacing
the standard memory allocators during debugging sessions since the new
allocator is used to realloc() an area previously allocated using the
default malloc().

Lua provides lua_newstate() in addition to luaL_newstate(), which takes
an allocator for the initial malloc. This is exactly what we need, and
this patch does this and fixes the problem. The now useless call to
lua_setallocf() could be removed.

This has no impact outside of debugging sessions and there's no need to
backport this.
2017-04-13 17:10:15 +02:00
Thierry FOURNIER
7d38863552 BUG/MAJOR: lua segmentation fault when the request is like 'GET ?arg=val HTTP/1.1'
Error in the HTTP parser. The function http_get_path() can
return NULL and this case is not catched in the code. So, we
try to dereference NULL pointer, and a segfault occurs.

These two lines are useful to prevent the bug.

   acl prevent_bug path_beg /
	http-request deny if !prevent_bug

This bug fix should be backported in 1.6 and 1.7
2017-02-23 21:52:18 +01:00
Thierry FOURNIER
4dc7197338 BUG/MINOR: lua: Map.end are not reliable because "end" is a reserved keyword
This patch change the names prefixing it by a "_". So "end" becomes "_end".
The backward compatibility with names without the prefix "_" is assured.
In other way, another the keyword "end" can be used like this: Map['end'].

Thanks Robin H. Johnson for the bug repport

This should be backported in version 1.6 and 1.7
2017-01-30 20:29:10 +01:00
Jarno Huuskonen
16ad94adf6 MINOR: Use "500 Internal Server Error" for 500 error/status code message.
Internal Server Error is what is in RFC 2616/7231.
2017-01-11 12:44:40 +01:00
Willy Tarreau
48ef4c95b6 MINOR: tools: make str2sa_range() return the port in a separate argument
This will be needed so that we're don't have to extract it from the
returned address where it will not always be anymore (eg: for unresolved
servers).
2017-01-06 19:29:34 +01:00
Robin H. Johnson
52f5db2a44 MINOR: http: custom status reason.
The older 'rsprep' directive allows modification of the status reason.

Extend 'http-response set-status' to take an optional string of the new
status reason.

  http-response set-status 418 reason "I'm a coffeepot"

Matching updates in Lua code:
- AppletHTTP.set_status
- HTTP.res_set_status

Signed-off-by: Robin H. Johnson <robbat2@gentoo.org>
2017-01-06 11:57:44 +01:00
Willy Tarreau
17d4538044 MINOR: ssl_sock: implement and use prepare_srv()/destroy_srv()
Now we can simply check the transport layer at run time and decide
whether or not to initialize or destroy these entries. This removes
other ifdefs and includes from cfgparse.c, haproxy.c and hlua.c.
2016-12-22 23:26:38 +01:00
Willy Tarreau
a261e9b094 CLEANUP: connection: remove all direct references to raw_sock and ssl_sock
Now we exclusively use xprt_get(XPRT_RAW) instead of &raw_sock or
xprt_get(XPRT_SSL) for &ssl_sock. This removes a bunch of #ifdef and
include spread over a number of location including backend, cfgparse,
checks, cli, hlua, log, server and session.
2016-12-22 23:26:38 +01:00
Willy Tarreau
0320934f7e MEDIUM: ssl: remote the proxy argument from most functions
Most of the SSL functions used to have a proxy argument which was mostly
used to be able to emit clean errors using Alert(). First, many of them
were converted to memprintf() and don't require this pointer anymore.
Second, the rare which still need it also have either a bind_conf argument
or a server argument, both of which carry a pointer to the relevant proxy.

So let's now get rid of it, it needlessly complicates the API and certain
functions already have many arguments.
2016-12-22 23:26:38 +01:00
Willy Tarreau
bb57d94a96 CLEANUP: lua: use the build options list to report it
This removes 1 #ifdef from haproxy.c. The "build without" version
is not reported anymore now.
2016-12-21 21:30:54 +01:00
Thierry FOURNIER
2c8b54e7be MEDIUM: lua: remove Lua struct from session, and allocate it with memory pools
This patch use memory pools for allocating the Lua struct. This
save 128B of memory in the session if the Lua is unused.
2016-12-21 15:24:56 +01:00
Thierry FOURNIER
1be34152da BUG/MINOR: lua: memleak when Lua/cli fails
If the memory allocator fails, it return a bad code, and the execution
continue. If the Lua/cli initializer fails, the allocated struct is not
released.
2016-12-21 15:24:35 +01:00
Thierry FOURNIER
33558c4a3f BUG/MINOR: lua: bad return code
If the lua/cli fails during initialization, it returns an ok
status, an the execution continue. This will probably occur a
segfault.

Thiw patch should be backported in 1.7
2016-12-21 15:24:24 +01:00
Thierry FOURNIER
4e7c708612 BUG/MINOR: lua: memory leak executing tasks
The struct hlua isn't freed when the task is complete.

This patch should be backported in 1.6 and 1.7
2016-12-21 15:24:09 +01:00