W5500 - Is there a way to detect remote disconnect?

I have a TCP client socket open and connected to a remote server. Right now I rely on the application layer code to time out to determine server side disconnect. Is there a way to do this at W5500 socket API layer? I am looking at the return code from recv(), it says:

ReturnsSuccess : The real received data size
Fail :
SOCKERR_SOCKSTATUS - Invalid socket status for socket operation
SOCKERR_SOCKMODE - Invalid operation in the socket
SOCKERR_SOCKNUM - Invalid socket number
SOCKERR_DATALEN - zero data length
SOCK_BUSY - Socket is busy.

So, if getSn_RX_RSR() is positive but recv() isn’t, then all error code, except SOCK_BUSY, should lead to the socket close() on the client side. Correct?

If remote device finishes connection, it sends FIN packet, and socket connection state register Sn_SR should change from 0x17 to 0x1c. Thus you can know if other party finished with transmission reading this register.

I use ow level programming using W5500 registers, and if there’s a timeout, my application starts issuing RECV command to the W5500 (through its command register). This action triggers W5500 resending ACK packet, and if remote server is having its socket reset, then it will answer with RST packet and W5500 should “timeout” immediately. Howeher I had cases when application sends these packets but there’s simply no response from remote devices, maybe it is a problem with network intermediary devices (router, proxy etc). Anyway, this is workaround rather than solution; most probably you should keep timer anyway, and if it times out, reset connection at your end and actively reconnect.

Eugeny, thank you so much. I wish there is a W5500 software user’s guide somewhere. The only documentation I have is the W5500 datasheet, and it is difficult to use the datasheet unless you know what to look for. Anyway, I look up Sn_SR and I think that’s what I am after. You mentioned Sn_SR would change from 0x17 to 0x1c when FIN had been received. Can I simply check Sn_SR for SOCK_CLOSE? The datasheet states:

When the disconnect-process is successful (that is, FIN/ACK packet
is received successfully), Sn_SR is changed to SOCK_CLOSED.
Otherwise, TCPTO occurs (Sn_IR(3)=‘1)= and then Sn_SR is changed
cf> If CLOSE is used instead of DISCON, only Sn_SR is changed to
SOCK_CLOSED without disconnect-process.
If a RST packet is received from a peer during communication,
Sn_SR is unconditionally changed to SOCK_CLOSED.

This seems to mean that either FIN or RST would trigger a SOCK_CLOSE. Correct?

In my understanding if remote device sends FIN, it means that that device does not want to talk any more, and socket state goes to 0x1c (from 0x17 which is “two way lane”). Now if you issue DISCON command (meaning that you also do not want to talk any more) then socket will go closed IF that device will respond with ACK or with RST. If that device will not respond at all, socket will become hung until timeout event occurs.

So if Sn_SR reads back 0x1C, calling disconnect() until it returns SOCK_OK or SOCKERR_TIMEOUT should suffice.

If you have time for waiting for it because it may take seconds to complete. I do the following: while SR is 0x17, data flows, as soon as SR does NOT equal to 0x17, I check RX buffer again (to ensure there’s no new data in there pending, and then perform disconnect and immediately close - without waiting server responding with FIN. There’s small drawback for this though - when (and if) server responds with ACK for FIN sent by W5x00, it gets RST from the chip because socket was already closed.

1 Like