commit 3aec358: [Project] Rdns: Add reaper for inactive TCP connections
Vsevolod Stakhov
vsevolod at highsecure.ru
Wed Jan 5 11:28:12 UTC 2022
Author: Vsevolod Stakhov
Date: 2022-01-02 23:53:55 +0000
URL: https://github.com/rspamd/rspamd/commit/3aec3589a45dd71191f47da93656b6b5614903de
[Project] Rdns: Add reaper for inactive TCP connections
---
contrib/librdns/resolver.c | 13 +++++
contrib/librdns/util.c | 124 ++++++++++++++++++++++++++++++++++++---------
contrib/librdns/util.h | 14 ++++-
3 files changed, 127 insertions(+), 24 deletions(-)
diff --git a/contrib/librdns/resolver.c b/contrib/librdns/resolver.c
index 520e85588..3197230ed 100644
--- a/contrib/librdns/resolver.c
+++ b/contrib/librdns/resolver.c
@@ -526,8 +526,21 @@ static void
rdns_process_periodic (void *arg)
{
struct rdns_resolver *resolver = (struct rdns_resolver*)arg;
+ struct rdns_server *serv;
UPSTREAM_RESCAN (resolver->servers, time (NULL));
+
+ UPSTREAM_FOREACH (resolver->servers, serv) {
+ for (int i = 0; i < serv->tcp_io_cnt; i ++) {
+ if (IS_CHANNEL_CONNECTED(serv->tcp_io_channels[i])) {
+ /* Disconnect channels with no requests in flight */
+ if (kh_size(serv->tcp_io_channels[i]->requests) == 0) {
+ rdns_debug ("reset inactive TCP connection to %s", serv->name);
+ rdns_ioc_tcp_reset (serv->tcp_io_channels[i]);
+ }
+ }
+ }
+ }
}
static void
diff --git a/contrib/librdns/util.c b/contrib/librdns/util.c
index e33ab709c..61c244199 100644
--- a/contrib/librdns/util.c
+++ b/contrib/librdns/util.c
@@ -515,8 +515,15 @@ rdns_ioc_free (struct rdns_io_channel *ioc)
ioc->resolver->async->del_read (ioc->resolver->async->data,
ioc->async_io);
kh_destroy(rdns_requests_hash, ioc->requests);
- close (ioc->sock);
- free (ioc->saddr);
+
+ if (ioc->sock != -1) {
+ close(ioc->sock);
+ }
+
+ if (ioc->saddr != NULL) {
+ free(ioc->saddr);
+ }
+
free (ioc);
}
@@ -553,28 +560,12 @@ rdns_ioc_new (struct rdns_server *serv,
if (is_tcp) {
/* We also need to connect a TCP channel and set a TCP buffer */
nioc->tcp = (struct rdns_tcp_channel *)(((unsigned char *)nioc) + sizeof(*nioc));
- int r = connect (nioc->sock, nioc->saddr, nioc->slen);
-
- if (r == -1) {
- if (errno != EAGAIN && errno != EINTR && errno != EINPROGRESS) {
- rdns_err ("cannot connect a TCP socket: %s for server %s",
- strerror(errno), serv->name);
- close(nioc->sock);
- free(nioc);
- return NULL;
- }
- else {
- /* We need to wait for write readiness here */
- nioc->async_io = resolver->async->add_write (resolver->async->data,
- nioc->sock, nioc);
- }
- }
- else {
- /* Always be ready to read from a TCP socket */
- nioc->flags |= RDNS_CHANNEL_CONNECTED|RDNS_CHANNEL_ACTIVE;
- nioc->tcp->async_read = resolver->async->add_read(resolver->async->data,
- nioc->sock, nioc);
+ if (!rdns_ioc_tcp_connect(nioc)) {
+ rdns_err ("cannot connect TCP socket to %s: %s", serv->name,
+ strerror (errno));
+ free (nioc);
+ return NULL;
}
nioc->flags |= RDNS_CHANNEL_TCP;
@@ -636,6 +627,93 @@ rdns_request_release (struct rdns_request *req)
REF_RELEASE (req);
}
+void
+rdns_ioc_tcp_reset (struct rdns_io_channel *ioc)
+{
+ struct rdns_resolver *resolver = ioc->resolver;
+
+ if (IS_CHANNEL_CONNECTED(ioc)) {
+ if (ioc->tcp->async_write) {
+ resolver->async->del_write (resolver->async->data, ioc->tcp->async_write);
+ ioc->tcp->async_write = NULL;
+ }
+ if (ioc->tcp->async_read) {
+ resolver->async->del_read (resolver->async->data, ioc->tcp->async_read);
+ ioc->tcp->async_read = NULL;
+ }
+
+ ioc->flags &= ~RDNS_CHANNEL_CONNECTED;
+ }
+
+ if (ioc->sock != -1) {
+ close (ioc->sock);
+ ioc->sock = -1;
+ }
+ if (ioc->saddr) {
+ free (ioc->saddr);
+ ioc->saddr = NULL;
+ }
+}
+
+bool
+rdns_ioc_tcp_connect (struct rdns_io_channel *ioc)
+{
+ struct rdns_resolver *resolver = ioc->resolver;
+
+ if (IS_CHANNEL_CONNECTED(ioc)) {
+ rdns_err ("trying to connect already connected IO channel!");
+ return false;
+ }
+
+ if (ioc->sock == -1) {
+ ioc->sock = rdns_make_client_socket (ioc->srv->name, ioc->srv->port,
+ SOCK_STREAM, &ioc->saddr, &ioc->slen);
+ if (ioc->sock == -1) {
+ rdns_err ("cannot open socket to %s: %s", ioc->srv->name,
+ strerror (errno));
+
+ if (ioc->saddr) {
+ free (ioc->saddr);
+ ioc->saddr = NULL;
+ }
+
+ return false;
+ }
+ }
+
+ int r = connect (ioc->sock, ioc->saddr, ioc->slen);
+
+ if (r == -1) {
+ if (errno != EAGAIN && errno != EINTR && errno != EINPROGRESS) {
+ rdns_err ("cannot connect a TCP socket: %s for server %s",
+ strerror(errno), ioc->srv->name);
+ close (ioc->sock);
+
+ if (ioc->saddr) {
+ free (ioc->saddr);
+ ioc->saddr = NULL;
+ }
+
+ ioc->sock = -1;
+
+ return false;
+ }
+ else {
+ /* We need to wait for write readiness here */
+ ioc->tcp->async_write = resolver->async->add_write (resolver->async->data,
+ ioc->sock, ioc);
+ }
+ }
+ else {
+ /* Always be ready to read from a TCP socket */
+ ioc->flags |= RDNS_CHANNEL_CONNECTED|RDNS_CHANNEL_ACTIVE;
+ ioc->tcp->async_read = resolver->async->add_read(resolver->async->data,
+ ioc->sock, ioc);
+ }
+
+ return true;
+}
+
static bool
rdns_resolver_conf_process_line (struct rdns_resolver *resolver,
const char *line, rdns_resolv_conf_cb cb, void *ud)
diff --git a/contrib/librdns/util.h b/contrib/librdns/util.h
index eea818dee..70ad053a0 100644
--- a/contrib/librdns/util.h
+++ b/contrib/librdns/util.h
@@ -51,12 +51,24 @@ uint16_t rdns_permutor_generate_id (void);
void rdns_ioc_free (struct rdns_io_channel *ioc);
/**
- * C
+ * Creates a new IO channel
*/
struct rdns_io_channel * rdns_ioc_new (struct rdns_server *srv,
struct rdns_resolver *resolver,
bool is_tcp);
+/**
+ * Resets inactive/errored TCP chain as recommended by RFC
+ * @param ioc
+ */
+void rdns_ioc_tcp_reset (struct rdns_io_channel *ioc);
+
+/**
+ * Connect TCP IO channel to a server
+ * @param ioc
+ */
+bool rdns_ioc_tcp_connect (struct rdns_io_channel *ioc);
+
/**
* Free request
* @param req
More information about the Commits
mailing list