summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Pointner <equinox@spreadspace.org>2010-12-09 20:35:42 +0000
committerChristian Pointner <equinox@spreadspace.org>2010-12-09 20:35:42 +0000
commit8cd030696dd1bf0864443b4c745063821d9cd76c (patch)
tree6b52678b50bcf7bcd149c7e5858e9c9e5cefc30b
parentadvanced new lines (diff)
introduced listener states
git-svn-id: https://svn.spreadspace.org/tcpproxy/trunk@41 e61f0598-a718-4e21-a8f0-0aadfa62ad6b
-rw-r--r--src/listener.c140
-rw-r--r--src/listener.h6
-rw-r--r--src/tcpproxy.c8
3 files changed, 105 insertions, 49 deletions
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_)) {