diff options
Diffstat (limited to 'websocksy.c')
| -rw-r--r-- | websocksy.c | 40 | 
1 files changed, 32 insertions, 8 deletions
diff --git a/websocksy.c b/websocksy.c index c2f0631..8b37cec 100644 --- a/websocksy.c +++ b/websocksy.c @@ -9,6 +9,7 @@  #include <unistd.h>  #include <fcntl.h>  #include <ctype.h> +#include <time.h>  #include "websocksy.h"  #include "builtins.h" @@ -22,7 +23,6 @@  /* TODO   * - TLS - * - pings   * - continuation   */ @@ -46,6 +46,7 @@ char* xstr_lower(char* in){  static ws_config config = {  	.host = NULL,  	.port = NULL, +	.ping_interval = 30,  	/* Assign the built-in defaultpeer backend by default */  	.backend.init = backend_defaultpeer_init,  	.backend.config = backend_defaultpeer_configure, @@ -205,8 +206,9 @@ static int usage(char* fn){  	fprintf(stderr, "\t%s <configuration file>\n", fn);  	fprintf(stderr, "\t%s [-p <port>] [-l <listen address>] [-b <discovery backend>] [-c <option>=<value>]\n", fn);  	fprintf(stderr, "Arguments:\n"); -	fprintf(stderr, "\t-p <port>\t\tWebSocket listen port (Current: %s, Default: %s)\n", config.port, DEFAULT_PORT); -	fprintf(stderr, "\t-l <address>\t\tWebSocket listen address (Current: %s, Default: %s)\n", config.host, DEFAULT_HOST); +	fprintf(stderr, "\t-p <port>\t\tWebSocket listen port (Current: %s, Default: %s)\n", config.port ? config.port : DEFAULT_PORT, DEFAULT_PORT); +	fprintf(stderr, "\t-l <address>\t\tWebSocket listen address (Current: %s, Default: %s)\n", config.host ? config.host : DEFAULT_HOST, DEFAULT_HOST); +	fprintf(stderr, "\t-k <seconds>\t\tKeepalive ping interval (Current: %lu)\n", config.ping_interval);  	fprintf(stderr, "\t-b <backend>\t\tPeer discovery backend (Default: built-in 'defaultpeer')\n");  	fprintf(stderr, "\t-c <option>=<value>\tPass configuration options to the peer discovery backend\n");  	return EXIT_FAILURE; @@ -273,6 +275,10 @@ int main(int argc, char** argv){  	fd_set read_fds;  	size_t n;  	int listen_fd = -1, status, max_fd; +	struct timespec current_time; +	struct timeval select_timeout = { +		0 +	};  	//register default framing functions before parsing arguments, as they may be assigned within a backend configuration  	if(plugin_register_framing("auto", framing_auto) @@ -313,8 +319,14 @@ int main(int argc, char** argv){  	//core loop  	while(!shutdown_requested){ +		//reset the select timeout +		select_timeout.tv_sec = config.ping_interval / 2; +		select_timeout.tv_usec = 0; + +		//clear the select set  		FD_ZERO(&read_fds); +		//push the websocket fd  		FD_SET(listen_fd, &read_fds);  		max_fd = listen_fd; @@ -336,18 +348,21 @@ int main(int argc, char** argv){  		}  		//block until something happens -		status = select(max_fd + 1, &read_fds, NULL, NULL, NULL); +		status = select(max_fd + 1, &read_fds, NULL, NULL, config.ping_interval ? &select_timeout : NULL);  		if(status < 0){  			fprintf(stderr, "Failed to select: %s\n", strerror(errno));  			break;  		} -		else if(status == 0){ -			//timeout in select - ignore for now -		}  		else{ +			//update current timestamp +			if(clock_gettime(CLOCK_MONOTONIC_COARSE, ¤t_time) < 0){ +				fprintf(stderr, "Failed to update current timestamp\n"); +				break; +			} +  			//new websocket client  			if(FD_ISSET(listen_fd, &read_fds)){ -				if(ws_accept(listen_fd)){ +				if(ws_accept(listen_fd, current_time.tv_sec)){  					break;  				}  			} @@ -356,6 +371,7 @@ int main(int argc, char** argv){  			for(n = 0; n < socks; n++){  				if(sock[n].ws_fd >= 0){  					if(FD_ISSET(sock[n].ws_fd, &read_fds)){ +						sock[n].last_event = current_time.tv_sec;  						if(ws_data(sock + n)){  							break;  						} @@ -366,6 +382,14 @@ int main(int argc, char** argv){  							break;  						}  					} + +					//send keep-alive frames +					if(config.ping_interval && +							current_time.tv_sec - sock[n].last_event > config.ping_interval){ +						if(ws_send_frame(sock + n, ws_frame_ping, (uint8_t*) "PING", 4)){ +							ws_close(sock + n, ws_close_unexpected, NULL); +						} +					}  				}  			}  		}  | 
