MEDIUM: stream-int: make sure to try to immediately validate the connection

In the rare case of immediate connect() (unix sockets, socket pairs, and
occasionally TCP over the loopback), it is counter-productive to subscribe
for sending and then getting immediately back to process_stream() after
having passed through si_cs_process() just to update the connection. We
already know it is established and it doesn't have any handshake anymore
so we just have to complete it and return to process_stream() with the
stream_interface in the SI_ST_RDY state. In this case, process_stream will
simply loop back to the beginning to synchronize the state and turn it to
SI_ST_EST/ASS/CLO/TAR etc.

This will save us from having to needlessly subscribe in the connect()
code, something which in addition cannot work with edge-triggered pollers.
This commit is contained in:
Willy Tarreau 2020-03-04 16:42:03 +01:00
parent 667fefdc90
commit ada4c5806b
2 changed files with 38 additions and 0 deletions

View File

@ -1525,6 +1525,40 @@ int connect_server(struct stream *s)
}
/* Now handle synchronously connected sockets. We know the stream-int
* is at least in state SI_ST_CON. These ones typically are UNIX
* sockets, socket pairs, and occasionally TCP connections on the
* loopback on a heavily loaded system.
*/
if ((srv_conn->flags & CO_FL_ERROR || srv_cs->flags & CS_FL_ERROR))
s->si[1].flags |= SI_FL_ERR;
/* If we had early data, and the handshake ended, then
* we can remove the flag, and attempt to wake the task up,
* in the event there's an analyser waiting for the end of
* the handshake.
*/
if (!(srv_conn->flags & (CO_FL_WAIT_XPRT | CO_FL_EARLY_SSL_HS)))
srv_cs->flags &= ~CS_FL_WAIT_FOR_HS;
if (!si_state_in(s->si[1].state, SI_SB_EST|SI_SB_DIS|SI_SB_CLO) &&
(srv_conn->flags & CO_FL_WAIT_XPRT) == 0) {
s->si[1].exp = TICK_ETERNITY;
si_oc(&s->si[1])->flags |= CF_WRITE_NULL;
if (s->si[1].state == SI_ST_CON)
s->si[1].state = SI_ST_RDY;
}
/* Report EOI on the channel if it was reached from the mux point of
* view.
*
* Note: This test is only required because si_cs_process is also the SI
* wake callback. Otherwise si_cs_recv()/si_cs_send() already take
* care of it.
*/
if ((srv_cs->flags & CS_FL_EOI) && !(si_ic(&s->si[1])->flags & CF_EOI))
si_ic(&s->si[1])->flags |= (CF_EOI|CF_READ_PARTIAL);
return SF_ERR_NONE; /* connection is OK */
}

View File

@ -2085,6 +2085,10 @@ struct task *process_stream(struct task *t, void *context, unsigned short state)
if (si_b->state == SI_ST_REQ)
back_handle_st_req(s);
/* get a chance to complete an immediate connection setup */
if (si_b->state == SI_ST_RDY)
goto resync_stream_interface;
/* applets directly go to the ESTABLISHED state. Similarly,
* servers experience the same fate when their connection
* is reused.