[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [obfsproxy/master] We now handle signals according to 180-pluggable-transport.txt.
commit 874b61dfcd82c05a518d676f135ea52c7a190b78
Author: George Kadianakis <desnacked@xxxxxxxxx>
Date: Tue Jun 28 03:35:10 2011 +0200
We now handle signals according to 180-pluggable-transport.txt.
---
src/main.c | 70 ++++++++++++++++++------
src/main.h | 10 ++++
src/network.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
src/network.h | 2 +
4 files changed, 227 insertions(+), 18 deletions(-)
diff --git a/src/main.c b/src/main.c
index a8347c2..81e8c31 100644
--- a/src/main.c
+++ b/src/main.c
@@ -33,6 +33,8 @@ static int handle_obfsproxy_args(const char **argv);
extern char *supported_protocols[];
extern int n_supported_protocols;
+static struct event_base *the_event_base=NULL;
+
/**
Prints the obfsproxy usage instructions then exits.
*/
@@ -56,17 +58,46 @@ usage(void)
}
/**
- This is called on SIGINT. It kills the event base loop, so that we
- start exiting.
+ This is called when we receive a signal.
+ It figures out the signal type and acts accordingly.
+
+ Current behavior:
+ SIGINT: On a single SIGINT we stop accepting new connections,
+ keep the already existing connections open,
+ and terminate when they all close.
+ On a second SIGINT we shut down immediately but cleanly.
+ SIGTERM: Shut down obfsproxy immediately but cleanly.
*/
static void
handle_signal_cb(evutil_socket_t fd, short what, void *arg)
{
- struct event_base *base = arg;
- /* int signum = (int) fd; */
-
- log_info("Caught SIGINT.");
- event_base_loopexit(base, NULL);
+ int signum = (int) fd;
+ static int got_sigint=0;
+
+ switch (signum) {
+ case SIGINT:
+ if (!got_sigint) {
+ start_shutdown(0);
+ got_sigint++;
+ } else {
+ start_shutdown(1);
+ }
+ break;
+ case SIGTERM:
+ start_shutdown(1);
+ break;
+ }
+}
+
+/**
+ Stops obfsproxy's event loop.
+
+ Final cleanup happens in main().
+*/
+void
+finish_shutdown(void)
+{
+ event_base_loopexit(the_event_base, NULL);
}
/**
@@ -159,8 +190,8 @@ handle_obfsproxy_args(const char **argv)
int
main(int argc, const char **argv)
{
- struct event_base *base;
- struct event *sigevent;
+ struct event *sig_int;
+ struct event *sig_term;
/* Yes, these are three stars right there. This is an array of
arrays of strings! Every element of the array is an array of
@@ -290,14 +321,14 @@ main(int argc, const char **argv)
#endif
/* Initialize libevent */
- base = event_base_new();
- if (!base) {
+ the_event_base = event_base_new();
+ if (!the_event_base) {
log_warn("Can't initialize Libevent; failing");
return 1;
}
/* ASN should this happen only when SOCKS is enabled? */
- if (init_evdns_base(base) < 0) {
+ if (init_evdns_base(the_event_base) < 0) {
log_warn("Can't initialize evdns; failing");
return 1;
}
@@ -306,9 +337,11 @@ main(int argc, const char **argv)
#ifdef SIGPIPE
signal(SIGPIPE, SIG_IGN);
#endif
- sigevent = evsignal_new(base, SIGINT,
- handle_signal_cb, (void*) base);
- if (event_add(sigevent,NULL)) {
+ sig_int = evsignal_new(the_event_base, SIGINT,
+ handle_signal_cb, NULL);
+ sig_term = evsignal_new(the_event_base, SIGTERM,
+ handle_signal_cb, NULL);
+ if (event_add(sig_int,NULL) || event_add(sig_term,NULL)) {
log_warn("We can't even add events for signals! Exiting.");
return 1;
}
@@ -337,7 +370,7 @@ main(int argc, const char **argv)
continue;
}
- temp_listener = listener_new(base, proto_params);
+ temp_listener = listener_new(the_event_base, proto_params);
/** Free the space allocated for this protocol's options. */
free(protocol_options[h]);
@@ -358,7 +391,7 @@ main(int argc, const char **argv)
/* run the event loop if at least a listener was created. */
if (n_listeners)
- event_base_dispatch(base);
+ event_base_dispatch(the_event_base);
log_info("Exiting.");
@@ -368,6 +401,9 @@ main(int argc, const char **argv)
/* We are exiting. Clean everything. */
for (h=0;h<n_listeners;h++)
listener_free(listeners[h]);
+ if (listeners)
+ free(listeners);
+
free(protocol_options);
free(n_options_array);
free(protocols);
diff --git a/src/main.h b/src/main.h
new file mode 100644
index 0000000..8814499
--- /dev/null
+++ b/src/main.h
@@ -0,0 +1,10 @@
+/* Copyright 2011 Nick Mathewson, George Kadianakis
+ See LICENSE for other credits and copying information
+*/
+
+#ifndef MAIN_H
+#define MAIN_H
+
+void finish_shutdown(void);
+
+#endif
diff --git a/src/network.c b/src/network.c
index ed78104..fc53564 100644
--- a/src/network.c
+++ b/src/network.c
@@ -8,6 +8,7 @@
#include "socks.h"
#include "protocol.h"
#include "socks.h"
+#include "main.h"
#include <assert.h>
#include <stdlib.h>
@@ -25,10 +26,31 @@ struct listener_t {
protocol_params_t *proto_params;
};
+/**
+ Linked list carrying all currently active connections.
+ [linked list code was copied off tor.]
+*/
+typedef struct conn_list_t {
+ conn_t *conn;
+ struct conn_list_t *next;
+} conn_list_t;
+
+/** First and last elements in the linked list of active
+ connections. */
+static conn_list_t *cl_list=NULL;
+static conn_list_t *cl_tail=NULL;
+/** Active connection counter */
+static int n_connections=0;
+
+/** Flag toggled when obfsproxy is shutting down. It blocks new
+ connections and shutdowns when the last connection is closed. */
+static int shutting_down=0;
+
static void simple_listener_cb(struct evconnlistener *evcl,
evutil_socket_t fd, struct sockaddr *sourceaddr, int socklen, void *arg);
static void conn_free(conn_t *conn);
+static void close_all_connections(void);
static void close_conn_on_flush(struct bufferevent *bev, void *arg);
static void plaintext_read_cb(struct bufferevent *bev, void *arg);
@@ -40,6 +62,122 @@ static void input_event_cb(struct bufferevent *bev, short what, void *arg);
static void output_event_cb(struct bufferevent *bev, short what, void *arg);
/**
+ Puts obfsproxy's networking subsystem on "closing time" mode. This
+ means that we stop accepting new connections and we shutdown when
+ the last connection is closed.
+
+ If 'barbaric' is set, we forcefully close all open connections and
+ finish shutdown.
+*/
+void
+start_shutdown(int barbaric)
+{
+ if (!shutting_down)
+ shutting_down=1;
+
+ if (!n_connections) {
+ finish_shutdown();
+ return;
+ }
+
+ if (barbaric) {
+ if (n_connections)
+ close_all_connections();
+ finish_shutdown();
+ return;
+ }
+}
+
+/**
+ Closes all open connections.
+*/
+static void
+close_all_connections(void)
+{
+ conn_t *conn;
+
+ while (cl_list) {
+ assert(cl_list->conn);
+ assert(n_connections > 0);
+ conn = cl_list->conn;
+ conn_free(conn);
+ }
+}
+
+/**
+ Places 'conn' to the end of the linked list of active connections.
+ Returns 1 on success, -1 on fail.
+*/
+static int
+cl_add(conn_t *conn)
+{
+ conn_list_t *cl;
+
+ cl = calloc(1, sizeof(conn_list_t));
+ if (!cl)
+ return -1;
+
+ cl->conn = conn;
+
+ if (!cl_tail) {
+ assert(!cl_list);
+ assert(!n_connections);
+ cl_list=cl;
+ cl_tail=cl;
+ } else {
+ assert(cl_list);
+ assert(!cl_tail->next);
+ cl_tail->next = cl;
+ cl_tail = cl;
+ }
+
+ n_connections++;
+
+ return 1;
+}
+
+/**
+ Removes 'conn' from the linked list of connections:
+ It frees the list node carrying 'conn', but leaves 'conn' itself intact.
+*/
+static void
+cl_remove(conn_t *conn)
+{
+ conn_list_t *tmpo, *victim;
+
+ if (!cl_list)
+ return; /* nothing here. */
+
+ /* first check to see if it's the first entry */
+ tmpo = cl_list;
+ if (tmpo->conn == conn) {
+ /* it's the first one. remove it from the list. */
+ cl_list = tmpo->next;
+ if (!cl_list)
+ cl_tail = NULL;
+ n_connections--;
+ victim = tmpo;
+ } else { /* we need to hunt through the rest of the list */
+ for ( ;tmpo->next && tmpo->next->conn != conn; tmpo=tmpo->next) ;
+ if (!tmpo->next) {
+ return;
+ }
+ /* now we know tmpo->next->conn == conn */
+ victim = tmpo->next;
+ tmpo->next = victim->next;
+ if (cl_tail == victim)
+ cl_tail = tmpo;
+ n_connections--;
+ }
+
+ assert(n_connections>=0);
+
+ /* now victim points to the element that needs to be removed */
+ free(victim);
+ victim = NULL;
+}
+
+/**
This function sets up the protocol defined by 'options' and
attempts to bind a new listener for it.
@@ -91,13 +229,19 @@ static void
simple_listener_cb(struct evconnlistener *evcl,
evutil_socket_t fd, struct sockaddr *sourceaddr, int socklen, void *arg)
{
+ if (shutting_down) {
+ if (fd >= 0)
+ evutil_closesocket(fd);
+ return ;
+ }
+
listener_t *lsn = arg;
struct event_base *base;
conn_t *conn = calloc(1, sizeof(conn_t));
if (!conn)
goto err;
- log_debug("Got a connection");
+ log_debug("Got a connection attempt.");
conn->mode = lsn->proto_params->mode;
@@ -170,6 +314,13 @@ simple_listener_cb(struct evconnlistener *evcl,
bufferevent_enable(conn->output, EV_READ|EV_WRITE);
}
+ /* add conn to the linked list of connections */
+ if (cl_add(conn)<0)
+ goto err;
+
+ log_debug("Connection setup completed. "
+ "We currently have %d connections!", n_connections);
+
return;
err:
if (conn)
@@ -190,7 +341,17 @@ conn_free(conn_t *conn)
if (conn->output)
bufferevent_free(conn->output);
memset(conn, 0x99, sizeof(conn_t));
+ /* remove conn from the linked list of connections */
+ cl_remove(conn);
free(conn);
+
+ log_debug("Connection destroyed. "
+ "We currently have %d connections!", n_connections);
+
+ /** If this was the last connection AND we are shutting down,
+ finish shutdown. */
+ if (!n_connections && shutting_down)
+ finish_shutdown();
}
static void
diff --git a/src/network.h b/src/network.h
index 2a1daeb..28a0d7d 100644
--- a/src/network.h
+++ b/src/network.h
@@ -47,6 +47,8 @@ listener_t *listener_new(struct event_base *base,
struct protocol_params_t *params);
void listener_free(listener_t *listener);
+void start_shutdown(int barbaric);
+
#ifdef NETWORK_PRIVATE
typedef struct conn_t {
struct socks_state_t *socks_state;
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits