commit c37354b1e0adcb6d16929613e3bd4a509d487d2d Merge: 3fb0f0e 7f03b8e Author: Nick Mathewson nickm@torproject.org Date: Thu Jul 14 12:28:12 2011 -0400
Merge remote-tracking branch 'zwol/port-fixes'
Conflicts: src/network.c src/network.h src/protocol.c src/protocols/dummy.c src/protocols/obfs2.c src/socks.c src/socks.h src/util.c
Makefile.am | 34 +++--- configure.ac | 49 ++++----- m4/winsock.m4 | 56 ++++++++++ src/crypt.c | 220 ++++++++++++++++++++++++++++++++++++++ src/crypt.h | 64 +++++++++++ src/main.c | 7 +- src/network.c | 27 +++-- src/network.h | 19 ++-- src/protocol.c | 25 +++-- src/protocol.h | 35 +++--- src/protocols/dummy.c | 54 ++++------ src/protocols/dummy.h | 1 - src/protocols/obfs2.c | 84 ++++++--------- src/protocols/obfs2.h | 11 +- src/protocols/obfs2_crypt.c | 245 ------------------------------------------- src/protocols/obfs2_crypt.h | 61 ----------- src/sha256.c | 89 ++++------------ src/sha256.h | 18 +++ src/socks.c | 102 ++++++++---------- src/socks.h | 24 ++--- src/test/tinytest.c | 10 +- src/test/unittest.c | 3 +- src/test/unittest_crypt.c | 19 +--- src/test/unittest_obfs2.c | 133 ++++++++++++----------- src/test/unittest_socks.c | 16 ++-- src/util.c | 154 ++++++++++------------------ src/util.h | 83 +++++--------- 27 files changed, 772 insertions(+), 871 deletions(-)
diff --cc src/crypt.c index 0000000,43f6dfb..6be9726 mode 000000,100644..100644 --- a/src/crypt.c +++ b/src/crypt.c @@@ -1,0 -1,178 +1,220 @@@ + /* Copyright 2011 Nick Mathewson, George Kadianakis + See LICENSE for other credits and copying information + */ + + #define CRYPT_PRIVATE + #include "crypt.h" + + #include <assert.h> + #include <fcntl.h> + #include <stdlib.h> + #include <string.h> + #include <unistd.h> + + #include <openssl/opensslv.h> + #include <openssl/err.h> + #include <openssl/rand.h> + + #if OPENSSL_VERSION_NUMBER >= 0x0090800f + #define USE_OPENSSL_RANDPOLL 1 + #define USE_OPENSSL_SHA256 1 + #include <openssl/sha.h> + #else + #include "sha256.h" + #endif + ++/** ++ Initializes the obfs2 crypto subsystem. ++*/ + int + initialize_crypto(void) + { + ERR_load_crypto_strings(); + + #ifdef USE_OPENSSL_RANDPOLL + return RAND_poll() == 1 ? 0 : -1; + #else + /* XXX Or maybe fall back to the arc4random implementation in libevent2? */ + { + char buf[32]; + int fd, n; + fd = open("/dev/urandom", O_RDONLY); + if (fd == -1) { + perror("open"); + return -1; + } + n = read(fd, buf, sizeof(buf)); + if (n != sizeof(buf)) { + close(fd); + return -1; + } + RAND_seed(buf, sizeof(buf)); + close(fd); + return 0; + } + #endif + } + ++/** ++ Cleans up the obfs2 crypto subsystem. ++*/ + void + cleanup_crypto(void) + { + ERR_free_strings(); + } + + /* ===== + Digests + ===== */ + + #ifdef USE_OPENSSL_SHA256 + struct digest_t { + SHA256_CTX ctx; + }; ++ ++/** ++ Returns a new SHA256 digest container, or NULL on failure. ++*/ + digest_t * + digest_new(void) + { + digest_t *d = malloc(sizeof(digest_t)); ++ if (!d) ++ return NULL; + SHA256_Init(&d->ctx); + return d; + } ++ ++/** ++ Updates the contents of the SHA256 container 'd' with the first ++ 'len' bytes of 'buf'. ++*/ + void + digest_update(digest_t *d, const uchar *buf, size_t len) + { + SHA256_Update(&d->ctx, buf, len); + } ++ ++/** ++ Returns the digest stored in 'd' into 'buf' of length 'len'. ++*/ + size_t + digest_getdigest(digest_t *d, uchar *buf, size_t len) + { + uchar tmp[SHA256_LENGTH]; + int n = 32; + SHA256_Final(tmp, &d->ctx); + if (len < 32) + n = len; + memcpy(buf, tmp, n); + memset(tmp, 0, sizeof(tmp)); + return n; + } + #else + struct digest_t { + sha256_state ctx; + }; + digest_t * + digest_new(void) + { + digest_t *d = malloc(sizeof(digest_t)); ++ if (!d) ++ return NULL; + sha256_init(&d->ctx); + return d; + } + void + digest_update(digest_t *d, const uchar *buf, size_t len) + { + sha256_process(&d->ctx, buf, len); + } + size_t + digest_getdigest(digest_t *d, uchar *buf, size_t len) + { + uchar tmp[SHA256_LENGTH]; + int n = 32; + sha256_done(&d->ctx, tmp); + if (len < 32) + n = len; + memcpy(buf, tmp, n); + memset(tmp, 0, sizeof(tmp)); + return n; + } + #endif + + void + digest_free(digest_t *d) + { + memset(d, 0, sizeof(digest_t)); + free(d); + } + + /* ===== + Stream crypto + ===== */ + ++/** ++ Initializes the AES cipher with 'key'. ++*/ + crypt_t * + crypt_new(const uchar *key, size_t keylen) + { + crypt_t *k; + if (keylen < AES_BLOCK_SIZE) + return NULL; + + k = calloc(1, sizeof(crypt_t)); + if (k == NULL) + return NULL; + + AES_set_encrypt_key(key, 128, &k->key); + + return k; + } ++ ++/** ++ Sets the IV of 'key' to 'iv'. ++*/ + void + crypt_set_iv(crypt_t *key, const uchar *iv, size_t ivlen) + { + assert(ivlen == sizeof(key->ivec)); + memcpy(key->ivec, iv, ivlen); + } ++ ++/* ++ In-place encrypts 'buf' with 'key'. ++*/ + void + stream_crypt(crypt_t *key, uchar *buf, size_t len) + { + AES_ctr128_encrypt(buf, buf, /* XXX make sure this is okay to do. */ + len, + &key->key, key->ivec, key->ecount_buf, + &key->pos); + } ++ ++/** ++ Deallocates memory space of 'key'. ++*/ + void + crypt_free(crypt_t *key) + { + memset(key, 0, sizeof(key)); + free(key); + } + + /* ===== + PRNG + ===== */ + ++/** ++ Fills 'buf' with 'buflen' random bytes and returns 0 on success. ++ Returns -1 on failure. ++*/ + int + random_bytes(uchar *buf, size_t buflen) + { + return RAND_bytes(buf, buflen) == 1 ? 0 : -1; + } diff --cc src/main.c index ee2a802,8788067..48d0d37 --- a/src/main.c +++ b/src/main.c @@@ -402,12 -358,11 +398,11 @@@ main(int argc, const char **argv
log_info("Exiting.");
- if (close_obfsproxy_logfile() < 0) - printf("Failed closing logfile!\n"); + close_obfsproxy_logfile();
+ free_all_listeners(); /* free all listeners in our listener dll */ + /* We are exiting. Clean everything. */ - for (h=0;h<n_listeners;h++) - listener_free(listeners[h]); free(protocol_options); free(n_options_array); free(protocols); diff --cc src/network.c index 6d1d211,081af6e..ea06bc2 --- a/src/network.c +++ b/src/network.c @@@ -4,13 -4,13 +4,14 @@@
#define NETWORK_PRIVATE #include "network.h" + #include "util.h" ++#include "main.h" #include "socks.h" #include "protocol.h" - #include "socks.h" - #include "main.h"
#include <assert.h> + #include <errno.h> #include <stdlib.h> #include <string.h>
@@@ -18,14 -20,10 +21,14 @@@ #include <event2/util.h>
#ifdef _WIN32 - #include <WS2tcpip.h> + #include <ws2tcpip.h> /* socklen_t */ #endif
+/** Doubly linked list holding all our listeners. */ +static dll_t listener_list = DLL_INIT(); + struct listener_t { + dll_node_t dll_node; struct evconnlistener *listener; protocol_params_t *proto_params; }; @@@ -55,50 -43,10 +58,50 @@@ static void input_event_cb(struct buffe static void output_event_cb(struct bufferevent *bev, short what, void *arg);
/** - This function sets up the protocol defined by 'options' and - attempts to bind a new listener for it. + 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. + + (Only called by signal handlers) +*/ +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(); + return; + } +} + +/** + Closes all open connections. +*/ +static void +close_all_connections(void) +{ + /** Traverse the dll and close all connections */ + while (conn_list.head) { + conn_t *conn = UPCAST(conn_t, dll_node, conn_list.head); + conn_free(conn); /* removes it */ + } + assert(!n_connections); +} +/** + This function spawns a listener according to the 'proto_params'.
- Returns the listener on success and NULL on fail. + Returns the listener on success, NULL on fail. */ listener_t * listener_new(struct event_base *base, diff --cc src/network.h index dc6b583,7bc4811..ad54686 --- a/src/network.h +++ b/src/network.h @@@ -45,13 -33,13 +33,20 @@@ typedef struct listener_t listener_t listener_t *listener_new(struct event_base *base, struct protocol_params_t *params); void listener_free(listener_t *listener); +void free_all_listeners(void); + +void start_shutdown(int barbaric);
#ifdef NETWORK_PRIVATE ++ ++#include "util.h" ++ + struct bufferevent; + struct socks_state_t; + struct protocol_t; + typedef struct conn_t { + dll_node_t dll_node; struct socks_state_t *socks_state; struct protocol_t *proto; /* ASN Do we like this here? We probably don't. But it's so convenient!! So convenient! */ diff --cc src/protocol.c index 0845c11,557a5cc..282db10 --- a/src/protocol.c +++ b/src/protocol.c @@@ -40,8 -38,9 +38,9 @@@ set_up_protocol(int n_options, char **o }
/** - This function creates a protocol object. - It's called once per connection. - It creates a new protocol_t structure and fills it's vtable etc. + This function is called once per connection and creates a protocol + object to be used during the session. ++ Return a 'protocol_t' if successful, NULL otherwise. */ struct protocol_t * diff --cc src/protocols/dummy.c index eaf921c,7a32b47..3b31e12 --- a/src/protocols/dummy.c +++ b/src/protocols/dummy.c @@@ -54,20 -49,15 +50,18 @@@ dummy_init(int n_options, char **option vtable->send = dummy_send; vtable->recv = dummy_recv;
- return 1; + return 0; }
+/** + Helper: Parses 'options' and fills 'params'. +*/ static int - parse_and_set_options(int n_options, char **options, + parse_and_set_options(int n_options, char **options, struct protocol_params_t *params) { - struct sockaddr_storage ss_listen; - int sl_listen; const char* defport; - + if (n_options != 3) return -1;
@@@ -91,18 -82,10 +86,13 @@@ log_warn("addr"); return -1; } - assert(sl_listen <= sizeof(struct sockaddr_storage)); - struct sockaddr *sa_listen=NULL; - sa_listen = (struct sockaddr *)&ss_listen; - memcpy(¶ms->on_address, sa_listen, sl_listen); - params->on_address_len = sl_listen; - - return 0; + + return 1; }
+/** + Prints dummy protocol usage information. +*/ static void usage(void) { @@@ -115,13 -98,8 +105,13 @@@ "Example:\n" "\tobfsproxy dummy socks 127.0.0.1:5000\n"); } - + +/* + This is called everytime we get a connection for the dummy + protocol. - + + It sets up the protocol vtable in 'proto_struct'. +*/ void * dummy_new(struct protocol_t *proto_struct, struct protocol_params_t *params) diff --cc src/protocols/obfs2.c index f9beee5,c2169a1..27e9272 --- a/src/protocols/obfs2.c +++ b/src/protocols/obfs2.c @@@ -58,18 -55,13 +55,16 @@@ obfs2_init(int n_options, char **option return -1; }
- return 1; + return 0; }
+/** + Helper: Parses 'options' and fills 'params'. +*/ int - parse_and_set_options(int n_options, char **options, + parse_and_set_options(int n_options, char **options, struct protocol_params_t *params) { - struct sockaddr_storage ss_listen; - int sl_listen; int got_dest=0; int got_ss=0; const char* defport; @@@ -192,8 -174,8 +177,8 @@@ set_up_vtable(void vtable->handshake = obfs2_send_initial_message; vtable->send = obfs2_send; vtable->recv = obfs2_recv; - + - return 1; + return 0; }
/** Return true iff the OBFUSCATE_SEED_LENGTH-byte seed in 'seed' is nonzero */ diff --cc src/socks.c index f175a8e,e6d72fd..e89812f --- a/src/socks.c +++ b/src/socks.c @@@ -50,16 -40,8 +40,13 @@@ */
- static enum socks_ret socks5_do_negotiation(struct evbuffer *dest, - unsigned int neg_was_success); - typedef unsigned char uchar;
+/** + Creates a new SOCKS state. + + Returns a 'socks_state_t' on success, NULL on fail. +*/ socks_state_t * socks_state_new(void) { @@@ -123,17 -102,19 +110,16 @@@ socks_errno_to_reply(socks_state_t *sta #undef ERR
/** - Takes a command request from 'source', it evaluates it and if it's - legit it parses it into 'parsereq'. - - It returns '1' if everything went fine. - It returns '0' if we need more data from the client. - It returns '-1' if we didn't like something. - It returns '-2' if the client asked for something else than CONNECT. - If that's the case we should send a reply back to the client - telling him that we don't support it. - - Disclaimer: This is just a temporary documentation. - - Client Request (Client -> Server) + Takes a SOCKS5 command request from 'source', it evaluates it and + if it's legit it parses it into 'parsereq'. + + It returns SOCKS_GOOD if everything went fine. + It returns SOCKS_INCOMPLETE if we need more data from the client. + It returns SOCKS_BROKEN if we didn't like something. + It returns SOCKS_CMD_NOT_CONNECT if the client asked for something + else other than CONNECT. If that's the case we should send a reply + back to the client telling him that we don't support it. + - Client Request (Client -> Server) */ enum socks_ret socks5_handle_request(struct evbuffer *source, struct parsereq *parsereq) @@@ -292,8 -274,35 +280,33 @@@ socks5_send_reply(struct evbuffer *repl }
/** + This function sends a method negotiation reply to 'dest'. + If 'neg_was_success' is true send a positive response, + otherwise send a negative one. + It returns -1 if no suitable negotiation methods were found, + or if there was an error during replying. + + Method Negotiation Reply (Server -> Client): + | version | method selected | + 1b 1b + */ + static enum socks_ret + socks5_do_negotiation(struct evbuffer *dest, unsigned int neg_was_success) + { + uchar reply[2]; + reply[0] = SOCKS5_VERSION; + + reply[1] = neg_was_success ? SOCKS5_METHOD_NOAUTH : SOCKS5_METHOD_FAIL; + + if (evbuffer_add(dest, reply, 2) == -1 || !neg_was_success) + return SOCKS_BROKEN; + else + return SOCKS_GOOD; + } + + /** This function handles the initial SOCKS5 packet in 'source' sent by - the client, which negotiates the version and method of SOCKS. If + the client which negotiates the version and method of SOCKS. If the packet is actually valid, we reply to 'dest'.
Method Negotiation Packet (Client -> Server): @@@ -338,39 -347,7 +351,16 @@@ socks5_handle_negotiation(struct evbuff return socks5_do_negotiation(dest,found_noauth); }
-/* rename to socks4_handle_request or something. */ +/** - This function sends a method negotiation reply to 'dest'. - If 'neg_was_success' is true send a positive response, - otherwise send a negative one. - It returns -1 if no suitable negotiation methods were found, - or if there was an error during replying. - - Method Negotiation Reply (Server -> Client): - | version | method selected | - 1b 1b - */ - static enum socks_ret - socks5_do_negotiation(struct evbuffer *dest, unsigned int neg_was_success) - { - uchar reply[2]; - reply[0] = SOCKS5_VERSION; - - reply[1] = neg_was_success ? SOCKS5_METHOD_NOAUTH : SOCKS5_METHOD_FAIL; - - if (evbuffer_add(dest, reply, 2) == -1 || !neg_was_success) - return SOCKS_BROKEN; - else - return SOCKS_GOOD; - } - - /** + Takes a SOCKS4/SOCKS4a command request from 'source', it evaluates + it and if it's legit it parses it into 'parsereq'. + + It returns SOCKS_GOOD if everything went fine. + It returns SOCKS_INCOMPLETE if we need more data from the client. + It returns SOCKS_BROKEN if we didn't like something. +*/ ++ ++/* XXXX rename to socks4_handle_request or something. */ enum socks_ret socks4_read_request(struct evbuffer *source, socks_state_t *state) { diff --cc src/socks.h index 6ae69e9,ef7b953..e2c20b5 --- a/src/socks.h +++ b/src/socks.h @@@ -43,11 -39,11 +39,10 @@@ int socks_state_get_address(const socks const char **addr_out, int *port_out); int socks_state_set_address(socks_state_t *state, const struct sockaddr *sa); -int socks_send_reply(socks_state_t *state, struct evbuffer *dest, int error); -int socks5_send_reply(struct evbuffer *reply_dest, - socks_state_t *state, int status); - +void socks_send_reply(socks_state_t *state, struct evbuffer *dest, int error); - void socks5_send_reply(struct evbuffer *reply_dest, ++void socks5_send_reply(struct evbuffer *reply_dest, + socks_state_t *state, int status);
- #define SOCKS5_SUCCESS 0x00 #define SOCKS5_FAILED_GENERAL 0x01 #define SOCKS5_FAILED_NOTALLOWED 0x02 @@@ -106,11 -102,16 +101,14 @@@ struct socks_state_t
enum socks_ret socks5_handle_negotiation(struct evbuffer *source, struct evbuffer *dest, socks_state_t *state); -int socks5_send_reply(struct evbuffer *reply_dest, socks_state_t *state, - int status); -enum socks_ret socks5_handle_request(struct evbuffer *source, - struct parsereq *parsereq); +enum socks_ret socks5_handle_request(struct evbuffer *source, struct parsereq *parsereq); + - enum socks_ret socks4_read_request(struct evbuffer *source, socks_state_t *state); - void socks4_send_reply(struct evbuffer *dest, + + enum socks_ret socks4_read_request(struct evbuffer *source, + socks_state_t *state); -int socks4_send_reply(struct evbuffer *dest, - socks_state_t *state, int status); ++void socks4_send_reply(struct evbuffer *dest, + socks_state_t *state, int status); - #endif
- #endif + #endif /* SOCKS_PRIVATE */ + + #endif /* socks.h */ diff --cc src/test/unittest_obfs2.c index 27395df,a7c8112..0b2054b --- a/src/test/unittest_obfs2.c +++ b/src/test/unittest_obfs2.c @@@ -31,10 -30,10 +30,10 @@@ test_proto_option_parsing(void *data log_set_method(LOG_METHOD_NULL, NULL);
tt_assert(set_up_protocol(n_options, options, - proto_params) == 1); + proto_params) == 0);
/** two --dest. */ - char *options2[] = {"obfs2", "--dest=127.0.0.1:5555", "--dest=a", + char *options2[] = {"obfs2", "--dest=127.0.0.1:5555", "--dest=a", "server", "127.0.0.1:5552"}; n_options = 5;
diff --cc src/util.c index 4517f95,d54c67f..cab4bf1 --- a/src/util.c +++ b/src/util.c @@@ -159,120 -134,8 +145,120 @@@ obfs_vsnprintf(char *str, size_t size, return r; }
+/************************ Doubly Linked List (DLL) ******************/ + +/** + Insert 'new_node' after 'node' in the doubly linked list 'list'. +*/ +static void +dll_insert_after(dll_t *list, dll_node_t *node, dll_node_t *new_node) +{ + assert(node); + assert(new_node); + + if (!list) + return; + + new_node->prev = node; + new_node->next = node->next; + if (!node->next) + list->tail = new_node; + else + node->next->prev = new_node; + node->next = new_node; +} + +/** + Insert 'new_node' before 'node' in the doubly linked list 'list'. +*/ +static void +dll_insert_before(dll_t *list, dll_node_t *node, dll_node_t *new_node) +{ + assert(node); + assert(new_node); + + if (!list) + return; + + new_node->prev = node->prev; + new_node->next = node; + if (!node->prev) + list->head = new_node; + else + node->prev->next = new_node; + node->prev = new_node; +} + +/** Initialize <b>list</b> as an empty list. */ +void +dll_init(dll_t *list) +{ + list->head = list->tail = NULL; +} + +/** + Insert 'node' in the beginning of the doubly linked 'list'. +*/ +static void +dll_insert_beginning(dll_t *list, dll_node_t *node) +{ + assert(node); + + if (!list) + return; + + if (!list->head) { + list->head = node; + list->tail = node; + node->prev = NULL; + node->next = NULL; + } else { + dll_insert_before(list, list->head, node); + } +} + +/** + Appends 'data' to the end of the doubly linked 'list'. + Returns 1 on success, -1 on fail. +*/ +int +dll_append(dll_t *list, dll_node_t *node) +{ + assert(list); + assert(node); + + if (!list->tail) + dll_insert_beginning(list, node); + else + dll_insert_after(list, list->tail, node); + + return 1; +} + +/** + Removes 'node' from the doubly linked list 'list'. + It frees the list node, but leaves its data intact. +*/ +void +dll_remove(dll_t *list, dll_node_t *node) +{ + assert(node); + + if (!list) + return; + + if (!node->prev) + list->head = node->next; + else + node->prev->next = node->next; + if (!node->next) + list->tail = node->prev; + else + node->next->prev = node->prev; +} + /************************ Logging Subsystem *************************/ - /** The code of this section was to a great extend shamelessly copied + /** The code of this section was to a great extent shamelessly copied off tor. It's basicaly a stripped down version of tor's logging system. Thank you tor. */
@@@ -331,27 -200,8 +323,8 @@@ sev_is_valid(int severity }
/** - Sets the global logging 'method' and also sets and open the logfile - 'filename' in case we want to log into a file. - It returns 0 on success and -1 on fail. - */ - int - log_set_method(int method, const char *filename) - { - - logging_method = method; - if (method == LOG_METHOD_FILE) { - if (open_and_set_obfsproxy_logfile(filename) < 0) - return -1; - if (write_logfile_prologue(logging_logfile) < 0) - return -1; - } - return 0; - } - - /** Helper: Opens 'filename' and sets it as the obfsproxy logfile. - On success it returns 1, on fail it returns -1. + On success it returns 0, on fail it returns -1. */ static int open_and_set_obfsproxy_logfile(const char *filename) @@@ -381,17 -228,14 +351,16 @@@ close_obfsproxy_logfile(void }
/** - Writes a small prologue in the logfile 'fd' to separate log - instances. + Writes a small prologue in the logfile 'fd' that mentions the + obfsproxy version and helps separate log instances. + + Returns 0 on success, -1 on failure. */ static int - write_logfile_prologue(int logfile) { - char buf[256]; - if (compose_logfile_prologue(buf, sizeof(buf)) < 0) - return -1; - if (write(logfile, buf, strlen(buf)) < 0) + write_logfile_prologue(int logfile) + { + static const char prologue[] = "\nBrand new obfsproxy log:\n"; + if (write(logfile, prologue, strlen(prologue)) != strlen(prologue)) return -1; return 0; } diff --cc src/util.h index 7e73cee,f52f335..ff9df22 --- a/src/util.h +++ b/src/util.h @@@ -50,60 -35,8 +35,36 @@@ int obfs_snprintf(char *str, size_t siz const char *format, ...) __attribute__((format(printf, 3, 4)));
+/***** Doubly Linked List stuff. *****/ + +#define OFFSETOF(container_type, element) \ + (((char*)&((container_type*)0)->element) - ((char*) ((container_type*)0))) + +#define UPCAST(container_type, element, ptr) \ + (container_type*) ( \ + ((char*)ptr) - OFFSETOF(container_type, element) \ + ) + + +/** A doubly linked list node. + [algorithms ripped off Wikipedia (Doubly_linked_list) ] */ +typedef struct dll_node_t { + struct dll_node_t *next, *prev; +} dll_node_t; + +/** A doubly linked list. */ +typedef struct dll_t { + struct dll_node_t *head; + struct dll_node_t *tail; +} dll_t; + +void dll_init(dll_t *list); +int dll_append(dll_t *list, dll_node_t *node); +void dll_remove(dll_t *list, dll_node_t *node); +#define DLL_INIT() { NULL, NULL } + /***** Logging subsystem stuff. *****/
- void log_fn(int severity, const char *format, ...) - __attribute__((format(printf, 2, 3))); - int log_set_method(int method, const char *filename); - int log_set_min_severity(const char* sev_string); - int close_obfsproxy_logfile(void); - - #ifdef __GNUC__ - #define log_info(args...) log_fn(LOG_SEV_INFO, args) - #define log_warn(args...) log_fn(LOG_SEV_WARN, args) - #define log_debug(args...) log_fn(LOG_SEV_DEBUG, args) - #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - #define log_info(...) log_fn(LOG_SEV_INFO, __VA_ARGS__) - #define log_warn(...) log_fn(LOG_SEV_WARN, __VA_ARGS__) - #define log_debug(...) log_fn(LOG_SEV_DEBUG, __VA_ARGS__) - #else - #define NEED_LOG_WRAPPERS - void log_info(const char *format, ...) - __attribute__((format(printf, 1, 2))); - void log_warn(const char *format, ...) - __attribute__((format(printf, 1, 2))); - void log_debug(const char *format, ...) - __attribute__((format(printf, 1, 2))); - #endif - /** Logging methods */
/** Spit log messages on stdout. */
tor-commits@lists.torproject.org