Willy Tarreau | 4658c4d | 2012-05-26 00:18:09 +0200 | [diff] [blame] | 1 | An FD has a state : |
| 2 | - CLOSED |
| 3 | - READY |
| 4 | - ERROR (?) |
| 5 | - LISTEN (?) |
| 6 | |
| 7 | A connection has a state : |
| 8 | - CLOSED |
| 9 | - ACCEPTED |
| 10 | - CONNECTING |
| 11 | - ESTABLISHED |
| 12 | - ERROR |
| 13 | |
| 14 | A stream interface has a state : |
| 15 | - INI, REQ, QUE, TAR, ASS, CON, CER, EST, DIS, CLO |
| 16 | |
| 17 | Note that CON and CER might be replaced by EST if the connection state is used |
| 18 | instead. CON might even be more suited than EST to indicate that a connection |
| 19 | is known. |
| 20 | |
| 21 | |
| 22 | si_shutw() must do : |
| 23 | |
| 24 | data_shutw() |
| 25 | if (shutr) { |
| 26 | data_close() |
| 27 | ctrl_shutw() |
| 28 | ctrl_close() |
| 29 | } |
| 30 | |
| 31 | si_shutr() must do : |
| 32 | data_shutr() |
| 33 | if (shutw) { |
| 34 | data_close() |
| 35 | ctrl_shutr() |
| 36 | ctrl_close() |
| 37 | } |
| 38 | |
| 39 | Each of these steps may fail, in which case the step must be retained and the |
| 40 | operations postponed in an asynchronous task. |
| 41 | |
| 42 | The first asynchronous data_shut() might already fail so it is mandatory to |
| 43 | save the other side's status with the connection in order to let the async task |
| 44 | know whether the 3 next steps must be performed. |
| 45 | |
| 46 | The connection (or perhaps the FD) needs to know : |
| 47 | - the desired close operations : DSHR, DSHW, CSHR, CSHW |
| 48 | - the completed close operations : DSHR, DSHW, CSHR, CSHW |
| 49 | |
| 50 | |
| 51 | On the accept() side, we probably need to know : |
| 52 | - if a header is expected (eg: accept-proxy) |
| 53 | - if this header is still being waited for |
| 54 | => maybe both info might be combined into one bit |
| 55 | |
| 56 | - if a data-layer accept() is expected |
| 57 | - if a data-layer accept() has been started |
| 58 | - if a data-layer accept() has been performed |
| 59 | => possibly 2 bits, to indicate the need to free() |
| 60 | |
Joseph Herlant | 02cedc4 | 2018-11-13 19:45:17 -0800 | [diff] [blame] | 61 | On the connect() side, we need to know : |
Willy Tarreau | 4658c4d | 2012-05-26 00:18:09 +0200 | [diff] [blame] | 62 | - the desire to send a header (eg: send-proxy) |
| 63 | - if this header has been sent |
| 64 | => maybe both info might be combined |
| 65 | |
| 66 | - if a data-layer connect() is expected |
| 67 | - if a data-layer connect() has been started |
| 68 | - if a data-layer connect() has been completed |
| 69 | => possibly 2 bits, to indicate the need to free() |
| 70 | |
| 71 | On the response side, we also need to know : |
| 72 | - the desire to send a header (eg: health check response for monitor-net) |
| 73 | - if this header was sent |
| 74 | => might be the same as sending a header over a new connection |
| 75 | |
| 76 | Note: monitor-net has precedence over proxy proto and data layers. Same for |
| 77 | health mode. |
| 78 | |
| 79 | For multi-step operations, use 2 bits : |
| 80 | 00 = operation not desired, not performed |
| 81 | 10 = operation desired, not started |
| 82 | 11 = operation desired, started but not completed |
| 83 | 01 = operation desired, started and completed |
| 84 | |
| 85 | => X != 00 ==> operation desired |
| 86 | X & 01 ==> operation at least started |
| 87 | X & 10 ==> operation not completed |
| 88 | |
| 89 | Note: no way to store status information for error reporting. |
| 90 | |
| 91 | Note2: it would be nice if "tcp-request connection" rules could work at the |
| 92 | connection level, just after headers ! This means support for tracking stick |
| 93 | tables, possibly not too much complicated. |
| 94 | |
| 95 | |
| 96 | Proposal for incoming connection sequence : |
| 97 | |
| 98 | - accept() |
| 99 | - if monitor-net matches or if mode health => try to send response |
| 100 | - if accept-proxy, wait for proxy request |
| 101 | - if tcp-request connection, process tcp rules and possibly keep the |
| 102 | pointer to stick-table |
| 103 | - if SSL is enabled, switch to SSL handshake |
| 104 | - then switch to DATA state and instantiate a session |
| 105 | |
| 106 | We just need a map of handshake handlers on the connection. They all manage the |
| 107 | FD status themselves and set the callbacks themselves. If their work succeeds, |
| 108 | they remove themselves from the list. If it fails, they remain subscribed and |
| 109 | enable the required polling until they are woken up again or the timeout strikes. |
| 110 | |
| 111 | Identified handshake handlers for incoming connections : |
| 112 | - HH_HEALTH (tries to send OK and dies) |
| 113 | - HH_MONITOR_IN (matches src IP and adds/removes HH_SEND_OK/HH_SEND_HTTP_OK) |
| 114 | - HH_SEND_OK (tries to send "OK" and dies) |
| 115 | - HH_SEND_HTTP_OK (tries to send "HTTP/1.0 200 OK" and dies) |
| 116 | - HH_ACCEPT_PROXY (waits for PROXY line and parses it) |
| 117 | - HH_TCP_RULES (processes TCP rules) |
| 118 | - HH_SSL_HS (starts SSL handshake) |
Ilya Shipitsin | 2075ca8 | 2020-03-06 23:22:22 +0500 | [diff] [blame] | 119 | - HH_ACCEPT_SESSION (instantiates a session) |
Willy Tarreau | 4658c4d | 2012-05-26 00:18:09 +0200 | [diff] [blame] | 120 | |
| 121 | Identified handshake handlers for outgoing connections : |
| 122 | - HH_SEND_PROXY (tries to build and send the PROXY line) |
| 123 | - HH_SSL_HS (starts SSL handshake) |
| 124 | |
| 125 | For the pollers, we could check that handshake handlers are not 0 and decide to |
| 126 | call a generic connection handshake handler instead of usual callbacks. Problem |
| 127 | is that pollers don't know connections, they know fds. So entities which manage |
| 128 | handlers should update change the FD callbacks accordingly. |
| 129 | |
| 130 | With a bit of care, we could have : |
| 131 | - HH_SEND_LAST_CHUNK (sends the chunk pointed to by a pointer and dies) |
| 132 | => merges HEALTH, SEND_OK and SEND_HTTP_OK |
| 133 | |
| 134 | It sounds like the ctrl vs data state for the connection are per-direction |
| 135 | (eg: support an async ctrl shutw while still reading data). |
| 136 | |
| 137 | Also support shutr/shutw status at L4/L7. |
| 138 | |
| 139 | In practice, what we really need is : |
| 140 | |
| 141 | shutdown(conn) = |
| 142 | conn.data.shut() |
| 143 | conn.ctrl.shut() |
| 144 | conn.fd.shut() |
| 145 | |
| 146 | close(conn) = |
| 147 | conn.data.close() |
| 148 | conn.ctrl.close() |
| 149 | conn.fd.close() |
| 150 | |
| 151 | With SSL over Remote TCP (RTCP + RSSL) to reach the server, we would have : |
| 152 | |
| 153 | HTTP -> RTCP+RSSL connection <-> RTCP+RRAW connection -> TCP+SSL connection |
| 154 | |
| 155 | The connection has to be closed at 3 places after a successful response : |
| 156 | - DATA (RSSL over RTCP) |
| 157 | - CTRL (RTCP to close connection to server) |
| 158 | - SOCK (FD to close connection to second process) |
| 159 | |
| 160 | Externally, the connection is seen with very few flags : |
| 161 | - SHR |
| 162 | - SHW |
| 163 | - ERR |
| 164 | |
| 165 | We don't need a CLOSED flag as a connection must always be detached when it's closed. |
| 166 | |
| 167 | The internal status doesn't need to be exposed : |
| 168 | - FD allocated (Y/N) |
| 169 | - CTRL initialized (Y/N) |
| 170 | - CTRL connected (Y/N) |
| 171 | - CTRL handlers done (Y/N) |
| 172 | - CTRL failed (Y/N) |
| 173 | - CTRL shutr (Y/N) |
| 174 | - CTRL shutw (Y/N) |
| 175 | - DATA initialized (Y/N) |
| 176 | - DATA connected (Y/N) |
| 177 | - DATA handlers done (Y/N) |
| 178 | - DATA failed (Y/N) |
| 179 | - DATA shutr (Y/N) |
| 180 | - DATA shutw (Y/N) |
| 181 | |
| 182 | (note that having flags for operations needing to be completed might be easier) |
| 183 | -------------- |
| 184 | |
| 185 | Maybe we need to be able to call conn->fdset() and conn->fdclr() but it sounds |
| 186 | very unlikely since the only functions manipulating this are in the code of |
| 187 | the data/ctrl handlers. |
| 188 | |
| 189 | FDSET/FDCLR cannot be directly controlled by the stream interface since it also |
| 190 | depends on the DATA layer (WANT_READ/wANT_WRITE). |
| 191 | |
| 192 | But FDSET/FDCLR is probably controlled by who owns the connection (eg: DATA). |
| 193 | |