[tor-commits] [tor/master] Skeleton ExtORPort implementation. Needs testing, documentation.

nickm at torproject.org nickm at torproject.org
Thu Aug 15 16:16:45 UTC 2013


commit 8bf0382b220b31605fb5a542f36a842bdd7a6ed0
Author: Nick Mathewson <nickm at torproject.org>
Date:   Fri Mar 16 09:40:44 2012 -0400

    Skeleton ExtORPort implementation.  Needs testing, documentation.
    
    Does not implement TransportControlPort yet.
---
 src/or/buffers.c       |   48 ++++++++++++
 src/or/buffers.h       |    4 +
 src/or/config.c        |    9 +++
 src/or/connection.c    |   39 +++++++++-
 src/or/connection.h    |    2 +-
 src/or/connection_or.c |  202 +++++++++++++++++++++++++++++++++++++++++++++++-
 src/or/connection_or.h |    9 +++
 src/or/or.h            |   31 +++++++-
 8 files changed, 334 insertions(+), 10 deletions(-)

diff --git a/src/or/buffers.c b/src/or/buffers.c
index cc58904..a79d17b 100644
--- a/src/or/buffers.c
+++ b/src/or/buffers.c
@@ -1702,6 +1702,54 @@ fetch_from_evbuffer_socks(struct evbuffer *buf, socks_request_t *req,
 }
 #endif
 
