Issues with client:receive()


#1

Hello.

I have written an NTRIP client that connects to a network and then receives data until the connection is closed. The issue I am having is that occasionally client:receive() will hang and not return at all. I have set the timeout to be 5 seconds but when this error occurs the timeout does not kick in and the function does not receive nil as it should on a timeout.

Has anyone seen this issue before?

Here are the three chunks of code that are relevant to this issue:

Thank you very much!

Chunk 1 is the GETNTRIPMessage function which calls NTRIP.GetNewByte()

function GetNTRIPMessage()
	-- this function will get data byte by byte from the NTRIP connection and parse through it to find NCT or RTCM messages.
	-- It will return the Buffer, Buffer Length, and Message Number when found
	local NTRIPBuffer = {}
	local NTRIPBufferIndex = 0
	local NTRIPBufferLength = -1
	local NTRIPMessageType = "NONE"
	local Received = false
	local NTRIPByte = 0
	if(NTRIP.Connected) then
		while true do
			if(NTRIPBufferIndex > NTRIPBufferLength and NTRIPBufferLength ~= -1) then
				return false -- if we have a buffer larger then we expected there was an error in reading message length so return false and try again
			end
			if(NTRIPBufferIndex == NTRIPBufferLength) then
				-- we have the expected message lengthm so return true along with the message, length, and type
				return true, NTRIPBuffer, NTRIPBufferLength, NTRIPMessageType
			else
				print("main.Line204 - Calling NTRIP.GetNewByte")
				Received, NTRIPByte = NTRIP.GetNewByte(1)
				print("main.Line206 - NTRIPByte - " .. NTRIPByte)
				if(Received) then -- check to ensure we actually received a byte, if we did continue
					if(NTRIPBufferIndex == 0) then -- if we are at the start of the buffer with no other bytes loaded
						NTRIPBuffer[0] = NTRIPByte --NTRIP.GetNewByte() -- load a byte from the NTRIP connection into the buffer
						if(NTRIPBuffer[0] == 0xD3 or NTRIPBuffer[0] == 0x02) then -- if the byte is an 0x02 or a 0xD3 then we may have an NCT or a RTCM message
							NTRIPBufferIndex = NTRIPBufferIndex + 1 -- increment so we can start loading
						end
					elseif(NTRIPBufferIndex > 0 and NTRIPBufferIndex < 6) then -- we need 6 bytes to determing the length and message type so load that many in
						NTRIPBuffer[NTRIPBufferIndex] = NTRIPByte
						NTRIPBufferIndex = NTRIPBufferIndex + 1
					elseif(NTRIPBufferIndex == 6 ) then -- if we have 6 bytes loaded we can check the length and message type
						NTRIPBuffer[NTRIPBufferIndex] = NTRIPByte 
						if(NTRIPBuffer[0] == 0xD3) then -- we have an RTCM Message, so get the length and message type
							NTRIPBufferLength = bit32.lshift(bit32.band(NTRIPBuffer[1], 0x03), 8) + NTRIPBuffer[2] + 6
							NTRIPMessageType = bit32.lshift(NTRIPBuffer[3], 4) + bit32.rshift(NTRIPBuffer[4], 4)
							local Valid, MessageRemainder = NTRIP.GetNewByte(NTRIPBufferLength-7) -- now receive the remainder of the message
							if(Valid) then -- if it was succesful in receiving, copy to buffer.
								local ReceivedIndex = 1
								for  i = NTRIPBufferIndex+1, NTRIPBufferLength-1, 1 do
									NTRIPBuffer[i] = string.byte(MessageRemainder,ReceivedIndex)
									ReceivedIndex = ReceivedIndex +1
								end
								NTRIPBufferIndex = NTRIPBufferLength
							else
								return false -- we did not receive all of the message
							end
						elseif(NTRIPBuffer[0] == 0x02) then -- we have an NCT message, so get the length and message type
							NTRIPBufferLength = bit32.bor(NTRIPBuffer[4], bit32.lshift(NTRIPBuffer[5], 8)) + 4
							NTRIPMessageType = NTRIPBuffer[3]
							local Valid, MessageRemainder = NTRIP.GetNewByte(NTRIPBufferLength-7) -- now receive the remainder of the message
							if(Valid) then
								local ReceivedIndex = 1
								for  i = NTRIPBufferIndex+1, NTRIPBufferLength-1, 1 do
									NTRIPBuffer[i] = string.byte(MessageRemainder,ReceivedIndex)
									ReceivedIndex = ReceivedIndex +1
								end
								NTRIPBufferIndex = NTRIPBufferLength

							else
								return false -- we did not receive all of the message
							end
						end -- ends the RTCM or NCT Statement
					end -- end the 6 byte statement
					
				else
					return false -- if we did not receive a byte return false
				end
			end -- end of the main if statement to check for a full message or continue looping if not full.
		end -- end of the while loop for receiving
	else -- we are not connected
		return false
	end
