[tor-commits] [obfsproxy/master] Protocol API sanitization

nickm at torproject.org nickm at torproject.org
Fri Sep 9 17:08:55 UTC 2011


commit 4896bd7e4609f74780dbe047ac568283848d06f2
Author: Zack Weinberg <zackw at panix.com>
Date:   Tue Jul 12 17:04:21 2011 -0700

    Protocol API sanitization
    
    * Embed the protocol name in the protocol vtable
    * Protocol vtables are now statically allocated
    * Return objects rather than error codes when that makes sense
    * Use pseudo-inheritance rather than void pointers for protocol-
      specific, per-connection state
    * Tidy up the protocol.h upward interface a little
    * Constification
---
 src/main.c                |   47 +++----
 src/network.c             |    2 +-
 src/protocol.c            |  109 +++++++-------
 src/protocol.h            |  120 +++++++++------
 src/protocols/dummy.c     |  104 +++++++-------
 src/protocols/dummy.h     |   12 +-
 src/protocols/obfs2.c     |  212 ++++++++++-----------------
 src/protocols/obfs2.h     |   29 ++--
 src/test/unittest_obfs2.c |  363 +++++++++++++++++++--------------------------
 9 files changed, 448 insertions(+), 550 deletions(-)

diff --git a/src/main.c b/src/main.c
index 48d0d37..f41d502 100644
--- a/src/main.c
+++ b/src/main.c
@@ -25,10 +25,6 @@
 static void usage(void) __attribute__((noreturn));
 static int handle_obfsproxy_args(const char **argv);
 
-/* protocol.c */
-extern char *supported_protocols[];
-extern int n_supported_protocols;
-
 static struct event_base *the_event_base=NULL;
 
 /**
@@ -44,7 +40,7 @@ usage(void)
           SEPARATOR);
   /* this is awful. */
   for (i=0;i<n_supported_protocols;i++)
