[or-cvs] Don"t tell anybody, but we"re going OO here. This patch sp...

Nick Mathewson nickm at seul.org
Sun Jul 23 07:37:37 UTC 2006


Update of /home/or/cvsroot/tor/src/or
In directory moria:/tmp/cvs-serv28777/src/or

Modified Files:
	circuitbuild.c circuitlist.c circuituse.c command.c 
	connection_edge.c control.c cpuworker.c dns.c onion.c or.h 
	relay.c rendclient.c rendcommon.c rendmid.c rendservice.c 
Log Message:
Don't tell anybody, but we're going OO here.  This patch splits
circuit_t into origin_circuit_t and or_circuit_t.  I fixed some
segaults; there may be more.  We still need to move more rendezvous
stuff into subtypes.

This is a trial run for splitting up connection_t; if the approach is
insane, please say so soon so we can do something smarter.

Also, this discards the old HALF_OPEN code, which nobody seems to
want.



Index: circuitbuild.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/circuitbuild.c,v
retrieving revision 1.257
retrieving revision 1.258
diff -u -p -d -r1.257 -r1.258
--- circuitbuild.c	21 Jul 2006 07:06:18 -0000	1.257
+++ circuitbuild.c	23 Jul 2006 07:37:35 -0000	1.258
@@ -43,7 +43,7 @@ static int entry_guards_dirty = 0;
 
 static int circuit_deliver_create_cell(circuit_t *circ,
                                        uint8_t cell_type, char *payload);
-static int onion_pick_cpath_exit(circuit_t *circ, extend_info_t *exit);
+static int onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit);
 static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath);
 static int onion_extend_cpath(uint8_t purpose, crypt_path_t **head_ptr,
                               cpath_build_state_t *state);
