diff options
| author | tomsmeding <tom.smeding@gmail.com> | 2017-04-14 21:36:22 +0200 | 
|---|---|---|
| committer | tomsmeding <tom.smeding@gmail.com> | 2017-04-14 21:55:22 +0200 | 
| commit | ca207b038bf4c150f008042e1bf3a102e68880ca (patch) | |
| tree | 02f5e0da719b1c070defd24e47bc6ef10c69d675 | |
| parent | c02fa99188c868496f864a20b1139ec4e6f93c2a (diff) | |
server: Send _push ping every 60s
| -rw-r--r-- | main.c | 12 | ||||
| -rw-r--r-- | runloop.c | 55 | ||||
| -rw-r--r-- | runloop.h | 4 | 
3 files changed, 64 insertions, 7 deletions
| @@ -10,6 +10,7 @@  #include "command.h"  #include "conn_data.h"  #include "db.h" +#include "net.h"  #include "runloop.h"  #include "user_data.h" @@ -111,7 +112,7 @@ static bool server_socket_callback(int fd){  	do sock=accept(fd,NULL,NULL);  	while(sock<0&&errno==EINTR);  	if(sock<0)die_perror("accept"); -	runloop_add_fd(sock,client_socket_callback); +	runloop_add_fd(sock,client_socket_callback,true);  	struct hash_item *item=malloc(1,struct hash_item);  	conn_data_init(&item->cd,sock); @@ -121,6 +122,11 @@ static bool server_socket_callback(int fd){  	return false;  } +static bool timeout_callback(int fd){ +	net_send_raw_text(fd,"_push ping\n",11); +	return false;  // We aren't going to get closure info from a send() +} +  #ifndef __APPLE__  void srandomdev(void){  	FILE *f=fopen("/dev/urandom","r"); @@ -139,7 +145,9 @@ int main(void){  	db_init();  	int sock=create_server_socket();  	printf("Listening on port %d\n",PORT); -	runloop_add_fd(sock,server_socket_callback); +	runloop_set_timeout(60*1000000,timeout_callback); +	runloop_add_fd(sock,server_socket_callback,false);  	runloop_run(); +	printf("Runloop empty, shutting down\n");  	db_close();  } @@ -1,17 +1,22 @@  #include <string.h>  #include <errno.h>  #include <sys/select.h> +#include <sys/time.h>  #include "runloop.h"  struct fd_list_item{  	int fd;  	runloop_callback *func; +	i64 last_activity;  // -1 if timeout is not enabled  };  static struct fd_list_item *fd_list;  static size_t fd_list_len,fd_list_cap; +static i64 timeout_usecs=0; +static runloop_callback *timeout_callback=NULL; +  __attribute__((constructor))  static void constructor(void){  	fd_list_cap=16; @@ -20,32 +25,74 @@ static void constructor(void){  } -void runloop_add_fd(int fd,runloop_callback *func){ +static i64 make_timestamp(void){ +	struct timeval tv; +	gettimeofday(&tv,NULL); +	return (i64)tv.tv_sec*1000000+tv.tv_usec; +} + +void runloop_set_timeout(i64 usecs,runloop_callback *cb){ +	timeout_usecs=usecs; +	timeout_callback=cb; +} + +void runloop_add_fd(int fd,runloop_callback *func,bool use_timeout){  	if(fd_list_len==fd_list_cap){  		fd_list_cap*=2;  		fd_list=realloc(fd_list,fd_list_cap,struct fd_list_item);  	}  	fd_list[fd_list_len].fd=fd;  	fd_list[fd_list_len].func=func; +	fd_list[fd_list_len].last_activity=use_timeout ? make_timestamp() : -1;  	fd_list_len++;  }  void runloop_run(void){ -	while(true){ +	while(fd_list_len>0){  		fd_set inset;  		FD_ZERO(&inset);  		int maxfd=-1; +		i64 oldest_timestamp=-1; +		int oldest_at=-1;  		for(size_t i=0;i<fd_list_len;i++){  			FD_SET(fd_list[i].fd,&inset);  			if(fd_list[i].fd>maxfd)maxfd=fd_list[i].fd; +			if(fd_list[i].last_activity!=-1&& +					(oldest_timestamp==-1||fd_list[i].last_activity<oldest_timestamp)){ +				oldest_timestamp=fd_list[i].last_activity; +				oldest_at=i; +			}  		} -		int ret=select(maxfd+1,&inset,NULL,NULL,NULL); -		if(ret<=0){ + +		struct timeval tv={.tv_sec=0,.tv_usec=0}; +		struct timeval *tv_ptr=NULL; +		if(timeout_usecs>0&&timeout_callback!=NULL&&oldest_timestamp!=-1){ +			i64 chosen_timeout=timeout_usecs-(make_timestamp()-oldest_timestamp); +			if(chosen_timeout<0)chosen_timeout=0; +			tv.tv_sec=chosen_timeout/1000000; +			tv.tv_usec=chosen_timeout%1000000; +			tv_ptr=&tv; +		} +		int ret=select(maxfd+1,&inset,NULL,NULL,tv_ptr); +		if(ret==0){ +			fd_list[oldest_at].last_activity=make_timestamp(); +			if(timeout_callback(fd_list[oldest_at].fd)){ +				memmove(fd_list+oldest_at,fd_list+oldest_at+1, +				        (fd_list_len-oldest_at-1)*sizeof(struct fd_list_item)); +				fd_list_len--; +			} +			continue; +		} +		if(ret<0){  			if(errno==EINTR)continue;  			die_perror("select");  		} +  		for(size_t i=0;i<fd_list_len;i++){  			if(FD_ISSET(fd_list[i].fd,&inset)){ +				if(fd_list[i].last_activity!=-1){ +					fd_list[i].last_activity=make_timestamp(); +				}  				if(fd_list[i].func(fd_list[i].fd)){  					memmove(fd_list+i,fd_list+i+1,(fd_list_len-i-1)*sizeof(struct fd_list_item));  					i--; @@ -6,5 +6,7 @@  // Return true to remove fd from runloop  typedef bool runloop_callback(int fd); -void runloop_add_fd(int fd,runloop_callback *func); +void runloop_set_timeout(i64 usecs,runloop_callback *timeout_callback); + +void runloop_add_fd(int fd,runloop_callback *func,bool use_timeout);  void runloop_run(void);  // Returns when empty | 
