callback, for clients there's a new callback just for this purpose
LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH.
+
+TCP Keepalive
+-------------
+
+It is possible for a connection which is not being used to send to die
+silently somewhere between the peer and the side not sending. In this case
+by default TCP will just not report anything and you will never get any more
+incoming data or sign the link is dead until you try to send.
+
+To deal with getting a notification of that situation, you can choose to
+enable TCP keepalives on all libwebsockets sockets, when you create the
+context.
+
+To enable keepalive, set the ka_time member of the context creation parameter
+struct to a nonzero value (in seconds) at context creation time. You should
+also fill ka_probes and ka_interval in that case.
+
+With keepalive enabled, the TCP layer will send control packets that should
+stimulate a response from the peer without affecting link traffic. If the
+response is not coming, the socket will announce an error at poll() forcing
+a close.
+
"1.1 9e7f737", representing the library version from configure.ac
and the git HEAD hash the library was built from
+ - TCP Keepalive can now optionally be applied to all lws sockets, with
+ controllable timeout, number of probes and probe interval. This
+ enables detection of idle connections which are logically okay, but
+ are in fact dead, due to network connectivity issues at the server,
+ client, or any intermediary. By default it's not enabled, but you
+ can enable it by setting a non-zero timeout (in seconds) at the new
+ ka_time member at context creation time.
+
User api changes
----------------
int n;
int plen = 0;
char pkt[512];
- int opt = 1;
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
- struct protoent *tcp_proto;
-#endif
lwsl_client("__libwebsocket_client_connect_2\n");
#ifndef LWS_NO_EXTENSIONS
* prepare the actual connection (to the proxy, if any)
*/
- lwsl_client("__libwebsocket_client_connect_2: address %s", wsi->c_address);
+ lwsl_client("__libwebsocket_client_connect_2: address %s\n",
+ wsi->c_address);
server_hostent = gethostbyname(wsi->c_address);
if (server_hostent == NULL) {
server_addr.sin_addr = *((struct in_addr *)server_hostent->h_addr);
bzero(&server_addr.sin_zero, 8);
- /* Disable Nagle */
-#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
- setsockopt(wsi->sock, SOL_TCP, TCP_NODELAY,
- (const void *)&opt, sizeof(opt));
-#else
- tcp_proto = getprotobyname("TCP");
- setsockopt(wsi->sock, tcp_proto->p_proto, TCP_NODELAY,
- &opt, sizeof(opt));
-#endif
-
if (connect(wsi->sock, (struct sockaddr *)&server_addr,
sizeof(struct sockaddr)) == -1) {
lwsl_debug("Connect failed\n");
lwsl_client("connected\n");
+ if (lws_set_socket_options(context, wsi->sock)) {
+ lwsl_err("Failed to set wsi socket options\n");
+ close(wsi->sock);
+ goto oom4;
+ }
+
insert_wsi_socket_into_fds(context, wsi);
/* we are connected to server, or proxy */
return n;
}
+int lws_set_socket_options(struct libwebsocket_context *context, int fd)
+{
+ int optval = 1;
+ socklen_t optlen = sizeof(optval);
+#ifdef WIN32
+ unsigned long optl = 0;
+#endif
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
+ struct protoent *tcp_proto;
+#endif
+
+ if (context->ka_time) {
+ /* enable keepalive on this socket */
+ optval = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
+ (const void *)&optval, optlen) < 0)
+ return 1;
+
+ /* set the keepalive conditions we want on it too */
+ optval = context->ka_time;
+ if (setsockopt(fd, IPPROTO_IP, TCP_KEEPIDLE,
+ (const void *)&optval, optlen) < 0)
+ return 1;
+
+ optval = context->ka_probes;
+ if (setsockopt(fd, IPPROTO_IP, TCP_KEEPINTVL,
+ (const void *)&optval, optlen) < 0)
+ return 1;
+
+ optval = context->ka_interval;
+ if (setsockopt(fd, IPPROTO_IP, TCP_KEEPCNT,
+ (const void *)&optval, optlen) < 0)
+ return 1;
+ }
+
+ /* Disable Nagle */
+ optval = 1;
+#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
+ setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen);
+#else
+ tcp_proto = getprotobyname("TCP");
+ setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen);
+#endif
+
+ /* We are nonblocking... */
+#ifdef WIN32
+ ioctlsocket(fd, FIONBIO, &optl);
+#else
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+#endif
+
+ return 0;
+}
+
int lws_send_pipe_choked(struct libwebsocket *wsi)
{
struct pollfd fds;
* @options: 0, or LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK
* @user: optional user pointer that can be recovered via the context
* pointer using libwebsocket_context_user
+ * @ka_time: 0 for no keepalive, otherwise apply this keepalive timeout to
+ * all libwebsocket sockets, client or server
+ * @ka_probes: if ka_time was nonzero, after the timeout expires how many
+ * times to try to get a response from the peer before giving up
+ * and killing the connection
+ * @ka_interval: if ka_time was nonzero, how long to wait before each ka_probes
+ * attempt
*/
struct lws_context_creation_info {
int uid;
unsigned int options;
void *user;
+ int ka_time;
+ int ka_probes;
+ int ka_interval;
+
};
LWS_EXTERN
int listen_service_fd;
int listen_service_extraseen;
+ int ka_time;
+ int ka_probes;
+ int ka_interval;
+
#ifdef LWS_LATENCY
unsigned long worst_latency;
char worst_latency_info[256];
enum libwebsocket_callback_reasons reason, void *user,
void *in, size_t len);
+extern int
+lws_set_socket_options(struct libwebsocket_context *context, int fd);
+
#ifndef LWS_OPENSSL_SUPPORT
unsigned char *
unsigned int clilen;
struct sockaddr_in cli_addr;
int n;
- int opt = 1;
ssize_t len;
#ifdef LWS_OPENSSL_SUPPORT
int m;
break;
}
- /* Disable Nagle */
- opt = 1;
- setsockopt(accept_fd, IPPROTO_TCP, TCP_NODELAY,
- (const void *)&opt, sizeof(opt));
-
- /* We are nonblocking... */
- #ifdef WIN32
- opt = 0;
- ioctlsocket(accept_fd, FIONBIO, (unsigned long *)&opt );
- #else
- fcntl(accept_fd, F_SETFL, O_NONBLOCK);
- #endif
+ lws_set_socket_options(context, accept_fd);
/*
* look at who we connected to and give user code a chance
<i>int</i> <b>uid</b>;<br>
<i>unsigned int</i> <b>options</b>;<br>
<i>void *</i> <b>user</b>;<br>
+ <i>int</i> <b>ka_time</b>;<br>
+ <i>int</i> <b>ka_probes</b>;<br>
+ <i>int</i> <b>ka_interval</b>;<br>
};<br>
<h3>Members</h3>
<dl>
<dt><b>user</b>
<dd>optional user pointer that can be recovered via the context
pointer using libwebsocket_context_user
+<dt><b>ka_time</b>
+<dd>0 for no keepalive, otherwise apply this keepalive timeout to
+all libwebsocket sockets, client or server
+<dt><b>ka_probes</b>
+<dd>if ka_time was nonzero, after the timeout expires how many
+times to try to get a response from the peer before giving up
+and killing the connection
+<dt><b>ka_interval</b>
+<dd>if ka_time was nonzero, how long to wait before each ka_probes
+attempt
</dl>
<hr>