From 14e844f3f2838dc4401c59cba54c1ffcff89e4fd Mon Sep 17 00:00:00 2001 From: Damien Stuart Date: Thu, 1 Jul 2010 03:12:32 +0000 Subject: [PATCH] Updates to TCP server to close the lock file handle, use a non-blocking socket, and detect when the parent fwknop dies so it can exit as well. git-svn-id: file:///home/mbr/svn/fwknop/trunk@228 510a4753-2344-4c79-9c09-4d669213fbeb --- server/fwknopd.c | 5 +++ server/fwknopd_common.h | 1 + server/tcp_server.c | 84 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 83 insertions(+), 7 deletions(-) diff --git a/server/fwknopd.c b/server/fwknopd.c index 72b119d6..b919dbf8 100644 --- a/server/fwknopd.c +++ b/server/fwknopd.c @@ -597,6 +597,11 @@ write_pid_file(fko_srv_options_t *opts) */ fsync(op_fd); + /* Put the lock file discriptor in out options struct so any + * child processes we my spawn can close and release it. + */ + opts->lock_fd = op_fd; + return 0; } diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index 1b3e3717..f54470cf 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -435,6 +435,7 @@ typedef struct fko_srv_options int data_link_offset; int tcp_server_pid; + int lock_fd; spa_pkt_info_t spa_pkt; /* The current SPA packet */ diff --git a/server/tcp_server.c b/server/tcp_server.c index 5cb898ae..26b79fdd 100644 --- a/server/tcp_server.c +++ b/server/tcp_server.c @@ -33,9 +33,10 @@ #include #endif #include -#include +#include +#include -static int c_sock; +//static int c_sock; /* Fork off and run a "dummy" TCP server. The return value is the PID of * the child process or -1 if there is a fork error. @@ -43,9 +44,12 @@ static int c_sock; int run_tcp_server(fko_srv_options_t *opts) { - pid_t pid; - int s_sock, clen; + pid_t pid, ppid; + int s_sock, c_sock, sfd_flags, clen, selval; + int reuse_addr = 1; + fd_set sfd_set; struct sockaddr_in saddr, caddr; + struct timeval tv; char sipbuf[MAX_IP_STR_LEN]; unsigned short port = atoi(opts->config[CONF_TCPSERV_PORT]); @@ -65,8 +69,19 @@ run_tcp_server(fko_srv_options_t *opts) return(pid); } - /* We are the child, so let's make a TCP server */ + /* Get our parent PID so we can periodically check for it. We want to + * know when it goes away so we can to. + */ + ppid = getppid(); + /* We are the child. The first thing to do is close our copy of the + * parent PID file so we don't end up holding the lock if the parent + * suffers a sudden death that doesn't take us out too. + */ + close(opts->lock_fd); + + /* Now, let's make a TCP server + */ if ((s_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { log_msg(LOG_ERR, "run_tcp_server: socket() failed: %s", @@ -74,6 +89,29 @@ run_tcp_server(fko_srv_options_t *opts) exit(EXIT_FAILURE); } + /* So that we can re-bind to it without TIME_WAIT problems + */ + setsockopt(s_sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)); + + /* Make our main socket non-blocking so we don't have to be stuck on + * listening for incoming connections. + */ + if((sfd_flags = fcntl(s_sock, F_GETFL, 0)) < 0) + { + log_msg(LOG_ERR, "run_tcp_server: fcntl F_GETFL error: %s", + strerror(errno)); + exit(EXIT_FAILURE); + } + + sfd_flags |= O_NONBLOCK; + + if(fcntl(s_sock, F_SETFL, sfd_flags) < 0) + { + log_msg(LOG_ERR, "run_tcp_server: fcntl F_SETFL error setting )_NONBLOCK: %s", + strerror(errno)); + exit(EXIT_FAILURE); + } + /* Construct local address structure */ memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; /* Internet address family */ @@ -105,6 +143,38 @@ run_tcp_server(fko_srv_options_t *opts) */ while(1) { + /* Initialize and setup the socket for select. + */ + FD_ZERO(&sfd_set); + FD_SET(s_sock, &sfd_set); + + /* Set our select timeout to 200 ms. + */ + tv.tv_sec = 0; + tv.tv_usec = 200000; + + selval = select(s_sock+1, &sfd_set, NULL, NULL, &tv); + + if(selval == -1) + { + /* Select error - so kill the child and bail. + */ + log_msg(LOG_ERR, "run_tcp_server: select error socket: %s", + strerror(errno)); + exit(EXIT_FAILURE); + } + + if(selval == 0) + { + /* Timeout - So we check to make sure our parent is still there by simply + * using kill(ppid, 0) and checking the return value. + */ + if(kill(ppid, 0) != 0 && errno == ESRCH) + exit(EXIT_FAILURE); + + continue; + } + /* Wait for a client to connect */ if((c_sock = accept(s_sock, (struct sockaddr *) &caddr, &clen)) < 0) @@ -118,7 +188,7 @@ run_tcp_server(fko_srv_options_t *opts) { memset(sipbuf, 0x0, MAX_IP_STR_LEN); inet_ntop(AF_INET, &(caddr.sin_addr.s_addr), sipbuf, MAX_IP_STR_LEN); - log_msg(LOG_INFO, "tcp_server: Got TCP connection from %s.", sipbuf); + log_msg(LOG_INFO|LOG_STDERR, "tcp_server: Got TCP connection from %s.", sipbuf); } /* Though hacky and clunky, we just sleep for a second then @@ -128,7 +198,7 @@ run_tcp_server(fko_srv_options_t *opts) * after that time. */ usleep(1000000); - + shutdown(c_sock, SHUT_RDWR); close(c_sock); } }