summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Pointner <equinox@spreadspace.org>2010-12-10 00:41:52 +0000
committerChristian Pointner <equinox@spreadspace.org>2010-12-10 00:41:52 +0000
commitfcf009ded7a77959da5592e298de93fb044a6757 (patch)
tree3cbd3d7e245e7d63e9c5eed0e5075fa97ea1a6de
parentlistner_ vs listeners_ (diff)
re-reading the config file after sig-hup
git-svn-id: https://svn.spreadspace.org/tcpproxy/trunk@43 e61f0598-a718-4e21-a8f0-0aadfa62ad6b
-rw-r--r--src/cfg_parser.rl15
-rw-r--r--src/listener.c117
-rw-r--r--src/listener.h4
-rw-r--r--src/options.c2
-rw-r--r--src/sig_handler.c2
-rw-r--r--src/tcpproxy.c22
6 files changed, 116 insertions, 46 deletions
diff --git a/src/cfg_parser.rl b/src/cfg_parser.rl
index c215a83..47d237c 100644
--- a/src/cfg_parser.rl
+++ b/src/cfg_parser.rl
@@ -163,17 +163,18 @@ int parse_listener(char* p, char* pe, listeners_t* listener)
char* eof = pe;
%% write exec;
- if(cs == cfg_parser_error) {
+ if(cs == cfg_parser_error) {
log_printf(ERROR, "config file syntax error at line %d", cur_line);
+ listeners_revert(listener);
ret = 1;
- }
-
- // we only have one file so if we aren't there something is wrong
- if(cs != cfg_parser_first_final) {
+ } else if(cs != cfg_parser_first_final) {
+ // we only have one file so if we aren't there something is wrong
log_printf(ERROR, "config file syntax error: unexpected end of file");
+ listeners_revert(listener);
ret = 1;
- }
-
+ } else
+ ret = listeners_update(listener);
+
clear_listener_struct(&lst);
return ret;
diff --git a/src/listener.c b/src/listener.c
index 80876c5..69833b7 100644
--- a/src/listener.c
+++ b/src/listener.c
@@ -1,14 +1,14 @@
/*
* tcpproxy
*
- * tcpproxy is a simple tcp connection proxy which combines the
- * features of rinetd and 6tunnel. tcpproxy supports IPv4 and
- * IPv6 and also supports connections from IPv6 to IPv4
+ * tcpproxy is a simple tcp connection proxy which combines the
+ * features of rinetd and 6tunnel. tcpproxy supports IPv4 and
+ * IPv6 and also supports connections from IPv6 to IPv4
* endpoints and vice versa.
- *
+ *
*
* Copyright (C) 2010-2011 Christian Pointner <equinox@spreadspace.org>
- *
+ *
* This file is part of tcpproxy.
*
* tcpproxy is free software: you can redistribute it and/or modify
@@ -49,7 +49,7 @@ void listeners_delete_element(void* e)
{
if(!e)
return;
-
+
listener_t* element = (listener_t*)e;
if(element->fd_ >= 0)
close(element->fd_);
@@ -76,7 +76,7 @@ int listeners_add(listeners_t* list, const char* laddr, resolv_type_t lrt, const
if(!raddr) { log_printf(ERROR, "no remote address specified"); return -1; }
if(!rport) { log_printf(ERROR, "no remote port specified"); return -1; }
-// TODO: what if more than one address is returned here?
+// TODO: what if more than one address is returned here?
struct addrinfo* re = tcp_resolve_endpoint(raddr, rport, rrt, 0);
if(!re)
return -1;
@@ -86,7 +86,7 @@ int listeners_add(listeners_t* list, const char* laddr, resolv_type_t lrt, const
se = tcp_resolve_endpoint(saddr, NULL, rrt, 0);
if(!se) {
freeaddrinfo(re);
- return -1;
+ return -1;
}
}
@@ -140,13 +140,16 @@ int listeners_add(listeners_t* list, const char* laddr, resolv_type_t lrt, const
static int activate_listener(listener_t* l)
{
+ if(!l || l->state_ != NEW)
+ return -1;
+
l->fd_ = socket(l->local_end_.addr_.ss_family, SOCK_STREAM, 0);
if(l->fd_ < 0) {
log_printf(ERROR, "Error on opening tcp socket: %s", strerror(errno));
l->state_ = ZOMBIE;
return -1;
}
-
+
int on = 1;
int ret = setsockopt(l->fd_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if(ret) {
@@ -158,23 +161,23 @@ static int activate_listener(listener_t* l)
if(setsockopt(l->fd_, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)))
log_printf(WARNING, "failed to set IPV6_V6ONLY socket option: %s", strerror(errno));
}
-
+
ret = bind(l->fd_, (struct sockaddr *)&(l->local_end_.addr_), l->local_end_.len_);
if(ret) {
log_printf(ERROR, "Error on bind(): %s", strerror(errno));
l->state_ = ZOMBIE;
return -1;
}
-
+
ret = listen(l->fd_, 0);
if(ret) {
log_printf(ERROR, "Error on listen(): %s", strerror(errno));
l->state_ = ZOMBIE;
return -1;
}
-
+
l->state_ = ACTIVE;
-
+
char* ls = tcp_endpoint_to_string(l->local_end_);
char* rs = tcp_endpoint_to_string(l->remote_end_);
char* ss = tcp_endpoint_to_string(l->source_end_);
@@ -186,38 +189,102 @@ static int activate_listener(listener_t* l)
return 0;
}
-int listeners_activate(listeners_t* list)
+static void update_listener(listener_t* dest, listener_t* src)
+{
+ if(!dest || !src || src->state_ != ZOMBIE || dest->state_ != NEW)
+ return;
+
+ dest->fd_ = src->fd_;
+ src->fd_ = -1;
+ dest->state_ = ACTIVE;
+
+ char* ls = tcp_endpoint_to_string(dest->local_end_);
+ char* rs = tcp_endpoint_to_string(dest->remote_end_);
+ char* ss = tcp_endpoint_to_string(dest->source_end_);
+ log_printf(NOTICE, "reusing %s with remote: %s%s%s", ls ? ls:"(null)", rs ? rs:"(null)", ss ? " and source " : "", ss ? ss : "");
+ if(ls) free(ls);
+ if(rs) free(rs);
+ if(ss) free(ss);
+}
+
+static listener_t* find_zombie_listener(listeners_t* list, tcp_endpoint_t* local_end)
+{
+ if(!list)
+ return NULL;
+
+ slist_element_t* tmp = list->first_;
+ while(tmp) {
+ listener_t* l = (listener_t*)tmp->data_;
+ if(l && l->state_ == ZOMBIE && l->local_end_.len_ == local_end->len_ &&
+ !memcmp(&(l->local_end_.addr_), &(local_end->addr_), local_end->len_))
+ return l;
+ tmp = tmp->next_;
+ }
+
+ return NULL;
+}
+
+int listeners_update(listeners_t* list)
{
if(!list)
return;
-
- int ret = 0;
+
slist_element_t* tmp = list->first_;
while(tmp) {
listener_t* l = (listener_t*)tmp->data_;
- if(l && l->state_ == NEW)
- ret = activate_listener(l);
+ if(l && l->state_ == ACTIVE)
+ l->state_ = ZOMBIE;
+ tmp = tmp->next_;
+ }
- if(ret)
- break;
+ int retval = 0;
+ tmp = list->first_;
+ while(tmp) {
+ listener_t* l = (listener_t*)tmp->data_;
+ int ret = 0;
+ if(l && l->state_ == NEW) {
+ listener_t* tmp = find_zombie_listener(list, &(l->local_end_));
+ if(tmp)
+ update_listener(l, tmp);
+ else
+ ret = activate_listener(l);
+ }
+ if(!retval) retval = ret;
tmp = tmp->next_;
}
- return ret;
+ int cnt = 0;
+ tmp = list->first_;
+ while(tmp) {
+ listener_t* l = (listener_t*)tmp->data_;
+ tmp = tmp->next_;
+ if(l && l->state_ == ZOMBIE) {
+ cnt++;
+ slist_remove(list, l);
+ }
+ }
+ log_printf(DEBUG, "%d listener zombies removed", cnt);
+
+ return retval;
}
-void listeners_cleanup(listeners_t* list)
+void listeners_revert(listeners_t* list)
{
if(!list)
return;
+ int cnt = 0;
slist_element_t* tmp = list->first_;
while(tmp) {
listener_t* l = (listener_t*)tmp->data_;
tmp = tmp->next_;
- if(l && l->state_ == ZOMBIE)
+ if(l && l->state_ == NEW) {
+ cnt++;
slist_remove(list, l);
+ }
}
+
+ log_printf(DEBUG, "%d new listeners reverted", cnt);
}
void listeners_remove(listeners_t* list, int fd)
@@ -245,7 +312,7 @@ void listeners_print(listeners_t* list)
{
if(!list)
return;
-
+
slist_element_t* tmp = list->first_;
while(tmp) {
listener_t* l = (listener_t*)tmp->data_;
@@ -309,6 +376,6 @@ int listeners_handle_accept(listeners_t* list, clients_t* clients, fd_set* set)
}
tmp = tmp->next_;
}
-
+
return 0;
}
diff --git a/src/listener.h b/src/listener.h
index 7638254..6b95498 100644
--- a/src/listener.h
+++ b/src/listener.h
@@ -52,8 +52,8 @@ typedef slist_t listeners_t;
int listeners_init(listeners_t* list);
void listeners_clear(listeners_t* list);
int listeners_add(listeners_t* list, const char* laddr, resolv_type_t lrt, const char* lport, const char* raddr, resolv_type_t rrt, const char* rport, const char* saddr);
-int listeners_activate(listeners_t* list);
-void listeners_cleanup(listeners_t* list);
+int listeners_update(listeners_t* list);
+void listeners_revert(listeners_t* list);
void listeners_remove(listeners_t* list, int fd);
listener_t* listeners_find(listeners_t* list, int fd);
void listeners_print(listeners_t* list);
diff --git a/src/options.c b/src/options.c
index b905426..116cb52 100644
--- a/src/options.c
+++ b/src/options.c
@@ -234,6 +234,8 @@ void options_parse_post(options_t* opt)
if(opt->config_file_ && opt->local_port_) {
log_printf(WARNING, "local port and config file specified, will ignore config file");
+ free(opt->config_file_);
+ opt->config_file_ = NULL;
}
if(opt->buffer_size_ <= 0) {
diff --git a/src/sig_handler.c b/src/sig_handler.c
index 6e6a04a..7c3d45b 100644
--- a/src/sig_handler.c
+++ b/src/sig_handler.c
@@ -119,7 +119,7 @@ int signal_handle()
case SIGINT: log_printf(NOTICE, "SIG-Int caught, exitting"); return_value = 1; break;
case SIGQUIT: log_printf(NOTICE, "SIG-Quit caught, exitting"); return_value = 1; break;
case SIGTERM: log_printf(NOTICE, "SIG-Term caught, exitting"); return_value = 1; break;
- case SIGHUP: log_printf(NOTICE, "SIG-Hup caught"); break;
+ case SIGHUP: log_printf(NOTICE, "SIG-Hup caught"); return_value = 2; break;
case SIGUSR1: log_printf(NOTICE, "SIG-Usr1 caught"); break;
case SIGUSR2: log_printf(NOTICE, "SIG-Usr2 caught"); break;
default: log_printf(WARNING, "unknown signal %d caught, ignoring", sig); break;
diff --git a/src/tcpproxy.c b/src/tcpproxy.c
index fcc871f..1007b80 100644
--- a/src/tcpproxy.c
+++ b/src/tcpproxy.c
@@ -71,9 +71,16 @@ int main_loop(options_t* opt, listeners_t* listeners)
continue;
if(FD_ISSET(sig_fd, &readfds)) {
- if(signal_handle()) {
- return_value = 1;
- break;
+ return_value = signal_handle();
+ if(return_value == 1) break;
+ if(return_value == 2) {
+ if(opt->config_file_) {
+ log_printf(NOTICE, "re-reading config file: %s", opt->config_file_);
+ read_configfile(opt->config_file_, listeners);
+ } else
+ log_printf(NOTICE, "ignoring SIGHUP: no config file specified");
+
+ return_value = 0;
}
}
@@ -149,6 +156,7 @@ int main(int argc, char* argv[])
if(opt.local_port_) {
ret = listeners_add(&listeners, opt.local_addr_, opt.lresolv_type_, opt.local_port_, opt.remote_addr_, opt.rresolv_type_, opt.remote_port_, opt.source_addr_);
+ if(!ret) ret = listeners_update(&listeners);
if(ret) {
listeners_clear(&listeners);
options_clear(&opt);
@@ -167,14 +175,6 @@ int main(int argc, char* argv[])
}
}
- ret = listeners_activate(&listeners);
- if(ret) {
- listeners_clear(&listeners);
- options_clear(&opt);
- log_close();
- exit(-1);
- }
-
priv_info_t priv;
if(opt.username_)
if(priv_init(&priv, opt.username_, opt.groupname_)) {