| 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 know : |
| - 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 (instantiates 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). |
| |