introduce timeout system

This adds a concept of timeouts for operations enforced by
connection closure if the timeout is reached.

Once a second all sockets are checked for timing out, every time
there is a service call it checks to see if a second has passed since
the last check and checks if so.

You can also call libwebsocket_service_fd() with a NULL fd to give
the timeouts a chance to be detected; if it's less than a second since
the last check it returns immediately.

Signed-off-by: Andy Green <andy@warmcat.com>
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index c6477ce..a35193d 100644
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -276,7 +276,7 @@
 {
 	unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + MAX_BROADCAST_PAYLOAD +
 						  LWS_SEND_BUFFER_POST_PADDING];
-	struct libwebsocket *wsi = wsi_from_fd(this, pollfd->fd);
+	struct libwebsocket *wsi;
 	struct libwebsocket *new_wsi;
 	int n;
 	int m;
@@ -284,6 +284,44 @@
 	int accept_fd;
 	unsigned int clilen;
 	struct sockaddr_in cli_addr;
+	struct timeval tv;
+
+	/*
+	 * you can call us with pollfd = NULL to just allow the once-per-second
+	 * global timeout checks; if less than a second since the last check
+	 * it returns immediately then.
+	 */
+
+	gettimeofday(&tv, NULL);
+
+	if (this->last_timeout_check_s != tv.tv_sec) {
+		this->last_timeout_check_s = tv.tv_sec;
+
+		/* global timeout check once per second */
+
+		for (n = 0; n < this->fds_count; n++) {
+			wsi = wsi_from_fd(this, this->fds[n].fd);
+			if (!wsi->pending_timeout)
+				continue;
+
+			/*
+			 * if we went beyond the allowed time, kill the
+			 * connection
+			 */
+
+			if (tv.tv_sec > wsi->pending_timeout_limit)
+				libwebsocket_close_and_free_session(this, wsi);
+		}
+	}
+
+	/* just here for timeout management? */
+
+	if (pollfd == NULL)
+		return 0;
+
+	/* no, here to service a socket descriptor */
+
+	wsi = wsi_from_fd(this, pollfd->fd);
 
 	if (wsi == NULL)
 		return 1;
@@ -336,6 +374,7 @@
 
 		memset(new_wsi, 0, sizeof (struct libwebsocket));
 		new_wsi->sock = accept_fd;
+		new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
 
 #ifdef LWS_OPENSSL_SUPPORT
 		new_wsi->ssl = NULL;