+/*DOCDOC*/
+#define EXT_OR_CMD_HEADER_SIZE 4
+/*DOCDOC*/
+int
+fetch_ext_or_command_from_buf(buf_t *buf, ext_or_cmd_t **out)
+{
+  char hdr[EXT_OR_CMD_HEADER_SIZE];
+  uint16_t len;
+
+  check();
+  if (buf->datalen < EXT_OR_CMD_HEADER_SIZE)
+    return 0;
+  peek_from_buf(hdr, sizeof(hdr), buf);
+  len = ntohs(get_uint16(hdr+2));
+  if (buf->datalen < (unsigned)len + EXT_OR_CMD_HEADER_SIZE)
+    return 0;
+  *out = ext_or_cmd_new(len);
+  (*out)->cmd = ntohs(get_uint16(hdr));
+  (*out)->len = len;
+  buf_remove_from_front(buf, EXT_OR_CMD_HEADER_SIZE);
+  fetch_from_buf((*out)->body, len, buf);
+  return 1;
+}
+
+#ifdef USE_BUFFEREVENTS
+/*DOCDOC*/
+int
+fetch_ext_or_command_from_evbuffer(struct evbuffer *buf, ext_or_cmd_t **out)
+{
+  char hdr[EXT_OR_CMD_HEADER_SIZE];
+  uint16_t len;
+  size_t buf_len = evbuffer_get_length(buf);
+
+  if (buf_len < EXT_OR_CMD_HEADER_SIZE)
+    return 0;
+  evbuffer_copyout(buf, hdr, EXT_OR_CMD_HEADER_SIZE);
+  len = ntohs(get_uint16(hdr+2));
+  if (buf_len < (unsigned)len + EXT_OR_CMD_HEADER_SIZE)
+    return 0;
+  *out = ext_or_cmd_new(len);
+  (*out)->cmd = ntohs(get_uint16(hdr));
+  (*out)->len = len;
+  evbuffer_drain(buf, EXT_OR_CMD_HEADER_SIZE);
+  evbuffer_remove(buf, (*out)->body, len);
+  return 1;
+}
+#endif
+
 /** Implementation helper to implement fetch_from_*_socks.  Instead of looking
  * at a buffer's contents, we look at the <b>datalen</b> bytes of data in
  * <b>data</b>. Instead of removing data from the buffer, we set
diff --git a/src/or/buffers.h b/src/or/buffers.h
index 910494a..50ac3dc 100644
--- a/src/or/buffers.h
+++ b/src/or/buffers.h
@@ -53,6 +53,8 @@ int fetch_from_buf_line(buf_t *buf, char *data_out, size_t *data_len);
 
 int peek_buf_has_control0_command(buf_t *buf);
 
+int fetch_ext_or_command_from_buf(buf_t *buf, ext_or_cmd_t **out);
+
 #ifdef USE_BUFFEREVENTS
 int fetch_var_cell_from_evbuffer(struct evbuffer *buf, var_cell_t **out,
                                  int linkproto);
@@ -68,6 +70,8 @@ int peek_evbuffer_has_control0_command(struct evbuffer *buf);
 int write_to_evbuffer_zlib(struct evbuffer *buf, tor_zlib_state_t *state,
                            const char *data, size_t data_len,
                            int done);
+int fetch_ext_or_command_from_evbuffer(struct evbuffer *buf,
+                                       ext_or_cmd_t **out);
 #endif
 
 #ifdef USE_BUFFEREVENTS
diff --git a/src/or/config.c b/src/or/config.c
index 2218e50..afdee3d 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -230,6 +230,7 @@ static config_var_t option_vars_[] = {
   V(ExitPolicyRejectPrivate,     BOOL,     "1"),
   V(ExitPortStatistics,          BOOL,     "0"),
   V(ExtendAllowPrivateAddresses, BOOL,     "0"),
+  VPORT(ExtORPort,               LINELIST, NULL),
   V(ExtraInfoStatistics,         BOOL,     "1"),
   V(FallbackDir,                 LINELIST, NULL),
 
@@ -5688,6 +5689,14 @@ parse_ports(or_options_t *options, int validate_only,
       goto err;
     }
     if (parse_port_config(ports,
+                          options->ExtORPort_lines, NULL,
+                          "ExtOR", CONN_TYPE_EXT_OR_LISTENER,
+                          "127.0.0.1", 0,
+                          CL_PORT_SERVER_OPTIONS) < 0) {
+      *msg = tor_strdup("Invalid ExtORPort configuration");
+      goto err;
+    }
+    if (parse_port_config(ports,
                           options->DirPort_lines, options->DirListenAddress,
                           "Dir", CONN_TYPE_DIR_LISTENER,
                           "0.0.0.0", 0,
diff --git a/src/or/connection.c b/src/or/connection.c
index 6a3cc7b..130b1ec 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -98,6 +98,7 @@ static smartlist_t *outgoing_addrs = NULL;
 
 #define CASE_ANY_LISTENER_TYPE \
     case CONN_TYPE_OR_LISTENER: \
+    case CONN_TYPE_EXT_OR_LISTENER: \
     case CONN_TYPE_AP_LISTENER: \
     case CONN_TYPE_DIR_LISTENER: \
     case CONN_TYPE_CONTROL_LISTENER: \
@@ -129,6 +130,8 @@ conn_type_to_string(int type)
     case CONN_TYPE_CPUWORKER: return "CPU worker";
     case CONN_TYPE_CONTROL_LISTENER: return "Control listener";
     case CONN_TYPE_CONTROL: return "Control";
+    case CONN_TYPE_EXT_OR: return "Extended OR";
+    case CONN_TYPE_EXT_OR_LISTENER: return "Extended OR listener";
     default:
       log_warn(LD_BUG, "unknown connection type %d", type);
       tor_snprintf(buf, sizeof(buf), "unknown [%d]", type);
@@ -165,6 +168,12 @@ conn_state_to_string(int type, int state)
         case OR_CONN_STATE_OPEN: return "open";
       }
       break;
+    case CONN_TYPE_EXT_OR:
+      switch (state) {
+        case EXT_OR_CONN_STATE_OPEN: return "open";
+        case EXT_OR_CONN_STATE_FLUSHING: return "flushing final OKAY";
+      }
+      break;
     case CONN_TYPE_EXIT:
       switch (state) {
         case EXIT_CONN_STATE_RESOLVING: return "waiting for dest info";
@@ -229,6 +238,7 @@ connection_type_uses_bufferevent(connection_t *conn)
     case CONN_TYPE_DIR:
     case CONN_TYPE_CONTROL:
     case CONN_TYPE_OR:
+    case CONN_TYPE_EXT_OR:
     case CONN_TYPE_CPUWORKER:
       return 1;
     default:
@@ -259,14 +269,18 @@ dir_connection_new(int socket_family)
  * Set active_circuit_pqueue_last_recalibrated to current cell_ewma tick.
  */
 or_connection_t *
