Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to deal with hanging sockets? #555

Open
p-v-d-Veeken opened this issue Aug 20, 2019 · 4 comments
Open

How to deal with hanging sockets? #555

p-v-d-Veeken opened this issue Aug 20, 2019 · 4 comments
Labels

Comments

@p-v-d-Veeken
Copy link

p-v-d-Veeken commented Aug 20, 2019

I have found an issue (bug?) with unresponsive open websockets being uncloseable.

To reproduce this issue simply use a browser on a laptop (Only tested with a MacBook) to connect to a NanoHttpd websocket and close the lid of the laptop, causing the laptop to instantly go into hibernate. Doing this will not disconnect the websocket, the consequence of which is that when the server tries to send a message over the socket, it will wait indefinitely for the message to be delivered.

This is in itself not that bad, because it's fairly easy to detect a hanging socket. However, this becomes significantly worse when we try to close the socket in question:

public void close(CloseCode code, String reason, boolean initiatedByRemote) throws IOException {
State oldState = this.state;
this.state = State.CLOSING;
if (oldState == State.OPEN) {
sendFrame(new CloseFrame(code, reason));
} else {
doClose(code, reason, initiatedByRemote);
}
}

Attempting to close the socket sends another message, which will also hang indefinitely.

To the best of my understanding there is no way to fix or circumvent the issue described above, but I'll be gladly proven wrong.

@LordFokas LordFokas added the bug label Aug 20, 2019
@LordFokas
Copy link
Member

There is no such thing as "no way to fix". I could do it in a couple hours if I had the time or patience, but like everything else that is currently going on here it will have to wait.

@p-v-d-Veeken
Copy link
Author

Of course it's fixable, I meant that someone using NanoHttpd has no way to avoid the problem.

What kind of solution did you have in mind? I'd be happy to take a stab at it and see if I can fix it. :)

@LordFokas
Copy link
Member

For example with server side pings. In my use case in the past I had an automatic ping every 4 seconds and pongs were accounted for, if when you sent a ping more than 3 pongs were missing (aka unresponsive for >12 seconds) the socket would be forcibly closed and destroyed.

This is really something that should be built in, and if the server components were as abstract and pluggable as I'd like anyone could easily modify, fix or work around these kind of situations... I've actually started a lot of work on stuff like that, but I only have so much free time that I can sink into this.

@p-v-d-Veeken
Copy link
Author

For anyone stumbling upon this issue, I've managed to kill unresponsive sockets using the following black magic incantation:

void handleUnresponsiveSocket(NanoWSD.WebSocket unresponsive) {
    try {
        Class<NanoWSD.WebSocket> wsClass = NanoWSD.WebSocket.class;
        //Get method which closes socket without sending close message
        Method doClose = wsClass.getDeclaredMethod("doClose", CloseCode.class, String.class, boolean.class);

        doClose.setAccessible(true); //Circumvent private modifier
        doClose.invoke(unresponsive, CloseCode.ProtocolError, "Unresponsive", true); //Call method
    } catch (Exception e) {
        logger.error("Error force closing socket.", e);
    }
}

It goes without saying that this shouldn't be used for sockets which are still responsive

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants