[Home] [Downloads] [Search] [Help/forum]

Gammon Forum

See www.mushclient.com/spam for dealing with forum spam. Please read the MUSHclient FAQ!

[Folder]  Entire forum
-> [Folder]  MUSHclient
. -> [Folder]  Suggestions
. . -> [Subject]  Add an option to use TCP keepalives
Home  |  Users  |  Search  |  FAQ
Username:
Register forum user name
Password:
Forgotten password?

Add an option to use TCP keepalives

It is now over 60 days since the last post. This thread is closed.     [Refresh] Refresh page


Posted by Kobold   (5 posts)  [Biography] bio
Date Thu 12 Nov 2009 11:31 AM (UTC)
Message
I'm behind a NAT router that is really aggressive about kicking off idle connections, and I end up getting kicked off for inactivity every 10-20 minutes or so.

I'm aware that this can be solved via scripting (by sending an idle command), but I think this is a common enough problem that either a plugin should be provided as a download to users or the option included in the application. I don't think the user should be expected to code for this simple functionality. Also, such an application-level solution is inferior because it: a. makes idle timers inaccurate on MUCKs and b. makes it possible for the 'idle command' to mess up an edit in progress (that the user idled on).

Therefore, I think the best way is to use TCP keepalives. There was a discussion earlier on this board about them, but I think the objections some people raised were all very dated (being from the 80s). The proposed method would be to add an option in the world preferences, along with a text field for amount of time (in seconds) to wait between sending keepalive packets. The TCP keepalives can then be implemented with WSAIoctl(SIO_KEEPALIVE_VALS) when the sockets are opened.

I would contribute a patch, but I am basically inexperienced in Windows GUI programming. I barely managed to get MUCKClient compiled and even then it seemed to be off a bit (the toolbars were the wrong color). I also don't know how to go about adding the required UI elements.

However, I did "patch" this manually myself as an experiment. This involved the use of a disassembler and Microsoft Detours to hook into one of the methods in MUSHClient and making the call myself before returning control back to the main executable. It works very well with my connection, though as it stands, I have to find the offset for InitiateConnection with every MUSHClient revision, so it would be cool if this feature could make it in.
[Go to top] top

Posted by WillFa   USA  (525 posts)  [Biography] bio
Date Reply #1 on Thu 12 Nov 2009 03:46 PM (UTC)
Message
Have you tried updating the firmware on your router? I know old linksys routers loved putting the smackdown on sockets.
[Go to top] top

Posted by Nick Gammon   Australia  (21,324 posts)  [Biography] bio   Forum Administrator
Date Reply #2 on Thu 12 Nov 2009 07:22 PM (UTC)
Message
OK, well I added an option to the next version to set SO_KEEPALIVE for the main world socket. We'll see if that helps.

Like this:


  if (m_bSendKeepAlives)
    {
    BOOL bKeepAlive = TRUE;
    m_pSocket->SetSockOpt (SO_KEEPALIVE, &bKeepAlive, sizeof bKeepAlive);
    }


That isn't exactly what you did, but hopefully that will work. If you don't think it will, please advise.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Kobold   (5 posts)  [Biography] bio
Date Reply #3 on Fri 13 Nov 2009 02:48 AM (UTC)
Message
Nick: Thanks! The only problem with that is that the default Windows keep alive interval is something like two hours. I think if anyone actually needs the option, two hours is way too long. One can adjust this with a global registry setting, but it's easiest to use a per connection way to do it. The per-connection way is almost as easy as SO_KEEPALIVE. Just requires passing a struct via WSAIoctl.

Something like:


#include <mstcpip.h>

...

        if (m_bSendKeepAlives)
        {
                DWORD dwBytesReturned;
                tcp_keepalive keepaliveData = {1, 600000, 6000};
                WSAIoctl(m_pSocket->m_hSocket, SIO_KEEPALIVE_VALS, &keepaliveData, sizeof(keepaliveData), NULL, 0, &dwBytesReturned, NULL, NULL);
        }



This causes keep-alive probes to be sent after ten minutes of inactivity (every ten minutes if the server responds on time). (10 * 60 * 1000 = 600000). Also, if the server doesn't respond after a minute to probes, the connection is considered terminated. (60*1000/10, the 10 is the hardcoded number of probes Windows sends out before giving up on the connection, each probe timing out after 6000 milliseconds).

The numbers I've given are probably sensible ones, but the best thing might be to allow the user to specify the interval (in seconds) between keep-alives.

WSAIoctl returns non-zero on error and WSAGetLastError can be used to retrieve the exact error code if one is interested in that sort of thing (probably unnecessary).

Thanks again!

WillFa: Heh, I'm using the latest firmware for my router unfortunately (and I don't really want to mess with third-party firmware in this situation).
[Go to top] top

Posted by Nick Gammon   Australia  (21,324 posts)  [Biography] bio   Forum Administrator
Date Reply #4 on Fri 13 Nov 2009 03:16 AM (UTC)
Message
I initially thought the documentation said the same thing, but rather confusingly (standard however for Microsoft, heh) it says this:


