From 27b20fd4715024035e38db60fc70cf71faa407e2 Mon Sep 17 00:00:00 2001
From: Deuce <shurd@sasktel.net>
Date: Fri, 27 Nov 2020 03:38:15 -0500
Subject: [PATCH] "Handle" frames with a data length of zero.

These frames were already not allowed in the binkp/1.0 protocol,
and it is mentioned in the spec (issued in 2005) as "Some old
implementations do send empty frames as the last frame.".

It's certainly not allowed now, and any mailer which does it is
broken.

For zero-length data packets, it will be seen as a frame containing
zero data bytes which will also be logged as being after the file
if it comes after the file has already been completely transferred.

A zero-length command packet will abort with M_ERR, logging an error
regarding command number NaN or something like that.

This may fix #185 since attempting a recv() of zero bytes and
succeeding is the only way I can see for a zero second timeout to
have been logged in receving frame data.  The software assumed that
receiving zero bytes was a timeout, but if that's what you asked for,
it's actually success.
---
 exec/load/binkp.js | 35 ++++++++++++++++++++---------------
 1 file changed, 20 insertions(+), 15 deletions(-)

diff --git a/exec/load/binkp.js b/exec/load/binkp.js
index a22780385c..55ba148a19 100644
--- a/exec/load/binkp.js
+++ b/exec/load/binkp.js
@@ -1096,28 +1096,33 @@ BinkP.prototype.recvFrame = function(timeout)
 	else
 		ret = this.partialFrame;
 
-	i = this.recv_buf(this.sock.recv(ret.length - ret.data.length, timeout));
-	if (i == null) {
-		log(LOG_INFO, "Error in recv() of packet data");
-		this.sock.close();
-		this.sock = undefined;
-		return undefined;
+	if (ret.length == 0) {
+		log(LOG_WARNING, "Remote illegally sent a "+(ret.is_cmd ? 'Command' : 'Data')+" packet with data length of zero.  This isn't even allowed in protocol 1.0.");
 	}
-	if (i.length == 0) {
-		if (!this.sock.is_connected) {
-			log(LOG_DEBUG, "Remote host closed socket");
+	else {
+		i = this.recv_buf(this.sock.recv(ret.length - ret.data.length, timeout));
+		if (i == null) {
+			log(LOG_INFO, "Error in recv() of packet data");
 			this.sock.close();
 			this.sock = undefined;
 			return undefined;
 		}
-		else if (timeout) {
-			log(LOG_WARNING, "Timed out receiving packet data from remote: " + this.remote_addrs);
-			this.sock.close();
-			this.sock = undefined;
-			return undefined;
+		if (i.length == 0) {
+			if (!this.sock.is_connected) {
+				log(LOG_DEBUG, "Remote host closed socket");
+				this.sock.close();
+				this.sock = undefined;
+				return undefined;
+			}
+			else if (timeout) {
+				log(LOG_WARNING, "Timed out receiving packet data from remote: " + this.remote_addrs);
+				this.sock.close();
+				this.sock = undefined;
+				return undefined;
+			}
 		}
+		ret.data += i;
 	}
-	ret.data += i;
 
 	if (ret.data.length < ret.length)
 		this.partialFrame = ret;
-- 
GitLab