end

Here is the NTRIP.GetNewByte() function

function NTRIP.GetNewByte(bytes)
	print("NTRIP.Line93 - Beginning of function")
	if(NTRIP.NTRIPConnection ~= nil) then
		print("NTRIP.Line95 - NTRIP.NTRIPConnection is not nil, begin receive " .. bytes .. " bytes")
		local received = assert(NTRIP.NTRIPConnection:receive(bytes))
		print("NTRIP.Line97 - NTRIP.NTRIPConnection receive finished")
		if(received == nil) then
			print("NTRIP.Line78 - Received nil")
			return false, "0"
		elseif (bytes == 1) then
			print("NTRIP.Line81 - NTRIP Receive not nil, returning true + byte")
			return true, str.byte(received)
		else
			return true, received
		end
	else
		print("NTRIP.Line85 - NTRIP.NTRIPConnection is nil, returning false and 0")
		return false, "0"
	end
end

Finally here is where the NTRIP connection is initiated and the timeouts set

function NTRIP.Connect()
	print("NTRIP.Line17 - NTRIP.Connect Entered")
	if(NTRIP.NTRIPConnection ~= nil) then -- If we are trying to connect we had a data issue so delete and start over
		print("NTRIP.Line19 - NTRIP.NTRIPConnection is not nil")
		NTRIP.NTRIPConnection = nil
		NTRIP.Connected = false
		NTRIP.Status = "X"
	end
	print("NTRIP.Line24 - NTRIP.NTRIPConnection should now be nil, creating connection.")
	print("NTRIP.Line25 - IP - \"" .. DataAsset.tree.downlink.NTRIP_IP .. "\" port - \"" .. DataAsset.tree.downlink.NTRIP_Port .. "\"")
	NTRIP.NTRIPConnection = socket.connect(DataAsset.tree.downlink.NTRIP_IP, DataAsset.tree.downlink.NTRIP_Port) -- attempt connection
	if(NTRIP.NTRIPConnection ~= nil) then -- if connection failes it will return nil, so only continue if not nil
		print("NTRIP.Line28 - NTRIP connection is not nil, sending login")
		NTRIP.NTRIPConnection:settimeout(5, 't') -- set timeout and then send login info
		NTRIP.NTRIPConnection:settimeout(5, 'b')
		-- build NTRIP login and send it
		NTRIP.NTRIPConnection:send(NTRIP.BuildLogin(DataAsset.tree.downlink.NTRIP_Mount_Point, DataAsset.tree.downlink.NTRIP_Username, DataAsset.tree.downlink.NTRIP_Password))
		print("NTRIP.Line33 - NTRIP Login sent, proceed to NTRIP")
		NTRIP.Status = "C" -- this indicates we have a cell connectio
		NTRIP.CheckConnection() -- now check the NTRIP connection response/
	else -- if we fail reset
		NTRIP.NTRIPConnection = nil
		NTRIP.Status = "X"
		NTRIP.Connected = false
	end

end