love
love copied to clipboard
LuaSocket `select` and `receivefrom` behaving unexpectedly since Love2d 11.0 (luasocket 3.0-rc1)
Minimum code example with explanations below. Tested on Windows 10 with love2d versions 10.2-11.3.
function love.load()
socket = require 'socket'
udp = socket.udp()
udp:setsockname('127.0.0.1', 0)
-- when below line is commented the code behaves correctly
udp:sendto('whatever', '127.0.0.1', 12345) -- no receiver at this port
end
function love.update()
-- should wait 1s for incoming data but instead in the first iteration
-- `socket.select` returns immediately suggesting that `udp` is ready for reading
local r, w, e = socket.select({udp}, nil, 1)
print('status:', #r, #w, e)
if #r > 0 then
-- this seems to be the difference between love2d 10.2 and 11.0+ (luasocket 2 and 3)
-- luasocket 2 returns (nil, 'closed') and luasocket 3 blocks till some data is received
-- even though `socket.select` claims that the data is already there
print(udp:receivefrom())
end
end
This is probably an issue with luasocket and not with love2d itself but it hurts. I'd be glad to hear your thoughts on this and in the meantime I'll check the changes in luasocket out of my own curiosity.
Edit: modified the code to be a little bit more love2d-like, seems like the issue was introduced quite some time ago https://github.com/diegonehab/luasocket/commit/734cc23e1f03372314ebad07ffd35117c152afcd#diff-df7a8b28d4e32c5ab91743d465434df979267d91a79ed4d68cfc5a9787159483
Edit2: looks like someone already tried to fix that back in 2013 https://github.com/diegonehab/luasocket/pull/81
On macOS in both LÖVE 11.3 and 0.10.2 the socket.select
call always times out and the print(udp:receivefrom())
codepath is never hit, regardless of whether the sendto
call is commented or not. I guess you're seeing a Windows-specific difference in luasocket's code?
It's a Windows specific issue indeed. I've stumbled upon it once again but in a different technology stack.
Apparently there's an ioctl (SIO_UDP_CONNRESET
) to work around that problem. I don't think I fully understand what's going on but from what I've read online: sending udp packets to the loopback interface where the port is closed will result in a ICMP "Destination unreachable (port unreachable)" message. This somehow impacts further behavior: select returning ready for reading, receivefrom ignoring the error and trying to read some data but no data is available so it blocks.
The issue is not reproducible if the packets are sent through any other (non-loopback) interface.
Fun fact: After installing WireShark to investigate: luasocket no longer blocks on read but returns (nil, closed)
once and then continues timing out. What a mess.
This issue can be closed. The same way as Windows closes a connection on connectionless UDP :)
A change got merged into the luasocket repository that supposedly fixes this issue. love 12 has been updated to use a version of luasocket with that fix.