diff --git a/doc/design-thoughts/binding-possibilities.txt b/doc/design-thoughts/binding-possibilities.txt new file mode 100644 index 000000000..3f5e43219 --- /dev/null +++ b/doc/design-thoughts/binding-possibilities.txt @@ -0,0 +1,167 @@ +2013/10/10 - possibilities for setting source and destination addresses + + +When establishing a connection to a remote device, this device is designated +as a target, which designates an entity defined in the configuration. A same +target appears only once in a configuration, and multiple targets may share +the same settings if needed. + +The following types of targets are currently supported : + + - listener : all connections with this type of target come from clients ; + - server : connections to such targets are for "server" lines ; + - peer : connections to such target address "peer" lines in "peers" + sections ; + - proxy : these targets are used by "dispatch", "option transparent" + or "option http_proxy" statements. + +A connection might not be reused between two different targets, even if all +parameters seem similar. One of the reason is that some parameters are specific +to the target and are not easy or not cheap to compare (eg: bind to interface, +mss, ...). + +A number of source and destination addresses may be set for a given target. + + - listener : + - the "from" address:port is set by accept() + + - the "to" address:port is set if conn_get_to_addr() is called + + - peer : + - the "from" address:port is not set + + - the "to" address:port is static and dependent only on the peer + + - server : + - the "from" address may be set alone when "source" is used with + a forced IP address, or when "usesrc clientip" is used. + + - the "from" port may be set only combined with the address when + "source" is used with IP:port, IP:port-range or "usesrc client" is + used. Note that in this case, both the address and the port may be + 0, meaning that the kernel will pick the address or port and that + the final value might not match the one explicitly set (eg: + important for logging). + + - the "from" address may be forced from a header which implies it + may change between two consecutive requests on the same connection. + + - the "to" address and port are set together when connecting to a + regular server, or by copying the client's IP address when + "server 0.0.0.0" is used. Note that the destination port may be + an offset applied to the original destination port. + + - proxy : + - the "from" address may be set alone when "source" is used with a + forced IP address or when "usesrc clientip" is used. + + - the "from" port may be set only combined with the address when + "source" is used with IP:port or with "usesrc client". There is + no ip:port range for a proxy as of now. Same comment applies as + above when port and/or address are 0. + + - the "from" address may be forced from a header which implies it + may change between two consecutive requests on the same connection. + + - the "to" address and port are set together, either by configuration + when "dispatch" is used, or dynamically when "transparent" is used + (1:1 with client connection) or "option http_proxy" is used, where + each client request may lead to a different destination address. + + +At the moment, there are some limits in what might happen between multiple +concurrent requests to a same target. + + - peers parameter do not change, so no problem. + + - server parameters may change in this way : + - a connection may require a source bound to an IP address found in a + header, which will fall back to the "source" settings if the address + is not found in this header. This means that the source address may + switch between a dynamically forced IP address and another forced + IP and/or port range. + + - if the element is not found (eg: header), the remaining "forced" + source address might very well be empty (unset), so the connection + reuse is acceptable when switching in that direction. + + - it is not possible to switch between client and clientip or any of + these and hdr_ip() because they're exclusive. + + - using a source address/port belonging to a port range is compatible + with connection reuse because there is a single range per target, so + switching from a range to another range means we remain in the same + range. + + - destination address may currently not change since the only possible + case for dynamic destination address setting is the transparent mode, + reproducing the client's destination address. + + - proxy parameters may change in this way : + - a connection may require a source bound to an IP address found in a + header, which will fall back to the "source" settings if the address + is not found in this header. This means that the source address may + switch between a dynamically forced IP address and another forced + IP and/or port range. + + - if the element is not found (eg: header), the remaining "forced" + source address might very well be empty (unset), so the connection + reuse is acceptable when switching in that direction. + + - it is not possible to switch between client and clientip or any of + these and hdr_ip() because they're exclusive. + + - proxies do not support port ranges at the moment. + + - destination address might change in the case where "option http_proxy" + is used. + +So, for each source element (IP, port), we want to know : + - if the element was assigned by static configuration (eg: ":80") + - if the element was assigned from a connection-specific value (eg: usesrc clientip) + - if the element was assigned from a configuration-specific range (eg: 1024-65535) + - if the element was assigned from a request-specific value (eg: hdr_ip(xff)) + - if the element was not assigned at all + +For the destination, we want to know : + - if the element was assigned by static configuration (eg: ":80") + - if the element was assigned from a connection-specific value (eg: transparent) + - if the element was assigned from a request-specific value (eg: http_proxy) + +We don't need to store the information about the origin of the dynamic value +since we have the value itself. So in practice we have : + - default value, unknown (not yet checked with getsockname/getpeername) + - default value, known (check done) + - forced value (known) + - forced range (known) + +We can't do that on an ip:port basis because the port may be fixed regardless +of the address and conversely. + +So that means : + + enum { + CO_ADDR_NONE = 0, /* not set, unknown value */ + CO_ADDR_KNOWN = 1, /* not set, known value */ + CO_ADDR_FIXED = 2, /* fixed value, known */ + CO_ADDR_RANGE = 3, /* from assigned range, known */ + } conn_addr_values; + + unsigned int new_l3_src_status:2; + unsigned int new_l4_src_status:2; + unsigned int new_l3_dst_status:2; + unsigned int new_l4_dst_status:2; + + unsigned int cur_l3_src_status:2; + unsigned int cur_l4_src_status:2; + unsigned int cur_l3_dsp_status:2; + unsigned int cur_l4_dst_status:2; + + unsigned int new_family:2; + unsigned int cur_family:2; + +Note: this obsoletes CO_FL_ADDR_FROM_SET and CO_FL_ADDR_TO_SET. These flags +must be changed to individual l3+l4 checks ORed between old and new values, +or better, set to cur only which will inherit new. + +In the connection, these values may be merged in the same word as err_code. diff --git a/doc/design-thoughts/connection-reuse.txt b/doc/design-thoughts/connection-reuse.txt new file mode 100644 index 000000000..0c90eb229 --- /dev/null +++ b/doc/design-thoughts/connection-reuse.txt @@ -0,0 +1,139 @@ +2013/10/17 - server connection management and reuse + +Current state +------------- + +At the moment, a connection entity is needed to carry any address +information. This means in the following situations, we need a server +connection : + +- server is elected and the server's destination address is set + +- transparent mode is elected and the destination address is set from + the incoming connection + +- proxy mode is enabled, and the destination's address is set during + the parsing of the HTTP request + +- connection to the server fails and must be retried on the same + server using the same parameters, especially the destination + address (SN_ADDR_SET not removed) + + +On the accepting side, we have further requirements : + +- allocate a clean connection without a stream interface + +- incrementally set the accepted connection's parameters without + clearing it, and keep track of what is set (eg: getsockname). + +- initialize a stream interface in established mode + +- attach the accepted connection to a stream interface + + +This means several things : + +- the connection has to be allocated on the fly the first time it is + needed to store the source or destination address ; + +- the connection has to be attached to the stream interface at this + moment ; + +- it must be possible to incrementally set some settings on the + connection's addresses regardless of the connection's current state + +- the connection must not be released across connection retries ; + +- it must be possible to clear a connection's parameters for a + redispatch without having to detach/attach the connection ; + +- we need to allocate a connection without an existing stream interface + +So on the accept() side, it looks like this : + + fd = accept(); + conn = new_conn(); + get_some_addr_info(&conn->addr); + ... + si = new_si(); + si_attach_conn(si, conn); + si_set_state(si, SI_ST_EST); + ... + get_more_addr_info(&conn->addr); + +On the connect() side, it looks like this : + + si = new_si(); + while (!properly_connected) { + if (!(conn = si->end)) { + conn = new_conn(); + conn_clear(conn); + si_attach_conn(si, conn); + } + else { + if (connected) { + f = conn->flags & CO_FL_XPRT_TRACKED; + conn->flags &= ~CO_FL_XPRT_TRACKED; + conn_close(conn); + conn->flags |= f; + } + if (!correct_dest) + conn_clear(conn); + } + set_some_addr_info(&conn->addr); + si_set_state(si, SI_ST_CON); + ... + set_more_addr_info(&conn->addr); + conn->connect(); + if (must_retry) { + close_conn(conn); + } + } + +Note: we need to be able to set the control and transport protocols. +On outgoing connections, this is set once we know the destination address. +On incoming connections, this is set the earliest possible (once we know +the source address). + +The problem analysed below was solved on 2013/10/22 + +| ==> the real requirement is to know whether a connection is still valid or not +| before deciding to close it. CO_FL_CONNECTED could be enough, though it +| will not indicate connections that are still waiting for a connect to occur. +| This combined with CO_FL_WAIT_L4_CONN and CO_FL_WAIT_L6_CONN should be OK. +| +| Alternatively, conn->xprt could be used for this, but needs some careful checks +| (it's used by conn_full_close at least). +| +| Right now, conn_xprt_close() checks conn->xprt and sets it to NULL. +| conn_full_close() also checks conn->xprt and sets it to NULL, except +| that the check on ctrl is performed within xprt. So conn_xprt_close() +| followed by conn_full_close() will not close the file descriptor. +| Note that conn_xprt_close() is never called, maybe we should kill it ? +| +| Note: at the moment, it's problematic to leave conn->xprt to NULL before doing +| xprt_init() because we might end up with a pending file descriptor. Or at +| least with some transport not de-initialized. We might thus need +| conn_xprt_close() when conn_xprt_init() fails. +| +| The fd should be conditionned by ->ctrl only, and the transport layer by ->xprt. +| +| - conn_prepare_ctrl(conn, ctrl) +| - conn_prepare_xprt(conn, xprt) +| - conn_prepare_data(conn, data) +| +| Note: conn_xprt_init() needs conn->xprt so it's not a problem to set it early. +| +| One problem might be with conn_xprt_close() not being able to know if xprt_init() +| was called or not. That's where it might make sense to only set ->xprt during init. +| Except that it does not fly with outgoing connections (xprt_init is called after +| connect()). +| +| => currently conn_xprt_close() is only used by ssl_sock.c and decides whether +| to do something based on ->xprt_ctx which is set by ->init() from xprt_init(). +| So there is nothing to worry about. We just need to restore conn_xprt_close() +| and rely on ->ctrl to close the fd instead of ->xprt. +| +| => we have the same issue with conn_ctrl_close() : when is the fd supposed to be +| valid ? On outgoing connections, the control is set much before the fd... diff --git a/doc/design-thoughts/entities-v2.txt b/doc/design-thoughts/entities-v2.txt new file mode 100644 index 000000000..8c9eb4843 --- /dev/null +++ b/doc/design-thoughts/entities-v2.txt @@ -0,0 +1,276 @@ +2012/07/05 - Connection layering and sequencing + + +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). + +Example: an SSL conn relies on an FD. The buffer is full, and wants the conn to +stop reading. It must not stop the FD itself. It is the read function which +should notice that it has nothing to do with a read wake-up, which needs to +disable reading. + +Conversely, when calling conn->chk_rcv(), the reader might get a WANT_READ or +even WANT_WRITE and adjust the FDs accordingly. + +------------------------ + +OK, the problem is simple : we don't manipulate the FD at the right level. +We should have : + ->connect(), ->chk_snd(), ->chk_rcv(), ->shutw(), ->shutr() which are + called from the upper layer (buffer) + ->recv(), ->send(), called from the lower layer + +Note that the SHR is *reported* by lower layer but can be forced by upper +layer. In this case it's like a delayed abort. The difficulty consists in +knowing the output data were correctly read. Probably we'd need to drain +incoming data past the active shutr(). + +The only four purposes of the top-down shutr() call are : + - acknowledge a shut read report : could probably be done better + - read timeout => disable reading : it's a delayed abort. We want to + report that the buffer is SHR, maybe even the connection, but the + FD clearly isn't. + - read abort due to error on the other side or desire to close (eg: + http-server-close) : delayed abort + - complete abort + +The active shutr() is problematic as we can't disable reading if we expect some +exchanges for data acknowledgement. We probably need to drain data only until +the shutw() has been performed and ACKed. + +A connection shut down for read would behave like this : + + 1) bidir exchanges + + 2) shutr() => read_abort_pending=1 + + 3) drain input, still send output + + 4) shutw() + + 5) drain input, wait for read0 or ack(shutw) + + 6) close() + +--------------------- 2012/07/05 ------------------- + +Communications must be performed this way : + + connection <-> channel <-> connection + +A channel is composed of flags and stats, and may store data in either a buffer +or a pipe. We need low-layer operations between sockets and buffers or pipes. +Right now we only support sockets, but later we might support remote sockets +and maybe pipes or shared memory segments. + +So we need : + + - raw_sock_to_buf() => receive raw data from socket into buffer + - raw_sock_to_pipe => receive raw data from socket into pipe (splice in) + - raw_sock_from_buf() => send raw data from buffer to socket + - raw_sock_from_pipe => send raw data from pipe to socket (splice out) + + - ssl_sock_to_buf() => receive ssl data from socket into buffer + - ssl_sock_to_pipe => receive ssl data from socket into a pipe (NULL) + - ssl_sock_from_buf() => send ssl data from buffer to socket + - ssl_sock_from_pipe => send ssl data from pipe to socket (NULL) + +These functions should set such status flags : + +#define ERR_IN 0x01 +#define ERR_OUT 0x02 +#define SHUT_IN 0x04 +#define SHUT_OUT 0x08 +#define EMPTY_IN 0x10 +#define FULL_OUT 0x20 + diff --git a/doc/internals/sequence.fig b/doc/internals/sequence.fig new file mode 100644 index 000000000..295ace79b --- /dev/null +++ b/doc/internals/sequence.fig @@ -0,0 +1,123 @@ +#FIG 3.2 Produced by xfig version 3.2.5-alpha5 +Portrait +Center +Metric +A4 +100.00 +Single +-2 +1200 2 +6 900 945 3015 1800 +6 1035 1215 3015 1800 +6 1035 1215 3015 1350 +2 2 0 1 26 6 51 -1 20 0.000 0 0 -1 0 0 5 + 1035 1215 1620 1215 1620 1350 1035 1350 1035 1215 +4 0 0 50 -1 12 7 0.0000 4 90 1275 1710 1305 Standard settings\001 +-6 +6 1035 1440 2385 1575 +2 2 0 1 9 11 51 -1 20 0.000 0 0 -1 0 0 5 + 1035 1440 1620 1440 1620 1575 1035 1575 1035 1440 +4 0 0 50 -1 12 7 0.0000 4 60 675 1710 1530 Rule sets\001 +-6 +6 1035 1665 2790 1800 +2 2 0 1 13 2 52 -1 20 0.000 0 0 -1 0 0 5 + 1035 1665 1620 1665 1620 1800 1035 1800 1035 1665 +4 0 0 50 -1 12 7 0.0000 4 75 1050 1710 1755 HTTP mode only\001 +-6 +-6 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 945 1125 945 1800 +4 0 0 50 -1 17 10 0.0000 4 150 615 900 1080 Captions\001 +-6 +6 450 2250 3510 3195 +4 0 0 50 -1 16 10 0.0000 4 150 2865 450 2385 Each time a poller detects an activity on a\001 +4 0 0 50 -1 16 10 0.0000 4 150 2940 450 2580 listening socket, this sequence is executed.\001 +4 0 0 50 -1 16 10 0.0000 4 150 3000 450 2775 Note that stream_sock_accept() loops until\001 +4 0 0 50 -1 16 10 0.0000 4 150 3030 450 2970 accept() returns an error or tune.maxaccept\001 +4 0 0 50 -1 16 10 0.0000 4 150 1830 450 3165 loops have been executed.\001 +-6 +6 450 3375 3420 4275 +4 0 0 50 -1 16 10 0.0000 4 150 2535 450 3510 Once the session is started, function\001 +4 0 0 50 -1 16 10 0.0000 4 150 2880 450 3705 process_session() will be called once then\001 +4 0 0 50 -1 16 10 0.0000 4 150 2895 450 3900 each time an activity is detected on any of\001 +4 0 0 50 -1 16 10 0.0000 4 150 2955 450 4095 monitored file descriptors belonging to the\001 +4 0 0 50 -1 16 10 0.0000 4 120 555 450 4275 session.\001 +-6 +6 4230 945 6480 1125 +2 2 0 1 26 6 51 -1 20 0.000 0 0 -1 0 0 5 + 4230 945 6345 945 6345 1125 4230 1125 4230 945 +4 0 0 50 -1 14 10 0.0000 4 105 2205 4275 1080 rate-limit sessions ?\001 +-6 +6 4455 1620 7065 1800 +2 2 0 1 26 6 51 -1 20 0.000 0 0 -1 0 0 5 + 4455 1620 6885 1620 6885 1800 4455 1800 4455 1620 +4 0 0 50 -1 14 10 0.0000 4 135 2520 4521 1755 monitor-net (mode=tcp) ?\001 +-6 +6 4455 1845 7470 2025 +2 2 0 1 9 11 51 -1 20 0.000 0 0 -1 0 0 5 + 4455 1845 7290 1845 7290 2025 4455 2025 4455 1845 +4 0 0 50 -1 14 10 0.0000 4 135 2940 4500 1980 tcp-request connection {...}\001 +-6 +6 4635 3195 7425 3735 +6 4680 3420 7380 3600 +2 2 0 1 26 6 51 -1 20 0.000 0 0 -1 0 0 5 + 4680 3420 7200 3420 7200 3600 4680 3600 4680 3420 +4 0 0 50 -1 14 10 0.0000 4 135 2625 4725 3555 monitor-net (mode=http) ?\001 +-6 +2 2 0 1 13 2 52 -1 20 0.000 0 0 -1 0 0 5 + 4635 3195 7425 3195 7425 3735 4635 3735 4635 3195 +4 0 0 50 -1 14 10 0.0000 4 135 1575 4725 3330 http_init_txn()\001 +-6 +2 1 0 1 0 7 51 -1 -1 4.000 0 0 -1 1 0 3 + 1 1 1.00 60.00 120.00 + 6885 1710 7200 1710 7200 675 +2 1 0 1 0 7 51 -1 -1 4.000 0 0 -1 1 0 3 + 1 1 1.00 60.00 120.00 + 7290 1935 7425 1935 7425 675 +2 1 0 1 0 7 51 -1 -1 4.000 0 0 -1 1 0 3 + 1 1 1.00 60.00 120.00 + 5850 2340 7650 2340 7650 675 +2 1 0 1 0 7 51 -1 -1 4.000 0 0 -1 1 0 3 + 1 1 1.00 60.00 120.00 + 7200 3510 7875 3510 7875 675 +2 1 0 1 0 7 51 -1 -1 0.000 0 0 -1 0 0 2 + 4140 675 4140 4275 +2 1 0 1 0 7 51 -1 -1 0.000 0 0 -1 0 0 2 + 4320 1575 4320 4275 +2 1 0 1 0 7 51 -1 -1 4.000 0 0 -1 1 0 3 + 1 1 1.00 60.00 120.00 + 5580 1260 6750 1260 6750 675 +2 1 0 1 0 7 51 -1 -1 0.000 0 0 -1 0 0 2 + 4545 2700 4545 4050 +2 1 0 1 0 7 51 -1 -1 4.000 0 0 -1 1 0 3 + 1 1 1.00 60.00 120.00 + 6345 1035 6525 1035 6525 675 +2 2 0 1 26 6 51 -1 20 0.000 0 0 -1 0 0 5 + 4635 3825 6030 3825 6030 4005 4635 4005 4635 3825 +2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 3 + 6030 3915 7875 3915 7875 3510 +2 2 0 1 26 6 51 -1 20 0.000 0 0 -1 0 0 5 + 4230 720 5895 720 5895 900 4230 900 4230 720 +2 1 0 1 0 7 51 -1 -1 4.000 0 0 -1 1 0 3 + 1 1 1.00 60.00 120.00 + 5895 810 6300 810 6300 675 +4 1 0 51 -1 12 7 0.0000 4 60 375 7515 585 close\001 +4 1 0 51 -1 12 7 0.0000 4 75 1275 6930 2250 not enough memory\001 +4 0 0 51 -1 12 7 1.5708 4 60 1575 8010 2790 return "OK" and close\001 +4 0 0 50 -1 14 10 0.0000 4 135 1365 4275 1305 sock=accept()\001 +4 0 0 50 -1 14 10 0.0000 4 135 1890 4500 2655 frontend_accept(s)\001 +4 0 0 50 -1 14 10 0.0000 4 135 2100 4275 1530 session_accept(sock)\001 +4 0 0 50 -1 14 10 0.0000 4 105 1365 4500 2385 s=new session\001 +4 0 0 50 -1 14 10 0.0000 4 135 1575 4635 2880 prepare logs(s)\001 +4 0 0 50 -1 14 10 0.0000 4 135 2100 4635 3105 prepare socket(sock)\001 +4 0 0 50 -1 14 10 0.0000 4 105 1365 4680 3960 mode=health ?\001 +4 1 0 51 -1 12 7 0.0000 4 60 225 7605 3465 Yes\001 +4 1 0 51 -1 12 7 0.0000 4 60 225 7605 3870 Yes\001 +4 1 0 51 -1 12 7 0.0000 4 60 225 7065 1665 Yes\001 +4 1 0 51 -1 12 7 0.0000 4 75 300 6570 1215 Fail\001 +4 0 0 50 -1 14 10 0.0000 4 120 1680 4500 4230 start session(s)\001 +4 0 0 50 -1 14 10 0.0000 4 105 1785 4275 855 maxconn reached ?\001 +4 1 0 51 -1 12 7 0.0000 4 90 450 6525 585 ignore\001 +4 1 0 51 -1 12 7 0.0000 4 60 225 6120 765 Yes\001 +4 0 0 50 -1 17 12 0.0000 4 210 3000 450 630 Session instantiation sequence\001 +4 0 0 50 -1 14 10 0.0000 4 135 2100 4050 630 stream_sock_accept()\001