*
*/
+/* this is to have tcp_info defined on systems using musl
+ * library, such as Alpine Linux.
+ */
+#define _GNU_SOURCE
+
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
static int tcp_resume_receiver(struct receiver *rx);
static void tcp_enable_listener(struct listener *listener);
static void tcp_disable_listener(struct listener *listener);
+static int tcp_get_info(struct connection *conn, long long int *info, int info_num);
/* Note: must not be declared <const> as its list will be overwritten */
struct protocol proto_tcpv4 = {
.drain = sock_drain,
.check_events = sock_check_events,
.ignore_events = sock_ignore_events,
+ .get_info = tcp_get_info,
/* binding layer */
.rx_suspend = tcp_suspend_receiver,
.drain = sock_drain,
.check_events = sock_check_events,
.ignore_events = sock_ignore_events,
+ .get_info = tcp_get_info,
/* binding layer */
.rx_suspend = tcp_suspend_receiver,
return -1;
}
+#ifdef TCP_INFO
+/* Returns some tcp_info data if it's available for <conn> connection into <*info>.
+ * "info_num" represents the required value.
+ * If the function fails it returns 0, otherwise it returns 1 and "result" is filled.
+ */
+static int tcp_get_info(struct connection *conn, long long int *info, int info_num)
+{
+ struct tcp_info tcp_info;
+ socklen_t optlen;
+
+ /* The fd may not be available for the tcp_info struct, and the
+ syscal can fail. */
+ optlen = sizeof(tcp_info);
+ if ((conn->flags & CO_FL_FDLESS) ||
+ getsockopt(conn->handle.fd, IPPROTO_TCP, TCP_INFO, &tcp_info, &optlen) == -1)
+ return 0;
+
+ switch (info_num) {
+#if defined(__APPLE__)
+ case 0: *info = tcp_info.tcpi_rttcur; break;
+ case 1: *info = tcp_info.tcpi_rttvar; break;
+ case 2: *info = tcp_info.tcpi_tfo_syn_data_acked; break;
+ case 4: *info = tcp_info.tcpi_tfo_syn_loss; break;
+ case 5: *info = tcp_info.tcpi_rto; break;
+#else
+ /* all other platforms supporting TCP_INFO have these ones */
+ case 0: *info = tcp_info.tcpi_rtt; break;
+ case 1: *info = tcp_info.tcpi_rttvar; break;
+# if defined(__linux__)
+ /* these ones are common to all Linux versions */
+ case 2: *info = tcp_info.tcpi_unacked; break;
+ case 3: *info = tcp_info.tcpi_sacked; break;
+ case 4: *info = tcp_info.tcpi_lost; break;
+ case 5: *info = tcp_info.tcpi_retrans; break;
+ case 6: *info = tcp_info.tcpi_fackets; break;
+ case 7: *info = tcp_info.tcpi_reordering; break;
+# elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+ /* the ones are found on FreeBSD, NetBSD and OpenBSD featuring TCP_INFO */
+ case 2: *info = tcp_info.__tcpi_unacked; break;
+ case 3: *info = tcp_info.__tcpi_sacked; break;
+ case 4: *info = tcp_info.__tcpi_lost; break;
+ case 5: *info = tcp_info.__tcpi_retrans; break;
+ case 6: *info = tcp_info.__tcpi_fackets; break;
+ case 7: *info = tcp_info.__tcpi_reordering; break;
+# endif
+#endif // apple
+ default: return 0;
+ }
+
+ return 1;
+}
+#else
+static int tcp_get_info(struct connection *conn, long long int *info, int info_num)
+{
+ return 0;
+}
+#endif /* TCP_INFO */
+
/*
* Local variables:
*
*/
-/* this is to have tcp_info defined on systems using musl
- * library, such as Alpine Linux.
- */
-#define _GNU_SOURCE
-
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
int dir, int val)
{
struct connection *conn;
- struct tcp_info info;
- socklen_t optlen;
/* strm can be null. */
if (!smp->strm)
return 0;
+ smp->data.type = SMP_T_SINT;
/* get the object associated with the stream connector.The
* object can be other thing than a connection. For example,
- * it be a appctx.
+ * it could be an appctx.
*/
conn = (dir == 0 ? sc_conn(smp->strm->scf) : sc_conn(smp->strm->scb));
- if (!conn)
+ if (!conn || !conn->ctrl->get_info ||
+ !conn->ctrl->get_info(conn, &smp->data.u.sint, val))
return 0;
- /* The fd may not be available for the tcp_info struct, and the
- syscal can fail. */
- optlen = sizeof(info);
- if ((conn->flags & CO_FL_FDLESS) ||
- getsockopt(conn->handle.fd, IPPROTO_TCP, TCP_INFO, &info, &optlen) == -1)
- return 0;
-
- /* extract the value. */
- smp->data.type = SMP_T_SINT;
- switch (val) {
-#if defined(__APPLE__)
- case 0: smp->data.u.sint = info.tcpi_rttcur; break;
- case 1: smp->data.u.sint = info.tcpi_rttvar; break;
- case 2: smp->data.u.sint = info.tcpi_tfo_syn_data_acked; break;
- case 4: smp->data.u.sint = info.tcpi_tfo_syn_loss; break;
- case 5: smp->data.u.sint = info.tcpi_rto; break;
-#else
- /* all other platforms supporting TCP_INFO have these ones */
- case 0: smp->data.u.sint = info.tcpi_rtt; break;
- case 1: smp->data.u.sint = info.tcpi_rttvar; break;
-# if defined(__linux__)
- /* these ones are common to all Linux versions */
- case 2: smp->data.u.sint = info.tcpi_unacked; break;
- case 3: smp->data.u.sint = info.tcpi_sacked; break;
- case 4: smp->data.u.sint = info.tcpi_lost; break;
- case 5: smp->data.u.sint = info.tcpi_retrans; break;
- case 6: smp->data.u.sint = info.tcpi_fackets; break;
- case 7: smp->data.u.sint = info.tcpi_reordering; break;
-# elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
- /* the ones are found on FreeBSD, NetBSD and OpenBSD featuring TCP_INFO */
- case 2: smp->data.u.sint = info.__tcpi_unacked; break;
- case 3: smp->data.u.sint = info.__tcpi_sacked; break;
- case 4: smp->data.u.sint = info.__tcpi_lost; break;
- case 5: smp->data.u.sint = info.__tcpi_retrans; break;
- case 6: smp->data.u.sint = info.__tcpi_fackets; break;
- case 7: smp->data.u.sint = info.__tcpi_reordering; break;
-# endif
-#endif // apple
- default: return 0;
- }
return 1;
}