From 8cd030696dd1bf0864443b4c745063821d9cd76c Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Thu, 9 Dec 2010 20:35:42 +0000 Subject: introduced listener states git-svn-id: https://svn.spreadspace.org/tcpproxy/trunk@41 e61f0598-a718-4e21-a8f0-0aadfa62ad6b --- src/listener.c | 140 +++++++++++++++++++++++++++++++++++++-------------------- src/listener.h | 6 +++ src/tcpproxy.c | 8 ++++ 3 files changed, 105 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/src/listener.c b/src/listener.c index 9f54d26..19be646 100644 --- a/src/listener.c +++ b/src/listener.c @@ -51,7 +51,8 @@ void listener_delete_element(void* e) return; listener_t* element = (listener_t*)e; - close(element->fd_); + if(element->fd_ >= 0) + close(element->fd_); free(e); } @@ -119,54 +120,10 @@ int listener_add(listeners_t* list, const char* laddr, resolv_type_t lrt, const memset(&(element->local_end_.addr_), 0, sizeof(element->local_end_.addr_)); memcpy(&(element->local_end_.addr_), l->ai_addr, l->ai_addrlen); element->local_end_.len_ = l->ai_addrlen; - - element->fd_ = socket(l->ai_family, SOCK_STREAM, 0); - if(element->fd_ < 0) { - log_printf(ERROR, "Error on opening tcp socket: %s", strerror(errno)); - free(element); - ret = -1; - break; - } - - int on = 1; - ret = setsockopt(element->fd_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - if(ret) { - log_printf(ERROR, "Error on setsockopt(): %s", strerror(errno)); - close(element->fd_); - free(element); - break; - } - if(l->ai_family == AF_INET6) { - if(setsockopt(element->fd_, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on))) - log_printf(WARNING, "failed to set IPV6_V6ONLY socket option: %s", strerror(errno)); - } - - ret = bind(element->fd_, l->ai_addr, l->ai_addrlen); - if(ret) { - log_printf(ERROR, "Error on bind(): %s", strerror(errno)); - close(element->fd_); - free(element); - break; - } - - ret = listen(element->fd_, 0); - if(ret) { - log_printf(ERROR, "Error on listen(): %s", strerror(errno)); - close(element->fd_); - free(element); - break; - } - - char* ls = tcp_endpoint_to_string(element->local_end_); - char* rs = tcp_endpoint_to_string(element->remote_end_); - char* ss = tcp_endpoint_to_string(element->source_end_); - log_printf(NOTICE, "listening on: %s (remote: %s%s%s)", ls ? ls:"(null)", rs ? rs:"(null)", ss ? " with source " : "", ss ? ss : ""); - if(ls) free(ls); - if(rs) free(rs); - if(ss) free(ss); + element->state_ = NEW; + element->fd_ = -1; if(slist_add(list, element) == NULL) { - close(element->fd_); free(element); ret = -2; break; @@ -181,6 +138,83 @@ int listener_add(listeners_t* list, const char* laddr, resolv_type_t lrt, const return ret; } +int listener_activate(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) { + 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; + ret = -1; + break; + } + + int on = 1; + ret = setsockopt(l->fd_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if(ret) { + log_printf(ERROR, "Error on setsockopt(): %s", strerror(errno)); + l->state_ = ZOMBIE; + ret = -1; + break; + } + if(l->local_end_.addr_.ss_family == AF_INET6) { + 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; + ret = -1; + break; + } + + ret = listen(l->fd_, 0); + if(ret) { + log_printf(ERROR, "Error on listen(): %s", strerror(errno)); + l->state_ = ZOMBIE; + ret = -1; + break; + } + + 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_); + log_printf(NOTICE, "listening on: %s (remote: %s%s%s)", ls ? ls:"(null)", rs ? rs:"(null)", ss ? " with source " : "", ss ? ss : ""); + if(ls) free(ls); + if(rs) free(rs); + if(ss) free(ss); + } + tmp = tmp->next_; + } + + return ret; +} + +void listener_cleanup(listeners_t* list) +{ + if(!list) + return; + + slist_element_t* tmp = list->first_; + while(tmp) { + listener_t* l = (listener_t*)tmp->data_; + tmp = tmp->next_; + if(l && l->state_ == ZOMBIE) + slist_remove(list, l); + } +} + void listener_remove(listeners_t* list, int fd) { slist_remove(list, listener_find(list, fd)); @@ -213,9 +247,17 @@ void listener_print(listeners_t* list) if(l) { char* ls = tcp_endpoint_to_string(l->local_end_); char* rs = tcp_endpoint_to_string(l->remote_end_); - printf("listener #%d: %s -> %s\n", l->fd_, ls ? ls : "(null)", rs ? rs : "(null)"); + char* ss = tcp_endpoint_to_string(l->source_end_); + char state = '?'; + switch(l->state_) { + case NEW: state = 'n'; break; + case ACTIVE: state = 'a'; break; + case ZOMBIE: state = 'z'; break; + } + printf("listener [%c] #%d: %s -> %s%s%s\n", state, l->fd_, ls ? ls : "(null)", rs ? rs : "(null)", ss ? " with source " : "", ss ? ss : ""); if(ls) free(ls); if(rs) free(rs); + if(ss) free(ss); } tmp = tmp->next_; } @@ -229,7 +271,7 @@ void listener_read_fds(listeners_t* list, fd_set* set, int* max_fd) slist_element_t* tmp = list->first_; while(tmp) { listener_t* l = (listener_t*)tmp->data_; - if(l) { + if(l && l->state_ == ACTIVE) { FD_SET(l->fd_, set); *max_fd = *max_fd > l->fd_ ? *max_fd : l->fd_; } diff --git a/src/listener.h b/src/listener.h index 91b527f..2cb88d6 100644 --- a/src/listener.h +++ b/src/listener.h @@ -34,11 +34,15 @@ #include "tcp.h" #include "clients.h" +enum listener_state_enum { NEW, ACTIVE, ZOMBIE }; +typedef enum listener_state_enum listener_state_t; + typedef struct { int fd_; tcp_endpoint_t local_end_; tcp_endpoint_t remote_end_; tcp_endpoint_t source_end_; + listener_state_t state_; } listener_t; void listener_delete_element(void* e); @@ -48,6 +52,8 @@ typedef slist_t listeners_t; int listener_init(listeners_t* list); void listener_clear(listeners_t* list); int listener_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 listener_activate(listeners_t* list); +void listener_cleanup(listeners_t* list); void listener_remove(listeners_t* list, int fd); listener_t* listener_find(listeners_t* list, int fd); void listener_print(listeners_t* list); diff --git a/src/tcpproxy.c b/src/tcpproxy.c index 273aad0..58f9a4c 100644 --- a/src/tcpproxy.c +++ b/src/tcpproxy.c @@ -167,6 +167,14 @@ int main(int argc, char* argv[]) } } + ret = listener_activate(&listeners); + if(ret) { + listener_clear(&listeners); + options_clear(&opt); + log_close(); + exit(-1); + } + priv_info_t priv; if(opt.username_) if(priv_init(&priv, opt.username_, opt.groupname_)) { -- cgit v1.2.3