Conversation
|
@djc Simple and elegant. Not sure if "accept_error" is the best name for the function (given that could be read as accepting an error or converting an error in accept). Maybe something like "assess_accept_error" would be better. The one thing I'm wondering about is if the "never fail" approach of the tls enabled loop might have masked other errors that appear in practice (e.g., we don't run these services with tracing disabled, so we won't know). Potential candidates: I didn't find user code that handles EINTR in accept, so I guess that's not a thing in practice (edit: still, ignoring it won't hurt). Most programs will capsize in case of EMFILE and ENFILE anyway (some resistent daemons handle it though by delaying the next loop iteration), so some services would benefit from it. EWOULDBLOCK is handled inside tokio/net, but it seems like EAGAIN isn't. So based on this quick "analysis", I would suggest to handle at least EAGAIN and EINTR (edited) in here as well (unless I missed something, which is quite possible). To make sure, I checked the source of squid proxy (which is around long enough to have these things covered), which does this: const auto rawSock = accept(conn->fd, gai->ai_addr, &gai->ai_addrlen);
if (rawSock < 0) {
errcode = errno; // store last accept errno locally.
Ip::Address::FreeAddr(gai);
if (ignoreErrno(errcode) || errcode == ECONNABORTED) {
debugs(50, 5, status() << ": " << xstrerr(errcode));
return false;
} else {
throw TextException(ToSBuf("Failed to accept an incoming connection: ", xstrerr(errcode)), Here());
}
}and /*
* hm, this might be too general-purpose for all the places we'd
* like to use it.
*/
int
ignoreErrno(int ierrno)
{
switch (ierrno) {
case EINPROGRESS:
case EWOULDBLOCK:
#if EAGAIN != EWOULDBLOCK
case EAGAIN:
#endif
case EALREADY:
case EINTR:
#ifdef ERESTART
case ERESTART:
#endif
return 1;
default:
return 0;
}
/* NOTREACHED */
} |
|
Changed the name to |
Motivation
Share error handling logic from #1874 between TCP and TLS accept loops.
cc @grembo