summaryrefslogtreecommitdiff
path: root/src/listener.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/listener.c')
-rw-r--r--src/listener.c140
1 files changed, 91 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_;
}