-or_connection_new(int socket_family)
+or_connection_new(int type, int socket_family)
 {
   or_connection_t *or_conn = tor_malloc_zero(sizeof(or_connection_t));
   time_t now = time(NULL);
-  connection_init(now, TO_CONN(or_conn), CONN_TYPE_OR, socket_family);
+  tor_assert(type == CONN_TYPE_OR || type == CONN_TYPE_EXT_OR);
+  connection_init(now, TO_CONN(or_conn), type, socket_family);
 
   or_conn->timestamp_last_added_nonpadding = time(NULL);
 
+  if (type == CONN_TYPE_EXT_OR)
+    connection_or_set_ext_or_identifier(or_conn);
+
   return or_conn;
 }
 
@@ -335,7 +349,8 @@ connection_new(int type, int socket_family)
 {
   switch (type) {
     case CONN_TYPE_OR:
-      return TO_CONN(or_connection_new(socket_family));
+    case CONN_TYPE_EXT_OR:
+      return TO_CONN(or_connection_new(type, socket_family));
 
     case CONN_TYPE_EXIT:
       return TO_CONN(edge_connection_new(type, socket_family));
@@ -377,6 +392,7 @@ connection_init(time_t now, connection_t *conn, int type, int socket_family)
 
   switch (type) {
     case CONN_TYPE_OR:
+    case CONN_TYPE_EXT_OR:
       conn->magic = OR_CONNECTION_MAGIC;
       break;
     case CONN_TYPE_EXIT:
@@ -445,6 +461,7 @@ connection_free_(connection_t *conn)
 
   switch (conn->type) {
     case CONN_TYPE_OR:
+    case CONN_TYPE_EXT_OR:
       tor_assert(conn->magic == OR_CONNECTION_MAGIC);
       mem = TO_OR_CONN(conn);
       memlen = sizeof(or_connection_t);
@@ -575,6 +592,9 @@ connection_free_(connection_t *conn)
     log_warn(LD_BUG, "called on OR conn with non-zeroed identity_digest");
     connection_or_remove_from_identity_map(TO_OR_CONN(conn));
   }
+  if (conn->type == CONN_TYPE_OR || conn->type == CONN_TYPE_EXT_OR)
+    connection_or_remove_from_ext_or_id_map(TO_OR_CONN(conn));
+
 #ifdef USE_BUFFEREVENTS
   if (conn->type == CONN_TYPE_OR && TO_OR_CONN(conn)->bucket_cfg) {
     ev_token_bucket_cfg_free(TO_OR_CONN(conn)->bucket_cfg);
@@ -638,6 +658,7 @@ connection_about_to_close_connection(connection_t *conn)
       connection_dir_about_to_close(TO_DIR_CONN(conn));
       break;
     case CONN_TYPE_OR:
+    case CONN_TYPE_EXT_OR:
       connection_or_about_to_close(TO_OR_CONN(conn));
       break;
     case CONN_TYPE_AP:
@@ -1374,6 +1395,9 @@ connection_init_accepted_conn(connection_t *conn,
   connection_start_reading(conn);
 
   switch (conn->type) {
+    case CONN_TYPE_EXT_OR:
+      conn->state = EXT_OR_CONN_STATE_OPEN;
+      break;
     case CONN_TYPE_OR:
       control_event_or_conn_status(TO_OR_CONN(conn), OR_CONN_EVENT_NEW, 0);
       rv = connection_tls_start_handshake(TO_OR_CONN(conn), 1);
@@ -2886,6 +2910,8 @@ connection_handle_read_impl(connection_t *conn)
   switch (conn->type) {
     case CONN_TYPE_OR_LISTENER:
       return connection_handle_listener_read(conn, CONN_TYPE_OR);
+    case CONN_TYPE_EXT_OR_LISTENER:
+      return connection_handle_listener_read(conn, CONN_TYPE_EXT_OR);
     case CONN_TYPE_AP_LISTENER:
     case CONN_TYPE_AP_TRANS_LISTENER:
     case CONN_TYPE_AP_NATD_LISTENER:
@@ -3918,6 +3944,7 @@ int
 connection_is_listener(connection_t *conn)
 {
   if (conn->type == CONN_TYPE_OR_LISTENER ||
+      conn->type == CONN_TYPE_EXT_OR_LISTENER ||
       conn->type == CONN_TYPE_AP_LISTENER ||
       conn->type == CONN_TYPE_AP_TRANS_LISTENER ||
       conn->type == CONN_TYPE_AP_DNS_LISTENER ||
@@ -3940,6 +3967,7 @@ connection_state_is_open(connection_t *conn)
     return 0;
 
   if ((conn->type == CONN_TYPE_OR && conn->state == OR_CONN_STATE_OPEN) ||
+      (conn->type == CONN_TYPE_EXT_OR) ||
       (conn->type == CONN_TYPE_AP && conn->state == AP_CONN_STATE_OPEN) ||
       (conn->type == CONN_TYPE_EXIT && conn->state == EXIT_CONN_STATE_OPEN) ||
       (conn->type == CONN_TYPE_CONTROL &&
@@ -4109,6 +4137,8 @@ connection_process_inbuf(connection_t *conn, int package_partial)
   switch (conn->type) {
     case CONN_TYPE_OR:
       return connection_or_process_inbuf(TO_OR_CONN(conn));
+    case CONN_TYPE_EXT_OR:
+      return connection_ext_or_process_inbuf(TO_OR_CONN(conn));
     case CONN_TYPE_EXIT:
     case CONN_TYPE_AP:
       return connection_edge_process_inbuf(TO_EDGE_CONN(conn),
@@ -4169,6 +4199,8 @@ connection_finished_flushing(connection_t *conn)
   switch (conn->type) {
     case CONN_TYPE_OR:
       return connection_or_finished_flushing(TO_OR_CONN(conn));
+    case CONN_TYPE_EXT_OR:
+      return connection_ext_or_finished_flushing(TO_OR_CONN(conn));
     case CONN_TYPE_AP:
     case CONN_TYPE_EXIT:
       return connection_edge_finished_flushing(TO_EDGE_CONN(conn));
@@ -4224,6 +4256,7 @@ connection_reached_eof(connection_t *conn)
 {
   switch (conn->type) {
     case CONN_TYPE_OR:
+    case CONN_TYPE_EXT_OR:
       return connection_or_reached_eof(TO_OR_CONN(conn));
     case CONN_TYPE_AP:
     case CONN_TYPE_EXIT:
diff --git a/src/or/connection.h b/src/or/connection.h
index 3e656ec..5ca8ca3 100644
--- a/src/or/connection.h
+++ b/src/or/connection.h
@@ -19,7 +19,7 @@ const char *conn_type_to_string(int type);
 const char *conn_state_to_string(int type, int state);
 
 dir_connection_t *dir_connection_new(int socket_family);
-or_connection_t *or_connection_new(int socket_family);
+or_connection_t *or_connection_new(int type, int socket_family);
 edge_connection_t *edge_connection_new(int type, int socket_family);
 entry_connection_t *entry_connection_new(int type, int socket_family);
 control_connection_t *control_connection_new(int socket_family);
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 3616363..a6d1a8d 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -75,6 +75,9 @@ static void connection_or_handle_event_cb(struct bufferevent *bufev,
  * they form a linked list, with next_with_same_id as the next pointer. */
 static digestmap_t *orconn_identity_map = NULL;
 
+/**DOCDOC */
+static digestmap_t *orconn_ext_or_id_map = NULL;
+
 /** If conn is listed in orconn_identity_map, remove it, and clear
  * conn->identity_digest.  Otherwise do nothing. */
 void
@@ -174,6 +177,52 @@ connection_or_set_identity_digest(or_connection_t *conn, const char *digest)
 #endif
 }
 
+void
+connection_or_remove_from_ext_or_id_map(or_connection_t *conn)
+{
+  or_connection_t *tmp;
+  if (!orconn_identity_map)
+    orconn_identity_map = digestmap_new();
+
+  tmp = digestmap_remove(orconn_ext_or_id_map, conn->ext_or_conn_id);
+  if (!tor_digest_is_zero(conn->ext_or_conn_id))
+    tor_assert(tmp == conn);
+
+  memset(conn->ext_or_conn_id, 0, EXT_OR_CONN_ID_LEN);
+}
+
+
+/*DOCDOC*/
+void
+connection_or_clear_ext_or_id_map(void)
+{
+  digestmap_free(orconn_ext_or_id_map, NULL);
+}
+
+/*DOCDOC
+  sets it to a random value */
+void
+connection_or_set_ext_or_identifier(or_connection_t *conn)
+{
+  char random_id[EXT_OR_CONN_ID_LEN];
+  or_connection_t *tmp;
+
+  if (!orconn_ext_or_id_map)
+    orconn_ext_or_id_map = digestmap_new();
+
+  if (!tor_digest_is_zero(conn->ext_or_conn_id))
+      connection_or_remove_from_ext_or_id_map(conn);
+
+  do {
+    crypto_rand(random_id, sizeof(random_id));
+  } while (digestmap_get(orconn_ext_or_id_map, random_id));
+
+  memcpy(conn->ext_or_conn_id, random_id, EXT_OR_CONN_ID_LEN);
+
+  tmp = digestmap_set(orconn_ext_or_id_map, random_id, conn);
+  tor_assert(!tmp);
+}
+
 /**************************************************************/
 
 /** Map from a string describing what a non-open OR connection was doing when
@@ -228,7 +277,7 @@ connection_or_get_state_description(or_connection_t *orconn,
   const char *conn_state;
   char tls_state[256];
 
-  tor_assert(conn->type == CONN_TYPE_OR);
+  tor_assert(conn->type == CONN_TYPE_OR || conn->type == CONN_TYPE_EXT_OR);
 
   conn_state = conn_state_to_string(conn->type, conn->state);
   tor_tls_get_state_description(orconn->tls, tls_state, sizeof(tls_state));
@@ -423,6 +472,23 @@ var_cell_free(var_cell_t *cell)
   tor_free(cell);
 }
 
+/*DOCDOC*/
+ext_or_cmd_t *
+ext_or_cmd_new(uint16_t len)
+{
+  size_t size = STRUCT_OFFSET(ext_or_cmd_t, body) + len;
+  ext_or_cmd_t *cmd = tor_malloc(size);
+  cmd->len = len;
+  return cmd;
+}
+
+/*DOCDOC*/
+void
+ext_or_cmd_free(ext_or_cmd_t *cmd)
+{
+  tor_free(cmd);
+}
+
 /** We've received an EOF from <b>conn</b>. Mark it for close and return. */
 int
 connection_or_reached_eof(or_connection_t *conn)
@@ -1077,7 +1143,7 @@ connection_or_connect(const tor_addr_t *_addr, uint16_t port,
     return NULL;
   }
 
-  conn = or_connection_new(tor_addr_family(&addr));
+  conn = or_connection_new(CONN_TYPE_OR, tor_addr_family(&addr));
 
   /*
    * Set up conn so it's got all the data we need to remember for channels
@@ -1470,7 +1536,8 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event,
 int
 connection_or_nonopen_was_started_here(or_connection_t *conn)
 {
-  tor_assert(conn->base_.type == CONN_TYPE_OR);
+  tor_assert(conn->base_.type == CONN_TYPE_OR ||
+             conn->base_.type == CONN_TYPE_EXT_OR);
   if (!conn->tls)
     return 1; /* it's still in proxy states or something */
   if (conn->handshake_state)
@@ -2365,3 +2432,132 @@ connection_or_send_authenticate_cell(or_connection_t *conn, int authtype)
   return 0;
 }
 
+/*DOCDOC*/
+static int
+connection_fetch_ext_or_cmd_from_buf(connection_t *conn, ext_or_cmd_t **out)
+{
+  IF_HAS_BUFFEREVENT(conn, {
+    struct evbuffer *input = bufferevent_get_input(conn->bufev);
+    return fetch_ext_or_command_from_evbuffer(input, out);
+  }) ELSE_IF_NO_BUFFEREVENT {
+    return fetch_ext_or_command_from_buf(conn->inbuf, out);
+  }
+}
+
+/*DOCDOC*/
+static int
+connection_write_ext_or_command(connection_t *conn,
+                                uint16_t command,
+                                const char *body,
+                                size_t bodylen)
+{
+  char header[4];
+  if (bodylen > UINT16_MAX)
+    return -1;
+  set_uint16(header, htons(command));
+  set_uint16(header+2, htons(bodylen));
+  connection_write_to_buf(header, 4, conn);
+  if (bodylen) {
+    tor_assert(body);
+    connection_write_to_buf(body, bodylen, conn);
+  }
+  return 0;
+}
+
+/*DOCDOC*/
+static void
+connection_ext_or_transition(or_connection_t *conn)
+{
+  tor_assert(conn->base_.type == CONN_TYPE_EXT_OR);
+
+  conn->base_.type = CONN_TYPE_OR;
+  control_event_or_conn_status(conn, OR_CONN_EVENT_NEW, 0);
+  connection_tls_start_handshake(conn, 1);
+}
+
+/*XXXX make these match the spec .*/
+#define EXT_OR_CMD_DONE 0x0001
+#define EXT_OR_CMD_USERADDR 0x0002
+#define EXT_OR_CMD_WANT_CONTROL 0x0003
+#define EXT_OR_CMD_OKAY 0x1001
+
+/*DOCDOC*/
+int
+connection_ext_or_process_inbuf(or_connection_t *or_conn)
+{
+  connection_t *conn = TO_CONN(or_conn);
+  ext_or_cmd_t *command;
+  int r;
+
+  while (1) {
+    command = NULL;
+    r = connection_fetch_ext_or_cmd_from_buf(conn, &command);
+    if (r < 0)
+      return -1;
+    else if (r == 0)
+      return 0; /* need to wait for more data */
+
+    /* Got a command! */
+    tor_assert(command);
+
+    if (command->cmd == EXT_OR_CMD_DONE) {
+      if (connection_get_inbuf_len(conn)) {
+        /* The inbuf isn't empty; the client is misbehaving. */
+        goto err;
+      }
+      connection_write_ext_or_command(conn, EXT_OR_CMD_OKAY, NULL, 0);
+
+      /* can't transition immediately; need to flush first. */
+      conn->state = EXT_OR_CONN_STATE_FLUSHING;
+      connection_stop_reading(conn);
+    } else if (command->cmd == EXT_OR_CMD_USERADDR) {
+      /* Copy address string. */
+      tor_addr_t addr;
+      uint16_t port;
+      char *addr_str;
+      char *address_part=NULL;
+      int res;
+      addr_str = tor_malloc(command->len + 1);
+      memcpy(addr_str, command->body, command->len);
+      addr_str[command->len] = 0;
+
+      res = tor_addr_port_split(LOG_INFO, addr_str, &address_part, &port);
+      tor_free(addr_str);
+      if (res<0)
+        goto err;
+
+      res = tor_addr_parse(&addr, address_part);
+      tor_free(address_part);
+      if (res<0)
+        goto err;
+
+      /* record the address */
+      tor_addr_copy(&conn->addr, &addr);
+      conn->port = port;
+    } else if (command->cmd == EXT_OR_CMD_WANT_CONTROL) {
+      char response[128];
+      char *cp;
+      memcpy(response, or_conn->ext_or_conn_id, EXT_OR_CONN_ID_LEN);
+      cp = response+EXT_OR_CONN_ID_LEN;
+      /* XXXX write the TransportControlPort; advance cp. */
+      connection_write_ext_or_command(conn, EXT_OR_CMD_OKAY, response,
+                                      cp-response);
+    }
+
+    ext_or_cmd_free(command);
+  }
+
+ err:
+  ext_or_cmd_free(command);
+  return -1;
+}
+
+int
+connection_ext_or_finished_flushing(or_connection_t *conn)
+{
+  if (conn->base_.state == EXT_OR_CONN_STATE_FLUSHING) {
+    connection_start_reading(TO_CONN(conn));
+    connection_ext_or_transition(conn);
+  }
+  return 0;
+}
diff --git a/src/or/connection_or.h b/src/or/connection_or.h
index 85e68f1..a80871d 100644
--- a/src/or/connection_or.h
+++ b/src/or/connection_or.h
@@ -95,5 +95,14 @@ void var_cell_free(var_cell_t *cell);
 /** DOCDOC */
 #define MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS 4
 
+ext_or_cmd_t *ext_or_cmd_new(uint16_t len);
+void ext_or_cmd_free(ext_or_cmd_t *cmd);
+void connection_or_set_ext_or_identifier(or_connection_t *conn);
+void connection_or_remove_from_ext_or_id_map(or_connection_t *conn);
+void connection_or_clear_ext_or_id_map(void);
+
+int connection_ext_or_finished_flushing(or_connection_t *conn);
+int connection_ext_or_process_inbuf(or_connection_t *or_conn);
+
 #endif
 
diff --git a/src/or/or.h b/src/or/or.h
index 06363fa..2811f66 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -228,8 +228,13 @@ typedef enum {
 #define CONN_TYPE_AP_NATD_LISTENER 14
 /** Type for sockets listening for DNS requests. */
 #define CONN_TYPE_AP_DNS_LISTENER 15
-#define CONN_TYPE_MAX_ 15
-/* !!!! If CONN_TYPE_MAX_ is ever over 15, we must grow the type field in
+
+/** DOCDOC */
+#define CONN_TYPE_EXT_OR 16
+#define CONN_TYPE_EXT_OR_LISTENER 17
+
+#define CONN_TYPE_MAX_ 17
+/* !!!! If _CONN_TYPE_MAX is ever over 31, we must grow the type field in
  * connection_t. */
 
 /* Proxy client types */
@@ -309,6 +314,12 @@ typedef enum {
 #define OR_CONN_STATE_OPEN 8
 #define OR_CONN_STATE_MAX_ 8
 
+/*DOCDOC*/
+#define _EXT_OR_CONN_STATE_MIN 1
+#define EXT_OR_CONN_STATE_OPEN 1
+#define EXT_OR_CONN_STATE_FLUSHING 2
+#define _EXT_OR_CONN_STATE_MAX 2
+
 #define EXIT_CONN_STATE_MIN_ 1
 /** State for an exit connection: waiting for response from DNS farm. */
 #define EXIT_CONN_STATE_RESOLVING 1
@@ -1082,6 +1093,13 @@ typedef struct var_cell_t {
   uint8_t payload[FLEXIBLE_ARRAY_MEMBER];
 } var_cell_t;
 
+/* DOCDOC */
+typedef struct ext_or_cmd_t {
+  uint16_t cmd;
+  uint16_t len;
+  char body[FLEXIBLE_ARRAY_MEMBER];
+} ext_or_cmd_t;
+
 /** A cell as packed for writing to the network. */
 typedef struct packed_cell_t {
   /** Next cell queued on this circuit. */
@@ -1163,7 +1181,7 @@ typedef struct connection_t {
                    * *_CONNECTION_MAGIC. */
 
   uint8_t state; /**< Current state of this connection. */
-  unsigned int type:4; /**< What kind of connection is this? */
+  unsigned int type:5; /**< What kind of connection is this? */
   unsigned int purpose:5; /**< Only used for DIR and EXIT types currently. */
 
   /* The next fields are all one-bit booleans. Some are only applicable to
@@ -1405,6 +1423,9 @@ typedef struct or_handshake_state_t {
   /**@}*/
 } or_handshake_state_t;
 
+/* DOCDOC */
+#define EXT_OR_CONN_ID_LEN 20
+
 /** Subtype of connection_t for an "OR connection" -- that is, one that speaks
  * cells over TLS. */
 typedef struct or_connection_t {
@@ -1413,6 +1434,8 @@ typedef struct or_connection_t {
   /** Hash of the public RSA key for the other side's identity key, or zeroes
    * if the other side hasn't shown us a valid identity key. */
   char identity_digest[DIGEST_LEN];
+  /*DOCDOC*/
+  char ext_or_conn_id[EXT_OR_CONN_ID_LEN];
   char *nickname; /**< Nickname of OR on other side (if any). */
 
   tor_tls_t *tls; /**< TLS connection state. */
@@ -3428,6 +3451,8 @@ typedef struct {
   char *User; /**< Name of user to run Tor as. */
   char *Group; /**< Name of group to run Tor as. */
   config_line_t *ORPort_lines; /**< Ports to listen on for OR connections. */
+  /** Ports to listen on for extended OR connections. */
+  config_line_t *ExtORPort_lines;
   /** Ports to listen on for SOCKS connections. */
   config_line_t *SocksPort_lines;
   /** Ports to listen on for transparent pf/netfilter connections. */





More information about the tor-commits mailing list