diff --git a/doc/configuration.txt b/doc/configuration.txt index 56bd10281..3056ba6b5 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -22727,6 +22727,18 @@ fc_err_str : string | 42 | "SOCKS4 Proxy handshake aborted by server" | | 43 | "SSL fatal error" | | 44 | "Reverse connect failure" | + | 45 | "Poller reported POLLERR" | + | 46 | "ECONNREFUSED returned by OS" | + | 47 | "ECONNRESET returned by OS" | + | 48 | "ENETUNREACH returned by OS" | + | 49 | "ENOMEM returned by OS" | + | 50 | "EBADF returned by OS" | + | 51 | "EFAULT returned by OS" | + | 52 | "EINVAL returned by OS" | + | 53 | "ENCONN returned by OS" | + | 54 | "ENSOCK returned by OS" | + | 55 | "ENOBUFS returned by OS" | + | 56 | "EPIPE returned by OS" | +----+---------------------------------------------------------------------------+ fc_fackets : integer diff --git a/include/haproxy/connection-t.h b/include/haproxy/connection-t.h index ad454a320..42f529e15 100644 --- a/include/haproxy/connection-t.h +++ b/include/haproxy/connection-t.h @@ -241,6 +241,19 @@ enum { CO_ER_SSL_FATAL, /* SSL fatal error during a SSL_read or SSL_write */ CO_ER_REVERSE, /* Error during reverse connect */ + + CO_ER_POLLERR, /* we only noticed POLLERR */ + CO_ER_EREFUSED, /* ECONNREFUSED returned to recv/send */ + CO_ER_ERESET, /* ECONNRESET returned to recv/send */ + CO_ER_EUNREACH, /* ENETUNREACH returned to recv/send */ + CO_ER_ENOMEM, /* ENOMEM returned to recv/send */ + CO_ER_EBADF, /* EBADF returned to recv/send (serious bug) */ + CO_ER_EFAULT, /* EFAULT returned to recv/send (serious bug) */ + CO_ER_EINVAL, /* EINVAL returned to recv/send (serious bug) */ + CO_ER_ENCONN, /* ENCONN returned to recv/send */ + CO_ER_ENSOCK, /* ENSOCK returned to recv/send */ + CO_ER_ENOBUFS, /* ENOBUFS returned to send */ + CO_ER_EPIPE, /* EPIPE returned to send */ }; /* error return codes for accept_conn() */ diff --git a/include/haproxy/connection.h b/include/haproxy/connection.h index dc187eb91..b5271ae4b 100644 --- a/include/haproxy/connection.h +++ b/include/haproxy/connection.h @@ -90,6 +90,7 @@ void conn_init(struct connection *conn, void *target); struct connection *conn_new(void *target); void conn_free(struct connection *conn); void conn_release(struct connection *conn); +void conn_set_errno(struct connection *conn, int err); struct conn_hash_node *conn_alloc_hash_node(struct connection *conn); struct sockaddr_storage *sockaddr_alloc(struct sockaddr_storage **sap, const struct sockaddr_storage *orig, socklen_t len); void sockaddr_free(struct sockaddr_storage **sap); @@ -107,6 +108,15 @@ void register_mux_proto(struct mux_proto_list *list); extern struct idle_conns idle_conns[MAX_THREADS]; +/* set conn->err_code to any CO_ER_* code if it was not set yet, otherwise + * does nothing. + */ +static inline void conn_set_errcode(struct connection *conn, int err_code) +{ + if (!conn->err_code) + conn->err_code = err_code; +} + /* returns true if the transport layer is ready */ static inline int conn_xprt_ready(const struct connection *conn) { diff --git a/src/connection.c b/src/connection.c index 59baec65b..b8289ae3f 100644 --- a/src/connection.c +++ b/src/connection.c @@ -744,10 +744,54 @@ const char *conn_err_code_str(struct connection *c) case CO_ER_SSL_FATAL: return "SSL fatal error"; case CO_ER_REVERSE: return "Reverse connect failure"; + + case CO_ER_POLLERR: return "Poller reported POLLERR"; + case CO_ER_EREFUSED: return "ECONNREFUSED returned by OS"; + case CO_ER_ERESET: return "ECONNRESET returned by OS"; + case CO_ER_EUNREACH: return "ENETUNREACH returned by OS"; + case CO_ER_ENOMEM: return "ENOMEM returned by OS"; + case CO_ER_EBADF: return "EBADF returned by OS"; + case CO_ER_EFAULT: return "EFAULT returned by OS"; + case CO_ER_EINVAL: return "EINVAL returned by OS"; + case CO_ER_ENCONN: return "ENCONN returned by OS"; + case CO_ER_ENSOCK: return "ENSOCK returned by OS"; + case CO_ER_ENOBUFS: return "ENOBUFS returned by OS"; + case CO_ER_EPIPE: return "EPIPE returned by OS"; } return NULL; } +/* Try to set conn->err_code to a meaningful value based on the errno value + * passed in . Values of errno are meant to be set on return from recv/ + * send mostly, so not all of them are handled. Any existing err_code is + * preserved. + */ +void conn_set_errno(struct connection *conn, int err) +{ + uchar code = 0; + + if (conn->err_code) + return; + + switch (err) { + case ECONNREFUSED: code = CO_ER_EREFUSED; break; + case ECONNRESET: code = CO_ER_ERESET; break; + case EHOSTUNREACH: code = CO_ER_EUNREACH; break; + case ENETUNREACH: code = CO_ER_EUNREACH; break; + case ENOMEM: code = CO_ER_ENOMEM; break; + case EBADF: code = CO_ER_EBADF; break; + case EFAULT: code = CO_ER_EFAULT; break; + case EINVAL: code = CO_ER_EINVAL; break; + case ENOTCONN: code = CO_ER_ENCONN; break; + case ENOTSOCK: code = CO_ER_ENSOCK; break; + case ENOBUFS: code = CO_ER_ENOBUFS; break; + case EPIPE: code = CO_ER_EPIPE; break; + default: code = CO_ER_SOCK_ERR; break; + } + + conn->err_code = code; +} + /* Send a message over an established connection. It makes use of send() and * returns the same return code and errno. If the socket layer is not ready yet * then -1 is returned and ENOTSOCK is set into errno. If the fd is not marked