From ee366f8e74fbf1e274af91db12fdc4b4984d557d Mon Sep 17 00:00:00 2001
From: Rodrigo Gressler <rodrigo.gressler@gmail.com>
Date: Fri, 23 Oct 2026 13:28:06 +0000
Subject: [PATCH] rtl_tcp: keep serving after a client that disconnects at once

When a client went away before rtlsdr_read_async() had started, the
worker's rtlsdr_cancel_async() was a no-op, read_async then ran forever
with do_exit set and the server never got back to accept(): it kept
taking TCP connections but sent no greeting until restarted.

- rtlsdr_callback(): once do_exit is set, cancel from there and return
- command_worker(): recv() == 0 (client closed) ends the session
- tcp_worker(): a select() error ends the session; bytesleft/index only
  move when send() sent something

Signed-off-by: Rodrigo Gressler <rodrigo.gressler@gmail.com>
---
 src/rtl_tcp.c | 26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/src/rtl_tcp.c b/src/rtl_tcp.c
index b730bf4..745f443 100644
--- a/src/rtl_tcp.c
+++ b/src/rtl_tcp.c
@@ -154,7 +154,15 @@ static void sighandler(int signum)
 
 void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
 {
-	if(!do_exit) {
+	/* A client that disconnects before rtlsdr_read_async() has started
+	 * makes its worker call rtlsdr_cancel_async() too early (a no-op),
+	 * so read_async() would run forever and the server would never
+	 * accept() again: cancel from here once the session is over. */
+	if(do_exit) {
+		rtlsdr_cancel_async(dev);
+		return;
+	}
+	{
 		struct llist *rpt = (struct llist*)malloc(sizeof(struct llist));
 		rpt->data = (char*)malloc(len);
 		memcpy(rpt->data, buf, len);
@@ -237,12 +245,14 @@ static void *tcp_worker(void *arg)
 				tv.tv_sec = 1;
 				tv.tv_usec = 0;
 				r = select(s+1, NULL, &writefds, NULL, &tv);
-				if(r) {
+				if(r > 0) {
 					bytessent = send(s,  &curelem->data[index], bytesleft, 0);
-					bytesleft -= bytessent;
-					index += bytessent;
+					if(bytessent > 0) {
+						bytesleft -= bytessent;
+						index += bytessent;
+					}
 				}
-				if(bytessent == SOCKET_ERROR || do_exit) {
+				if(r < 0 || bytessent == SOCKET_ERROR || do_exit) {
 						printf("worker socket bye\n");
 						sighandler(0);
 						pthread_exit(NULL);
@@ -304,9 +314,11 @@ static void *command_worker(void *arg)
 			r = select(s+1, &readfds, NULL, NULL, &tv);
 			if(r) {
 				received = recv(s, (char*)&cmd+(sizeof(cmd)-left), left, 0);
-				left -= received;
+				if(received > 0)
+					left -= received;
 			}
-			if(received == SOCKET_ERROR || do_exit) {
+			/* recv() == 0: the client closed the connection */
+			if((r && received <= 0) || r < 0 || do_exit) {
 				printf("comm recv bye\n");
 				sighandler(0);
 				pthread_exit(NULL);
-- 
2.43.0

