From 4396674aa795bb147b510cc51037dcdd8fea6afb Mon Sep 17 00:00:00 2001
From: Joerg Wunsch <j@uriah.heep.sax.de>
Date: Sat, 27 Nov 2021 21:15:55 +0000
Subject: [PATCH] patch #9304: [Bug #48767] Implemented WinSock variation of
 "ser_drain(...)" functionality Submitted by Christopher Cooper: * ser_win32.c
 (ser_drain): Implement a network drain function.

git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1499 81a1dc3b-b13d-400b-aceb-764788c761c2
---
 ChangeLog   |  7 +++++
 NEWS        |  2 ++
 ser_win32.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 95 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index 0042e47f..6a813f7f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2021-11-27  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Christopher Cooper:
+	patch #9304: [Bug #48767] Implemented WinSock variation of "ser_drain(...)" functionality
+	* ser_win32.c (ser_drain): Implement a network drain
+	function.
+
 2021-11-27  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
 
 	Submitted by Lars Ollén:
diff --git a/NEWS b/NEWS
index 357f6244..c19c9dd8 100644
--- a/NEWS
+++ b/NEWS
@@ -73,6 +73,7 @@ Current:
     bug #60863: avrftdi programming error probably caused by multiple, consecutive empty pages
     bug #50517: Reading fails if "immediate mode" for output file format is selected - fileio: invalid operation=1
     bug #50630: Erase Cycle Counter options ( -y -Y n ) should be removed from usage Message
+    bug #48767: ser_drain() for TCP on Windows doesn't work
 
   * Patches:
     patch #9482: Add support for UPDI and AVR8X
@@ -126,6 +127,7 @@ Current:
     patch #10031: linuxspi: Support GPIO uAPI v2
     (no-id): Improve documentation of linuxspi driver, provide portname default
     (no-id): Use -B <bitclock> rather than -b <baudrate> for linuxspi driver
+    patch #9304: [Bug #48767] Implemented WinSock variation of "ser_drain(...)" functionality
 
   * Internals:
     - New avrdude.conf keyword "family_id", used to verify SIB attributes
diff --git a/ser_win32.c b/ser_win32.c
index fcaa55e6..5fc17b1b 100644
--- a/ser_win32.c
+++ b/ser_win32.c
@@ -628,9 +628,95 @@ static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen
   return 0;
 }
 
+#ifdef HAVE_LIBWS2_32
+static int net_drain(union filedescriptor *fd, int display)
+{
+	LPVOID lpMsgBuf;
+	struct timeval timeout;
+	fd_set rfds;
+	int nfds;
+	unsigned char buf;
+	int rc;
+
+	if (fd->ifd < 0) {
+		avrdude_message(MSG_INFO, "%s: ser_drain(): connection not open\n", progname);
+		exit(1);
+	}
+
+	if (display) {
+		avrdude_message(MSG_INFO, "drain>");
+	}
+
+	timeout.tv_sec  = 0;
+	timeout.tv_usec = 250000;
+
+	while (1) {
+		FD_ZERO(&rfds);
+		FD_SET(fd->ifd, &rfds);
+
+	reselect:
+		nfds = select(fd->ifd + 1, &rfds, NULL, NULL, &timeout);
+		if (nfds == 0) {
+			if (display) {
+				avrdude_message(MSG_INFO, "<drain\n");
+			}
+			break;
+		}
+		else if (nfds == -1) {
+			if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEINPROGRESS) {
+				avrdude_message(MSG_NOTICE, "%s: ser_drain(): programmer is not responding, reselecting\n", progname);
+				goto reselect;
+			} else {
+				FormatMessage(
+					FORMAT_MESSAGE_ALLOCATE_BUFFER |
+					FORMAT_MESSAGE_FROM_SYSTEM |
+					FORMAT_MESSAGE_IGNORE_INSERTS,
+					NULL,
+					WSAGetLastError(),
+					MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+					(LPTSTR)&lpMsgBuf,
+					0,
+					NULL);
+				avrdude_message(MSG_INFO, "%s: ser_drain(): select(): %s\n", progname, (char *)lpMsgBuf);
+				LocalFree(lpMsgBuf);
+				exit(1);
+			}
+		}
+
+		rc = recv(fd->ifd, &buf, 1, 0);
+		if (rc < 0) {
+			FormatMessage(
+				FORMAT_MESSAGE_ALLOCATE_BUFFER |
+				FORMAT_MESSAGE_FROM_SYSTEM |
+				FORMAT_MESSAGE_IGNORE_INSERTS,
+				NULL,
+				WSAGetLastError(),
+				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+				(LPTSTR)&lpMsgBuf,
+				0,
+				NULL);
+			avrdude_message(MSG_INFO, "%s: ser_drain(): read error: %s\n", progname, (char *)lpMsgBuf);
+			LocalFree(lpMsgBuf);
+			exit(1);
+		}
+
+		if (display) {
+			avrdude_message(MSG_INFO, "%02x ", buf);
+		}
+	}
+
+	return 0;
+}
+#endif
 
 static int ser_drain(union filedescriptor *fd, int display)
 {
+#ifdef HAVE_LIBWS2_32
+	if (serial_over_ethernet) {
+		return net_drain(fd, display);
+	}
+#endif
+
 	// int rc;
 	unsigned char buf[10];
 	BOOL readres;