diff --git a/nselib/rpc.lua b/nselib/rpc.lua index 8d8dfa350..9f7c03e2e 100644 --- a/nselib/rpc.lua +++ b/nselib/rpc.lua @@ -287,8 +287,11 @@ Comm = { self.program_id = progid end, - --- Checks if data contains enough bytes to read the needed amount - -- If it doesn't it attempts to read the remaining amount of bytes from the socket + --- Checks if data contains enough bytes to read the needed amount + -- + -- If it doesn't it attempts to read the remaining amount of bytes from the + -- socket. Unlike socket.receive_bytes, reading less than + -- needed is treated as an error. -- -- @param data string containing the current buffer -- @param pos number containing the current offset into the buffer @@ -296,16 +299,19 @@ Comm = { -- @return status success or failure -- @return data string containing the data passed to the function and the additional data appended to it or error message on failure GetAdditionalBytes = function( self, data, pos, needed ) - local status, tmp - - if data:len() - pos + 1 < needed then - local toread = needed - ( data:len() - pos + 1 ) - status, tmp = self.socket:receive_bytes( toread ) + local toread = needed - ( data:len() - pos + 1 ) + -- Do the loop ourselves instead of receive_bytes. Pathological case: + -- * read less than needed and timeout + -- * receive_bytes returns short but we don't know if it's eof or timeout + -- * Try again. If it was timeout, we've doubled the timeout waiting for bytes that aren't coming. + while toread > 0 do + local status, tmp = self.socket:receive() if status then + toread = toread - #tmp data = data .. tmp else - return false, string.format("getAdditionalBytes() failed to read: %d bytes from the socket", - needed - ( data:len() - pos ) ) + return false, string.format("getAdditionalBytes read %d bytes before error: %s", + needed - toread, tmp) end end return true, data