From f1035e971bb894203bdfba6cafbaf0bb30f197eb Mon Sep 17 00:00:00 2001
From: Guus Sliepen <guus@sliepen.org>
Date: Mon, 25 Feb 2019 09:57:57 +0100
Subject: [PATCH] Small fixes for utcp_abort_all_connections().

- Make utcp_reset_connection() a private function.
- Ensure we don't repeat any action when aborting a connection twice.
- Call the receive callback after resetting the connection, so the callback
  function can safely call utcp_close().
---
 utcp.c | 70 +++++++++++++++++++++++++++++-----------------------------
 utcp.h |  1 -
 2 files changed, 35 insertions(+), 36 deletions(-)

diff --git a/utcp.c b/utcp.c
index 7591e19..d09b9e7 100644
--- a/utcp.c
+++ b/utcp.c
@@ -1598,38 +1598,16 @@ int utcp_shutdown(struct utcp_connection *c, int dir) {
 	return 0;
 }
 
-// Closes all the opened connections
-void utcp_abort_all_connections(struct utcp *utcp) {
-	if(!utcp) {
-		return;
-	}
-
-	for(int i = 0; i < utcp->nconnections; i++) {
-		struct utcp_connection *c = utcp->connections[i];
-
-		if(c->recv) {
-			errno = 0;
-			c->recv(c, NULL, 0);
-		}
-
-		if(utcp_reset_connection(c) != -1) {
-			c->reapable = false;
-		}
-	}
-
-	return;
-}
-
-int utcp_reset_connection(struct utcp_connection *c) {
+static bool reset_connection(struct utcp_connection *c) {
 	if(!c) {
 		errno = EFAULT;
-		return -1;
+		return false;
 	}
 
 	if(c->reapable) {
 		debug("Error: abort() called on closed connection %p\n", c);
 		errno = EBADF;
-		return -1;
+		return false;
 	}
 
 	c->recv = NULL;
@@ -1637,7 +1615,7 @@ int utcp_reset_connection(struct utcp_connection *c) {
 
 	switch(c->state) {
 	case CLOSED:
-		return 0;
+		return true;
 
 	case LISTEN:
 	case SYN_SENT:
@@ -1645,7 +1623,7 @@ int utcp_reset_connection(struct utcp_connection *c) {
 	case LAST_ACK:
 	case TIME_WAIT:
 		set_state(c, CLOSED);
-		return 0;
+		return true;
 
 	case SYN_RECEIVED:
 	case ESTABLISHED:
@@ -1669,7 +1647,32 @@ int utcp_reset_connection(struct utcp_connection *c) {
 
 	print_packet(c->utcp, "send", &hdr, sizeof(hdr));
 	c->utcp->send(c->utcp, &hdr, sizeof(hdr));
-	return 0;
+	return true;
+}
+
+// Closes all the opened connections
+void utcp_abort_all_connections(struct utcp *utcp) {
+	if(!utcp) {
+		errno = EINVAL;
+		return;
+	}
+
+	for(int i = 0; i < utcp->nconnections; i++) {
+		struct utcp_connection *c = utcp->connections[i];
+
+		if(c->reapable || c->state == CLOSED) {
+			continue;
+		}
+
+		reset_connection(c);
+
+		if(c->recv) {
+			errno = 0;
+			c->recv(c, NULL, 0);
+		}
+	}
+
+	return;
 }
 
 int utcp_close(struct utcp_connection *c) {
@@ -1684,15 +1687,12 @@ int utcp_close(struct utcp_connection *c) {
 }
 
 int utcp_abort(struct utcp_connection *c) {
-	int utcp_reset_return;
-
-	utcp_reset_return = utcp_reset_connection(c);
-
-	if(utcp_reset_return != -1) {
-		c->reapable = true;
+	if(!reset_connection(c)) {
+		return -1;
 	}
 
-	return utcp_reset_return;
+	c->reapable = true;
+	return 0;
 }
 
 /* Handle timeouts.
diff --git a/utcp.h b/utcp.h
index 0cad458..fe4c720 100644
--- a/utcp.h
+++ b/utcp.h
@@ -78,7 +78,6 @@ extern void utcp_set_poll_cb(struct utcp_connection *connection, utcp_poll_t pol
 extern void utcp_set_accept_cb(struct utcp *utcp, utcp_accept_t accept, utcp_pre_accept_t pre_accept);
 extern bool utcp_is_active(struct utcp *utcp);
 extern void utcp_abort_all_connections(struct utcp *utcp);
-extern int utcp_reset_connection(struct utcp_connection *c);
 
 // Global socket options
 
-- 
2.39.5