@@ -95,14 +95,13 @@ get_unique_circ_id_by_conn(connection_t 
  * a more verbose format using spaces.
  */
 char *
-circuit_list_path(circuit_t *circ, int verbose)
+circuit_list_path(origin_circuit_t *circ, int verbose)
 {
   crypt_path_t *hop;
   smartlist_t *elements;
   const char *states[] = {"closed", "waiting for keys", "open"};
   char buf[128];
   char *s;
-  tor_assert(CIRCUIT_IS_ORIGIN(circ));
 
   elements = smartlist_create();
 
@@ -112,8 +111,8 @@ circuit_list_path(circuit_t *circ, int v
                  circ->build_state->is_internal ? "internal" : "exit",
                  circ->build_state->need_uptime ? " (high-uptime)" : "",
                  circ->build_state->desired_path_len,
-                 circ->state == CIRCUIT_STATE_OPEN ? "" : ", exit ",
-                 circ->state == CIRCUIT_STATE_OPEN ? "" :
+                 circ->_base.state == CIRCUIT_STATE_OPEN ? "" : ", exit ",
+                 circ->_base.state == CIRCUIT_STATE_OPEN ? "" :
                    (nickname?nickname:"*unnamed*"));
     smartlist_add(elements, tor_strdup(buf));
   }
@@ -152,7 +151,7 @@ circuit_list_path(circuit_t *circ, int v
  * exit point.
  */
 void
-circuit_log_path(int severity, unsigned int domain, circuit_t *circ)
+circuit_log_path(int severity, unsigned int domain, origin_circuit_t *circ)
 {
   char *s = circuit_list_path(circ,1);
   log(severity,domain,"%s",s);
@@ -165,7 +164,7 @@ circuit_log_path(int severity, unsigned 
  * unable to extend.
  */
 void
-circuit_rep_hist_note_result(circuit_t *circ)
+circuit_rep_hist_note_result(origin_circuit_t *circ)
 {
   crypt_path_t *hop;
   char *prev_digest = NULL;
@@ -206,74 +205,14 @@ circuit_rep_hist_note_result(circuit_t *
   } while (hop!=circ->cpath);
 }
 
-/** A helper function for circuit_dump_by_conn() below. Log a bunch
- * of information about circuit <b>circ</b>.
- */
-static void
-circuit_dump_details(int severity, circuit_t *circ, int poll_index,
-                     const char *type, int this_circid, int other_circid)
-{
-  log(severity, LD_CIRC, "Conn %d has %s circuit: circID %d (other side %d), "
-      "state %d (%s), born %d:",
-      poll_index, type, this_circid, other_circid, circ->state,
-      circuit_state_to_string(circ->state), (int)circ->timestamp_created);
-  if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */
-    circuit_log_path(severity, LD_CIRC, circ);
-  }
-}
-
-/** Log, at severity <b>severity</b>, information about each circuit
- * that is connected to <b>conn</b>.
- */
-void
-circuit_dump_by_conn(connection_t *conn, int severity)
-{
-  circuit_t *circ;
-  connection_t *tmpconn;
-
-  for (circ=global_circuitlist;circ;circ = circ->next) {
-    if (circ->marked_for_close)
-      continue;
-    if (circ->p_conn == conn)
-      circuit_dump_details(severity, circ, conn->poll_index, "App-ward",
-                           circ->p_circ_id, circ->n_circ_id);
-    for (tmpconn=circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream) {
-      if (tmpconn == conn) {
-        circuit_dump_details(severity, circ, conn->poll_index, "App-ward",
-                             circ->p_circ_id, circ->n_circ_id);
-      }
-    }
-    if (circ->n_conn == conn)
-      circuit_dump_details(severity, circ, conn->poll_index, "Exit-ward",
-                           circ->n_circ_id, circ->p_circ_id);
-    for (tmpconn=circ->n_streams; tmpconn; tmpconn=tmpconn->next_stream) {
-      if (tmpconn == conn) {
-        circuit_dump_details(severity, circ, conn->poll_index, "Exit-ward",
-                             circ->n_circ_id, circ->p_circ_id);
-      }
-    }
-    if (!circ->n_conn && circ->n_addr && circ->n_port &&
-        circ->n_addr == conn->addr &&
-        circ->n_port == conn->port &&
-        !memcmp(conn->identity_digest, circ->n_conn_id_digest, DIGEST_LEN)) {
-      circuit_dump_details(severity, circ, conn->poll_index,
-                           (circ->state == CIRCUIT_STATE_OPEN &&
-                            !CIRCUIT_IS_ORIGIN(circ)) ?
-                             "Endpoint" : "Pending",
-                           circ->n_circ_id, circ->p_circ_id);
-    }
-  }
-}
-
 /** Pick all the entries in our cpath. Stop and return 0 when we're
  * happy, or return -1 if an error occurs. */
 static int
-onion_populate_cpath(circuit_t *circ)
+onion_populate_cpath(origin_circuit_t *circ)
 {
   int r;
 again:
-  r = onion_extend_cpath(circ->purpose, &circ->cpath, circ->build_state);
-//    || !CIRCUIT_IS_ORIGIN(circ)) { // wtf? -rd
+  r = onion_extend_cpath(circ->_base.purpose, &circ->cpath, circ->build_state);
   if (r < 0) {
     log_info(LD_CIRC,"Generating cpath hop failed.");
     return -1;
@@ -283,19 +222,20 @@ again:
   return 0; /* if r == 1 */
 }
 
-/** Create and return a new circuit. Initialize its purpose and
+/** Create and return a new origin circuit. Initialize its purpose and
  * build-state based on our arguments. */
-circuit_t *
-circuit_init(uint8_t purpose, int need_uptime, int need_capacity, int internal)
+origin_circuit_t *
+origin_circuit_init(uint8_t purpose, int need_uptime, int need_capacity,
+                    int internal)
 {
   /* sets circ->p_circ_id and circ->p_conn */
-  circuit_t *circ = circuit_new(0, NULL);
-  circuit_set_state(circ, CIRCUIT_STATE_OR_WAIT);
+  origin_circuit_t *circ = origin_circuit_new();
+  circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OR_WAIT);
   circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
   circ->build_state->need_uptime = need_uptime;
   circ->build_state->need_capacity = need_capacity;
   circ->build_state->is_internal = internal;
-  circ->purpose = purpose;
+  circ->_base.purpose = purpose;
   return circ;
 }
 
@@ -306,24 +246,24 @@ circuit_init(uint8_t purpose, int need_u
  * Also launch a connection to the first OR in the chosen path, if
  * it's not open already.
  */
-circuit_t *
+origin_circuit_t *
 circuit_establish_circuit(uint8_t purpose, extend_info_t *info,
                           int need_uptime, int need_capacity, int internal)
 {
-  circuit_t *circ;
+  origin_circuit_t *circ;
 
-  circ = circuit_init(purpose, need_uptime, need_capacity, internal);
+  circ = origin_circuit_init(purpose, need_uptime, need_capacity, internal);
 
   if (onion_pick_cpath_exit(circ, info) < 0 ||
       onion_populate_cpath(circ) < 0) {
-    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
     return NULL;
   }
 
   control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED);
 
   if (circuit_handle_first_hop(circ) < 0) {
-    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
     return NULL;
   }
   return circ;
@@ -334,7 +274,7 @@ circuit_establish_circuit(uint8_t purpos
  * it. If we're already connected, then send the 'create' cell.
  * Return 0 for ok, -1 if circ should be marked-for-close. */
 int
-circuit_handle_first_hop(circuit_t *circ)
+circuit_handle_first_hop(origin_circuit_t *circ)
 {
   crypt_path_t *firsthop;
   connection_t *n_conn;
@@ -351,7 +291,7 @@ circuit_handle_first_hop(circuit_t *circ
   log_debug(LD_CIRC,"Looking for firsthop '%s:%u'",tmpbuf,
             firsthop->extend_info->port);
   /* imprint the circuit with its future n_conn->id */
-  memcpy(circ->n_conn_id_digest, firsthop->extend_info->identity_digest,
+  memcpy(circ->_base.n_conn_id_digest, firsthop->extend_info->identity_digest,
          DIGEST_LEN);
   n_conn = connection_or_get_by_identity_digest(
          firsthop->extend_info->identity_digest);
@@ -363,8 +303,8 @@ circuit_handle_first_hop(circuit_t *circ
        router_digest_version_as_new_as(firsthop->extend_info->identity_digest,
                                        "0.1.1.9-alpha-cvs"))) {
     /* not currently connected */
-    circ->n_addr = firsthop->extend_info->addr;
-    circ->n_port = firsthop->extend_info->port;
+    circ->_base.n_addr = firsthop->extend_info->addr;
+    circ->_base.n_port = firsthop->extend_info->port;
 
     if (!n_conn || n_conn->is_obsolete) { /* launch the connection */
       n_conn = connection_or_connect(firsthop->extend_info->addr,
@@ -383,9 +323,9 @@ circuit_handle_first_hop(circuit_t *circ
      */
     return 0;
   } else { /* it's already open. use it. */
-    circ->n_addr = n_conn->addr;
-    circ->n_port = n_conn->port;
-    circ->n_conn = n_conn;
+    circ->_base.n_addr = n_conn->addr;
+    circ->_base.n_port = n_conn->port;
+    circ->_base.n_conn = n_conn;
     log_debug(LD_CIRC,"Conn open. Delivering first onion skin.");
     if (circuit_send_next_onion_skin(circ) < 0) {
       log_info(LD_CIRC,"circuit_send_next_onion_skin failed.");
@@ -433,7 +373,7 @@ circuit_n_conn_done(connection_t *or_con
        * set_circid_orconn here. */
       circ->n_conn = or_conn;
       if (CIRCUIT_IS_ORIGIN(circ)) {
-        if (circuit_send_next_onion_skin(circ) < 0) {
+        if (circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ)) < 0) {
           log_info(LD_CIRC,
                    "send_next_onion_skin failed; circuit marked for closing.");
           circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
@@ -471,7 +411,8 @@ circuit_n_conn_done(connection_t *or_con
  * Return -1 if we failed to find a suitable circid, else return 0.
  */
 static int
-circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type, char *payload)
+circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type,
+                            char *payload)
 {
   cell_t cell;
   uint16_t id;
@@ -488,7 +429,7 @@ circuit_deliver_create_cell(circuit_t *c
     return -1;
   }
   log_debug(LD_CIRC,"Chosen circID %u.", id);
-  circuit_set_circid_orconn(circ, id, circ->n_conn, N_CONN_CHANGED);
+  circuit_set_n_circid_orconn(circ, id, circ->n_conn);
 
   memset(&cell, 0, sizeof(cell_t));
   cell.command = cell_type;
@@ -552,7 +493,7 @@ extern int has_completed_circuit;
  * Return -reason if we want to tear down circ, else return 0.
  */
 int
-circuit_send_next_onion_skin(circuit_t *circ)
+circuit_send_next_onion_skin(origin_circuit_t *circ)
 {
   crypt_path_t *hop;
   routerinfo_t *router;
@@ -561,14 +502,13 @@ circuit_send_next_onion_skin(circuit_t *
   size_t payload_len;
 
   tor_assert(circ);
-  tor_assert(CIRCUIT_IS_ORIGIN(circ));
 
   if (circ->cpath->state == CPATH_STATE_CLOSED) {
     int fast;
     uint8_t cell_type;
     log_debug(LD_CIRC,"First skin; sending create cell.");
 
-    router = router_get_by_digest(circ->n_conn->identity_digest);
+    router = router_get_by_digest(circ->_base.n_conn->identity_digest);
     fast = should_use_create_fast_for_router(router);
     if (! fast) {
       /* We are an OR, or we are connecting to an old Tor: we should
@@ -593,22 +533,22 @@ circuit_send_next_onion_skin(circuit_t *
              sizeof(circ->cpath->fast_handshake_state));
     }
 
-    if (circuit_deliver_create_cell(circ, cell_type, payload) < 0)
+    if (circuit_deliver_create_cell(TO_CIRCUIT(circ), cell_type, payload) < 0)
       return - END_CIRC_REASON_RESOURCELIMIT;
 
     circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
-    circuit_set_state(circ, CIRCUIT_STATE_BUILDING);
+    circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING);
     log_info(LD_CIRC,"First hop: finished sending %s cell to '%s'",
              fast ? "CREATE_FAST" : "CREATE",
              router ? router->nickname : "<unnamed>");
   } else {
     tor_assert(circ->cpath->state == CPATH_STATE_OPEN);
-    tor_assert(circ->state == CIRCUIT_STATE_BUILDING);
+    tor_assert(circ->_base.state == CIRCUIT_STATE_BUILDING);
     log_debug(LD_CIRC,"starting to send subsequent skin.");
     hop = onion_next_hop_in_cpath(circ->cpath);
     if (!hop) {
       /* done building the circuit. whew. */
-      circuit_set_state(circ, CIRCUIT_STATE_OPEN);
+      circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
       log_info(LD_CIRC,"circuit built!");
       circuit_reset_failure_count(0);
       if (!has_completed_circuit) {
@@ -645,7 +585,8 @@ circuit_send_next_onion_skin(circuit_t *
     log_debug(LD_CIRC,"Sending extend relay cell.");
     /* send it to hop->prev, because it will transfer
      * it to a create cell and then send to hop */
-    if (connection_edge_send_command(NULL, circ, RELAY_COMMAND_EXTEND,
+    if (connection_edge_send_command(NULL, TO_CIRCUIT(circ),
+                                     RELAY_COMMAND_EXTEND,
                                      payload, payload_len, hop->prev) < 0)
       return 0; /* circuit is closed */
 
@@ -820,12 +761,12 @@ circuit_init_cpath_crypto(crypt_path_t *
  * Return - reason if we want to mark circ for close, else return 0.
  */
 int
-circuit_finish_handshake(circuit_t *circ, uint8_t reply_type, char *reply)
+circuit_finish_handshake(origin_circuit_t *circ, uint8_t reply_type,
+                         char *reply)
 {
   char keys[CPATH_KEY_MATERIAL_LEN];
   crypt_path_t *hop;
 
-  tor_assert(CIRCUIT_IS_ORIGIN(circ));
   if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS)
     hop = circ->cpath;
   else {
@@ -883,20 +824,19 @@ circuit_finish_handshake(circuit_t *circ
  * just give up: for circ to close, and return 0.
  */
 int
-circuit_truncated(circuit_t *circ, crypt_path_t *layer)
+circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer)
 {
 //  crypt_path_t *victim;
 //  connection_t *stream;
 
   tor_assert(circ);
-  tor_assert(CIRCUIT_IS_ORIGIN(circ));
   tor_assert(layer);
 
   /* XXX Since we don't ask for truncates currently, getting a truncated
    *     means that a connection broke or an extend failed. For now,
    *     just give up.
    */
-  circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+  circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
   return 0;
 
 #if 0
@@ -929,7 +869,8 @@ circuit_truncated(circuit_t *circ, crypt
  * cell back.
  */
 int
-onionskin_answer(circuit_t *circ, uint8_t cell_type, char *payload, char *keys)
+onionskin_answer(or_circuit_t *circ, uint8_t cell_type, char *payload,
+                 char *keys)
 {
   cell_t cell;
   crypt_path_t *tmp_cpath;
@@ -941,7 +882,7 @@ onionskin_answer(circuit_t *circ, uint8_
   cell.command = cell_type;
   cell.circ_id = circ->p_circ_id;
 
-  circuit_set_state(circ, CIRCUIT_STATE_OPEN);
+  circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
 
   memcpy(cell.payload, payload,
          cell_type == CELL_CREATED ? ONIONSKIN_REPLY_LEN : DIGEST_LEN*2);
@@ -1338,13 +1279,13 @@ choose_good_exit_server(uint8_t purpose,
  * router (or use <b>exit</b> if provided). Store these in the
  * cpath. Return 0 if ok, -1 if circuit should be closed. */
 static int
-onion_pick_cpath_exit(circuit_t *circ, extend_info_t *exit)
+onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit)
 {
   cpath_build_state_t *state = circ->build_state;
   routerlist_t *rl = router_get_routerlist();
   int r;
 
-  r = new_route_len(get_options()->PathlenCoinWeight, circ->purpose,
+  r = new_route_len(get_options()->PathlenCoinWeight, circ->_base.purpose,
                     exit, rl->routers);
   if (r < 1) /* must be at least 1 */
     return -1;
@@ -1355,8 +1296,8 @@ onion_pick_cpath_exit(circuit_t *circ, e
     exit = extend_info_dup(exit);
   } else { /* we have to decide one */
     routerinfo_t *router =
-           choose_good_exit_server(circ->purpose, rl, state->need_uptime,
-                                   state->need_capacity, state->is_internal);
+      choose_good_exit_server(circ->_base.purpose, rl, state->need_uptime,
+                              state->need_capacity, state->is_internal);
     if (!router) {
       log_warn(LD_CIRC,"failed to choose an exit server");
       return -1;
@@ -1372,11 +1313,11 @@ onion_pick_cpath_exit(circuit_t *circ, e
  * the caller will do this if it wants to.
  */
 int
-circuit_append_new_exit(circuit_t *circ, extend_info_t *info)
+circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info)
 {
   cpath_build_state_t *state;
   tor_assert(info);
-  tor_assert(circ && CIRCUIT_IS_ORIGIN(circ));
+  tor_assert(circ);
 
   state = circ->build_state;
   tor_assert(state);
@@ -1394,15 +1335,14 @@ circuit_append_new_exit(circuit_t *circ,
  * send the next extend cell to begin connecting to that hop.
  */
 int
-circuit_extend_to_new_exit(circuit_t *circ, extend_info_t *info)
+circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info)
 {
-  tor_assert(CIRCUIT_IS_ORIGIN(circ));
   circuit_append_new_exit(circ, info);
-  circuit_set_state(circ, CIRCUIT_STATE_BUILDING);
+  circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING);
   if (circuit_send_next_onion_skin(circ)<0) {
     log_warn(LD_CIRC, "Couldn't extend circuit to new point '%s'.",
              info->nickname);
-    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
     return -1;
   }
   return 0;

Index: circuitlist.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/circuitlist.c,v
retrieving revision 1.93
retrieving revision 1.94
diff -u -p -d -r1.93 -r1.94
--- circuitlist.c	3 Apr 2006 11:24:14 -0000	1.93
+++ circuitlist.c	23 Jul 2006 07:37:35 -0000	1.94
@@ -68,35 +68,14 @@ HT_GENERATE(orconn_circid_map, orconn_ci
  */
 orconn_circid_circuit_map_t *_last_circid_orconn_ent = NULL;
 
-/** Set the p_conn or n_conn field of a circuit <b>circ</b>, along
- * with the corresponding circuit ID, and add the circuit as appropriate
- * to the (orconn,id)-\>circuit map. */
-void
-circuit_set_circid_orconn(circuit_t *circ, uint16_t id,
-                          connection_t *conn,
-                          enum which_conn_changed_t which)
+static void
+circuit_set_circid_orconn_helper(circuit_t *circ, uint16_t id,
+                                 connection_t *conn,
+                                 uint16_t old_id, connection_t *old_conn)
 {
-  uint16_t old_id;
-  connection_t *old_conn;
   orconn_circid_circuit_map_t search;
   orconn_circid_circuit_map_t *found;
 
-  tor_assert(!conn || conn->type == CONN_TYPE_OR);
-
-  if (which == P_CONN_CHANGED) {
-    old_id = circ->p_circ_id;
-    old_conn = circ->p_conn;
-    circ->p_circ_id = id;
-    circ->p_conn = conn;
-  } else {
-    old_id = circ->n_circ_id;
-    old_conn = circ->n_conn;
-    circ->n_circ_id = id;
-    circ->n_conn = conn;
-  }
-  if (conn == old_conn && old_id == id)
-    return;
-
   if (_last_circid_orconn_ent &&
       ((old_id == _last_circid_orconn_ent->circ_id &&
         old_conn == _last_circid_orconn_ent->or_conn) ||
@@ -135,6 +114,47 @@ circuit_set_circid_orconn(circuit_t *cir
   ++conn->n_circuits;
 }
 
+/** Set the p_conn field of a circuit <b>circ</b>, along
+ * with the corresponding circuit ID, and add the circuit as appropriate
+ * to the (orconn,id)-\>circuit map. */
+void
+circuit_set_p_circid_orconn(or_circuit_t *circ, uint16_t id,
+                            connection_t *conn)
+{
+  uint16_t old_id;
+  connection_t *old_conn;
+
+  old_id = circ->p_circ_id;
+  old_conn = circ->p_conn;
+  circ->p_circ_id = id;
+  circ->p_conn = conn;
+
+  if (id == old_id && conn == old_conn)
+    return;
+  circuit_set_circid_orconn_helper(TO_CIRCUIT(circ), id, conn,
+                                   old_id, old_conn);
+}
+
+/** Set the n_conn field of a circuit <b>circ</b>, along
+ * with the corresponding circuit ID, and add the circuit as appropriate
+ * to the (orconn,id)-\>circuit map. */
+void
+circuit_set_n_circid_orconn(circuit_t *circ, uint16_t id,
+                            connection_t *conn)
+{
+  uint16_t old_id;
+  connection_t *old_conn;
+
+  old_id = circ->n_circ_id;
+  old_conn = circ->n_conn;
+  circ->n_circ_id = id;
+  circ->n_conn = conn;
+
+  if (id == old_id && conn == old_conn)
+    return;
+  circuit_set_circid_orconn_helper(circ, id, conn, old_id, old_conn);
+}
+
 /** Change the state of <b>circ</b> to <b>state</b>, adding it to or removing
  * it from lists as appropriate. */
 void
@@ -224,36 +244,53 @@ circuit_state_to_string(int state)
   }
 }
 
-/** Allocate space for a new circuit, initializing with <b>p_circ_id</b>
- * and <b>p_conn</b>. Add it to the global circuit list.
- */
-circuit_t *
-circuit_new(uint16_t p_circ_id, connection_t *p_conn)
+/* DOCDOC */
+static void
+init_circuit_base(circuit_t *circ)
 {
-  circuit_t *circ;
   static uint32_t n_circuits_allocated = 1;
   /* never zero, since a global ID of 0 is treated specially by the
    * controller */
-
-  circ = tor_malloc_zero(sizeof(circuit_t));
-  circ->magic = CIRCUIT_MAGIC;
-
   circ->timestamp_created = time(NULL);
 
-  /* CircIDs */
-  if (p_conn) {
-    circuit_set_circid_orconn(circ, p_circ_id, p_conn, P_CONN_CHANGED);
-  }
-  /* circ->n_circ_id remains 0 because we haven't identified the next hop
-   * yet */
-
   circ->package_window = CIRCWINDOW_START;
   circ->deliver_window = CIRCWINDOW_START;
-
-  circ->next_stream_id = crypto_rand_int(1<<16);
   circ->global_identifier = n_circuits_allocated++;
 
   circuit_add(circ);
+}
+
+/** Allocate space for a new circuit, initializing with <b>p_circ_id</b>
+ * and <b>p_conn</b>. Add it to the global circuit list.
+ */
+origin_circuit_t *
+origin_circuit_new(void)
+{
+  origin_circuit_t *circ;
+
+  circ = tor_malloc_zero(sizeof(origin_circuit_t));
+  circ->_base.magic = ORIGIN_CIRCUIT_MAGIC;
+
+  circ->next_stream_id = crypto_rand_int(1<<16);
+
+  init_circuit_base(TO_CIRCUIT(circ));
+
+  return circ;
+}
+
+or_circuit_t *
+or_circuit_new(uint16_t p_circ_id, connection_t *p_conn)
+{
+  /* CircIDs */
+  or_circuit_t *circ;
+
+  circ = tor_malloc_zero(sizeof(or_circuit_t));
+  circ->_base.magic = OR_CIRCUIT_MAGIC;
+
+  if (p_conn)
+    circuit_set_p_circid_orconn(circ, p_circ_id, p_conn);
+
+  init_circuit_base(TO_CIRCUIT(circ));
 
   return circ;
 }
@@ -263,35 +300,53 @@ circuit_new(uint16_t p_circ_id, connecti
 static void
 circuit_free(circuit_t *circ)
 {
+  void *mem;
   tor_assert(circ);
-  tor_assert(circ->magic == CIRCUIT_MAGIC);
-  if (circ->n_crypto)
-    crypto_free_cipher_env(circ->n_crypto);
-  if (circ->p_crypto)
-    crypto_free_cipher_env(circ->p_crypto);
-  if (circ->n_digest)
-    crypto_free_digest_env(circ->n_digest);
-  if (circ->p_digest)
-    crypto_free_digest_env(circ->p_digest);
-  if (circ->build_state) {
-    if (circ->build_state->chosen_exit)
-      extend_info_free(circ->build_state->chosen_exit);
-    if (circ->build_state->pending_final_cpath)
-      circuit_free_cpath_node(circ->build_state->pending_final_cpath);
-  }
-  tor_free(circ->build_state);
-  tor_free(circ->onionskin);
-  circuit_free_cpath(circ->cpath);
-  if (circ->rend_splice) {
-    tor_assert(circ->rend_splice->magic == CIRCUIT_MAGIC);
-    circ->rend_splice->rend_splice = NULL;
+  if (CIRCUIT_IS_ORIGIN(circ)) {
+    origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
+    mem = ocirc;
+    tor_assert(circ->magic == ORIGIN_CIRCUIT_MAGIC);
+    if (ocirc->build_state) {
+      if (ocirc->build_state->chosen_exit)
+        extend_info_free(ocirc->build_state->chosen_exit);
+      if (ocirc->build_state->pending_final_cpath)
+        circuit_free_cpath_node(ocirc->build_state->pending_final_cpath);
+    }
+    tor_free(ocirc->build_state);
+
+    circuit_free_cpath(ocirc->cpath);
+
+  } else {
+    or_circuit_t *ocirc = TO_OR_CIRCUIT(circ);
+    mem = ocirc;
+    tor_assert(circ->magic == OR_CIRCUIT_MAGIC);
+
+    if (ocirc->p_crypto)
+      crypto_free_cipher_env(ocirc->p_crypto);
+    if (ocirc->p_digest)
+      crypto_free_digest_env(ocirc->p_digest);
+    if (ocirc->n_crypto)
+      crypto_free_cipher_env(ocirc->n_crypto);
+    if (ocirc->n_digest)
+      crypto_free_digest_env(ocirc->n_digest);
+
+    if (ocirc->rend_splice) {
+      or_circuit_t *other = ocirc->rend_splice;
+      tor_assert(other->_base.magic == OR_CIRCUIT_MAGIC);
+      other->rend_splice = NULL;
+    }
+
+    tor_free(circ->onionskin);
+
+    /* remove from map. */
+    circuit_set_p_circid_orconn(ocirc, 0, NULL);
   }
+
   /* Remove from map. */
-  circuit_set_circid_orconn(circ, 0, NULL, P_CONN_CHANGED);
-  circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED);
+  circuit_set_n_circid_orconn(circ, 0, NULL);
 
   memset(circ, 0xAA, sizeof(circuit_t)); /* poison memory */
-  tor_free(circ);
+  tor_free(mem);
 }
 
 /** Deallocate space associated with the linked list <b>cpath</b>. */
@@ -321,11 +376,14 @@ circuit_free_all(void)
   circuit_t *next;
   while (global_circuitlist) {
     next = global_circuitlist->next;
-    while (global_circuitlist->resolving_streams) {
-      connection_t *next;
-      next = global_circuitlist->resolving_streams->next_stream;
-      connection_free(global_circuitlist->resolving_streams);
-      global_circuitlist->resolving_streams = next;
+    if (! CIRCUIT_IS_ORIGIN(global_circuitlist)) {
+      or_circuit_t *or_circ = TO_OR_CIRCUIT(global_circuitlist);
+      while (or_circ->resolving_streams) {
+        connection_t *next;
+        next = or_circ->resolving_streams->next_stream;
+        connection_free(or_circ->resolving_streams);
+        or_circ->resolving_streams = next;
+      }
     }
     circuit_free(global_circuitlist);
     global_circuitlist = next;
@@ -358,6 +416,76 @@ circuit_free_cpath_node(crypt_path_t *vi
   tor_free(victim);
 }
 
+/** A helper function for circuit_dump_by_conn() below. Log a bunch
+ * of information about circuit <b>circ</b>.
+ */
+static void
+circuit_dump_details(int severity, circuit_t *circ, int poll_index,
+                     const char *type, int this_circid, int other_circid)
+{
+  log(severity, LD_CIRC, "Conn %d has %s circuit: circID %d (other side %d), "
+      "state %d (%s), born %d:",
+      poll_index, type, this_circid, other_circid, circ->state,
+      circuit_state_to_string(circ->state), (int)circ->timestamp_created);
+  if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */
+    circuit_log_path(severity, LD_CIRC, TO_ORIGIN_CIRCUIT(circ));
+  }
+}
+
+/** Log, at severity <b>severity</b>, information about each circuit
+ * that is connected to <b>conn</b>.
+ */
+void
+circuit_dump_by_conn(connection_t *conn, int severity)
+{
+  circuit_t *circ;
+  connection_t *tmpconn;
+
+  for (circ=global_circuitlist;circ;circ = circ->next) {
+    circid_t n_circ_id = circ->n_circ_id, p_circ_id = 0;
+    if (circ->marked_for_close)
+      continue;
+
+    if (! CIRCUIT_IS_ORIGIN(circ))
+      p_circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
+
+    if (! CIRCUIT_IS_ORIGIN(circ) && TO_OR_CIRCUIT(circ)->p_conn == conn)
+      circuit_dump_details(severity, circ, conn->poll_index, "App-ward",
+                           p_circ_id, n_circ_id);
+    if (CIRCUIT_IS_ORIGIN(circ)) {
+      for (tmpconn=TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn;
+           tmpconn=tmpconn->next_stream) {
+        if (tmpconn == conn) {
+          circuit_dump_details(severity, circ, conn->poll_index, "App-ward",
+                               p_circ_id, n_circ_id);
+        }
+      }
+    }
+    if (circ->n_conn == conn)
+      circuit_dump_details(severity, circ, conn->poll_index, "Exit-ward",
+                           n_circ_id, p_circ_id);
+    if (! CIRCUIT_IS_ORIGIN(circ)) {
+      for (tmpconn=TO_OR_CIRCUIT(circ)->n_streams; tmpconn;
+           tmpconn=tmpconn->next_stream) {
+        if (tmpconn == conn) {
+          circuit_dump_details(severity, circ, conn->poll_index, "Exit-ward",
+                               n_circ_id, p_circ_id);
+        }
+      }
+    }
+    if (!circ->n_conn && circ->n_addr && circ->n_port &&
+        circ->n_addr == conn->addr &&
+        circ->n_port == conn->port &&
+        !memcmp(conn->identity_digest, circ->n_conn_id_digest, DIGEST_LEN)) {
+      circuit_dump_details(severity, circ, conn->poll_index,
+                           (circ->state == CIRCUIT_STATE_OPEN &&
+                            !CIRCUIT_IS_ORIGIN(circ)) ?
+                             "Endpoint" : "Pending",
+                           n_circ_id, p_circ_id);
+    }
+  }
+}
+
 /** Return the circuit whose global ID is <b>id</b>, or NULL if no
  * such circuit exists. */
 circuit_t *
@@ -407,10 +535,13 @@ circuit_get_by_circid_orconn_impl(uint16
   {
     circuit_t *circ;
     for (circ=global_circuitlist;circ;circ = circ->next) {
-      if (circ->p_conn == conn && circ->p_circ_id == circ_id) {
-        log_warn(LD_BUG,
-                 "circuit matches p_conn, but not in hash table (Bug!)");
-        return circ;
+      if (! CIRCUIT_IS_ORIGIN(circ)) {
+        or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
+        if (or_circ->p_conn == conn && or_circ->p_circ_id == circ_id) {
+          log_warn(LD_BUG,
+                   "circuit matches p_conn, but not in hash table (Bug!)");
+          return circ;
+        }
       }
       if (circ->n_conn == conn && circ->n_circ_id == circ_id) {
         log_warn(LD_BUG,
@@ -462,7 +593,9 @@ circuit_get_by_edge_conn(connection_t *c
   tor_assert(CONN_IS_EDGE(conn));
 
   circ = conn->on_circuit;
-  tor_assert(!circ || circ->magic == CIRCUIT_MAGIC);
+  tor_assert(!circ ||
+             (CIRCUIT_IS_ORIGIN(circ) ? circ->magic == ORIGIN_CIRCUIT_MAGIC
+                                      : circ->magic == OR_CIRCUIT_MAGIC));
 
   return circ;
 }
@@ -476,14 +609,20 @@ circuit_unlink_all_from_or_conn(connecti
 {
   circuit_t *circ;
   for (circ = global_circuitlist; circ; circ = circ->next) {
-    if (circ->n_conn == conn || circ->p_conn == conn) {
-      if (circ->n_conn == conn)
-        circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED);
-      if (circ->p_conn == conn)
-        circuit_set_circid_orconn(circ, 0, NULL, P_CONN_CHANGED);
-      if (!circ->marked_for_close)
-        circuit_mark_for_close(circ, reason);
+    int mark = 0;
+    if (circ->n_conn == conn) {
+        circuit_set_n_circid_orconn(circ, 0, NULL);
+        mark = 1;
     }
+    if (! CIRCUIT_IS_ORIGIN(circ)) {
+      or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
+      if (or_circ->p_conn == conn) {
+        circuit_set_p_circid_orconn(or_circ, 0, NULL);
+        mark = 1;
+      }
+    }
+    if (mark && !circ->marked_for_close)
+      circuit_mark_for_close(circ, reason);
   }
 }
 
@@ -536,7 +675,7 @@ circuit_get_next_by_pk_and_purpose(circu
 /** Return the circuit waiting for a rendezvous with the provided cookie.
  * Return NULL if no such circuit is found.
  */
-circuit_t *
+or_circuit_t *
 circuit_get_rendezvous(const char *cookie)
 {
   circuit_t *circ;
@@ -544,7 +683,7 @@ circuit_get_rendezvous(const char *cooki
     if (! circ->marked_for_close &&
         circ->purpose == CIRCUIT_PURPOSE_REND_POINT_WAITING &&
         ! memcmp(circ->rend_cookie, cookie, REND_COOKIE_LEN) )
-      return circ;
+      return TO_OR_CIRCUIT(circ);
   }
   return NULL;
 }
@@ -559,41 +698,43 @@ circuit_get_rendezvous(const char *cooki
  *
  * Only return internal circuits if that is requested.
  */
-circuit_t *
+origin_circuit_t *
 circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
                             int need_uptime,
                             int need_capacity, int internal)
 {
-  circuit_t *circ;
-  circuit_t *best=NULL;
+  circuit_t *_circ;
+  origin_circuit_t *best=NULL;
 
   log_debug(LD_CIRC,
             "Hunting for a circ to cannibalize: purpose %d, uptime %d, "
             "capacity %d, internal %d",
             purpose, need_uptime, need_capacity, internal);
 
-  for (circ=global_circuitlist; circ; circ = circ->next) {
-    if (CIRCUIT_IS_ORIGIN(circ) &&
-        circ->state == CIRCUIT_STATE_OPEN &&
-        !circ->marked_for_close &&
-        circ->purpose == purpose &&
-        !circ->timestamp_dirty &&
-        (!need_uptime || circ->build_state->need_uptime) &&
-        (!need_capacity || circ->build_state->need_capacity) &&
-        (internal == circ->build_state->is_internal)) {
-      if (info) {
-        /* need to make sure we don't duplicate hops */
-        crypt_path_t *hop = circ->cpath;
-        do {
-          if (!memcmp(hop->extend_info->identity_digest,
-                      info->identity_digest, DIGEST_LEN))
-            goto next;
-          hop=hop->next;
-        } while (hop!=circ->cpath);
-      }
-      if (!best || (best->build_state->need_uptime && !need_uptime))
-        best = circ;
+  for (_circ=global_circuitlist; _circ; _circ = _circ->next) {
+    if (CIRCUIT_IS_ORIGIN(_circ) &&
+        _circ->state == CIRCUIT_STATE_OPEN &&
+        !_circ->marked_for_close &&
+        _circ->purpose == purpose &&
+        !_circ->timestamp_dirty) {
+      origin_circuit_t *circ = TO_ORIGIN_CIRCUIT(_circ);
+      if ((!need_uptime || circ->build_state->need_uptime) &&
+          (!need_capacity || circ->build_state->need_capacity) &&
+          (internal == circ->build_state->is_internal)) {
+        if (info) {
+          /* need to make sure we don't duplicate hops */
+          crypt_path_t *hop = circ->cpath;
+          do {
+            if (!memcmp(hop->extend_info->identity_digest,
+                        info->identity_digest, DIGEST_LEN))
+              goto next;
+            hop=hop->next;
+          } while (hop!=circ->cpath);
+        }
+        if (!best || (best->build_state->need_uptime && !need_uptime))
+          best = circ;
       next: ;
+      }
     }
   }
   return best;
@@ -685,7 +826,7 @@ _circuit_mark_for_close(circuit_t *circ,
   }
 
   if (circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
-    onion_pending_remove(circ);
+    onion_pending_remove(TO_OR_CIRCUIT(circ));
   }
   /* If the circuit ever became OPEN, we sent it to the reputation history
    * module then.  If it isn't OPEN, we send it there now to remember which
@@ -693,60 +834,72 @@ _circuit_mark_for_close(circuit_t *circ,
    */
   if (circ->state != CIRCUIT_STATE_OPEN) {
     if (CIRCUIT_IS_ORIGIN(circ)) {
-      circuit_build_failed(circ); /* take actions if necessary */
+      origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
+      circuit_build_failed(ocirc); /* take actions if necessary */
+      circuit_rep_hist_note_result(ocirc);
     }
-    circuit_rep_hist_note_result(circ);
   }
   if (circ->state == CIRCUIT_STATE_OR_WAIT) {
     if (circuits_pending_or_conns)
       smartlist_remove(circuits_pending_or_conns, circ);
   }
   if (CIRCUIT_IS_ORIGIN(circ)) {
-    control_event_circuit_status(circ,
+    control_event_circuit_status(TO_ORIGIN_CIRCUIT(circ),
      (circ->state == CIRCUIT_STATE_OPEN)?CIRC_EVENT_CLOSED:CIRC_EVENT_FAILED);
   }
   if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
+    origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
     tor_assert(circ->state == CIRCUIT_STATE_OPEN);
-    tor_assert(circ->build_state->chosen_exit);
+    tor_assert(ocirc->build_state->chosen_exit);
     /* treat this like getting a nack from it */
     log_info(LD_REND, "Failed intro circ %s to %s (awaiting ack). "
              "Removing from descriptor.",
              safe_str(circ->rend_query),
-             safe_str(build_state_get_exit_nickname(circ->build_state)));
-    rend_client_remove_intro_point(circ->build_state->chosen_exit,
+             safe_str(build_state_get_exit_nickname(ocirc->build_state)));
+    rend_client_remove_intro_point(ocirc->build_state->chosen_exit,
                                    circ->rend_query);
   }
-
   if (circ->n_conn)
     connection_or_send_destroy(circ->n_circ_id, circ->n_conn, reason);
-  for (conn=circ->n_streams; conn; conn=conn->next_stream)
-    connection_edge_destroy(circ->n_circ_id, conn);
-  while (circ->resolving_streams) {
-    conn = circ->resolving_streams;
-    circ->resolving_streams = conn->next_stream;
-    if (!conn->marked_for_close) {
-      /* The other side will see a DESTROY, and infer that the connections
-       * are closing because the circuit is getting torn down.  No need
-       * to send an end cell. */
-      conn->has_sent_end = 1;
-      connection_mark_for_close(conn);
+
+  if (! CIRCUIT_IS_ORIGIN(circ)) {
+    or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
+    for (conn=or_circ->n_streams; conn; conn=conn->next_stream)
+      connection_edge_destroy(or_circ->p_circ_id, conn);
+
+    while (or_circ->resolving_streams) {
+      conn = or_circ->resolving_streams;
+      or_circ->resolving_streams = conn->next_stream;
+      if (!conn->marked_for_close) {
+        /* The other side will see a DESTROY, and infer that the connections
+         * are closing because the circuit is getting torn down.  No need
+         * to send an end cell. */
+        conn->has_sent_end = 1;
+        connection_mark_for_close(conn);
+      }
+      conn->on_circuit = NULL;
     }
-    conn->on_circuit = NULL;
+
+    if (or_circ->p_conn)
+      connection_or_send_destroy(or_circ->p_circ_id, or_circ->p_conn, reason);
+  } else {
+    origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
+    for (conn=ocirc->p_streams; conn; conn=conn->next_stream)
+      connection_edge_destroy(circ->n_circ_id, conn);
   }
-  if (circ->p_conn)
-    connection_or_send_destroy(circ->p_circ_id, circ->p_conn, reason);
-  for (conn=circ->p_streams; conn; conn=conn->next_stream)
-    connection_edge_destroy(circ->p_circ_id, conn);
 
   circ->marked_for_close = line;
   circ->marked_for_close_file = file;
 
-  if (circ->rend_splice) {
-    if (!circ->rend_splice->marked_for_close) {
-      /* do this after marking this circuit, to avoid infinite recursion. */
-      circuit_mark_for_close(circ->rend_splice, reason);
+  if (! CIRCUIT_IS_ORIGIN(circ)) {
+    or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
+    if (or_circ->rend_splice) {
+      if (!or_circ->rend_splice->_base.marked_for_close) {
+        /* do this after marking this circuit, to avoid infinite recursion. */
+        circuit_mark_for_close(TO_CIRCUIT(or_circ->rend_splice), reason);
+      }
+      or_circ->rend_splice = NULL;
     }
-    circ->rend_splice = NULL;
   }
 }
 
@@ -810,12 +963,19 @@ void
 assert_circuit_ok(const circuit_t *c)
 {
   connection_t *conn;
+  const or_circuit_t *or_circ = NULL;
+  const origin_circuit_t *origin_circ = NULL;
 
   tor_assert(c);
-  tor_assert(c->magic == CIRCUIT_MAGIC);
+  tor_assert(c->magic == ORIGIN_CIRCUIT_MAGIC || c->magic == OR_CIRCUIT_MAGIC);
   tor_assert(c->purpose >= _CIRCUIT_PURPOSE_MIN &&
              c->purpose <= _CIRCUIT_PURPOSE_MAX);
 
+  if (CIRCUIT_IS_ORIGIN(c))
+    origin_circ = TO_ORIGIN_CIRCUIT((circuit_t*)c);
+  else
+    or_circ = TO_OR_CIRCUIT((circuit_t*)c);
+
   if (c->n_conn) {
     tor_assert(c->n_conn->type == CONN_TYPE_OR);
     tor_assert(!memcmp(c->n_conn->identity_digest, c->n_conn_id_digest,
@@ -823,32 +983,28 @@ assert_circuit_ok(const circuit_t *c)
     if (c->n_circ_id)
       tor_assert(c == circuit_get_by_circid_orconn(c->n_circ_id, c->n_conn));
   }
-  if (c->p_conn) {
-    tor_assert(c->p_conn->type == CONN_TYPE_OR);
-    if (c->p_circ_id)
-      tor_assert(c == circuit_get_by_circid_orconn(c->p_circ_id, c->p_conn));
+  if (or_circ && or_circ->p_conn) {
+    tor_assert(or_circ->p_conn->type == CONN_TYPE_OR);
+    if (or_circ->p_circ_id)
+      tor_assert(c == circuit_get_by_circid_orconn(or_circ->p_circ_id,
+                                                   or_circ->p_conn));
   }
-  for (conn = c->p_streams; conn; conn = conn->next_stream)
-    tor_assert(conn->type == CONN_TYPE_AP);
-  for (conn = c->n_streams; conn; conn = conn->next_stream)
-    tor_assert(conn->type == CONN_TYPE_EXIT);
+  if (origin_circ)
+    for (conn = origin_circ->p_streams; conn; conn = conn->next_stream)
+      tor_assert(conn->type == CONN_TYPE_AP);
+  if (or_circ)
+    for (conn = or_circ->n_streams; conn; conn = conn->next_stream)
+      tor_assert(conn->type == CONN_TYPE_EXIT);
 
   tor_assert(c->deliver_window >= 0);
   tor_assert(c->package_window >= 0);
   if (c->state == CIRCUIT_STATE_OPEN) {
     tor_assert(!c->onionskin);
-    if (c->cpath) {
-      tor_assert(CIRCUIT_IS_ORIGIN(c));
-      tor_assert(!c->n_crypto);
-      tor_assert(!c->p_crypto);
-      tor_assert(!c->n_digest);
-      tor_assert(!c->p_digest);
-    } else {
-      tor_assert(!CIRCUIT_IS_ORIGIN(c));
-      tor_assert(c->n_crypto);
-      tor_assert(c->p_crypto);
-      tor_assert(c->n_digest);
-      tor_assert(c->p_digest);
+    if (or_circ) {
+      tor_assert(or_circ->n_crypto);
+      tor_assert(or_circ->p_crypto);
+      tor_assert(or_circ->n_digest);
+      tor_assert(or_circ->p_digest);
     }
   }
   if (c->state == CIRCUIT_STATE_OR_WAIT && !c->marked_for_close) {
@@ -858,17 +1014,18 @@ assert_circuit_ok(const circuit_t *c)
     tor_assert(!circuits_pending_or_conns ||
                !smartlist_isin(circuits_pending_or_conns, c));
   }
-  if (c->cpath) {
-    assert_cpath_ok(c->cpath);
+  if (origin_circ->cpath) {
+    assert_cpath_ok(origin_circ->cpath);
   }
   if (c->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED) {
+    tor_assert(or_circ);
     if (!c->marked_for_close) {
-      tor_assert(c->rend_splice);
-      tor_assert(c->rend_splice->rend_splice == c);
+      tor_assert(or_circ->rend_splice);
+      tor_assert(or_circ->rend_splice->rend_splice == or_circ);
     }
-    tor_assert(c->rend_splice != c);
+    tor_assert(or_circ->rend_splice != or_circ);
   } else {
-    tor_assert(!c->rend_splice);
+    tor_assert(!or_circ || !or_circ->rend_splice);
   }
 }
 

Index: circuituse.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/circuituse.c,v
retrieving revision 1.132
retrieving revision 1.133
diff -u -p -d -r1.132 -r1.133
--- circuituse.c	18 Jul 2006 00:58:11 -0000	1.132
+++ circuituse.c	23 Jul 2006 07:37:35 -0000	1.133
@@ -32,6 +32,7 @@ circuit_is_acceptable(circuit_t *circ, c
                       time_t now)
 {
   routerinfo_t *exitrouter;
+  cpath_build_state_t *build_state;
   tor_assert(circ);
   tor_assert(conn);
   tor_assert(conn->socks_request);
@@ -71,11 +72,12 @@ circuit_is_acceptable(circuit_t *circ, c
    * circuit, it's the magical extra bob hop. so just check the nickname
    * of the one we meant to finish at.
    */
-  exitrouter = build_state_get_exit_router(circ->build_state);
+  build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
+  exitrouter = build_state_get_exit_router(build_state);
 
-  if (need_uptime && !circ->build_state->need_uptime)
+  if (need_uptime && !build_state->need_uptime)
     return 0;
-  if (need_internal != circ->build_state->is_internal)
+  if (need_internal != build_state->is_internal)
     return 0;
 
   if (purpose == CIRCUIT_PURPOSE_C_GENERAL) {
@@ -114,9 +116,11 @@ circuit_is_better(circuit_t *a, circuit_
           return 1;
       } else {
         if (a->timestamp_dirty ||
-            b->build_state->is_internal ||
             a->timestamp_created > b->timestamp_created)
           return 1;
+        if (CIRCUIT_IS_ORIGIN(b) &&
+            TO_ORIGIN_CIRCUIT(b)->build_state->is_internal)
+          return 1;
       }
       break;
     case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
@@ -149,7 +153,7 @@ circuit_is_better(circuit_t *a, circuit_
  * If it's INTRODUCE_ACK_WAIT and must_be_open==0, then return the
  * closest introduce-purposed circuit that you can find.
  */
-static circuit_t *
+static origin_circuit_t *
 circuit_get_best(connection_t *conn, int must_be_open, uint8_t purpose,
                  int need_uptime, int need_internal)
 {
@@ -163,6 +167,8 @@ circuit_get_best(connection_t *conn, int
              purpose == CIRCUIT_PURPOSE_C_REND_JOINED);
 
   for (circ=global_circuitlist;circ;circ = circ->next) {
+    if (!CIRCUIT_IS_ORIGIN(circ))
+      continue;
     if (!circuit_is_acceptable(circ,conn,must_be_open,purpose,
                                need_uptime,need_internal,now))
       continue;
@@ -174,7 +180,7 @@ circuit_get_best(connection_t *conn, int
       best = circ;
   }
 
-  return best;
+  return best ? TO_ORIGIN_CIRCUIT(best) : NULL;
 }
 
 /** Close all circuits that start at us, aren't open, and were born
@@ -255,7 +261,7 @@ circuit_expire_building(time_t now)
                victim->n_circ_id, victim->state,
                circuit_state_to_string(victim->state), victim->purpose);
 
-    circuit_log_path(LOG_INFO,LD_CIRC,victim);
+    circuit_log_path(LOG_INFO,LD_CIRC,TO_ORIGIN_CIRCUIT(victim));
     circuit_mark_for_close(victim, END_CIRC_AT_ORIGIN);
   }
 }
@@ -301,12 +307,14 @@ circuit_stream_is_being_handled(connecti
     if (CIRCUIT_IS_ORIGIN(circ) &&
         !circ->marked_for_close &&
         circ->purpose == CIRCUIT_PURPOSE_C_GENERAL &&
-        !circ->build_state->is_internal &&
         (!circ->timestamp_dirty ||
          circ->timestamp_dirty + get_options()->MaxCircuitDirtiness > now)) {
-      exitrouter = build_state_get_exit_router(circ->build_state);
-      if (exitrouter &&
-          (!need_uptime || circ->build_state->need_uptime)) {
+      cpath_build_state_t *build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
+      if (build_state->is_internal)
+        continue;
+
+      exitrouter = build_state_get_exit_router(build_state);
+      if (exitrouter && (!need_uptime || build_state->need_uptime)) {
         int ok;
         if (conn) {
           ok = connection_ap_can_use_exit(conn, exitrouter);
@@ -343,6 +351,7 @@ circuit_predict_and_launch_new(void)
 
   /* First, count how many of each type of circuit we have already. */
   for (circ=global_circuitlist;circ;circ = circ->next) {
+    cpath_build_state_t *build_state;
     if (!CIRCUIT_IS_ORIGIN(circ))
       continue;
     if (circ->marked_for_close)
@@ -352,9 +361,10 @@ circuit_predict_and_launch_new(void)
     if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL)
       continue; /* only pay attention to general-purpose circs */
     num++;
-    if (circ->build_state->is_internal)
+    build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
+    if (build_state->is_internal)
       num_internal++;
-    if (circ->build_state->need_uptime && circ->build_state->is_internal)
+    if (build_state->need_uptime && build_state->is_internal)
       num_uptime_internal++;
   }
 
@@ -455,44 +465,49 @@ circuit_detach_stream(circuit_t *circ, c
   conn->cpath_layer = NULL; /* make sure we don't keep a stale pointer */
   conn->on_circuit = NULL;
 
-  if (conn == circ->p_streams) {
-    circ->p_streams = conn->next_stream;
-    return;
-  }
-  if (conn == circ->n_streams) {
-    circ->n_streams = conn->next_stream;
-    return;
-  }
-  if (conn == circ->resolving_streams) {
-    circ->resolving_streams = conn->next_stream;
-    return;
-  }
+  if (CIRCUIT_IS_ORIGIN(circ)) {
+    origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
+    if (conn == origin_circ->p_streams) {
+      origin_circ->p_streams = conn->next_stream;
+      return;
+    }
 
-  for (prevconn = circ->p_streams;
-      prevconn && prevconn->next_stream && prevconn->next_stream != conn;
-      prevconn = prevconn->next_stream)
-    ;
-  if (prevconn && prevconn->next_stream) {
-    prevconn->next_stream = conn->next_stream;
-    return;
-  }
+    for (prevconn = origin_circ->p_streams;
+         prevconn && prevconn->next_stream && prevconn->next_stream != conn;
+         prevconn = prevconn->next_stream)
+      ;
+    if (prevconn && prevconn->next_stream) {
+      prevconn->next_stream = conn->next_stream;
+      return;
+    }
+  } else {
+    or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
+    if (conn == or_circ->n_streams) {
+      or_circ->n_streams = conn->next_stream;
+      return;
+    }
+    if (conn == or_circ->resolving_streams) {
+      or_circ->resolving_streams = conn->next_stream;
+      return;
+    }
 
-  for (prevconn = circ->n_streams;
-      prevconn && prevconn->next_stream && prevconn->next_stream != conn;
-      prevconn = prevconn->next_stream)
-    ;
-  if (prevconn && prevconn->next_stream) {
-    prevconn->next_stream = conn->next_stream;
-    return;
-  }
+    for (prevconn = or_circ->n_streams;
+         prevconn && prevconn->next_stream && prevconn->next_stream != conn;
+         prevconn = prevconn->next_stream)
+      ;
+    if (prevconn && prevconn->next_stream) {
+      prevconn->next_stream = conn->next_stream;
+      return;
+    }
 
-  for (prevconn = circ->resolving_streams;
-      prevconn && prevconn->next_stream && prevconn->next_stream != conn;
-      prevconn = prevconn->next_stream)
-    ;
-  if (prevconn && prevconn->next_stream) {
-    prevconn->next_stream = conn->next_stream;
-    return;
+    for (prevconn = or_circ->resolving_streams;
+         prevconn && prevconn->next_stream && prevconn->next_stream != conn;
+         prevconn = prevconn->next_stream)
+      ;
+    if (prevconn && prevconn->next_stream) {
+      prevconn->next_stream = conn->next_stream;
+      return;
+    }
   }
 
   log_err(LD_BUG,"edge conn not in circuit's list?");
@@ -543,7 +558,7 @@ circuit_about_to_close_connection(connec
 }
 
 /** Find each circuit that has been unused for too long, or dirty
- * for too long and has no streams on it: mark it for close.
+ * for too long and has no streax=ms on it: mark it for close.
  */
 static void
 circuit_expire_old_circuits(time_t now)
@@ -552,23 +567,21 @@ circuit_expire_old_circuits(time_t now)
   time_t cutoff = now - get_options()->CircuitIdleTimeout;
 
   for (circ = global_circuitlist; circ; circ = circ->next) {
-    if (circ->marked_for_close)
+    if (circ->marked_for_close || ! CIRCUIT_IS_ORIGIN(circ))
       continue;
     /* If the circuit has been dirty for too long, and there are no streams
      * on it, mark it for close.
      */
     if (circ->timestamp_dirty &&
         circ->timestamp_dirty + get_options()->MaxCircuitDirtiness < now &&
-        CIRCUIT_IS_ORIGIN(circ) &&
-        !circ->p_streams /* nothing attached */ ) {
+        !TO_ORIGIN_CIRCUIT(circ)->p_streams /* nothing attached */ ) {
       log_debug(LD_CIRC, "Closing n_circ_id %d (dirty %d secs ago, purp %d)",
                 circ->n_circ_id, (int)(now - circ->timestamp_dirty),
                 circ->purpose);
       /* (only general and purpose_c circs can get dirty) */
-      tor_assert(!circ->n_streams);
       tor_assert(circ->purpose <= CIRCUIT_PURPOSE_C_REND_JOINED);
       circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
-    } else if (!circ->timestamp_dirty && CIRCUIT_IS_ORIGIN(circ) &&
+    } else if (!circ->timestamp_dirty &&
                circ->state == CIRCUIT_STATE_OPEN &&
                circ->purpose == CIRCUIT_PURPOSE_C_GENERAL) {
       if (circ->timestamp_created < cutoff) {
@@ -583,17 +596,17 @@ circuit_expire_old_circuits(time_t now)
 
 /** A testing circuit has completed. Take whatever stats we want. */
 static void
-circuit_testing_opened(circuit_t *circ)
+circuit_testing_opened(origin_circuit_t *circ)
 {
   /* For now, we only use testing circuits to see if our ORPort is
      reachable. But we remember reachability in onionskin_answer(),
      so there's no need to record anything here. Just close the circ. */
-  circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+  circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
 }
 
 /** A testing circuit has failed to build. Take whatever stats we want. */
 static void
-circuit_testing_failed(circuit_t *circ, int at_last_hop)
+circuit_testing_failed(origin_circuit_t *circ, int at_last_hop)
 {
   if (server_mode(get_options()) && check_whether_orport_reachable())
     return;
@@ -614,11 +627,11 @@ circuit_testing_failed(circuit_t *circ, 
  * that could use circ.
  */
 void
-circuit_has_opened(circuit_t *circ)
+circuit_has_opened(origin_circuit_t *circ)
 {
   control_event_circuit_status(circ, CIRC_EVENT_BUILT);
 
-  switch (circ->purpose) {
+  switch (TO_CIRCUIT(circ)->purpose) {
     case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
       rend_client_rendcirc_has_opened(circ);
       connection_ap_attach_pending();
@@ -643,7 +656,7 @@ circuit_has_opened(circuit_t *circ)
       circuit_testing_opened(circ);
       break;
     default:
-      log_err(LD_BUG,"unhandled purpose %d",circ->purpose);
+      log_err(LD_BUG,"unhandled purpose %d",circ->_base.purpose);
       tor_assert(0);
   }
 }
@@ -651,7 +664,7 @@ circuit_has_opened(circuit_t *circ)
 /** Called whenever a circuit could not be successfully built.
  */
 void
-circuit_build_failed(circuit_t *circ)
+circuit_build_failed(origin_circuit_t *circ)
 {
   /* we should examine circ and see if it failed because of
    * the last hop or an earlier hop. then use this info below.
@@ -669,11 +682,12 @@ circuit_build_failed(circuit_t *circ)
     /* We failed at the first hop. If there's an OR connection
        to blame, blame it. */
     connection_t *n_conn = NULL;
-    if (circ->n_conn) {
-      n_conn = circ->n_conn;
-    } else if (circ->state == CIRCUIT_STATE_OR_WAIT) {
+    if (circ->_base.n_conn) {
+      n_conn = circ->_base.n_conn;
+    } else if (circ->_base.state == CIRCUIT_STATE_OR_WAIT) {
       /* we have to hunt for it */
-      n_conn = connection_or_get_by_identity_digest(circ->n_conn_id_digest);
+      n_conn = connection_or_get_by_identity_digest(
+                                               circ->_base.n_conn_id_digest);
     }
     if (n_conn) {
       log_info(LD_OR,
@@ -685,7 +699,7 @@ circuit_build_failed(circuit_t *circ)
     }
   }
 
-  switch (circ->purpose) {
+  switch (circ->_base.purpose) {
     case CIRCUIT_PURPOSE_C_GENERAL:
       /* If we never built the circuit, note it as a failure. */
       circuit_increment_failure_count();
@@ -695,7 +709,7 @@ circuit_build_failed(circuit_t *circ)
       break;
     case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
       /* at Bob, waiting for introductions */
-      if (circ->state != CIRCUIT_STATE_OPEN) {
+      if (circ->_base.state != CIRCUIT_STATE_OPEN) {
         circuit_increment_failure_count();
       }
       /* no need to care here, because bob will rebuild intro
@@ -744,11 +758,11 @@ static int did_circs_fail_last_period = 
 
 /** Launch a new circuit; see circuit_launch_by_extend_info() for
  * details on arguments. */
-circuit_t *
+origin_circuit_t *
 circuit_launch_by_router(uint8_t purpose, routerinfo_t *exit,
                          int need_uptime, int need_capacity, int internal)
 {
-  circuit_t *circ;
+  origin_circuit_t *circ;
   extend_info_t *info = NULL;
   if (exit)
     info = extend_info_from_router(exit);
@@ -765,11 +779,11 @@ circuit_launch_by_router(uint8_t purpose
  * choose among routers with high bandwidth.  If <b>internal</b> is true, the
  * last hop need not be an exit node. Return the newly allocated circuit on
  * success, or NULL on failure. */
-circuit_t *
+origin_circuit_t *
 circuit_launch_by_extend_info(uint8_t purpose, extend_info_t *extend_info,
                int need_uptime, int need_capacity, int internal)
 {
-  circuit_t *circ;
+  origin_circuit_t *circ;
 
   if (!router_have_minimum_dir_info()) {
     log_debug(LD_CIRC,"Haven't fetched enough directory info yet; canceling "
@@ -785,11 +799,11 @@ circuit_launch_by_extend_info(uint8_t pu
     if (circ) {
       log_info(LD_CIRC,"Cannibalizing circ '%s' for purpose %d",
                build_state_get_exit_nickname(circ->build_state), purpose);
-      circ->purpose = purpose;
+      circ->_base.purpose = purpose;
       /* reset the birth date of this circ, else expire_building
        * will see it and think it's been trying to build since it
        * began. */
-      circ->timestamp_created = time(NULL);
+      circ->_base.timestamp_created = time(NULL);
       switch (purpose) {
         case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
         case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
@@ -829,7 +843,7 @@ circuit_launch_by_extend_info(uint8_t pu
 
 /** Launch a new circuit; see circuit_launch_by_extend_info() for
  * details on arguments. */
-circuit_t *
+origin_circuit_t *
 circuit_launch_by_nickname(uint8_t purpose, const char *exit_nickname,
                            int need_uptime, int need_capacity, int internal)
 {
@@ -879,9 +893,9 @@ circuit_reset_failure_count(int timeout)
 static int
 circuit_get_open_circ_or_launch(connection_t *conn,
                                 uint8_t desired_circuit_purpose,
-                                circuit_t **circp)
+                                origin_circuit_t **circp)
 {
-  circuit_t *circ;
+  origin_circuit_t *circ;
   int is_resolve;
   int need_uptime, need_internal;
 
@@ -996,9 +1010,10 @@ circuit_get_open_circ_or_launch(connecti
       rep_hist_note_used_internal(time(NULL), need_uptime, 1);
       if (circ) {
         /* write the service_id into circ */
-        strlcpy(circ->rend_query, conn->rend_query, sizeof(circ->rend_query));
-        if (circ->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND &&
-            circ->state == CIRCUIT_STATE_OPEN)
+        strlcpy(circ->_base.rend_query, conn->rend_query,
+                sizeof(circ->_base.rend_query));
+        if (circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND &&
+            circ->_base.state == CIRCUIT_STATE_OPEN)
           rend_client_rendcirc_has_opened(circ);
       }
     }
@@ -1017,19 +1032,18 @@ circuit_get_open_circ_or_launch(connecti
  * circ's cpath.
  */
 static void
-link_apconn_to_circ(connection_t *apconn, circuit_t *circ)
+link_apconn_to_circ(connection_t *apconn, origin_circuit_t *circ)
 {
   /* add it into the linked list of streams on this circuit */
   log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %d.",
-            circ->n_circ_id);
+            circ->_base.n_circ_id);
   /* reset it, so we can measure circ timeouts */
   apconn->timestamp_lastread = time(NULL);
   apconn->next_stream = circ->p_streams;
-  apconn->on_circuit = circ;
+  apconn->on_circuit = TO_CIRCUIT(circ);
   /* assert_connection_ok(conn, time(NULL)); */
   circ->p_streams = apconn;
 
-  tor_assert(CIRCUIT_IS_ORIGIN(circ));
   tor_assert(circ->cpath);
   tor_assert(circ->cpath->prev);
   tor_assert(circ->cpath->prev->state == CPATH_STATE_OPEN);
@@ -1039,7 +1053,7 @@ link_apconn_to_circ(connection_t *apconn
 /** If an exit wasn't specifically chosen, save the history for future
  * use. */
 static void
-consider_recording_trackhost(connection_t *conn, circuit_t *circ)
+consider_recording_trackhost(connection_t *conn, origin_circuit_t *circ)
 {
   int found_needle = 0;
   char *str;
@@ -1094,7 +1108,7 @@ consider_recording_trackhost(connection_
  * for connection_ap_handshake_attach_circuit. */
 int
 connection_ap_handshake_attach_chosen_circuit(connection_t *conn,
-                                              circuit_t *circ)
+                                              origin_circuit_t *circ)
 {
   tor_assert(conn);
   tor_assert(conn->type == CONN_TYPE_AP);
@@ -1102,12 +1116,12 @@ connection_ap_handshake_attach_chosen_ci
              conn->state == AP_CONN_STATE_CONTROLLER_WAIT);
   tor_assert(conn->socks_request);
   tor_assert(circ);
-  tor_assert(circ->state == CIRCUIT_STATE_OPEN);
+  tor_assert(circ->_base.state == CIRCUIT_STATE_OPEN);
 
   conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
 
-  if (!circ->timestamp_dirty)
-    circ->timestamp_dirty = time(NULL);
+  if (!circ->_base.timestamp_dirty)
+    circ->_base.timestamp_dirty = time(NULL);
 
   link_apconn_to_circ(conn, circ);
   tor_assert(conn->socks_request);
@@ -1153,7 +1167,7 @@ connection_ap_handshake_attach_circuit(c
   }
 
   if (!connection_edge_is_rendezvous_stream(conn)) { /* we're a general conn */
-    circuit_t *circ=NULL;
+    origin_circuit_t *circ=NULL;
 
     if (conn->chosen_exit_name) {
       routerinfo_t *router = router_get_by_nickname(conn->chosen_exit_name, 1);
@@ -1190,7 +1204,7 @@ connection_ap_handshake_attach_circuit(c
 
     log_debug(LD_APP|LD_CIRC,
               "Attaching apconn to circ %d (stream %d sec old).",
-              circ->n_circ_id, conn_age);
+              circ->_base.n_circ_id, conn_age);
     /* here, print the circ's path. so people can figure out which circs are
      * sucking. */
     circuit_log_path(LOG_INFO,LD_APP|LD_CIRC,circ);
@@ -1199,7 +1213,7 @@ connection_ap_handshake_attach_circuit(c
     return connection_ap_handshake_attach_chosen_circuit(conn, circ);
 
   } else { /* we're a rendezvous conn */
-    circuit_t *rendcirc=NULL, *introcirc=NULL;
+    origin_circuit_t *rendcirc=NULL, *introcirc=NULL;
 
     tor_assert(!conn->cpath_layer);
 
@@ -1215,25 +1229,25 @@ connection_ap_handshake_attach_circuit(c
       log_info(LD_REND,
                "rend joined circ %d already here. attaching. "
                "(stream %d sec old)",
-               rendcirc->n_circ_id, conn_age);
+               rendcirc->_base.n_circ_id, conn_age);
       /* Mark rendezvous circuits as 'newly dirty' every time you use
        * them, since the process of rebuilding a rendezvous circ is so
        * expensive. There is a tradeoffs between linkability and
        * feasibility, at this point.
        */
-      rendcirc->timestamp_dirty = time(NULL);
+      rendcirc->_base.timestamp_dirty = time(NULL);
       link_apconn_to_circ(conn, rendcirc);
       if (connection_ap_handshake_send_begin(conn, rendcirc) < 0)
         return 0; /* already marked, let them fade away */
       return 1;
     }
 
-    if (rendcirc && (rendcirc->purpose ==
+    if (rendcirc && (rendcirc->_base.purpose ==
                      CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)) {
       log_info(LD_REND,
                "pending-join circ %d already here, with intro ack. "
                "Stalling. (stream %d sec old)",
-                rendcirc->n_circ_id, conn_age);
+                rendcirc->_base.n_circ_id, conn_age);
       return 0;
     }
 
@@ -1247,7 +1261,8 @@ connection_ap_handshake_attach_circuit(c
       tor_assert(introcirc);
       log_info(LD_REND, "Intro circ %d present and awaiting ack (rend %d). "
                "Stalling. (stream %d sec old)",
-               introcirc->n_circ_id, rendcirc ? rendcirc->n_circ_id : 0,
+               introcirc->_base.n_circ_id,
+               rendcirc ? rendcirc->_base.n_circ_id : 0,
                conn_age);
       return 0;
     }
@@ -1255,32 +1270,34 @@ connection_ap_handshake_attach_circuit(c
     /* now rendcirc and introcirc are each either undefined or not finished */
 
     if (rendcirc && introcirc &&
-        rendcirc->purpose == CIRCUIT_PURPOSE_C_REND_READY) {
+        rendcirc->_base.purpose == CIRCUIT_PURPOSE_C_REND_READY) {
       log_info(LD_REND,
                "ready rend circ %d already here (no intro-ack yet on "
                "intro %d). (stream %d sec old)",
-               rendcirc->n_circ_id, introcirc->n_circ_id, conn_age);
+               rendcirc->_base.n_circ_id,
+               introcirc->_base.n_circ_id, conn_age);
 
-      tor_assert(introcirc->purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
-      if (introcirc->state == CIRCUIT_STATE_OPEN) {
+      tor_assert(introcirc->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
+      if (introcirc->_base.state == CIRCUIT_STATE_OPEN) {
         log_info(LD_REND,"found open intro circ %d (rend %d); sending "
                  "introduction. (stream %d sec old)",
-                 introcirc->n_circ_id, rendcirc->n_circ_id, conn_age);
+                 introcirc->_base.n_circ_id, rendcirc->_base.n_circ_id,
+                 conn_age);
         if (rend_client_send_introduction(introcirc, rendcirc) < 0) {
           return -1;
         }
-        rendcirc->timestamp_dirty = time(NULL);
-        introcirc->timestamp_dirty = time(NULL);
-        assert_circuit_ok(rendcirc);
-        assert_circuit_ok(introcirc);
+        rendcirc->_base.timestamp_dirty = time(NULL);
+        introcirc->_base.timestamp_dirty = time(NULL);
+        assert_circuit_ok(TO_CIRCUIT(rendcirc));
+        assert_circuit_ok(TO_CIRCUIT(introcirc));
         return 0;
       }
     }
 
     log_info(LD_REND, "Intro (%d) and rend (%d) circs are not both ready. "
              "Stalling conn. (%d sec old)",
-             introcirc ? introcirc->n_circ_id : 0,
-             rendcirc ? rendcirc->n_circ_id : 0, conn_age);
+             introcirc ? introcirc->_base.n_circ_id : 0,
+             rendcirc ? rendcirc->_base.n_circ_id : 0, conn_age);
     return 0;
   }
 }

Index: command.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/command.c,v
retrieving revision 1.111
retrieving revision 1.112
diff -u -p -d -r1.111 -r1.112
--- command.c	4 Jul 2006 03:27:09 -0000	1.111
+++ command.c	23 Jul 2006 07:37:35 -0000	1.112
@@ -161,7 +161,7 @@ command_process_cell(cell_t *cell, conne
 static void
 command_process_create_cell(cell_t *cell, connection_t *conn)
 {
-  circuit_t *circ;
+  or_circuit_t *circ;
   int id_is_high;
 
   if (we_are_hibernating()) {
@@ -186,9 +186,7 @@ command_process_create_cell(cell_t *cell
     return;
   }
 
-  circ = circuit_get_by_circid_orconn(cell->circ_id, conn);
-
-  if (circ) {
+  if (circuit_get_by_circid_orconn(cell->circ_id, conn)) {
     routerinfo_t *router = router_get_by_digest(conn->identity_digest);
     log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
            "Received CREATE cell (circID %d) for known circ. "
@@ -201,17 +199,17 @@ command_process_create_cell(cell_t *cell
     return;
   }
 
-  circ = circuit_new(cell->circ_id, conn);
-  circ->purpose = CIRCUIT_PURPOSE_OR;
-  circuit_set_state(circ, CIRCUIT_STATE_ONIONSKIN_PENDING);
+  circ = or_circuit_new(cell->circ_id, conn);
+  circ->_base.purpose = CIRCUIT_PURPOSE_OR;
+  circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING);
   if (cell->command == CELL_CREATE) {
-    circ->onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN);
-    memcpy(circ->onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN);
+    circ->_base.onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN);
+    memcpy(circ->_base.onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN);
 
     /* hand it off to the cpuworkers, and then return. */
     if (assign_to_cpuworker(NULL, CPUWORKER_TASK_ONION, circ) < 0) {
       log_warn(LD_GENERAL,"Failed to hand off onionskin. Closing.");
-      circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
+      circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
       return;
     }
     log_debug(LD_OR,"success: handed off onionskin.");
@@ -223,12 +221,12 @@ command_process_create_cell(cell_t *cell
     tor_assert(cell->command == CELL_CREATE_FAST);
     if (fast_server_handshake(cell->payload, reply, keys, sizeof(keys))<0) {
       log_warn(LD_OR,"Failed to generate key material. Closing.");
-      circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
+      circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
       return;
     }
     if (onionskin_answer(circ, CELL_CREATED_FAST, reply, keys)<0) {
       log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing.");
-      circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
+      circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
       return;
     }
   }
@@ -264,14 +262,16 @@ command_process_created_cell(cell_t *cel
   }
 
   if (CIRCUIT_IS_ORIGIN(circ)) { /* we're the OP. Handshake this. */
+    origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
     log_debug(LD_OR,"at OP. Finishing handshake.");
-    if (circuit_finish_handshake(circ, cell->command, cell->payload) < 0) {
+    if (circuit_finish_handshake(origin_circ, cell->command,
+                                 cell->payload) < 0) {
       log_warn(LD_OR,"circuit_finish_handshake failed.");
       circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
       return;
     }
     log_debug(LD_OR,"Moving to next skin.");
-    if (circuit_send_next_onion_skin(circ) < 0) {
+    if (circuit_send_next_onion_skin(origin_circ) < 0) {
       log_info(LD_OR,"circuit_send_next_onion_skin failed.");
       /* XXX push this circuit_close lower */
       circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
@@ -310,7 +310,9 @@ command_process_relay_cell(cell_t *cell,
     return;
   }
 
-  if (cell->circ_id == circ->p_circ_id) { /* it's an outgoing cell */
+  if (!CIRCUIT_IS_ORIGIN(circ) &&
+      cell->circ_id == TO_OR_CIRCUIT(circ)->p_circ_id) {
+    /* it's an outgoing cell */
     if ((reason = circuit_receive_relay_cell(cell, circ,
                                              CELL_DIRECTION_OUT)) < 0) {
       log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,"circuit_receive_relay_cell "
@@ -357,12 +359,13 @@ command_process_destroy_cell(cell_t *cel
   }
   log_debug(LD_OR,"Received for circID %d.",cell->circ_id);
 
-  if (cell->circ_id == circ->p_circ_id) {
+  if (!CIRCUIT_IS_ORIGIN(circ) &&
+      cell->circ_id == TO_OR_CIRCUIT(circ)->p_circ_id) {
     /* the destroy came from behind */
-    circuit_set_circid_orconn(circ, 0, NULL, P_CONN_CHANGED);
+    circuit_set_p_circid_orconn(TO_OR_CIRCUIT(circ), 0, NULL);
     circuit_mark_for_close(circ, reason);
   } else { /* the destroy came from ahead */
-    circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED);
+    circuit_set_n_circid_orconn(circ, 0, NULL);
     if (CIRCUIT_IS_ORIGIN(circ)) {
       circuit_mark_for_close(circ, reason);
     } else {

Index: connection_edge.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/connection_edge.c,v
retrieving revision 1.406
retrieving revision 1.407
diff -u -p -d -r1.406 -r1.407
--- connection_edge.c	18 Jul 2006 04:48:59 -0000	1.406
+++ connection_edge.c	23 Jul 2006 07:37:35 -0000	1.407
@@ -60,20 +60,6 @@ _connection_mark_unattached_ap(connectio
 int
 connection_edge_reached_eof(connection_t *conn)
 {
-#ifdef HALF_OPEN
-  /* eof reached; we're done reading, but we might want to write more. */
-  conn->done_receiving = 1;
-  shutdown(conn->s, 0); /* XXX check return, refactor NM */
-  if (conn->done_sending) {
-    connection_edge_end(conn, END_STREAM_REASON_DONE, conn->cpath_layer);
-    connection_mark_for_close(conn);
-  } else {
-    connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
-                                 RELAY_COMMAND_END,
-                                 NULL, 0, conn->cpath_layer);
-  }
-  return 0;
-#else
   if (buf_datalen(conn->inbuf) && connection_state_is_open(conn)) {
     /* it still has stuff to process. don't let it die yet. */
     return 0;
@@ -88,7 +74,6 @@ connection_edge_reached_eof(connection_t
     connection_mark_for_close(conn);
   }
   return 0;
-#endif
 }
 
 /** Handle new bytes on conn->inbuf based on state:
@@ -386,7 +371,8 @@ connection_ap_expire_beginning(void)
       continue;
     }
     tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_GENERAL);
-    nickname = build_state_get_exit_nickname(circ->build_state);
+    nickname = build_state_get_exit_nickname(
+                                        TO_ORIGIN_CIRCUIT(circ)->build_state);
     log_fn(cutoff < 15 ? LOG_INFO : severity, LD_APP,
            "We tried for %d seconds to connect to '%s' using exit '%s'."
            " Retrying on a new circuit.",
@@ -406,7 +392,7 @@ connection_ap_expire_beginning(void)
     conn->timestamp_lastread += cutoff;
     conn->num_socks_retries++;
     /* move it back into 'pending' state, and try to attach. */
-    if (connection_ap_detach_retriable(conn, circ)<0) {
+    if (connection_ap_detach_retriable(conn, TO_ORIGIN_CIRCUIT(circ))<0) {
       connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
     }
   } /* end for */
@@ -444,17 +430,17 @@ connection_ap_attach_pending(void)
  * Returns -1 on err, 1 on success, 0 on not-yet-sure.
  */
 int
-connection_ap_detach_retriable(connection_t *conn, circuit_t *circ)
+connection_ap_detach_retriable(connection_t *conn, origin_circuit_t *circ)
 {
   control_event_stream_status(conn, STREAM_EVENT_FAILED_RETRIABLE);
   conn->timestamp_lastread = time(NULL);
   if (! get_options()->LeaveStreamsUnattached) {
     conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
-    circuit_detach_stream(circ,conn);
+    circuit_detach_stream(TO_CIRCUIT(circ),conn);
     return connection_ap_handshake_attach_circuit(conn);
   } else {
     conn->state = AP_CONN_STATE_CONTROLLER_WAIT;
-    circuit_detach_stream(circ,conn);
+    circuit_detach_stream(TO_CIRCUIT(circ),conn);
     return 0;
   }
 }
@@ -1026,7 +1012,7 @@ addressmap_get_mappings(smartlist_t *sl,
  */
 int
 connection_ap_handshake_rewrite_and_attach(connection_t *conn,
-                                           circuit_t *circ)
+                                           origin_circuit_t *circ)
 {
   socks_request_t *socks = conn->socks_request;
   hostname_type_t addresstype;
@@ -1287,7 +1273,7 @@ connection_ap_handshake_process_socks(co
  * already in use; return it. Return 0 if can't get a unique stream_id.
  */
 static uint16_t
-get_unique_stream_id_by_circ(circuit_t *circ)
+get_unique_stream_id_by_circ(origin_circuit_t *circ)
 {
   connection_t *tmpconn;
   uint16_t test_stream_id;
@@ -1314,7 +1300,8 @@ again:
  * If ap_conn is broken, mark it for close and return -1. Else return 0.
  */
 int
-connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ)
+connection_ap_handshake_send_begin(connection_t *ap_conn,
+                                   origin_circuit_t *circ)
 {
   char payload[CELL_PAYLOAD_SIZE];
   int payload_len;
@@ -1326,12 +1313,12 @@ connection_ap_handshake_send_begin(conne
   ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
   if (ap_conn->stream_id==0) {
     connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
-    circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
+    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
     return -1;
   }
 
   tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:%d",
-               (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL) ?
+               (circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL) ?
                  ap_conn->socks_request->address : "",
                ap_conn->socks_request->port);
   payload_len = strlen(payload)+1;
@@ -1339,7 +1326,8 @@ connection_ap_handshake_send_begin(conne
   log_debug(LD_APP,
             "Sending relay cell to begin stream %d.", ap_conn->stream_id);
 
-  if (connection_edge_send_command(ap_conn, circ, RELAY_COMMAND_BEGIN,
+  if (connection_edge_send_command(ap_conn, TO_CIRCUIT(circ),
+                                   RELAY_COMMAND_BEGIN,
                                    payload, payload_len,
                                    ap_conn->cpath_layer) < 0)
     return -1; /* circuit is closed, don't continue */
@@ -1348,7 +1336,7 @@ connection_ap_handshake_send_begin(conne
   ap_conn->deliver_window = STREAMWINDOW_START;
   ap_conn->state = AP_CONN_STATE_CONNECT_WAIT;
   log_info(LD_APP,"Address/port sent, ap socket %d, n_circ_id %d",
-           ap_conn->s, circ->n_circ_id);
+           ap_conn->s, circ->_base.n_circ_id);
   control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT);
   return 0;
 }
@@ -1359,7 +1347,8 @@ connection_ap_handshake_send_begin(conne
  * If ap_conn is broken, mark it for close and return -1. Else return 0.
  */
 int
-connection_ap_handshake_send_resolve(connection_t *ap_conn, circuit_t *circ)
+connection_ap_handshake_send_resolve(connection_t *ap_conn,
+                                     origin_circuit_t *circ)
 {
   int payload_len;
   const char *string_addr;
@@ -1368,12 +1357,12 @@ connection_ap_handshake_send_resolve(con
   tor_assert(ap_conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
   tor_assert(ap_conn->socks_request);
   tor_assert(ap_conn->socks_request->command == SOCKS_COMMAND_RESOLVE);
-  tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_GENERAL);
+  tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL);
 
   ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
   if (ap_conn->stream_id==0) {
     connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
-    circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
+    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
     return -1;
   }
 
@@ -1384,13 +1373,14 @@ connection_ap_handshake_send_resolve(con
   log_debug(LD_APP,
             "Sending relay cell to begin stream %d.", ap_conn->stream_id);
 
-  if (connection_edge_send_command(ap_conn, circ, RELAY_COMMAND_RESOLVE,
+  if (connection_edge_send_command(ap_conn, TO_CIRCUIT(circ),
+                           RELAY_COMMAND_RESOLVE,
                            string_addr, payload_len, ap_conn->cpath_layer) < 0)
     return -1; /* circuit is closed, don't continue */
 
   ap_conn->state = AP_CONN_STATE_RESOLVE_WAIT;
   log_info(LD_APP,"Address sent for resolve, ap socket %d, n_circ_id %d",
-           ap_conn->s, circ->n_circ_id);
+           ap_conn->s, circ->_base.n_circ_id);
   control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE);
   return 0;
 }
@@ -1643,6 +1633,7 @@ connection_exit_begin_conn(cell_t *cell,
   n_stream->deliver_window = STREAMWINDOW_START;
 
   if (circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) {
+    origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
     log_debug(LD_REND,"begin is for rendezvous. configuring stream.");
     n_stream->address = tor_strdup("(rendezvous)");
     n_stream->state = EXIT_CONN_STATE_CONNECTING;
@@ -1650,7 +1641,7 @@ connection_exit_begin_conn(cell_t *cell,
             sizeof(n_stream->rend_query));
     tor_assert(connection_edge_is_rendezvous_stream(n_stream));
     assert_circuit_ok(circ);
-    if (rend_service_set_connection_addr_port(n_stream, circ) < 0) {
+    if (rend_service_set_connection_addr_port(n_stream, origin_circ) < 0) {
       log_info(LD_REND,"Didn't find rendezvous service (port %d)",
                n_stream->port);
       connection_edge_end(n_stream, END_STREAM_REASON_EXITPOLICY,
@@ -1663,12 +1654,12 @@ connection_exit_begin_conn(cell_t *cell,
     }
     assert_circuit_ok(circ);
     log_debug(LD_REND,"Finished assigning addr/port");
-    n_stream->cpath_layer = circ->cpath->prev; /* link it */
+    n_stream->cpath_layer = origin_circ->cpath->prev; /* link it */
 
     /* add it into the linked list of n_streams on this circuit */
-    n_stream->next_stream = circ->n_streams;
+    n_stream->next_stream = origin_circ->p_streams;
     n_stream->on_circuit = circ;
-    circ->n_streams = n_stream;
+    origin_circ->p_streams = n_stream;
     assert_circuit_ok(circ);
 
     connection_exit_connect(n_stream);
@@ -1693,9 +1684,9 @@ connection_exit_begin_conn(cell_t *cell,
     case 1: /* resolve worked */
 
       /* add it into the linked list of n_streams on this circuit */
-      n_stream->next_stream = circ->n_streams;
+      n_stream->next_stream = TO_OR_CIRCUIT(circ)->n_streams;
       n_stream->on_circuit = circ;
-      circ->n_streams = n_stream;
+      TO_OR_CIRCUIT(circ)->n_streams = n_stream;
       assert_circuit_ok(circ);
 
       log_debug(LD_EXIT,"about to call connection_exit_connect().");
@@ -1706,9 +1697,9 @@ connection_exit_begin_conn(cell_t *cell,
       break;
     case 0: /* resolve added to pending list */
       /* add it into the linked list of resolving_streams on this circuit */
-      n_stream->next_stream = circ->resolving_streams;
+      n_stream->next_stream = TO_OR_CIRCUIT(circ)->resolving_streams;
       n_stream->on_circuit = circ;
-      circ->resolving_streams = n_stream;
+      TO_OR_CIRCUIT(circ)->resolving_streams = n_stream;
       assert_circuit_ok(circ);
       ;
   }
@@ -1720,12 +1711,12 @@ connection_exit_begin_conn(cell_t *cell,
  * begin resolving the hostname, and (eventually) reply with a RESOLVED cell.
  */
 int
-connection_exit_begin_resolve(cell_t *cell, circuit_t *circ)
+connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ)
 {
   connection_t *dummy_conn;
   relay_header_t rh;
 
-  assert_circuit_ok(circ);
+  assert_circuit_ok(TO_CIRCUIT(circ));
   relay_header_unpack(&rh, cell->payload);
 
   /* This 'dummy_conn' only exists to remember the stream ID
@@ -1754,9 +1745,9 @@ connection_exit_begin_resolve(cell_t *ce
       return 0;
     case 0: /* resolve added to pending list */
       dummy_conn->next_stream = circ->resolving_streams;
-      dummy_conn->on_circuit = circ;
+      dummy_conn->on_circuit = TO_CIRCUIT(circ);
       circ->resolving_streams = dummy_conn;
-      assert_circuit_ok(circ);
+      assert_circuit_ok(TO_CIRCUIT(circ));
       break;
   }
   return 0;

Index: control.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/control.c,v
retrieving revision 1.197
retrieving revision 1.198
diff -u -p -d -r1.197 -r1.198
--- control.c	15 Jul 2006 19:21:30 -0000	1.197
+++ control.c	23 Jul 2006 07:37:35 -0000	1.198
@@ -1372,7 +1372,7 @@ handle_getinfo_helper(const char *questi
       const char *state;
       if (! CIRCUIT_IS_ORIGIN(circ) || circ->marked_for_close)
         continue;
-      path = circuit_list_path(circ,0);
+      path = circuit_list_path(TO_ORIGIN_CIRCUIT(circ),0);
       if (circ->state == CIRCUIT_STATE_OPEN)
         state = "BUILT";
       else if (strlen(path))
@@ -1728,6 +1728,15 @@ handle_control_extendcircuit(connection_
     }
   }
 
+  if (circ && ! CIRCUIT_IS_ORIGIN(circ)) {
+    if (v0)
+      send_control0_error(conn, ERR_NO_CIRC,"Circuit does not originate here");
+    else
+      connection_printf_to_buf(conn,
+                               "555 Circuit does not originate here\r\n");
+    goto done;
+  }
+
   routers = smartlist_create();
   SMARTLIST_FOREACH(router_nicknames, const char *, n,
   {
@@ -1751,20 +1760,20 @@ handle_control_extendcircuit(connection_
 
   if (zero_circ) {
     /* start a new circuit */
-    circ = circuit_init(intended_purpose, 0, 0, 0);
+    circ = TO_CIRCUIT( origin_circuit_init(intended_purpose, 0, 0, 0) );
   }
 
   /* now circ refers to something that is ready to be extended */
   SMARTLIST_FOREACH(routers, routerinfo_t *, r,
   {
     extend_info_t *info = extend_info_from_router(r);
-    circuit_append_new_exit(circ, info);
+    circuit_append_new_exit(TO_ORIGIN_CIRCUIT(circ), info);
     extend_info_free(info);
   });
 
   /* now that we've populated the cpath, start extending */
   if (zero_circ) {
-    if (circuit_handle_first_hop(circ) < 0) {
+    if (circuit_handle_first_hop(TO_ORIGIN_CIRCUIT(circ)) < 0) {
       circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
       if (v0)
         send_control0_error(conn, ERR_INTERNAL, "couldn't start circuit");
@@ -1775,7 +1784,7 @@ handle_control_extendcircuit(connection_
   } else {
     if (circ->state == CIRCUIT_STATE_OPEN) {
       circuit_set_state(circ, CIRCUIT_STATE_BUILDING);
-      if (circuit_send_next_onion_skin(circ) < 0) {
+      if (circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ)) < 0) {
         log_info(LD_CONTROL,
                  "send_next_onion_skin failed; circuit marked for closing.");
         circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
@@ -1940,17 +1949,19 @@ handle_control_attachstream(connection_t
     ap_conn->state = AP_CONN_STATE_CONTROLLER_WAIT;
   }
 
-  if (circ && circ->state != CIRCUIT_STATE_OPEN) {
+  if (circ &&
+      (circ->state != CIRCUIT_STATE_OPEN || ! CIRCUIT_IS_ORIGIN(circ))) {
     if (STATE_IS_V0(conn->state))
       send_control0_error(conn, ERR_INTERNAL,
-                          "Refuse to attach stream to non-open circ.");
+                          "Refuse to attach stream to non-open, origin circ.");
     else
       connection_write_str_to_buf(
-                          "551 Can't attach stream to non-open circuit\r\n",
-                          conn);
+                     "551 Can't attach stream to non-open, origin circuit\r\n",
+                     conn);
     return 0;
   }
-  if (connection_ap_handshake_rewrite_and_attach(ap_conn, circ) < 0) {
+  if (connection_ap_handshake_rewrite_and_attach(ap_conn,
+                                  circ ? TO_ORIGIN_CIRCUIT(circ) : NULL) < 0) {
     if (STATE_IS_V0(conn->state))
       send_control0_error(conn, ERR_INTERNAL, "Unable to attach stream.");
     else
@@ -2195,7 +2206,8 @@ handle_control_closecircuit(connection_t
       return 0;
   }
 
-  if (!safe || !circ->p_streams) {
+  if (!safe || !CIRCUIT_IS_ORIGIN(circ) ||
+      !TO_ORIGIN_CIRCUIT(circ)->p_streams) {
     circuit_mark_for_close(circ, END_CIRC_REASON_NONE);
   }
 
@@ -2586,20 +2598,19 @@ connection_control_process_inbuf(connect
 /** Something has happened to circuit <b>circ</b>: tell any interested
  * control connections. */
 int
-control_event_circuit_status(circuit_t *circ, circuit_status_event_t tp)
+control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t tp)
 {
   char *path, *msg;
   if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS))
     return 0;
   tor_assert(circ);
-  tor_assert(CIRCUIT_IS_ORIGIN(circ));
 
   path = circuit_list_path(circ,0);
   if (EVENT_IS_INTERESTING0(EVENT_CIRCUIT_STATUS)) {
     size_t path_len = strlen(path);
     msg = tor_malloc(1+4+path_len+1); /* event, circid, path, NUL. */
     msg[0] = (uint8_t) tp;
-    set_uint32(msg+1, htonl(circ->global_identifier));
+    set_uint32(msg+1, htonl(circ->_base.global_identifier));
     strlcpy(msg+5,path,path_len+1);
 
     send_control0_event(EVENT_CIRCUIT_STATUS, (uint32_t)(path_len+6), msg);
@@ -2620,7 +2631,7 @@ control_event_circuit_status(circuit_t *
       }
     send_control1_event(EVENT_CIRCUIT_STATUS,
                         "650 CIRC %lu %s %s\r\n",
-                        (unsigned long)circ->global_identifier,
+                        (unsigned long)circ->_base.global_identifier,
                         status, path);
   }
   tor_free(path);

Index: cpuworker.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/cpuworker.c,v
retrieving revision 1.104
retrieving revision 1.105
diff -u -p -d -r1.104 -r1.105
--- cpuworker.c	12 Jun 2006 11:59:19 -0000	1.104
+++ cpuworker.c	23 Jul 2006 07:37:35 -0000	1.105
@@ -181,8 +181,8 @@ connection_cpu_process_inbuf(connection_
       log_debug(LD_OR,"processed onion for a circ that's gone. Dropping.");
       goto done_processing;
     }
-    tor_assert(circ->p_conn);
-    if (onionskin_answer(circ, CELL_CREATED, buf+TAG_LEN,
+    tor_assert(! CIRCUIT_IS_ORIGIN(circ));
+    if (onionskin_answer(TO_OR_CIRCUIT(circ), CELL_CREATED, buf+TAG_LEN,
                          buf+TAG_LEN+ONIONSKIN_REPLY_LEN) < 0) {
       log_warn(LD_OR,"onionskin_answer failed. Closing.");
       circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
@@ -386,7 +386,7 @@ spawn_enough_cpuworkers(void)
 static void
 process_pending_task(connection_t *cpuworker)
 {
-  circuit_t *circ;
+  or_circuit_t *circ;
 
   tor_assert(cpuworker);
 
@@ -444,7 +444,7 @@ int
 assign_to_cpuworker(connection_t *cpuworker, uint8_t question_type,
                     void *task)
 {
-  circuit_t *circ;
+  or_circuit_t *circ;
   char tag[TAG_LEN];
 
   tor_assert(question_type == CPUWORKER_TASK_ONION);
@@ -454,7 +454,7 @@ assign_to_cpuworker(connection_t *cpuwor
 
   if (question_type == CPUWORKER_TASK_ONION) {
     circ = task;
-    tor_assert(circ->onionskin);
+    tor_assert(circ->_base.onionskin);
 
     if (num_cpuworkers_busy == num_cpuworkers) {
       log_debug(LD_OR,"No idle cpuworkers. Queuing.");
@@ -484,9 +484,9 @@ assign_to_cpuworker(connection_t *cpuwor
 
     connection_write_to_buf((char*)&question_type, 1, cpuworker);
     connection_write_to_buf(tag, sizeof(tag), cpuworker);
-    connection_write_to_buf(circ->onionskin, ONIONSKIN_CHALLENGE_LEN,
+    connection_write_to_buf(circ->_base.onionskin, ONIONSKIN_CHALLENGE_LEN,
                             cpuworker);
-    tor_free(circ->onionskin);
+    tor_free(circ->_base.onionskin);
   }
   return 0;
 }

Index: dns.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/dns.c,v
retrieving revision 1.199
retrieving revision 1.200
diff -u -p -d -r1.199 -r1.200
--- dns.c	21 Jul 2006 22:02:58 -0000	1.199
+++ dns.c	23 Jul 2006 07:37:35 -0000	1.200
@@ -686,12 +686,13 @@ dns_found_answer(const char *address, ui
 
         circ = circuit_get_by_edge_conn(pend->conn);
         tor_assert(circ);
+        tor_assert(!CIRCUIT_IS_ORIGIN(circ));
         /* unlink pend->conn from resolving_streams, */
         circuit_detach_stream(circ, pend->conn);
         /* and link it to n_streams */
-        pend->conn->next_stream = circ->n_streams;
+        pend->conn->next_stream = TO_OR_CIRCUIT(circ)->n_streams;
         pend->conn->on_circuit = circ;
-        circ->n_streams = pend->conn;
+        TO_OR_CIRCUIT(circ)->n_streams = pend->conn;
 
         connection_exit_connect(pend->conn);
       } else {

Index: onion.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/onion.c,v
retrieving revision 1.196
retrieving revision 1.197
diff -u -p -d -r1.196 -r1.197
--- onion.c	13 Feb 2006 09:37:53 -0000	1.196
+++ onion.c	23 Jul 2006 07:37:35 -0000	1.197
@@ -17,7 +17,7 @@ const char onion_c_id[] =
 /** Type for a linked list of circuits that are waiting for a free CPU worker
  * to process a waiting onion handshake. */
 typedef struct onion_queue_t {
-  circuit_t *circ;
+  or_circuit_t *circ;
   time_t when_added;
   struct onion_queue_t *next;
 } onion_queue_t;
@@ -35,7 +35,7 @@ static int ol_length=0;
  * if ol_list is too long, in which case do nothing and return -1.
  */
 int
-onion_pending_add(circuit_t *circ)
+onion_pending_add(or_circuit_t *circ)
 {
   onion_queue_t *tmp;
   time_t now = time(NULL);
@@ -75,7 +75,7 @@ onion_pending_add(circuit_t *circ)
     onion_pending_remove(ol_list->circ);
     log_info(LD_CIRC,
              "Circuit create request is too old; cancelling due to overload.");
-    circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
+    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
   }
   return 0;
 }
@@ -83,10 +83,10 @@ onion_pending_add(circuit_t *circ)
 /** Remove the first item from ol_list and return it, or return
  * NULL if the list is empty.
  */
-circuit_t *
+or_circuit_t *
 onion_next_task(void)
 {
-  circuit_t *circ;
+  or_circuit_t *circ;
 
   if (!ol_list)
     return NULL; /* no onions pending, we're done */
@@ -103,7 +103,7 @@ onion_next_task(void)
  * circ, remove and free that element. Leave circ itself alone.
  */
 void
-onion_pending_remove(circuit_t *circ)
+onion_pending_remove(or_circuit_t *circ)
 {
   onion_queue_t *tmpo, *victim;
 

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/or.h,v
retrieving revision 1.854
retrieving revision 1.855
diff -u -p -d -r1.854 -r1.855
--- or.h	22 Jul 2006 07:15:34 -0000	1.854
+++ or.h	23 Jul 2006 07:37:35 -0000	1.855
@@ -1040,7 +1040,10 @@ typedef struct {
   time_t expiry_time;
 } cpath_build_state_t;
 
-#define CIRCUIT_MAGIC 0x35315243u
+#define ORIGIN_CIRCUIT_MAGIC 0x35315243u
+#define OR_CIRCUIT_MAGIC 0x98ABC04Fu
+
+typedef uint16_t circid_t;
 
 /**
  * A circuit is a path over the onion routing
@@ -1064,29 +1067,20 @@ typedef struct {
  * "backward" (towards the OP).  At the OR, a circuit has only two stream
  * ciphers: one for data going forward, and one for data going backward.
  */
-struct circuit_t {
-  uint32_t magic; /**< For memory debugging: must equal CIRCUIT_MAGIC. */
+typedef struct circuit_t {
+  uint32_t magic; /**< For memory and type debugging: must equal
+                   * ORIGIN_CIRCUIT_MAGIC or OR_CIRCUIT_MAGIC. */
 
-  /** The OR connection that is previous in this circuit. */
-  connection_t *p_conn;
   /** The OR connection that is next in this circuit. */
   connection_t *n_conn;
   /** The identity hash of n_conn. */
   char n_conn_id_digest[DIGEST_LEN];
-  /** Linked list of AP streams associated with this circuit. */
-  connection_t *p_streams;
-  /** Linked list of Exit streams associated with this circuit. */
-  connection_t *n_streams;
-  /** Linked list of Exit streams associated with this circuit that are
-   * still being resolved. */
-  connection_t *resolving_streams;
+  /** The circuit_id used in the next (forward) hop of this circuit. */
+  uint16_t n_circ_id;
   /** The IPv4 address of the OR that is next in this circuit. */
   uint32_t n_addr;
   /** The port for the OR that is next in this circuit. */
   uint16_t n_port;
-  /** The next stream_id that will be tried when we're attempting to
-   * construct a new AP stream originating at this circuit. */
-  uint16_t next_stream_id;
   /** How many relay data cells can we package (read from edge streams)
    * on this circuit before we receive a circuit-level sendme cell asking
    * for more? */
@@ -1097,48 +1091,12 @@ struct circuit_t {
    * more. */
   int deliver_window;
 
-  /** The circuit_id used in the previous (backward) hop of this circuit. */
-  uint16_t p_circ_id;
-  /** The circuit_id used in the next (forward) hop of this circuit. */
-  uint16_t n_circ_id;
-
-  /** The cipher used by intermediate hops for cells heading toward the
-   * OP. */
-  crypto_cipher_env_t *p_crypto;
-  /** The cipher used by intermediate hops for cells heading away from
-   * the OP. */
-  crypto_cipher_env_t *n_crypto;
-
-  /** The integrity-checking digest used by intermediate hops, for
-   * cells packaged here and heading towards the OP.
-   */
-  crypto_digest_env_t *p_digest;
-  /** The integrity-checking digest used by intermediate hops, for
-   * cells packaged at the OP and arriving here.
-   */
-  crypto_digest_env_t *n_digest;
-
-  /** Build state for this circuit. It includes the intended path
-   * length, the chosen exit router, rendezvous information, etc.
-   */
-  cpath_build_state_t *build_state;
-  /** The doubly-linked list of crypt_path_t entries, one per hop,
-   * for this circuit. This includes ciphers for each hop,
-   * integrity-checking digests for each hop, and package/delivery
-   * windows for each hop.
-   *
-   * The cpath field is defined only when we are the circuit's origin.
-   */
-  crypt_path_t *cpath;
-
   /** For storage while passing to cpuworker (state
     * CIRCUIT_STATE_ONIONSKIN_PENDING), or while n_conn is pending
     * (state CIRCUIT_STATE_OR_WAIT). When defined, it is always
     * length ONIONSKIN_CHALLENGE_LEN. */
   char *onionskin;
 
-  char handshake_digest[DIGEST_LEN]; /**< Stores KH for intermediate hops. */
-
   time_t timestamp_created; /**< When was this circuit created? */
   time_t timestamp_dirty; /**< When the circuit was first used, or 0 if the
                            * circuit is clean. */
@@ -1169,18 +1127,85 @@ struct circuit_t {
    */
   char rend_cookie[REND_COOKIE_LEN];
 
-  /** Points to spliced circuit if purpose is REND_ESTABLISHED, and circuit
-   * is not marked for close. */
-  struct circuit_t *rend_splice;
-
   /** Quasi-global identifier for this circuit; used for control.c */
   /* XXXX NM This can get re-used after 2**32 circuits. */
   uint32_t global_identifier;
 
   struct circuit_t *next; /**< Next circuit in linked list. */
-};
+} circuit_t;
 
-typedef struct circuit_t circuit_t;
+typedef struct origin_circuit_t {
+  circuit_t _base;
+
+  /** Linked list of AP streams associated with this circuit. */
+  connection_t *p_streams;
+  /** The next stream_id that will be tried when we're attempting to
+   * construct a new AP stream originating at this circuit. */
+  uint16_t next_stream_id;
+  /** Build state for this circuit. It includes the intended path
+   * length, the chosen exit router, rendezvous information, etc.
+   */
+  cpath_build_state_t *build_state;
+  /** The doubly-linked list of crypt_path_t entries, one per hop,
+   * for this circuit. This includes ciphers for each hop,
+   * integrity-checking digests for each hop, and package/delivery
+   * windows for each hop.
+   *
+   * The cpath field is defined only when we are the circuit's origin.
+   */
+  crypt_path_t *cpath;
+
+} origin_circuit_t;
+
+typedef struct or_circuit_t {
+  circuit_t _base;
+
+  /** The circuit_id used in the previous (backward) hop of this circuit. */
+  circid_t p_circ_id;
+  /** The OR connection that is previous in this circuit. */
+  connection_t *p_conn;
+  /** Linked list of Exit streams associated with this circuit. */
+  connection_t *n_streams;
+  /** Linked list of Exit streams associated with this circuit that are
+   * still being resolved. */
+  connection_t *resolving_streams;
+    /** The cipher used by intermediate hops for cells heading toward the
+   * OP. */
+  crypto_cipher_env_t *p_crypto;
+  /** The cipher used by intermediate hops for cells heading away from
+   * the OP. */
+  crypto_cipher_env_t *n_crypto;
+
+  /** The integrity-checking digest used by intermediate hops, for
+   * cells packaged here and heading towards the OP.
+   */
+  crypto_digest_env_t *p_digest;
+  /** The integrity-checking digest used by intermediate hops, for
+   * cells packaged at the OP and arriving here.
+   */
+  crypto_digest_env_t *n_digest;
+
+  /** Points to spliced circuit if purpose is REND_ESTABLISHED, and circuit
+   * is not marked for close. */
+  struct or_circuit_t *rend_splice;
+
+  char handshake_digest[DIGEST_LEN]; /**< Stores KH for intermediate hops. */
+} or_circuit_t;
+
+#define TO_CIRCUIT(x)  (&((x)->_base))
+or_circuit_t *TO_OR_CIRCUIT(circuit_t *x);
+extern INLINE or_circuit_t *TO_OR_CIRCUIT(circuit_t *x)
+{
+  tor_assert(x->magic == OR_CIRCUIT_MAGIC);
+  return (or_circuit_t*) (((char*)x) - STRUCT_OFFSET(or_circuit_t, _base));
+}
+origin_circuit_t *TO_ORIGIN_CIRCUIT(circuit_t *x);
+extern INLINE origin_circuit_t *TO_ORIGIN_CIRCUIT(circuit_t *x)
+{
+  tor_assert(x->magic == ORIGIN_CIRCUIT_MAGIC);
+  return (origin_circuit_t*)
+    (((char*)x) - STRUCT_OFFSET(origin_circuit_t, _base));
+}
 
 #define ALLOW_INVALID_ENTRY        1
 #define ALLOW_INVALID_EXIT         2
@@ -1505,32 +1530,34 @@ void assert_buf_ok(buf_t *buf);
 
 /********************************* circuitbuild.c **********************/
 
-char *circuit_list_path(circuit_t *circ, int verbose);
-void circuit_log_path(int severity, unsigned int domain, circuit_t *circ);
-void circuit_rep_hist_note_result(circuit_t *circ);
-void circuit_dump_by_conn(connection_t *conn, int severity);
-circuit_t *circuit_init(uint8_t purpose, int need_uptime,
-                        int need_capacity, int internal);
-circuit_t *circuit_establish_circuit(uint8_t purpose, extend_info_t *exit,
+char *circuit_list_path(origin_circuit_t *circ, int verbose);
+void circuit_log_path(int severity, unsigned int domain,
+                      origin_circuit_t *circ);
+void circuit_rep_hist_note_result(origin_circuit_t *circ);
+origin_circuit_t *origin_circuit_init(uint8_t purpose, int need_uptime,
+                                      int need_capacity, int internal);
+origin_circuit_t *circuit_establish_circuit(uint8_t purpose,
+                                     extend_info_t *exit,
                                      int need_uptime, int need_capacity,
                                      int internal);
-int circuit_handle_first_hop(circuit_t *circ);
+int circuit_handle_first_hop(origin_circuit_t *circ);
 void circuit_n_conn_done(connection_t *or_conn, int status);
 int inform_testing_reachability(void);
-int circuit_send_next_onion_skin(circuit_t *circ);
+int circuit_send_next_onion_skin(origin_circuit_t *circ);
 void circuit_note_clock_jumped(int seconds_elapsed);
 int circuit_extend(cell_t *cell, circuit_t *circ);
 int circuit_init_cpath_crypto(crypt_path_t *cpath, char *key_data,
                               int reverse);
-int circuit_finish_handshake(circuit_t *circ, uint8_t cell_type, char *reply);
-int circuit_truncated(circuit_t *circ, crypt_path_t *layer);
-int onionskin_answer(circuit_t *circ, uint8_t cell_type, char *payload,
+int circuit_finish_handshake(origin_circuit_t *circ, uint8_t cell_type,
+                             char *reply);
+int circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer);
+int onionskin_answer(or_circuit_t *circ, uint8_t cell_type, char *payload,
                      char *keys);
 int circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
                                         int *need_capacity);
 
-int circuit_append_new_exit(circuit_t *circ, extend_info_t *info);
-int circuit_extend_to_new_exit(circuit_t *circ, extend_info_t *info);
+int circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info);
+int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info);
 void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop);
 extend_info_t *extend_info_from_router(routerinfo_t *r);
 extend_info_t *extend_info_dup(extend_info_t *info);
@@ -1551,13 +1578,15 @@ void entry_guards_free_all(void);
 
 circuit_t * _circuit_get_global_list(void);
 const char *circuit_state_to_string(int state);
-enum which_conn_changed_t { P_CONN_CHANGED=1, N_CONN_CHANGED=0 };
-void circuit_set_circid_orconn(circuit_t *circ, uint16_t id,
-                               connection_t *conn,
-                               enum which_conn_changed_t which);
+void circuit_dump_by_conn(connection_t *conn, int severity);
+void circuit_set_p_circid_orconn(or_circuit_t *circ, uint16_t id,
+                                 connection_t *conn);
+void circuit_set_n_circid_orconn(circuit_t *circ, uint16_t id,
+                                 connection_t *conn);
 void circuit_set_state(circuit_t *circ, int state);
 void circuit_close_all_marked(void);
-circuit_t *circuit_new(uint16_t p_circ_id, connection_t *p_conn);
+origin_circuit_t *origin_circuit_new(void);
+or_circuit_t *or_circuit_new(uint16_t p_circ_id, connection_t *p_conn);
 circuit_t *circuit_get_by_circid_orconn(uint16_t circ_id, connection_t *conn);
 int circuit_id_used_on_conn(uint16_t circ_id, connection_t *conn);
 circuit_t *circuit_get_by_edge_conn(connection_t *conn);
@@ -1567,8 +1596,9 @@ circuit_t *circuit_get_by_rend_query_and
                                                  uint8_t purpose);
 circuit_t *circuit_get_next_by_pk_and_purpose(circuit_t *start,
                                          const char *digest, uint8_t purpose);
-circuit_t *circuit_get_rendezvous(const char *cookie);
-circuit_t *circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
+or_circuit_t *circuit_get_rendezvous(const char *cookie);
+origin_circuit_t *circuit_find_to_cannibalize(uint8_t purpose,
+                                       extend_info_t *info,
                                        int need_uptime,
                                        int need_capacity, int internal);
 void circuit_mark_all_unused_circs(void);
@@ -1592,22 +1622,22 @@ int circuit_stream_is_being_handled(conn
 void circuit_build_needed_circs(time_t now);
 void circuit_detach_stream(circuit_t *circ, connection_t *conn);
 void circuit_about_to_close_connection(connection_t *conn);
-void circuit_has_opened(circuit_t *circ);
-void circuit_build_failed(circuit_t *circ);
-circuit_t *circuit_launch_by_nickname(uint8_t purpose,
+void circuit_has_opened(origin_circuit_t *circ);
+void circuit_build_failed(origin_circuit_t *circ);
+origin_circuit_t *circuit_launch_by_nickname(uint8_t purpose,
                                       const char *exit_nickname,
                                       int need_uptime, int need_capacity,
                                       int is_internal);
-circuit_t *circuit_launch_by_extend_info(uint8_t purpose,
+origin_circuit_t *circuit_launch_by_extend_info(uint8_t purpose,
                                          extend_info_t *info,
                                          int need_uptime, int need_capacity,
                                          int is_internal);
-circuit_t *circuit_launch_by_router(uint8_t purpose, routerinfo_t *exit,
+origin_circuit_t *circuit_launch_by_router(uint8_t purpose, routerinfo_t *exit,
                                     int need_uptime, int need_capacity,
                                     int is_internal);
 void circuit_reset_failure_count(int timeout);
 int connection_ap_handshake_attach_chosen_circuit(connection_t *conn,
-                                                  circuit_t *circ);
+                                                  origin_circuit_t *circ);
 int connection_ap_handshake_attach_circuit(connection_t *conn);
 
 /********************************* command.c ***************************/
@@ -1733,9 +1763,10 @@ int connection_edge_end_errno(connection
 int connection_edge_finished_flushing(connection_t *conn);
 int connection_edge_finished_connecting(connection_t *conn);
 
-int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ);
+int connection_ap_handshake_send_begin(connection_t *ap_conn,
+                                       origin_circuit_t *circ);
 int connection_ap_handshake_send_resolve(connection_t *ap_conn,
-                                         circuit_t *circ);
+                                         origin_circuit_t *circ);
 
 int connection_ap_make_bridge(char *address, uint16_t port);
 void connection_ap_handshake_socks_reply(connection_t *conn, char *reply,
@@ -1748,13 +1779,13 @@ void connection_ap_handshake_socks_resol
                                             int ttl);
 
 int connection_exit_begin_conn(cell_t *cell, circuit_t *circ);
-int connection_exit_begin_resolve(cell_t *cell, circuit_t *circ);
+int connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ);
 void connection_exit_connect(connection_t *conn);
 int connection_edge_is_rendezvous_stream(connection_t *conn);
 int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit);
 void connection_ap_expire_beginning(void);
 void connection_ap_attach_pending(void);
-int connection_ap_detach_retriable(connection_t *conn, circuit_t *circ);
+int connection_ap_detach_retriable(connection_t *conn, origin_circuit_t *circ);
 
 void addressmap_init(void);
 void addressmap_clean(time_t now);
@@ -1776,7 +1807,7 @@ const char *addressmap_register_virtual_
 void addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
                              time_t max_expires);
 int connection_ap_handshake_rewrite_and_attach(connection_t *conn,
-                                               circuit_t *circ);
+                                               origin_circuit_t *circ);
 
 void set_exit_redirects(smartlist_t *lst);
 typedef enum hostname_type_t {
@@ -1865,7 +1896,8 @@ int connection_control_finished_flushing
 int connection_control_reached_eof(connection_t *conn);
 int connection_control_process_inbuf(connection_t *conn);
 
-int control_event_circuit_status(circuit_t *circ, circuit_status_event_t e);
+int control_event_circuit_status(origin_circuit_t *circ,
+                                 circuit_status_event_t e);
 int control_event_stream_status(connection_t *conn, stream_status_event_t e);
 int control_event_or_conn_status(connection_t *conn, or_conn_status_event_t e);
 int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written);
@@ -2026,9 +2058,9 @@ int tor_main(int argc, char *argv[]);
 
 /********************************* onion.c ***************************/
 
-int onion_pending_add(circuit_t *circ);
-circuit_t *onion_next_task(void);
-void onion_pending_remove(circuit_t *circ);
+int onion_pending_add(or_circuit_t *circ);
+or_circuit_t *onion_next_task(void);
+void onion_pending_remove(or_circuit_t *circ);
 
 int onion_skin_create(crypto_pk_env_t *router_key,
                       crypto_dh_env_t **handshake_state_out,
@@ -2148,22 +2180,23 @@ void rep_hist_free_all(void);
 
 /********************************* rendclient.c ***************************/
 
-void rend_client_introcirc_has_opened(circuit_t *circ);
-void rend_client_rendcirc_has_opened(circuit_t *circ);
-int rend_client_introduction_acked(circuit_t *circ, const char *request,
+void rend_client_introcirc_has_opened(origin_circuit_t *circ);
+void rend_client_rendcirc_has_opened(origin_circuit_t *circ);
+int rend_client_introduction_acked(origin_circuit_t *circ, const char *request,
                                    size_t request_len);
 void rend_client_refetch_renddesc(const char *query);
 int rend_client_remove_intro_point(extend_info_t *failed_intro,
                                    const char *query);
-int rend_client_rendezvous_acked(circuit_t *circ, const char *request,
+int rend_client_rendezvous_acked(origin_circuit_t *circ, const char *request,
                                  size_t request_len);
-int rend_client_receive_rendezvous(circuit_t *circ, const char *request,
+int rend_client_receive_rendezvous(origin_circuit_t *circ, const char *request,
                                    size_t request_len);
 void rend_client_desc_here(const char *query);
 
 extend_info_t *rend_client_get_random_intro(const char *query);
 
-int rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc);
+int rend_client_send_introduction(origin_circuit_t *introcirc,
+                                  origin_circuit_t *rendcirc);
 
 /********************************* rendcommon.c ***************************/
 
@@ -2228,25 +2261,27 @@ void rend_services_init(void);
 void rend_services_introduce(void);
 void rend_consider_services_upload(time_t now);
 
-void rend_service_intro_has_opened(circuit_t *circuit);
-int rend_service_intro_established(circuit_t *circuit, const char *request,
+void rend_service_intro_has_opened(origin_circuit_t *circuit);
+int rend_service_intro_established(origin_circuit_t *circuit,
+                                   const char *request,
                                    size_t request_len);
-void rend_service_rendezvous_has_opened(circuit_t *circuit);
-int rend_service_introduce(circuit_t *circuit, const char *request,
+void rend_service_rendezvous_has_opened(origin_circuit_t *circuit);
+int rend_service_introduce(origin_circuit_t *circuit, const char *request,
                            size_t request_len);
-void rend_service_relaunch_rendezvous(circuit_t *oldcirc);
-int rend_service_set_connection_addr_port(connection_t *conn, circuit_t *circ);
+void rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc);
+int rend_service_set_connection_addr_port(connection_t *conn,
+                                          origin_circuit_t *circ);
 void rend_service_dump_stats(int severity);
 void rend_service_free_all(void);
 
 /********************************* rendmid.c *******************************/
-int rend_mid_establish_intro(circuit_t *circ, const char *request,
+int rend_mid_establish_intro(or_circuit_t *circ, const char *request,
                              size_t request_len);
-int rend_mid_introduce(circuit_t *circ, const char *request,
+int rend_mid_introduce(or_circuit_t *circ, const char *request,
                        size_t request_len);
-int rend_mid_establish_rendezvous(circuit_t *circ, const char *request,
+int rend_mid_establish_rendezvous(or_circuit_t *circ, const char *request,
                                   size_t request_len);
-int rend_mid_rendezvous(circuit_t *circ, const char *request,
+int rend_mid_rendezvous(or_circuit_t *circ, const char *request,
                         size_t request_len);
 
 /********************************* router.c ***************************/

Index: relay.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/relay.c,v
retrieving revision 1.103
retrieving revision 1.104
diff -u -p -d -r1.103 -r1.104
--- relay.c	18 Jul 2006 00:58:11 -0000	1.103
+++ relay.c	23 Jul 2006 07:37:35 -0000	1.104
@@ -191,18 +191,24 @@ circuit_receive_relay_cell(cell_t *cell,
   if (cell_direction == CELL_DIRECTION_OUT) {
     cell->circ_id = circ->n_circ_id; /* switch it */
     conn = circ->n_conn;
+  } else if (! CIRCUIT_IS_ORIGIN(circ)) {
+    cell->circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; /* switch it */
+    conn = TO_OR_CIRCUIT(circ)->p_conn;
   } else {
-    cell->circ_id = circ->p_circ_id; /* switch it */
-    conn = circ->p_conn;
+    // XXXX NM WARN.
+    return 0;
   }
 
   if (!conn) {
-    if (circ->rend_splice && cell_direction == CELL_DIRECTION_OUT) {
+    // XXXX Can this splice stuff be done more cleanly?
+    if (! CIRCUIT_IS_ORIGIN(circ) &&
+        TO_OR_CIRCUIT(circ)->rend_splice &&
+        cell_direction == CELL_DIRECTION_OUT) {
+      or_circuit_t *splice = TO_OR_CIRCUIT(circ)->rend_splice;
       tor_assert(circ->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED);
-      tor_assert(circ->rend_splice->purpose ==
-                 CIRCUIT_PURPOSE_REND_ESTABLISHED);
-      cell->circ_id = circ->rend_splice->p_circ_id;
-      if ((reason = circuit_receive_relay_cell(cell, circ->rend_splice,
+      tor_assert(splice->_base.purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED);
+      cell->circ_id = splice->p_circ_id;
+      if ((reason = circuit_receive_relay_cell(cell, TO_CIRCUIT(splice),
                                                CELL_DIRECTION_IN)) < 0) {
         log_warn(LD_REND, "Error relaying cell across rendezvous; closing "
                  "circuits");
@@ -244,7 +250,6 @@ static int
 relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction,
             crypt_path_t **layer_hint, char *recognized)
 {
-  crypt_path_t *thishop;
   relay_header_t rh;
 
   tor_assert(circ);
@@ -256,8 +261,8 @@ relay_crypt(circuit_t *circ, cell_t *cel
   if (cell_direction == CELL_DIRECTION_IN) {
     if (CIRCUIT_IS_ORIGIN(circ)) { /* We're at the beginning of the circuit.
                                     * We'll want to do layered decrypts. */
-      tor_assert(circ->cpath);
-      thishop = circ->cpath;
+      crypt_path_t *thishop, *cpath = TO_ORIGIN_CIRCUIT(circ)->cpath;
+      thishop = cpath;
       if (thishop->state != CPATH_STATE_OPEN) {
         log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
                "Relay cell before first created cell? Closing.");
@@ -280,11 +285,12 @@ relay_crypt(circuit_t *circ, cell_t *cel
         }
 
         thishop = thishop->next;
-      } while (thishop != circ->cpath && thishop->state == CPATH_STATE_OPEN);
+      } while (thishop != cpath && thishop->state == CPATH_STATE_OPEN);
       log_warn(LD_OR,"in-cell at OP not recognized. Closing.");
       return -1;
     } else { /* we're in the middle. Just one crypt. */
-      if (relay_crypt_one_payload(circ->p_crypto, cell->payload, 1) < 0)
+      if (relay_crypt_one_payload(TO_OR_CIRCUIT(circ)->p_crypto,
+                                  cell->payload, 1) < 0)
         return -1;
 //      log_fn(LOG_DEBUG,"Skipping recognized check, because we're not "
 //             "the OP.");
@@ -292,13 +298,14 @@ relay_crypt(circuit_t *circ, cell_t *cel
   } else /* cell_direction == CELL_DIRECTION_OUT */ {
     /* we're in the middle. Just one crypt. */
 
-    if (relay_crypt_one_payload(circ->n_crypto, cell->payload, 0) < 0)
+    if (relay_crypt_one_payload(TO_OR_CIRCUIT(circ)->n_crypto,
+                                cell->payload, 0) < 0)
       return -1;
 
     relay_header_unpack(&rh, cell->payload);
     if (rh.recognized == 0) {
       /* it's possibly recognized. have to check digest to be sure. */
-      if (relay_digest_matches(circ->n_digest, cell)) {
+      if (relay_digest_matches(TO_OR_CIRCUIT(circ)->n_digest, cell)) {
         *recognized = 1;
         return 0;
       }
@@ -307,7 +314,7 @@ relay_crypt(circuit_t *circ, cell_t *cel
   return 0;
 }
 
-/** Package a relay cell:
+/** Package a relay cell from an edge:
  *  - Encrypt it to the right layer
  *  - connection_or_write_cell_to_buf to the right conn
  */
@@ -317,11 +324,11 @@ circuit_package_relay_cell(cell_t *cell,
                            crypt_path_t *layer_hint)
 {
   connection_t *conn; /* where to send the cell */
-  crypt_path_t *thishop; /* counter for repeated crypts */
 
   if (cell_direction == CELL_DIRECTION_OUT) {
+    crypt_path_t *thishop; /* counter for repeated crypts */
     conn = circ->n_conn;
-    if (!conn) {
+    if (!CIRCUIT_IS_ORIGIN(circ) || !conn) {
       log_warn(LD_BUG,"outgoing relay cell has n_conn==NULL. Dropping.");
       return 0; /* just drop it */
     }
@@ -338,18 +345,20 @@ circuit_package_relay_cell(cell_t *cell,
       }
 
       thishop = thishop->prev;
-    } while (thishop != circ->cpath->prev);
+    } while (thishop != TO_ORIGIN_CIRCUIT(circ)->cpath->prev);
 
   } else { /* incoming cell */
-    conn = circ->p_conn;
-    if (!conn) {
+    or_circuit_t *or_circ;
+    if (CIRCUIT_IS_ORIGIN(circ)) {
       /* XXXX RD This is a bug, right? */
-      log_warn(LD_BUG,"incoming relay cell has p_conn==NULL. Dropping.");
+      log_warn(LD_BUG,"incoming relay cell at origin circuit. Dropping.");
       assert_circuit_ok(circ);
       return 0; /* just drop it */
     }
-    relay_set_digest(circ->p_digest, cell);
-    if (relay_crypt_one_payload(circ->p_crypto, cell->payload, 1) < 0)
+    or_circ = TO_OR_CIRCUIT(circ);
+    conn = or_circ->p_conn;
+    relay_set_digest(or_circ->p_digest, cell);
+    if (relay_crypt_one_payload(or_circ->p_crypto, cell->payload, 1) < 0)
       return -1;
   }
   ++stats_n_relay_cells_relayed;
@@ -375,25 +384,30 @@ relay_lookup_conn(circuit_t *circ, cell_
    * that we allow rendezvous *to* an OP.
    */
 
-  for (tmpconn = circ->n_streams; tmpconn; tmpconn=tmpconn->next_stream) {
-    if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) {
-      log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id);
-      if (cell_direction == CELL_DIRECTION_OUT ||
-          connection_edge_is_rendezvous_stream(tmpconn))
+  if (CIRCUIT_IS_ORIGIN(circ)) {
+    for (tmpconn = TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn;
+         tmpconn=tmpconn->next_stream) {
+      if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) {
+        log_debug(LD_APP,"found conn for stream %d.", rh.stream_id);
         return tmpconn;
+      }
     }
-  }
-  for (tmpconn = circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream) {
-    if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) {
-      log_debug(LD_APP,"found conn for stream %d.", rh.stream_id);
-      return tmpconn;
+  } else {
+    for (tmpconn = TO_OR_CIRCUIT(circ)->n_streams; tmpconn;
+         tmpconn=tmpconn->next_stream) {
+      if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) {
+        log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id);
+        if (cell_direction == CELL_DIRECTION_OUT ||
+            connection_edge_is_rendezvous_stream(tmpconn))
+          return tmpconn;
+      }
     }
-  }
-  for (tmpconn = circ->resolving_streams; tmpconn;
-       tmpconn=tmpconn->next_stream) {
-    if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) {
-      log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id);
-      return tmpconn;
+    for (tmpconn = TO_OR_CIRCUIT(circ)->resolving_streams; tmpconn;
+         tmpconn=tmpconn->next_stream) {
+      if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) {
+        log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id);
+        return tmpconn;
+      }
     }
   }
   return NULL; /* probably a begin relay cell */
@@ -445,6 +459,7 @@ connection_edge_send_command(connection_
   cell_t cell;
   relay_header_t rh;
   int cell_direction;
+  /* XXXX NM Split this function into a separate versions per circuit type? */
 
   if (fromconn && fromconn->marked_for_close) {
     log_warn(LD_BUG,
@@ -471,9 +486,11 @@ connection_edge_send_command(connection_
   if (cpath_layer) {
     cell.circ_id = circ->n_circ_id;
     cell_direction = CELL_DIRECTION_OUT;
-  } else {
-    cell.circ_id = circ->p_circ_id;
+  } else if (! CIRCUIT_IS_ORIGIN(circ)) {
+    cell.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
     cell_direction = CELL_DIRECTION_IN;
+  } else {
+    return -1;
   }
 
   memset(&rh, 0, sizeof(rh));
@@ -647,7 +664,7 @@ edge_reason_is_retriable(int reason)
  */
 static int
 connection_edge_process_end_not_open(
-    relay_header_t *rh, cell_t *cell, circuit_t *circ,
+    relay_header_t *rh, cell_t *cell, origin_circuit_t *circ,
     connection_t *conn, crypt_path_t *layer_hint)
 {
   struct in_addr in;
@@ -716,8 +733,8 @@ connection_edge_process_end_not_open(
             < MAX_RESOLVE_FAILURES) {
           /* We haven't retried too many times; reattach the connection. */
           circuit_log_path(LOG_INFO,LD_APP,circ);
-          tor_assert(circ->timestamp_dirty);
-          circ->timestamp_dirty -= get_options()->MaxCircuitDirtiness;
+          tor_assert(circ->_base.timestamp_dirty);
+          circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
 
           if (conn->chosen_exit_optional) { /* stop wanting a specific exit */
             conn->chosen_exit_optional = 0;
@@ -780,11 +797,17 @@ connection_edge_process_relay_cell_not_o
     relay_header_t *rh, cell_t *cell, circuit_t *circ,
     connection_t *conn, crypt_path_t *layer_hint)
 {
-  if (rh->command == RELAY_COMMAND_END)
-    return connection_edge_process_end_not_open(rh, cell, circ, conn,
-                                                layer_hint);
+  if (rh->command == RELAY_COMMAND_END) {
+    if (CIRCUIT_IS_ORIGIN(circ))
+      return connection_edge_process_end_not_open(rh, cell,
+                                                 TO_ORIGIN_CIRCUIT(circ), conn,
+                                                 layer_hint);
+    else
+      return 0;
+  }
 
   if (conn->type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_CONNECTED) {
+    tor_assert(CIRCUIT_IS_ORIGIN(circ));
     if (conn->state != AP_CONN_STATE_CONNECT_WAIT) {
       log_warn(LD_APP,"Got 'connected' while not in state connect_wait. "
                "Dropping.");
@@ -812,7 +835,7 @@ connection_edge_process_relay_cell_not_o
       client_dns_set_addressmap(conn->socks_request->address, addr,
                                 conn->chosen_exit_name, ttl);
     }
-    circuit_log_path(LOG_INFO,LD_APP,circ);
+    circuit_log_path(LOG_INFO,LD_APP,TO_ORIGIN_CIRCUIT(circ));
     connection_ap_handshake_socks_reply(conn, NULL, 0, SOCKS5_SUCCEEDED);
     /* handle anything that might have queued */
     if (connection_edge_package_raw_inbuf(conn, 1) < 0) {
@@ -967,16 +990,6 @@ connection_edge_process_relay_cell(cell_
       if (conn->socks_request && !conn->socks_request->has_finished)
         log_warn(LD_BUG,
                  "Bug: open stream hasn't sent socks answer yet? Closing.");
-#ifdef HALF_OPEN
-      conn->done_sending = 1;
-      shutdown(conn->s, 1); /* XXX check return; refactor NM */
-      if (conn->done_receiving) {
-        /* We just *got* an end; no reason to send one. */
-        conn->has_sent_end = 1;
-        connection_mark_for_close(conn);
-        conn->hold_open_until_flushed = 1;
-      }
-#else
       /* We just *got* an end; no reason to send one. */
       conn->has_sent_end = 1;
       if (!conn->marked_for_close) {
@@ -985,7 +998,6 @@ connection_edge_process_relay_cell(cell_
         connection_mark_for_close(conn);
         conn->hold_open_until_flushed = 1;
       }
-#endif
       return 0;
     case RELAY_COMMAND_EXTEND:
       if (conn) {
@@ -1000,12 +1012,13 @@ connection_edge_process_relay_cell(cell_
         return 0;
       }
       log_debug(domain,"Got an extended cell! Yay.");
-      if ((reason = circuit_finish_handshake(circ, CELL_CREATED,
+      if ((reason = circuit_finish_handshake(TO_ORIGIN_CIRCUIT(circ),
+                                       CELL_CREATED,
                                        cell->payload+RELAY_HEADER_SIZE)) < 0) {
         log_warn(domain,"circuit_finish_handshake failed.");
         return reason;
       }
-      if ((reason=circuit_send_next_onion_skin(circ))<0) {
+      if ((reason=circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ)))<0) {
         log_info(domain,"circuit_send_next_onion_skin() failed.");
         return reason;
       }
@@ -1018,7 +1031,7 @@ connection_edge_process_relay_cell(cell_
       if (circ->n_conn) {
         uint8_t reason = *(uint8_t*)(cell->payload + RELAY_HEADER_SIZE);
         connection_or_send_destroy(circ->n_circ_id, circ->n_conn, reason);
-        circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED);
+        circuit_set_n_circid_orconn(circ, 0, NULL);
       }
       log_debug(LD_EXIT, "Processed 'truncate', replying.");
       {
@@ -1033,7 +1046,7 @@ connection_edge_process_relay_cell(cell_
         log_warn(LD_EXIT,"'truncated' unsupported at non-origin. Dropping.");
         return 0;
       }
-      circuit_truncated(circ, layer_hint);
+      circuit_truncated(TO_ORIGIN_CIRCUIT(circ), layer_hint);
       return 0;
     case RELAY_COMMAND_CONNECTED:
       if (conn) {
@@ -1083,7 +1096,7 @@ connection_edge_process_relay_cell(cell_
                  circ->purpose);
         return 0;
       }
-      connection_exit_begin_resolve(cell, circ);
+      connection_exit_begin_resolve(cell, TO_OR_CIRCUIT(circ));
       return 0;
     case RELAY_COMMAND_RESOLVED:
       if (conn) {
@@ -1252,10 +1265,12 @@ circuit_resume_edge_reading(circuit_t *c
 
   log_debug(layer_hint?LD_APP:LD_EXIT,"resuming");
 
-  /* have to check both n_streams and p_streams, to handle rendezvous */
-  if (circuit_resume_edge_reading_helper(circ->n_streams, circ, layer_hint)
-      >= 0)
-    circuit_resume_edge_reading_helper(circ->p_streams, circ, layer_hint);
+  if (CIRCUIT_IS_ORIGIN(circ))
+    circuit_resume_edge_reading_helper(TO_ORIGIN_CIRCUIT(circ)->p_streams,
+                                       circ, layer_hint);
+  else
+    circuit_resume_edge_reading_helper(TO_OR_CIRCUIT(circ)->n_streams,
+                                       circ, layer_hint);
 }
 
 /** A helper function for circuit_resume_edge_reading() above.
@@ -1304,11 +1319,12 @@ circuit_consider_stop_edge_reading(circu
   unsigned domain = layer_hint ? LD_APP : LD_EXIT;
 
   if (!layer_hint) {
+    or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
     log_debug(domain,"considering circ->package_window %d",
               circ->package_window);
     if (circ->package_window <= 0) {
       log_debug(domain,"yes, not-at-origin. stopped.");
-      for (conn = circ->n_streams; conn; conn=conn->next_stream)
+      for (conn = or_circ->n_streams; conn; conn=conn->next_stream)
         connection_stop_reading(conn);
       return 1;
     }
@@ -1319,10 +1335,14 @@ circuit_consider_stop_edge_reading(circu
             layer_hint->package_window);
   if (layer_hint->package_window <= 0) {
     log_debug(domain,"yes, at-origin. stopped.");
+#if 0
+    // XXXX NM DEAD CODE.
     for (conn = circ->n_streams; conn; conn=conn->next_stream)
       if (conn->cpath_layer == layer_hint)
         connection_stop_reading(conn);
-    for (conn = circ->p_streams; conn; conn=conn->next_stream)
+#endif
+    for (conn = TO_ORIGIN_CIRCUIT(circ)->p_streams; conn;
+         conn=conn->next_stream)
       if (conn->cpath_layer == layer_hint)
         connection_stop_reading(conn);
     return 1;

Index: rendclient.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/rendclient.c,v
retrieving revision 1.108
retrieving revision 1.109
diff -u -p -d -r1.108 -r1.109
--- rendclient.c	4 Jun 2006 22:42:13 -0000	1.108
+++ rendclient.c	23 Jul 2006 07:37:35 -0000	1.109
@@ -14,10 +14,9 @@ const char rendclient_c_id[] =
 /** Called when we've established a circuit to an introduction point:
  * send the introduction request. */
 void
-rend_client_introcirc_has_opened(circuit_t *circ)
+rend_client_introcirc_has_opened(origin_circuit_t *circ)
 {
-  tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
-  tor_assert(CIRCUIT_IS_ORIGIN(circ));
+  tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
   tor_assert(circ->cpath);
 
   log_info(LD_REND,"introcirc is open");
@@ -28,19 +27,19 @@ rend_client_introcirc_has_opened(circuit
  * it fails, mark the circ for close and return -1. else return 0.
  */
 static int
-rend_client_send_establish_rendezvous(circuit_t *circ)
+rend_client_send_establish_rendezvous(origin_circuit_t *circ)
 {
-  tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
+  tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
   log_info(LD_REND, "Sending an ESTABLISH_RENDEZVOUS cell");
 
-  if (crypto_rand(circ->rend_cookie, REND_COOKIE_LEN) < 0) {
+  if (crypto_rand(circ->_base.rend_cookie, REND_COOKIE_LEN) < 0) {
     log_warn(LD_BUG, "Internal error: Couldn't produce random cookie.");
-    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
     return -1;
   }
-  if (connection_edge_send_command(NULL,circ,
+  if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
                                    RELAY_COMMAND_ESTABLISH_RENDEZVOUS,
-                                   circ->rend_cookie, REND_COOKIE_LEN,
+                                   circ->_base.rend_cookie, REND_COOKIE_LEN,
                                    circ->cpath->prev)<0) {
     /* circ is already marked for close */
     log_warn(LD_GENERAL, "Couldn't send ESTABLISH_RENDEZVOUS cell");
@@ -54,7 +53,8 @@ rend_client_send_establish_rendezvous(ci
  * down introcirc if possible.
  */
 int
-rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc)
+rend_client_send_introduction(origin_circuit_t *introcirc,
+                              origin_circuit_t *rendcirc)
 {
   size_t payload_len;
   int r;
@@ -64,15 +64,15 @@ rend_client_send_introduction(circuit_t 
   crypt_path_t *cpath;
   off_t dh_offset;
 
-  tor_assert(introcirc->purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
-  tor_assert(rendcirc->purpose == CIRCUIT_PURPOSE_C_REND_READY);
-  tor_assert(!rend_cmp_service_ids(introcirc->rend_query,
-                                   rendcirc->rend_query));
+  tor_assert(introcirc->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
+  tor_assert(rendcirc->_base.purpose == CIRCUIT_PURPOSE_C_REND_READY);
+  tor_assert(!rend_cmp_service_ids(introcirc->_base.rend_query,
+                                   rendcirc->_base.rend_query));
 
-  if (rend_cache_lookup_entry(introcirc->rend_query, -1, &entry) < 1) {
+  if (rend_cache_lookup_entry(introcirc->_base.rend_query, -1, &entry) < 1) {
     log_warn(LD_REND,
              "query %s didn't have valid rend desc in cache. Failing.",
-             escaped_safe_str(introcirc->rend_query));
+             escaped_safe_str(introcirc->_base.rend_query));
     goto err;
   }
 
@@ -111,13 +111,15 @@ rend_client_send_introduction(circuit_t 
     klen = crypto_pk_asn1_encode(extend_info->onion_key, tmp+7+DIGEST_LEN+2,
                                  sizeof(tmp)-(7+DIGEST_LEN+2));
     set_uint16(tmp+7+DIGEST_LEN, htons(klen));
-    memcpy(tmp+7+DIGEST_LEN+2+klen, rendcirc->rend_cookie, REND_COOKIE_LEN);
+    memcpy(tmp+7+DIGEST_LEN+2+klen, rendcirc->_base.rend_cookie,
+           REND_COOKIE_LEN);
     dh_offset = 7+DIGEST_LEN+2+klen+REND_COOKIE_LEN;
   } else {
     /* Version 0. */
     strncpy(tmp, rendcirc->build_state->chosen_exit->nickname,
             (MAX_NICKNAME_LEN+1)); /* nul pads */
-    memcpy(tmp+MAX_NICKNAME_LEN+1, rendcirc->rend_cookie, REND_COOKIE_LEN);
+    memcpy(tmp+MAX_NICKNAME_LEN+1, rendcirc->_base.rend_cookie,
+           REND_COOKIE_LEN);
     dh_offset = MAX_NICKNAME_LEN+1+REND_COOKIE_LEN;
   }
 
@@ -141,7 +143,7 @@ rend_client_send_introduction(circuit_t 
   tor_assert(DIGEST_LEN + r <= RELAY_PAYLOAD_SIZE); /* we overran something */
   payload_len = DIGEST_LEN + r;
 
-  if (connection_edge_send_command(NULL, introcirc,
+  if (connection_edge_send_command(NULL, TO_CIRCUIT(introcirc),
                                    RELAY_COMMAND_INTRODUCE1,
                                    payload, payload_len,
                                    introcirc->cpath->prev)<0) {
@@ -151,22 +153,21 @@ rend_client_send_introduction(circuit_t 
   }
 
   /* Now, we wait for an ACK or NAK on this circuit. */
-  introcirc->purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT;
+  introcirc->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT;
 
   return 0;
 err:
-  circuit_mark_for_close(introcirc, END_CIRC_AT_ORIGIN);
-  circuit_mark_for_close(rendcirc, END_CIRC_AT_ORIGIN);
+  circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_AT_ORIGIN);
+  circuit_mark_for_close(TO_CIRCUIT(rendcirc), END_CIRC_AT_ORIGIN);
   return -1;
 }
 
 /** Called when a rendezvous circuit is open; sends a establish
  * rendezvous circuit as appropriate. */
 void
-rend_client_rendcirc_has_opened(circuit_t *circ)
+rend_client_rendcirc_has_opened(origin_circuit_t *circ)
 {
-  tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
-  tor_assert(CIRCUIT_IS_ORIGIN(circ));
+  tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
 
   log_info(LD_REND,"rendcirc is open");
 
@@ -179,17 +180,17 @@ rend_client_rendcirc_has_opened(circuit_
 /** Called when get an ACK or a NAK for a REND_INTRODUCE1 cell.
  */
 int
-rend_client_introduction_acked(circuit_t *circ,
+rend_client_introduction_acked(origin_circuit_t *circ,
                                const char *request, size_t request_len)
 {
   circuit_t *rendcirc;
   (void) request; // XXXX Use this.
 
-  if (circ->purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
+  if (circ->_base.purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
     log_warn(LD_PROTOCOL,
              "Received REND_INTRODUCE_ACK on unexpected circuit %d.",
-             circ->n_circ_id);
-    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+             circ->_base.n_circ_id);
+    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
     return -1;
   }
 
@@ -203,40 +204,40 @@ rend_client_introduction_acked(circuit_t
      */
     log_info(LD_REND,"Received ack. Telling rend circ...");
     rendcirc = circuit_get_by_rend_query_and_purpose(
-               circ->rend_query, CIRCUIT_PURPOSE_C_REND_READY);
+               circ->_base.rend_query, CIRCUIT_PURPOSE_C_REND_READY);
     if (rendcirc) { /* remember the ack */
       rendcirc->purpose = CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED;
     } else {
       log_info(LD_REND,"...Found no rend circ. Dropping on the floor.");
     }
     /* close the circuit: we won't need it anymore. */
-    circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACKED;
-    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+    circ->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACKED;
+    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
   } else {
     /* It's a NAK; the introduction point didn't relay our request. */
-    circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
+    circ->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
     /* Remove this intro point from the set of viable introduction
      * points. If any remain, extend to a new one and try again.
      * If none remain, refetch the service descriptor.
      */
     if (rend_client_remove_intro_point(circ->build_state->chosen_exit,
-                                       circ->rend_query) > 0) {
+                                       circ->_base.rend_query) > 0) {
       /* There are introduction points left. Re-extend the circuit to
        * another intro point and try again. */
       extend_info_t *extend_info;
       int result;
-      extend_info = rend_client_get_random_intro(circ->rend_query);
+      extend_info = rend_client_get_random_intro(circ->_base.rend_query);
       if (!extend_info) {
         log_warn(LD_REND, "No introduction points left for %s. Closing.",
-                 escaped_safe_str(circ->rend_query));
-        circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+                 escaped_safe_str(circ->_base.rend_query));
+        circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
         return -1;
       }
       log_info(LD_REND,
                "Got nack for %s from %s. Re-extending circ %d, "
                "this time to %s.",
-               escaped_safe_str(circ->rend_query),
-               circ->build_state->chosen_exit->nickname, circ->n_circ_id,
+               escaped_safe_str(circ->_base.rend_query),
+               circ->build_state->chosen_exit->nickname, circ->_base.n_circ_id,
                extend_info->nickname);
       result = circuit_extend_to_new_exit(circ, extend_info);
       extend_info_free(extend_info);
@@ -340,38 +341,38 @@ rend_client_remove_intro_point(extend_in
  * the circuit to C_REND_READY.
  */
 int
-rend_client_rendezvous_acked(circuit_t *circ, const char *request,
+rend_client_rendezvous_acked(origin_circuit_t *circ, const char *request,
                              size_t request_len)
 {
   (void) request;
   (void) request_len;
   /* we just got an ack for our establish-rendezvous. switch purposes. */
-  if (circ->purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) {
+  if (circ->_base.purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) {
     log_warn(LD_PROTOCOL,"Got a rendezvous ack when we weren't expecting one. "
              "Closing circ.");
-    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
     return -1;
   }
   log_info(LD_REND,"Got rendezvous ack. This circuit is now ready for "
            "rendezvous.");
-  circ->purpose = CIRCUIT_PURPOSE_C_REND_READY;
+  circ->_base.purpose = CIRCUIT_PURPOSE_C_REND_READY;
   return 0;
 }
 
 /** Bob sent us a rendezvous cell; join the circuits. */
 int
-rend_client_receive_rendezvous(circuit_t *circ, const char *request,
+rend_client_receive_rendezvous(origin_circuit_t *circ, const char *request,
                                size_t request_len)
 {
   crypt_path_t *hop;
   char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN];
 
-  if ((circ->purpose != CIRCUIT_PURPOSE_C_REND_READY &&
-       circ->purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)
+  if ((circ->_base.purpose != CIRCUIT_PURPOSE_C_REND_READY &&
+       circ->_base.purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)
       || !circ->build_state->pending_final_cpath) {
     log_warn(LD_PROTOCOL,"Got rendezvous2 cell from hidden service, but not "
              "expecting it. Closing.");
-    circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
     return -1;
   }
 
@@ -405,7 +406,7 @@ rend_client_receive_rendezvous(circuit_t
   hop->dh_handshake_state = NULL;
 
   /* All is well. Extend the circuit. */
-  circ->purpose = CIRCUIT_PURPOSE_C_REND_JOINED;
+  circ->_base.purpose = CIRCUIT_PURPOSE_C_REND_JOINED;
   hop->state = CPATH_STATE_OPEN;
   /* set the windows to default. these are the windows
    * that alice thinks bob has.
@@ -417,7 +418,7 @@ rend_client_receive_rendezvous(circuit_t
   circ->build_state->pending_final_cpath = NULL; /* prevent double-free */
   return 0;
  err:
-  circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+  circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
   return -1;
 }
 

Index: rendcommon.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/rendcommon.c,v
retrieving revision 1.70
retrieving revision 1.71
diff -u -p -d -r1.70 -r1.71
--- rendcommon.c	6 Jun 2006 00:05:39 -0000	1.70
+++ rendcommon.c	23 Jul 2006 07:37:35 -0000	1.71
@@ -432,34 +432,41 @@ void
 rend_process_relay_cell(circuit_t *circ, int command, size_t length,
                         const char *payload)
 {
+  or_circuit_t *or_circ = NULL;
+  origin_circuit_t *origin_circ = NULL;
   int r;
+  if (CIRCUIT_IS_ORIGIN(circ))
+    origin_circ = TO_ORIGIN_CIRCUIT(circ);
+  else
+    or_circ = TO_OR_CIRCUIT(circ);
+
   switch (command) {
     case RELAY_COMMAND_ESTABLISH_INTRO:
-      r = rend_mid_establish_intro(circ,payload,length);
+      r = rend_mid_establish_intro(or_circ,payload,length);
       break;
     case RELAY_COMMAND_ESTABLISH_RENDEZVOUS:
-      r = rend_mid_establish_rendezvous(circ,payload,length);
+      r = rend_mid_establish_rendezvous(or_circ,payload,length);
       break;
     case RELAY_COMMAND_INTRODUCE1:
-      r = rend_mid_introduce(circ,payload,length);
+      r = rend_mid_introduce(or_circ,payload,length);
       break;
     case RELAY_COMMAND_INTRODUCE2:
-      r = rend_service_introduce(circ,payload,length);
+      r = rend_service_introduce(origin_circ,payload,length);
       break;
     case RELAY_COMMAND_INTRODUCE_ACK:
-      r = rend_client_introduction_acked(circ,payload,length);
+      r = rend_client_introduction_acked(origin_circ,payload,length);
       break;
     case RELAY_COMMAND_RENDEZVOUS1:
-      r = rend_mid_rendezvous(circ,payload,length);
+      r = rend_mid_rendezvous(or_circ,payload,length);
       break;
     case RELAY_COMMAND_RENDEZVOUS2:
-      r = rend_client_receive_rendezvous(circ,payload,length);
+      r = rend_client_receive_rendezvous(origin_circ,payload,length);
       break;
     case RELAY_COMMAND_INTRO_ESTABLISHED:
-      r = rend_service_intro_established(circ,payload,length);
+      r = rend_service_intro_established(origin_circ,payload,length);
       break;
     case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED:
-      r = rend_client_rendezvous_acked(circ,payload,length);
+      r = rend_client_rendezvous_acked(origin_circ,payload,length);
       break;
     default:
       tor_assert(0);

Index: rendmid.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/rendmid.c,v
retrieving revision 1.50
retrieving revision 1.51
diff -u -p -d -r1.50 -r1.51
--- rendmid.c	13 Feb 2006 10:32:59 -0000	1.50
+++ rendmid.c	23 Jul 2006 07:37:35 -0000	1.51
@@ -15,7 +15,7 @@ const char rendmid_c_id[] =
  * setting the circuit's purpose and service pk digest.
  */
 int
-rend_mid_establish_intro(circuit_t *circ, const char *request,
+rend_mid_establish_intro(or_circuit_t *circ, const char *request,
                          size_t request_len)
 {
   crypto_pk_env_t *pk = NULL;
@@ -31,7 +31,7 @@ rend_mid_establish_intro(circuit_t *circ
            "Received an ESTABLISH_INTRO request on circuit %d",
            circ->p_circ_id);
 
-  if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) {
+  if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
     log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
          "Rejecting ESTABLISH_INTRO on non-OR or non-edge circuit.");
     reason = END_CIRC_REASON_TORPROTOCOL;
@@ -89,13 +89,13 @@ rend_mid_establish_intro(circuit_t *circ
   c = NULL;
   while ((c = circuit_get_next_by_pk_and_purpose(
                                 c,pk_digest,CIRCUIT_PURPOSE_INTRO_POINT))) {
-    log_info(LD_REND, "Replacing old circuit %d for service %s",
-             c->p_circ_id, safe_str(serviceid));
+    log_info(LD_REND, "Replacing old circuit for service %s",
+             safe_str(serviceid));
     circuit_mark_for_close(c, END_CIRC_REASON_REQUESTED);
   }
 
   /* Acknowledge the request. */
-  if (connection_edge_send_command(NULL,circ,
+  if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
                                    RELAY_COMMAND_INTRO_ESTABLISHED,
                                    "", 0, NULL)<0) {
     log_info(LD_GENERAL, "Couldn't send INTRO_ESTABLISHED cell.");
@@ -103,8 +103,8 @@ rend_mid_establish_intro(circuit_t *circ
   }
 
   /* Now, set up this circuit. */
-  circ->purpose = CIRCUIT_PURPOSE_INTRO_POINT;
-  memcpy(circ->rend_pk_digest, pk_digest, DIGEST_LEN);
+  circ->_base.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
+  memcpy(circ->_base.rend_pk_digest, pk_digest, DIGEST_LEN);
 
   log_info(LD_REND,
            "Established introduction point on circuit %d for service %s",
@@ -116,7 +116,7 @@ rend_mid_establish_intro(circuit_t *circ
   reason = END_CIRC_REASON_TORPROTOCOL;
  err:
   if (pk) crypto_free_pk_env(pk);
-  circuit_mark_for_close(circ, reason);
+  circuit_mark_for_close(TO_CIRCUIT(circ), reason);
   return -1;
 }
 
@@ -125,20 +125,23 @@ rend_mid_establish_intro(circuit_t *circ
  * INTRODUCE2 cell.
  */
 int
-rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len)
+rend_mid_introduce(or_circuit_t *circ, const char *request, size_t request_len)
 {
   circuit_t *intro_circ;
   char serviceid[REND_SERVICE_ID_LEN+1];
   char nak_body[1];
 
-  if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) {
+  if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
     log_warn(LD_PROTOCOL,
              "Rejecting INTRODUCE1 on non-OR or non-edge circuit %d.",
              circ->p_circ_id);
     goto err;
   }
 
-  /* change to MAX_HEX_NICKNAME_LEN once 0.0.9.x is obsolete */
+  /* We could change this to MAX_HEX_NICKNAME_LEN now that 0.0.9.x is
+   * obsolete; however, there isn't much reason to do so, and we're going
+   * to revise this protocol anyway.
+   */
   if (request_len < (DIGEST_LEN+(MAX_NICKNAME_LEN+1)+REND_COOKIE_LEN+
                      DH_KEY_LEN+CIPHER_KEY_LEN+PKCS1_OAEP_PADDING_OVERHEAD)) {
     log_warn(LD_PROTOCOL, "Impossibly short INTRODUCE1 cell on circuit %d; "
@@ -152,7 +155,7 @@ rend_mid_introduce(circuit_t *circ, cons
   /* The first 20 bytes are all we look at: they have a hash of Bob's PK. */
   intro_circ = circuit_get_next_by_pk_and_purpose(
                              NULL, request, CIRCUIT_PURPOSE_INTRO_POINT);
-  if (!intro_circ) {
+  if (!intro_circ || CIRCUIT_IS_ORIGIN(intro_circ)) {
     log_info(LD_REND,
              "No intro circ found for INTRODUCE1 cell (%s) from circuit %d; "
              "responding with nack.",
@@ -163,7 +166,8 @@ rend_mid_introduce(circuit_t *circ, cons
   log_info(LD_REND,
            "Sending introduction request for service %s "
            "from circ %d to circ %d",
-           safe_str(serviceid), circ->p_circ_id, intro_circ->p_circ_id);
+           safe_str(serviceid), circ->p_circ_id,
+           TO_OR_CIRCUIT(intro_circ)->p_circ_id);
 
   /* Great.  Now we just relay the cell down the circuit. */
   if (connection_edge_send_command(NULL, intro_circ,
@@ -174,10 +178,11 @@ rend_mid_introduce(circuit_t *circ, cons
     goto err;
   }
   /* And sent an ack down Alice's circuit.  Empty body means succeeded. */
-  if (connection_edge_send_command(NULL,circ,RELAY_COMMAND_INTRODUCE_ACK,
+  if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
+                                   RELAY_COMMAND_INTRODUCE_ACK,
                                    NULL,0,NULL)) {
     log_warn(LD_GENERAL, "Unable to send INTRODUCE_ACK cell to Tor client.");
-    circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
+    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
     return -1;
   }
 
@@ -185,11 +190,12 @@ rend_mid_introduce(circuit_t *circ, cons
  err:
   /* Send the client an NACK */
   nak_body[0] = 1;
-  if (connection_edge_send_command(NULL,circ,RELAY_COMMAND_INTRODUCE_ACK,
+  if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
+                                   RELAY_COMMAND_INTRODUCE_ACK,
                                    nak_body, 1, NULL)) {
     log_warn(LD_GENERAL, "Unable to send NAK to Tor client.");
     /* Is this right? */
-    circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
+    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
   }
   return -1;
 }
@@ -198,13 +204,13 @@ rend_mid_introduce(circuit_t *circ, cons
  * rendezvous cookie.
  */
 int
-rend_mid_establish_rendezvous(circuit_t *circ, const char *request,
+rend_mid_establish_rendezvous(or_circuit_t *circ, const char *request,
                               size_t request_len)
 {
   char hexid[9];
   int reason = END_CIRC_REASON_TORPROTOCOL;
 
-  if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) {
+  if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
     log_warn(LD_PROTOCOL,
              "Tried to establish rendezvous on non-OR or non-edge circuit.");
     goto err;
@@ -222,7 +228,7 @@ rend_mid_establish_rendezvous(circuit_t 
   }
 
   /* Acknowledge the request. */
-  if (connection_edge_send_command(NULL,circ,
+  if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
                                    RELAY_COMMAND_RENDEZVOUS_ESTABLISHED,
                                    "", 0, NULL)<0) {
     log_warn(LD_PROTOCOL, "Couldn't send RENDEZVOUS_ESTABLISHED cell.");
@@ -230,8 +236,8 @@ rend_mid_establish_rendezvous(circuit_t 
     goto err;
   }
 
-  circ->purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
-  memcpy(circ->rend_cookie, request, REND_COOKIE_LEN);
+  circ->_base.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
+  memcpy(circ->_base.rend_cookie, request, REND_COOKIE_LEN);
 
   base16_encode(hexid,9,request,4);
 
@@ -241,7 +247,7 @@ rend_mid_establish_rendezvous(circuit_t 
 
   return 0;
  err:
-  circuit_mark_for_close(circ, reason);
+  circuit_mark_for_close(TO_CIRCUIT(circ), reason);
   return -1;
 }
 
@@ -250,9 +256,10 @@ rend_mid_establish_rendezvous(circuit_t 
  * connecting the two circuits.
  */
 int
-rend_mid_rendezvous(circuit_t *circ, const char *request, size_t request_len)
+rend_mid_rendezvous(or_circuit_t *circ, const char *request,
+                    size_t request_len)
 {
-  circuit_t *rend_circ;
+  or_circuit_t *rend_circ;
   char hexid[9];
   int reason = END_CIRC_REASON_INTERNAL;
   base16_encode(hexid,9,request,request_len<4?request_len:4);
@@ -263,7 +270,7 @@ rend_mid_rendezvous(circuit_t *circ, con
              circ->p_circ_id, hexid);
   }
 
-  if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) {
+  if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
     log_info(LD_REND,
              "Tried to complete rendezvous on non-OR or non-edge circuit %d.",
              circ->p_circ_id);
@@ -289,7 +296,7 @@ rend_mid_rendezvous(circuit_t *circ, con
   }
 
   /* Send the RENDEZVOUS2 cell to Alice. */
-  if (connection_edge_send_command(NULL, rend_circ,
+  if (connection_edge_send_command(NULL, TO_CIRCUIT(rend_circ),
                                    RELAY_COMMAND_RENDEZVOUS2,
                                    request+REND_COOKIE_LEN,
                                    request_len-REND_COOKIE_LEN, NULL)) {
@@ -304,16 +311,16 @@ rend_mid_rendezvous(circuit_t *circ, con
            "Completing rendezvous: circuit %d joins circuit %d (cookie %s)",
            circ->p_circ_id, rend_circ->p_circ_id, hexid);
 
-  circ->purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED;
-  rend_circ->purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED;
-  memset(circ->rend_cookie, 0, REND_COOKIE_LEN);
+  circ->_base.purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED;
+  rend_circ->_base.purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED;
+  memset(circ->_base.rend_cookie, 0, REND_COOKIE_LEN);
 
   rend_circ->rend_splice = circ;
   circ->rend_splice = rend_circ;
 
   return 0;
  err:
-  circuit_mark_for_close(circ, reason);
+  circuit_mark_for_close(TO_CIRCUIT(circ), reason);
   return -1;
 }
 

Index: rendservice.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/rendservice.c,v
retrieving revision 1.163
retrieving revision 1.164
diff -u -p -d -r1.163 -r1.164
--- rendservice.c	15 Jul 2006 19:21:30 -0000	1.163
+++ rendservice.c	23 Jul 2006 07:37:35 -0000	1.164
@@ -11,8 +11,8 @@ const char rendservice_c_id[] =
 
 #include "or.h"
 
-static circuit_t *find_intro_circuit(routerinfo_t *router,
-                                     const char *pk_digest);
+static origin_circuit_t *find_intro_circuit(routerinfo_t *router,
+                                            const char *pk_digest);
 
 /** Represents the mapping from a virtual port of a rendezvous service to
  * a real port on some IP.
@@ -285,7 +285,7 @@ static void
 rend_service_update_descriptor(rend_service_t *service)
 {
   rend_service_descriptor_t *d;
-  circuit_t *circ;
+  origin_circuit_t *circ;
   int i,n;
   routerinfo_t *router;
 
@@ -310,7 +310,7 @@ rend_service_update_descriptor(rend_serv
       continue;
     }
     circ = find_intro_circuit(router, service->pk_digest);
-    if (circ && circ->purpose == CIRCUIT_PURPOSE_S_INTRO) {
+    if (circ && circ->_base.purpose == CIRCUIT_PURPOSE_S_INTRO) {
       /* We have an entirely established intro circuit. */
       d->intro_points[d->n_intro_points] = tor_strdup(router->nickname);
       d->intro_point_extend_info[d->n_intro_points] =
@@ -410,7 +410,7 @@ rend_service_requires_uptime(rend_servic
  * rendezvous point.
  */
 int
-rend_service_introduce(circuit_t *circuit, const char *request,
+rend_service_introduce(origin_circuit_t *circuit, const char *request,
                        size_t request_len)
 {
   char *ptr, *r_cookie;
@@ -421,21 +421,21 @@ rend_service_introduce(circuit_t *circui
   int r, i;
   size_t len, keylen;
   crypto_dh_env_t *dh = NULL;
-  circuit_t *launched = NULL;
+  origin_circuit_t *launched = NULL;
   crypt_path_t *cpath = NULL;
   char serviceid[REND_SERVICE_ID_LEN+1];
   char hexcookie[9];
   int circ_needs_uptime;
 
   base32_encode(serviceid, REND_SERVICE_ID_LEN+1,
-                circuit->rend_pk_digest,10);
+                circuit->_base.rend_pk_digest,10);
   log_info(LD_REND, "Received INTRODUCE2 cell for service %s on circ %d.",
-           escaped(serviceid), circuit->n_circ_id);
+           escaped(serviceid), circuit->_base.n_circ_id);
 
-  if (circuit->purpose != CIRCUIT_PURPOSE_S_INTRO) {
+  if (circuit->_base.purpose != CIRCUIT_PURPOSE_S_INTRO) {
     log_warn(LD_PROTOCOL,
              "Got an INTRODUCE2 over a non-introduction circuit %d.",
-             circuit->n_circ_id);
+             circuit->_base.n_circ_id);
     return -1;
   }
 
@@ -443,7 +443,7 @@ rend_service_introduce(circuit_t *circui
   if (request_len < DIGEST_LEN+REND_COOKIE_LEN+(MAX_NICKNAME_LEN+1)+
       DH_KEY_LEN+42) {
     log_warn(LD_PROTOCOL, "Got a truncated INTRODUCE2 cell on circ %d.",
-             circuit->n_circ_id);
+             circuit->_base.n_circ_id);
     return -1;
   }
 
@@ -454,7 +454,7 @@ rend_service_introduce(circuit_t *circui
              escaped(serviceid));
     return -1;
   }
-  if (memcmp(circuit->rend_pk_digest, request, DIGEST_LEN)) {
+  if (memcmp(circuit->_base.rend_pk_digest, request, DIGEST_LEN)) {
     base32_encode(serviceid, REND_SERVICE_ID_LEN+1, request, 10);
     log_warn(LD_REND, "Got an INTRODUCE2 cell for the wrong service (%s).",
              escaped(serviceid));
@@ -589,11 +589,11 @@ rend_service_introduce(circuit_t *circui
            extend_info->nickname, hexcookie, serviceid);
   tor_assert(launched->build_state);
   /* Fill in the circuit's state. */
-  memcpy(launched->rend_pk_digest, circuit->rend_pk_digest,
+  memcpy(launched->_base.rend_pk_digest, circuit->_base.rend_pk_digest,
          DIGEST_LEN);
-  memcpy(launched->rend_cookie, r_cookie, REND_COOKIE_LEN);
-  strlcpy(launched->rend_query, service->service_id,
-          sizeof(launched->rend_query));
+  memcpy(launched->_base.rend_cookie, r_cookie, REND_COOKIE_LEN);
+  strlcpy(launched->_base.rend_query, service->service_id,
+          sizeof(launched->_base.rend_query));
   launched->build_state->pending_final_cpath = cpath =
     tor_malloc_zero(sizeof(crypt_path_t));
   cpath->magic = CRYPT_PATH_MAGIC;
@@ -609,7 +609,8 @@ rend_service_introduce(circuit_t *circui
   return 0;
  err:
   if (dh) crypto_dh_free(dh);
-  if (launched) circuit_mark_for_close(launched, END_CIRC_AT_ORIGIN);
+  if (launched)
+    circuit_mark_for_close(TO_CIRCUIT(launched), END_CIRC_AT_ORIGIN);
   if (extend_info) extend_info_free(extend_info);
   return -1;
 }
@@ -618,12 +619,12 @@ rend_service_introduce(circuit_t *circui
  * than the last hop: launches a new circuit to the same rendezvous point.
  */
 void
-rend_service_relaunch_rendezvous(circuit_t *oldcirc)
+rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc)
 {
-  circuit_t *newcirc;
+  origin_circuit_t *newcirc;
   cpath_build_state_t *newstate, *oldstate;
 
-  tor_assert(oldcirc->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
+  tor_assert(oldcirc->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
 
   if (!oldcirc->build_state ||
       oldcirc->build_state->failure_count > MAX_REND_FAILURES ||
@@ -662,9 +663,12 @@ rend_service_relaunch_rendezvous(circuit
   newstate->pending_final_cpath = oldstate->pending_final_cpath;
   oldstate->pending_final_cpath = NULL;
 
-  memcpy(newcirc->rend_query, oldcirc->rend_query, REND_SERVICE_ID_LEN+1);
-  memcpy(newcirc->rend_pk_digest, oldcirc->rend_pk_digest, DIGEST_LEN);
-  memcpy(newcirc->rend_cookie, oldcirc->rend_cookie, REND_COOKIE_LEN);
+  memcpy(newcirc->_base.rend_query, oldcirc->_base.rend_query,
+         REND_SERVICE_ID_LEN+1);
+  memcpy(newcirc->_base.rend_pk_digest, oldcirc->_base.rend_pk_digest,
+         DIGEST_LEN);
+  memcpy(newcirc->_base.rend_cookie, oldcirc->_base.rend_cookie,
+         REND_COOKIE_LEN);
 }
 
 /** Launch a circuit to serve as an introduction point for the service
@@ -674,7 +678,7 @@ static int
 rend_service_launch_establish_intro(rend_service_t *service,
                                     const char *nickname)
 {
-  circuit_t *launched;
+  origin_circuit_t *launched;
 
   log_info(LD_REND,
            "Launching circuit to introduction point %s for service %s",
@@ -691,11 +695,11 @@ rend_service_launch_establish_intro(rend
              nickname);
     return -1;
   }
-  strlcpy(launched->rend_query, service->service_id,
-          sizeof(launched->rend_query));
-  memcpy(launched->rend_pk_digest, service->pk_digest, DIGEST_LEN);
+  strlcpy(launched->_base.rend_query, service->service_id,
+          sizeof(launched->_base.rend_query));
+  memcpy(launched->_base.rend_pk_digest, service->pk_digest, DIGEST_LEN);
 
-  if (launched->state == CIRCUIT_STATE_OPEN)
+  if (launched->_base.state == CIRCUIT_STATE_OPEN)
     rend_service_intro_has_opened(launched);
   return 0;
 }
@@ -704,7 +708,7 @@ rend_service_launch_establish_intro(rend
  *  sends a RELAY_ESTABLISH_INTRO cell.
  */
 void
-rend_service_intro_has_opened(circuit_t *circuit)
+rend_service_intro_has_opened(origin_circuit_t *circuit)
 {
   rend_service_t *service;
   size_t len;
@@ -713,23 +717,22 @@ rend_service_intro_has_opened(circuit_t 
   char auth[DIGEST_LEN + 9];
   char serviceid[REND_SERVICE_ID_LEN+1];
 
-  tor_assert(circuit->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
-  tor_assert(CIRCUIT_IS_ORIGIN(circuit));
+  tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
   tor_assert(circuit->cpath);
 
   base32_encode(serviceid, REND_SERVICE_ID_LEN+1,
-                circuit->rend_pk_digest,10);
+                circuit->_base.rend_pk_digest,10);
 
-  service = rend_service_get_by_pk_digest(circuit->rend_pk_digest);
+  service = rend_service_get_by_pk_digest(circuit->_base.rend_pk_digest);
   if (!service) {
     log_warn(LD_REND, "Unrecognized service ID %s on introduction circuit %d.",
-             serviceid, circuit->n_circ_id);
+             serviceid, circuit->_base.n_circ_id);
     goto err;
   }
 
   log_info(LD_REND,
            "Established circuit %d as introduction point for service %s",
-           circuit->n_circ_id, serviceid);
+           circuit->_base.n_circ_id, serviceid);
 
   /* Build the payload for a RELAY_ESTABLISH_INTRO cell. */
   len = crypto_pk_asn1_encode(service->private_key, buf+2,
@@ -748,47 +751,48 @@ rend_service_intro_has_opened(circuit_t 
   }
   len += r;
 
-  if (connection_edge_send_command(NULL, circuit,RELAY_COMMAND_ESTABLISH_INTRO,
+  if (connection_edge_send_command(NULL, TO_CIRCUIT(circuit),
+                                   RELAY_COMMAND_ESTABLISH_INTRO,
                                    buf, len, circuit->cpath->prev)<0) {
     log_info(LD_GENERAL,
              "Couldn't send introduction request for service %s on circuit %d",
-             serviceid, circuit->n_circ_id);
+             serviceid, circuit->_base.n_circ_id);
     goto err;
   }
 
   return;
  err:
-  circuit_mark_for_close(circuit, END_CIRC_AT_ORIGIN);
+  circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_AT_ORIGIN);
 }
 
 /** Called when we get an INTRO_ESTABLISHED cell; mark the circuit as a
  * live introduction point, and note that the service descriptor is
  * now out-of-date.*/
 int
-rend_service_intro_established(circuit_t *circuit, const char *request,
+rend_service_intro_established(origin_circuit_t *circuit, const char *request,
                                size_t request_len)
 {
   rend_service_t *service;
   (void) request;
   (void) request_len;
 
-  if (circuit->purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
+  if (circuit->_base.purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
     log_warn(LD_PROTOCOL,
              "received INTRO_ESTABLISHED cell on non-intro circuit.");
     goto err;
   }
-  service = rend_service_get_by_pk_digest(circuit->rend_pk_digest);
+  service = rend_service_get_by_pk_digest(circuit->_base.rend_pk_digest);
   if (!service) {
     log_warn(LD_REND, "Unknown service on introduction circuit %d.",
-             circuit->n_circ_id);
+             circuit->_base.n_circ_id);
     goto err;
   }
   service->desc_is_dirty = time(NULL);
-  circuit->purpose = CIRCUIT_PURPOSE_S_INTRO;
+  circuit->_base.purpose = CIRCUIT_PURPOSE_S_INTRO;
 
   return 0;
  err:
-  circuit_mark_for_close(circuit, END_CIRC_AT_ORIGIN);
+  circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_AT_ORIGIN);
   return -1;
 }
 
@@ -796,7 +800,7 @@ rend_service_intro_established(circuit_t
  *  RELAY_COMMAND_RENDEZVOUS1 cell.
  */
 void
-rend_service_rendezvous_has_opened(circuit_t *circuit)
+rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
 {
   rend_service_t *service;
   char buf[RELAY_PAYLOAD_SIZE];
@@ -804,22 +808,22 @@ rend_service_rendezvous_has_opened(circu
   char serviceid[REND_SERVICE_ID_LEN+1];
   char hexcookie[9];
 
-  tor_assert(circuit->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
+  tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
   tor_assert(circuit->cpath);
   tor_assert(circuit->build_state);
   hop = circuit->build_state->pending_final_cpath;
   tor_assert(hop);
 
-  base16_encode(hexcookie,9,circuit->rend_cookie,4);
+  base16_encode(hexcookie,9,circuit->_base.rend_cookie,4);
   base32_encode(serviceid, REND_SERVICE_ID_LEN+1,
-                circuit->rend_pk_digest,10);
+                circuit->_base.rend_pk_digest,10);
 
   log_info(LD_REND,
            "Done building circuit %d to rendezvous with "
            "cookie %s for service %s",
-           circuit->n_circ_id, hexcookie, serviceid);
+           circuit->_base.n_circ_id, hexcookie, serviceid);
 
-  service = rend_service_get_by_pk_digest(circuit->rend_pk_digest);
+  service = rend_service_get_by_pk_digest(circuit->_base.rend_pk_digest);
   if (!service) {
     log_warn(LD_GENERAL, "Internal error: unrecognized service ID on "
              "introduction circuit.");
@@ -827,7 +831,7 @@ rend_service_rendezvous_has_opened(circu
   }
 
   /* All we need to do is send a RELAY_RENDEZVOUS1 cell... */
-  memcpy(buf, circuit->rend_cookie, REND_COOKIE_LEN);
+  memcpy(buf, circuit->_base.rend_cookie, REND_COOKIE_LEN);
   if (crypto_dh_get_public(hop->dh_handshake_state,
                            buf+REND_COOKIE_LEN, DH_KEY_LEN)<0) {
     log_warn(LD_GENERAL,"Couldn't get DH public key.");
@@ -837,7 +841,8 @@ rend_service_rendezvous_has_opened(circu
          DIGEST_LEN);
 
   /* Send the cell */
-  if (connection_edge_send_command(NULL, circuit, RELAY_COMMAND_RENDEZVOUS1,
+  if (connection_edge_send_command(NULL, TO_CIRCUIT(circuit),
+                                   RELAY_COMMAND_RENDEZVOUS1,
                                    buf, REND_COOKIE_LEN+DH_KEY_LEN+DIGEST_LEN,
                                    circuit->cpath->prev)<0) {
     log_warn(LD_GENERAL, "Couldn't send RENDEZVOUS1 cell.");
@@ -859,11 +864,11 @@ rend_service_rendezvous_has_opened(circu
   circuit->build_state->pending_final_cpath = NULL; /* prevent double-free */
 
   /* Change the circuit purpose. */
-  circuit->purpose = CIRCUIT_PURPOSE_S_REND_JOINED;
+  circuit->_base.purpose = CIRCUIT_PURPOSE_S_REND_JOINED;
 
   return;
  err:
-  circuit_mark_for_close(circuit, END_CIRC_AT_ORIGIN);
+  circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_AT_ORIGIN);
 }
 
 /*
@@ -874,28 +879,31 @@ rend_service_rendezvous_has_opened(circu
  * <b>router</b> for the service whose public key is <b>pk_digest</b>.  Return
  * NULL if no such service is found.
  */
-static circuit_t *
+static origin_circuit_t *
 find_intro_circuit(routerinfo_t *router, const char *pk_digest)
 {
   circuit_t *circ = NULL;
+  cpath_build_state_t *build_state = NULL;
 
   tor_assert(router);
   while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest,
                                                   CIRCUIT_PURPOSE_S_INTRO))) {
-    tor_assert(circ->cpath);
-    if (!strcasecmp(circ->build_state->chosen_exit->nickname,
+    tor_assert(CIRCUIT_IS_ORIGIN(circ));
+    build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
+    if (!strcasecmp(build_state->chosen_exit->nickname,
                     router->nickname)) {
-      return circ;
+      return TO_ORIGIN_CIRCUIT(circ);
     }
   }
 
   circ = NULL;
   while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest,
                                         CIRCUIT_PURPOSE_S_ESTABLISH_INTRO))) {
-    tor_assert(circ->cpath);
-    if (!strcasecmp(circ->build_state->chosen_exit->nickname,
+    tor_assert(CIRCUIT_IS_ORIGIN(circ));
+    build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
+    if (!strcasecmp(build_state->chosen_exit->nickname,
                     router->nickname)) {
-      return circ;
+      return TO_ORIGIN_CIRCUIT(circ);
     }
   }
   return NULL;
@@ -1088,7 +1096,7 @@ rend_service_dump_stats(int severity)
   routerinfo_t *router;
   rend_service_t *service;
   char *nickname;
-  circuit_t *circ;
+  origin_circuit_t *circ;
 
   for (i=0; i < smartlist_len(rend_service_list); ++i) {
     service = smartlist_get(rend_service_list, i);
@@ -1108,7 +1116,7 @@ rend_service_dump_stats(int severity)
         continue;
       }
       log(severity, LD_GENERAL, "  Intro point at %s: circuit is %s",nickname,
-          circuit_state_to_string(circ->state));
+          circuit_state_to_string(circ->_base.state));
     }
   }
 }
@@ -1119,22 +1127,23 @@ rend_service_dump_stats(int severity)
  * or 0 for success.
  */
 int
-rend_service_set_connection_addr_port(connection_t *conn, circuit_t *circ)
+rend_service_set_connection_addr_port(connection_t *conn,
+                                      origin_circuit_t *circ)
 {
   rend_service_t *service;
   int i;
   rend_service_port_config_t *p;
   char serviceid[REND_SERVICE_ID_LEN+1];
 
-  tor_assert(circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED);
+  tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_S_REND_JOINED);
   log_debug(LD_REND,"beginning to hunt for addr/port");
   base32_encode(serviceid, REND_SERVICE_ID_LEN+1,
-                circ->rend_pk_digest,10);
-  service = rend_service_get_by_pk_digest(circ->rend_pk_digest);
+                circ->_base.rend_pk_digest,10);
+  service = rend_service_get_by_pk_digest(circ->_base.rend_pk_digest);
   if (!service) {
     log_warn(LD_REND, "Couldn't find any service associated with pk %s on "
              "rendezvous circuit %d; closing.",
-             serviceid, circ->n_circ_id);
+             serviceid, circ->_base.n_circ_id);
     return -1;
   }
   for (i = 0; i < smartlist_len(service->ports); ++i) {



More information about the tor-commits mailing list