The default settings when a TCP socket is initialized sets the keep-alive timeout to 2 hours and the keep-alive interval to 1 second. The default system-wide value of the keep-alive timeout is controllable through the KeepAliveTime registry setting which takes a value in milliseconds. The default system-wide value of the keep-alive interval is controllable through the KeepAliveInterval registry setting which takes a value in milliseconds.

On Windows Vista and later, the number of keep-alive probes (data retransmissions) is set to 10 and cannot be changed.


What is this "1 second" interval they talk about?

From:

http://msdn.microsoft.com/en-us/library/ee470551(VS.85).aspx

However I have no objection to using your alternate code.


...

Or I would if I had mstcpip.h, which I don't. Can you post enough of that to get my code to work, specifically the structure for tcp_keepalive and the value of SIO_KEEPALIVE_VALS?

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Twisol   USA  (2,257 posts)  [Biography] bio
Date Reply #5 on Fri 13 Nov 2009 07:07 AM (UTC)
Message
It sounds like it sends a keepalive packet every second, and if the keepalives aren't responded to for two hours, it decides the connection has broken. Assuming there weren't any more obvious network failures/closures, that is.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
[Go to top] top

Posted by Kobold   (5 posts)  [Biography] bio
Date Reply #6 on Fri 13 Nov 2009 08:25 AM (UTC)

Amended on Fri 13 Nov 2009 09:17 AM (UTC) by Kobold

Message
See this page: http://msdn.microsoft.com/en-us/library/dd877220(VS.85).aspx


/* Argument structure for SIO_KEEPALIVE_VALS */
struct tcp_keepalive {
    u_long  onoff;
    u_long  keepalivetime;
    u_long  keepaliveinterval;
};


Quote:
The value specified in the onoff member determines if TCP keep-alive is enabled or disabled. If the onoff member is set to a non-zero value, TCP keep-alive is enabled and the other members in the structure are used. The keepalivetime member specifies the timeout, in milliseconds, with no activity until the first keep-alive packet is sent. The keepaliveinterval member specifies the interval, in milliseconds, between when successive keep-alive packets are sent if no acknowledgement is received.

...

On Windows Vista and later, the number of keep-alive probes (data retransmissions) is set to 10 and cannot be changed.


Anyway, it means the default is two hours between transmissions and one second in between retransmissions of the probe that was transmitted. If ten probes have been transmitted but have gotten no response from the peer, the connection is considered terminated.

And I have plenty of empirical evidence on this score too. I tried SO_KEEPALIVE only myself only when I first did it and it didn't help at all. =P Later, I added the proper registry settings and that worked.

EDIT: I zipped up mstcpip.h and nldef.h and put it here: http://3.ly/w3w

The important parts to know seems to be that SIO_KEEPALIVE_VALS is 0x98000004 and the struct tcp_keepalive above. The include files came with my install of Visual Studio 2008, which installed Windows Platform SDK 6.0a which is what had those includes.
[Go to top] top

Posted by Nick Gammon   Australia  (21,324 posts)  [Biography] bio   Forum Administrator
Date Reply #7 on Sat 14 Nov 2009 08:05 PM (UTC)
Message
OK got that thanks.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (21,324 posts)  [Biography] bio   Forum Administrator
Date Reply #8 on Fri 26 Mar 2010 08:59 PM (UTC)
Message
I saw an interesting suggestion recently.

The sequence IAC NOP (255 241) should be ignored by the server (I'm not saying it *will* be ignored but the spec says it should).

Thus doing this periodically (eg. in a timer) should keep the connection alive, whilst have no effect on the server:


SendPkt (string.char (255, 241))


I wouldn't flood the server with them, once a minute or 5 minutes should be plenty. And depending on the server, it might either get you disconnected, or result in funny characters in your input stream. However technically it should work.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Twisol   USA  (2,257 posts)  [Biography] bio
Date Reply #9 on Fri 26 Mar 2010 10:38 PM (UTC)
Message
Unfortunately, the full extent of Telnet (or even just the subnegotiations) is often not supported by MUD codebases, from what I've heard recently. I think someone said Diku specifically had problems with it. TCP is pretty much universal, though, and protocol-level keepalives are just about guaranteed to work.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
[Go to top] top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


10,021 views.

It is now over 60 days since the last post. This thread is closed.     [Refresh] Refresh page

Go to topic:           Search the forum


[Go to top] top

Quick links: MUSHclient. MUSHclient help. Forum shortcuts. Posting templates. Lua modules. Lua documentation.

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.

[Home]


Written by Nick Gammon - 5K   profile for Nick Gammon on Stack Exchange, a network of free, community-driven Q&A sites   Marriage equality

Comments to: Gammon Software support
[RH click to get RSS URL] Forum RSS feed ( https://gammon.com.au/rss/forum.xml )

[Best viewed with any browser - 2K]    [Hosted at FutureQuest]