-    fprintf(stderr,"[%s] ", supported_protocols[i]);
+    fprintf(stderr,"[%s] ", supported_protocols[i]->name);
   fprintf(stderr, "\n* Available arguments:\n"
           "--log-file=<file> ~ set logfile\n"
           "--log-min-severity=warn|info|debug ~ set minimum logging severity\n"
@@ -93,7 +89,7 @@ handle_signal_cb(evutil_socket_t fd, short what, void *arg)
    Stops obfsproxy's event loop.
 
    Final cleanup happens in main().
-*/ 
+*/
 void
 finish_shutdown(void)
 {
@@ -105,8 +101,8 @@ finish_shutdown(void)
    and writes them in 'options_string'.
 */
 static void
-populate_options(char **options_string, 
-                 const char **argv, int n_options) 
+populate_options(char **options_string,
+                 const char **argv, int n_options)
 {
   int g;
   for (g=0;g<=n_options-1;g++)
@@ -114,14 +110,14 @@ populate_options(char **options_string,
 }
 
 /**
-   Return 0 if 'name' is the nmae of a supported protocol, otherwise
+   Return 0 if 'name' is the name of a supported protocol, otherwise
    return -1.
 */
 static int
 is_supported_protocol(const char *name) {
   int f;
   for (f=0;f<n_supported_protocols;f++) {
-    if (!strcmp(name,supported_protocols[f])) 
+    if (!strcmp(name,supported_protocols[f]->name))
       return 0;
   }
   return -1;
@@ -130,7 +126,7 @@ is_supported_protocol(const char *name) {
 /**
    Receives argv[1] as 'argv' and scans from thereafter for any
    obfsproxy optional arguments and tries to set them in effect.
-   
+
    If it succeeds it returns the number of argv arguments its caller
    should skip to get past the optional arguments we already handled.
    If it fails, it exits obfsproxy.
@@ -142,14 +138,14 @@ handle_obfsproxy_args(const char **argv)
   int logsev_set=0;
   int i=0;
 
-  while (argv[i] && 
+  while (argv[i] &&
          !strncmp(argv[i],"--",2)) {
     if (!strncmp(argv[i], "--log-file=", 11)) {
       if (logmethod_set) {
-        log_warn("You've already set a log file!"); 
+        log_warn("You've already set a log file!");
         exit(1);
       }
-      if (log_set_method(LOG_METHOD_FILE, 
+      if (log_set_method(LOG_METHOD_FILE,
                          (char *)argv[i]+11) < 0) {
         log_warn("Failed creating logfile.");
         exit(1);
@@ -161,7 +157,7 @@ handle_obfsproxy_args(const char **argv)
         exit(1);
       }
       if (log_set_min_severity((char *)argv[i]+19) < 0) {
-        log_warn("Error at setting logging severity"); 
+        log_warn("Error at setting logging severity");
         exit(1);
       }
       logsev_set=1;
@@ -171,7 +167,7 @@ handle_obfsproxy_args(const char **argv)
           exit(1);
         }
         if (log_set_method(LOG_METHOD_NULL, NULL) < 0) {
-          printf("Error at setting logging severity.\n"); 
+          printf("Error at setting logging severity.\n");
           exit(1);
         }
         logsev_set=1;
@@ -212,7 +208,7 @@ main(int argc, const char **argv)
      managed to recognize, by their protocol name.  Of course it's not
      the *actual* actual_protocols since some of them could have wrong
      options or arguments, but this will be resolved per-protocol by
-     set_up_protocol(). */
+     proto_params_init(). */
   int actual_protocols=0;
 
   int start;
@@ -300,7 +296,7 @@ main(int argc, const char **argv)
 
     /* First option should be protocol_name. See if we support it. */
     if (is_supported_protocol(argv[start])<0) {
-      log_warn("We don't support protocol: %s", argv[start]); 
+      log_warn("We don't support protocol: %s", argv[start]);
       continue;
     }
 
@@ -308,14 +304,14 @@ main(int argc, const char **argv)
 
     /* Allocate space for the array carrying the options of this
        protocol. */
-    protocol_options[actual_protocols-1] = 
+    protocol_options[actual_protocols-1] =
       calloc(sizeof(char*), (n_options));
     if (!protocol_options[actual_protocols-1])
       die_oom();
 
     /* Write the number of options to the correct place in n_options_array[]. */
     n_options_array[actual_protocols-1] = n_options;
-  
+
     /* Finally! Let's fill protocol_options. */
     populate_options(protocol_options[actual_protocols-1],
                      &argv[start], n_options);
@@ -343,7 +339,7 @@ main(int argc, const char **argv)
     log_warn("Can't initialize evdns; failing");
     return 1;
   }
-  
+
   /* Handle signals */
 #ifdef SIGPIPE
    signal(SIGPIPE, SIG_IGN);
@@ -357,7 +353,7 @@ main(int argc, const char **argv)
     return 1;
   }
 
-  /*Let's open a new listener for each protocol. */ 
+  /*Let's open a new listener for each protocol. */
   int h;
   listener_t *temp_listener;
   int n_listeners=0;
@@ -366,10 +362,9 @@ main(int argc, const char **argv)
     log_debug("Spawning listener %d!", h+1);
 
     /** normally free'd in listener_free() */
-    proto_params = calloc(1, sizeof(protocol_params_t));
-    if (set_up_protocol(n_options_array[h],protocol_options[h],
-                        proto_params)<0) {
-      free(proto_params);
+    proto_params = proto_params_init(n_options_array[h],
+                                     (const char *const *)protocol_options[h]);
+    if (!proto_params) {
       free(protocol_options[h]);
       continue;
     }
diff --git a/src/network.c b/src/network.c
index 6a8afa6..365c61a 100644
--- a/src/network.c
+++ b/src/network.c
@@ -202,7 +202,7 @@ simple_listener_cb(struct evconnlistener *evcl,
 
   conn->mode = lsn->proto_params->mode;
 
-  conn->proto = proto_new(lsn->proto_params);
+  conn->proto = proto_create(lsn->proto_params);
   if (!conn->proto) {
     log_warn("Creation of protocol object failed! Closing connection.");
     goto err;
diff --git a/src/protocol.c b/src/protocol.c
index 282db10..85b975f 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -15,8 +15,13 @@
     All supported protocols should be put in this array.
     It's used by main.c.
 */
-char *supported_protocols[] = { "obfs2", "dummy" };
-int n_supported_protocols = 2;
+const protocol_vtable *const supported_protocols[] =
+{
+  &dummy_vtable,
+  &obfs2_vtable,
+};
+const size_t n_supported_protocols =
+  sizeof(supported_protocols)/sizeof(supported_protocols[0]);
 
 /**
    This function figures out which protocol we want to set up, and
@@ -25,16 +30,33 @@ int n_supported_protocols = 2;
    This function is called once for every listener through the runtime
    of obfsproxy.
 */
-int
-set_up_protocol(int n_options, char **options,
-                struct protocol_params_t *params)
+struct protocol_params_t *
+proto_params_init(int n_options, const char *const *options)
 {
-  if (!strcmp(*options,"dummy"))
-    return dummy_init(n_options, options, params);
-  else if (!strcmp(*options,"obfs2"))
-    return obfs2_init(n_options, options, params);
-  else
-    return -1;
+  size_t i;
+  for (i = 0; i < n_supported_protocols; i++)
+    if (!strcmp(*options, supported_protocols[i]->name))
+      return supported_protocols[i]->init(n_options, options);
+
+  return NULL;
+}
+
+/**
+   This function destroys 'params'.
+   It's called everytime we free a listener.
+*/
+void
+proto_params_free(protocol_params_t *params)
+{
+  assert(params);
+
+  if (params->target_address)
+    free(params->target_address);
+  if (params->listen_address)
+    free(params->listen_address);
+  if (params->shared_secret)
+    free(params->shared_secret);
+  free(params);
 }
 
 /**
@@ -44,17 +66,12 @@ set_up_protocol(int n_options, char **options,
    Return a 'protocol_t' if successful, NULL otherwise.
 */
 struct protocol_t *
-proto_new(protocol_params_t *params) {
-  struct protocol_t *proto = calloc(1, sizeof(struct protocol_t));
-  if (!proto)
-    return NULL;
-
-  if (params->proto == OBFS2_PROTOCOL)
-    proto->state = obfs2_new(proto, params);
-  else if (params->proto == DUMMY_PROTOCOL)
-    proto->state = dummy_new(proto, NULL);
-
-  return proto->state ? proto : NULL;
+proto_create(protocol_params_t *params)
+{
+  assert(params);
+  assert(params->vtable);
+  assert(params->vtable->create);
+  return params->vtable->create(params);
 }
 
 /**
@@ -64,10 +81,9 @@ proto_new(protocol_params_t *params) {
 int
 proto_handshake(struct protocol_t *proto, void *buf) {
   assert(proto);
-  if (proto->vtable->handshake)
-    return proto->vtable->handshake(proto->state, buf);
-  else /* It's okay with me, protocol didn't have a handshake */
-    return 0;
+  assert(proto->vtable);
+  assert(proto->vtable->handshake);
+  return proto->vtable->handshake(proto, buf);
 }
 
 /**
@@ -76,10 +92,9 @@ proto_handshake(struct protocol_t *proto, void *buf) {
 int
 proto_send(struct protocol_t *proto, void *source, void *dest) {
   assert(proto);
-  if (proto->vtable->send)
-    return proto->vtable->send(proto->state, source, dest);
-  else
-    return -1;
+  assert(proto->vtable);
+  assert(proto->vtable->send);
+  return proto->vtable->send(proto, source, dest);
 }
 
 /**
@@ -88,10 +103,9 @@ proto_send(struct protocol_t *proto, void *source, void *dest) {
 enum recv_ret
 proto_recv(struct protocol_t *proto, void *source, void *dest) {
   assert(proto);
-  if (proto->vtable->recv)
-    return proto->vtable->recv(proto->state, source, dest);
-  else
-    return -1;
+  assert(proto->vtable);
+  assert(proto->vtable->recv);
+  return proto->vtable->recv(proto, source, dest);
 }
 
 /**
@@ -101,28 +115,7 @@ proto_recv(struct protocol_t *proto, void *source, void *dest) {
 void
 proto_destroy(struct protocol_t *proto) {
   assert(proto);
-  assert(proto->state);
-
-  if (proto->vtable->destroy)
-    proto->vtable->destroy(proto->state);
-
-  free(proto);
-}
-
-/**
-   This function destroys 'params'.
-   It's called everytime we free a listener.
-*/
-void
-proto_params_free(protocol_params_t *params)
-{
-  assert(params);
-
-  if (params->target_address)
-    free(params->target_address);
-  if (params->listen_address)
-    free(params->listen_address);
-  if (params->shared_secret)
-    free(params->shared_secret);
-  free(params);
+  assert(proto->vtable);
+  assert(proto->vtable->destroy);
+  proto->vtable->destroy(proto);
 }
diff --git a/src/protocol.h b/src/protocol.h
index 6d5dcfe..476d447 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -11,17 +11,15 @@
 struct evbuffer;
 struct sockaddr;
 
-#define DUMMY_PROTOCOL      1
-#define OBFS2_PROTOCOL      2
-
 /**
-  This struct defines parameters of the protocol per-listener basis.
+  This struct defines parameters of a protocol on a per-listener basis.
 
   By 'per-listener basis' I mean that the parameters defined here will
   be inherited by *all* connections opened from the listener_t that
   owns this protocol_params_t.
 */
 typedef struct protocol_params_t {
+  const struct protocol_vtable *vtable;
   struct sockaddr *target_address;
   struct sockaddr *listen_address;
   char *shared_secret;
@@ -30,61 +28,91 @@ typedef struct protocol_params_t {
   size_t listen_address_len;
   int is_initiator;
   int mode;
-  int proto; /* Protocol that this listener can speak. */
 } protocol_params_t;
 
+/**
+   This protocol specific struct defines the state of the protocol
+   on a per-connection basis.
+
+   By 'protocol specific' I mean that every protocol has its own
+   state struct. (for example, obfs2 has obfs2_state_t).  A protocol_t
+   struct is always the first member of this struct, and vtable->create
+   returns that member (standard fake-inheritance-in-C technique).
+   All data other than the vtable is hidden from everything but the
+   protocol implementation.
+
+   By 'per-connection basis' I mean that the every connection has a
+   different protocol_t struct, and that's precisely the reason that
+   this struct is owned by the conn_t struct.
+ */
 struct protocol_t {
-  /* protocol vtable */
-  struct protocol_vtable *vtable;
-
-  /* This protocol specific struct defines the state of the protocol
-     per-connection basis.
-
-     By 'protocol specific' I mean that every protocol has it's own
-     state struct. (for example, obfs2 has obfs2_state_t)
-
-     By 'per-connection basis' I mean that the every connection has a
-     different protocol_t struct, and that's precisely the reason that
-     this struct is owned by the conn_t struct.
-  */
-  void *state;
+  const struct protocol_vtable *vtable;
 };
-int set_up_protocol(int n_options, char **options,
-                    struct protocol_params_t *params);
-struct protocol_t *proto_new(struct protocol_params_t *params);
-void proto_destroy(struct protocol_t *proto);
-int proto_handshake(struct protocol_t *proto, void *buf);
-int proto_send(struct protocol_t *proto, void *source, void *dest);
-enum recv_ret proto_recv(struct protocol_t *proto, void *source, void *dest);
-
-void proto_params_free(protocol_params_t *params);
-
-typedef struct protocol_vtable {
-  /* Initialization function: Fills in the protocol vtable. */
-  int (*init)(int n_options, char **options,
-              struct protocol_params_t *params);
-
-  /* Destructor: Destroys the protocol state.  */
-  void (*destroy)(void *state);
 
-  /* Constructor: Creates a protocol object. */
-  void *(*create)(struct protocol_t *proto_params,
-                  struct protocol_params_t *parameters);
-
-  /* does handshake. Not all protocols have a handshake. */
-  int (*handshake)(void *state,
+/**
+   This struct defines a protocol and its methods; note that not all
+   of them are methods on the same object in the C++ sense.
+
+   A filled-in, statically allocated protocol_vtable object is the
+   principal interface between each individual protocol and generic
+   code.  At present there is a static list of these objects in protocol.c.
+ */
+typedef struct protocol_vtable
+{
+  /** The short name of this protocol. */
+  const char *name;
+
+  /** Initialization function: Allocate a 'protocol_params_t' object
+      and fill it in from the provided 'options' array. */
+  struct protocol_params_t *(*init)(int n_options,
+                                    const char *const *options);
+
+  /** Constructor: Allocates per-connection, protocol-specific state. */
+  struct protocol_t *(*create)(struct protocol_params_t *params);
+
+  /** Destructor: Destroys per-connection, protocol-specific state.  */
+  void (*destroy)(struct protocol_t *state);
+
+  /** Perform a connection handshake. Not all protocols have a handshake. */
+  int (*handshake)(struct protocol_t *state,
                    struct evbuffer *buf);
 
-  /* send data function */
-  int (*send)(void *state,
+  /** Send data coming downstream from 'source' along to 'dest'. */
+  int (*send)(struct protocol_t *state,
               struct evbuffer *source,
               struct evbuffer *dest);
 
-  /* receive data function */
-  enum recv_ret (*recv)(void *state,
+  /** Receive data from 'source' and pass it upstream to 'dest'. */
+  enum recv_ret (*recv)(struct protocol_t *state,
                         struct evbuffer *source,
                         struct evbuffer *dest);
 
 } protocol_vtable;
 
+/**
+   Use this macro to define protocol_vtable objects; it ensures all
+   the methods are in the correct order and enforces a consistent
+   naming convention on protocol implementations.
+ */
+#define DEFINE_PROTOCOL_VTABLE(name)                    \
+  const struct protocol_vtable name##_vtable = {        \
+    #name,                                              \
+    name##_init, name##_create, name##_destroy,         \
+    name##_handshake, name##_send, name##_recv          \
+  }
+
+struct protocol_params_t *proto_params_init(int n_options,
+                                            const char *const *options);
+void proto_params_free(protocol_params_t *params);
+
+struct protocol_t *proto_create(struct protocol_params_t *params);
+void proto_destroy(struct protocol_t *proto);
+
+int proto_handshake(struct protocol_t *proto, void *buf);
+int proto_send(struct protocol_t *proto, void *source, void *dest);
+enum recv_ret proto_recv(struct protocol_t *proto, void *source, void *dest);
+
+extern const protocol_vtable *const supported_protocols[];
+extern const size_t n_supported_protocols;
+
 #endif
diff --git a/src/protocols/dummy.c b/src/protocols/dummy.c
index 3b31e12..7db48d7 100644
--- a/src/protocols/dummy.c
+++ b/src/protocols/dummy.c
@@ -7,22 +7,16 @@
 #include "../util.h"
 
 #include <assert.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include <event2/buffer.h>
 
-static int dummy_send(void *nothing,
-                      struct evbuffer *source, struct evbuffer *dest);
-static enum recv_ret dummy_recv(void *nothing, struct evbuffer *source,
-                                struct evbuffer *dest);
 static void usage(void);
-static int parse_and_set_options(int n_options, char **options,
+static int parse_and_set_options(int n_options,
+                                 const char *const *options,
                                  struct protocol_params_t *params);
 
-static protocol_vtable *vtable=NULL;
-
 /**
    This function populates 'params' according to 'options' and sets up
    the protocol vtable.
@@ -30,34 +24,28 @@ static protocol_vtable *vtable=NULL;
    'options' is an array like this:
    {"dummy","socks","127.0.0.1:6666"}
 */
-int
-dummy_init(int n_options, char **options,
-           struct protocol_params_t *params)
+static struct protocol_params_t *
+dummy_init(int n_options, const char *const *options)
 {
-  if (parse_and_set_options(n_options,options,params) < 0) {
+  struct protocol_params_t *params
+    = calloc(1, sizeof(struct protocol_params_t));
+  if (!params)
+    return NULL;
+
+  if (parse_and_set_options(n_options, options, params) < 0) {
+    free(params);
     usage();
-    return -1;
+    return NULL;
   }
 
-  /* XXX memleak. */
-  vtable = calloc(1, sizeof(protocol_vtable));
-  if (!vtable)
-    return -1;
-
-  vtable->destroy = NULL;
-  vtable->create = dummy_new;
-  vtable->handshake = NULL;
-  vtable->send = dummy_send;
-  vtable->recv = dummy_recv;
-
-  return 0;
+  return params;
 }
 
 /**
    Helper: Parses 'options' and fills 'params'.
-*/ 
+*/
 static int
-parse_and_set_options(int n_options, char **options,
+parse_and_set_options(int n_options, const char *const *options,
                       struct protocol_params_t *params)
 {
   const char* defport;
@@ -66,7 +54,6 @@ parse_and_set_options(int n_options, char **options,
     return -1;
 
   assert(!strcmp(options[0],"dummy"));
-  params->proto = DUMMY_PROTOCOL;
 
   if (!strcmp(options[1], "client")) {
     defport = "48988"; /* bf5c */
@@ -87,7 +74,8 @@ parse_and_set_options(int n_options, char **options,
     return -1;
   }
 
-  return 1;
+  params->vtable = &dummy_vtable;
+  return 0;
 }
 
 /**
@@ -96,31 +84,34 @@ parse_and_set_options(int n_options, char **options,
 static void
 usage(void)
 {
-  printf("Great... You can't even form a dummy protocol line:\n"
-         "dummy syntax:\n"
-         "\tdummy dummy_opts\n"
-         "\t'dummy_opts':\n"
-         "\t\tmode ~ server|client|socks\n"
-         "\t\tlisten address ~ host:port\n"
-         "Example:\n"
-         "\tobfsproxy dummy socks 127.0.0.1:5000\n");
+  log_warn("Great... You can't even form a dummy protocol line:\n"
+           "dummy syntax:\n"
+           "\tdummy dummy_opts\n"
+           "\t'dummy_opts':\n"
+           "\t\tmode ~ server|client|socks\n"
+           "\t\tlisten address ~ host:port\n"
+           "Example:\n"
+           "\tobfsproxy dummy socks 127.0.0.1:5000");
 }
 
 /*
   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)
+
+static struct protocol_t *
+dummy_create(struct protocol_params_t *params)
 {
-  proto_struct->vtable = vtable;
+  /* Dummy needs no per-connection protocol-specific state. */
+  struct protocol_t *proto = calloc(1, sizeof(struct protocol_t));
+  proto->vtable = &dummy_vtable;
+  return proto;
+}
 
-  /* Dodging state check.
-     This is terrible I know.*/
-  return (void *)666U;
+static void
+dummy_destroy(struct protocol_t *proto)
+{
+  free(proto);
 }
 
 /**
@@ -129,10 +120,16 @@ dummy_new(struct protocol_t *proto_struct,
    The dummy protocol just puts the data of 'source' in 'dest'.
 */
 static int
-dummy_send(void *nothing,
-           struct evbuffer *source, struct evbuffer *dest) {
-  (void)nothing;
+dummy_handshake(struct protocol_t *proto __attribute__((unused)),
+                struct evbuffer *buf __attribute__((unused)))
+{
+  return 0;
+}
 
+static int
+dummy_send(struct protocol_t *proto __attribute__((unused)),
+           struct evbuffer *source, struct evbuffer *dest)
+{
   return evbuffer_add_buffer(dest,source);
 }
 
@@ -142,12 +139,13 @@ dummy_send(void *nothing,
   The dummy protocol just puts the data of 'source' into 'dest'.
 */
 static enum recv_ret
-dummy_recv(void *nothing,
-           struct evbuffer *source, struct evbuffer *dest) {
-  (void)nothing;
-
+dummy_recv(struct protocol_t *proto __attribute__((unused)),
+           struct evbuffer *source, struct evbuffer *dest)
+{
   if (evbuffer_add_buffer(dest,source)<0)
     return RECV_BAD;
   else
     return RECV_GOOD;
 }
+
+DEFINE_PROTOCOL_VTABLE(dummy);
diff --git a/src/protocols/dummy.h b/src/protocols/dummy.h
index a3fa32d..e7dbd2a 100644
--- a/src/protocols/dummy.h
+++ b/src/protocols/dummy.h
@@ -1,14 +1,10 @@
 /* Copyright 2011 Nick Mathewson, George Kadianakis
    See LICENSE for other credits and copying information
 */
-#ifndef DUMMY_H
-#define DUMMY_H
+#ifndef PROTOCOL_DUMMY_H
+#define PROTOCOL_DUMMY_H
 
-struct protocol_t;
-struct protocol_params_t;
-
-int dummy_init(int n_options, char **options, struct protocol_params_t *lsn);
-void *dummy_new(struct protocol_t *proto_struct,
-                struct protocol_params_t *params);
+struct protocol_vtable;
+extern const struct protocol_vtable dummy_vtable;
 
 #endif
diff --git a/src/protocols/obfs2.c b/src/protocols/obfs2.c
index 27e9272..cc208ed 100644
--- a/src/protocols/obfs2.c
+++ b/src/protocols/obfs2.c
@@ -2,34 +2,28 @@
    See LICENSE for other credits and copying information
 */
 
-#define CRYPT_PROTOCOL_PRIVATE
+#define PROTOCOL_OBFS2_PRIVATE
 #include "obfs2.h"
 
-#include "../protocol.h"
 #include "../util.h"
 
 #include <assert.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include <event2/buffer.h>
 
-
-static void obfs2_state_free(void *state);
-static int obfs2_send_initial_message(void *state, struct evbuffer *buf);
-static int obfs2_send(void *state,
-                      struct evbuffer *source, struct evbuffer *dest);
-static enum recv_ret obfs2_recv(void *state, struct evbuffer *source,
-                                struct evbuffer *dest);
-static void *obfs2_state_new(protocol_params_t *params);
-static int obfs2_state_set_shared_secret(void *s,
-                                         const char *secret,
-                                         size_t secretlen);
-static int set_up_vtable(void);
 static void usage(void);
+static int parse_and_set_options(int n_options,
+                                 const char *const *options,
+                                 struct protocol_params_t *params);
 
-static protocol_vtable *vtable=NULL;
+static inline obfs2_protocol_t *
+downcast(struct protocol_t *proto)
+{
+  return (obfs2_protocol_t *)
+    ((char *)proto - offsetof(obfs2_protocol_t, super));
+}
 
 /*
    This function parses 'options' and fills the protocol parameters
@@ -38,31 +32,34 @@ static protocol_vtable *vtable=NULL;
 
    Returns 0 on success, -1 on fail.
 */
-int
-obfs2_init(int n_options, char **options,
-           struct protocol_params_t *params)
+static struct protocol_params_t *
+obfs2_init(int n_options, const char *const *options)
 {
-  if (parse_and_set_options(n_options,options,params) < 0) {
+  struct protocol_params_t *params
+    = calloc(1, sizeof(struct protocol_params_t));
+  if (!params)
+    return NULL;
+
+  if (parse_and_set_options(n_options, options, params) < 0) {
     usage();
-    return -1;
+    free(params);
+    return NULL;
   }
 
-  if (set_up_vtable() < 0)
-    return -1;
-
   if (initialize_crypto() < 0) {
-    fprintf(stderr, "Can't initialize crypto; failing\n");
-    return -1;
+    log_warn("Can't initialize crypto; failing");
+    free(params);
+    return NULL;
   }
 
-  return 0;
+  return params;
 }
 
 /**
    Helper: Parses 'options' and fills 'params'.
 */
 int
-parse_and_set_options(int n_options, char **options,
+parse_and_set_options(int n_options, const char *const *options,
                       struct protocol_params_t *params)
 {
   int got_dest=0;
@@ -75,7 +72,6 @@ parse_and_set_options(int n_options, char **options,
   }
 
   assert(!strcmp(*options,"obfs2"));
-  params->proto = OBFS2_PROTOCOL;
   options++;
 
   /* Now parse the optional arguments */
@@ -136,6 +132,8 @@ parse_and_set_options(int n_options, char **options,
     }
 
     log_debug("%s(): Parsed obfs2 options nicely!", __func__);
+
+    params->vtable = &obfs2_vtable;
     return 0;
 }
 
@@ -159,28 +157,6 @@ usage(void)
          "\tobfs2 server 127.0.0.1:1026");
 }
 
-/**
-   Helper: Allocates space for the protocol vtable and populates it's
-   function pointers.
-   Returns 0 on success, -1 on fail.
-*/
-static int
-set_up_vtable(void)
-{
-  /* XXX memleak. */
-  vtable = calloc(1, sizeof(protocol_vtable));
-  if (!vtable)
-    return -1;
-
-  vtable->destroy = obfs2_state_free;
-  vtable->create = obfs2_new;
-  vtable->handshake = obfs2_send_initial_message;
-  vtable->send = obfs2_send;
-  vtable->recv = obfs2_recv;
-
-  return 0;
-}
-
 /** Return true iff the OBFUSCATE_SEED_LENGTH-byte seed in 'seed' is nonzero */
 static int
 seed_nonzero(const uchar *seed)
@@ -195,7 +171,7 @@ seed_nonzero(const uchar *seed)
 static crypt_t *
 derive_key(void *s, const char *keytype)
 {
-  obfs2_state_t *state = s;
+  obfs2_protocol_t *state = s;
   crypt_t *cryptstate;
   uchar buf[SHA256_LENGTH];
   digest_t *c = digest_new();
@@ -235,7 +211,7 @@ static crypt_t *
 derive_padding_key(void *s, const uchar *seed,
                    const char *keytype)
 {
-  obfs2_state_t *state = s;
+  obfs2_protocol_t *state = s;
 
   crypt_t *cryptstate;
   uchar buf[SHA256_LENGTH];
@@ -274,95 +250,84 @@ derive_padding_key(void *s, const uchar *seed,
    to create and return a protocol state according to the protocol
    parameters 'params'.
 */
-void *
-obfs2_new(struct protocol_t *proto_struct,
-          protocol_params_t *params)
+static struct protocol_t *
+obfs2_create(protocol_params_t *params)
 {
-  assert(vtable);
-  proto_struct->vtable = vtable;
-
-  return obfs2_state_new(params);
-}
-
-/**
-   Returns an obfs2 state according to the protocol parameters
-   'params'. If something goes wrong it returns NULL.
- */
-static void *
-obfs2_state_new(protocol_params_t *params)
-{
-  obfs2_state_t *state = calloc(1, sizeof(obfs2_state_t));
+  obfs2_protocol_t *proto = calloc(1, sizeof(obfs2_protocol_t));
   uchar *seed;
   const char *send_pad_type;
 
-  if (!state)
+  if (!proto)
     return NULL;
-  state->state = ST_WAIT_FOR_KEY;
-  state->we_are_initiator = params->is_initiator;
-  if (state->we_are_initiator) {
+  proto->state = ST_WAIT_FOR_KEY;
+  proto->we_are_initiator = params->is_initiator;
+  if (proto->we_are_initiator) {
     send_pad_type = INITIATOR_PAD_TYPE;
-    seed = state->initiator_seed;
+    seed = proto->initiator_seed;
   } else {
     send_pad_type = RESPONDER_PAD_TYPE;
-    seed = state->responder_seed;
+    seed = proto->responder_seed;
   }
 
   /* Generate our seed */
   if (random_bytes(seed, OBFUSCATE_SEED_LENGTH) < 0) {
-    free(state);
+    free(proto);
     return NULL;
   }
 
-  if (params->shared_secret)
-    if (obfs2_state_set_shared_secret(state,
-                                      params->shared_secret,
-                                      params->shared_secret_len)<0)
+  if (params->shared_secret) {
+    /* ASN we must say in spec that we hash command line shared secret. */
+    digest_t *c = digest_new();
+    if (!c) {
+      free(proto);
       return NULL;
+    }
+    digest_update(c, (uchar*)params->shared_secret, params->shared_secret_len);
+    digest_getdigest(c, proto->secret_seed, SHARED_SECRET_LENGTH);
+    digest_free(c);
+  }
 
   /* Derive the key for what we're sending */
-  state->send_padding_crypto = derive_padding_key(state, seed, send_pad_type);
-  if (state->send_padding_crypto == NULL) {
-    free(state);
+  proto->send_padding_crypto = derive_padding_key(proto, seed, send_pad_type);
+  if (proto->send_padding_crypto == NULL) {
+    free(proto);
     return NULL;
   }
 
-  return state;
+  proto->super.vtable = &obfs2_vtable;
+  return &proto->super;
 }
 
 /**
-    Sets the shared 'secret' to be used, on the protocol state 's'.
+    Frees obfs2 state 's'
 */
-static int
-obfs2_state_set_shared_secret(void *s, const char *secret,
-                              size_t secretlen)
+static void
+obfs2_destroy(struct protocol_t *s)
 {
-  assert(secret);
-  assert(secretlen);
-
-  uchar buf[SHARED_SECRET_LENGTH];
-  obfs2_state_t *state = s;
-
-  /* ASN we must say in spec that we hash command line shared secret. */
-  digest_t *c = digest_new();
-  digest_update(c, (uchar*)secret, secretlen);
-  digest_getdigest(c, buf, sizeof(buf));
-
-  memcpy(state->secret_seed, buf, SHARED_SECRET_LENGTH);
-
-  memset(buf,0,SHARED_SECRET_LENGTH);
-  digest_free(c);
-
-  return 0;
+  obfs2_protocol_t *state = downcast(s);
+  if (state->send_crypto)
+    crypt_free(state->send_crypto);
+  if (state->send_padding_crypto)
+    crypt_free(state->send_padding_crypto);
+  if (state->recv_crypto)
+    crypt_free(state->recv_crypto);
+  if (state->recv_padding_crypto)
+    crypt_free(state->recv_padding_crypto);
+  if (state->pending_data_to_send)
+    evbuffer_free(state->pending_data_to_send);
+  memset(state, 0x0a, sizeof(obfs2_protocol_t));
+  free(state);
 }
 
+
 /**
    Write the initial protocol setup and padding message for state 's' to
    the evbuffer 'buf'.  Return 0 on success, -1 on failure.
  */
 static int
-obfs2_send_initial_message(void *s, struct evbuffer *buf)
+obfs2_handshake(struct protocol_t *s, struct evbuffer *buf)
 {
-  obfs2_state_t *state = s;
+  obfs2_protocol_t *state = downcast(s);
 
   uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE), plength, send_plength;
   uchar msg[OBFUSCATE_MAX_PADDING + OBFUSCATE_SEED_LENGTH + 8];
@@ -426,10 +391,10 @@ crypt_and_transmit(crypt_t *crypto,
    using the state in 'state'.  Returns 0 on success, -1 on failure.
  */
 static int
-obfs2_send(void *s,
+obfs2_send(struct protocol_t *s,
           struct evbuffer *source, struct evbuffer *dest)
 {
-  obfs2_state_t *state = s;
+  obfs2_protocol_t *state = downcast(s);
 
   if (state->send_crypto) {
     /* First of all, send any data that we've been waiting to send. */
@@ -460,7 +425,7 @@ obfs2_send(void *s,
 static int
 init_crypto(void *s)
 {
-  obfs2_state_t *state = s;
+  obfs2_protocol_t *state = s;
 
   const char *send_keytype;
   const char *recv_keytype;
@@ -503,10 +468,10 @@ init_crypto(void *s)
  *  our callers that they must call obfs2_send() immediately.
  */
 static enum recv_ret
-obfs2_recv(void *s, struct evbuffer *source,
+obfs2_recv(struct protocol_t *s, struct evbuffer *source,
            struct evbuffer *dest)
 {
-  obfs2_state_t *state = s;
+  obfs2_protocol_t *state = downcast(s);
   enum recv_ret r=0;
 
   if (state->state == ST_WAIT_FOR_KEY) {
@@ -587,23 +552,4 @@ obfs2_recv(void *s, struct evbuffer *source,
   return r;
 }
 
-/**
-    Frees obfs2 state 's'
-*/
-static void
-obfs2_state_free(void *s)
-{
-  obfs2_state_t *state = s;
-  if (state->send_crypto)
-    crypt_free(state->send_crypto);
-  if (state->send_padding_crypto)
-    crypt_free(state->send_padding_crypto);
-  if (state->recv_crypto)
-    crypt_free(state->recv_crypto);
-  if (state->recv_padding_crypto)
-    crypt_free(state->recv_padding_crypto);
-  if (state->pending_data_to_send)
-    evbuffer_free(state->pending_data_to_send);
-  memset(state, 0x0a, sizeof(obfs2_state_t));
-  free(state);
-}
+DEFINE_PROTOCOL_VTABLE(obfs2);
diff --git a/src/protocols/obfs2.h b/src/protocols/obfs2.h
index a9ebfb1..e93fbcd 100644
--- a/src/protocols/obfs2.h
+++ b/src/protocols/obfs2.h
@@ -2,27 +2,19 @@
    See LICENSE for other credits and copying information
 */
 
-#ifndef OBFS2_H
-#define OBFS2_H
+#ifndef PROTOCOL_OBFS2_H
+#define PROTOCOL_OBFS2_H
 
-typedef struct obfs2_state_t obfs2_state_t;
-struct evbuffer;
-struct protocol_t;
-struct protocol_params_t;
-struct listener_t;
+struct protocol_vtable;
+extern const struct protocol_vtable obfs2_vtable;
 
-int obfs2_init(int n_options, char **options, struct protocol_params_t *params);
-void *obfs2_new(struct protocol_t *proto_struct,
-                struct protocol_params_t *params);
-int parse_and_set_options(int n_options, char **options,
-                          struct protocol_params_t *params);
-
-#ifdef CRYPT_PROTOCOL_PRIVATE
+#ifdef PROTOCOL_OBFS2_PRIVATE
 
 #include "../crypt.h"
+#include "../protocol.h"
 
 /* ==========
-   These definitions are not part of the crypt_protocol interface.
+   These definitions are not part of the obfs2_protocol interface.
    They're exposed here so that the unit tests can use them.
    ==========
 */
@@ -43,7 +35,9 @@ int parse_and_set_options(int n_options, char **options,
 
 #define SHARED_SECRET_LENGTH SHA256_LENGTH
 
-struct obfs2_state_t {
+typedef struct obfs2_protocol_t {
+  struct protocol_t super;
+
   /** Current protocol state.  We start out waiting for key information.  Then
       we have a key and wait for padding to arrive.  Finally, we are sending
       and receiving bytes on the connection.
@@ -76,7 +70,8 @@ struct obfs2_state_t {
 
   /** Number of padding bytes to read before we get to real data */
   int padding_left_to_read;
-};
+} obfs2_protocol_t;
+
 #endif
 
 #endif
diff --git a/src/test/unittest_obfs2.c b/src/test/unittest_obfs2.c
index 0b2054b..594c36c 100644
--- a/src/test/unittest_obfs2.c
+++ b/src/test/unittest_obfs2.c
@@ -5,12 +5,11 @@
 #include "tinytest.h"
 #include "tinytest_macros.h"
 
-#define CRYPT_PROTOCOL_PRIVATE
+#define PROTOCOL_OBFS2_PRIVATE
 #define CRYPT_PRIVATE
 #include "../protocols/obfs2.h"
 #include "../crypt.h"
 #include "../util.h"
-#include "../protocol.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -18,86 +17,60 @@
 
 #include <event2/buffer.h>
 
+#define ALEN(x) (sizeof x/sizeof x[0])
+#define OPTV(name) static const char *const name[]
+
+static inline obfs2_protocol_t *
+downcast(struct protocol_t *proto)
+{
+  return (obfs2_protocol_t *)
+    ((char *)proto - offsetof(obfs2_protocol_t, super));
+}
 
 static void
 test_proto_option_parsing(void *data)
 {
-  protocol_params_t *proto_params = calloc(1, sizeof(protocol_params_t));
-  char *options[] = {"obfs2", "--shared-secret=a", "socks", "127.0.0.1:0"};
-  int n_options = 4;
-
   /* Suppress logs for the duration of this function. */
   log_set_method(LOG_METHOD_NULL, NULL);
 
-  tt_assert(set_up_protocol(n_options, options,
-                            proto_params) == 0);
+  /** good option list */
+  OPTV(options1) = {"obfs2", "--shared-secret=a", "socks", "127.0.0.1:0"};
+  tt_assert(proto_params_init(ALEN(options1), options1) != NULL);
 
   /** two --dest. */
-  char *options2[] = {"obfs2", "--dest=127.0.0.1:5555", "--dest=a",
-                      "server", "127.0.0.1:5552"};
-  n_options = 5;
-
-  tt_assert(set_up_protocol(n_options, options2,
-                            proto_params) == -1);
+  OPTV(options2) = {"obfs2", "--dest=127.0.0.1:5555", "--dest=a",
+                    "server", "127.0.0.1:5552"};
+  tt_assert(proto_params_init(ALEN(options2), options2) == NULL);
 
   /** unknown arg */
-  char *options3[] = {"obfs2", "--gabura=a",
-                      "server", "127.0.0.1:5552"};
-  n_options = 4;
-
-  tt_assert(set_up_protocol(n_options, options3,
-                            proto_params) == -1);
+  OPTV(options3) = {"obfs2", "--gabura=a", "server", "127.0.0.1:5552"};
+  tt_assert(proto_params_init(ALEN(options3), options3) == NULL)
 
   /** too many args */
-  char *options4[] = {"obfs2", "1", "2", "3", "4", "5" };
-  n_options = 6;
-
-  tt_assert(set_up_protocol(n_options, options4,
-                            proto_params) == -1);
+  OPTV(options4) = {"obfs2", "1", "2", "3", "4", "5" };
+  tt_assert(proto_params_init(ALEN(options4), options4) == NULL)
 
   /** wrong mode  */
-  char *options5[] = {"obfs2", "--dest=1:1",
-                      "gladiator", "127.0.0.1:5552"};
-  n_options = 4;
-
-  tt_assert(set_up_protocol(n_options, options5,
-                            proto_params) == -1);
-
-  /** stupid listen addr.  */
-  char *options6[] = {"obfs2", "--dest=1:1",
-                      "server", "127.0.0.1:a"};
-  n_options = 4;
+  OPTV(options5) = {"obfs2", "--dest=1:1", "gladiator", "127.0.0.1:5552"};
+  tt_assert(proto_params_init(ALEN(options5), options5) == NULL)
 
-  tt_assert(set_up_protocol(n_options, options6,
-                            proto_params) == -1);
+  /** bad listen addr.  */
+  OPTV(options6) = {"obfs2", "--dest=1:1", "server", "127.0.0.1:a"};
+  tt_assert(proto_params_init(ALEN(options6), options6) == NULL)
 
-  /** stupid dest addr.  */
-  char *options7[] = {"obfs2", "--dest=1:b",
-                      "server", "127.0.0.1:1"};
-  n_options = 4;
-
-  tt_assert(set_up_protocol(n_options, options7,
-                            proto_params) == -1);
+  /** bad dest addr.  */
+  OPTV(options7) = {"obfs2", "--dest=1:b", "server", "127.0.0.1:1"};
+  tt_assert(proto_params_init(ALEN(options7), options7) == NULL)
 
   /** socks with dest.  */
-  char *options8[] = {"obfs2", "--dest=1:2",
-                      "socks", "127.0.0.1:1"};
-  n_options = 4;
-
-  tt_assert(set_up_protocol(n_options, options8,
-                            proto_params) == -1);
+  OPTV(options8) = {"obfs2", "--dest=1:2", "socks", "127.0.0.1:1"};
+  tt_assert(proto_params_init(ALEN(options8), options8) == NULL)
 
   /** socks with dest.  */
-  char *options9[] = {"obfs2", "--shared-secret=a",
-                      "server", "127.0.0.1:1"};
-  n_options = 4;
-
-  tt_assert(set_up_protocol(n_options, options9,
-                            proto_params) == -1);
+  OPTV(options9) = {"obfs2", "--shared-secret=a", "server", "127.0.0.1:1"};
+  tt_assert(proto_params_init(ALEN(options9), options9) == NULL)
 
  end:
-  if (proto_params)
-    free(proto_params);
   /* Unsuspend logging */
   log_set_method(LOG_METHOD_STDOUT, NULL);
 }
@@ -108,36 +81,36 @@ test_proto_setup(void *data)
 {
   struct protocol_t *client_proto = NULL;
   struct protocol_t *server_proto = NULL;
+  struct protocol_params_t *proto_params_client = NULL;
+  struct protocol_params_t *proto_params_server = NULL;
 
-  protocol_params_t *proto_params_client = calloc(1, sizeof(protocol_params_t));
-  char *options_client[] = {"obfs2", "--shared-secret=hahaha",
-                            "socks", "127.0.0.1:1800"};
-  int n_options_client = 4;
-
-  protocol_params_t *proto_params_serv = calloc(1, sizeof(protocol_params_t));
-  char *options_server[] = {"obfs2", "--shared-secret=hahaha",
-                            "--dest=127.0.0.1:1500",
-                           "server", "127.0.0.1:1800"};
-  int n_options_server = 5;
-
-  tt_assert(set_up_protocol(n_options_client, options_client,
-                            proto_params_client) >= 0);
-  tt_assert(set_up_protocol(n_options_server, options_server,
-                            proto_params_serv) >= 0);
+  OPTV(options_client) = {"obfs2", "--shared-secret=hahaha",
+                          "socks", "127.0.0.1:1800"};
+  proto_params_client = proto_params_init(ALEN(options_client), options_client);
+  tt_assert(proto_params_client);
 
-  client_proto = proto_new(proto_params_serv);
-  server_proto = proto_new(proto_params_client);
+  OPTV(options_server) = {"obfs2", "--shared-secret=hahaha",
+                          "--dest=127.0.0.1:1500",
+                          "server", "127.0.0.1:1800"};
+  proto_params_server = proto_params_init(ALEN(options_server), options_server);
+  tt_assert(proto_params_server);
 
+  client_proto = proto_create(proto_params_client);
   tt_assert(client_proto);
+
+  server_proto = proto_create(proto_params_server);
   tt_assert(server_proto);
-  tt_assert(client_proto->state);
-  tt_assert(server_proto->state);
 
- end:
+ end:;
   if (client_proto)
-    proto_destroy(client_proto);
+      proto_destroy(client_proto);
   if (server_proto)
-    proto_destroy(server_proto);
+      proto_destroy(server_proto);
+
+  if (proto_params_client)
+    proto_params_free(proto_params_client);
+  if (proto_params_server)
+    proto_params_free(proto_params_server);
 }
 
 static void
@@ -150,33 +123,28 @@ test_proto_handshake(void *data)
 
   struct protocol_t *client_proto = NULL;
   struct protocol_t *server_proto = NULL;
+  struct protocol_params_t *proto_params_client = NULL;
+  struct protocol_params_t *proto_params_server = NULL;
 
-  protocol_params_t *proto_params_client = calloc(1, sizeof(protocol_params_t));
-  char *options_client[] = {"obfs2", "--shared-secret=hahaha",
-                            "socks", "127.0.0.1:1800"};
-  int n_options_client = 4;
-
-  protocol_params_t *proto_params_serv = calloc(1, sizeof(protocol_params_t));
-  char *options_server[] = {"obfs2", "--shared-secret=hahaha",
-                            "--dest=127.0.0.1:1500",
-                            "server", "127.0.0.1:1800"};
-  int n_options_server = 5;
-
-  tt_assert(set_up_protocol(n_options_client, options_client,
-                            proto_params_client) >= 0);
-  tt_assert(set_up_protocol(n_options_server, options_server,
-                            proto_params_serv) >= 0);
+  OPTV(options_client) = {"obfs2", "--shared-secret=hahaha",
+                          "socks", "127.0.0.1:1800"};
+  proto_params_client = proto_params_init(ALEN(options_client), options_client);
+  tt_assert(proto_params_client);
 
-  client_proto = proto_new(proto_params_client);
-  server_proto = proto_new(proto_params_serv);
+  OPTV(options_server) = {"obfs2", "--shared-secret=hahaha",
+                          "--dest=127.0.0.1:1500",
+                          "server", "127.0.0.1:1800"};
+  proto_params_server = proto_params_init(ALEN(options_server), options_server);
+  tt_assert(proto_params_server);
 
+  client_proto = proto_create(proto_params_client);
   tt_assert(client_proto);
+
+  server_proto = proto_create(proto_params_server);
   tt_assert(server_proto);
-  tt_assert(client_proto->state);
-  tt_assert(server_proto->state);
 
-  obfs2_state_t *client_state = client_proto->state;
-  obfs2_state_t *server_state = server_proto->state;
+  obfs2_protocol_t *client_state = downcast(client_proto);
+  obfs2_protocol_t *server_state = downcast(server_proto);
 
   /* We create a client handshake message and pass it to output_buffer */
   tt_int_op(0, <=, proto_handshake(client_proto, output_buffer));
@@ -209,9 +177,9 @@ test_proto_handshake(void *data)
       proto_destroy(server_proto);
 
   if (proto_params_client)
-    free(proto_params_client);
-  if (proto_params_serv)
-    free(proto_params_serv);
+    proto_params_free(proto_params_client);
+  if (proto_params_server)
+    proto_params_free(proto_params_server);
 
   if (output_buffer)
     evbuffer_free(output_buffer);
@@ -229,30 +197,25 @@ test_proto_transfer(void *data)
 
   struct protocol_t *client_proto = NULL;
   struct protocol_t *server_proto = NULL;
+  struct protocol_params_t *proto_params_client = NULL;
+  struct protocol_params_t *proto_params_server = NULL;
 
-  protocol_params_t *proto_params_client = calloc(1, sizeof(protocol_params_t));
-  char *options_client[] = {"obfs2", "--shared-secret=hahaha",
-                            "socks", "127.0.0.1:1800"};
-  int n_options_client = 4;
-
-  protocol_params_t *proto_params_serv = calloc(1, sizeof(protocol_params_t));
-  char *options_server[] = {"obfs2", "--shared-secret=hahaha",
-                            "--dest=127.0.0.1:1500",
-                            "server", "127.0.0.1:1800"};
-  int n_options_server = 5;
-
-  tt_assert(set_up_protocol(n_options_client, options_client,
-                            proto_params_client) >= 0);
-  tt_assert(set_up_protocol(n_options_server, options_server,
-                            proto_params_serv) >= 0);
+  OPTV(options_client) = {"obfs2", "--shared-secret=hahaha",
+                          "socks", "127.0.0.1:1800"};
+  proto_params_client = proto_params_init(ALEN(options_client), options_client);
+  tt_assert(proto_params_client);
 
-  client_proto = proto_new(proto_params_client);
-  server_proto = proto_new(proto_params_serv);
+  OPTV(options_server) = {"obfs2", "--shared-secret=hahaha",
+                          "--dest=127.0.0.1:1500",
+                          "server", "127.0.0.1:1800"};
+  proto_params_server = proto_params_init(ALEN(options_server), options_server);
+  tt_assert(proto_params_server);
 
+  client_proto = proto_create(proto_params_client);
   tt_assert(client_proto);
+
+  server_proto = proto_create(proto_params_server);
   tt_assert(server_proto);
-  tt_assert(client_proto->state);
-  tt_assert(server_proto->state);
 
   int n;
   struct evbuffer_iovec v[2];
@@ -302,9 +265,9 @@ test_proto_transfer(void *data)
     proto_destroy(server_proto);
 
   if (proto_params_client)
-    free(proto_params_client);
-  if (proto_params_serv)
-    free(proto_params_serv);
+    proto_params_free(proto_params_client);
+  if (proto_params_server)
+    proto_params_free(proto_params_server);
 
   if (output_buffer)
     evbuffer_free(output_buffer);
@@ -325,8 +288,8 @@ test_proto_transfer(void *data)
 static void
 test_proto_split_handshake(void *data)
 {
-  obfs2_state_t *client_state = NULL;
-  obfs2_state_t *server_state = NULL;
+  obfs2_protocol_t *client_state = NULL;
+  obfs2_protocol_t *server_state = NULL;
 
   struct evbuffer *output_buffer = NULL;
   struct evbuffer *dummy_buffer = NULL;
@@ -335,33 +298,28 @@ test_proto_split_handshake(void *data)
 
   struct protocol_t *client_proto = NULL;
   struct protocol_t *server_proto = NULL;
+  struct protocol_params_t *proto_params_client = NULL;
+  struct protocol_params_t *proto_params_server = NULL;
 
-  protocol_params_t *proto_params_client = calloc(1, sizeof(protocol_params_t));
-  char *options_client[] = {"obfs2", "--shared-secret=hahaha",
-                            "socks", "127.0.0.1:1800"};
-  int n_options_client = 4;
-
-  protocol_params_t *proto_params_serv = calloc(1, sizeof(protocol_params_t));
-  char *options_server[] = {"obfs2", "--shared-secret=hahaha",
-                            "--dest=127.0.0.1:1500",
-                            "server", "127.0.0.1:1800"};
-  int n_options_server = 5;
-
-  tt_assert(set_up_protocol(n_options_client, options_client,
-                            proto_params_client) >= 0);
-  tt_assert(set_up_protocol(n_options_server, options_server,
-                            proto_params_serv) >= 0);
+  OPTV(options_client) = {"obfs2", "--shared-secret=hahaha",
+                          "socks", "127.0.0.1:1800"};
+  proto_params_client = proto_params_init(ALEN(options_client), options_client);
+  tt_assert(proto_params_client);
 
-  client_proto = proto_new(proto_params_client);
-  server_proto = proto_new(proto_params_serv);
+  OPTV(options_server) = {"obfs2", "--shared-secret=hahaha",
+                          "--dest=127.0.0.1:1500",
+                          "server", "127.0.0.1:1800"};
+  proto_params_server = proto_params_init(ALEN(options_server), options_server);
+  tt_assert(proto_params_server);
 
+  client_proto = proto_create(proto_params_client);
   tt_assert(client_proto);
+
+  server_proto = proto_create(proto_params_server);
   tt_assert(server_proto);
-  tt_assert(client_proto->state);
-  tt_assert(server_proto->state);
 
-  client_state = client_proto->state;
-  server_state = server_proto->state;
+  client_state = downcast(client_proto);
+  server_state = downcast(server_proto);
 
   uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE);
   uint32_t plength1, plength1_msg1, plength1_msg2, send_plength1;
@@ -474,9 +432,9 @@ test_proto_split_handshake(void *data)
     proto_destroy(server_proto);
 
   if (proto_params_client)
-    free(proto_params_client);
-  if (proto_params_serv)
-    free(proto_params_serv);
+    proto_params_free(proto_params_client);
+  if (proto_params_server)
+    proto_params_free(proto_params_server);
 
   if (output_buffer)
     evbuffer_free(output_buffer);
@@ -491,8 +449,8 @@ test_proto_split_handshake(void *data)
 static void
 test_proto_wrong_handshake_magic(void *data)
 {
-  obfs2_state_t *client_state = NULL;
-  obfs2_state_t *server_state = NULL;
+  obfs2_protocol_t *client_state = NULL;
+  obfs2_protocol_t *server_state = NULL;
 
   struct evbuffer *output_buffer = NULL;
   struct evbuffer *dummy_buffer = NULL;
@@ -501,33 +459,28 @@ test_proto_wrong_handshake_magic(void *data)
 
   struct protocol_t *client_proto = NULL;
   struct protocol_t *server_proto = NULL;
+  struct protocol_params_t *proto_params_client = NULL;
+  struct protocol_params_t *proto_params_server = NULL;
 
-  protocol_params_t *proto_params_client = calloc(1, sizeof(protocol_params_t));
-  char *options_client[] = {"obfs2", "--shared-secret=hahaha",
-                            "socks", "127.0.0.1:1800"};
-  int n_options_client = 4;
-
-  protocol_params_t *proto_params_serv = calloc(1, sizeof(protocol_params_t));
-  char *options_server[] = {"obfs2", "--shared-secret=hahaha",
-                            "--dest=127.0.0.1:1500",
-                            "server", "127.0.0.1:1800"};
-  int n_options_server = 5;
+  OPTV(options_client) = {"obfs2", "--shared-secret=hahaha",
+                          "socks", "127.0.0.1:1800"};
+  proto_params_client = proto_params_init(ALEN(options_client), options_client);
+  tt_assert(proto_params_client);
 
-  tt_assert(set_up_protocol(n_options_client, options_client,
-                            proto_params_client) >= 0);
-  tt_assert(set_up_protocol(n_options_server, options_server,
-                            proto_params_serv) >= 0);
-
-  client_proto = proto_new(proto_params_client);
-  server_proto = proto_new(proto_params_serv);
+  OPTV(options_server) = {"obfs2", "--shared-secret=hahaha",
+                          "--dest=127.0.0.1:1500",
+                          "server", "127.0.0.1:1800"};
+  proto_params_server = proto_params_init(ALEN(options_server), options_server);
+  tt_assert(proto_params_server);
 
+  client_proto = proto_create(proto_params_client);
   tt_assert(client_proto);
+
+  server_proto = proto_create(proto_params_server);
   tt_assert(server_proto);
-  tt_assert(client_proto->state);
-  tt_assert(server_proto->state);
 
-  client_state = client_proto->state;
-  server_state = server_proto->state;
+  client_state = downcast(client_proto);
+  server_state = downcast(server_proto);
 
   uint32_t wrong_magic = 0xD15EA5E;
 
@@ -561,9 +514,9 @@ test_proto_wrong_handshake_magic(void *data)
     proto_destroy(server_proto);
 
   if (proto_params_client)
-    free(proto_params_client);
-  if (proto_params_serv)
-    free(proto_params_serv);
+    proto_params_free(proto_params_client);
+  if (proto_params_server)
+    proto_params_free(proto_params_server);
 
   if (output_buffer)
     evbuffer_free(output_buffer);
@@ -577,8 +530,8 @@ test_proto_wrong_handshake_magic(void *data)
 static void
 test_proto_wrong_handshake_plength(void *data)
 {
-  obfs2_state_t *client_state = NULL;
-  obfs2_state_t *server_state = NULL;
+  obfs2_protocol_t *client_state = NULL;
+  obfs2_protocol_t *server_state = NULL;
 
   struct evbuffer *output_buffer = NULL;
   struct evbuffer *dummy_buffer = NULL;
@@ -587,34 +540,28 @@ test_proto_wrong_handshake_plength(void *data)
 
   struct protocol_t *client_proto = NULL;
   struct protocol_t *server_proto = NULL;
+  struct protocol_params_t *proto_params_client = NULL;
+  struct protocol_params_t *proto_params_server = NULL;
 
+  OPTV(options_client) = {"obfs2", "--shared-secret=hahaha",
+                          "socks", "127.0.0.1:1800"};
+  proto_params_client = proto_params_init(ALEN(options_client), options_client);
+  tt_assert(proto_params_client);
 
-  protocol_params_t *proto_params_client = calloc(1, sizeof(protocol_params_t));
-  char *options_client[] = {"obfs2", "--shared-secret=hahaha",
-                            "socks", "127.0.0.1:1800"};
-  int n_options_client = 4;
-
-  protocol_params_t *proto_params_serv = calloc(1, sizeof(protocol_params_t));
-  char *options_server[] = {"obfs2", "--shared-secret=hahaha",
-                            "--dest=127.0.0.1:1500",
-                            "server", "127.0.0.1:1800"};
-  int n_options_server = 5;
-
-  tt_assert(set_up_protocol(n_options_client, options_client,
-                            proto_params_client) >= 0);
-  tt_assert(set_up_protocol(n_options_server, options_server,
-                            proto_params_serv) >= 0);
-
-  client_proto = proto_new(proto_params_client);
-  server_proto = proto_new(proto_params_serv);
+  OPTV(options_server) = {"obfs2", "--shared-secret=hahaha",
+                          "--dest=127.0.0.1:1500",
+                          "server", "127.0.0.1:1800"};
+  proto_params_server = proto_params_init(ALEN(options_server), options_server);
+  tt_assert(proto_params_server);
 
+  client_proto = proto_create(proto_params_client);
   tt_assert(client_proto);
+
+  server_proto = proto_create(proto_params_server);
   tt_assert(server_proto);
-  tt_assert(client_proto->state);
-  tt_assert(server_proto->state);
 
-  client_state = client_proto->state;
-  server_state = server_proto->state;
+  client_state = downcast(client_proto);
+  server_state = downcast(server_proto);
 
   uchar msg[OBFUSCATE_MAX_PADDING + OBFUSCATE_SEED_LENGTH + 8 + 1];
   uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE);
@@ -641,15 +588,15 @@ test_proto_wrong_handshake_plength(void *data)
   tt_assert(server_state->state == ST_WAIT_FOR_KEY);
 
  end:
-  if (client_state)
+  if (client_proto)
     proto_destroy(client_proto);
-  if (server_state)
+  if (server_proto)
     proto_destroy(server_proto);
 
   if (proto_params_client)
-    free(proto_params_client);
-  if (proto_params_serv)
-    free(proto_params_serv);
+    proto_params_free(proto_params_client);
+  if (proto_params_server)
+    proto_params_free(proto_params_server);
 
   if (output_buffer)
     evbuffer_free(output_buffer);





More information about the tor-commits mailing list