DOC: add doc/internals/entities-v2.txt
This contains some thoughts about how to improve connection management for 1.5 in order to support SSL.
This commit is contained in:
parent
f3934b8c6d
commit
4658c4dfe5
|
@ -0,0 +1,193 @@
|
|||
An FD has a state :
|
||||
- CLOSED
|
||||
- READY
|
||||
- ERROR (?)
|
||||
- LISTEN (?)
|
||||
|
||||
A connection has a state :
|
||||
- CLOSED
|
||||
- ACCEPTED
|
||||
- CONNECTING
|
||||
- ESTABLISHED
|
||||
- ERROR
|
||||
|
||||
A stream interface has a state :
|
||||
- INI, REQ, QUE, TAR, ASS, CON, CER, EST, DIS, CLO
|
||||
|
||||
Note that CON and CER might be replaced by EST if the connection state is used
|
||||
instead. CON might even be more suited than EST to indicate that a connection
|
||||
is known.
|
||||
|
||||
|
||||
si_shutw() must do :
|
||||
|
||||
data_shutw()
|
||||
if (shutr) {
|
||||
data_close()
|
||||
ctrl_shutw()
|
||||
ctrl_close()
|
||||
}
|
||||
|
||||
si_shutr() must do :
|
||||
data_shutr()
|
||||
if (shutw) {
|
||||
data_close()
|
||||
ctrl_shutr()
|
||||
ctrl_close()
|
||||
}
|
||||
|
||||
Each of these steps may fail, in which case the step must be retained and the
|
||||
operations postponed in an asynchronous task.
|
||||
|
||||
The first asynchronous data_shut() might already fail so it is mandatory to
|
||||
save the other side's status with the connection in order to let the async task
|
||||
know whether the 3 next steps must be performed.
|
||||
|
||||
The connection (or perhaps the FD) needs to know :
|
||||
- the desired close operations : DSHR, DSHW, CSHR, CSHW
|
||||
- the completed close operations : DSHR, DSHW, CSHR, CSHW
|
||||
|
||||
|
||||
On the accept() side, we probably need to know :
|
||||
- if a header is expected (eg: accept-proxy)
|
||||
- if this header is still being waited for
|
||||
=> maybe both info might be combined into one bit
|
||||
|
||||
- if a data-layer accept() is expected
|
||||
- if a data-layer accept() has been started
|
||||
- if a data-layer accept() has been performed
|
||||
=> possibly 2 bits, to indicate the need to free()
|
||||
|
||||
On the connect() side, we need to konw :
|
||||
- the desire to send a header (eg: send-proxy)
|
||||
- if this header has been sent
|
||||
=> maybe both info might be combined
|
||||
|
||||
- if a data-layer connect() is expected
|
||||
- if a data-layer connect() has been started
|
||||
- if a data-layer connect() has been completed
|
||||
=> possibly 2 bits, to indicate the need to free()
|
||||
|
||||
On the response side, we also need to know :
|
||||
- the desire to send a header (eg: health check response for monitor-net)
|
||||
- if this header was sent
|
||||
=> might be the same as sending a header over a new connection
|
||||
|
||||
Note: monitor-net has precedence over proxy proto and data layers. Same for
|
||||
health mode.
|
||||
|
||||
For multi-step operations, use 2 bits :
|
||||
00 = operation not desired, not performed
|
||||
10 = operation desired, not started
|
||||
11 = operation desired, started but not completed
|
||||
01 = operation desired, started and completed
|
||||
|
||||
=> X != 00 ==> operation desired
|
||||
X & 01 ==> operation at least started
|
||||
X & 10 ==> operation not completed
|
||||
|
||||
Note: no way to store status information for error reporting.
|
||||
|
||||
Note2: it would be nice if "tcp-request connection" rules could work at the
|
||||
connection level, just after headers ! This means support for tracking stick
|
||||
tables, possibly not too much complicated.
|
||||
|
||||
|
||||
Proposal for incoming connection sequence :
|
||||
|
||||
- accept()
|
||||
- if monitor-net matches or if mode health => try to send response
|
||||
- if accept-proxy, wait for proxy request
|
||||
- if tcp-request connection, process tcp rules and possibly keep the
|
||||
pointer to stick-table
|
||||
- if SSL is enabled, switch to SSL handshake
|
||||
- then switch to DATA state and instantiate a session
|
||||
|
||||
We just need a map of handshake handlers on the connection. They all manage the
|
||||
FD status themselves and set the callbacks themselves. If their work succeeds,
|
||||
they remove themselves from the list. If it fails, they remain subscribed and
|
||||
enable the required polling until they are woken up again or the timeout strikes.
|
||||
|
||||
Identified handshake handlers for incoming connections :
|
||||
- HH_HEALTH (tries to send OK and dies)
|
||||
- HH_MONITOR_IN (matches src IP and adds/removes HH_SEND_OK/HH_SEND_HTTP_OK)
|
||||
- HH_SEND_OK (tries to send "OK" and dies)
|
||||
- HH_SEND_HTTP_OK (tries to send "HTTP/1.0 200 OK" and dies)
|
||||
- HH_ACCEPT_PROXY (waits for PROXY line and parses it)
|
||||
- HH_TCP_RULES (processes TCP rules)
|
||||
- HH_SSL_HS (starts SSL handshake)
|
||||
- HH_ACCEPT_SESSION (instanciates a session)
|
||||
|
||||
Identified handshake handlers for outgoing connections :
|
||||
- HH_SEND_PROXY (tries to build and send the PROXY line)
|
||||
- HH_SSL_HS (starts SSL handshake)
|
||||
|
||||
For the pollers, we could check that handshake handlers are not 0 and decide to
|
||||
call a generic connection handshake handler instead of usual callbacks. Problem
|
||||
is that pollers don't know connections, they know fds. So entities which manage
|
||||
handlers should update change the FD callbacks accordingly.
|
||||
|
||||
With a bit of care, we could have :
|
||||
- HH_SEND_LAST_CHUNK (sends the chunk pointed to by a pointer and dies)
|
||||
=> merges HEALTH, SEND_OK and SEND_HTTP_OK
|
||||
|
||||
It sounds like the ctrl vs data state for the connection are per-direction
|
||||
(eg: support an async ctrl shutw while still reading data).
|
||||
|
||||
Also support shutr/shutw status at L4/L7.
|
||||
|
||||
In practice, what we really need is :
|
||||
|
||||
shutdown(conn) =
|
||||
conn.data.shut()
|
||||
conn.ctrl.shut()
|
||||
conn.fd.shut()
|
||||
|
||||
close(conn) =
|
||||
conn.data.close()
|
||||
conn.ctrl.close()
|
||||
conn.fd.close()
|
||||
|
||||
With SSL over Remote TCP (RTCP + RSSL) to reach the server, we would have :
|
||||
|
||||
HTTP -> RTCP+RSSL connection <-> RTCP+RRAW connection -> TCP+SSL connection
|
||||
|
||||
The connection has to be closed at 3 places after a successful response :
|
||||
- DATA (RSSL over RTCP)
|
||||
- CTRL (RTCP to close connection to server)
|
||||
- SOCK (FD to close connection to second process)
|
||||
|
||||
Externally, the connection is seen with very few flags :
|
||||
- SHR
|
||||
- SHW
|
||||
- ERR
|
||||
|
||||
We don't need a CLOSED flag as a connection must always be detached when it's closed.
|
||||
|
||||
The internal status doesn't need to be exposed :
|
||||
- FD allocated (Y/N)
|
||||
- CTRL initialized (Y/N)
|
||||
- CTRL connected (Y/N)
|
||||
- CTRL handlers done (Y/N)
|
||||
- CTRL failed (Y/N)
|
||||
- CTRL shutr (Y/N)
|
||||
- CTRL shutw (Y/N)
|
||||
- DATA initialized (Y/N)
|
||||
- DATA connected (Y/N)
|
||||
- DATA handlers done (Y/N)
|
||||
- DATA failed (Y/N)
|
||||
- DATA shutr (Y/N)
|
||||
- DATA shutw (Y/N)
|
||||
|
||||
(note that having flags for operations needing to be completed might be easier)
|
||||
--------------
|
||||
|
||||
Maybe we need to be able to call conn->fdset() and conn->fdclr() but it sounds
|
||||
very unlikely since the only functions manipulating this are in the code of
|
||||
the data/ctrl handlers.
|
||||
|
||||
FDSET/FDCLR cannot be directly controlled by the stream interface since it also
|
||||
depends on the DATA layer (WANT_READ/wANT_WRITE).
|
||||
|
||||
But FDSET/FDCLR is probably controlled by who owns the connection (eg: DATA).
|
||||
|
Loading…
Reference in New Issue