/* * This program is IN THE PUBLIC DOMAIN and was written by Cody Ferguson on * 2014/10/14 to demonstrate how to set the various TCP keepalive options on a * socket. It is not a fully functional program[1] in that it doesn't call the * function and it doesn't create the sockets, either. It is a demo and nothing * else. Does not handle all errors - it is left as an exercise to the * programmer making use of it; depending on the error and the program, the way * the error is handled will vary: is TCP keepalives absolutely critical? If a * runtime configuration option requests it, then it might be a fatal error; * otherwise it might simply be ignored. * * Comments below on the function arguments and certain specifics. * * [1] However, https://xexyl.net/source/code/sockets/sockbind.c does create the * sockets, binds to a port and listens on the socket (it doesn't poll the * descriptors to know if there is a connection request and it obviously doesn't * call accept because of this - it isn't a fully working server; on the subject * of polling sockets, I suggest that if you have access to a Linux system, * check select_tut(2) man page). * * - Xexyl. */ #include /* TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT */ #include /* setsockopt */ #include /* setsockopt */ #include /* perror */ /* Function to enable keepalive on a socket s. If keepalive cannot be enabled we * return from the function. Otherwise, try to enable each option (for * keepalive) and if it fails go to next (although I've never seen any of these * fail) as this isn't - or at least I don't consider it to be - a fatal error. * There could be an exception however, as noted above. * * s is the socket created with socket() call (not included). * ka_time is how often to send a keepalive probe (after idleness time). * ka_intvl is the delay between sending another probe (if no response after * first probe). * ka_probes is the maximum number of probes before the connection is considered * dead. * * If ka_time, ka_intvl or ka_probes is <= 0, set to what I originally had * this at (updated 2014/10/15), which I guess you could consider similar to a * default parameter as you have in C++ (only that you have to pass all * parameters in C). */ void keepalive(int s, int ka_time, int ka_intvl, int ka_probes) { /* I don't know any system that does not have these defines but be safe and * check for the defines (including the others, below). If a system didn't have * it and you attempted to compile this code, you would get a compiler error. */ #ifdef SO_KEEPALIVE /* Technically, we pass a pointer to int to setsockopt but due to a * really stupid POSIX screw up it is a socklen_t (for the setsockopt * function). See Linus Torvalds' discussion on this in accept(2). int * works fine as socklen_t is a typedef anyway (POSIX's way of hiding * their blunder, is the theory). */ int ka = 1; if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &ka, sizeof(ka)) < 0) { /* Can't continue (without keepalive socket option TCP keepalives * are irrelevant); just return from this function. Modularity is a * good thing always but it is also helpful to not use the ugly goto * statements; just return at each error, to the proper location. */ perror("setsockopt"); return; } #ifdef TCP_KEEPIDLE if (ka_time <= 0) ka_time = 120; /* 60 seconds per minute * 2 minutes = 120. */ if (setsockopt(s, SOL_TCP, TCP_KEEPIDLE, &ka_time, sizeof(ka_time)) < 0) perror("setsockopt TCP_KEEPIDLE"); /* Should it continue if one call fails? Perhaps it shouldn't but I've * not seen this ever fail; presumably if one fails then the others will * also fail. I cannot confirm this without finding a way to make it * fail (maybe passing a file descriptor to it but why would anyone do * that in the first place? On the other hand, there is the ENOTSOCK * errno code) and I can't be bothered to do such a thing for a demo * anyway. */ #endif #ifdef TCP_KEEPINTVL if (ka_intvl <= 0) ka_intvl = 30; /* 30 seconds after no response from initial probe. */ if (setsockopt(s, SOL_TCP, TCP_KEEPINTVL, &ka_intvl, sizeof(ka_intvl)) < 0) perror("setsockopt TCP_KEEPINTVL"); #endif #ifdef TCP_KEEPCNT if (ka_probes <= 0) ka_probes = 20; /* Send up to 20 probes (ka_intvl seconds between each) until connection 'death'. */ if (setsockopt(s, SOL_TCP, TCP_KEEPCNT, &ka_probes, sizeof(ka_probes)) < 0) perror("setsockopt TCP_KEEPCNT"); #endif #endif } int main(int argc, char **argv) { /* dummy main to test compiling. */ return 0; }