[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] r6908@Kushana: nickm | 2006-07-26 12:38:52 -0400 Refactor c (r6906 in tor/trunk: . src/or)



Author: nickm
Date: 2006-07-26 15:07:26 -0400 (Wed, 26 Jul 2006)
New Revision: 6906

Modified:
   tor/trunk/
   tor/trunk/src/or/circuitbuild.c
   tor/trunk/src/or/circuitlist.c
   tor/trunk/src/or/circuituse.c
   tor/trunk/src/or/command.c
   tor/trunk/src/or/connection.c
   tor/trunk/src/or/connection_edge.c
   tor/trunk/src/or/connection_or.c
   tor/trunk/src/or/control.c
   tor/trunk/src/or/cpuworker.c
   tor/trunk/src/or/directory.c
   tor/trunk/src/or/dirserv.c
   tor/trunk/src/or/dns.c
   tor/trunk/src/or/hibernate.c
   tor/trunk/src/or/main.c
   tor/trunk/src/or/or.h
   tor/trunk/src/or/relay.c
   tor/trunk/src/or/rendclient.c
   tor/trunk/src/or/rendservice.c
   tor/trunk/src/or/router.c
   tor/trunk/src/or/routerlist.c
Log:
 r6908@Kushana:  nickm | 2006-07-26 12:38:52 -0400
 Refactor connection_t into edge, or, dir, control, and base subtypes.  This might save some RAM on busy exit servers, but really matters most in terms of correctness.



Property changes on: tor/trunk
___________________________________________________________________
Name: svk:merge
   - c95137ef-5f19-0410-b913-86e773d04f59:/tor/branches/oo-connections:6907
   + c95137ef-5f19-0410-b913-86e773d04f59:/tor/branches/oo-connections:6908

Modified: tor/trunk/src/or/circuitbuild.c
===================================================================
--- tor/trunk/src/or/circuitbuild.c	2006-07-26 19:07:23 UTC (rev 6905)
+++ tor/trunk/src/or/circuitbuild.c	2006-07-26 19:07:26 UTC (rev 6906)
@@ -60,14 +60,13 @@
  * Return it, or 0 if can't get a unique circ_id.
  */
 static uint16_t
-get_unique_circ_id_by_conn(connection_t *conn)
+get_unique_circ_id_by_conn(or_connection_t *conn)
 {
   uint16_t test_circ_id;
   uint16_t attempts=0;
   uint16_t high_bit;
 
   tor_assert(conn);
-  tor_assert(conn->type == CONN_TYPE_OR);
   high_bit = (conn->circ_id_type == CIRC_ID_TYPE_HIGHER) ? 1<<15 : 0;
   do {
     /* Sequentially iterate over test_circ_id=1...1<<15-1 until we find a
@@ -277,7 +276,7 @@
 circuit_handle_first_hop(origin_circuit_t *circ)
 {
   crypt_path_t *firsthop;
-  connection_t *n_conn;
+  or_connection_t *n_conn;
   char tmpbuf[INET_NTOA_BUF_LEN];
   struct in_addr in;
 
@@ -298,15 +297,15 @@
   /* If we don't have an open conn, or the conn we have is obsolete
    * (i.e. old or broken) and the other side will let us make a second
    * connection without dropping it immediately... */
-  if (!n_conn || n_conn->state != OR_CONN_STATE_OPEN ||
-      (n_conn->is_obsolete &&
+  if (!n_conn || n_conn->_base.state != OR_CONN_STATE_OPEN ||
+      (n_conn->_base.or_is_obsolete &&
        router_digest_version_as_new_as(firsthop->extend_info->identity_digest,
                                        "0.1.1.9-alpha-cvs"))) {
     /* not currently connected */
     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 */
+    if (!n_conn || n_conn->_base.or_is_obsolete) { /* launch the connection */
       n_conn = connection_or_connect(firsthop->extend_info->addr,
                                      firsthop->extend_info->port,
                                      firsthop->extend_info->identity_digest);
@@ -323,8 +322,8 @@
      */
     return 0;
   } else { /* it's already open. use it. */
-    circ->_base.n_addr = n_conn->addr;
-    circ->_base.n_port = n_conn->port;
+    circ->_base.n_addr = n_conn->_base.addr;
+    circ->_base.n_port = n_conn->_base.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) {
@@ -341,7 +340,7 @@
  * Status is 1 if connect succeeded, or 0 if connect failed.
  */
 void
-circuit_n_conn_done(connection_t *or_conn, int status)
+circuit_n_conn_done(or_connection_t *or_conn, int status)
 {
   extern smartlist_t *circuits_pending_or_conns;
   smartlist_t *changed_circs;
@@ -419,7 +418,6 @@
 
   tor_assert(circ);
   tor_assert(circ->n_conn);
-  tor_assert(circ->n_conn->type == CONN_TYPE_OR);
   tor_assert(payload);
   tor_assert(cell_type == CELL_CREATE || cell_type == CELL_CREATE_FAST);
 
@@ -621,7 +619,7 @@
 int
 circuit_extend(cell_t *cell, circuit_t *circ)
 {
-  connection_t *n_conn;
+  or_connection_t *n_conn;
   relay_header_t rh;
   char *onionskin;
   char *id_digest=NULL;
@@ -651,8 +649,8 @@
   /* If we don't have an open conn, or the conn we have is obsolete
    * (i.e. old or broken) and the other side will let us make a second
    * connection without dropping it immediately... */
-  if (!n_conn || n_conn->state != OR_CONN_STATE_OPEN ||
-    (n_conn->is_obsolete &&
+  if (!n_conn || n_conn->_base.state != OR_CONN_STATE_OPEN ||
+    (n_conn->_base.or_is_obsolete &&
      router_digest_version_as_new_as(id_digest,"0.1.1.9-alpha-cvs"))) {
     struct in_addr in;
     char tmpbuf[INET_NTOA_BUF_LEN];
@@ -668,9 +666,9 @@
     /* imprint the circuit with its future n_conn->id */
     memcpy(circ->n_conn_id_digest, id_digest, DIGEST_LEN);
 
-    if (n_conn && !n_conn->is_obsolete) {
-      circ->n_addr = n_conn->addr;
-      circ->n_port = n_conn->port;
+    if (n_conn && !n_conn->_base.or_is_obsolete) {
+      circ->n_addr = n_conn->_base.addr;
+      circ->n_port = n_conn->_base.port;
     } else {
      /* we should try to open a connection */
       n_conn = connection_or_connect(circ->n_addr, circ->n_port, id_digest);
@@ -689,12 +687,12 @@
   }
 
   /* these may be different if the router connected to us from elsewhere */
-  circ->n_addr = n_conn->addr;
-  circ->n_port = n_conn->port;
+  circ->n_addr = n_conn->_base.addr;
+  circ->n_port = n_conn->_base.port;
 
   circ->n_conn = n_conn;
   memcpy(circ->n_conn_id_digest, n_conn->identity_digest, DIGEST_LEN);
-  log_debug(LD_CIRC,"n_conn is %s:%u",n_conn->address,n_conn->port);
+  log_debug(LD_CIRC,"n_conn is %s:%u",n_conn->_base.address,n_conn->_base.port);
 
   if (circuit_deliver_create_cell(circ, CELL_CREATE, onionskin) < 0)
     return -1;
@@ -910,7 +908,7 @@
   connection_or_write_cell_to_buf(&cell, circ->p_conn);
   log_debug(LD_CIRC,"Finished sending 'created' cell.");
 
-  if (!is_local_IP(circ->p_conn->addr) &&
+  if (!is_local_IP(circ->p_conn->_base.addr) &&
       !connection_or_nonopen_was_started_here(circ->p_conn)) {
     /* record that we could process create cells from a non-local conn
      * that we didn't initiate; presumably this means that create cells
@@ -1048,8 +1046,9 @@
   if (conn->type == CONN_TYPE_AP &&
       conn->state == AP_CONN_STATE_CIRCUIT_WAIT &&
       !conn->marked_for_close &&
-      !connection_edge_is_rendezvous_stream(conn) &&
-      !circuit_stream_is_being_handled(conn, 0, MIN_CIRCUITS_HANDLING_STREAM))
+      !connection_edge_is_rendezvous_stream(TO_EDGE_CONN(conn)) &&
+      !circuit_stream_is_being_handled(TO_EDGE_CONN(conn), 0,
+                                       MIN_CIRCUITS_HANDLING_STREAM))
     return 1;
   return 0;
 }
@@ -1134,7 +1133,7 @@
     for (j = 0; j < n_connections; ++j) { /* iterate over connections */
       if (!ap_stream_wants_exit_attention(carray[j]))
         continue; /* Skip everything but APs in CIRCUIT_WAIT */
-      if (connection_ap_can_use_exit(carray[j], router)) {
+      if (connection_ap_can_use_exit(TO_EDGE_CONN(carray[j]), router)) {
         ++n_supported[i];
 //        log_fn(LOG_DEBUG,"%s is supported. n_supported[%d] now %d.",
 //               router->nickname, i, n_supported[i]);

Modified: tor/trunk/src/or/circuitlist.c
===================================================================
--- tor/trunk/src/or/circuitlist.c	2006-07-26 19:07:23 UTC (rev 6905)
+++ tor/trunk/src/or/circuitlist.c	2006-07-26 19:07:26 UTC (rev 6906)
@@ -33,7 +33,7 @@
  * very important here, since we need to do it every time a cell arrives.) */
 typedef struct orconn_circid_circuit_map_t {
   HT_ENTRY(orconn_circid_circuit_map_t) node;
-  connection_t *or_conn;
+  or_connection_t *or_conn;
   uint16_t circ_id;
   circuit_t *circuit;
 } orconn_circid_circuit_map_t;
@@ -70,8 +70,8 @@
 
 static void
 circuit_set_circid_orconn_helper(circuit_t *circ, uint16_t id,
-                                 connection_t *conn,
-                                 uint16_t old_id, connection_t *old_conn)
+                                 or_connection_t *conn,
+                                 uint16_t old_id, or_connection_t *old_conn)
 {
   orconn_circid_circuit_map_t search;
   orconn_circid_circuit_map_t *found;
@@ -85,7 +85,7 @@
   }
 
   if (old_conn) { /* we may need to remove it from the conn-circid map */
-    tor_assert(old_conn->magic == CONNECTION_MAGIC);
+    tor_assert(old_conn->_base.magic == OR_CONNECTION_MAGIC);
     search.circ_id = old_id;
     search.or_conn = old_conn;
     found = HT_REMOVE(orconn_circid_map, &orconn_circid_circuit_map, &search);
@@ -119,10 +119,10 @@
  * to the (orconn,id)-\>circuit map. */
 void
 circuit_set_p_circid_orconn(or_circuit_t *circ, uint16_t id,
-                            connection_t *conn)
+                            or_connection_t *conn)
 {
   uint16_t old_id;
-  connection_t *old_conn;
+  or_connection_t *old_conn;
 
   old_id = circ->p_circ_id;
   old_conn = circ->p_conn;
@@ -140,10 +140,10 @@
  * to the (orconn,id)-\>circuit map. */
 void
 circuit_set_n_circid_orconn(circuit_t *circ, uint16_t id,
-                            connection_t *conn)
+                            or_connection_t *conn)
 {
   uint16_t old_id;
-  connection_t *old_conn;
+  or_connection_t *old_conn;
 
   old_id = circ->n_circ_id;
   old_conn = circ->n_conn;
@@ -279,7 +279,7 @@
 }
 
 or_circuit_t *
-or_circuit_new(uint16_t p_circ_id, connection_t *p_conn)
+or_circuit_new(uint16_t p_circ_id, or_connection_t *p_conn)
 {
   /* CircIDs */
   or_circuit_t *circ;
@@ -379,9 +379,9 @@
     if (! CIRCUIT_IS_ORIGIN(global_circuitlist)) {
       or_circuit_t *or_circ = TO_OR_CIRCUIT(global_circuitlist);
       while (or_circ->resolving_streams) {
-        connection_t *next;
+        edge_connection_t *next;
         next = or_circ->resolving_streams->next_stream;
-        connection_free(or_circ->resolving_streams);
+        connection_free(TO_CONN(or_circ->resolving_streams));
         or_circ->resolving_streams = next;
       }
     }
@@ -439,7 +439,7 @@
 circuit_dump_by_conn(connection_t *conn, int severity)
 {
   circuit_t *circ;
-  connection_t *tmpconn;
+  edge_connection_t *tmpconn;
 
   for (circ=global_circuitlist;circ;circ = circ->next) {
     circid_t n_circ_id = circ->n_circ_id, p_circ_id = 0;
@@ -449,25 +449,26 @@
     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)
+    if (! CIRCUIT_IS_ORIGIN(circ) && TO_OR_CIRCUIT(circ)->p_conn &&
+        TO_CONN(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) {
+        if (TO_CONN(tmpconn) == conn) {
           circuit_dump_details(severity, circ, conn->poll_index, "App-ward",
                                p_circ_id, n_circ_id);
         }
       }
     }
-    if (circ->n_conn == conn)
+    if (circ->n_conn && TO_CONN(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) {
+        if (TO_CONN(tmpconn) == conn) {
           circuit_dump_details(severity, circ, conn->poll_index, "Exit-ward",
                                n_circ_id, p_circ_id);
         }
@@ -476,7 +477,9 @@
     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)) {
+        conn->type == CONN_TYPE_OR &&
+        !memcmp(TO_OR_CONN(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)) ?
@@ -509,13 +512,11 @@
  * Return NULL if no such circuit exists.
  */
 static INLINE circuit_t *
-circuit_get_by_circid_orconn_impl(uint16_t circ_id, connection_t *conn)
+circuit_get_by_circid_orconn_impl(uint16_t circ_id, or_connection_t *conn)
 {
   orconn_circid_circuit_map_t search;
   orconn_circid_circuit_map_t *found;
 
-  tor_assert(conn->type == CONN_TYPE_OR);
-
   if (_last_circid_orconn_ent &&
       circ_id == _last_circid_orconn_ent->circ_id &&
       conn == _last_circid_orconn_ent->or_conn) {
@@ -560,7 +561,7 @@
  * Return NULL if no such circuit exists.
  */
 circuit_t *
-circuit_get_by_circid_orconn(uint16_t circ_id, connection_t *conn)
+circuit_get_by_circid_orconn(uint16_t circ_id, or_connection_t *conn)
 {
   circuit_t *circ = circuit_get_by_circid_orconn_impl(circ_id, conn);
   if (!circ || circ->marked_for_close)
@@ -575,7 +576,7 @@
  * Return NULL if no such circuit exists.
  */
 int
-circuit_id_used_on_conn(uint16_t circ_id, connection_t *conn)
+circuit_id_used_on_conn(uint16_t circ_id, or_connection_t *conn)
 {
   circuit_t *circ = circuit_get_by_circid_orconn_impl(circ_id, conn);
   if (circ && circ->marked_for_close)
@@ -587,10 +588,9 @@
 
 /** Return the circuit that a given edge connection is using. */
 circuit_t *
-circuit_get_by_edge_conn(connection_t *conn)
+circuit_get_by_edge_conn(edge_connection_t *conn)
 {
   circuit_t *circ;
-  tor_assert(CONN_IS_EDGE(conn));
 
   circ = conn->on_circuit;
   tor_assert(!circ ||
@@ -605,7 +605,7 @@
  * been marked already.
  */
 void
-circuit_unlink_all_from_or_conn(connection_t *conn, int reason)
+circuit_unlink_all_from_or_conn(or_connection_t *conn, int reason)
 {
   circuit_t *circ;
   for (circ = global_circuitlist; circ; circ = circ->next) {
@@ -820,8 +820,6 @@
 _circuit_mark_for_close(circuit_t *circ, int reason, int line,
                         const char *file)
 {
-  connection_t *conn;
-
   assert_circuit_ok(circ);
   tor_assert(line);
   tor_assert(file);
@@ -889,18 +887,19 @@
 
   if (! CIRCUIT_IS_ORIGIN(circ)) {
     or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
+    edge_connection_t *conn;
     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) {
+      if (!conn->_base.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->_base.edge_has_sent_end = 1;
+        connection_mark_for_close(TO_CONN(conn));
       }
       conn->on_circuit = NULL;
     }
@@ -909,6 +908,7 @@
       connection_or_send_destroy(or_circ->p_circ_id, or_circ->p_conn, reason);
   } else {
     origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
+    edge_connection_t *conn;
     for (conn=ocirc->p_streams; conn; conn=conn->next_stream)
       connection_edge_destroy(circ->n_circ_id, conn);
   }
@@ -987,7 +987,7 @@
 void
 assert_circuit_ok(const circuit_t *c)
 {
-  connection_t *conn;
+  edge_connection_t *conn;
   const or_circuit_t *or_circ = NULL;
   const origin_circuit_t *origin_circ = NULL;
 
@@ -1002,24 +1002,22 @@
     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,
                        DIGEST_LEN));
     if (c->n_circ_id)
       tor_assert(c == circuit_get_by_circid_orconn(c->n_circ_id, c->n_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));
   }
   if (origin_circ)
     for (conn = origin_circ->p_streams; conn; conn = conn->next_stream)
-      tor_assert(conn->type == CONN_TYPE_AP);
+      tor_assert(conn->_base.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(conn->_base.type == CONN_TYPE_EXIT);
 
   tor_assert(c->deliver_window >= 0);
   tor_assert(c->package_window >= 0);

Modified: tor/trunk/src/or/circuituse.c
===================================================================
--- tor/trunk/src/or/circuituse.c	2006-07-26 19:07:23 UTC (rev 6905)
+++ tor/trunk/src/or/circuituse.c	2006-07-26 19:07:26 UTC (rev 6906)
@@ -26,7 +26,7 @@
  * Else return 0.
  */
 static int
-circuit_is_acceptable(circuit_t *circ, connection_t *conn,
+circuit_is_acceptable(circuit_t *circ, edge_connection_t *conn,
                       int must_be_open, uint8_t purpose,
                       int need_uptime, int need_internal,
                       time_t now)
@@ -155,7 +155,7 @@
  * closest introduce-purposed circuit that you can find.
  */
 static origin_circuit_t *
-circuit_get_best(connection_t *conn, int must_be_open, uint8_t purpose,
+circuit_get_best(edge_connection_t *conn, int must_be_open, uint8_t purpose,
                  int need_uptime, int need_internal)
 {
   circuit_t *circ, *best=NULL;
@@ -255,7 +255,7 @@
 
     if (victim->n_conn)
       log_info(LD_CIRC,"Abandoning circ %s:%d:%d (state %d:%s, purpose %d)",
-               victim->n_conn->address, victim->n_port, victim->n_circ_id,
+               victim->n_conn->_base.address, victim->n_port, victim->n_circ_id,
                victim->state, circuit_state_to_string(victim->state),
                victim->purpose);
     else
@@ -296,7 +296,7 @@
  * Else return 0.
  */
 int
-circuit_stream_is_being_handled(connection_t *conn, uint16_t port, int min)
+circuit_stream_is_being_handled(edge_connection_t *conn, uint16_t port, int min)
 {
   circuit_t *circ;
   routerinfo_t *exitrouter;
@@ -457,9 +457,9 @@
  * lists of <b>circ</b>, then remove it from the list.
  */
 void
-circuit_detach_stream(circuit_t *circ, connection_t *conn)
+circuit_detach_stream(circuit_t *circ, edge_connection_t *conn)
 {
-  connection_t *prevconn;
+  edge_connection_t *prevconn;
 
   tor_assert(circ);
   tor_assert(conn);
@@ -536,10 +536,11 @@
       if (!connection_state_is_open(conn)) {
         /* Inform any pending (not attached) circs that they should
          * give up. */
-        circuit_n_conn_done(conn, 0);
+        circuit_n_conn_done(TO_OR_CONN(conn), 0);
       }
       /* Now close all the attached circuits on it. */
-      circuit_unlink_all_from_or_conn(conn, END_CIRC_REASON_OR_CONN_CLOSED);
+      circuit_unlink_all_from_or_conn(TO_OR_CONN(conn),
+                                      END_CIRC_REASON_OR_CONN_CLOSED);
       return;
     }
     case CONN_TYPE_AP:
@@ -550,11 +551,11 @@
        * been sent. But don't kill the circuit.
        */
 
-      circ = circuit_get_by_edge_conn(conn);
+      circ = circuit_get_by_edge_conn(TO_EDGE_CONN(conn));
       if (!circ)
         return;
 
-      circuit_detach_stream(circ, conn);
+      circuit_detach_stream(circ, TO_EDGE_CONN(conn));
     }
   } /* end switch */
 }
@@ -683,7 +684,7 @@
       circ->cpath->state != CPATH_STATE_OPEN) {
     /* We failed at the first hop. If there's an OR connection
        to blame, blame it. */
-    connection_t *n_conn = NULL;
+    or_connection_t *n_conn = NULL;
     if (circ->_base.n_conn) {
       n_conn = circ->_base.n_conn;
     } else if (circ->_base.state == CIRCUIT_STATE_OR_WAIT) {
@@ -695,8 +696,8 @@
       log_info(LD_OR,
                "Our circuit failed to get a response from the first hop "
                "(%s:%d). I'm going to try to rotate to a better connection.",
-               n_conn->address, n_conn->port);
-      n_conn->is_obsolete = 1;
+               n_conn->_base.address, n_conn->_base.port);
+      n_conn->_base.or_is_obsolete = 1;
       entry_guard_set_status(n_conn->identity_digest, 0);
     }
   }
@@ -893,7 +894,7 @@
  * Write the found or in-progress or launched circ into *circp.
  */
 static int
-circuit_get_open_circ_or_launch(connection_t *conn,
+circuit_get_open_circ_or_launch(edge_connection_t *conn,
                                 uint8_t desired_circuit_purpose,
                                 origin_circuit_t **circp)
 {
@@ -903,7 +904,7 @@
 
   tor_assert(conn);
   tor_assert(circp);
-  tor_assert(conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
+  tor_assert(conn->_base.state == AP_CONN_STATE_CIRCUIT_WAIT);
   is_resolve = conn->socks_request->command == SOCKS_COMMAND_RESOLVE;
 
   need_uptime = smartlist_string_num_isin(get_options()->LongLivedPorts,
@@ -966,7 +967,7 @@
                  "No intro points for '%s': refetching service descriptor.",
                  safe_str(conn->rend_query));
         rend_client_refetch_renddesc(conn->rend_query);
-        conn->state = AP_CONN_STATE_RENDDESC_WAIT;
+        conn->_base.state = AP_CONN_STATE_RENDDESC_WAIT;
         return 0;
       }
       log_info(LD_REND,"Chose '%s' as intro point for '%s'.",
@@ -1033,13 +1034,13 @@
  * circ's cpath.
  */
 static void
-link_apconn_to_circ(connection_t *apconn, origin_circuit_t *circ)
+link_apconn_to_circ(edge_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->_base.n_circ_id);
   /* reset it, so we can measure circ timeouts */
-  apconn->timestamp_lastread = time(NULL);
+  apconn->_base.timestamp_lastread = time(NULL);
   apconn->next_stream = circ->p_streams;
   apconn->on_circuit = TO_CIRCUIT(circ);
   /* assert_connection_ok(conn, time(NULL)); */
@@ -1054,7 +1055,7 @@
 /** If an exit wasn't specifically chosen, save the history for future
  * use. */
 static void
-consider_recording_trackhost(connection_t *conn, origin_circuit_t *circ)
+consider_recording_trackhost(edge_connection_t *conn, origin_circuit_t *circ)
 {
   int found_needle = 0;
   char *str;
@@ -1108,18 +1109,17 @@
  * send a begin or resolve cell as appropriate.  Return values are as
  * for connection_ap_handshake_attach_circuit. */
 int
-connection_ap_handshake_attach_chosen_circuit(connection_t *conn,
+connection_ap_handshake_attach_chosen_circuit(edge_connection_t *conn,
                                               origin_circuit_t *circ)
 {
   tor_assert(conn);
-  tor_assert(conn->type == CONN_TYPE_AP);
-  tor_assert(conn->state == AP_CONN_STATE_CIRCUIT_WAIT ||
-             conn->state == AP_CONN_STATE_CONTROLLER_WAIT);
+  tor_assert(conn->_base.state == AP_CONN_STATE_CIRCUIT_WAIT ||
+             conn->_base.state == AP_CONN_STATE_CONTROLLER_WAIT);
   tor_assert(conn->socks_request);
   tor_assert(circ);
   tor_assert(circ->_base.state == CIRCUIT_STATE_OPEN);
 
-  conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
+  conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
 
   if (!circ->_base.timestamp_dirty)
     circ->_base.timestamp_dirty = time(NULL);
@@ -1146,19 +1146,18 @@
  * right next step, and return 1.
  */
 int
-connection_ap_handshake_attach_circuit(connection_t *conn)
+connection_ap_handshake_attach_circuit(edge_connection_t *conn)
 {
   int retval;
   int conn_age;
   int severity;
 
   tor_assert(conn);
-  tor_assert(conn->type == CONN_TYPE_AP);
-  tor_assert(conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
+  tor_assert(conn->_base.state == AP_CONN_STATE_CIRCUIT_WAIT);
   tor_assert(conn->socks_request);
 
-  conn_age = time(NULL) - conn->timestamp_created;
-  severity = (!conn->addr && !conn->port) ? LOG_INFO : LOG_NOTICE;
+  conn_age = time(NULL) - conn->_base.timestamp_created;
+  severity = (!conn->_base.addr && !conn->_base.port) ? LOG_INFO : LOG_NOTICE;
   if (conn_age > get_options()->SocksTimeout) {
     log_fn(severity, LD_APP,
            "Tried for %d seconds to get a connection to %s:%d. Giving up.",

Modified: tor/trunk/src/or/command.c
===================================================================
--- tor/trunk/src/or/command.c	2006-07-26 19:07:23 UTC (rev 6905)
+++ tor/trunk/src/or/command.c	2006-07-26 19:07:26 UTC (rev 6906)
@@ -27,10 +27,10 @@
 uint64_t stats_n_destroy_cells_processed = 0;
 
 /* These are the main four functions for processing cells */
-static void command_process_create_cell(cell_t *cell, connection_t *conn);
-static void command_process_created_cell(cell_t *cell, connection_t *conn);
-static void command_process_relay_cell(cell_t *cell, connection_t *conn);
-static void command_process_destroy_cell(cell_t *cell, connection_t *conn);
+static void command_process_create_cell(cell_t *cell, or_connection_t *conn);
+static void command_process_created_cell(cell_t *cell, or_connection_t *conn);
+static void command_process_relay_cell(cell_t *cell, or_connection_t *conn);
+static void command_process_destroy_cell(cell_t *cell, or_connection_t *conn);
 
 #ifdef KEEP_TIMING_STATS
 /** This is a wrapper function around the actual function that processes the
@@ -38,8 +38,8 @@
  * by the number of microseconds used by the call to <b>*func(cell, conn)</b>.
  */
 static void
-command_time_process_cell(cell_t *cell, connection_t *conn, int *time,
-                               void (*func)(cell_t *, connection_t *))
+command_time_process_cell(cell_t *cell, or_connection_t *conn, int *time,
+                               void (*func)(cell_t *, or_connection_t *))
 {
   struct timeval start, end;
   long time_passed;
@@ -68,7 +68,7 @@
  * process each type of cell.
  */
 void
-command_process_cell(cell_t *cell, connection_t *conn)
+command_process_cell(cell_t *cell, or_connection_t *conn)
 {
 #ifdef KEEP_TIMING_STATS
   /* how many of each cell have we seen so far this second? needs better
@@ -159,7 +159,7 @@
  * picked up again when the cpuworker finishes decrypting it.
  */
 static void
-command_process_create_cell(cell_t *cell, connection_t *conn)
+command_process_create_cell(cell_t *cell, or_connection_t *conn)
 {
   or_circuit_t *circ;
   int id_is_high;
@@ -191,7 +191,7 @@
     log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
            "Received CREATE cell (circID %d) for known circ. "
            "Dropping (age %d).",
-           cell->circ_id, (int)(time(NULL) - conn->timestamp_created));
+           cell->circ_id, (int)(time(NULL) - conn->_base.timestamp_created));
     if (router)
       log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
              "Details: nickname \"%s\", platform %s.",
@@ -241,7 +241,7 @@
  * extend to the next hop in the circuit if necessary.
  */
 static void
-command_process_created_cell(cell_t *cell, connection_t *conn)
+command_process_created_cell(cell_t *cell, or_connection_t *conn)
 {
   circuit_t *circ;
 
@@ -290,7 +290,7 @@
  * circuit_receive_relay_cell() for actual processing.
  */
 static void
-command_process_relay_cell(cell_t *cell, connection_t *conn)
+command_process_relay_cell(cell_t *cell, or_connection_t *conn)
 {
   circuit_t *circ;
   int reason;
@@ -300,7 +300,7 @@
   if (!circ) {
     log_debug(LD_OR,
               "unknown circuit %d on connection from %s:%d. Dropping.",
-              cell->circ_id, conn->address, conn->port);
+              cell->circ_id, conn->_base.address, conn->_base.port);
     return;
   }
 
@@ -345,7 +345,7 @@
  * and passes the destroy cell onward if necessary).
  */
 static void
-command_process_destroy_cell(cell_t *cell, connection_t *conn)
+command_process_destroy_cell(cell_t *cell, or_connection_t *conn)
 {
   circuit_t *circ;
   uint8_t reason;
@@ -354,7 +354,7 @@
   reason = (uint8_t)cell->payload[0];
   if (!circ) {
     log_info(LD_OR,"unknown circuit %d on connection from %s:%d. Dropping.",
-             cell->circ_id, conn->address, conn->port);
+             cell->circ_id, conn->_base.address, conn->_base.port);
     return;
   }
   log_debug(LD_OR,"Received for circID %d.",cell->circ_id);

Modified: tor/trunk/src/or/connection.c
===================================================================
--- tor/trunk/src/or/connection.c	2006-07-26 19:07:23 UTC (rev 6905)
+++ tor/trunk/src/or/connection.c	2006-07-26 19:07:26 UTC (rev 6906)
@@ -18,7 +18,7 @@
                                                 uint16_t listenport, int type);
 static int connection_init_accepted_conn(connection_t *conn);
 static int connection_handle_listener_read(connection_t *conn, int new_type);
-static int connection_receiver_bucket_should_increase(connection_t *conn);
+static int connection_receiver_bucket_should_increase(or_connection_t *conn);
 static int connection_finished_flushing(connection_t *conn);
 static int connection_flushed_some(connection_t *conn);
 static int connection_finished_connecting(connection_t *conn);
@@ -161,9 +161,35 @@
   static uint32_t n_connections_allocated = 0;
   connection_t *conn;
   time_t now = time(NULL);
+  size_t length;
+  uint32_t magic;
 
-  conn = tor_malloc_zero(sizeof(connection_t));
-  conn->magic = CONNECTION_MAGIC;
+  switch (type) {
+    case CONN_TYPE_OR:
+      length = sizeof(or_connection_t);
+      magic = OR_CONNECTION_MAGIC;
+      break;
+    case CONN_TYPE_EXIT:
+    case CONN_TYPE_AP:
+      length = sizeof(edge_connection_t);
+      magic = EDGE_CONNECTION_MAGIC;
+      break;
+    case CONN_TYPE_DIR:
+      length = sizeof(dir_connection_t);
+      magic = DIR_CONNECTION_MAGIC;
+      break;
+    case CONN_TYPE_CONTROL:
+      length = sizeof(control_connection_t);
+      magic = CONTROL_CONNECTION_MAGIC;
+      break;
+    default:
+      length = sizeof(connection_t);
+      magic = BASE_CONNECTION_MAGIC;
+      break;
+  }
+
+  conn = tor_malloc_zero(length);
+  conn->magic = magic;
   conn->s = -1; /* give it a default of 'not used' */
   conn->poll_index = -1; /* also default to 'not used' */
   conn->global_identifier = n_connections_allocated++;
@@ -174,11 +200,12 @@
     conn->outbuf = buf_new();
   }
   if (type == CONN_TYPE_AP) {
-    conn->socks_request = tor_malloc_zero(sizeof(socks_request_t));
+    TO_EDGE_CONN(conn)->socks_request =
+      tor_malloc_zero(sizeof(socks_request_t));
   }
+  if (type == CONN_TYPE_OR)
+    TO_OR_CONN(conn)->next_circ_id = crypto_rand_int(1<<15);
 
-  conn->next_circ_id = crypto_rand_int(1<<15);
-
   conn->timestamp_created = now;
   conn->timestamp_lastread = now;
   conn->timestamp_lastwritten = now;
@@ -209,50 +236,86 @@
 static void
 _connection_free(connection_t *conn)
 {
-  tor_assert(conn->magic == CONNECTION_MAGIC);
+  void *mem;
+  switch (conn->type) {
+    case CONN_TYPE_OR:
+      tor_assert(conn->magic == OR_CONNECTION_MAGIC);
+      mem = TO_OR_CONN(conn);
+      break;
+    case CONN_TYPE_AP:
+    case CONN_TYPE_EXIT:
+      tor_assert(conn->magic == EDGE_CONNECTION_MAGIC);
+      mem = TO_EDGE_CONN(conn);
+      break;
+    case CONN_TYPE_DIR:
+      tor_assert(conn->magic == DIR_CONNECTION_MAGIC);
+      mem = TO_DIR_CONN(conn);
+      break;
+    case CONN_TYPE_CONTROL:
+      tor_assert(conn->magic == CONTROL_CONNECTION_MAGIC);
+      mem = TO_CONTROL_CONN(conn);
+      break;
+    default:
+      tor_assert(conn->magic == BASE_CONNECTION_MAGIC);
+      mem = conn;
+      break;
+  }
 
   if (!connection_is_listener(conn)) {
     buf_free(conn->inbuf);
     buf_free(conn->outbuf);
   }
+
   tor_free(conn->address);
-  tor_free(conn->chosen_exit_name);
 
   if (connection_speaks_cells(conn)) {
-    if (conn->tls) {
-      tor_tls_free(conn->tls);
-      conn->tls = NULL;
+    or_connection_t *or_conn = TO_OR_CONN(conn);
+    if (or_conn->tls) {
+      tor_tls_free(or_conn->tls);
+      or_conn->tls = NULL;
     }
+
+    tor_free(or_conn->nickname);
   }
+  if (CONN_IS_EDGE(conn)) {
+    edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
+    tor_free(edge_conn->chosen_exit_name);
+    tor_free(edge_conn->socks_request);
+  }
+  if (conn->type == CONN_TYPE_CONTROL) {
+    control_connection_t *control_conn = TO_CONTROL_CONN(conn);
+    tor_free(control_conn->incoming_cmd);
+  }
 
-  tor_free(conn->nickname);
-  tor_free(conn->socks_request);
-  tor_free(conn->incoming_cmd);
   tor_free(conn->read_event); /* Probably already freed by connection_free. */
   tor_free(conn->write_event); /* Probably already freed by connection_free. */
-  tor_free(conn->requested_resource);
 
+  if (conn->type == CONN_TYPE_DIR) {
+    dir_connection_t *dir_conn = TO_DIR_CONN(conn);
+    tor_free(dir_conn->requested_resource);
+    if (dir_conn->zlib_state)
+      tor_zlib_free(dir_conn->zlib_state);
+    if (dir_conn->fingerprint_stack) {
+      SMARTLIST_FOREACH(dir_conn->fingerprint_stack, char *, cp, tor_free(cp));
+      smartlist_free(dir_conn->fingerprint_stack);
+    }
+    if (dir_conn->cached_dir)
+      cached_dir_decref(dir_conn->cached_dir);
+  }
+
   if (conn->s >= 0) {
     log_debug(LD_NET,"closing fd %d.",conn->s);
     tor_close_socket(conn->s);
   }
 
   if (conn->type == CONN_TYPE_OR &&
-      !tor_digest_is_zero(conn->identity_digest)) {
+      !tor_digest_is_zero(TO_OR_CONN(conn)->identity_digest)) {
     log_warn(LD_BUG, "called on OR conn with non-zeroed identity_digest");
-    connection_or_remove_from_identity_map(conn);
+    connection_or_remove_from_identity_map(TO_OR_CONN(conn));
   }
-  if (conn->zlib_state)
-    tor_zlib_free(conn->zlib_state);
-  if (conn->fingerprint_stack) {
-    SMARTLIST_FOREACH(conn->fingerprint_stack, char *, cp, tor_free(cp));
-    smartlist_free(conn->fingerprint_stack);
-  }
-  if (conn->cached_dir)
-    cached_dir_decref(conn->cached_dir);
 
   memset(conn, 0xAA, sizeof(connection_t)); /* poison memory */
-  tor_free(conn);
+  tor_free(mem);
 }
 
 /** Make sure <b>conn</b> isn't in any of the global conn lists; then free it.
@@ -266,12 +329,12 @@
   if (connection_speaks_cells(conn)) {
     if (conn->state == OR_CONN_STATE_OPEN)
       directory_set_dirty();
-    if (!tor_digest_is_zero(conn->identity_digest)) {
-      connection_or_remove_from_identity_map(conn);
+    if (!tor_digest_is_zero(TO_OR_CONN(conn)->identity_digest)) {
+      connection_or_remove_from_identity_map(TO_OR_CONN(conn));
     }
   }
   if (conn->type == CONN_TYPE_CONTROL) {
-    conn->event_mask = 0;
+    TO_CONTROL_CONN(conn)->event_mask = 0;
     control_update_global_event_mask();
   }
   connection_unregister(conn);
@@ -297,7 +360,7 @@
   /* We don't want to log any messages to controllers. */
   for (i=0;i<n;i++)
     if (carray[i]->type == CONN_TYPE_CONTROL)
-      carray[i]->event_mask = 0;
+      TO_CONTROL_CONN(carray[i])->event_mask = 0;
   control_update_global_event_mask();
 
   /* Unlink everything from the identity map. */
@@ -326,11 +389,14 @@
 connection_about_to_close_connection(connection_t *conn)
 {
   circuit_t *circ;
+  dir_connection_t *dir_conn;
+  or_connection_t *or_conn;
+  edge_connection_t *edge_conn;
 
   assert(conn->marked_for_close);
 
   if (CONN_IS_EDGE(conn)) {
-    if (!conn->has_sent_end) {
+    if (!conn->edge_has_sent_end) {
       log_warn(LD_BUG, "Harmless bug: Edge connection (marked at %s:%d) "
                "hasn't sent end yet?",
                conn->marked_for_close_file, conn->marked_for_close);
@@ -340,23 +406,25 @@
 
   switch (conn->type) {
     case CONN_TYPE_DIR:
+      dir_conn = TO_DIR_CONN(conn);
       if (conn->state < DIR_CONN_STATE_CLIENT_FINISHED) {
         /* It's a directory connection and connecting or fetching
          * failed: forget about this router, and maybe try again. */
-        connection_dir_request_failed(conn);
+        connection_dir_request_failed(dir_conn);
         // XXX if it's rend desc we may want to retry -RD
       }
       if (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC)
-        rend_client_desc_here(conn->rend_query); /* give it a try */
+        rend_client_desc_here(dir_conn->rend_query); /* give it a try */
       break;
     case CONN_TYPE_OR:
+      or_conn = TO_OR_CONN(conn);
       /* Remember why we're closing this connection. */
       if (conn->state != OR_CONN_STATE_OPEN) {
-        if (connection_or_nonopen_was_started_here(conn)) {
-          rep_hist_note_connect_failed(conn->identity_digest, time(NULL));
-          entry_guard_set_status(conn->identity_digest, 0);
-          router_set_status(conn->identity_digest, 0);
-          control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
+        if (connection_or_nonopen_was_started_here(or_conn)) {
+          rep_hist_note_connect_failed(or_conn->identity_digest, time(NULL));
+          entry_guard_set_status(or_conn->identity_digest, 0);
+          router_set_status(or_conn->identity_digest, 0);
+          control_event_or_conn_status(or_conn, OR_CONN_EVENT_FAILED);
         }
       } else if (conn->hold_open_until_flushed) {
         /* XXXX009 We used to have an arg that told us whether we closed the
@@ -368,30 +436,32 @@
          * flushing still get noted as dead, not disconnected.  But this is an
          * improvement. -NM
          */
-        rep_hist_note_disconnect(conn->identity_digest, time(NULL));
-        control_event_or_conn_status(conn, OR_CONN_EVENT_CLOSED);
-      } else if (conn->identity_digest) {
-        rep_hist_note_connection_died(conn->identity_digest, time(NULL));
-        control_event_or_conn_status(conn, OR_CONN_EVENT_CLOSED);
+        rep_hist_note_disconnect(or_conn->identity_digest, time(NULL));
+        control_event_or_conn_status(or_conn, OR_CONN_EVENT_CLOSED);
+      } else if (or_conn->identity_digest) {
+        rep_hist_note_connection_died(or_conn->identity_digest, time(NULL));
+        control_event_or_conn_status(or_conn, OR_CONN_EVENT_CLOSED);
       }
       break;
     case CONN_TYPE_AP:
-      if (conn->socks_request->has_finished == 0) {
+      edge_conn = TO_EDGE_CONN(conn);
+      if (edge_conn->socks_request->has_finished == 0) {
         /* since conn gets removed right after this function finishes,
          * there's no point trying to send back a reply at this point. */
         log_warn(LD_BUG,"Bug: Closing stream (marked at %s:%d) without sending"
                  " back a socks reply.",
                  conn->marked_for_close_file, conn->marked_for_close);
       } else {
-        control_event_stream_status(conn, STREAM_EVENT_CLOSED);
+        control_event_stream_status(edge_conn, STREAM_EVENT_CLOSED);
       }
       break;
     case CONN_TYPE_EXIT:
+      edge_conn = TO_EDGE_CONN(conn);
       if (conn->state == EXIT_CONN_STATE_RESOLVING) {
-        circ = circuit_get_by_edge_conn(conn);
+        circ = circuit_get_by_edge_conn(edge_conn);
         if (circ)
-          circuit_detach_stream(circ, conn);
-        connection_dns_remove(conn);
+          circuit_detach_stream(circ, edge_conn);
+        connection_dns_remove(edge_conn);
       }
       break;
     case CONN_TYPE_DNSWORKER:
@@ -731,8 +801,8 @@
 
   switch (conn->type) {
     case CONN_TYPE_OR:
-      control_event_or_conn_status(conn, OR_CONN_EVENT_NEW);
-      return connection_tls_start_handshake(conn, 1);
+      control_event_or_conn_status(TO_OR_CONN(conn), OR_CONN_EVENT_NEW);
+      return connection_tls_start_handshake(TO_OR_CONN(conn), 1);
     case CONN_TYPE_AP:
       conn->state = AP_CONN_STATE_SOCKS_WAIT;
       break;
@@ -1006,9 +1076,11 @@
   if (at_most > global_read_bucket)
     at_most = global_read_bucket;
 
-  if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN)
-    if (at_most > conn->receiver_bucket)
-      at_most = conn->receiver_bucket;
+  if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN) {
+    or_connection_t *or_conn = TO_OR_CONN(conn);
+    if (at_most > or_conn->receiver_bucket)
+      at_most = or_conn->receiver_bucket;
+  }
 
   if (at_most < 0)
     return 0;
@@ -1052,7 +1124,7 @@
 {
   global_read_bucket -= num_read;
   if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN) {
-    conn->receiver_bucket -= num_read;
+    TO_OR_CONN(conn)->receiver_bucket -= num_read;
   }
 }
 
@@ -1069,7 +1141,7 @@
   }
   if (connection_speaks_cells(conn) &&
       conn->state == OR_CONN_STATE_OPEN &&
-      conn->receiver_bucket <= 0) {
+      TO_OR_CONN(conn)->receiver_bucket <= 0) {
     LOG_FN_CONN(conn,
                 (LOG_DEBUG,LD_NET,"receiver bucket exhausted. Pausing."));
     conn->wants_to_read = 1;
@@ -1114,12 +1186,15 @@
   for (i=0;i<n;i++) {
     conn = carray[i];
 
-    if (connection_receiver_bucket_should_increase(conn)) {
-      conn->receiver_bucket += conn->bandwidthrate;
-      if (conn->receiver_bucket > conn->bandwidthburst)
-        conn->receiver_bucket = conn->bandwidthburst;
-      //log_fn(LOG_DEBUG,"Receiver bucket %d now %d.", i,
-      //       conn->receiver_bucket);
+    if (connection_speaks_cells(conn)) {
+      or_connection_t *or_conn = TO_OR_CONN(conn);
+      if (connection_receiver_bucket_should_increase(or_conn)) {
+        or_conn->receiver_bucket += or_conn->bandwidthrate;
+        if (or_conn->receiver_bucket > or_conn->bandwidthburst)
+          or_conn->receiver_bucket = or_conn->bandwidthburst;
+        //log_fn(LOG_DEBUG,"Receiver bucket %d now %d.", i,
+        //       conn->receiver_bucket);
+      }
     }
 
     if (conn->wants_to_read == 1 /* it's marked to turn reading back on now */
@@ -1128,7 +1203,7 @@
                                     * not the best place to check this.) */
         && (!connection_speaks_cells(conn) ||
             conn->state != OR_CONN_STATE_OPEN ||
-            conn->receiver_bucket > 0)) {
+            TO_OR_CONN(conn)->receiver_bucket > 0)) {
       /* and either a non-cell conn or a cell conn with non-empty bucket */
       LOG_FN_CONN(conn, (LOG_DEBUG,LD_NET,"waking up conn (fd %d)",conn->s));
       conn->wants_to_read = 0;
@@ -1145,15 +1220,12 @@
  * should add another pile of tokens to it?
  */
 static int
-connection_receiver_bucket_should_increase(connection_t *conn)
+connection_receiver_bucket_should_increase(or_connection_t *conn)
 {
   tor_assert(conn);
 
-  if (!connection_speaks_cells(conn))
-    return 0; /* edge connections don't use receiver_buckets */
-  if (conn->state != OR_CONN_STATE_OPEN)
+  if (conn->_base.state != OR_CONN_STATE_OPEN)
     return 0; /* only open connections play the rate limiting game */
-
   if (conn->receiver_bucket >= conn->bandwidthburst)
     return 0;
 
@@ -1200,15 +1272,15 @@
     /* There's a read error; kill the connection.*/
     connection_close_immediate(conn); /* Don't flush; connection is dead. */
     if (CONN_IS_EDGE(conn)) {
-      connection_edge_end_errno(conn, conn->cpath_layer);
-      if (conn->socks_request) /* broken, so don't send a socks reply back */
-        conn->socks_request->has_finished = 1;
+      edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
+      connection_edge_end_errno(edge_conn, edge_conn->cpath_layer);
+      if (edge_conn->socks_request) /* broken, don't send a socks reply back */
+        edge_conn->socks_request->has_finished = 1;
     }
     connection_mark_for_close(conn);
     return -1;
   }
-  if (CONN_IS_EDGE(conn) &&
-      try_to_read != max_to_read) {
+  if (CONN_IS_EDGE(conn) && try_to_read != max_to_read) {
     /* instruct it not to try to package partial cells. */
     if (connection_process_inbuf(conn, 0) < 0) {
       return -1;
@@ -1265,29 +1337,32 @@
   if (connection_speaks_cells(conn) &&
       conn->state > OR_CONN_STATE_PROXY_READING) {
     int pending;
+    or_connection_t *or_conn = TO_OR_CONN(conn);
     if (conn->state == OR_CONN_STATE_HANDSHAKING) {
       /* continue handshaking even if global token bucket is empty */
-      return connection_tls_continue_handshake(conn);
+      return connection_tls_continue_handshake(or_conn);
     }
 
     log_debug(LD_NET,
               "%d: starting, inbuf_datalen %d (%d pending in tls object)."
               " at_most %d.",
               conn->s,(int)buf_datalen(conn->inbuf),
-              tor_tls_get_pending_bytes(conn->tls), at_most);
+              tor_tls_get_pending_bytes(or_conn->tls), at_most);
 
     /* else open, or closing */
-    result = read_to_buf_tls(conn->tls, at_most, conn->inbuf);
+    result = read_to_buf_tls(or_conn->tls, at_most, conn->inbuf);
 
     switch (result) {
       case TOR_TLS_CLOSE:
         log_info(LD_NET,"TLS connection closed on read. Closing. "
                  "(Nickname %s, address %s",
-                 conn->nickname ? conn->nickname : "not set", conn->address);
+                 or_conn->nickname ? or_conn->nickname : "not set",
+                 conn->address);
         return -1;
       case TOR_TLS_ERROR:
         log_info(LD_NET,"tls error. breaking (nickname %s, address %s).",
-                 conn->nickname ? conn->nickname : "not set", conn->address);
+                 or_conn->nickname ? or_conn->nickname : "not set",
+                 conn->address);
         return -1;
       case TOR_TLS_WANTWRITE:
         connection_start_writing(conn);
@@ -1299,12 +1374,12 @@
       default:
         break;
     }
-    pending = tor_tls_get_pending_bytes(conn->tls);
+    pending = tor_tls_get_pending_bytes(or_conn->tls);
     if (pending) {
       /* XXXX If we have any pending bytes, read them now.  This *can*
        * take us over our read allotment, but really we shouldn't be
        * believing that SSL bytes are the same as TCP bytes anyway. */
-      int r2 = read_to_buf_tls(conn->tls, pending, conn->inbuf);
+      int r2 = read_to_buf_tls(or_conn->tls, pending, conn->inbuf);
       if (r2<0) {
         log_warn(LD_BUG, "Bug: apparently, reading pending bytes can fail.");
         return -1;
@@ -1409,7 +1484,8 @@
       log_warn(LD_BUG,
                "getsockopt() syscall failed?! Please report to tor-ops.");
       if (CONN_IS_EDGE(conn))
-        connection_edge_end_errno(conn, conn->cpath_layer);
+        connection_edge_end_errno(TO_EDGE_CONN(conn),
+                                  TO_EDGE_CONN(conn)->cpath_layer);
       connection_mark_for_close(conn);
       return -1;
     }
@@ -1418,7 +1494,8 @@
       if (!ERRNO_IS_CONN_EINPROGRESS(e)) {
         log_info(LD_NET,"in-progress connect failed. Removing.");
         if (CONN_IS_EDGE(conn))
-          connection_edge_end_errno(conn, conn->cpath_layer);
+          connection_edge_end_errno(TO_EDGE_CONN(conn),
+                                    TO_EDGE_CONN(conn)->cpath_layer);
 
         connection_close_immediate(conn);
         connection_mark_for_close(conn);
@@ -1426,7 +1503,7 @@
          * ignores unrecognized routers
          */
         if (conn->type == CONN_TYPE_OR && !get_options()->HttpsProxy)
-          router_set_status(conn->identity_digest, 0);
+          router_set_status(TO_OR_CONN(conn)->identity_digest, 0);
         return -1;
       } else {
         return 0; /* no change, see if next time is better */
@@ -1441,9 +1518,10 @@
 
   if (connection_speaks_cells(conn) &&
       conn->state > OR_CONN_STATE_PROXY_READING) {
+    or_connection_t *or_conn = TO_OR_CONN(conn);
     if (conn->state == OR_CONN_STATE_HANDSHAKING) {
       connection_stop_writing(conn);
-      if (connection_tls_continue_handshake(conn) < 0) {
+      if (connection_tls_continue_handshake(or_conn) < 0) {
         /* Don't flush; connection is dead. */
         connection_close_immediate(conn);
         connection_mark_for_close(conn);
@@ -1453,7 +1531,7 @@
     }
 
     /* else open, or closing */
-    result = flush_buf_tls(conn->tls, conn->outbuf,
+    result = flush_buf_tls(or_conn->tls, conn->outbuf,
                            max_to_write, &conn->outbuf_flushlen);
     switch (result) {
       case TOR_TLS_ERROR:
@@ -1491,7 +1569,8 @@
                                 max_to_write, &conn->outbuf_flushlen));
     if (result < 0) {
       if (CONN_IS_EDGE(conn))
-        connection_edge_end_errno(conn, conn->cpath_layer);
+        connection_edge_end_errno(TO_EDGE_CONN(conn),
+                                  TO_EDGE_CONN(conn)->cpath_layer);
 
       connection_close_immediate(conn); /* Don't flush; connection is dead. */
       connection_mark_for_close(conn);
@@ -1521,16 +1600,17 @@
 /* A controller event has just happened with such urgency that we
  * need to write it onto controller <b>conn</b> immediately. */
 void
-_connection_controller_force_write(connection_t *conn)
+_connection_controller_force_write(control_connection_t *control_conn)
 {
   /* XXX This is hideous code duplication, but raising it seems a little
    * tricky for now.  Think more about this one.   We only call it for
    * EVENT_ERR_MSG, so messing with buckets a little isn't such a big problem.
    */
   int result;
-  tor_assert(conn);
-  tor_assert(!conn->tls);
-  tor_assert(conn->type == CONN_TYPE_CONTROL);
+  connection_t *conn;
+  tor_assert(control_conn);
+  conn = TO_CONN(control_conn);
+
   if (conn->marked_for_close || conn->s < 0)
     return;
 
@@ -1580,7 +1660,7 @@
          wrong compared to our max outbuf size. close the whole circuit. */
       log_warn(LD_NET,
                "write_to_buf failed. Closing circuit (fd %d).", conn->s);
-      circuit_mark_for_close(circuit_get_by_edge_conn(conn),
+      circuit_mark_for_close(circuit_get_by_edge_conn(TO_EDGE_CONN(conn)),
                              END_CIRC_REASON_INTERNAL);
     } else {
       log_warn(LD_NET,
@@ -1595,15 +1675,17 @@
 }
 
 void
-connection_write_to_buf_zlib(connection_t *conn,
+connection_write_to_buf_zlib(dir_connection_t *dir_conn,
                              tor_zlib_state_t *state,
                              const char *data, size_t data_len,
                              int done)
 {
   int r;
   size_t old_datalen;
+  connection_t *conn;
   if (!data_len)
     return;
+  conn = TO_CONN(dir_conn);
   /* if it's marked for close, only allow write if we mean to flush it */
   if (conn->marked_for_close && !conn->hold_open_until_flushed)
     return;
@@ -1614,18 +1696,9 @@
                                 conn->outbuf, state, data, data_len,
                                 done));
   if (r < 0) {
-    if (CONN_IS_EDGE(conn)) {
-      /* if it failed, it means we have our package/delivery windows set
-         wrong compared to our max outbuf size. close the whole circuit. */
-      log_warn(LD_NET,
-               "write_to_buf failed. Closing circuit (fd %d).", conn->s);
-      circuit_mark_for_close(circuit_get_by_edge_conn(conn),
-                             END_CIRC_REASON_INTERNAL);
-    } else {
-      log_warn(LD_NET,
-               "write_to_buf failed. Closing connection (fd %d).", conn->s);
-      connection_mark_for_close(conn);
-    }
+    log_warn(LD_NET,
+             "write_to_buf failed. Closing connection (fd %d).", conn->s);
+    connection_mark_for_close(conn);
     return;
   }
 
@@ -1635,11 +1708,12 @@
 
 /** Return the conn to addr/port that has the most recent
  * timestamp_created, or NULL if no such conn exists. */
-connection_t *
+or_connection_t *
 connection_or_exact_get_by_addr_port(uint32_t addr, uint16_t port)
 {
   int i, n;
-  connection_t *conn, *best=NULL;
+  connection_t *conn;
+  or_connection_t *best=NULL;
   connection_t **carray;
 
   get_connection_array(&carray,&n);
@@ -1649,8 +1723,8 @@
         conn->addr == addr &&
         conn->port == port &&
         !conn->marked_for_close &&
-        (!best || best->timestamp_created < conn->timestamp_created))
-      best = conn;
+        (!best || best->_base.timestamp_created < conn->timestamp_created))
+      best = TO_OR_CONN(conn);
   }
   return best;
 }
@@ -1772,14 +1846,22 @@
   connection_t *conn;
   connection_t **carray;
 
+  tor_assert(type == CONN_TYPE_DIR ||
+             type == CONN_TYPE_AP || type == CONN_TYPE_EXIT);
+
   get_connection_array(&carray,&n);
   for (i=0;i<n;i++) {
     conn = carray[i];
     if (conn->type == type &&
         !conn->marked_for_close &&
-        (!state || state == conn->state) &&
-        !rend_cmp_service_ids(rendquery, conn->rend_query))
-      return conn;
+        (!state || state == conn->state)) {
+      if (type == CONN_TYPE_DIR &&
+          rend_cmp_service_ids(rendquery, TO_DIR_CONN(conn)->rend_query))
+        return conn;
+      else if (CONN_IS_EDGE(conn) &&
+               rend_cmp_service_ids(rendquery, TO_EDGE_CONN(conn)->rend_query))
+        return conn;
+    }
   }
   return NULL;
 }
@@ -1949,18 +2031,18 @@
 
   switch (conn->type) {
     case CONN_TYPE_OR:
-      return connection_or_process_inbuf(conn);
+      return connection_or_process_inbuf(TO_OR_CONN(conn));
     case CONN_TYPE_EXIT:
     case CONN_TYPE_AP:
-      return connection_edge_process_inbuf(conn, package_partial);
+      return connection_edge_process_inbuf(TO_EDGE_CONN(conn), package_partial);
     case CONN_TYPE_DIR:
-      return connection_dir_process_inbuf(conn);
+      return connection_dir_process_inbuf(TO_DIR_CONN(conn));
     case CONN_TYPE_DNSWORKER:
       return connection_dns_process_inbuf(conn);
     case CONN_TYPE_CPUWORKER:
       return connection_cpu_process_inbuf(conn);
     case CONN_TYPE_CONTROL:
-      return connection_control_process_inbuf(conn);
+      return connection_control_process_inbuf(TO_CONTROL_CONN(conn));
     default:
       log_err(LD_BUG,"Bug: got unexpected conn type %d.", conn->type);
       tor_fragile_assert();
@@ -1974,7 +2056,7 @@
 {
   if (conn->type == CONN_TYPE_DIR &&
       conn->state == DIR_CONN_STATE_SERVER_WRITING)
-    return connection_dirserv_flushed_some(conn);
+    return connection_dirserv_flushed_some(TO_DIR_CONN(conn));
   else
     return 0;
 }
@@ -1994,18 +2076,18 @@
 
   switch (conn->type) {
     case CONN_TYPE_OR:
-      return connection_or_finished_flushing(conn);
+      return connection_or_finished_flushing(TO_OR_CONN(conn));
     case CONN_TYPE_AP:
     case CONN_TYPE_EXIT:
-      return connection_edge_finished_flushing(conn);
+      return connection_edge_finished_flushing(TO_EDGE_CONN(conn));
     case CONN_TYPE_DIR:
-      return connection_dir_finished_flushing(conn);
+      return connection_dir_finished_flushing(TO_DIR_CONN(conn));
     case CONN_TYPE_DNSWORKER:
       return connection_dns_finished_flushing(conn);
     case CONN_TYPE_CPUWORKER:
       return connection_cpu_finished_flushing(conn);
     case CONN_TYPE_CONTROL:
-      return connection_control_finished_flushing(conn);
+      return connection_control_finished_flushing(TO_CONTROL_CONN(conn));
     default:
       log_err(LD_BUG,"Bug: got unexpected conn type %d.", conn->type);
       tor_fragile_assert();
@@ -2026,11 +2108,11 @@
   switch (conn->type)
     {
     case CONN_TYPE_OR:
-      return connection_or_finished_connecting(conn);
+      return connection_or_finished_connecting(TO_OR_CONN(conn));
     case CONN_TYPE_EXIT:
-      return connection_edge_finished_connecting(conn);
+      return connection_edge_finished_connecting(TO_EDGE_CONN(conn));
     case CONN_TYPE_DIR:
-      return connection_dir_finished_connecting(conn);
+      return connection_dir_finished_connecting(TO_DIR_CONN(conn));
     default:
       log_err(LD_BUG,"Bug: got unexpected conn type %d.", conn->type);
       tor_fragile_assert();
@@ -2044,18 +2126,18 @@
 {
   switch (conn->type) {
     case CONN_TYPE_OR:
-      return connection_or_reached_eof(conn);
+      return connection_or_reached_eof(TO_OR_CONN(conn));
     case CONN_TYPE_AP:
     case CONN_TYPE_EXIT:
-      return connection_edge_reached_eof(conn);
+      return connection_edge_reached_eof(TO_EDGE_CONN(conn));
     case CONN_TYPE_DIR:
-      return connection_dir_reached_eof(conn);
+      return connection_dir_reached_eof(TO_DIR_CONN(conn));
     case CONN_TYPE_DNSWORKER:
       return connection_dns_reached_eof(conn);
     case CONN_TYPE_CPUWORKER:
       return connection_cpu_reached_eof(conn);
     case CONN_TYPE_CONTROL:
-      return connection_control_reached_eof(conn);
+      return connection_control_reached_eof(TO_CONTROL_CONN(conn));
     default:
       log_err(LD_BUG,"Bug: got unexpected conn type %d.", conn->type);
       tor_fragile_assert();
@@ -2071,9 +2153,26 @@
 {
   (void) now; /* XXXX unused. */
   tor_assert(conn);
-  tor_assert(conn->magic == CONNECTION_MAGIC);
   tor_assert(conn->type >= _CONN_TYPE_MIN);
   tor_assert(conn->type <= _CONN_TYPE_MAX);
+  switch (conn->type) {
+    case CONN_TYPE_OR:
+      tor_assert(conn->magic == OR_CONNECTION_MAGIC);
+      break;
+    case CONN_TYPE_AP:
+    case CONN_TYPE_EXIT:
+      tor_assert(conn->magic == EDGE_CONNECTION_MAGIC);
+      break;
+    case CONN_TYPE_DIR:
+      tor_assert(conn->magic == DIR_CONNECTION_MAGIC);
+      break;
+    case CONN_TYPE_CONTROL:
+      tor_assert(conn->magic == CONTROL_CONNECTION_MAGIC);
+      break;
+    default:
+      tor_assert(conn->magic == BASE_CONNECTION_MAGIC);
+      break;
+  }
 
   if (conn->outbuf_flushlen > 0) {
     tor_assert(connection_is_writing(conn) || conn->wants_to_write);
@@ -2100,9 +2199,8 @@
    */
 #endif
 
-  if (conn->type != CONN_TYPE_OR) {
-    tor_assert(!conn->tls);
-  } else {
+  if (conn->type == CONN_TYPE_OR) {
+    or_connection_t *or_conn = TO_OR_CONN(conn);
     if (conn->state == OR_CONN_STATE_OPEN) {
       /* tor_assert(conn->bandwidth > 0); */
       /* the above isn't necessarily true: if we just did a TLS
@@ -2115,43 +2213,31 @@
 //    tor_assert(conn->addr && conn->port);
     tor_assert(conn->address);
     if (conn->state > OR_CONN_STATE_PROXY_READING)
-      tor_assert(conn->tls);
+      tor_assert(or_conn->tls);
   }
 
-  if (! CONN_IS_EDGE(conn)) {
-    tor_assert(!conn->stream_id);
-    tor_assert(!conn->next_stream);
-    tor_assert(!conn->cpath_layer);
-    tor_assert(!conn->package_window);
-    tor_assert(!conn->deliver_window);
-#if 0
-    tor_assert(!conn->done_sending);
-    tor_assert(!conn->done_receiving);
-#endif
-  } else {
+  if (CONN_IS_EDGE(conn)) {
+    edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
     /* XXX unchecked: package window, deliver window. */
-  }
-  if (conn->type == CONN_TYPE_AP) {
-    tor_assert(conn->socks_request);
-    if (conn->state == AP_CONN_STATE_OPEN) {
-      tor_assert(conn->socks_request->has_finished);
-      if (!conn->marked_for_close) {
-        tor_assert(conn->cpath_layer);
-        assert_cpath_layer_ok(conn->cpath_layer);
+    if (conn->type == CONN_TYPE_AP) {
+
+      tor_assert(edge_conn->socks_request);
+      if (conn->state == AP_CONN_STATE_OPEN) {
+        tor_assert(edge_conn->socks_request->has_finished);
+        if (!conn->marked_for_close) {
+          tor_assert(edge_conn->cpath_layer);
+          assert_cpath_layer_ok(edge_conn->cpath_layer);
+        }
       }
     }
-  } else {
-    tor_assert(!conn->socks_request);
+    if (conn->type == CONN_TYPE_EXIT) {
+      tor_assert(conn->purpose == EXIT_PURPOSE_CONNECT ||
+                 conn->purpose == EXIT_PURPOSE_RESOLVE);
+    }
   }
-  if (conn->type == CONN_TYPE_EXIT) {
-    tor_assert(conn->purpose == EXIT_PURPOSE_CONNECT ||
-               conn->purpose == EXIT_PURPOSE_RESOLVE);
-  } else if (conn->type != CONN_TYPE_DIR) {
+  if (conn->type != CONN_TYPE_DIR) {
     tor_assert(!conn->purpose); /* only used for dir types currently */
   }
-  if (conn->type != CONN_TYPE_DIR) {
-    tor_assert(!conn->requested_resource);
-  }
 
   switch (conn->type)
     {
@@ -2164,7 +2250,7 @@
     case CONN_TYPE_OR:
       tor_assert(conn->state >= _OR_CONN_STATE_MIN);
       tor_assert(conn->state <= _OR_CONN_STATE_MAX);
-      tor_assert(conn->n_circuits >= 0);
+      tor_assert(TO_OR_CONN(conn)->n_circuits >= 0);
       break;
     case CONN_TYPE_EXIT:
       tor_assert(conn->state >= _EXIT_CONN_STATE_MIN);
@@ -2175,7 +2261,7 @@
     case CONN_TYPE_AP:
       tor_assert(conn->state >= _AP_CONN_STATE_MIN);
       tor_assert(conn->state <= _AP_CONN_STATE_MAX);
-      tor_assert(conn->socks_request);
+      tor_assert(TO_EDGE_CONN(conn)->socks_request);
       break;
     case CONN_TYPE_DIR:
       tor_assert(conn->state >= _DIR_CONN_STATE_MIN);

Modified: tor/trunk/src/or/connection_edge.c
===================================================================
--- tor/trunk/src/or/connection_edge.c	2006-07-26 19:07:23 UTC (rev 6905)
+++ tor/trunk/src/or/connection_edge.c	2006-07-26 19:07:26 UTC (rev 6906)
@@ -16,22 +16,22 @@
 /* List of exit_redirect_t */
 static smartlist_t *redirect_exit_list = NULL;
 
-static int connection_ap_handshake_process_socks(connection_t *conn);
+static int connection_ap_handshake_process_socks(edge_connection_t *conn);
 
 /** An AP stream has failed/finished. If it hasn't already sent back
  * a socks reply, send one now (based on endreason). Also set
  * has_sent_end to 1, and mark the conn.
  */
 void
-_connection_mark_unattached_ap(connection_t *conn, int endreason,
+_connection_mark_unattached_ap(edge_connection_t *conn, int endreason,
                                int line, const char *file)
 {
-  tor_assert(conn->type == CONN_TYPE_AP);
-  conn->has_sent_end = 1; /* no circ yet */
+  tor_assert(conn->_base.type == CONN_TYPE_AP);
+  conn->_base.edge_has_sent_end = 1; /* no circ yet */
 
-  if (conn->marked_for_close) {
+  if (conn->_base.marked_for_close) {
     /* This call will warn as appropriate. */
-    _connection_mark_for_close(conn, line, file);
+    _connection_mark_for_close(TO_CONN(conn), line, file);
     return;
   }
 
@@ -51,27 +51,28 @@
                                              0, NULL, -1);
   }
 
-  _connection_mark_for_close(conn, line, file);
-  conn->hold_open_until_flushed = 1;
+  _connection_mark_for_close(TO_CONN(conn), line, file);
+  conn->_base.hold_open_until_flushed = 1;
 }
 
 /** There was an EOF. Send an end and mark the connection for close.
  */
 int
-connection_edge_reached_eof(connection_t *conn)
+connection_edge_reached_eof(edge_connection_t *conn)
 {
-  if (buf_datalen(conn->inbuf) && connection_state_is_open(conn)) {
+  if (buf_datalen(conn->_base.inbuf) &&
+      connection_state_is_open(TO_CONN(conn))) {
     /* it still has stuff to process. don't let it die yet. */
     return 0;
   }
-  log_info(LD_EDGE,"conn (fd %d) reached eof. Closing.", conn->s);
-  if (!conn->marked_for_close) {
+  log_info(LD_EDGE,"conn (fd %d) reached eof. Closing.", conn->_base.s);
+  if (!conn->_base.marked_for_close) {
     /* only mark it if not already marked. it's possible to
      * get the 'end' right around when the client hangs up on us. */
     connection_edge_end(conn, END_STREAM_REASON_DONE, conn->cpath_layer);
     if (conn->socks_request) /* eof, so don't send a socks reply back */
       conn->socks_request->has_finished = 1;
-    connection_mark_for_close(conn);
+    connection_mark_for_close(TO_CONN(conn));
   }
   return 0;
 }
@@ -86,12 +87,11 @@
  * else return 0.
  */
 int
-connection_edge_process_inbuf(connection_t *conn, int package_partial)
+connection_edge_process_inbuf(edge_connection_t *conn, int package_partial)
 {
   tor_assert(conn);
-  tor_assert(CONN_IS_EDGE(conn));
 
-  switch (conn->state) {
+  switch (conn->_base.state) {
     case AP_CONN_STATE_SOCKS_WAIT:
       if (connection_ap_handshake_process_socks(conn) < 0) {
         /* already marked */
@@ -102,7 +102,7 @@
     case EXIT_CONN_STATE_OPEN:
       if (connection_edge_package_raw_inbuf(conn, package_partial) < 0) {
         /* (We already sent an end cell if possible) */
-        connection_mark_for_close(conn);
+        connection_mark_for_close(TO_CONN(conn));
         return -1;
       }
       return 0;
@@ -114,13 +114,13 @@
     case AP_CONN_STATE_CONTROLLER_WAIT:
       log_info(LD_EDGE,
                "data from edge while in '%s' state. Leaving it on buffer.",
-               conn_state_to_string(conn->type, conn->state));
+               conn_state_to_string(conn->_base.type, conn->_base.state));
       return 0;
   }
-  log_warn(LD_BUG,"Bug: Got unexpected state %d. Closing.",conn->state);
+  log_warn(LD_BUG,"Bug: Got unexpected state %d. Closing.",conn->_base.state);
   tor_fragile_assert();
   connection_edge_end(conn, END_STREAM_REASON_INTERNAL, conn->cpath_layer);
-  connection_mark_for_close(conn);
+  connection_mark_for_close(TO_CONN(conn));
   return -1;
 }
 
@@ -128,19 +128,17 @@
  * Mark it for close and return 0.
  */
 int
-connection_edge_destroy(uint16_t circ_id, connection_t *conn)
+connection_edge_destroy(uint16_t circ_id, edge_connection_t *conn)
 {
-  tor_assert(CONN_IS_EDGE(conn));
-
-  if (!conn->marked_for_close) {
+  if (!conn->_base.marked_for_close) {
     log_info(LD_EDGE,
              "CircID %d: At an edge. Marking connection for close.", circ_id);
-    if (conn->type == CONN_TYPE_AP) {
+    if (conn->_base.type == CONN_TYPE_AP) {
       connection_mark_unattached_ap(conn, END_STREAM_REASON_DESTROY);
     } else {
-      conn->has_sent_end = 1; /* closing the circuit, nothing to send to */
-      connection_mark_for_close(conn);
-      conn->hold_open_until_flushed = 1;
+      conn->_base.edge_has_sent_end = 1; /* closing the circuit, nothing to send to */
+      connection_mark_for_close(TO_CONN(conn));
+      conn->_base.hold_open_until_flushed = 1;
     }
   }
   conn->cpath_layer = NULL;
@@ -157,44 +155,46 @@
  * else return 0.
  */
 int
-connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_layer)
+connection_edge_end(edge_connection_t *conn, char reason,
+                    crypt_path_t *cpath_layer)
 {
   char payload[RELAY_PAYLOAD_SIZE];
   size_t payload_len=1;
   circuit_t *circ;
 
-  if (conn->has_sent_end) {
+  if (conn->_base.edge_has_sent_end) {
     log_warn(LD_BUG,"Harmless bug: Calling connection_edge_end (reason %d) "
              "on an already ended stream?", reason);
     tor_fragile_assert();
     return -1;
   }
 
-  if (conn->marked_for_close) {
+  if (conn->_base.marked_for_close) {
     log_warn(LD_BUG,
              "Bug: called on conn that's already marked for close at %s:%d.",
-             conn->marked_for_close_file, conn->marked_for_close);
+             conn->_base.marked_for_close_file, conn->_base.marked_for_close);
     return 0;
   }
 
   payload[0] = reason;
   if (reason == END_STREAM_REASON_EXITPOLICY &&
       !connection_edge_is_rendezvous_stream(conn)) {
-    set_uint32(payload+1, htonl(conn->addr));
+    set_uint32(payload+1, htonl(conn->_base.addr));
     set_uint32(payload+5, htonl(dns_clip_ttl(conn->address_ttl)));
     payload_len += 8;
   }
 
   circ = circuit_get_by_edge_conn(conn);
   if (circ && !circ->marked_for_close) {
-    log_debug(LD_EDGE,"Marking conn (fd %d) and sending end.",conn->s);
+    log_debug(LD_EDGE,"Marking conn (fd %d) and sending end.",conn->_base.s);
     connection_edge_send_command(conn, circ, RELAY_COMMAND_END,
                                  payload, payload_len, cpath_layer);
   } else {
-    log_debug(LD_EDGE,"Marking conn (fd %d); no circ to send end.",conn->s);
+    log_debug(LD_EDGE,"Marking conn (fd %d); no circ to send end.",
+              conn->_base.s);
   }
 
-  conn->has_sent_end = 1;
+  conn->_base.edge_has_sent_end = 1;
   return 0;
 }
 
@@ -203,11 +203,11 @@
  * an appropriate relay end cell to <b>cpath_layer</b>.
  **/
 int
-connection_edge_end_errno(connection_t *conn, crypt_path_t *cpath_layer)
+connection_edge_end_errno(edge_connection_t *conn, crypt_path_t *cpath_layer)
 {
   uint8_t reason;
   tor_assert(conn);
-  reason = (uint8_t)errno_to_end_reason(tor_socket_errno(conn->s));
+  reason = (uint8_t)errno_to_end_reason(tor_socket_errno(conn->_base.s));
   return connection_edge_end(conn, reason, cpath_layer);
 }
 
@@ -222,15 +222,14 @@
  * return 0.
  */
 int
-connection_edge_finished_flushing(connection_t *conn)
+connection_edge_finished_flushing(edge_connection_t *conn)
 {
   tor_assert(conn);
-  tor_assert(CONN_IS_EDGE(conn));
 
-  switch (conn->state) {
+  switch (conn->_base.state) {
     case AP_CONN_STATE_OPEN:
     case EXIT_CONN_STATE_OPEN:
-      connection_stop_writing(conn);
+      connection_stop_writing(TO_CONN(conn));
       connection_edge_consider_sending_sendme(conn);
       return 0;
     case AP_CONN_STATE_SOCKS_WAIT:
@@ -238,10 +237,10 @@
     case AP_CONN_STATE_CIRCUIT_WAIT:
     case AP_CONN_STATE_CONNECT_WAIT:
     case AP_CONN_STATE_CONTROLLER_WAIT:
-      connection_stop_writing(conn);
+      connection_stop_writing(TO_CONN(conn));
       return 0;
     default:
-      log_warn(LD_BUG,"BUG: called in unexpected state %d.", conn->state);
+      log_warn(LD_BUG,"BUG: called in unexpected state %d.", conn->_base.state);
       tor_fragile_assert();
       return -1;
   }
@@ -252,13 +251,15 @@
  * data, deliver 'CONNECTED' relay cells as appropriate, and check
  * any pending data that may have been received. */
 int
-connection_edge_finished_connecting(connection_t *conn)
+connection_edge_finished_connecting(edge_connection_t *edge_conn)
 {
   char valbuf[INET_NTOA_BUF_LEN];
+  connection_t *conn;
   struct in_addr in;
 
-  tor_assert(conn);
-  tor_assert(conn->type == CONN_TYPE_EXIT);
+  tor_assert(edge_conn);
+  tor_assert(edge_conn->_base.type == CONN_TYPE_EXIT);
+  conn = TO_CONN(edge_conn);
   tor_assert(conn->state == EXIT_CONN_STATE_CONNECTING);
 
   in.s_addr = htonl(conn->addr);
@@ -272,23 +273,27 @@
                                         * cells */
     connection_start_writing(conn);
   /* deliver a 'connected' relay cell back through the circuit. */
-  if (connection_edge_is_rendezvous_stream(conn)) {
-    if (connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
+  if (connection_edge_is_rendezvous_stream(edge_conn)) {
+    if (connection_edge_send_command(edge_conn,
+                                     circuit_get_by_edge_conn(edge_conn),
                                      RELAY_COMMAND_CONNECTED, NULL, 0,
-                                     conn->cpath_layer) < 0)
+                                     edge_conn->cpath_layer) < 0)
       return 0; /* circuit is closed, don't continue */
   } else {
     char connected_payload[8];
     set_uint32(connected_payload, htonl(conn->addr));
     set_uint32(connected_payload+4,
-               htonl(dns_clip_ttl(conn->address_ttl)));
-    if (connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
-        RELAY_COMMAND_CONNECTED, connected_payload, 8, conn->cpath_layer) < 0)
+               htonl(dns_clip_ttl(edge_conn->address_ttl)));
+    if (connection_edge_send_command(edge_conn,
+                                     circuit_get_by_edge_conn(edge_conn),
+                                     RELAY_COMMAND_CONNECTED,
+                                     connected_payload, 8,
+                                     edge_conn->cpath_layer) < 0)
       return 0; /* circuit is closed, don't continue */
   }
-  tor_assert(conn->package_window > 0);
+  tor_assert(edge_conn->package_window > 0);
   /* in case the server has written anything */
-  return connection_edge_process_inbuf(conn, 1);
+  return connection_edge_process_inbuf(edge_conn, 1);
 }
 
 /** Define a schedule for how long to wait between retrying
@@ -297,7 +302,7 @@
  * 10 seconds for the second, and 15 seconds for each retry after
  * that. Hopefully this will improve the expected experience. */
 static int
-compute_socks_timeout(connection_t *conn)
+compute_socks_timeout(edge_connection_t *conn)
 {
   if (conn->num_socks_retries == 0)
     return 5;
@@ -319,7 +324,7 @@
 connection_ap_expire_beginning(void)
 {
   connection_t **carray;
-  connection_t *conn;
+  edge_connection_t *conn;
   circuit_t *circ;
   const char *nickname;
   int n, i;
@@ -331,24 +336,24 @@
   get_connection_array(&carray, &n);
 
   for (i = 0; i < n; ++i) {
-    conn = carray[i];
-    if (conn->type != CONN_TYPE_AP)
+    if (carray[i]->type != CONN_TYPE_AP)
       continue;
+    conn = TO_EDGE_CONN(carray[i]);
     /* if it's an internal bridge connection, don't yell its status. */
-    severity = (!conn->addr && !conn->port) ? LOG_INFO : LOG_NOTICE;
-    if (conn->state == AP_CONN_STATE_CONTROLLER_WAIT) {
-      if (now - conn->timestamp_lastread >= options->SocksTimeout) {
+    severity = (!conn->_base.addr && !conn->_base.port) ? LOG_INFO : LOG_NOTICE;
+    if (conn->_base.state == AP_CONN_STATE_CONTROLLER_WAIT) {
+      if (now - conn->_base.timestamp_lastread >= options->SocksTimeout) {
         log_fn(severity, LD_APP, "Closing unattached stream.");
         connection_mark_unattached_ap(conn, END_STREAM_REASON_TIMEOUT);
       }
       continue;
     }
 
-    if (conn->state != AP_CONN_STATE_RESOLVE_WAIT &&
-        conn->state != AP_CONN_STATE_CONNECT_WAIT)
+    if (conn->_base.state != AP_CONN_STATE_RESOLVE_WAIT &&
+        conn->_base.state != AP_CONN_STATE_CONNECT_WAIT)
       continue;
     cutoff = compute_socks_timeout(conn);
-    if (now - conn->timestamp_lastread < cutoff)
+    if (now - conn->_base.timestamp_lastread < cutoff)
       continue;
     circ = circuit_get_by_edge_conn(conn);
     if (!circ) { /* it's vanished? */
@@ -358,11 +363,11 @@
       continue;
     }
     if (circ->purpose == CIRCUIT_PURPOSE_C_REND_JOINED) {
-      if (now - conn->timestamp_lastread > options->SocksTimeout) {
+      if (now - conn->_base.timestamp_lastread > options->SocksTimeout) {
         log_fn(severity, LD_REND,
                "Rend stream is %d seconds late. Giving up on address"
                " '%s.onion'.",
-               (int)(now - conn->timestamp_lastread),
+               (int)(now - conn->_base.timestamp_lastread),
                safe_str(conn->socks_request->address));
         connection_edge_end(conn, END_STREAM_REASON_TIMEOUT,
                             conn->cpath_layer);
@@ -376,20 +381,20 @@
     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.",
-           (int)(now - conn->timestamp_lastread),
+           (int)(now - conn->_base.timestamp_lastread),
            safe_str(conn->socks_request->address),
            nickname ? nickname : "*unnamed*");
     /* send an end down the circuit */
     connection_edge_end(conn, END_STREAM_REASON_TIMEOUT, conn->cpath_layer);
     /* un-mark it as ending, since we're going to reuse it */
-    conn->has_sent_end = 0;
+    conn->_base.edge_has_sent_end = 0;
     /* kludge to make us not try this circuit again, yet to allow
      * current streams on it to survive if they can: make it
      * unattractive to use for new streams */
     tor_assert(circ->timestamp_dirty);
     circ->timestamp_dirty -= options->MaxCircuitDirtiness;
     /* give our stream another 'cutoff' seconds to try */
-    conn->timestamp_lastread += cutoff;
+    conn->_base.timestamp_lastread += cutoff;
     conn->num_socks_retries++;
     /* move it back into 'pending' state, and try to attach. */
     if (connection_ap_detach_retriable(conn, TO_ORIGIN_CIRCUIT(circ))<0) {
@@ -406,6 +411,7 @@
 {
   connection_t **carray;
   connection_t *conn;
+  edge_connection_t *edge_conn;
   int n, i;
 
   get_connection_array(&carray, &n);
@@ -416,8 +422,9 @@
         conn->type != CONN_TYPE_AP ||
         conn->state != AP_CONN_STATE_CIRCUIT_WAIT)
       continue;
-    if (connection_ap_handshake_attach_circuit(conn) < 0) {
-      connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
+    edge_conn = TO_EDGE_CONN(conn);
+    if (connection_ap_handshake_attach_circuit(edge_conn) < 0) {
+      connection_mark_unattached_ap(edge_conn, END_STREAM_REASON_CANT_ATTACH);
     }
   }
 }
@@ -430,16 +437,16 @@
  * Returns -1 on err, 1 on success, 0 on not-yet-sure.
  */
 int
-connection_ap_detach_retriable(connection_t *conn, origin_circuit_t *circ)
+connection_ap_detach_retriable(edge_connection_t *conn, origin_circuit_t *circ)
 {
   control_event_stream_status(conn, STREAM_EVENT_FAILED_RETRIABLE);
-  conn->timestamp_lastread = time(NULL);
+  conn->_base.timestamp_lastread = time(NULL);
   if (! get_options()->LeaveStreamsUnattached) {
-    conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
+    conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
     circuit_detach_stream(TO_CIRCUIT(circ),conn);
     return connection_ap_handshake_attach_circuit(conn);
   } else {
-    conn->state = AP_CONN_STATE_CONTROLLER_WAIT;
+    conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
     circuit_detach_stream(TO_CIRCUIT(circ),conn);
     return 0;
   }
@@ -1011,7 +1018,7 @@
  * rendezvous descriptor is already here and fresh enough).
  */
 int
-connection_ap_handshake_rewrite_and_attach(connection_t *conn,
+connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
                                            origin_circuit_t *circ)
 {
   socks_request_t *socks = conn->socks_request;
@@ -1137,7 +1144,7 @@
       /* help predict this next time */
       rep_hist_note_used_port(socks->port, time(NULL));
     }
-    conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
+    conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
     if ((circ &&
          connection_ap_handshake_attach_chosen_circuit(conn, circ) < 0) ||
         (!circ &&
@@ -1182,21 +1189,21 @@
       return -1;
     }
     if (r==0) {
-      conn->state = AP_CONN_STATE_RENDDESC_WAIT;
+      conn->_base.state = AP_CONN_STATE_RENDDESC_WAIT;
       log_info(LD_REND, "Unknown descriptor %s. Fetching.",
                safe_str(conn->rend_query));
       rend_client_refetch_renddesc(conn->rend_query);
     } else { /* r > 0 */
 #define NUM_SECONDS_BEFORE_REFETCH (60*15)
       if (time(NULL) - entry->received < NUM_SECONDS_BEFORE_REFETCH) {
-        conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
+        conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
         log_info(LD_REND, "Descriptor is here and fresh enough. Great.");
         if (connection_ap_handshake_attach_circuit(conn) < 0) {
           connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
           return -1;
         }
       } else {
-        conn->state = AP_CONN_STATE_RENDDESC_WAIT;
+        conn->_base.state = AP_CONN_STATE_RENDDESC_WAIT;
         log_info(LD_REND, "Stale descriptor %s. Refetching.",
                  safe_str(conn->rend_query));
         rend_client_refetch_renddesc(conn->rend_query);
@@ -1218,25 +1225,25 @@
  * for close), else return 0.
  */
 static int
-connection_ap_handshake_process_socks(connection_t *conn)
+connection_ap_handshake_process_socks(edge_connection_t *conn)
 {
   socks_request_t *socks;
   int sockshere;
   or_options_t *options = get_options();
 
   tor_assert(conn);
-  tor_assert(conn->type == CONN_TYPE_AP);
-  tor_assert(conn->state == AP_CONN_STATE_SOCKS_WAIT);
+  tor_assert(conn->_base.type == CONN_TYPE_AP);
+  tor_assert(conn->_base.state == AP_CONN_STATE_SOCKS_WAIT);
   tor_assert(conn->socks_request);
   socks = conn->socks_request;
 
   log_debug(LD_APP,"entered.");
 
-  sockshere = fetch_from_buf_socks(conn->inbuf, socks,
+  sockshere = fetch_from_buf_socks(conn->_base.inbuf, socks,
                                    options->TestSocks, options->SafeSocks);
   if (sockshere == 0) {
     if (socks->replylen) {
-      connection_write_to_buf(socks->reply, socks->replylen, conn);
+      connection_write_to_buf(socks->reply, socks->replylen, TO_CONN(conn));
       /* zero it out so we can do another round of negotiation */
       socks->replylen = 0;
     } else {
@@ -1263,7 +1270,7 @@
     control_event_stream_status(conn, STREAM_EVENT_NEW_RESOLVE);
 
   if (options->LeaveStreamsUnattached) {
-    conn->state = AP_CONN_STATE_CONTROLLER_WAIT;
+    conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
     return 0;
   }
   return connection_ap_handshake_rewrite_and_attach(conn, NULL);
@@ -1275,7 +1282,7 @@
 static uint16_t
 get_unique_stream_id_by_circ(origin_circuit_t *circ)
 {
-  connection_t *tmpconn;
+  edge_connection_t *tmpconn;
   uint16_t test_stream_id;
   uint32_t attempts=0;
 
@@ -1300,14 +1307,14 @@
  * 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,
+connection_ap_handshake_send_begin(edge_connection_t *ap_conn,
                                    origin_circuit_t *circ)
 {
   char payload[CELL_PAYLOAD_SIZE];
   int payload_len;
 
-  tor_assert(ap_conn->type == CONN_TYPE_AP);
-  tor_assert(ap_conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
+  tor_assert(ap_conn->_base.type == CONN_TYPE_AP);
+  tor_assert(ap_conn->_base.state == AP_CONN_STATE_CIRCUIT_WAIT);
   tor_assert(ap_conn->socks_request);
 
   ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
@@ -1334,9 +1341,9 @@
 
   ap_conn->package_window = STREAMWINDOW_START;
   ap_conn->deliver_window = STREAMWINDOW_START;
-  ap_conn->state = AP_CONN_STATE_CONNECT_WAIT;
+  ap_conn->_base.state = AP_CONN_STATE_CONNECT_WAIT;
   log_info(LD_APP,"Address/port sent, ap socket %d, n_circ_id %d",
-           ap_conn->s, circ->_base.n_circ_id);
+           ap_conn->_base.s, circ->_base.n_circ_id);
   control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT);
   return 0;
 }
@@ -1347,14 +1354,14 @@
  * 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,
+connection_ap_handshake_send_resolve(edge_connection_t *ap_conn,
                                      origin_circuit_t *circ)
 {
   int payload_len;
   const char *string_addr;
 
-  tor_assert(ap_conn->type == CONN_TYPE_AP);
-  tor_assert(ap_conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
+  tor_assert(ap_conn->_base.type == CONN_TYPE_AP);
+  tor_assert(ap_conn->_base.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->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL);
@@ -1378,9 +1385,9 @@
                            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;
+  ap_conn->_base.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->_base.n_circ_id);
+           ap_conn->_base.s, circ->_base.n_circ_id);
   control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE);
   return 0;
 }
@@ -1395,7 +1402,7 @@
 connection_ap_make_bridge(char *address, uint16_t port)
 {
   int fd[2];
-  connection_t *conn;
+  edge_connection_t *conn;
   int err;
 
   log_info(LD_APP,"Making AP bridge to %s:%d ...",safe_str(address),port);
@@ -1413,8 +1420,8 @@
   set_socket_nonblocking(fd[0]);
   set_socket_nonblocking(fd[1]);
 
-  conn = connection_new(CONN_TYPE_AP);
-  conn->s = fd[0];
+  conn = TO_EDGE_CONN(connection_new(CONN_TYPE_AP));
+  conn->_base.s = fd[0];
 
   /* populate conn->socks_request */
 
@@ -1426,18 +1433,18 @@
   conn->socks_request->port = port;
   conn->socks_request->command = SOCKS_COMMAND_CONNECT;
 
-  conn->address = tor_strdup("(local bridge)");
-  conn->addr = 0;
-  conn->port = 0;
+  conn->_base.address = tor_strdup("(local bridge)");
+  conn->_base.addr = 0;
+  conn->_base.port = 0;
 
-  if (connection_add(conn) < 0) { /* no space, forget it */
-    connection_free(conn); /* this closes fd[0] */
+  if (connection_add(TO_CONN(conn)) < 0) { /* no space, forget it */
+    connection_free(TO_CONN(conn)); /* this closes fd[0] */
     tor_close_socket(fd[1]);
     return -1;
   }
 
-  conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
-  connection_start_reading(conn);
+  conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
+  connection_start_reading(TO_CONN(conn));
 
   /* attaching to a dirty circuit is fine */
   if (connection_ap_handshake_attach_circuit(conn) < 0) {
@@ -1456,7 +1463,7 @@
  * in the socks extensions document.
  **/
 void
-connection_ap_handshake_socks_resolved(connection_t *conn,
+connection_ap_handshake_socks_resolved(edge_connection_t *conn,
                                        int answer_type,
                                        size_t answer_len,
                                        const char *answer,
@@ -1523,7 +1530,7 @@
  * If <b>reply</b> is undefined, <b>status</b> can't be 0.
  */
 void
-connection_ap_handshake_socks_reply(connection_t *conn, char *reply,
+connection_ap_handshake_socks_reply(edge_connection_t *conn, char *reply,
                                     size_t replylen,
                                     socks5_reply_status_t status) {
   char buf[256];
@@ -1538,7 +1545,7 @@
     return;
   }
   if (replylen) { /* we already have a reply in mind */
-    connection_write_to_buf(reply, replylen, conn);
+    connection_write_to_buf(reply, replylen, TO_CONN(conn));
     conn->socks_request->has_finished = 1;
     return;
   }
@@ -1548,7 +1555,7 @@
 #define SOCKS4_REJECT           91
     buf[1] = (status==SOCKS5_SUCCEEDED ? SOCKS4_GRANTED : SOCKS4_REJECT);
     /* leave version, destport, destip zero */
-    connection_write_to_buf(buf, SOCKS4_NETWORK_LEN, conn);
+    connection_write_to_buf(buf, SOCKS4_NETWORK_LEN, TO_CONN(conn));
   } else if (conn->socks_request->socks_version == 5) {
     buf[0] = 5; /* version 5 */
     buf[1] = (char)status;
@@ -1556,7 +1563,7 @@
     buf[3] = 1; /* ipv4 addr */
     memset(buf+4,0,6); /* Set external addr/port to 0.
                           The spec doesn't seem to say what to do here. -RD */
-    connection_write_to_buf(buf,10,conn);
+    connection_write_to_buf(buf,10,TO_CONN(conn));
   }
   /* If socks_version isn't 4 or 5, don't send anything.
    * This can happen in the case of AP bridges. */
@@ -1583,7 +1590,7 @@
 int
 connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
 {
-  connection_t *n_stream;
+  edge_connection_t *n_stream;
   relay_header_t rh;
   char *address=NULL;
   uint16_t port;
@@ -1623,11 +1630,11 @@
 #endif
 
   log_debug(LD_EXIT,"Creating new exit connection.");
-  n_stream = connection_new(CONN_TYPE_EXIT);
-  n_stream->purpose = EXIT_PURPOSE_CONNECT;
+  n_stream = TO_EDGE_CONN(connection_new(CONN_TYPE_EXIT));
+  n_stream->_base.purpose = EXIT_PURPOSE_CONNECT;
 
   n_stream->stream_id = rh.stream_id;
-  n_stream->port = port;
+  n_stream->_base.port = port;
   /* leave n_stream->s at -1, because it's not yet valid */
   n_stream->package_window = STREAMWINDOW_START;
   n_stream->deliver_window = STREAMWINDOW_START;
@@ -1635,18 +1642,18 @@
   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;
+    n_stream->_base.address = tor_strdup("(rendezvous)");
+    n_stream->_base.state = EXIT_CONN_STATE_CONNECTING;
     strlcpy(n_stream->rend_query, origin_circ->rend_query,
             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, origin_circ) < 0) {
       log_info(LD_REND,"Didn't find rendezvous service (port %d)",
-               n_stream->port);
+               n_stream->_base.port);
       connection_edge_end(n_stream, END_STREAM_REASON_EXITPOLICY,
                           n_stream->cpath_layer);
-      connection_free(n_stream);
+      connection_free(TO_CONN(n_stream));
       /* knock the whole thing down, somebody screwed up */
       circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
       tor_free(address);
@@ -1667,14 +1674,14 @@
     return 0;
   }
   tor_strlower(address);
-  n_stream->address = address;
-  n_stream->state = EXIT_CONN_STATE_RESOLVEFAILED;
+  n_stream->_base.address = address;
+  n_stream->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
   /* default to failed, change in dns_resolve if it turns out not to fail */
 
   if (we_are_hibernating()) {
     connection_edge_end(n_stream, END_STREAM_REASON_HIBERNATING,
                         n_stream->cpath_layer);
-    connection_free(n_stream);
+    connection_free(TO_CONN(n_stream));
     return 0;
   }
   log_debug(LD_EXIT,"about to start the dns_resolve().");
@@ -1713,7 +1720,7 @@
 int
 connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ)
 {
-  connection_t *dummy_conn;
+  edge_connection_t *dummy_conn;
   relay_header_t rh;
 
   assert_circuit_ok(TO_CIRCUIT(circ));
@@ -1726,13 +1733,13 @@
    * resolved; but if we didn't store them in a connection like this,
    * the housekeeping in dns.c would get way more complicated.)
    */
-  dummy_conn = connection_new(CONN_TYPE_EXIT);
+  dummy_conn = TO_EDGE_CONN(connection_new(CONN_TYPE_EXIT));
   dummy_conn->stream_id = rh.stream_id;
-  dummy_conn->address = tor_strndup(cell->payload+RELAY_HEADER_SIZE,
-                                    rh.length);
-  dummy_conn->port = 0;
-  dummy_conn->state = EXIT_CONN_STATE_RESOLVEFAILED;
-  dummy_conn->purpose = EXIT_PURPOSE_RESOLVE;
+  dummy_conn->_base.address = tor_strndup(cell->payload+RELAY_HEADER_SIZE,
+                                          rh.length);
+  dummy_conn->_base.port = 0;
+  dummy_conn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
+  dummy_conn->_base.purpose = EXIT_PURPOSE_RESOLVE;
 
   /* send it off to the gethostbyname farm */
   switch (dns_resolve(dummy_conn)) {
@@ -1740,8 +1747,8 @@
       /* Connection freed; don't touch it. */
       return 0;
     case 1: /* The result was cached; a resolved cell was sent. */
-      if (!dummy_conn->marked_for_close)
-        connection_free(dummy_conn);
+      if (!dummy_conn->_base.marked_for_close)
+        connection_free(TO_CONN(dummy_conn));
       return 0;
     case 0: /* resolve added to pending list */
       dummy_conn->next_stream = circ->resolving_streams;
@@ -1761,17 +1768,19 @@
  * streams must not reveal what IP they connected to.)
  */
 void
-connection_exit_connect(connection_t *conn)
+connection_exit_connect(edge_connection_t *edge_conn)
 {
   uint32_t addr;
   uint16_t port;
+  connection_t *conn = TO_CONN(edge_conn);
 
-  if (!connection_edge_is_rendezvous_stream(conn) &&
-      router_compare_to_my_exit_policy(conn)) {
+  if (!connection_edge_is_rendezvous_stream(edge_conn) &&
+      router_compare_to_my_exit_policy(edge_conn)) {
     log_info(LD_EXIT,"%s:%d failed exit policy. Closing.",
              escaped_safe_str(conn->address), conn->port);
-    connection_edge_end(conn, END_STREAM_REASON_EXITPOLICY, conn->cpath_layer);
-    circuit_detach_stream(circuit_get_by_edge_conn(conn), conn);
+    connection_edge_end(edge_conn, END_STREAM_REASON_EXITPOLICY,
+                        edge_conn->cpath_layer);
+    circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn);
     connection_free(conn);
     return;
   }
@@ -1802,8 +1811,8 @@
   log_debug(LD_EXIT,"about to try connecting");
   switch (connection_connect(conn, conn->address, addr, port)) {
     case -1:
-      connection_edge_end_errno(conn, conn->cpath_layer);
-      circuit_detach_stream(circuit_get_by_edge_conn(conn), conn);
+      connection_edge_end_errno(edge_conn, edge_conn->cpath_layer);
+      circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn);
       connection_free(conn);
       return;
     case 0:
@@ -1825,20 +1834,20 @@
   connection_watch_events(conn, EV_READ);
 
   /* also, deliver a 'connected' cell back through the circuit. */
-  if (connection_edge_is_rendezvous_stream(conn)) { /* rendezvous stream */
+  if (connection_edge_is_rendezvous_stream(edge_conn)) { /* rendezvous stream */
     /* don't send an address back! */
-    connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
+    connection_edge_send_command(edge_conn, circuit_get_by_edge_conn(edge_conn),
                                  RELAY_COMMAND_CONNECTED,
-                                 NULL, 0, conn->cpath_layer);
+                                 NULL, 0, edge_conn->cpath_layer);
   } else { /* normal stream */
     /* This must be the original address, not the redirected address. */
     char connected_payload[8];
     set_uint32(connected_payload, htonl(conn->addr));
     set_uint32(connected_payload+4,
-               htonl(dns_clip_ttl(conn->address_ttl)));
-    connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
+               htonl(dns_clip_ttl(edge_conn->address_ttl)));
+    connection_edge_send_command(edge_conn, circuit_get_by_edge_conn(edge_conn),
                                  RELAY_COMMAND_CONNECTED,
-                                 connected_payload, 8, conn->cpath_layer);
+                                 connected_payload, 8, edge_conn->cpath_layer);
   }
 }
 
@@ -1846,7 +1855,7 @@
  * it is a general stream.
  */
 int
-connection_edge_is_rendezvous_stream(connection_t *conn)
+connection_edge_is_rendezvous_stream(edge_connection_t *conn)
 {
   tor_assert(conn);
   if (*conn->rend_query) /* XXX */
@@ -1860,10 +1869,10 @@
  * resolved.)
  */
 int
-connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit)
+connection_ap_can_use_exit(edge_connection_t *conn, routerinfo_t *exit)
 {
   tor_assert(conn);
-  tor_assert(conn->type == CONN_TYPE_AP);
+  tor_assert(conn->_base.type == CONN_TYPE_AP);
   tor_assert(conn->socks_request);
   tor_assert(exit);
 

Modified: tor/trunk/src/or/connection_or.c
===================================================================
--- tor/trunk/src/or/connection_or.c	2006-07-26 19:07:23 UTC (rev 6905)
+++ tor/trunk/src/or/connection_or.c	2006-07-26 19:07:26 UTC (rev 6906)
@@ -19,8 +19,8 @@
 
 #define TIGHT_CERT_ALLOW_SKEW (90*60)
 
-static int connection_tls_finish_handshake(connection_t *conn);
-static int connection_or_process_cells_from_inbuf(connection_t *conn);
+static int connection_tls_finish_handshake(or_connection_t *conn);
+static int connection_or_process_cells_from_inbuf(or_connection_t *conn);
 
 /**************************************************************/
 
@@ -32,11 +32,10 @@
 /** If conn is listed in orconn_identity_map, remove it, and clear
  * conn->identity_digest. */
 void
-connection_or_remove_from_identity_map(connection_t *conn)
+connection_or_remove_from_identity_map(or_connection_t *conn)
 {
-  connection_t *tmp;
+  or_connection_t *tmp;
   tor_assert(conn);
-  tor_assert(conn->type == CONN_TYPE_OR);
   if (!orconn_identity_map)
     return;
   tmp = digestmap_get(orconn_identity_map, conn->identity_digest);
@@ -73,8 +72,9 @@
   for (i = 0; i < n; ++i) {
     connection_t* conn = carray[i];
     if (conn->type == CONN_TYPE_OR) {
-      memset(conn->identity_digest, 0, DIGEST_LEN);
-      conn->next_with_same_id = NULL;
+      or_connection_t *or_conn = TO_OR_CONN(conn);
+      memset(or_conn->identity_digest, 0, DIGEST_LEN);
+      or_conn->next_with_same_id = NULL;
     }
   }
 
@@ -87,11 +87,10 @@
 /** Change conn->identity_digest to digest, and add conn into
  * orconn_digest_map. */
 static void
-connection_or_set_identity_digest(connection_t *conn, const char *digest)
+connection_or_set_identity_digest(or_connection_t *conn, const char *digest)
 {
-  connection_t *tmp;
+  or_connection_t *tmp;
   tor_assert(conn);
-  tor_assert(conn->type == CONN_TYPE_OR);
   tor_assert(digest);
 
   if (!orconn_identity_map)
@@ -136,10 +135,10 @@
 }
 
 int
-connection_or_reached_eof(connection_t *conn)
+connection_or_reached_eof(or_connection_t *conn)
 {
   log_info(LD_OR,"OR connection reached EOF. Closing.");
-  connection_mark_for_close(conn);
+  connection_mark_for_close(TO_CONN(conn));
   return 0;
 }
 
@@ -149,13 +148,14 @@
  * and hope for better luck next time.
  */
 static int
-connection_or_read_proxy_response(connection_t *conn)
+connection_or_read_proxy_response(or_connection_t *or_conn)
 {
   char *headers;
   char *reason=NULL;
   int status_code;
   time_t date_header;
   int compression;
+  connection_t *conn = TO_CONN(or_conn);
 
   switch (fetch_from_buf_http(conn->inbuf,
                               &headers, MAX_HEADERS_SIZE,
@@ -185,7 +185,7 @@
              "HTTPS connect to '%s' successful! (200 %s) Starting TLS.",
              conn->address, escaped(reason));
     tor_free(reason);
-    if (connection_tls_start_handshake(conn, 0) < 0) {
+    if (connection_tls_start_handshake(or_conn, 0) < 0) {
       /* TLS handshaking error of some kind. */
       connection_mark_for_close(conn);
 
@@ -209,12 +209,11 @@
  * (else do nothing).
  */
 int
-connection_or_process_inbuf(connection_t *conn)
+connection_or_process_inbuf(or_connection_t *conn)
 {
   tor_assert(conn);
-  tor_assert(conn->type == CONN_TYPE_OR);
 
-  switch (conn->state) {
+  switch (conn->_base.state) {
     case OR_CONN_STATE_PROXY_READING:
       return connection_or_read_proxy_response(conn);
     case OR_CONN_STATE_OPEN:
@@ -233,24 +232,22 @@
  * return 0.
  */
 int
-connection_or_finished_flushing(connection_t *conn)
+connection_or_finished_flushing(or_connection_t *conn)
 {
   tor_assert(conn);
-  tor_assert(conn->type == CONN_TYPE_OR);
+  assert_connection_ok(TO_CONN(conn),0);
 
-  assert_connection_ok(conn,0);
-
-  switch (conn->state) {
+  switch (conn->_base.state) {
     case OR_CONN_STATE_PROXY_FLUSHING:
       log_debug(LD_OR,"finished sending CONNECT to proxy.");
-      conn->state = OR_CONN_STATE_PROXY_READING;
-      connection_stop_writing(conn);
+      conn->_base.state = OR_CONN_STATE_PROXY_READING;
+      connection_stop_writing(TO_CONN(conn));
       break;
     case OR_CONN_STATE_OPEN:
-      connection_stop_writing(conn);
+      connection_stop_writing(TO_CONN(conn));
       break;
     default:
-      log_err(LD_BUG,"BUG: called in unexpected state %d.", conn->state);
+      log_err(LD_BUG,"BUG: called in unexpected state %d.", conn->_base.state);
       tor_fragile_assert();
       return -1;
   }
@@ -260,10 +257,11 @@
 /** Connected handler for OR connections: begin the TLS handshake.
  */
 int
-connection_or_finished_connecting(connection_t *conn)
+connection_or_finished_connecting(or_connection_t *or_conn)
 {
-  tor_assert(conn);
-  tor_assert(conn->type == CONN_TYPE_OR);
+  connection_t *conn;
+  tor_assert(or_conn);
+  conn = TO_CONN(or_conn);
   tor_assert(conn->state == OR_CONN_STATE_CONNECTING);
 
   log_debug(LD_OR,"OR connect() to router at %s:%u finished.",
@@ -298,7 +296,7 @@
     return 0;
   }
 
-  if (connection_tls_start_handshake(conn, 0) < 0) {
+  if (connection_tls_start_handshake(or_conn, 0) < 0) {
     /* TLS handshaking error of some kind. */
     connection_mark_for_close(conn);
     return -1;
@@ -310,7 +308,7 @@
  * have an addr/port/id_digest, then fill in as much as we can. Start
  * by checking to see if this describes a router we know. */
 static void
-connection_or_init_conn_from_address(connection_t *conn,
+connection_or_init_conn_from_address(or_connection_t *conn,
                                      uint32_t addr, uint16_t port,
                                      const char *id_digest,
                                      int started_here)
@@ -320,19 +318,19 @@
   conn->bandwidthrate = (int)options->BandwidthRate;
   conn->receiver_bucket = conn->bandwidthburst = (int)options->BandwidthBurst;
   connection_or_set_identity_digest(conn, id_digest);
-  conn->addr = addr;
-  conn->port = port;
+  conn->_base.addr = addr;
+  conn->_base.port = port;
   if (r) {
     if (!started_here) {
       /* Override the addr/port, so our log messages will make sense.
        * This is dangerous, since if we ever try looking up a conn by
        * its actual addr/port, we won't remember. Careful! */
-      conn->addr = r->addr;
-      conn->port = r->or_port;
+      conn->_base.addr = r->addr;
+      conn->_base.port = r->or_port;
     }
     conn->nickname = tor_strdup(r->nickname);
-    tor_free(conn->address);
-    conn->address = tor_strdup(r->address);
+    tor_free(conn->_base.address);
+    conn->_base.address = tor_strdup(r->address);
   } else {
     const char *n;
     /* If we're an authoritative directory server, we may know a
@@ -346,8 +344,8 @@
       base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1,
                     conn->identity_digest, DIGEST_LEN);
     }
-    tor_free(conn->address);
-    conn->address = tor_dup_addr(addr);
+    tor_free(conn->_base.address);
+    conn->_base.address = tor_dup_addr(addr);
   }
 }
 
@@ -360,11 +358,11 @@
  * 4) Then if there are any non-empty conns, ignore empty conns.
  * 5) Of the remaining conns, prefer newer conns.
  */
-connection_t *
+or_connection_t *
 connection_or_get_by_identity_digest(const char *digest)
 {
   int newer;
-  connection_t *conn, *best=NULL;
+  or_connection_t *conn, *best=NULL;
 
   if (!orconn_identity_map)
     return NULL;
@@ -372,26 +370,26 @@
   conn = digestmap_get(orconn_identity_map, digest);
 
   for (; conn; conn = conn->next_with_same_id) {
-    tor_assert(conn->magic == CONNECTION_MAGIC);
-    tor_assert(conn->type == CONN_TYPE_OR);
+    tor_assert(conn->_base.magic == OR_CONNECTION_MAGIC);
+    tor_assert(conn->_base.type == CONN_TYPE_OR);
     tor_assert(!memcmp(conn->identity_digest, digest, DIGEST_LEN));
-    if (conn->marked_for_close)
+    if (conn->_base.marked_for_close)
       continue;
     if (!best) {
       best = conn; /* whatever it is, it's better than nothing. */
       continue;
     }
-    if (best->state == OR_CONN_STATE_OPEN &&
-        conn->state != OR_CONN_STATE_OPEN)
+    if (best->_base.state == OR_CONN_STATE_OPEN &&
+        conn->_base.state != OR_CONN_STATE_OPEN)
       continue; /* avoid non-open conns if we can */
-    newer = best->timestamp_created < conn->timestamp_created;
+    newer = best->_base.timestamp_created < conn->_base.timestamp_created;
 
-    if (!best->is_obsolete && conn->is_obsolete)
+    if (!best->_base.or_is_obsolete && conn->_base.or_is_obsolete)
       continue; /* We never prefer obsolete over non-obsolete connections. */
 
     if (
       /* We prefer non-obsolete connections: */
-        (best->is_obsolete && !conn->is_obsolete) ||
+        (best->_base.or_is_obsolete && !conn->_base.or_is_obsolete) ||
       /* If both have circuits we prefer the newer: */
         (best->n_circuits && conn->n_circuits && newer) ||
       /* If neither has circuits we prefer the newer: */
@@ -418,10 +416,10 @@
  *
  * Return the launched conn, or NULL if it failed.
  */
-connection_t *
+or_connection_t *
 connection_or_connect(uint32_t addr, uint16_t port, const char *id_digest)
 {
-  connection_t *conn;
+  or_connection_t *conn;
   or_options_t *options = get_options();
 
   tor_assert(id_digest);
@@ -431,11 +429,11 @@
     return NULL;
   }
 
-  conn = connection_new(CONN_TYPE_OR);
+  conn = TO_OR_CONN(connection_new(CONN_TYPE_OR));
 
   /* set up conn so it's got all the data we need to remember */
   connection_or_init_conn_from_address(conn, addr, port, id_digest, 1);
-  conn->state = OR_CONN_STATE_CONNECTING;
+  conn->_base.state = OR_CONN_STATE_CONNECTING;
   control_event_or_conn_status(conn, OR_CONN_EVENT_LAUNCHED);
 
   if (options->HttpsProxy) {
@@ -444,7 +442,7 @@
     port = options->HttpsProxyPort;
   }
 
-  switch (connection_connect(conn, conn->address, addr, port)) {
+  switch (connection_connect(TO_CONN(conn), conn->_base.address, addr, port)) {
     case -1:
       /* If the connection failed immediately, and we're using
        * an https proxy, our https proxy is down. Don't blame the
@@ -454,10 +452,10 @@
         router_set_status(conn->identity_digest, 0);
       }
       control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
-      connection_free(conn);
+      connection_free(TO_CONN(conn));
       return NULL;
     case 0:
-      connection_watch_events(conn, EV_READ | EV_WRITE);
+      connection_watch_events(TO_CONN(conn), EV_READ | EV_WRITE);
       /* writable indicates finish, readable indicates broken link,
          error indicates broken link on windows */
       return conn;
@@ -480,16 +478,16 @@
  * Return -1 if <b>conn</b> is broken, else return 0.
  */
 int
-connection_tls_start_handshake(connection_t *conn, int receiving)
+connection_tls_start_handshake(or_connection_t *conn, int receiving)
 {
-  conn->state = OR_CONN_STATE_HANDSHAKING;
-  conn->tls = tor_tls_new(conn->s, receiving);
+  conn->_base.state = OR_CONN_STATE_HANDSHAKING;
+  conn->tls = tor_tls_new(conn->_base.s, receiving);
   if (!conn->tls) {
     log_warn(LD_BUG,"tor_tls_new failed. Closing.");
     return -1;
   }
-  connection_start_reading(conn);
-  log_debug(LD_OR,"starting TLS handshake on fd %d", conn->s);
+  connection_start_reading(TO_CONN(conn));
+  log_debug(LD_OR,"starting TLS handshake on fd %d", conn->_base.s);
   if (connection_tls_continue_handshake(conn) < 0) {
     return -1;
   }
@@ -502,7 +500,7 @@
  * Return -1 if <b>conn</b> is broken, else return 0.
  */
 int
-connection_tls_continue_handshake(connection_t *conn)
+connection_tls_continue_handshake(or_connection_t *conn)
 {
   check_no_tls_errors();
   switch (tor_tls_handshake(conn->tls)) {
@@ -513,7 +511,7 @@
     case TOR_TLS_DONE:
      return connection_tls_finish_handshake(conn);
     case TOR_TLS_WANTWRITE:
-      connection_start_writing(conn);
+      connection_start_writing(TO_CONN(conn));
       log_debug(LD_OR,"wanted write");
       return 0;
     case TOR_TLS_WANTREAD: /* handshaking conns are *always* reading */
@@ -531,9 +529,9 @@
  * one day so we're clearer.
  */
 int
-connection_or_nonopen_was_started_here(connection_t *conn)
+connection_or_nonopen_was_started_here(or_connection_t *conn)
 {
-  tor_assert(conn->type == CONN_TYPE_OR);
+  tor_assert(conn->_base.type == CONN_TYPE_OR);
   if (!conn->tls)
     return 1; /* it's still in proxy states or something */
   return !tor_tls_is_server(conn->tls);
@@ -557,7 +555,7 @@
  *    this guy; and note that this guy is reachable.
  */
 static int
-connection_or_check_valid_handshake(connection_t *conn, char *digest_rcvd)
+connection_or_check_valid_handshake(or_connection_t *conn, char *digest_rcvd)
 {
   routerinfo_t *router;
   crypto_pk_env_t *identity_rcvd=NULL;
@@ -568,7 +566,7 @@
   check_no_tls_errors();
   if (! tor_tls_peer_has_cert(conn->tls)) {
     log_info(LD_PROTOCOL,"Peer (%s:%d) didn't send a cert! Closing.",
-             conn->address, conn->port);
+             conn->_base.address, conn->_base.port);
     return -1;
   }
   check_no_tls_errors();
@@ -576,17 +574,17 @@
                                      sizeof(nickname))) {
     log_fn(severity,LD_PROTOCOL,"Other side (%s:%d) has a cert without a "
            "valid nickname. Closing.",
-           conn->address, conn->port);
+           conn->_base.address, conn->_base.port);
     return -1;
   }
   check_no_tls_errors();
   log_debug(LD_OR, "Other side (%s:%d) claims to be router '%s'",
-            conn->address, conn->port, nickname);
+            conn->_base.address, conn->_base.port, nickname);
 
   if (tor_tls_verify(severity, conn->tls, &identity_rcvd) < 0) {
     log_fn(severity,LD_OR,"Other side, which claims to be router '%s' (%s:%d),"
            " has a cert but it's invalid. Closing.",
-           nickname, conn->address, conn->port);
+           nickname, conn->_base.address, conn->_base.port);
     return -1;
   }
   check_no_tls_errors();
@@ -607,7 +605,7 @@
     log_fn(severity, LD_OR,
            "Identity key not as expected for router claiming to be "
            "'%s' (%s:%d)",
-           nickname, conn->address, conn->port);
+           nickname, conn->_base.address, conn->_base.port);
     return -1;
   }
 
@@ -623,7 +621,7 @@
       log_fn(severity, LD_OR,
              "Identity key not as expected for router at %s:%d: wanted %s "
              "but got %s",
-             conn->address, conn->port, expected, seen);
+             conn->_base.address, conn->_base.port, expected, seen);
       entry_guard_set_status(conn->identity_digest, 0);
       router_set_status(conn->identity_digest, 0);
       control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
@@ -633,7 +631,7 @@
       /* We initiated this connection to address:port.  Drop all routers
        * with the same address:port and a different key or nickname.
        */
-      dirserv_orconn_tls_done(conn->address, conn->port,
+      dirserv_orconn_tls_done(conn->_base.address, conn->_base.port,
                               digest_rcvd, nickname, as_advertised);
     }
     if (!as_advertised)
@@ -654,7 +652,7 @@
  * directory to be dirty (only matters if I'm an authdirserver).
  */
 static int
-connection_tls_finish_handshake(connection_t *conn)
+connection_tls_finish_handshake(or_connection_t *conn)
 {
   char digest_rcvd[DIGEST_LEN];
   int started_here = connection_or_nonopen_was_started_here(conn);
@@ -664,7 +662,7 @@
     return -1;
 
   if (!started_here) {
-    connection_or_init_conn_from_address(conn,conn->addr,conn->port,
+    connection_or_init_conn_from_address(conn,conn->_base.addr,conn->_base.port,
                                          digest_rcvd, 0);
 
     /* Annotate that we received a TLS connection.
@@ -677,12 +675,12 @@
      * The reason this bandaid is here is because there's a bug in
      * Tor 0.1.1.x where middle hops don't always send their create
      * cell; so some servers rarely find themselves reachable. */
-//    if (!is_local_IP(conn->addr))
+//    if (!is_local_IP(conn->_base.addr))
 //      router_orport_found_reachable();
   }
 
   directory_set_dirty();
-  conn->state = OR_CONN_STATE_OPEN;
+  conn->_base.state = OR_CONN_STATE_OPEN;
   control_event_or_conn_status(conn, OR_CONN_EVENT_CONNECTED);
   if (started_here) {
     rep_hist_note_connect_succeeded(conn->identity_digest, time(NULL));
@@ -692,7 +690,7 @@
     }
     router_set_status(conn->identity_digest, 1);
   }
-  connection_watch_events(conn, EV_READ);
+  connection_watch_events(TO_CONN(conn), EV_READ);
   circuit_n_conn_done(conn, 1); /* send the pending creates, if any. */
   return 0;
 }
@@ -704,18 +702,17 @@
  * ready, then try to flush the record now.
  */
 void
-connection_or_write_cell_to_buf(const cell_t *cell, connection_t *conn)
+connection_or_write_cell_to_buf(const cell_t *cell, or_connection_t *conn)
 {
   char networkcell[CELL_NETWORK_SIZE];
   char *n = networkcell;
 
   tor_assert(cell);
   tor_assert(conn);
-  tor_assert(connection_speaks_cells(conn));
 
   cell_pack(n, cell);
 
-  connection_write_to_buf(n, CELL_NETWORK_SIZE, conn);
+  connection_write_to_buf(n, CELL_NETWORK_SIZE, TO_CONN(conn));
 
 #define MIN_TLS_FLUSHLEN 15872
 /* openssl tls record size is 16383, this is close. The goal here is to
@@ -723,26 +720,28 @@
  * during periods of high load we won't read the entire megabyte from
  * input before pushing any data out. It also has the feature of not
  * growing huge outbufs unless something is slow. */
-  if (conn->outbuf_flushlen-CELL_NETWORK_SIZE < MIN_TLS_FLUSHLEN &&
-      conn->outbuf_flushlen >= MIN_TLS_FLUSHLEN) {
-    int extra = conn->outbuf_flushlen - MIN_TLS_FLUSHLEN;
-    conn->outbuf_flushlen = MIN_TLS_FLUSHLEN;
-    if (connection_handle_write(conn) < 0) {
-      if (!conn->marked_for_close) {
+  if (conn->_base.outbuf_flushlen-CELL_NETWORK_SIZE < MIN_TLS_FLUSHLEN &&
+      conn->_base.outbuf_flushlen >= MIN_TLS_FLUSHLEN) {
+    int extra = conn->_base.outbuf_flushlen - MIN_TLS_FLUSHLEN;
+    conn->_base.outbuf_flushlen = MIN_TLS_FLUSHLEN;
+    if (connection_handle_write(TO_CONN(conn)) < 0) {
+      if (!conn->_base.marked_for_close) {
         /* this connection is broken. remove it. */
         log_warn(LD_BUG,
                  "Bug: unhandled error on write for OR conn (fd %d); removing",
-                 conn->s);
+                 conn->_base.s);
         tor_fragile_assert();
-        conn->has_sent_end = 1; /* don't cry wolf about duplicate close */
+        // XXX This was supposed to be edge-only!
+        // conn->has_sent_end = 1; /* don't cry wolf about duplicate close */
+
         /* XXX do we need a close-immediate here, so we don't try to flush? */
-        connection_mark_for_close(conn);
+        connection_mark_for_close(TO_CONN(conn));
       }
       return;
     }
     if (extra) {
-      conn->outbuf_flushlen += extra;
-      connection_start_writing(conn);
+      conn->_base.outbuf_flushlen += extra;
+      connection_start_writing(TO_CONN(conn));
     }
   }
 }
@@ -755,7 +754,7 @@
  * Always return 0.
  */
 static int
-connection_or_process_cells_from_inbuf(connection_t *conn)
+connection_or_process_cells_from_inbuf(or_connection_t *conn)
 {
   char buf[CELL_NETWORK_SIZE];
   cell_t cell;
@@ -763,13 +762,13 @@
 loop:
   log_debug(LD_OR,
             "%d: starting, inbuf_datalen %d (%d pending in tls object).",
-            conn->s,(int)buf_datalen(conn->inbuf),
+            conn->_base.s,(int)buf_datalen(conn->_base.inbuf),
             tor_tls_get_pending_bytes(conn->tls));
-  if (buf_datalen(conn->inbuf) < CELL_NETWORK_SIZE) /* whole response
-                                                       available? */
+  if (buf_datalen(conn->_base.inbuf) < CELL_NETWORK_SIZE) /* whole response
+                                                             available? */
     return 0; /* not yet */
 
-  connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, conn);
+  connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, TO_CONN(conn));
 
   /* retrieve cell info from buf (create the host-order struct from the
    * network-order string) */
@@ -787,12 +786,11 @@
  * Return 0.
  */
 int
-connection_or_send_destroy(uint16_t circ_id, connection_t *conn, int reason)
+connection_or_send_destroy(uint16_t circ_id, or_connection_t *conn, int reason)
 {
   cell_t cell;
 
   tor_assert(conn);
-  tor_assert(connection_speaks_cells(conn));
 
   memset(&cell, 0, sizeof(cell_t));
   cell.circ_id = circ_id;

Modified: tor/trunk/src/or/control.c
===================================================================
--- tor/trunk/src/or/control.c	2006-07-26 19:07:23 UTC (rev 6905)
+++ tor/trunk/src/or/control.c	2006-07-26 19:07:26 UTC (rev 6906)
@@ -131,57 +131,57 @@
 static int authentication_cookie_is_set = 0;
 static char authentication_cookie[AUTHENTICATION_COOKIE_LEN];
 
-static void connection_printf_to_buf(connection_t *conn,
+static void connection_printf_to_buf(control_connection_t *conn,
                                      const char *format, ...)
   CHECK_PRINTF(2,3);
 /*static*/ size_t write_escaped_data(const char *data, size_t len,
                                      int translate_newlines, char **out);
 /*static*/ size_t read_escaped_data(const char *data, size_t len,
                                     int translate_newlines,  char **out);
-static void send_control0_message(connection_t *conn, uint16_t type,
+static void send_control0_message(control_connection_t *conn, uint16_t type,
                                  uint32_t len, const char *body);
-static void send_control_done(connection_t *conn);
-static void send_control_done2(connection_t *conn, const char *msg,
+static void send_control_done(control_connection_t *conn);
+static void send_control_done2(control_connection_t *conn, const char *msg,
                                size_t len);
-static void send_control0_error(connection_t *conn, uint16_t error,
+static void send_control0_error(control_connection_t *conn, uint16_t error,
                                const char *message);
 static void send_control0_event(uint16_t event, uint32_t len,
                                 const char *body);
 static void send_control1_event(uint16_t event, const char *format, ...)
   CHECK_PRINTF(2,3);
-static int handle_control_setconf(connection_t *conn, uint32_t len,
+static int handle_control_setconf(control_connection_t *conn, uint32_t len,
                                   char *body);
-static int handle_control_resetconf(connection_t *conn, uint32_t len,
+static int handle_control_resetconf(control_connection_t *conn, uint32_t len,
                                     char *body);
-static int handle_control_getconf(connection_t *conn, uint32_t len,
+static int handle_control_getconf(control_connection_t *conn, uint32_t len,
                                   const char *body);
-static int handle_control_setevents(connection_t *conn, uint32_t len,
+static int handle_control_setevents(control_connection_t *conn, uint32_t len,
                                     const char *body);
-static int handle_control_authenticate(connection_t *conn, uint32_t len,
+static int handle_control_authenticate(control_connection_t *conn, uint32_t len,
                                        const char *body);
-static int handle_control_saveconf(connection_t *conn, uint32_t len,
+static int handle_control_saveconf(control_connection_t *conn, uint32_t len,
                                    const char *body);
-static int handle_control_signal(connection_t *conn, uint32_t len,
+static int handle_control_signal(control_connection_t *conn, uint32_t len,
                                  const char *body);
-static int handle_control_mapaddress(connection_t *conn, uint32_t len,
+static int handle_control_mapaddress(control_connection_t *conn, uint32_t len,
                                      const char *body);
-static int handle_control_getinfo(connection_t *conn, uint32_t len,
+static int handle_control_getinfo(control_connection_t *conn, uint32_t len,
                                   const char *body);
-static int handle_control_extendcircuit(connection_t *conn, uint32_t len,
+static int handle_control_extendcircuit(control_connection_t *conn, uint32_t len,
                                         const char *body);
-static int handle_control_setpurpose(connection_t *conn, int for_circuits,
+static int handle_control_setpurpose(control_connection_t *conn, int for_circuits,
                                      uint32_t len, const char *body);
-static int handle_control_attachstream(connection_t *conn, uint32_t len,
+static int handle_control_attachstream(control_connection_t *conn, uint32_t len,
                                         const char *body);
-static int handle_control_postdescriptor(connection_t *conn, uint32_t len,
+static int handle_control_postdescriptor(control_connection_t *conn, uint32_t len,
                                          const char *body);
-static int handle_control_redirectstream(connection_t *conn, uint32_t len,
+static int handle_control_redirectstream(control_connection_t *conn, uint32_t len,
                                          const char *body);
-static int handle_control_closestream(connection_t *conn, uint32_t len,
+static int handle_control_closestream(control_connection_t *conn, uint32_t len,
                                       const char *body);
-static int handle_control_closecircuit(connection_t *conn, uint32_t len,
+static int handle_control_closecircuit(control_connection_t *conn, uint32_t len,
                                        const char *body);
-static int write_stream_target_to_buf(connection_t *conn, char *buf,
+static int write_stream_target_to_buf(edge_connection_t *conn, char *buf,
                                       size_t len);
 
 /** Given a possibly invalid message type code <b>cmd</b>, return a
@@ -235,10 +235,11 @@
   for (i = 0; i < n_conns; ++i) {
     if (conns[i]->type == CONN_TYPE_CONTROL &&
         STATE_IS_OPEN(conns[i]->state)) {
-      if (STATE_IS_V0(conns[i]->state))
-        global_event_mask0 |= conns[i]->event_mask;
+      control_connection_t *conn = TO_CONTROL_CONN(conns[i]);
+      if (STATE_IS_V0(conn->_base.state))
+        global_event_mask0 |= conn->event_mask;
       else
-        global_event_mask1 |= conns[i]->event_mask;
+        global_event_mask1 |= conn->event_mask;
     }
   }
 
@@ -281,10 +282,10 @@
  * <b>conn</b>-\>outbuf
  */
 static INLINE void
-connection_write_str_to_buf(const char *s, connection_t *conn)
+connection_write_str_to_buf(const char *s, control_connection_t *conn)
 {
   size_t len = strlen(s);
-  connection_write_to_buf(s, len, conn);
+  connection_write_to_buf(s, len, TO_CONN(conn));
 }
 
 /** Given a <b>len</b>-character string in <b>data</b>, made of lines
@@ -446,7 +447,7 @@
  * Currently the length of the message is limited to 1024 (including the
  * ending \n\r\0. */
 static void
-connection_printf_to_buf(connection_t *conn, const char *format, ...)
+connection_printf_to_buf(control_connection_t *conn, const char *format, ...)
 {
 #define CONNECTION_PRINTF_TO_BUF_BUFFERSIZE 1024
   va_list ap;
@@ -462,41 +463,41 @@
     buf[CONNECTION_PRINTF_TO_BUF_BUFFERSIZE-2] = '\n';
     buf[CONNECTION_PRINTF_TO_BUF_BUFFERSIZE-3] = '\r';
   }
-  connection_write_to_buf(buf, len, conn);
+  connection_write_to_buf(buf, len, TO_CONN(conn));
 }
 
 /** Send a message of type <b>type</b> containing <b>len</b> bytes
  * from <b>body</b> along the control connection <b>conn</b> */
 static void
-send_control0_message(connection_t *conn, uint16_t type, uint32_t len,
-                     const char *body)
+send_control0_message(control_connection_t *conn, uint16_t type, uint32_t len,
+                      const char *body)
 {
   char buf[10];
   tor_assert(conn);
-  tor_assert(STATE_IS_V0(conn->state));
+  tor_assert(STATE_IS_V0(conn->_base.state));
   tor_assert(len || !body);
   tor_assert(type <= _CONTROL0_CMD_MAX_RECOGNIZED);
   if (len < 65536) {
     set_uint16(buf, htons(len));
     set_uint16(buf+2, htons(type));
-    connection_write_to_buf(buf, 4, conn);
+    connection_write_to_buf(buf, 4, TO_CONN(conn));
     if (len)
-      connection_write_to_buf(body, len, conn);
+      connection_write_to_buf(body, len, TO_CONN(conn));
   } else {
     set_uint16(buf, htons(65535));
     set_uint16(buf+2, htons(CONTROL0_CMD_FRAGMENTHEADER));
     set_uint16(buf+4, htons(type));
     set_uint32(buf+6, htonl(len));
-    connection_write_to_buf(buf, 10, conn);
-    connection_write_to_buf(body, 65535-6, conn);
+    connection_write_to_buf(buf, 10, TO_CONN(conn));
+    connection_write_to_buf(body, 65535-6, TO_CONN(conn));
     len -= (65535-6);
     body += (65535-6);
     while (len) {
       size_t chunklen = (len<65535)?len:65535;
       set_uint16(buf, htons((uint16_t)chunklen));
       set_uint16(buf+2, htons(CONTROL0_CMD_FRAGMENT));
-      connection_write_to_buf(buf, 4, conn);
-      connection_write_to_buf(body, chunklen, conn);
+      connection_write_to_buf(buf, 4, TO_CONN(conn));
+      connection_write_to_buf(body, chunklen, TO_CONN(conn));
       len -= chunklen;
       body += chunklen;
     }
@@ -505,9 +506,9 @@
 
 /** Send a "DONE" message down the control connection <b>conn</b> */
 static void
-send_control_done(connection_t *conn)
+send_control_done(control_connection_t *conn)
 {
-  if (STATE_IS_V0(conn->state)) {
+  if (STATE_IS_V0(conn->_base.state)) {
     send_control0_message(conn, CONTROL0_CMD_DONE, 0, NULL);
   } else {
     connection_write_str_to_buf("250 OK\r\n", conn);
@@ -518,7 +519,7 @@
  * as provided in the <b>len</b> bytes at <b>msg</b>.
  */
 static void
-send_control_done2(connection_t *conn, const char *msg, size_t len)
+send_control_done2(control_connection_t *conn, const char *msg, size_t len)
 {
   if (len==0)
     len = strlen(msg);
@@ -528,7 +529,7 @@
 /** Send an error message with error code <b>error</b> and body
  * <b>message</b> down the connection <b>conn</b> */
 static void
-send_control0_error(connection_t *conn, uint16_t error, const char *message)
+send_control0_error(control_connection_t *conn, uint16_t error, const char *message)
 {
   char buf[256];
   size_t len;
@@ -561,11 +562,13 @@
   for (i = 0; i < n_conns; ++i) {
     if (conns[i]->type == CONN_TYPE_CONTROL &&
         !conns[i]->marked_for_close &&
-        conns[i]->state == CONTROL_CONN_STATE_OPEN_V0 &&
-        conns[i]->event_mask & (1<<event)) {
-      send_control0_message(conns[i], CONTROL0_CMD_EVENT, buflen, buf);
-      if (event == EVENT_ERR_MSG)
-        _connection_controller_force_write(conns[i]);
+        conns[i]->state == CONTROL_CONN_STATE_OPEN_V0) {
+      control_connection_t *control_conn = TO_CONTROL_CONN(conns[i]);
+      if (control_conn->event_mask & (1<<event)) {
+        send_control0_message(control_conn, CONTROL0_CMD_EVENT, buflen, buf);
+        if (event == EVENT_ERR_MSG)
+          _connection_controller_force_write(control_conn);
+      }
     }
   }
 
@@ -586,11 +589,13 @@
   for (i = 0; i < n_conns; ++i) {
     if (conns[i]->type == CONN_TYPE_CONTROL &&
         !conns[i]->marked_for_close &&
-        conns[i]->state == CONTROL_CONN_STATE_OPEN_V1 &&
-        conns[i]->event_mask & (1<<event)) {
-      connection_write_to_buf(msg, strlen(msg), conns[i]);
-      if (event == EVENT_ERR_MSG)
-        _connection_controller_force_write(conns[i]);
+        conns[i]->state == CONTROL_CONN_STATE_OPEN_V1) {
+      control_connection_t *control_conn = TO_CONTROL_CONN(conns[i]);
+      if (control_conn->event_mask & (1<<event)) {
+        connection_write_to_buf(msg, strlen(msg), TO_CONN(control_conn));
+        if (event == EVENT_ERR_MSG)
+          _connection_controller_force_write(control_conn);
+      }
     }
   }
 }
@@ -657,14 +662,14 @@
  * it passes <b>use_defaults</b> on to options_trial_assign().
  */
 static int
-control_setconf_helper(connection_t *conn, uint32_t len, char *body,
+control_setconf_helper(control_connection_t *conn, uint32_t len, char *body,
                        int use_defaults, int clear_first)
 {
   int r;
   config_line_t *lines=NULL;
   char *start = body;
   char *errstring = NULL;
-  int v0 = STATE_IS_V0(conn->state);
+  int v0 = STATE_IS_V0(conn->_base.state);
 
   if (!v0) {
     char *config = tor_malloc(len+1);
@@ -761,7 +766,7 @@
 /** Called when we receive a SETCONF message: parse the body and try
  * to update our configuration.  Reply with a DONE or ERROR message. */
 static int
-handle_control_setconf(connection_t *conn, uint32_t len, char *body)
+handle_control_setconf(control_connection_t *conn, uint32_t len, char *body)
 {
   return control_setconf_helper(conn, len, body, 0, 1);
 }
@@ -769,9 +774,9 @@
 /** Called when we receive a RESETCONF message: parse the body and try
  * to update our configuration.  Reply with a DONE or ERROR message. */
 static int
-handle_control_resetconf(connection_t *conn, uint32_t len, char *body)
+handle_control_resetconf(control_connection_t *conn, uint32_t len, char *body)
 {
-  int v0 = STATE_IS_V0(conn->state);
+  int v0 = STATE_IS_V0(conn->_base.state);
   tor_assert(!v0);
   return control_setconf_helper(conn, len, body, 1, 1);
 }
@@ -779,7 +784,7 @@
 /** Called when we receive a GETCONF message.  Parse the request, and
  * reply with a CONFVALUE or an ERROR message */
 static int
-handle_control_getconf(connection_t *conn, uint32_t body_len, const char *body)
+handle_control_getconf(control_connection_t *conn, uint32_t body_len, const char *body)
 {
   smartlist_t *questions = NULL;
   smartlist_t *answers = NULL;
@@ -787,7 +792,7 @@
   char *msg = NULL;
   size_t msg_len;
   or_options_t *options = get_options();
-  int v0 = STATE_IS_V0(conn->state);
+  int v0 = STATE_IS_V0(conn->_base.state);
 
   questions = smartlist_create();
   (void) body_len; /* body is nul-terminated; so we can ignore len. */
@@ -858,7 +863,7 @@
       tor_assert(strlen(tmp)>4);
       tmp[3] = ' ';
       msg = smartlist_join_strings(answers, "", 0, &msg_len);
-      connection_write_to_buf(msg, msg_len, conn);
+      connection_write_to_buf(msg, msg_len, TO_CONN(conn));
     } else {
       connection_write_str_to_buf("250 OK\r\n", conn);
     }
@@ -882,13 +887,13 @@
 /** Called when we get a SETEVENTS message: update conn->event_mask,
  * and reply with DONE or ERROR. */
 static int
-handle_control_setevents(connection_t *conn, uint32_t len, const char *body)
+handle_control_setevents(control_connection_t *conn, uint32_t len, const char *body)
 {
   uint16_t event_code;
   uint32_t event_mask = 0;
   unsigned int extended = 0;
 
-  if (STATE_IS_V0(conn->state)) {
+  if (STATE_IS_V0(conn->_base.state)) {
     if (len % 2) {
       send_control0_error(conn, ERR_SYNTAX,
                           "Odd number of bytes in setevents message");
@@ -950,7 +955,7 @@
     smartlist_free(events);
   }
   conn->event_mask = event_mask;
-  conn->control_events_are_extended = extended;
+  conn->_base.control_events_are_extended = extended;
 
   control_update_global_event_mask();
   send_control_done(conn);
@@ -987,13 +992,13 @@
  * OPEN.  Reply with DONE or ERROR.
  */
 static int
-handle_control_authenticate(connection_t *conn, uint32_t len, const char *body)
+handle_control_authenticate(control_connection_t *conn, uint32_t len, const char *body)
 {
   int used_quoted_string = 0;
   or_options_t *options = get_options();
   char *password;
   size_t password_len;
-  if (STATE_IS_V0(conn->state)) {
+  if (STATE_IS_V0(conn->_base.state)) {
     password = (char*)body;
     password_len = len;
   } else {
@@ -1047,7 +1052,7 @@
   }
 
  err:
-  if (STATE_IS_V0(conn->state))
+  if (STATE_IS_V0(conn->_base.state))
     send_control0_error(conn,ERR_REJECTED_AUTHENTICATION,
                         "Authentication failed");
   else {
@@ -1061,12 +1066,12 @@
   }
   return 0;
  ok:
-  log_info(LD_CONTROL, "Authenticated control connection (%d)", conn->s);
+  log_info(LD_CONTROL, "Authenticated control connection (%d)", conn->_base.s);
   send_control_done(conn);
-  if (STATE_IS_V0(conn->state))
-    conn->state = CONTROL_CONN_STATE_OPEN_V0;
+  if (STATE_IS_V0(conn->_base.state))
+    conn->_base.state = CONTROL_CONN_STATE_OPEN_V0;
   else {
-    conn->state = CONTROL_CONN_STATE_OPEN_V1;
+    conn->_base.state = CONTROL_CONN_STATE_OPEN_V1;
     tor_free(password);
   }
   return 0;
@@ -1075,13 +1080,13 @@
 /** Called when we get a SAVECONF command. Try to flush the current options to
  * disk, and report success or failure. */
 static int
-handle_control_saveconf(connection_t *conn, uint32_t len,
+handle_control_saveconf(control_connection_t *conn, uint32_t len,
                         const char *body)
 {
   (void) len;
   (void) body;
   if (options_save_current()<0) {
-    if (STATE_IS_V0(conn->state))
+    if (STATE_IS_V0(conn->_base.state))
       send_control0_error(conn, ERR_INTERNAL,
                           "Unable to write configuration to disk.");
     else
@@ -1097,11 +1102,11 @@
  * report success or failure. (If the signal results in a shutdown, success
  * may not be reported.) */
 static int
-handle_control_signal(connection_t *conn, uint32_t len,
+handle_control_signal(control_connection_t *conn, uint32_t len,
                       const char *body)
 {
   int sig;
-  if (STATE_IS_V0(conn->state)) {
+  if (STATE_IS_V0(conn->_base.state)) {
     if (len != 1) {
       send_control0_error(conn, ERR_SYNTAX,
                           "Body of SIGNAL command too long or too short.");
@@ -1138,7 +1143,7 @@
   }
 
   if (control_signal_act(sig) < 0) {
-    if (STATE_IS_V0(conn->state))
+    if (STATE_IS_V0(conn->_base.state))
       send_control0_error(conn, ERR_SYNTAX, "Unrecognized signal number.");
     else
       connection_write_str_to_buf("551 Internal error acting on signal\r\n",
@@ -1152,14 +1157,14 @@
 /** Called when we get a MAPADDRESS command; try to bind all listed addresses,
  * and report success or failrue. */
 static int
-handle_control_mapaddress(connection_t *conn, uint32_t len, const char *body)
+handle_control_mapaddress(control_connection_t *conn, uint32_t len, const char *body)
 {
   smartlist_t *elts;
   smartlist_t *lines;
   smartlist_t *reply;
   char *r;
   size_t sz;
-  int v0 = STATE_IS_V0(conn->state);
+  int v0 = STATE_IS_V0(conn->_base.state);
   (void) len; /* body is nul-terminated, so it's safe to ignore the length. */
 
   lines = smartlist_create();
@@ -1257,12 +1262,12 @@
     if (smartlist_len(reply)) {
       ((char*)smartlist_get(reply,smartlist_len(reply)-1))[3] = ' ';
       r = smartlist_join_strings(reply, "\r\n", 1, &sz);
-      connection_write_to_buf(r, sz, conn);
+      connection_write_to_buf(r, sz, TO_CONN(conn));
       tor_free(r);
     } else {
       const char *response =
         "512 syntax error: not enough arguments to mapaddress.\r\n";
-      connection_write_to_buf(response, strlen(response), conn);
+      connection_write_to_buf(response, strlen(response), TO_CONN(conn));
     }
   }
 
@@ -1399,6 +1404,7 @@
     get_connection_array(&conns, &n_conns);
     for (i=0; i < n_conns; ++i) {
       const char *state;
+      edge_connection_t *conn;
       char *s;
       size_t slen;
       circuit_t *circ;
@@ -1406,12 +1412,13 @@
           conns[i]->marked_for_close ||
           conns[i]->state == AP_CONN_STATE_SOCKS_WAIT)
         continue;
-      switch (conns[i]->state)
+      conn = TO_EDGE_CONN(conns[i]);
+      switch (conn->_base.state)
         {
         case AP_CONN_STATE_CONTROLLER_WAIT:
         case AP_CONN_STATE_CIRCUIT_WAIT:
-          if (conns[i]->socks_request &&
-              conns[i]->socks_request->command == SOCKS_COMMAND_RESOLVE)
+          if (conn->socks_request &&
+              conn->socks_request->command == SOCKS_COMMAND_RESOLVE)
             state = "NEWRESOLVE";
           else
             state = "NEW";
@@ -1425,15 +1432,15 @@
           state = "SUCCEEDED"; break;
         default:
           log_warn(LD_BUG, "Asked for stream in unknown state %d",
-                   conns[i]->state);
+                   conn->_base.state);
           continue;
         }
-      circ = circuit_get_by_edge_conn(conns[i]);
-      write_stream_target_to_buf(conns[i], buf, sizeof(buf));
+      circ = circuit_get_by_edge_conn(conn);
+      write_stream_target_to_buf(conn, buf, sizeof(buf));
       slen = strlen(buf)+strlen(state)+32;
       s = tor_malloc(slen+1);
       tor_snprintf(s, slen, "%lu %s %lu %s",
-                   (unsigned long) conns[i]->global_identifier,state,
+                   (unsigned long) conn->_base.global_identifier,state,
                    circ?(unsigned long)circ->global_identifier : 0ul,
                    buf);
       smartlist_add(status, s);
@@ -1451,10 +1458,11 @@
       char *s;
       char name[128];
       size_t slen;
-      connection_t *conn = conns[i];
-      if (conn->type != CONN_TYPE_OR || conn->marked_for_close)
+      or_connection_t *conn;
+      if (conns[i]->type != CONN_TYPE_OR || conns[i]->marked_for_close)
         continue;
-      if (conn->state == OR_CONN_STATE_OPEN)
+      conn = TO_OR_CONN(conns[i]);
+      if (conn->_base.state == OR_CONN_STATE_OPEN)
         state = "CONNECTED";
       else if (conn->nickname)
         state = "LAUNCHED";
@@ -1464,7 +1472,7 @@
         strlcpy(name, conn->nickname, sizeof(name));
       else
         tor_snprintf(name, sizeof(name), "%s:%d",
-                     conn->address, conn->port);
+                     conn->_base.address, conn->_base.port);
 
       slen = strlen(name)+strlen(state)+2;
       s = tor_malloc(slen+1);
@@ -1544,14 +1552,14 @@
 /** Called when we receive a GETINFO command.  Try to fetch all requested
  * information, and reply with information or error message. */
 static int
-handle_control_getinfo(connection_t *conn, uint32_t len, const char *body)
+handle_control_getinfo(control_connection_t *conn, uint32_t len, const char *body)
 {
   smartlist_t *questions = NULL;
   smartlist_t *answers = NULL;
   smartlist_t *unrecognized = NULL;
   char *msg = NULL, *ans = NULL;
   size_t msg_len;
-  int v0 = STATE_IS_V0(conn->state);
+  int v0 = STATE_IS_V0(conn->_base.state);
   (void) len; /* body is nul-terminated, so it's safe to ignore the length. */
 
   questions = smartlist_create();
@@ -1615,7 +1623,7 @@
         size_t len;
         len = write_escaped_data(v, strlen(v), 1, &esc);
         connection_printf_to_buf(conn, "250+%s=\r\n", k);
-        connection_write_to_buf(esc, len, conn);
+        connection_write_to_buf(esc, len, TO_CONN(conn));
         tor_free(esc);
       }
     }
@@ -1662,7 +1670,7 @@
 /** Called when we get an EXTENDCIRCUIT message.  Try to extend the listed
  * circuit, and report success or failure. */
 static int
-handle_control_extendcircuit(connection_t *conn, uint32_t len,
+handle_control_extendcircuit(control_connection_t *conn, uint32_t len,
                              const char *body)
 {
   smartlist_t *router_nicknames=NULL, *routers=NULL;
@@ -1672,7 +1680,7 @@
   char reply[4];
   uint8_t intended_purpose = CIRCUIT_PURPOSE_C_GENERAL;
 
-  v0 = STATE_IS_V0(conn->state);
+  v0 = STATE_IS_V0(conn->_base.state);
   router_nicknames = smartlist_create();
 
   if (v0) {
@@ -1816,7 +1824,7 @@
  * is 1) or SETROUTERPURPOSE message. If we can find
  * the circuit/router and it's a valid purpose, change it. */
 static int
-handle_control_setpurpose(connection_t *conn, int for_circuits,
+handle_control_setpurpose(control_connection_t *conn, int for_circuits,
                           uint32_t len, const char *body)
 {
   circuit_t *circ = NULL;
@@ -1868,14 +1876,15 @@
 /** Called when we get an ATTACHSTREAM message.  Try to attach the requested
  * stream, and report success or failure. */
 static int
-handle_control_attachstream(connection_t *conn, uint32_t len,
+handle_control_attachstream(control_connection_t *conn, uint32_t len,
                             const char *body)
 {
   connection_t *ap_conn = NULL;
   circuit_t *circ = NULL;
   int zero_circ;
+  edge_connection_t *edge_conn;
 
-  if (STATE_IS_V0(conn->state)) {
+  if (STATE_IS_V0(conn->_base.state)) {
     uint32_t conn_id;
     uint32_t circ_id;
     if (len < 8) {
@@ -1927,7 +1936,7 @@
   if (ap_conn->state != AP_CONN_STATE_CONTROLLER_WAIT &&
       ap_conn->state != AP_CONN_STATE_CONNECT_WAIT &&
       ap_conn->state != AP_CONN_STATE_RESOLVE_WAIT) {
-    if (STATE_IS_V0(conn->state)) {
+    if (STATE_IS_V0(conn->_base.state)) {
       send_control0_error(conn, ERR_NO_STREAM,
                           "Connection is not managed by controller.");
     } else {
@@ -1938,20 +1947,23 @@
     return 0;
   }
 
+  edge_conn = TO_EDGE_CONN(ap_conn);
+
   /* Do we need to detach it first? */
   if (ap_conn->state != AP_CONN_STATE_CONTROLLER_WAIT) {
-    circuit_t *tmpcirc = circuit_get_by_edge_conn(ap_conn);
-    connection_edge_end(ap_conn, END_STREAM_REASON_TIMEOUT, conn->cpath_layer);
+    circuit_t *tmpcirc = circuit_get_by_edge_conn(edge_conn);
+    connection_edge_end(edge_conn, END_STREAM_REASON_TIMEOUT,
+                        edge_conn->cpath_layer);
     /* Un-mark it as ending, since we're going to reuse it. */
-    ap_conn->has_sent_end = 0;
+    ap_conn->edge_has_sent_end = 0;
     if (tmpcirc)
-      circuit_detach_stream(tmpcirc,ap_conn);
+      circuit_detach_stream(tmpcirc,edge_conn);
     ap_conn->state = AP_CONN_STATE_CONTROLLER_WAIT;
   }
 
   if (circ &&
       (circ->state != CIRCUIT_STATE_OPEN || ! CIRCUIT_IS_ORIGIN(circ))) {
-    if (STATE_IS_V0(conn->state))
+    if (STATE_IS_V0(conn->_base.state))
       send_control0_error(conn, ERR_INTERNAL,
                           "Refuse to attach stream to non-open, origin circ.");
     else
@@ -1960,9 +1972,9 @@
                      conn);
     return 0;
   }
-  if (connection_ap_handshake_rewrite_and_attach(ap_conn,
+  if (connection_ap_handshake_rewrite_and_attach(edge_conn,
                                   circ ? TO_ORIGIN_CIRCUIT(circ) : NULL) < 0) {
-    if (STATE_IS_V0(conn->state))
+    if (STATE_IS_V0(conn->_base.state))
       send_control0_error(conn, ERR_INTERNAL, "Unable to attach stream.");
     else
       connection_write_str_to_buf("551 Unable to attach stream\r\n", conn);
@@ -1975,11 +1987,11 @@
 /** Called when we get a POSTDESCRIPTOR message.  Try to learn the provided
  * descriptor, and report success or failure. */
 static int
-handle_control_postdescriptor(connection_t *conn, uint32_t len,
+handle_control_postdescriptor(control_connection_t *conn, uint32_t len,
                               const char *body)
 {
   char *desc;
-  int v0 = STATE_IS_V0(conn->state);
+  int v0 = STATE_IS_V0(conn->_base.state);
   const char *msg=NULL;
   uint8_t purpose = ROUTER_PURPOSE_GENERAL;
 
@@ -2034,14 +2046,14 @@
 /** Called when we receive a REDIRECTSTERAM command.  Try to change the target
  * address of the named AP stream, and report success or failure. */
 static int
-handle_control_redirectstream(connection_t *conn, uint32_t len,
+handle_control_redirectstream(control_connection_t *conn, uint32_t len,
                               const char *body)
 {
   connection_t *ap_conn = NULL;
   uint32_t conn_id;
   char *new_addr = NULL;
   uint16_t new_port = 0;
-  if (STATE_IS_V0(conn->state)) {
+  if (STATE_IS_V0(conn->_base.state)) {
     if (len < 6) {
       send_control0_error(conn, ERR_SYNTAX,
                           "redirectstream message too short");
@@ -2051,7 +2063,7 @@
 
     if (!(ap_conn = connection_get_by_global_id(conn_id))
         || ap_conn->state != CONN_TYPE_AP
-        || !ap_conn->socks_request) {
+        || !TO_EDGE_CONN(ap_conn)->socks_request) {
       send_control0_error(conn, ERR_NO_STREAM,
                           "No AP connection found with given ID");
       return 0;
@@ -2066,7 +2078,7 @@
       connection_printf_to_buf(conn,
                                "512 Missing argument to REDIRECTSTREAM\r\n");
     else if (!(ap_conn = get_stream(smartlist_get(args, 0)))
-             || !ap_conn->socks_request) {
+             || !TO_EDGE_CONN(ap_conn)->socks_request) {
       connection_printf_to_buf(conn, "552 Unknown stream \"%s\"\r\n",
                                (char*)smartlist_get(args, 0));
     } else {
@@ -2089,25 +2101,28 @@
       return 0;
   }
 
-  strlcpy(ap_conn->socks_request->address, new_addr,
-          sizeof(ap_conn->socks_request->address));
-  if (new_port)
-    ap_conn->socks_request->port = new_port;
-  tor_free(new_addr);
-  send_control_done(conn);
-  return 0;
+  {
+    edge_connection_t *ap = TO_EDGE_CONN(ap_conn);
+    strlcpy(ap->socks_request->address, new_addr,
+            sizeof(ap->socks_request->address));
+    if (new_port)
+      ap->socks_request->port = new_port;
+    tor_free(new_addr);
+    send_control_done(conn);
+    return 0;
+  }
 }
 
 /** Called when we get a CLOSESTREAM command; try to close the named stream
  * and report success or failure. */
 static int
-handle_control_closestream(connection_t *conn, uint32_t len,
+handle_control_closestream(control_connection_t *conn, uint32_t len,
                            const char *body)
 {
   connection_t *ap_conn=NULL;
   uint8_t reason=0;
 
-  if (STATE_IS_V0(conn->state)) {
+  if (STATE_IS_V0(conn->_base.state)) {
     uint32_t conn_id;
     if (len < 6) {
       send_control0_error(conn, ERR_SYNTAX, "closestream message too short");
@@ -2119,7 +2134,7 @@
 
     if (!(ap_conn = connection_get_by_global_id(conn_id))
         || ap_conn->state != CONN_TYPE_AP
-        || !ap_conn->socks_request) {
+        || !TO_EDGE_CONN(ap_conn)->socks_request) {
       send_control0_error(conn, ERR_NO_STREAM,
                           "No AP connection found with given ID");
       return 0;
@@ -2151,7 +2166,7 @@
       return 0;
   }
 
-  connection_mark_unattached_ap(ap_conn, reason);
+  connection_mark_unattached_ap(TO_EDGE_CONN(ap_conn), reason);
   send_control_done(conn);
   return 0;
 }
@@ -2159,13 +2174,13 @@
 /** Called when we get a CLOSECIRCUIT command; try to close the named circuit
  * and report success or failure. */
 static int
-handle_control_closecircuit(connection_t *conn, uint32_t len,
+handle_control_closecircuit(control_connection_t *conn, uint32_t len,
                             const char *body)
 {
   circuit_t *circ = NULL;
   int safe = 0;
 
-  if (STATE_IS_V0(conn->state)) {
+  if (STATE_IS_V0(conn->_base.state)) {
     uint32_t circ_id;
     if (len < 5) {
       send_control0_error(conn, ERR_SYNTAX, "closecircuit message too short");
@@ -2221,7 +2236,7 @@
  * fragments and report failure.
  */
 static int
-handle_control_fragments(connection_t *conn, uint16_t command_type,
+handle_control_fragments(control_connection_t *conn, uint16_t command_type,
                          uint32_t body_len, char *body)
 {
   if (command_type == CONTROL0_CMD_FRAGMENTHEADER) {
@@ -2262,24 +2277,22 @@
 
 /** Called when <b>conn</b> has no more bytes left on its outbuf. */
 int
-connection_control_finished_flushing(connection_t *conn)
+connection_control_finished_flushing(control_connection_t *conn)
 {
   tor_assert(conn);
-  tor_assert(conn->type == CONN_TYPE_CONTROL);
 
-  connection_stop_writing(conn);
+  connection_stop_writing(TO_CONN(conn));
   return 0;
 }
 
 /** Called when <b>conn</b> has gotten its socket closed. */
 int
-connection_control_reached_eof(connection_t *conn)
+connection_control_reached_eof(control_connection_t *conn)
 {
   tor_assert(conn);
-  tor_assert(conn->type == CONN_TYPE_CONTROL);
 
   log_info(LD_CONTROL,"Control connection reached EOF. Closing.");
-  connection_mark_for_close(conn);
+  connection_mark_for_close(TO_CONN(conn));
   return 0;
 }
 
@@ -2287,16 +2300,15 @@
  * commands from conn->inbuf, and execute them.
  */
 static int
-connection_control_process_inbuf_v1(connection_t *conn)
+connection_control_process_inbuf_v1(control_connection_t *conn)
 {
   size_t data_len;
   int cmd_len;
   char *args;
 
   tor_assert(conn);
-  tor_assert(conn->type == CONN_TYPE_CONTROL);
-  tor_assert(conn->state == CONTROL_CONN_STATE_OPEN_V1 ||
-             conn->state == CONTROL_CONN_STATE_NEEDAUTH_V1);
+  tor_assert(conn->_base.state == CONTROL_CONN_STATE_OPEN_V1 ||
+             conn->_base.state == CONTROL_CONN_STATE_NEEDAUTH_V1);
 
   if (!conn->incoming_cmd) {
     conn->incoming_cmd = tor_malloc(1024);
@@ -2311,7 +2323,7 @@
     /* First, fetch a line. */
     do {
       data_len = conn->incoming_cmd_len - conn->incoming_cmd_cur_len;
-      r = fetch_from_buf_line(conn->inbuf,
+      r = fetch_from_buf_line(conn->_base.inbuf,
                               conn->incoming_cmd+conn->incoming_cmd_cur_len,
                               &data_len);
       if (r == 0)
@@ -2361,11 +2373,11 @@
 
   if (!strcasecmp(conn->incoming_cmd, "QUIT")) {
     connection_write_str_to_buf("250 closing connection\r\n", conn);
-    connection_mark_for_close(conn);
+    connection_mark_for_close(TO_CONN(conn));
     return 0;
   }
 
-  if (conn->state == CONTROL_CONN_STATE_NEEDAUTH_V1 &&
+  if (conn->_base.state == CONTROL_CONN_STATE_NEEDAUTH_V1 &&
       strcasecmp(conn->incoming_cmd, "AUTHENTICATE")) {
     connection_write_str_to_buf("514 Authentication required.\r\n", conn);
     conn->incoming_cmd_cur_len = 0;
@@ -2436,7 +2448,7 @@
  * commands from conn->inbuf, and execute them.
  */
 static int
-connection_control_process_inbuf_v0(connection_t *conn)
+connection_control_process_inbuf_v0(control_connection_t *conn)
 {
   uint32_t body_len;
   uint16_t command_type;
@@ -2444,15 +2456,15 @@
 
  again:
   /* Try to suck a control message from the buffer. */
-  switch (fetch_from_buf_control0(conn->inbuf, &body_len, &command_type, &body,
-                                conn->state == CONTROL_CONN_STATE_NEEDAUTH_V0))
+  switch (fetch_from_buf_control0(conn->_base.inbuf, &body_len, &command_type, &body,
+                                conn->_base.state == CONTROL_CONN_STATE_NEEDAUTH_V0))
     {
     case -2:
       tor_free(body);
       log_info(LD_CONTROL,
                "Detected v1 control protocol on connection (fd %d)",
-               conn->s);
-      conn->state = CONTROL_CONN_STATE_NEEDAUTH_V1;
+               conn->_base.s);
+      conn->_base.state = CONTROL_CONN_STATE_NEEDAUTH_V1;
       return connection_control_process_inbuf_v1(conn);
     case -1:
       tor_free(body);
@@ -2470,7 +2482,7 @@
 
   /* We got a command.  If we need authentication, only authentication
    * commands will be considered. */
-  if (conn->state == CONTROL_CONN_STATE_NEEDAUTH_V0 &&
+  if (conn->_base.state == CONTROL_CONN_STATE_NEEDAUTH_V0 &&
       command_type != CONTROL0_CMD_AUTHENTICATE) {
     log_info(LD_CONTROL, "Rejecting '%s' command; authentication needed.",
              control_cmd_to_string(command_type));
@@ -2584,12 +2596,11 @@
 /** Called when <b>conn</b> has received more bytes on its inbuf.
  */
 int
-connection_control_process_inbuf(connection_t *conn)
+connection_control_process_inbuf(control_connection_t *conn)
 {
   tor_assert(conn);
-  tor_assert(conn->type == CONN_TYPE_CONTROL);
 
-  if (STATE_IS_V0(conn->state))
+  if (STATE_IS_V0(conn->_base.state))
     return connection_control_process_inbuf_v0(conn);
   else
     return connection_control_process_inbuf_v1(conn);
@@ -2644,7 +2655,7 @@
  * <b>conn</b>, and write it to <b>buf</b>.  Return 0 on success, -1 on
  * failure. */
 static int
-write_stream_target_to_buf(connection_t *conn, char *buf, size_t len)
+write_stream_target_to_buf(edge_connection_t *conn, char *buf, size_t len)
 {
   char buf2[256];
   if (conn->chosen_exit_name)
@@ -2663,12 +2674,11 @@
 /** Something has happened to the stream associated with AP connection
  * <b>conn</b>: tell any interested control connections. */
 int
-control_event_stream_status(connection_t *conn, stream_status_event_t tp)
+control_event_stream_status(edge_connection_t *conn, stream_status_event_t tp)
 {
   char *msg;
   size_t len;
   char buf[256];
-  tor_assert(conn->type == CONN_TYPE_AP);
   tor_assert(conn->socks_request);
 
   if (!EVENT_IS_INTERESTING(EVENT_STREAM_STATUS))
@@ -2679,7 +2689,7 @@
     len = strlen(buf);
     msg = tor_malloc(5+len+1);
     msg[0] = (uint8_t) tp;
-    set_uint32(msg+1, htonl(conn->global_identifier));
+    set_uint32(msg+1, htonl(conn->_base.global_identifier));
     strlcpy(msg+5, buf, len+1);
 
     send_control0_event(EVENT_STREAM_STATUS, (uint32_t)(5+len+1), msg);
@@ -2705,7 +2715,7 @@
     circ = circuit_get_by_edge_conn(conn);
     send_control1_event(EVENT_STREAM_STATUS,
                         "650 STREAM %lu %s %lu %s\r\n",
-                        (unsigned long)conn->global_identifier, status,
+                        (unsigned long)conn->_base.global_identifier, status,
                         circ?(unsigned long)circ->global_identifier : 0ul,
                         buf);
     /* XXX need to specify its intended exit, etc? */
@@ -2716,13 +2726,11 @@
 /** Something has happened to the OR connection <b>conn</b>: tell any
  * interested control connections. */
 int
-control_event_or_conn_status(connection_t *conn,or_conn_status_event_t tp)
+control_event_or_conn_status(or_connection_t *conn,or_conn_status_event_t tp)
 {
   char buf[HEX_DIGEST_LEN+3]; /* status, dollar, identity, NUL */
   size_t len;
 
-  tor_assert(conn->type == CONN_TYPE_OR);
-
   if (!EVENT_IS_INTERESTING(EVENT_OR_CONN_STATUS))
     return 0;
 
@@ -2739,7 +2747,7 @@
       strlcpy(name, conn->nickname, sizeof(name));
     else
       tor_snprintf(name, sizeof(name), "%s:%d",
-                   conn->address, conn->port);
+                   conn->_base.address, conn->_base.port);
     switch (tp)
       {
       case OR_CONN_EVENT_LAUNCHED: status = "LAUNCHED"; break;

Modified: tor/trunk/src/or/cpuworker.c
===================================================================
--- tor/trunk/src/or/cpuworker.c	2006-07-26 19:07:23 UTC (rev 6905)
+++ tor/trunk/src/or/cpuworker.c	2006-07-26 19:07:26 UTC (rev 6906)
@@ -137,7 +137,7 @@
   uint32_t addr;
   uint16_t port;
   uint16_t circ_id;
-  connection_t *p_conn;
+  or_connection_t *p_conn;
   circuit_t *circ;
 
   tor_assert(conn);
@@ -473,7 +473,8 @@
       log_info(LD_OR,"circ->p_conn gone. Failing circ.");
       return -1;
     }
-    tag_pack(tag, circ->p_conn->addr, circ->p_conn->port, circ->p_circ_id);
+    tag_pack(tag, circ->p_conn->_base.addr, circ->p_conn->_base.port,
+             circ->p_circ_id);
 
     cpuworker->state = CPUWORKER_STATE_BUSY_ONION;
     /* touch the lastwritten timestamp, since that's how we check to

Modified: tor/trunk/src/or/directory.c
===================================================================
--- tor/trunk/src/or/directory.c	2006-07-26 19:07:23 UTC (rev 6905)
+++ tor/trunk/src/or/directory.c	2006-07-26 19:07:26 UTC (rev 6906)
@@ -38,16 +38,16 @@
                            const char *payload, size_t payload_len);
 
 static void
-directory_send_command(connection_t *conn, const char *platform,
+directory_send_command(dir_connection_t *conn, const char *platform,
                        int purpose, const char *resource,
                        const char *payload, size_t payload_len);
-static int directory_handle_command(connection_t *conn);
+static int directory_handle_command(dir_connection_t *conn);
 static int body_is_plausible(const char *body, size_t body_len, int purpose);
 static int purpose_is_private(uint8_t purpose);
 static char *http_get_header(const char *headers, const char *which);
 static void http_set_address_origin(const char *headers, connection_t *conn);
-static void connection_dir_download_networkstatus_failed(connection_t *conn);
-static void connection_dir_download_routerdesc_failed(connection_t *conn);
+static void connection_dir_download_networkstatus_failed(dir_connection_t *conn);
+static void connection_dir_download_routerdesc_failed(dir_connection_t *conn);
 static void dir_networkstatus_download_failed(smartlist_t *failed);
 static void dir_routerdesc_download_failed(smartlist_t *failed);
 static void note_request(const char *key, size_t bytes);
@@ -261,24 +261,24 @@
  * directory server: Mark the router as down and try again if possible.
  */
 void
-connection_dir_request_failed(connection_t *conn)
+connection_dir_request_failed(dir_connection_t *conn)
 {
   if (router_digest_is_me(conn->identity_digest))
     return; /* this was a test fetch. don't retry. */
   router_set_status(conn->identity_digest, 0); /* don't try him again */
-  if (conn->purpose == DIR_PURPOSE_FETCH_DIR ||
-      conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
+  if (conn->_base.purpose == DIR_PURPOSE_FETCH_DIR ||
+      conn->_base.purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
     log_info(LD_DIR, "Giving up on directory server at '%s:%d'; retrying",
-             conn->address, conn->port);
-    directory_get_from_dirserver(conn->purpose, NULL,
+             conn->_base.address, conn->_base.port);
+    directory_get_from_dirserver(conn->_base.purpose, NULL,
                                  0 /* don't retry_if_no_servers */);
-  } else if (conn->purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS) {
+  } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS) {
     log_info(LD_DIR, "Giving up on directory server at '%s'; retrying",
-             conn->address);
+             conn->_base.address);
     connection_dir_download_networkstatus_failed(conn);
-  } else if (conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC) {
+  } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC) {
     log_info(LD_DIR, "Giving up on directory server at '%s'; retrying",
-             conn->address);
+             conn->_base.address);
     connection_dir_download_routerdesc_failed(conn);
   }
 }
@@ -288,7 +288,7 @@
  * retry the fetch now, later, or never.
  */
 static void
-connection_dir_download_networkstatus_failed(connection_t *conn)
+connection_dir_download_networkstatus_failed(dir_connection_t *conn)
 {
   if (!conn->requested_resource) {
     /* We never reached directory_send_command, which means that we never
@@ -301,7 +301,7 @@
     smartlist_t *trusted_dirs = router_get_trusted_dir_servers();
     SMARTLIST_FOREACH(trusted_dirs, trusted_dir_server_t *, ds,
                       ++ds->n_networkstatus_failures);
-    directory_get_from_dirserver(conn->purpose, "all.z",
+    directory_get_from_dirserver(conn->_base.purpose, "all.z",
                                  0 /* don't retry_if_no_servers */);
   } else if (!strcmpstart(conn->requested_resource, "fp/")) {
     /* We were trying to download by fingerprint; mark them all as having
@@ -321,7 +321,7 @@
  * on connection <b>conn</b> failed.
  */
 static void
-connection_dir_download_routerdesc_failed(connection_t *conn)
+connection_dir_download_routerdesc_failed(dir_connection_t *conn)
 {
   /* Try again. No need to increment the failure count for routerdescs, since
    * it's not their fault.*/
@@ -342,7 +342,7 @@
                            int private_connection, const char *resource,
                            const char *payload, size_t payload_len)
 {
-  connection_t *conn;
+  dir_connection_t *conn;
 
   tor_assert(address);
   tor_assert(addr);
@@ -376,18 +376,18 @@
       tor_assert(0);
   }
 
-  conn = connection_new(CONN_TYPE_DIR);
+  conn = TO_DIR_CONN(connection_new(CONN_TYPE_DIR));
 
   /* set up conn so it's got all the data we need to remember */
-  conn->addr = addr;
-  conn->port = dir_port;
-  conn->address = tor_strdup(address);
+  conn->_base.addr = addr;
+  conn->_base.port = dir_port;
+  conn->_base.address = tor_strdup(address);
   memcpy(conn->identity_digest, digest, DIGEST_LEN);
 
-  conn->purpose = purpose;
+  conn->_base.purpose = purpose;
 
   /* give it an initial state */
-  conn->state = DIR_CONN_STATE_CONNECTING;
+  conn->_base.state = DIR_CONN_STATE_CONNECTING;
   conn->dirconn_direct = (private_connection == 0);
 
   if (!private_connection) {
@@ -398,19 +398,19 @@
       dir_port = get_options()->HttpProxyPort;
     }
 
-    switch (connection_connect(conn, conn->address, addr, dir_port)) {
+    switch (connection_connect(TO_CONN(conn), conn->_base.address, addr, dir_port)) {
       case -1:
         connection_dir_request_failed(conn); /* retry if we want */
-        connection_free(conn);
+        connection_free(TO_CONN(conn));
         return;
       case 1:
-        conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
+        conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
         /* fall through */
       case 0:
         /* queue the command on the outbuf */
         directory_send_command(conn, platform, purpose, resource,
                                payload, payload_len);
-        connection_watch_events(conn, EV_READ | EV_WRITE);
+        connection_watch_events(TO_CONN(conn), EV_READ | EV_WRITE);
         /* writable indicates finish, readable indicates broken link,
            error indicates broken link in windowsland. */
     }
@@ -419,23 +419,24 @@
      * populate it and add it at the right state
      * socketpair and hook up both sides
      */
-    conn->s = connection_ap_make_bridge(conn->address, conn->port);
-    if (conn->s < 0) {
+    conn->_base.s = connection_ap_make_bridge(conn->_base.address,
+                                              conn->_base.port);
+    if (conn->_base.s < 0) {
       log_warn(LD_NET,"Making AP bridge to dirserver failed.");
-      connection_mark_for_close(conn);
+      connection_mark_for_close(TO_CONN(conn));
       return;
     }
 
-    if (connection_add(conn) < 0) {
+    if (connection_add(TO_CONN(conn)) < 0) {
       log_warn(LD_NET,"Unable to add AP bridge to dirserver.");
-      connection_mark_for_close(conn);
+      connection_mark_for_close(TO_CONN(conn));
       return;
     }
-    conn->state = DIR_CONN_STATE_CLIENT_SENDING;
+    conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING;
     /* queue the command on the outbuf */
     directory_send_command(conn, platform, purpose, resource,
                            payload, payload_len);
-    connection_watch_events(conn, EV_READ | EV_WRITE);
+    connection_watch_events(TO_CONN(conn), EV_READ | EV_WRITE);
   }
 }
 
@@ -443,7 +444,7 @@
  * are as in directory_initiate_command.
  */
 static void
-directory_send_command(connection_t *conn, const char *platform,
+directory_send_command(dir_connection_t *conn, const char *platform,
                        int purpose, const char *resource,
                        const char *payload, size_t payload_len)
 {
@@ -456,18 +457,18 @@
   size_t len;
 
   tor_assert(conn);
-  tor_assert(conn->type == CONN_TYPE_DIR);
+  tor_assert(conn->_base.type == CONN_TYPE_DIR);
 
   tor_free(conn->requested_resource);
   if (resource)
     conn->requested_resource = tor_strdup(resource);
 
   /* come up with a string for which Host: we want */
-  if (conn->port == 80) {
-    strlcpy(hoststring, conn->address, sizeof(hoststring));
+  if (conn->_base.port == 80) {
+    strlcpy(hoststring, conn->_base.address, sizeof(hoststring));
   } else {
     tor_snprintf(hoststring, sizeof(hoststring),"%s:%d",
-                 conn->address, conn->port);
+                 conn->_base.address, conn->_base.port);
   }
 
   /* come up with some proxy lines, if we're using one. */
@@ -564,8 +565,8 @@
   }
 
   tor_snprintf(request, sizeof(request), "%s %s", httpcommand, proxystring);
-  connection_write_to_buf(request, strlen(request), conn);
-  connection_write_to_buf(url, strlen(url), conn);
+  connection_write_to_buf(request, strlen(request), TO_CONN(conn));
+  connection_write_to_buf(url, strlen(url), TO_CONN(conn));
   tor_free(url);
 
   if (!strcmp(httpcommand, "GET") && !payload) {
@@ -580,11 +581,11 @@
                  hoststring,
                  proxyauthstring);
   }
-  connection_write_to_buf(request, strlen(request), conn);
+  connection_write_to_buf(request, strlen(request), TO_CONN(conn));
 
   if (payload) {
     /* then send the payload afterwards too */
-    connection_write_to_buf(payload, payload_len, conn);
+    connection_write_to_buf(payload, payload_len, TO_CONN(conn));
   }
 }
 
@@ -804,7 +805,7 @@
  * The caller will take care of marking the connection for close.
  */
 static int
-connection_dir_client_reached_eof(connection_t *conn)
+connection_dir_client_reached_eof(dir_connection_t *conn)
 {
   char *body;
   char *headers;
@@ -816,17 +817,17 @@
   int compression;
   int plausible;
   int skewed=0;
-  int allow_partial = conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC;
+  int allow_partial = conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC;
   int was_compressed=0;
 
-  switch (fetch_from_buf_http(conn->inbuf,
+  switch (fetch_from_buf_http(conn->_base.inbuf,
                               &headers, MAX_HEADERS_SIZE,
                               &body, &body_len, MAX_DIR_SIZE,
                               allow_partial)) {
     case -1: /* overflow */
       log_warn(LD_PROTOCOL,
                "'fetch' response too large (server '%s:%d'). Closing.",
-               conn->address, conn->port);
+               conn->_base.address, conn->_base.port);
       return -1;
     case 0:
       log_info(LD_HTTP,
@@ -839,7 +840,7 @@
   if (parse_http_response(headers, &status_code, &date_header,
                           &compression, &reason) < 0) {
     log_warn(LD_HTTP,"Unparseable headers (server '%s:%d'). Closing.",
-             conn->address, conn->port);
+             conn->_base.address, conn->_base.port);
     tor_free(body); tor_free(headers);
     return -1;
   }
@@ -847,7 +848,7 @@
 
   log_debug(LD_DIR,
             "Received response from directory server '%s:%d': %d %s",
-            conn->address, conn->port, status_code, escaped(reason));
+            conn->_base.address, conn->_base.port, status_code, escaped(reason));
 
   /* now check if it's got any hints for us about our IP address. */
   if (server_mode(get_options())) {
@@ -867,7 +868,7 @@
              LD_HTTP,
              "Received directory with skewed time (server '%s:%d'): "
              "we are %d minutes %s, or the directory is %d minutes %s.",
-             conn->address, conn->port,
+             conn->_base.address, conn->_base.port,
              abs(delta)/60, delta>0 ? "ahead" : "behind",
              abs(delta)/60, delta>0 ? "behind" : "ahead");
       skewed = 1; /* don't check the recommended-versions line */
@@ -880,12 +881,12 @@
   if (status_code == 503) {
     log_info(LD_DIR,"Received http status code %d (%s) from server "
              "'%s:%d'. I'll try again soon.",
-             status_code, escaped(reason), conn->address, conn->port);
+             status_code, escaped(reason), conn->_base.address, conn->_base.port);
     tor_free(body); tor_free(headers); tor_free(reason);
     return -1;
   }
 
-  plausible = body_is_plausible(body, body_len, conn->purpose);
+  plausible = body_is_plausible(body, body_len, conn->_base.purpose);
   if (compression || !plausible) {
     char *new_body = NULL;
     size_t new_len = 0;
@@ -912,7 +913,7 @@
 
       log_info(LD_HTTP, "HTTP body from server '%s:%d' was labeled %s, "
                "but it seems to be %s.%s",
-               conn->address, conn->port, description1, description2,
+               conn->_base.address, conn->_base.port, description1, description2,
                (compression>0 && guessed>0)?"  Trying both.":"");
     }
     /* Try declared compression first if we can. */
@@ -929,7 +930,7 @@
     if (!plausible && !new_body) {
       log_fn(LOG_PROTOCOL_WARN, LD_HTTP,
              "Unable to decompress HTTP body (server '%s:%d').",
-             conn->address, conn->port);
+             conn->_base.address, conn->_base.port);
       tor_free(body); tor_free(headers); tor_free(reason);
       return -1;
     }
@@ -941,38 +942,38 @@
     }
   }
 
-  if (conn->purpose == DIR_PURPOSE_FETCH_DIR) {
+  if (conn->_base.purpose == DIR_PURPOSE_FETCH_DIR) {
     /* fetch/process the directory to cache it. */
     log_info(LD_DIR,"Received directory (size %d) from server '%s:%d'",
-             (int)body_len, conn->address, conn->port);
+             (int)body_len, conn->_base.address, conn->_base.port);
     if (status_code != 200) {
       log_warn(LD_DIR,"Received http status code %d (%s) from server "
                "'%s:%d'. I'll try again soon.",
-               status_code, escaped(reason), conn->address, conn->port);
+               status_code, escaped(reason), conn->_base.address, conn->_base.port);
       tor_free(body); tor_free(headers); tor_free(reason);
       return -1;
     }
     if (router_parse_directory(body) < 0) {
       log_notice(LD_DIR,"I failed to parse the directory I fetched from "
-                 "'%s:%d'. Ignoring.", conn->address, conn->port);
+                 "'%s:%d'. Ignoring.", conn->_base.address, conn->_base.port);
     }
     note_request(was_compressed?"dl/dir.z":"dl/dir", orig_len);
   }
 
-  if (conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
+  if (conn->_base.purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
     /* just update our list of running routers, if this list is new info */
     log_info(LD_DIR,"Received running-routers list (size %d)", (int)body_len);
     if (status_code != 200) {
       log_warn(LD_DIR,"Received http status code %d (%s) from server "
                "'%s:%d'. I'll try again soon.",
-               status_code, escaped(reason), conn->address, conn->port);
+               status_code, escaped(reason), conn->_base.address, conn->_base.port);
       tor_free(body); tor_free(headers); tor_free(reason);
       return -1;
     }
     if (router_parse_runningrouters(body)<0) {
       log_warn(LD_DIR,
                "Bad running-routers from server '%s:%d'. I'll try again soon.",
-               conn->address, conn->port);
+               conn->_base.address, conn->_base.port);
       tor_free(body); tor_free(headers); tor_free(reason);
       return -1;
     }
@@ -980,16 +981,16 @@
                  "dl/running-routers", orig_len);
   }
 
-  if (conn->purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS) {
+  if (conn->_base.purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS) {
     smartlist_t *which = NULL;
     char *cp;
     log_info(LD_DIR,"Received networkstatus objects (size %d) from server "
-             "'%s:%d'",(int) body_len, conn->address, conn->port);
+             "'%s:%d'",(int) body_len, conn->_base.address, conn->_base.port);
     if (status_code != 200) {
       log_warn(LD_DIR,
            "Received http status code %d (%s) from server "
            "'%s:%d' while fetching \"/tor/status/%s\". I'll try again soon.",
-           status_code, escaped(reason), conn->address, conn->port,
+           status_code, escaped(reason), conn->_base.address, conn->_base.port,
            conn->requested_resource);
       tor_free(body); tor_free(headers); tor_free(reason);
       connection_dir_download_networkstatus_failed(conn);
@@ -1038,11 +1039,11 @@
     }
   }
 
-  if (conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC) {
+  if (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC) {
     smartlist_t *which = NULL;
     int n_asked_for = 0;
     log_info(LD_DIR,"Received server info (size %d) from server '%s:%d'",
-             (int)body_len, conn->address, conn->port);
+             (int)body_len, conn->_base.address, conn->_base.port);
     note_request(was_compressed?"dl/server.z":"dl/server", orig_len);
     if (conn->requested_resource &&
         !strcmpstart(conn->requested_resource,"d/")) {
@@ -1059,7 +1060,7 @@
       log_fn(dir_okay ? LOG_INFO : LOG_WARN, LD_DIR,
              "Received http status code %d (%s) from server '%s:%d' "
              "while fetching \"/tor/server/%s\". I'll try again soon.",
-             status_code, escaped(reason), conn->address, conn->port,
+             status_code, escaped(reason), conn->_base.address, conn->_base.port,
              conn->requested_resource);
       if (!which) {
         connection_dir_download_routerdesc_failed(conn);
@@ -1085,7 +1086,7 @@
     if (which) { /* mark remaining ones as failed */
       log_info(LD_DIR, "Received %d/%d routers requested from %s:%d",
                n_asked_for-smartlist_len(which), n_asked_for,
-               conn->address, (int)conn->port);
+               conn->_base.address, (int)conn->_base.port);
       if (smartlist_len(which)) {
         dir_routerdesc_download_failed(which);
       }
@@ -1098,13 +1099,13 @@
       routerinfo_t *me = router_get_my_routerinfo();
       if (me &&
           router_digest_is_me(conn->identity_digest) &&
-          me->addr == conn->addr &&
-          me->dir_port == conn->port)
+          me->addr == conn->_base.addr &&
+          me->dir_port == conn->_base.port)
         router_dirport_found_reachable();
     }
   }
 
-  if (conn->purpose == DIR_PURPOSE_UPLOAD_DIR) {
+  if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_DIR) {
     switch (status_code) {
       case 200:
         log_info(LD_GENERAL,"eof (status 200) after uploading server "
@@ -1113,7 +1114,7 @@
       case 400:
         log_warn(LD_GENERAL,"http status 400 (%s) response from "
                  "dirserver '%s:%d'. Please correct.",
-                 escaped(reason), conn->address, conn->port);
+                 escaped(reason), conn->_base.address, conn->_base.port);
         break;
       case 403:
         log_warn(LD_GENERAL,
@@ -1121,19 +1122,19 @@
              "'%s:%d'. Is your clock skewed? Have you mailed us your key "
              "fingerprint? Are you using the right key? Are you using a "
              "private IP address? See http://tor.eff.org/doc/";
-             "tor-doc-server.html",escaped(reason), conn->address, conn->port);
+             "tor-doc-server.html",escaped(reason), conn->_base.address, conn->_base.port);
         break;
       default:
         log_warn(LD_GENERAL,
              "http status %d (%s) reason unexpected (server '%s:%d').",
-             status_code, escaped(reason), conn->address, conn->port);
+             status_code, escaped(reason), conn->_base.address, conn->_base.port);
         break;
     }
     /* return 0 in all cases, since we don't want to mark any
      * dirservers down just because they don't like us. */
   }
 
-  if (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC) {
+  if (conn->_base.purpose == DIR_PURPOSE_FETCH_RENDDESC) {
     log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d "
              "(%s))",
              (int)body_len, status_code, escaped(reason));
@@ -1145,7 +1146,7 @@
            * cleans it up */
         } else {
           /* success. notify pending connections about this. */
-          conn->purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
+          conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
           rend_client_desc_here(conn->rend_query);
         }
         break;
@@ -1161,12 +1162,12 @@
       default:
         log_warn(LD_REND,"http status %d (%s) response unexpected (server "
                  "'%s:%d').",
-                 status_code, escaped(reason), conn->address, conn->port);
+                 status_code, escaped(reason), conn->_base.address, conn->_base.port);
         break;
     }
   }
 
-  if (conn->purpose == DIR_PURPOSE_UPLOAD_RENDDESC) {
+  if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_RENDDESC) {
     switch (status_code) {
       case 200:
         log_info(LD_REND,
@@ -1176,12 +1177,12 @@
       case 400:
         log_warn(LD_REND,"http status 400 (%s) response from dirserver "
                  "'%s:%d'. Malformed rendezvous descriptor?",
-                 escaped(reason), conn->address, conn->port);
+                 escaped(reason), conn->_base.address, conn->_base.port);
         break;
       default:
         log_warn(LD_REND,"http status %d (%s) response unexpected (server "
                  "'%s:%d').",
-                 status_code, escaped(reason), conn->address, conn->port);
+                 status_code, escaped(reason), conn->_base.address, conn->_base.port);
         break;
     }
   }
@@ -1191,20 +1192,20 @@
 
 /** Called when a directory connection reaches EOF */
 int
-connection_dir_reached_eof(connection_t *conn)
+connection_dir_reached_eof(dir_connection_t *conn)
 {
   int retval;
-  if (conn->state != DIR_CONN_STATE_CLIENT_READING) {
+  if (conn->_base.state != DIR_CONN_STATE_CLIENT_READING) {
     log_info(LD_HTTP,"conn reached eof, not reading. Closing.");
-    connection_close_immediate(conn); /* error: give up on flushing */
-    connection_mark_for_close(conn);
+    connection_close_immediate(TO_CONN(conn)); /* error: give up on flushing */
+    connection_mark_for_close(TO_CONN(conn));
     return -1;
   }
 
   retval = connection_dir_client_reached_eof(conn);
   if (retval == 0) /* success */
-    conn->state = DIR_CONN_STATE_CLIENT_FINISHED;
-  connection_mark_for_close(conn);
+    conn->_base.state = DIR_CONN_STATE_CLIENT_FINISHED;
+  connection_mark_for_close(TO_CONN(conn));
   return retval;
 }
 
@@ -1212,10 +1213,10 @@
  * directory servers and connections <em>at</em> directory servers.)
  */
 int
-connection_dir_process_inbuf(connection_t *conn)
+connection_dir_process_inbuf(dir_connection_t *conn)
 {
   tor_assert(conn);
-  tor_assert(conn->type == CONN_TYPE_DIR);
+  tor_assert(conn->_base.type == CONN_TYPE_DIR);
 
   /* Directory clients write, then read data until they receive EOF;
    * directory servers read data until they get an HTTP command, then
@@ -1224,9 +1225,9 @@
    */
 
   /* If we're on the dirserver side, look for a command. */
-  if (conn->state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
+  if (conn->_base.state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
     if (directory_handle_command(conn) < 0) {
-      connection_mark_for_close(conn);
+      connection_mark_for_close(TO_CONN(conn));
       return -1;
     }
     return 0;
@@ -1234,7 +1235,7 @@
 
   /* XXX for READ states, might want to make sure inbuf isn't too big */
 
-  if (!conn->inbuf_reached_eof)
+  if (!conn->_base.inbuf_reached_eof)
     log_debug(LD_HTTP,"Got data, not eof. Leaving on inbuf.");
   return 0;
 }
@@ -1243,7 +1244,7 @@
  * <b>status</b> and <b>reason_phrase</b>. Write it to <b>conn</b>.
  */
 static void
-write_http_status_line(connection_t *conn, int status,
+write_http_status_line(dir_connection_t *conn, int status,
                        const char *reason_phrase)
 {
   char buf[256];
@@ -1252,12 +1253,12 @@
     log_warn(LD_BUG,"Bug: status line too long.");
     return;
   }
-  connection_write_to_buf(buf, strlen(buf), conn);
+  connection_write_to_buf(buf, strlen(buf), TO_CONN(conn));
 }
 
 /** DOCDOC */
 static void
-write_http_response_header(connection_t *conn, ssize_t length,
+write_http_response_header(dir_connection_t *conn, ssize_t length,
                            const char *type, const char *encoding)
 {
   char date[RFC1123_TIME_LEN+1];
@@ -1272,7 +1273,7 @@
   tor_snprintf(cp, sizeof(tmp),
                "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Type: %s\r\n"
                X_ADDRESS_HEADER "%s\r\n",
-               date, type, conn->address);
+               date, type, conn->_base.address);
   cp += strlen(tmp);
   if (encoding) {
     tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
@@ -1288,7 +1289,7 @@
     memcpy(cp, "\r\n", 3);
   else
     tor_assert(0);
-  connection_write_to_buf(tmp, strlen(tmp), conn);
+  connection_write_to_buf(tmp, strlen(tmp), TO_CONN(conn));
 }
 
 /** Helper function: return 1 if there are any dir conns of purpose
@@ -1308,7 +1309,7 @@
     if (conn->type == CONN_TYPE_DIR &&
         conn->purpose == purpose &&
         !conn->marked_for_close &&
-        !router_digest_is_me(conn->identity_digest))
+        !router_digest_is_me(TO_DIR_CONN(conn)->identity_digest))
       return 1;
   }
   return 0;
@@ -1389,7 +1390,7 @@
  * conn-\>outbuf.  If the request is unrecognized, send a 400.
  * Always return 0. */
 static int
-directory_handle_command_get(connection_t *conn, char *headers,
+directory_handle_command_get(dir_connection_t *conn, char *headers,
                              char *body, size_t body_len)
 {
   size_t dlen;
@@ -1401,7 +1402,7 @@
 
   log_debug(LD_DIRSERV,"Received GET command.");
 
-  conn->state = DIR_CONN_STATE_SERVER_WRITING;
+  conn->_base.state = DIR_CONN_STATE_SERVER_WRITING;
 
   if (parse_http_url(headers, &url) < 0) {
     write_http_status_line(conn, 400, "Bad request");
@@ -1471,7 +1472,7 @@
     write_http_response_header(conn, dlen,
                  deflated?"application/octet-stream":"text/plain",
                  deflated?"deflate":"identity");
-    connection_write_to_buf(cp, strlen(cp), conn);
+    connection_write_to_buf(cp, strlen(cp), TO_CONN(conn));
     return 0;
   }
 
@@ -1583,7 +1584,7 @@
                                    NULL);
         note_request("/tor/rendezvous?/", desc_len);
         /* need to send descp separately, because it may include nuls */
-        connection_write_to_buf(descp, desc_len, conn);
+        connection_write_to_buf(descp, desc_len, TO_CONN(conn));
         break;
       case 0: /* well-formed but not present */
         write_http_status_line(conn, 404, "Not found");
@@ -1600,7 +1601,7 @@
     char *bytes = directory_dump_request_log();
     size_t len = strlen(bytes);
     write_http_response_header(conn, len, "text/plain", NULL);
-    connection_write_to_buf(bytes, len, conn);
+    connection_write_to_buf(bytes, len, TO_CONN(conn));
     tor_free(bytes);
     tor_free(url);
     return 0;
@@ -1611,12 +1612,12 @@
     char robots[] = "User-agent: *\r\nDisallow: /\r\n";
     size_t len = strlen(robots);
     write_http_response_header(conn, len, "text/plain", NULL);
-    connection_write_to_buf(robots, len, conn);
+    connection_write_to_buf(robots, len, TO_CONN(conn));
     tor_free(url);
     return 0;
   }
 
-  if (!strcmp(url,"/tor/dir-all-weaselhack") && (conn->addr == 0x7f000001ul) &&
+  if (!strcmp(url,"/tor/dir-all-weaselhack") && (conn->_base.addr == 0x7f000001ul) &&
       authdir_mode(get_options())) {
     /* XXX until weasel rewrites his scripts  XXXX012 */
     char *new_directory=NULL;
@@ -1633,7 +1634,7 @@
 
     write_http_response_header(conn, dlen, "text/plain", "identity");
 
-    connection_write_to_buf(new_directory, dlen, conn);
+    connection_write_to_buf(new_directory, dlen, TO_CONN(conn));
     tor_free(new_directory);
     tor_free(url);
     return 0;
@@ -1651,14 +1652,14 @@
  * response into conn-\>outbuf.  If the request is unrecognized, send a
  * 400.  Always return 0. */
 static int
-directory_handle_command_post(connection_t *conn, char *headers,
+directory_handle_command_post(dir_connection_t *conn, char *headers,
                               char *body, size_t body_len)
 {
   char *url = NULL;
 
   log_debug(LD_DIRSERV,"Received POST command.");
 
-  conn->state = DIR_CONN_STATE_SERVER_WRITING;
+  conn->_base.state = DIR_CONN_STATE_SERVER_WRITING;
 
   if (!authdir_mode(get_options())) {
     /* we just provide cached directories; we don't want to
@@ -1685,7 +1686,7 @@
       case -1:
       case 1:
         log_notice(LD_DIRSERV,"Rejected router descriptor from %s.",
-                   conn->address);
+                   conn->_base.address);
         /* malformed descriptor, or something wrong */
         write_http_status_line(conn, 400, msg);
         break;
@@ -1703,7 +1704,7 @@
 //      char tmp[1024*2+1];
       log_fn(LOG_PROTOCOL_WARN, LD_DIRSERV,
              "Rejected rend descriptor (length %d) from %s.",
-             (int)body_len, conn->address);
+             (int)body_len, conn->_base.address);
 #if 0
       if (body_len <= 1024) {
         base16_encode(tmp, sizeof(tmp), body, body_len);
@@ -1731,21 +1732,21 @@
  * buffer.  Return a 0 on success, or -1 on error.
  */
 static int
-directory_handle_command(connection_t *conn)
+directory_handle_command(dir_connection_t *conn)
 {
   char *headers=NULL, *body=NULL;
   size_t body_len=0;
   int r;
 
   tor_assert(conn);
-  tor_assert(conn->type == CONN_TYPE_DIR);
+  tor_assert(conn->_base.type == CONN_TYPE_DIR);
 
-  switch (fetch_from_buf_http(conn->inbuf,
+  switch (fetch_from_buf_http(conn->_base.inbuf,
                               &headers, MAX_HEADERS_SIZE,
                               &body, &body_len, MAX_BODY_SIZE, 0)) {
     case -1: /* overflow */
       log_warn(LD_DIRSERV,
-               "Invalid input from address '%s'. Closing.", conn->address);
+               "Invalid input from address '%s'. Closing.", conn->_base.address);
       return -1;
     case 0:
       log_debug(LD_DIRSERV,"command not all here yet.");
@@ -1753,7 +1754,7 @@
     /* case 1, fall through */
   }
 
-  http_set_address_origin(headers, conn);
+  http_set_address_origin(headers, TO_CONN(conn));
   //log_debug(LD_DIRSERV,"headers %s, body %s.", headers, body);
 
   if (!strncasecmp(headers,"GET",3))
@@ -1776,23 +1777,23 @@
  * appropriate.
  */
 int
-connection_dir_finished_flushing(connection_t *conn)
+connection_dir_finished_flushing(dir_connection_t *conn)
 {
   tor_assert(conn);
-  tor_assert(conn->type == CONN_TYPE_DIR);
+  tor_assert(conn->_base.type == CONN_TYPE_DIR);
 
-  switch (conn->state) {
+  switch (conn->_base.state) {
     case DIR_CONN_STATE_CLIENT_SENDING:
       log_debug(LD_DIR,"client finished sending command.");
-      conn->state = DIR_CONN_STATE_CLIENT_READING;
-      connection_stop_writing(conn);
+      conn->_base.state = DIR_CONN_STATE_CLIENT_READING;
+      connection_stop_writing(TO_CONN(conn));
       return 0;
     case DIR_CONN_STATE_SERVER_WRITING:
       log_debug(LD_DIRSERV,"Finished writing server response. Closing.");
-      connection_mark_for_close(conn);
+      connection_mark_for_close(TO_CONN(conn));
       return 0;
     default:
-      log_warn(LD_BUG,"Bug: called in unexpected state %d.", conn->state);
+      log_warn(LD_BUG,"Bug: called in unexpected state %d.", conn->_base.state);
       tor_fragile_assert();
       return -1;
   }
@@ -1802,16 +1803,16 @@
 /** Connected handler for directory connections: begin sending data to the
  * server */
 int
-connection_dir_finished_connecting(connection_t *conn)
+connection_dir_finished_connecting(dir_connection_t *conn)
 {
   tor_assert(conn);
-  tor_assert(conn->type == CONN_TYPE_DIR);
-  tor_assert(conn->state == DIR_CONN_STATE_CONNECTING);
+  tor_assert(conn->_base.type == CONN_TYPE_DIR);
+  tor_assert(conn->_base.state == DIR_CONN_STATE_CONNECTING);
 
   log_debug(LD_HTTP,"Dir connection to router %s:%u established.",
-            conn->address,conn->port);
+            conn->_base.address,conn->_base.port);
 
-  conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
+  conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
   return 0;
 }
 

Modified: tor/trunk/src/or/dirserv.c
===================================================================
--- tor/trunk/src/or/dirserv.c	2006-07-26 19:07:23 UTC (rev 6905)
+++ tor/trunk/src/or/dirserv.c	2006-07-26 19:07:26 UTC (rev 6906)
@@ -1825,7 +1825,7 @@
 #define DIRSERV_BUFFER_MIN 16384
 
 static int
-connection_dirserv_finish_spooling(connection_t *conn)
+connection_dirserv_finish_spooling(dir_connection_t *conn)
 {
   if (conn->zlib_state) {
     connection_write_to_buf_zlib(conn, conn->zlib_state, "", 0, 1);
@@ -1838,12 +1838,12 @@
 
 /** DOCDOC */
 static int
-connection_dirserv_add_servers_to_outbuf(connection_t *conn)
+connection_dirserv_add_servers_to_outbuf(dir_connection_t *conn)
 {
   int by_fp = conn->dir_spool_src == DIR_SPOOL_SERVER_BY_FP;
 
   while (smartlist_len(conn->fingerprint_stack) &&
-         buf_datalen(conn->outbuf) < DIRSERV_BUFFER_MIN) {
+         buf_datalen(conn->_base.outbuf) < DIRSERV_BUFFER_MIN) {
     const char *body;
     char *fp = smartlist_pop_last(conn->fingerprint_stack);
     signed_descriptor_t *sd = NULL;
@@ -1875,7 +1875,7 @@
     } else {
       connection_write_to_buf(body,
                               sd->signed_descriptor_len,
-                              conn);
+                              TO_CONN(conn));
     }
   }
 
@@ -1890,11 +1890,11 @@
 
 /** DOCDOC */
 static int
-connection_dirserv_add_dir_bytes_to_outbuf(connection_t *conn)
+connection_dirserv_add_dir_bytes_to_outbuf(dir_connection_t *conn)
 {
   int bytes, remaining;
 
-  bytes = DIRSERV_BUFFER_MIN - buf_datalen(conn->outbuf);
+  bytes = DIRSERV_BUFFER_MIN - buf_datalen(conn->_base.outbuf);
   tor_assert(bytes > 0);
   tor_assert(conn->cached_dir);
   if (bytes < 8192)
@@ -1909,7 +1909,7 @@
                              bytes, bytes == remaining);
   } else {
     connection_write_to_buf(conn->cached_dir->dir_z + conn->cached_dir_offset,
-                            bytes, conn);
+                            bytes, TO_CONN(conn));
   }
   conn->cached_dir_offset += bytes;
   if (conn->cached_dir_offset == (int)conn->cached_dir->dir_z_len) {
@@ -1923,10 +1923,10 @@
 
 /* DOCDOC */
 static int
-connection_dirserv_add_networkstatus_bytes_to_outbuf(connection_t *conn)
+connection_dirserv_add_networkstatus_bytes_to_outbuf(dir_connection_t *conn)
 {
 
-  while (buf_datalen(conn->outbuf) < DIRSERV_BUFFER_MIN) {
+  while (buf_datalen(conn->_base.outbuf) < DIRSERV_BUFFER_MIN) {
     if (conn->cached_dir) {
       int uncompressing = (conn->zlib_state != NULL);
       int r = connection_dirserv_add_dir_bytes_to_outbuf(conn);
@@ -1973,13 +1973,12 @@
 /** Called whenever we have flushed some directory data in state
  * SERVER_WRITING. */
 int
-connection_dirserv_flushed_some(connection_t *conn)
+connection_dirserv_flushed_some(dir_connection_t *conn)
 {
-  tor_assert(conn->type == CONN_TYPE_DIR);
-  tor_assert(conn->state == DIR_CONN_STATE_SERVER_WRITING);
+  tor_assert(conn->_base.state == DIR_CONN_STATE_SERVER_WRITING);
 
   if (conn->dir_spool_src == DIR_SPOOL_NONE
-      || buf_datalen(conn->outbuf) >= DIRSERV_BUFFER_MIN)
+      || buf_datalen(conn->_base.outbuf) >= DIRSERV_BUFFER_MIN)
     return 0;
 
   switch (conn->dir_spool_src) {

Modified: tor/trunk/src/or/dns.c
===================================================================
--- tor/trunk/src/or/dns.c	2006-07-26 19:07:23 UTC (rev 6905)
+++ tor/trunk/src/or/dns.c	2006-07-26 19:07:26 UTC (rev 6906)
@@ -53,7 +53,7 @@
 
 /** Linked list of connections waiting for a DNS answer. */
 typedef struct pending_connection_t {
-  connection_t *conn;
+  edge_connection_t *conn;
   struct pending_connection_t *next;
 } pending_connection_t;
 
@@ -83,8 +83,8 @@
 static void dns_purge_resolve(cached_resolve_t *resolve);
 static void dns_found_answer(const char *address, uint32_t addr, char outcome,
                              uint32_t ttl);
-static void send_resolved_cell(connection_t *conn, uint8_t answer_type);
-static int assign_to_dnsworker(connection_t *exitconn);
+static void send_resolved_cell(edge_connection_t *conn, uint8_t answer_type);
+static int assign_to_dnsworker(edge_connection_t *exitconn);
 #ifndef USE_EVENTDNS
 static int dnsworker_main(void *data);
 static int spawn_dnsworker(void);
@@ -226,7 +226,7 @@
 {
   cached_resolve_t *resolve;
   pending_connection_t *pend;
-  connection_t *pendconn;
+  edge_connection_t *pendconn;
 
   /* this is fast because the linked list
    * oldest_cached_resolve is ordered by when they came in.
@@ -251,12 +251,12 @@
         pend = resolve->pending_connections;
         resolve->pending_connections = pend->next;
         /* Connections should only be pending if they have no socket. */
-        tor_assert(pend->conn->s == -1);
+        tor_assert(pend->conn->_base.s == -1);
         pendconn = pend->conn;
         connection_edge_end(pendconn, END_STREAM_REASON_TIMEOUT,
                             pendconn->cpath_layer);
         circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
-        connection_free(pendconn);
+        connection_free(TO_CONN(pendconn));
         tor_free(pend);
       }
     }
@@ -273,7 +273,7 @@
 /** Send a response to the RESOVLE request of a connection. answer_type must
  *  be one of RESOLVED_TYPE_(IPV4|ERROR|ERROR_TRANSIENT) */
 static void
-send_resolved_cell(connection_t *conn, uint8_t answer_type)
+send_resolved_cell(edge_connection_t *conn, uint8_t answer_type)
 {
   char buf[RELAY_PAYLOAD_SIZE];
   size_t buflen;
@@ -286,7 +286,7 @@
     {
     case RESOLVED_TYPE_IPV4:
       buf[1] = 4;
-      set_uint32(buf+2, htonl(conn->addr));
+      set_uint32(buf+2, htonl(conn->_base.addr));
       set_uint32(buf+6, htonl(ttl));
       buflen = 10;
       break;
@@ -337,7 +337,7 @@
  * dns farm, and return 0.
  */
 int
-dns_resolve(connection_t *exitconn)
+dns_resolve(edge_connection_t *exitconn)
 {
   cached_resolve_t *resolve;
   cached_resolve_t search;
@@ -345,17 +345,17 @@
   struct in_addr in;
   circuit_t *circ;
   uint32_t now = time(NULL);
-  assert_connection_ok(exitconn, 0);
-  tor_assert(exitconn->s == -1);
+  assert_connection_ok(TO_CONN(exitconn), 0);
+  tor_assert(exitconn->_base.s == -1);
 
   assert_cache_ok();
 
-  /* first check if exitconn->address is an IP. If so, we already
+  /* first check if exitconn->_base.address is an IP. If so, we already
    * know the answer. */
-  if (tor_inet_aton(exitconn->address, &in) != 0) {
-    exitconn->addr = ntohl(in.s_addr);
+  if (tor_inet_aton(exitconn->_base.address, &in) != 0) {
+    exitconn->_base.addr = ntohl(in.s_addr);
     exitconn->address_ttl = DEFAULT_DNS_TTL;
-    if (exitconn->purpose == EXIT_PURPOSE_RESOLVE)
+    if (exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE)
       send_resolved_cell(exitconn, RESOLVED_TYPE_IPV4);
     return 1;
   }
@@ -364,11 +364,11 @@
    * resolves in the hash table. */
   purge_expired_resolves(now);
 
-  /* lower-case exitconn->address, so it's in canonical form */
-  tor_strlower(exitconn->address);
+  /* lower-case exitconn->_base.address, so it's in canonical form */
+  tor_strlower(exitconn->_base.address);
 
   /* now check the hash table to see if 'address' is already there. */
-  strlcpy(search.address, exitconn->address, sizeof(search.address));
+  strlcpy(search.address, exitconn->_base.address, sizeof(search.address));
   resolve = HT_FIND(cache_map, &cache_root, &search);
   if (resolve && resolve->expire > now) { /* already there */
     switch (resolve->state) {
@@ -381,27 +381,27 @@
         resolve->pending_connections = pending_connection;
         log_debug(LD_EXIT,"Connection (fd %d) waiting for pending DNS "
                   "resolve of %s",
-                  exitconn->s, escaped_safe_str(exitconn->address));
-        exitconn->state = EXIT_CONN_STATE_RESOLVING;
+                  exitconn->_base.s, escaped_safe_str(exitconn->_base.address));
+        exitconn->_base.state = EXIT_CONN_STATE_RESOLVING;
         return 0;
       case CACHE_STATE_VALID:
-        exitconn->addr = resolve->addr;
+        exitconn->_base.addr = resolve->addr;
         exitconn->address_ttl = resolve->ttl;
         log_debug(LD_EXIT,"Connection (fd %d) found cached answer for %s",
-                  exitconn->s, escaped_safe_str(exitconn->address));
-        if (exitconn->purpose == EXIT_PURPOSE_RESOLVE)
+                  exitconn->_base.s, escaped_safe_str(exitconn->_base.address));
+        if (exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE)
           send_resolved_cell(exitconn, RESOLVED_TYPE_IPV4);
         return 1;
       case CACHE_STATE_FAILED:
         log_debug(LD_EXIT,"Connection (fd %d) found cached error for %s",
-                  exitconn->s, escaped_safe_str(exitconn->address));
-        if (exitconn->purpose == EXIT_PURPOSE_RESOLVE)
+                  exitconn->_base.s, escaped_safe_str(exitconn->_base.address));
+        if (exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE)
           send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR);
         circ = circuit_get_by_edge_conn(exitconn);
         if (circ)
           circuit_detach_stream(circ, exitconn);
-        if (!exitconn->marked_for_close)
-          connection_free(exitconn);
+        if (!exitconn->_base.marked_for_close)
+          connection_free(TO_CONN(exitconn));
         return -1;
     }
     tor_assert(0);
@@ -411,17 +411,17 @@
   resolve->magic = CACHED_RESOLVE_MAGIC;
   resolve->state = CACHE_STATE_PENDING;
   resolve->expire = now + DEFAULT_DNS_TTL; /* this will get replaced. */
-  strlcpy(resolve->address, exitconn->address, sizeof(resolve->address));
+  strlcpy(resolve->address, exitconn->_base.address, sizeof(resolve->address));
 
   /* add us to the pending list */
   pending_connection = tor_malloc_zero(sizeof(pending_connection_t));
   pending_connection->conn = exitconn;
   resolve->pending_connections = pending_connection;
-  exitconn->state = EXIT_CONN_STATE_RESOLVING;
+  exitconn->_base.state = EXIT_CONN_STATE_RESOLVING;
 
   insert_resolve(resolve);
   log_debug(LD_EXIT,"Assigning question %s to dnsworker.",
-            escaped_safe_str(exitconn->address));
+            escaped_safe_str(exitconn->_base.address));
   assert_cache_ok();
   return assign_to_dnsworker(exitconn);
 }
@@ -429,7 +429,7 @@
 /** Log an error and abort if conn is waiting for a DNS resolve.
  */
 void
-assert_connection_edge_not_dns_pending(connection_t *conn)
+assert_connection_edge_not_dns_pending(edge_connection_t *conn)
 {
   pending_connection_t *pend;
   cached_resolve_t **resolve;
@@ -455,9 +455,9 @@
     for (pend = (*resolve)->pending_connections;
          pend;
          pend = pend->next) {
-      assert_connection_ok(pend->conn, 0);
-      tor_assert(pend->conn->s == -1);
-      tor_assert(!connection_in_array(pend->conn));
+      assert_connection_ok(TO_CONN(pend->conn), 0);
+      tor_assert(pend->conn->_base.s == -1);
+      tor_assert(!connection_in_array(TO_CONN(pend->conn)));
     }
   }
 }
@@ -465,26 +465,26 @@
 /** Remove <b>conn</b> from the list of connections waiting for conn-\>address.
  */
 void
-connection_dns_remove(connection_t *conn)
+connection_dns_remove(edge_connection_t *conn)
 {
   pending_connection_t *pend, *victim;
   cached_resolve_t search;
   cached_resolve_t *resolve;
 
-  tor_assert(conn->type == CONN_TYPE_EXIT);
-  tor_assert(conn->state == EXIT_CONN_STATE_RESOLVING);
+  tor_assert(conn->_base.type == CONN_TYPE_EXIT);
+  tor_assert(conn->_base.state == EXIT_CONN_STATE_RESOLVING);
 
-  strlcpy(search.address, conn->address, sizeof(search.address));
+  strlcpy(search.address, conn->_base.address, sizeof(search.address));
 
   resolve = HT_FIND(cache_map, &cache_root, &search);
   if (!resolve) {
     log_notice(LD_BUG, "Address %s is not pending. Dropping.",
-               escaped_safe_str(conn->address));
+               escaped_safe_str(conn->_base.address));
     return;
   }
 
   tor_assert(resolve->pending_connections);
-  assert_connection_ok(conn,0);
+  assert_connection_ok(TO_CONN(conn),0);
 
   pend = resolve->pending_connections;
 
@@ -493,7 +493,7 @@
     tor_free(pend);
     log_debug(LD_EXIT, "First connection (fd %d) no longer waiting "
               "for resolve of %s",
-              conn->s, escaped_safe_str(conn->address));
+              conn->_base.s, escaped_safe_str(conn->_base.address));
     return;
   } else {
     for ( ; pend->next; pend = pend->next) {
@@ -503,7 +503,7 @@
         tor_free(victim);
         log_debug(LD_EXIT,
                   "Connection (fd %d) no longer waiting for resolve of %s",
-                  conn->s, escaped_safe_str(conn->address));
+                  conn->_base.s, escaped_safe_str(conn->_base.address));
         return; /* more are pending */
       }
     }
@@ -521,7 +521,7 @@
   pending_connection_t *pend;
   cached_resolve_t search;
   cached_resolve_t *resolve;
-  connection_t *pendconn;
+  edge_connection_t *pendconn;
   circuit_t *circ;
 
   strlcpy(search.address, address, sizeof(search.address));
@@ -549,18 +549,18 @@
              escaped_safe_str(address));
   while (resolve->pending_connections) {
     pend = resolve->pending_connections;
-    pend->conn->state = EXIT_CONN_STATE_RESOLVEFAILED;
+    pend->conn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
     pendconn = pend->conn;
-    assert_connection_ok(pendconn, 0);
-    tor_assert(pendconn->s == -1);
-    if (!pendconn->marked_for_close) {
+    assert_connection_ok(TO_CONN(pendconn), 0);
+    tor_assert(pendconn->_base.s == -1);
+    if (!pendconn->_base.marked_for_close) {
       connection_edge_end(pendconn, END_STREAM_REASON_RESOURCELIMIT,
                           pendconn->cpath_layer);
     }
     circ = circuit_get_by_edge_conn(pendconn);
     if (circ)
       circuit_detach_stream(circ, pendconn);
-    connection_free(pendconn);
+    connection_free(TO_CONN(pendconn));
     resolve->pending_connections = pend->next;
     tor_free(pend);
   }
@@ -612,7 +612,7 @@
   pending_connection_t *pend;
   cached_resolve_t search;
   cached_resolve_t *resolve;
-  connection_t *pendconn;
+  edge_connection_t *pendconn;
   circuit_t *circ;
 
   assert_cache_ok();
@@ -659,16 +659,16 @@
 
   while (resolve->pending_connections) {
     pend = resolve->pending_connections;
-    assert_connection_ok(pend->conn,time(NULL));
-    pend->conn->addr = resolve->addr;
+    assert_connection_ok(TO_CONN(pend->conn),time(NULL));
+    pend->conn->_base.addr = resolve->addr;
     pend->conn->address_ttl = resolve->ttl;
     pendconn = pend->conn; /* don't pass complex things to the
                               connection_mark_for_close macro */
 
     if (resolve->state == CACHE_STATE_FAILED) {
       /* prevent double-remove. */
-      pendconn->state = EXIT_CONN_STATE_RESOLVEFAILED;
-      if (pendconn->purpose == EXIT_PURPOSE_CONNECT) {
+      pendconn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
+      if (pendconn->_base.purpose == EXIT_PURPOSE_CONNECT) {
         connection_edge_end(pendconn, END_STREAM_REASON_RESOLVEFAILED,
                             pendconn->cpath_layer);
         /* This detach must happen after we send the end cell. */
@@ -678,11 +678,11 @@
         /* This detach must happen after we send the resolved cell. */
         circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
       }
-      connection_free(pendconn);
+      connection_free(TO_CONN(pendconn));
     } else {
-      if (pendconn->purpose == EXIT_PURPOSE_CONNECT) {
+      if (pendconn->_base.purpose == EXIT_PURPOSE_CONNECT) {
         /* prevent double-remove. */
-        pend->conn->state = EXIT_CONN_STATE_CONNECTING;
+        pend->conn->_base.state = EXIT_CONN_STATE_CONNECTING;
 
         circ = circuit_get_by_edge_conn(pend->conn);
         tor_assert(circ);
@@ -698,12 +698,12 @@
       } else {
         /* prevent double-remove.  This isn't really an accurate state,
          * but it does the right thing. */
-        pendconn->state = EXIT_CONN_STATE_RESOLVEFAILED;
+        pendconn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
         send_resolved_cell(pendconn, RESOLVED_TYPE_IPV4);
         circ = circuit_get_by_edge_conn(pendconn);
         tor_assert(circ);
         circuit_detach_stream(circ, pendconn);
-        connection_free(pendconn);
+        connection_free(TO_CONN(pendconn));
       }
     }
     resolve->pending_connections = pend->next;
@@ -722,14 +722,14 @@
  * <b>exitconn</b>-\>address; tell that dns worker to begin resolving.
  */
 static int
-assign_to_dnsworker(connection_t *exitconn)
+assign_to_dnsworker(edge_connection_t *exitconn)
 {
   connection_t *dnsconn;
   unsigned char len;
 
-  tor_assert(exitconn->state == EXIT_CONN_STATE_RESOLVING);
-  assert_connection_ok(exitconn, 0);
-  tor_assert(exitconn->s == -1);
+  tor_assert(exitconn->_base.state == EXIT_CONN_STATE_RESOLVING);
+  assert_connection_ok(TO_CONN(exitconn), 0);
+  tor_assert(exitconn->_base.s == -1);
 
   /* respawn here, to be sure there are enough */
   if (spawn_enough_dnsworkers() < 0) {
@@ -741,18 +741,18 @@
 
   if (!dnsconn) {
     log_warn(LD_EXIT,"no idle dns workers. Failing.");
-    if (exitconn->purpose == EXIT_PURPOSE_RESOLVE)
+    if (exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE)
       send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR_TRANSIENT);
     goto err;
   }
 
   log_debug(LD_EXIT,
             "Connection (fd %d) needs to resolve %s; assigning "
-            "to DNSWorker (fd %d)", exitconn->s,
-            escaped_safe_str(exitconn->address), dnsconn->s);
+            "to DNSWorker (fd %d)", exitconn->_base.s,
+            escaped_safe_str(exitconn->_base.address), dnsconn->s);
 
   tor_free(dnsconn->address);
-  dnsconn->address = tor_strdup(exitconn->address);
+  dnsconn->address = tor_strdup(exitconn->_base.address);
   dnsconn->state = DNSWORKER_STATE_BUSY;
   /* touch the lastwritten timestamp, since that's how we check to
    * see how long it's been since we asked the question, and sometimes
@@ -766,7 +766,7 @@
 
   return 0;
 err:
-  dns_cancel_pending_resolve(exitconn->address); /* also sends end and frees */
+  dns_cancel_pending_resolve(exitconn->_base.address); /* also sends end and frees */
   return -1;
 }
 
@@ -1172,11 +1172,11 @@
 static int
 assign_to_dnsworker(connection_t *exitconn)
 {
-  char *addr = tor_strdup(exitconn->address);
+  char *addr = tor_strdup(exitconn->_base.address);
   int r;
   log_info(LD_EXIT, "Launching eventdns request for %s",
-           escaped_safe_str(exitconn->address));
-  r = eventdns_resolve(exitconn->address, DNS_QUERY_NO_SEARCH,
+           escaped_safe_str(exitconn->_base.address));
+  r = eventdns_resolve(exitconn->_base.address, DNS_QUERY_NO_SEARCH,
                        eventdns_callback, addr);
   if (r) {
     log_warn(LD_EXIT, "eventdns rejected address %s: error %d.",

Modified: tor/trunk/src/or/hibernate.c
===================================================================
--- tor/trunk/src/or/hibernate.c	2006-07-26 19:07:23 UTC (rev 6905)
+++ tor/trunk/src/or/hibernate.c	2006-07-26 19:07:26 UTC (rev 6906)
@@ -786,11 +786,12 @@
          (conn = connection_get_by_type(CONN_TYPE_AP)) ||
          (conn = connection_get_by_type(CONN_TYPE_EXIT))) {
     if (CONN_IS_EDGE(conn))
-      connection_edge_end(conn, END_STREAM_REASON_HIBERNATING,
-                          conn->cpath_layer);
+      connection_edge_end(TO_EDGE_CONN(conn), END_STREAM_REASON_HIBERNATING,
+                          TO_EDGE_CONN(conn)->cpath_layer);
     log_info(LD_NET,"Closing conn type %d", conn->type);
     if (conn->type == CONN_TYPE_AP) /* send socks failure if needed */
-      connection_mark_unattached_ap(conn, END_STREAM_REASON_HIBERNATING);
+      connection_mark_unattached_ap(TO_EDGE_CONN(conn),
+                                    END_STREAM_REASON_HIBERNATING);
     else
       connection_mark_for_close(conn);
   }

Modified: tor/trunk/src/or/main.c
===================================================================
--- tor/trunk/src/or/main.c	2006-07-26 19:07:23 UTC (rev 6905)
+++ tor/trunk/src/or/main.c	2006-07-26 19:07:26 UTC (rev 6906)
@@ -212,11 +212,11 @@
   }
   smartlist_remove(closeable_connection_lst, conn);
   if (conn->type == CONN_TYPE_EXIT) {
-    assert_connection_edge_not_dns_pending(conn);
+    assert_connection_edge_not_dns_pending(TO_EDGE_CONN(conn));
   }
-  if (conn->type == CONN_TYPE_OR &&
-      !tor_digest_is_zero(conn->identity_digest)) {
-    connection_or_remove_from_identity_map(conn);
+  if (conn->type == CONN_TYPE_OR) {
+    if (!tor_digest_is_zero(TO_OR_CONN(conn)->identity_digest))
+      connection_or_remove_from_identity_map(TO_OR_CONN(conn));
   }
   connection_free(conn);
 }
@@ -413,7 +413,8 @@
       tor_fragile_assert();
 #endif
       if (CONN_IS_EDGE(conn))
-        connection_edge_end_errno(conn, conn->cpath_layer);
+        connection_edge_end_errno(TO_EDGE_CONN(conn),
+                                  TO_EDGE_CONN(conn)->cpath_layer);
       connection_mark_for_close(conn);
     }
   }
@@ -443,7 +444,8 @@
            "Bug: unhandled error on write for %s connection (fd %d); removing",
            conn_type_to_string(conn->type), conn->s);
       tor_fragile_assert();
-      conn->has_sent_end = 1; /* otherwise we cry wolf about duplicate close */
+      if (CONN_IS_EDGE(conn))
+        conn->edge_has_sent_end = 1; /* otherwise we cry wolf about duplicate close */
       /* XXX do we need a close-immediate here, so we don't try to flush? */
       connection_mark_for_close(conn);
     }
@@ -489,7 +491,7 @@
                 conn->marked_for_close_file, conn->marked_for_close);
     if (connection_speaks_cells(conn)) {
       if (conn->state == OR_CONN_STATE_OPEN) {
-        retval = flush_buf_tls(conn->tls, conn->outbuf, sz,
+        retval = flush_buf_tls(TO_OR_CONN(conn)->tls, conn->outbuf, sz,
                                &conn->outbuf_flushlen);
       } else
         retval = -1; /* never flush non-open broken tls connections */
@@ -544,12 +546,13 @@
 
   while ((conn = connection_get_by_type_state(CONN_TYPE_AP,
                                               AP_CONN_STATE_CIRCUIT_WAIT))) {
+    edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
     log_notice(LD_NET,
                "Is your network connection down? "
                "Failing connection to '%s:%d'.",
-               safe_str(conn->socks_request->address),
-               conn->socks_request->port);
-    connection_mark_unattached_ap(conn, END_STREAM_REASON_NET_UNREACHABLE);
+               safe_str(edge_conn->socks_request->address),
+               edge_conn->socks_request->port);
+    connection_mark_unattached_ap(edge_conn, END_STREAM_REASON_NET_UNREACHABLE);
   }
 }
 
@@ -582,6 +585,7 @@
   cell_t cell;
   connection_t *conn = connection_array[i];
   or_options_t *options = get_options();
+  or_connection_t *or_conn;
 
   if (conn->outbuf && !buf_datalen(conn->outbuf))
     conn->timestamp_lastempty = now;
@@ -602,7 +606,7 @@
         buf_datalen(conn->inbuf)>=1024) {
       log_info(LD_DIR,"Trying to extract information from wedged server desc "
                "download.");
-      connection_dir_reached_eof(conn);
+      connection_dir_reached_eof(TO_DIR_CONN(conn));
     } else {
       connection_mark_for_close(conn);
     }
@@ -612,17 +616,19 @@
   if (!connection_speaks_cells(conn))
     return; /* we're all done here, the rest is just for OR conns */
 
-  if (!conn->is_obsolete) {
+  or_conn = TO_OR_CONN(conn);
+
+  if (!conn->or_is_obsolete) {
     if (conn->timestamp_created + TIME_BEFORE_OR_CONN_IS_OBSOLETE < now) {
       log_info(LD_OR,
                "Marking OR conn to %s:%d obsolete (fd %d, %d secs old).",
                conn->address, conn->port, conn->s,
                (int)(now - conn->timestamp_created));
-      conn->is_obsolete = 1;
+      conn->or_is_obsolete = 1;
     } else {
-      connection_t *best =
-        connection_or_get_by_identity_digest(conn->identity_digest);
-      if (best && best != conn &&
+      or_connection_t *best =
+        connection_or_get_by_identity_digest(or_conn->identity_digest);
+      if (best && best != or_conn &&
           (conn->state == OR_CONN_STATE_OPEN ||
            now > conn->timestamp_created + TLS_HANDSHAKE_TIMEOUT)) {
           /* We only mark as obsolete connections that already are in
@@ -637,16 +643,16 @@
                  "(fd %d, %d secs old).",
                  conn->address, conn->port, conn->s,
                  (int)(now - conn->timestamp_created));
-        conn->is_obsolete = 1;
+        conn->or_is_obsolete = 1;
       }
     }
   }
 
-  if (conn->is_obsolete && !conn->n_circuits) {
+  if (conn->or_is_obsolete && !or_conn->n_circuits) {
     /* no unmarked circs -- mark it now */
     log_info(LD_OR,
              "Expiring non-used OR connection to fd %d (%s:%d) [Obsolete].",
-             conn->s,conn->address, conn->port);
+             conn->s, conn->address, conn->port);
     connection_mark_for_close(conn);
     conn->hold_open_until_flushed = 1;
     return;
@@ -655,20 +661,20 @@
   /* If we haven't written to an OR connection for a while, then either nuke
      the connection or send a keepalive, depending. */
   if (now >= conn->timestamp_lastwritten + options->KeepalivePeriod) {
-    routerinfo_t *router = router_get_by_digest(conn->identity_digest);
+    routerinfo_t *router = router_get_by_digest(or_conn->identity_digest);
     if (!connection_state_is_open(conn)) {
       log_info(LD_OR,"Expiring non-open OR connection to fd %d (%s:%d).",
                conn->s,conn->address, conn->port);
       connection_mark_for_close(conn);
       conn->hold_open_until_flushed = 1;
-    } else if (we_are_hibernating() && !conn->n_circuits &&
+    } else if (we_are_hibernating() && !or_conn->n_circuits &&
                !buf_datalen(conn->outbuf)) {
       log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) "
                "[Hibernating or exiting].",
                conn->s,conn->address, conn->port);
       connection_mark_for_close(conn);
       conn->hold_open_until_flushed = 1;
-    } else if (!clique_mode(options) && !conn->n_circuits &&
+    } else if (!clique_mode(options) && !or_conn->n_circuits &&
                (!router || !server_mode(options) ||
                 !router_is_clique_mode(router))) {
       log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) "
@@ -692,7 +698,7 @@
              conn->address, conn->port);
       memset(&cell,0,sizeof(cell_t));
       cell.command = CELL_PADDING;
-      connection_or_write_cell_to_buf(&cell, conn);
+      connection_or_write_cell_to_buf(&cell, or_conn);
     }
   }
 }

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2006-07-26 19:07:23 UTC (rev 6905)
+++ tor/trunk/src/or/or.h	2006-07-26 19:07:26 UTC (rev 6906)
@@ -576,7 +576,11 @@
 typedef struct buf_t buf_t;
 typedef struct socks_request_t socks_request_t;
 
-#define CONNECTION_MAGIC 0x7C3C304Eu
+#define BASE_CONNECTION_MAGIC 0x7C3C304Eu
+#define OR_CONNECTION_MAGIC 0x7D31FF03u
+#define EDGE_CONNECTION_MAGIC 0xF0374013u
+#define DIR_CONNECTION_MAGIC 0x9988ffeeu
+#define CONTROL_CONNECTION_MAGIC 0x8abc765du
 
 /** Description of a connection to another host or process, and associated
  * data.
@@ -609,14 +613,15 @@
   unsigned hold_open_until_flushed:1; /**< Despite this connection's being
                                       * marked for close, do we flush it
                                       * before closing it? */
-  unsigned has_sent_end:1; /**< For debugging; only used on edge connections.
-                         * Set once we've set the stream end,
+
+  unsigned edge_has_sent_end:1; /**< For debugging; only used on edge
+                         * connections.  Set once we've set the stream end,
                          * and check in circuit_about_to_close_connection(). */
   /** For control connections only. If set, we send extended info with control
    * events as appropriate. */
   unsigned int control_events_are_extended:1;
   /** Used for OR conns that shouldn't get any new circs attached to them. */
-  unsigned int is_obsolete:1;
+  unsigned int or_is_obsolete:1;
 
   int s; /**< Our socket; -1 if this connection is closed. */
   int poll_index; /* XXXX rename. */
@@ -648,22 +653,23 @@
                                       * we marked for close? */
   char *address; /**< FQDN (or IP) of the guy on the other end.
                   * strdup into this, because free_connection frees it. */
-  uint32_t address_ttl; /**< TTL for address-to-addr mapping on exit
-                         * connection.  Exit connections only. */
+
+  /** Quasi-global identifier for this connection; used for control.c */
+  /* XXXX NM This can get re-used after 2**32 circuits. */
+  uint32_t global_identifier;
+
+};
+
+typedef struct connection_t connection_t;
+
+/** DOCDOC */
+typedef struct or_connection_t {
+  connection_t _base;
+
   char identity_digest[DIGEST_LEN]; /**< Hash of the public RSA key for
                                      * the other side's signing key. */
   char *nickname; /**< Nickname of OR on other side (if any). */
 
-  /** Nickname of planned exit node -- used with .exit support. */
-  char *chosen_exit_name;
-  /** If 1, and we fail to reach the chosen exit, stop requiring it. */
-  unsigned int chosen_exit_optional:1;
-  /** Number of times we've reassigned this application connection to
-   * a new circuit. We keep track because the timeout is longer if we've
-   * already retried several times. */
-  int num_socks_retries;
-
-/* Used only by OR connections: */
   tor_tls_t *tls; /**< TLS connection state (OR only.) */
 
   /* bandwidth* and receiver_bucket only used by ORs in OPEN state: */
@@ -677,16 +683,19 @@
                                 * we use? */
   int n_circuits; /**< How many circuits use this connection as p_conn or
                    * n_conn ? */
-  struct connection_t *next_with_same_id; /**< Next connection with same
+  struct or_connection_t *next_with_same_id; /**< Next connection with same
                                            * identity digest as this one. */
   uint16_t next_circ_id; /**< Which circ_id do we try to use next on
                           * this connection?  This is always in the
                           * range 0..1<<15-1. (OR only.)*/
+} or_connection_t;
 
-/* Used only by edge connections: */
+typedef struct edge_connection_t {
+  connection_t _base;
+
   uint16_t stream_id;
-  struct connection_t *next_stream; /**< Points to the next stream at this
-                                     * edge, if any (Edge only). */
+  struct edge_connection_t *next_stream; /**< Points to the next stream at this
+                                          * edge, if any (Edge only). */
   struct crypt_path_t *cpath_layer; /**< A pointer to which node in the circ
                                      * this conn exits at. (Edge only.) */
   int package_window; /**< How many more relay cells can i send into the
@@ -694,6 +703,36 @@
   int deliver_window; /**< How many more relay cells can end at me? (Edge
                        * only.) */
 
+  /** Number of times we've reassigned this application connection to
+   * a new circuit. We keep track because the timeout is longer if we've
+   * already retried several times. */
+  int num_socks_retries;
+
+  /** Nickname of planned exit node -- used with .exit support. */
+  char *chosen_exit_name;
+  /** If 1, and we fail to reach the chosen exit, stop requiring it. */
+  unsigned int chosen_exit_optional:1;
+
+/* Used only by AP connections */
+  socks_request_t *socks_request; /**< SOCKS structure describing request (AP
+                                   * only.) */
+
+  struct circuit_t *on_circuit; /**< The circuit (if any) that this edge
+                                 * connection is using. */
+
+  uint32_t address_ttl; /**< TTL for address-to-addr mapping on exit
+                         * connection.  Exit connections only. */
+
+/* Used only by DIR and AP connections: */
+  char rend_query[REND_SERVICE_ID_LEN+1]; /**< What rendezvous service are we
+                                           * querying for? (DIR/AP only) */
+
+
+} edge_connection_t;
+
+typedef struct dir_connection_t {
+  connection_t _base;
+
 /* Used only by Dir connections */
   char *requested_resource; /**< Which 'resource' did we ask the directory
                              * for? */
@@ -708,32 +747,56 @@
   off_t cached_dir_offset;
   tor_zlib_state_t *zlib_state;
 
-/* Used only by AP connections */
-  socks_request_t *socks_request; /**< SOCKS structure describing request (AP
-                                   * only.) */
+/* Used only by DIR and AP connections: */
+  char rend_query[REND_SERVICE_ID_LEN+1]; /**< What rendezvous service are we
+                                           * querying for? (DIR/AP only) */
 
-  /** Quasi-global identifier for this connection; used for control.c */
-  /* XXXX NM This can get re-used after 2**32 circuits. */
-  uint32_t global_identifier;
+  char identity_digest[DIGEST_LEN]; /**< Hash of the public RSA key for
+                                     * the directory server's signing key. */
+} dir_connection_t;
 
+typedef struct control_connection_t {
+  connection_t _base;
+
   /* Used only by control connections */
   uint32_t event_mask;
   uint32_t incoming_cmd_len;
   uint32_t incoming_cmd_cur_len;
   char *incoming_cmd;
-
-/* Used only by DIR and AP connections: */
-  struct circuit_t *on_circuit; /**< The circuit (if any) that this edge
-                                 * connection is using. */
-  char rend_query[REND_SERVICE_ID_LEN+1]; /**< What rendezvous service are we
-                                           * querying for? (DIR/AP only) */
-
   /* Used only by control v0 connections */
   uint16_t incoming_cmd_type;
-};
+} control_connection_t;
 
-typedef struct connection_t connection_t;
+#define TO_CONN(c) &(((c)->_base))
+#define DOWNCAST(from, to, ptr) \
+  (to*) (((from*)(ptr)) - STRUCT_OFFSET(to, _base))
 
+or_connection_t *TO_OR_CONN(connection_t *);
+dir_connection_t *TO_DIR_CONN(connection_t *);
+edge_connection_t *TO_EDGE_CONN(connection_t *);
+control_connection_t *TO_CONTROL_CONN(connection_t *);
+
+extern INLINE or_connection_t *TO_OR_CONN(connection_t *c)
+{
+  tor_assert(c->magic == OR_CONNECTION_MAGIC);
+  return DOWNCAST(connection_t, or_connection_t, c);
+}
+extern INLINE dir_connection_t *TO_DIR_CONN(connection_t *c)
+{
+  tor_assert(c->magic == DIR_CONNECTION_MAGIC);
+  return DOWNCAST(connection_t, dir_connection_t, c);
+}
+extern INLINE edge_connection_t *TO_EDGE_CONN(connection_t *c)
+{
+  tor_assert(c->magic == EDGE_CONNECTION_MAGIC);
+  return DOWNCAST(connection_t, edge_connection_t, c);
+}
+extern INLINE control_connection_t *TO_CONTROL_CONN(connection_t *c)
+{
+  tor_assert(c->magic == CONTROL_CONNECTION_MAGIC);
+  return DOWNCAST(connection_t, control_connection_t, c);
+}
+
 typedef enum {
   ADDR_POLICY_ACCEPT=1,
   ADDR_POLICY_REJECT=2,
@@ -1072,7 +1135,7 @@
                    * ORIGIN_CIRCUIT_MAGIC or OR_CIRCUIT_MAGIC. */
 
   /** The OR connection that is next in this circuit. */
-  connection_t *n_conn;
+  or_connection_t *n_conn;
   /** The identity hash of n_conn. */
   char n_conn_id_digest[DIGEST_LEN];
   /** The circuit_id used in the next (forward) hop of this circuit. */
@@ -1121,7 +1184,7 @@
   circuit_t _base;
 
   /** Linked list of AP streams associated with this circuit. */
-  connection_t *p_streams;
+  edge_connection_t *p_streams;
   /** Build state for this circuit. It includes the intended path
    * length, the chosen exit router, rendezvous information, etc.
    */
@@ -1164,12 +1227,12 @@
   /** 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;
+  or_connection_t *p_conn;
   /** Linked list of Exit streams associated with this circuit. */
-  connection_t *n_streams;
+  edge_connection_t *n_streams;
   /** Linked list of Exit streams associated with this circuit that are
    * still being resolved. */
-  connection_t *resolving_streams;
+  edge_connection_t *resolving_streams;
     /** The cipher used by intermediate hops for cells heading toward the
    * OP. */
   crypto_cipher_env_t *p_crypto;
@@ -1210,14 +1273,16 @@
 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));
+  //return (or_circuit_t*) (((char*)x) - STRUCT_OFFSET(or_circuit_t, _base));
+  return DOWNCAST(circuit_t, or_circuit_t, x);
 }
 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));
+  //return (origin_circuit_t*)
+  //  (((char*)x) - STRUCT_OFFSET(origin_circuit_t, _base));
+  return DOWNCAST(circuit_t, origin_circuit_t, x);
 }
 
 #define ALLOW_INVALID_ENTRY        1
@@ -1554,7 +1619,7 @@
                                      int need_uptime, int need_capacity,
                                      int internal);
 int circuit_handle_first_hop(origin_circuit_t *circ);
-void circuit_n_conn_done(connection_t *or_conn, int status);
+void circuit_n_conn_done(or_connection_t *or_conn, int status);
 int inform_testing_reachability(void);
 int circuit_send_next_onion_skin(origin_circuit_t *circ);
 void circuit_note_clock_jumped(int seconds_elapsed);
@@ -1593,17 +1658,18 @@
 const char *circuit_state_to_string(int state);
 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);
+                                 or_connection_t *conn);
 void circuit_set_n_circid_orconn(circuit_t *circ, uint16_t id,
-                                 connection_t *conn);
+                                 or_connection_t *conn);
 void circuit_set_state(circuit_t *circ, int state);
 void circuit_close_all_marked(void);
 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);
-void circuit_unlink_all_from_or_conn(connection_t *conn, int reason);
+or_circuit_t *or_circuit_new(uint16_t p_circ_id, or_connection_t *p_conn);
+circuit_t *circuit_get_by_circid_orconn(uint16_t circ_id,
+                                        or_connection_t *conn);
+int circuit_id_used_on_conn(uint16_t circ_id, or_connection_t *conn);
+circuit_t *circuit_get_by_edge_conn(edge_connection_t *conn);
+void circuit_unlink_all_from_or_conn(or_connection_t *conn, int reason);
 circuit_t *circuit_get_by_global_id(uint32_t id);
 origin_circuit_t *circuit_get_by_rend_query_and_purpose(const char *rend_query,
                                                         uint8_t purpose);
@@ -1631,10 +1697,10 @@
 
 void circuit_expire_building(time_t now);
 void circuit_remove_handled_ports(smartlist_t *needed_ports);
-int circuit_stream_is_being_handled(connection_t *conn, uint16_t port,
+int circuit_stream_is_being_handled(edge_connection_t *conn, uint16_t port,
                                     int min);
 void circuit_build_needed_circs(time_t now);
-void circuit_detach_stream(circuit_t *circ, connection_t *conn);
+void circuit_detach_stream(circuit_t *circ, edge_connection_t *conn);
 void circuit_about_to_close_connection(connection_t *conn);
 void circuit_has_opened(origin_circuit_t *circ);
 void circuit_build_failed(origin_circuit_t *circ);
@@ -1650,13 +1716,13 @@
                                     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,
+int connection_ap_handshake_attach_chosen_circuit(edge_connection_t *conn,
                                                   origin_circuit_t *circ);
-int connection_ap_handshake_attach_circuit(connection_t *conn);
+int connection_ap_handshake_attach_circuit(edge_connection_t *conn);
 
 /********************************* command.c ***************************/
 
-void command_process_cell(cell_t *cell, connection_t *conn);
+void command_process_cell(cell_t *cell, or_connection_t *conn);
 
 extern uint64_t stats_n_padding_cells_processed;
 extern uint64_t stats_n_create_cells_processed;
@@ -1730,15 +1796,15 @@
 int connection_wants_to_flush(connection_t *conn);
 int connection_outbuf_too_full(connection_t *conn);
 int connection_handle_write(connection_t *conn);
-void _connection_controller_force_write(connection_t *conn);
+void _connection_controller_force_write(control_connection_t *conn);
 void connection_write_to_buf(const char *string, size_t len,
                              connection_t *conn);
-void connection_write_to_buf_zlib(connection_t *conn,
+void connection_write_to_buf_zlib(dir_connection_t *conn,
                                   tor_zlib_state_t *state,
                                   const char *data, size_t data_len,
                                   int done);
 
-connection_t *connection_or_exact_get_by_addr_port(uint32_t addr,
+or_connection_t *connection_or_exact_get_by_addr_port(uint32_t addr,
                                                    uint16_t port);
 connection_t *connection_get_by_global_id(uint32_t id);
 
@@ -1759,34 +1825,34 @@
 char *alloc_http_authenticator(const char *authenticator);
 
 void assert_connection_ok(connection_t *conn, time_t now);
-int connection_or_nonopen_was_started_here(connection_t *conn);
+int connection_or_nonopen_was_started_here(or_connection_t *conn);
 
 /********************************* connection_edge.c *************************/
 
 #define connection_mark_unattached_ap(conn, endreason) \
   _connection_mark_unattached_ap((conn), (endreason), __LINE__, _SHORT_FILE_)
 
-void _connection_mark_unattached_ap(connection_t *conn, int endreason,
+void _connection_mark_unattached_ap(edge_connection_t *conn, int endreason,
                                     int line, const char *file);
-int connection_edge_reached_eof(connection_t *conn);
-int connection_edge_process_inbuf(connection_t *conn, int package_partial);
-int connection_edge_destroy(uint16_t circ_id, connection_t *conn);
-int connection_edge_end(connection_t *conn, char reason,
+int connection_edge_reached_eof(edge_connection_t *conn);
+int connection_edge_process_inbuf(edge_connection_t *conn, int package_partial);
+int connection_edge_destroy(uint16_t circ_id, edge_connection_t *conn);
+int connection_edge_end(edge_connection_t *conn, char reason,
                         crypt_path_t *cpath_layer);
-int connection_edge_end_errno(connection_t *conn, crypt_path_t *cpath_layer);
-int connection_edge_finished_flushing(connection_t *conn);
-int connection_edge_finished_connecting(connection_t *conn);
+int connection_edge_end_errno(edge_connection_t *conn, crypt_path_t *cpath_layer);
+int connection_edge_finished_flushing(edge_connection_t *conn);
+int connection_edge_finished_connecting(edge_connection_t *conn);
 
-int connection_ap_handshake_send_begin(connection_t *ap_conn,
+int connection_ap_handshake_send_begin(edge_connection_t *ap_conn,
                                        origin_circuit_t *circ);
-int connection_ap_handshake_send_resolve(connection_t *ap_conn,
+int connection_ap_handshake_send_resolve(edge_connection_t *ap_conn,
                                          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,
+void connection_ap_handshake_socks_reply(edge_connection_t *conn, char *reply,
                                          size_t replylen,
                                          socks5_reply_status_t status);
-void connection_ap_handshake_socks_resolved(connection_t *conn,
+void connection_ap_handshake_socks_resolved(edge_connection_t *conn,
                                             int answer_type,
                                             size_t answer_len,
                                             const char *answer,
@@ -1794,12 +1860,12 @@
 
 int connection_exit_begin_conn(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_exit_connect(edge_connection_t *conn);
+int connection_edge_is_rendezvous_stream(edge_connection_t *conn);
+int connection_ap_can_use_exit(edge_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, origin_circuit_t *circ);
+int connection_ap_detach_retriable(edge_connection_t *conn, origin_circuit_t *circ);
 
 void addressmap_init(void);
 void addressmap_clean(time_t now);
@@ -1820,7 +1886,7 @@
 const char *addressmap_register_virtual_address(int type, char *new_address);
 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,
+int connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
                                                origin_circuit_t *circ);
 
 void set_exit_redirects(smartlist_t *lst);
@@ -1831,23 +1897,23 @@
 
 /********************************* connection_or.c ***************************/
 
-void connection_or_remove_from_identity_map(connection_t *conn);
+void connection_or_remove_from_identity_map(or_connection_t *conn);
 void connection_or_clear_identity_map(void);
-connection_t *connection_or_get_by_identity_digest(const char *digest);
+or_connection_t *connection_or_get_by_identity_digest(const char *digest);
 
-int connection_or_reached_eof(connection_t *conn);
-int connection_or_process_inbuf(connection_t *conn);
-int connection_or_finished_flushing(connection_t *conn);
-int connection_or_finished_connecting(connection_t *conn);
+int connection_or_reached_eof(or_connection_t *conn);
+int connection_or_process_inbuf(or_connection_t *conn);
+int connection_or_finished_flushing(or_connection_t *conn);
+int connection_or_finished_connecting(or_connection_t *conn);
 
-connection_t *connection_or_connect(uint32_t addr, uint16_t port,
+or_connection_t *connection_or_connect(uint32_t addr, uint16_t port,
                                     const char *id_digest);
 
-int connection_tls_start_handshake(connection_t *conn, int receiving);
-int connection_tls_continue_handshake(connection_t *conn);
+int connection_tls_start_handshake(or_connection_t *conn, int receiving);
+int connection_tls_continue_handshake(or_connection_t *conn);
 
-void connection_or_write_cell_to_buf(const cell_t *cell, connection_t *conn);
-int connection_or_send_destroy(uint16_t circ_id, connection_t *conn,
+void connection_or_write_cell_to_buf(const cell_t *cell, or_connection_t *conn);
+int connection_or_send_destroy(uint16_t circ_id, or_connection_t *conn,
                                int reason);
 
 /********************************* control.c ***************************/
@@ -1906,14 +1972,14 @@
 #define LOG_FN_CONN(conn, args)                 \
   CONN_LOG_PROTECT(conn, log_fn args)
 
-int connection_control_finished_flushing(connection_t *conn);
-int connection_control_reached_eof(connection_t *conn);
-int connection_control_process_inbuf(connection_t *conn);
+int connection_control_finished_flushing(control_connection_t *conn);
+int connection_control_reached_eof(control_connection_t *conn);
+int connection_control_process_inbuf(control_connection_t *conn);
 
 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_stream_status(edge_connection_t *conn, stream_status_event_t e);
+int control_event_or_conn_status(or_connection_t *conn, or_conn_status_event_t e);
 int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written);
 void control_event_logmsg(int severity, unsigned int domain, const char *msg);
 int control_event_descriptors_changed(smartlist_t *routers);
@@ -1959,11 +2025,11 @@
 int parse_http_response(const char *headers, int *code, time_t *date,
                         int *compression, char **response);
 
-int connection_dir_reached_eof(connection_t *conn);
-int connection_dir_process_inbuf(connection_t *conn);
-int connection_dir_finished_flushing(connection_t *conn);
-int connection_dir_finished_connecting(connection_t *conn);
-void connection_dir_request_failed(connection_t *conn);
+int connection_dir_reached_eof(dir_connection_t *conn);
+int connection_dir_process_inbuf(dir_connection_t *conn);
+int connection_dir_finished_flushing(dir_connection_t *conn);
+int connection_dir_finished_connecting(dir_connection_t *conn);
+void connection_dir_request_failed(dir_connection_t *conn);
 int dir_split_resource_into_fingerprints(const char *resource,
                                     smartlist_t *fp_out, int *compresseed_out,
                                     int decode_hex, int sort_uniq);
@@ -1971,7 +2037,7 @@
 
 /********************************* dirserv.c ***************************/
 
-int connection_dirserv_flushed_some(connection_t *conn);
+int connection_dirserv_flushed_some(dir_connection_t *conn);
 int dirserv_add_own_fingerprint(const char *nickname, crypto_pk_env_t *pk);
 int dirserv_parse_fingerprint_file(const char *fname);
 void dirserv_free_fingerprint_list(void);
@@ -2021,11 +2087,11 @@
 int connection_dns_reached_eof(connection_t *conn);
 int connection_dns_process_inbuf(connection_t *conn);
 void dnsworkers_rotate(void);
-void connection_dns_remove(connection_t *conn);
-void assert_connection_edge_not_dns_pending(connection_t *conn);
+void connection_dns_remove(edge_connection_t *conn);
+void assert_connection_edge_not_dns_pending(edge_connection_t *conn);
 void assert_all_pending_dns_resolves_ok(void);
 void dns_cancel_pending_resolve(char *question);
-int dns_resolve(connection_t *exitconn);
+int dns_resolve(edge_connection_t *exitconn);
 
 /********************************* hibernate.c **********************/
 
@@ -2146,12 +2212,12 @@
 
 void relay_header_pack(char *dest, const relay_header_t *src);
 void relay_header_unpack(relay_header_t *dest, const char *src);
-int connection_edge_send_command(connection_t *fromconn, circuit_t *circ,
+int connection_edge_send_command(edge_connection_t *fromconn, circuit_t *circ,
                                  int relay_command, const char *payload,
                                  size_t payload_len,
                                  crypt_path_t *cpath_layer);
-int connection_edge_package_raw_inbuf(connection_t *conn, int package_partial);
-void connection_edge_consider_sending_sendme(connection_t *conn);
+int connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial);
+void connection_edge_consider_sending_sendme(edge_connection_t *conn);
 socks5_reply_status_t connection_edge_end_reason_socks5_response(int reason);
 int errno_to_end_reason(int e);
 
@@ -2283,7 +2349,7 @@
 int rend_service_introduce(origin_circuit_t *circuit, const char *request,
                            size_t request_len);
 void rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc);
-int rend_service_set_connection_addr_port(connection_t *conn,
+int rend_service_set_connection_addr_port(edge_connection_t *conn,
                                           origin_circuit_t *circ);
 void rend_service_dump_stats(int severity);
 void rend_service_free_all(void);
@@ -2332,7 +2398,7 @@
 void check_descriptor_bandwidth_changed(time_t now);
 void check_descriptor_ipaddress_changed(time_t now);
 void router_new_address_suggestion(const char *suggestion);
-int router_compare_to_my_exit_policy(connection_t *conn);
+int router_compare_to_my_exit_policy(edge_connection_t *conn);
 routerinfo_t *router_get_my_routerinfo(void);
 const char *router_get_my_descriptor(void);
 int router_digest_is_me(const char *digest);

Modified: tor/trunk/src/or/relay.c
===================================================================
--- tor/trunk/src/or/relay.c	2006-07-26 19:07:23 UTC (rev 6905)
+++ tor/trunk/src/or/relay.c	2006-07-26 19:07:26 UTC (rev 6906)
@@ -16,19 +16,19 @@
 
 static int relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction,
                 crypt_path_t **layer_hint, char *recognized);
-static connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell,
+static edge_connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell,
                                        int cell_direction);
 
 static int
 connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
-                                   connection_t *conn,
+                                   edge_connection_t *conn,
                                    crypt_path_t *layer_hint);
 static void
 circuit_consider_sending_sendme(circuit_t *circ, crypt_path_t *layer_hint);
 static void
 circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint);
 static int
-circuit_resume_edge_reading_helper(connection_t *conn,
+circuit_resume_edge_reading_helper(edge_connection_t *conn,
                                    circuit_t *circ,
                                    crypt_path_t *layer_hint);
 static int
@@ -144,7 +144,7 @@
 int
 circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction)
 {
-  connection_t *conn=NULL;
+  or_connection_t *or_conn=NULL;
   crypt_path_t *layer_hint=NULL;
   char recognized=0;
   int reason;
@@ -162,7 +162,7 @@
   }
 
   if (recognized) {
-    conn = relay_lookup_conn(circ, cell, cell_direction);
+    edge_connection_t *conn = relay_lookup_conn(circ, cell, cell_direction);
     if (cell_direction == CELL_DIRECTION_OUT) {
       ++stats_n_relay_cells_delivered;
       log_debug(LD_OR,"Sending away from origin.");
@@ -190,16 +190,16 @@
   /* not recognized. pass it on. */
   if (cell_direction == CELL_DIRECTION_OUT) {
     cell->circ_id = circ->n_circ_id; /* switch it */
-    conn = circ->n_conn;
+    or_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;
+    or_conn = TO_OR_CIRCUIT(circ)->p_conn;
   } else {
     // XXXX NM WARN.
     return 0;
   }
 
-  if (!conn) {
+  if (!or_conn) {
     // XXXX Can this splice stuff be done more cleanly?
     if (! CIRCUIT_IS_ORIGIN(circ) &&
         TO_OR_CIRCUIT(circ)->rend_splice &&
@@ -225,7 +225,7 @@
 
   log_debug(LD_OR,"Passing on unrecognized cell.");
   ++stats_n_relay_cells_relayed;
-  connection_or_write_cell_to_buf(cell, conn);
+  connection_or_write_cell_to_buf(cell, or_conn);
   return 0;
 }
 
@@ -323,7 +323,7 @@
                            int cell_direction,
                            crypt_path_t *layer_hint)
 {
-  connection_t *conn; /* where to send the cell */
+  or_connection_t *conn; /* where to send the cell */
 
   if (cell_direction == CELL_DIRECTION_OUT) {
     crypt_path_t *thishop; /* counter for repeated crypts */
@@ -369,10 +369,10 @@
 /** If cell's stream_id matches the stream_id of any conn that's
  * attached to circ, return that conn, else return NULL.
  */
-static connection_t *
+static edge_connection_t *
 relay_lookup_conn(circuit_t *circ, cell_t *cell, int cell_direction)
 {
-  connection_t *tmpconn;
+  edge_connection_t *tmpconn;
   relay_header_t rh;
 
   relay_header_unpack(&rh, cell->payload);
@@ -387,7 +387,8 @@
   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) {
+      if (rh.stream_id == tmpconn->stream_id &&
+          !tmpconn->_base.marked_for_close) {
         log_debug(LD_APP,"found conn for stream %d.", rh.stream_id);
         return tmpconn;
       }
@@ -395,7 +396,7 @@
   } 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) {
+      if (rh.stream_id == tmpconn->stream_id && !tmpconn->_base.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))
@@ -404,7 +405,7 @@
     }
     for (tmpconn = TO_OR_CIRCUIT(circ)->resolving_streams; tmpconn;
          tmpconn=tmpconn->next_stream) {
-      if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) {
+      if (rh.stream_id == tmpconn->stream_id && !tmpconn->_base.marked_for_close) {
         log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id);
         return tmpconn;
       }
@@ -452,7 +453,7 @@
  * return -1. Else return 0.
  */
 int
-connection_edge_send_command(connection_t *fromconn, circuit_t *circ,
+connection_edge_send_command(edge_connection_t *fromconn, circuit_t *circ,
                              int relay_command, const char *payload,
                              size_t payload_len, crypt_path_t *cpath_layer)
 {
@@ -461,22 +462,22 @@
   int cell_direction;
   /* XXXX NM Split this function into a separate versions per circuit type? */
 
-  if (fromconn && fromconn->marked_for_close) {
+  if (fromconn && fromconn->_base.marked_for_close) {
     log_warn(LD_BUG,
              "Bug: called on conn that's already marked for close at %s:%d.",
-             fromconn->marked_for_close_file, fromconn->marked_for_close);
+             fromconn->_base.marked_for_close_file, fromconn->_base.marked_for_close);
     return 0;
   }
 
   if (!circ) {
     tor_assert(fromconn);
-    if (fromconn->type == CONN_TYPE_AP) {
+    if (fromconn->_base.type == CONN_TYPE_AP) {
       log_info(LD_APP,"no circ. Closing conn.");
       connection_mark_unattached_ap(fromconn, END_STREAM_REASON_INTERNAL);
     } else {
       log_info(LD_EXIT,"no circ. Closing conn.");
-      fromconn->has_sent_end = 1; /* no circ to send to */
-      connection_mark_for_close(fromconn);
+      fromconn->_base.edge_has_sent_end = 1; /* no circ to send to */
+      connection_mark_for_close(TO_CONN(fromconn));
     }
     return -1;
   }
@@ -665,7 +666,7 @@
 static int
 connection_edge_process_end_not_open(
     relay_header_t *rh, cell_t *cell, origin_circuit_t *circ,
-    connection_t *conn, crypt_path_t *layer_hint)
+    edge_connection_t *conn, crypt_path_t *layer_hint)
 {
   struct in_addr in;
   routerinfo_t *exitrouter;
@@ -673,7 +674,7 @@
   (void) layer_hint; /* unused */
 
   if (rh->length > 0 && edge_reason_is_retriable(reason) &&
-      conn->type == CONN_TYPE_AP) {
+      conn->_base.type == CONN_TYPE_AP) {
     log_info(LD_APP,"Address '%s' refused due to '%s'. Considering retrying.",
              safe_str(conn->socks_request->address),
              connection_edge_end_reason_str(reason));
@@ -775,12 +776,12 @@
   log_info(LD_APP,
            "Edge got end (%s) before we're connected. Marking for close.",
        connection_edge_end_reason_str(rh->length > 0 ? reason : -1));
-  if (conn->type == CONN_TYPE_AP) {
+  if (conn->_base.type == CONN_TYPE_AP) {
     circuit_log_path(LOG_INFO,LD_APP,circ);
     connection_mark_unattached_ap(conn, reason);
   } else {
-    conn->has_sent_end = 1; /* we just got an 'end', don't need to send one */
-    connection_mark_for_close(conn);
+    conn->_base.edge_has_sent_end = 1; /* we just got an 'end', don't need to send one */
+    connection_mark_for_close(TO_CONN(conn));
   }
   return 0;
 }
@@ -795,7 +796,7 @@
 static int
 connection_edge_process_relay_cell_not_open(
     relay_header_t *rh, cell_t *cell, circuit_t *circ,
-    connection_t *conn, crypt_path_t *layer_hint)
+    edge_connection_t *conn, crypt_path_t *layer_hint)
 {
   if (rh->command == RELAY_COMMAND_END) {
     if (CIRCUIT_IS_ORIGIN(circ))
@@ -806,17 +807,17 @@
       return 0;
   }
 
-  if (conn->type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_CONNECTED) {
+  if (conn->_base.type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_CONNECTED) {
     tor_assert(CIRCUIT_IS_ORIGIN(circ));
-    if (conn->state != AP_CONN_STATE_CONNECT_WAIT) {
+    if (conn->_base.state != AP_CONN_STATE_CONNECT_WAIT) {
       log_warn(LD_APP,"Got 'connected' while not in state connect_wait. "
                "Dropping.");
       return 0;
     }
 //    log_fn(LOG_INFO,"Connected! Notifying application.");
-    conn->state = AP_CONN_STATE_OPEN;
+    conn->_base.state = AP_CONN_STATE_OPEN;
     log_info(LD_APP,"'connected' received after %d seconds.",
-             (int)(time(NULL) - conn->timestamp_lastread));
+             (int)(time(NULL) - conn->_base.timestamp_lastread));
     if (rh->length >= 4) {
       uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE));
       int ttl;
@@ -840,15 +841,15 @@
     /* handle anything that might have queued */
     if (connection_edge_package_raw_inbuf(conn, 1) < 0) {
       /* (We already sent an end cell if possible) */
-      connection_mark_for_close(conn);
+      connection_mark_for_close(TO_CONN(conn));
       return 0;
     }
     return 0;
   }
-  if (conn->type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_RESOLVED) {
+  if (conn->_base.type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_RESOLVED) {
     int ttl;
     int answer_len;
-    if (conn->state != AP_CONN_STATE_RESOLVE_WAIT) {
+    if (conn->_base.state != AP_CONN_STATE_RESOLVE_WAIT) {
       log_warn(LD_APP,"Got a 'resolved' cell while not in state resolve_wait. "
                "Dropping.");
       return 0;
@@ -877,8 +878,8 @@
 
   log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
          "Got an unexpected relay command %d, in state %d (%s). Dropping.",
-         rh->command, conn->state,
-         conn_state_to_string(conn->type, conn->state));
+         rh->command, conn->_base.state,
+         conn_state_to_string(conn->_base.type, conn->_base.state));
   return 0; /* for forward compatibility, don't kill the circuit */
 //  connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL,
 //                      conn->cpath_layer);
@@ -897,7 +898,7 @@
  */
 static int
 connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
-                                   connection_t *conn,
+                                   edge_connection_t *conn,
                                    crypt_path_t *layer_hint)
 {
   static int num_seen=0;
@@ -922,7 +923,7 @@
   /* either conn is NULL, in which case we've got a control cell, or else
    * conn points to the recognized stream. */
 
-  if (conn && !connection_state_is_open(conn))
+  if (conn && !connection_state_is_open(TO_CONN(conn)))
     return connection_edge_process_relay_cell_not_open(
              &rh, cell, circ, conn, layer_hint);
 
@@ -950,7 +951,7 @@
                "(relay data) circ deliver_window below 0. Killing.");
         connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL,
                             conn->cpath_layer);
-        connection_mark_for_close(conn);
+        connection_mark_for_close(TO_CONN(conn));
         return -END_CIRC_REASON_TORPROTOCOL;
       }
       log_debug(domain,"circ deliver_window now %d.", layer_hint ?
@@ -971,7 +972,7 @@
 
       stats_n_data_bytes_received += rh.length;
       connection_write_to_buf(cell->payload + RELAY_HEADER_SIZE,
-                              rh.length, conn);
+                              rh.length, TO_CONN(conn));
       connection_edge_consider_sending_sendme(conn);
       return 0;
     case RELAY_COMMAND_END:
@@ -983,7 +984,7 @@
       }
 /* XXX add to this log_fn the exit node's nickname? */
       log_info(domain,"%d: end cell (%s) for stream %d. Removing stream.",
-               conn->s,
+               conn->_base.s,
                connection_edge_end_reason_str(rh.length > 0 ?
                  *(char *)(cell->payload+RELAY_HEADER_SIZE) : -1),
                conn->stream_id);
@@ -991,12 +992,12 @@
         log_warn(LD_BUG,
                  "Bug: open stream hasn't sent socks answer yet? Closing.");
       /* We just *got* an end; no reason to send one. */
-      conn->has_sent_end = 1;
-      if (!conn->marked_for_close) {
+      conn->_base.edge_has_sent_end = 1;
+      if (!conn->_base.marked_for_close) {
         /* only mark it if not already marked. it's possible to
          * get the 'end' right around when the client hangs up on us. */
-        connection_mark_for_close(conn);
-        conn->hold_open_until_flushed = 1;
+        connection_mark_for_close(TO_CONN(conn));
+        conn->_base.hold_open_until_flushed = 1;
       }
       return 0;
     case RELAY_COMMAND_EXTEND:
@@ -1076,11 +1077,11 @@
       conn->package_window += STREAMWINDOW_INCREMENT;
       log_debug(domain,"stream-level sendme, packagewindow now %d.",
                 conn->package_window);
-      connection_start_reading(conn);
+      connection_start_reading(TO_CONN(conn));
       /* handle whatever might still be on the inbuf */
       if (connection_edge_package_raw_inbuf(conn, 1) < 0) {
         /* (We already sent an end cell if possible) */
-        connection_mark_for_close(conn);
+        connection_mark_for_close(TO_CONN(conn));
         return 0;
       }
       return 0;
@@ -1139,7 +1140,7 @@
  * be marked for close, else return 0.
  */
 int
-connection_edge_package_raw_inbuf(connection_t *conn, int package_partial)
+connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial)
 {
   size_t amount_to_process, length;
   char payload[CELL_PAYLOAD_SIZE];
@@ -1147,11 +1148,11 @@
   unsigned domain = conn->cpath_layer ? LD_APP : LD_EXIT;
 
   tor_assert(conn);
-  tor_assert(!connection_speaks_cells(conn));
-  if (conn->marked_for_close) {
+
+  if (conn->_base.marked_for_close) {
     log_warn(LD_BUG,
              "Bug: called on conn that's already marked for close at %s:%d.",
-             conn->marked_for_close_file, conn->marked_for_close);
+             conn->_base.marked_for_close_file, conn->_base.marked_for_close);
     return 0;
   }
 
@@ -1169,11 +1170,11 @@
   if (conn->package_window <= 0) {
     log_info(domain,"called with package_window %d. Skipping.",
              conn->package_window);
-    connection_stop_reading(conn);
+    connection_stop_reading(TO_CONN(conn));
     return 0;
   }
 
-  amount_to_process = buf_datalen(conn->inbuf);
+  amount_to_process = buf_datalen(conn->_base.inbuf);
 
   if (!amount_to_process)
     return 0;
@@ -1189,10 +1190,10 @@
   stats_n_data_bytes_packaged += length;
   stats_n_data_cells_packaged += 1;
 
-  connection_fetch_from_buf(payload, length, conn);
+  connection_fetch_from_buf(payload, length, TO_CONN(conn));
 
-  log_debug(domain,"(%d) Packaging %d bytes (%d waiting).", conn->s,
-            (int)length, (int)buf_datalen(conn->inbuf));
+  log_debug(domain,"(%d) Packaging %d bytes (%d waiting).", conn->_base.s,
+            (int)length, (int)buf_datalen(conn->_base.inbuf));
 
   if (connection_edge_send_command(conn, circ, RELAY_COMMAND_DATA,
                                    payload, length, conn->cpath_layer) < 0)
@@ -1208,7 +1209,7 @@
   }
 
   if (--conn->package_window <= 0) { /* is it 0 after decrement? */
-    connection_stop_reading(conn);
+    connection_stop_reading(TO_CONN(conn));
     log_debug(domain,"conn->package_window reached 0.");
     circuit_consider_stop_edge_reading(circ, conn->cpath_layer);
     return 0; /* don't process the inbuf any more */
@@ -1226,11 +1227,11 @@
  * low, send back a suitable number of stream-level sendme cells.
  */
 void
-connection_edge_consider_sending_sendme(connection_t *conn)
+connection_edge_consider_sending_sendme(edge_connection_t *conn)
 {
   circuit_t *circ;
 
-  if (connection_outbuf_too_full(conn))
+  if (connection_outbuf_too_full(TO_CONN(conn)))
     return;
 
   circ = circuit_get_by_edge_conn(conn);
@@ -1244,7 +1245,7 @@
   while (conn->deliver_window < STREAMWINDOW_START - STREAMWINDOW_INCREMENT) {
     log_debug(conn->cpath_layer?LD_APP:LD_EXIT,
               "Outbuf %d, Queueing stream sendme.",
-              (int)conn->outbuf_flushlen);
+              (int)conn->_base.outbuf_flushlen);
     conn->deliver_window += STREAMWINDOW_INCREMENT;
     if (connection_edge_send_command(conn, circ, RELAY_COMMAND_SENDME,
                                      NULL, 0, conn->cpath_layer) < 0) {
@@ -1278,21 +1279,21 @@
  * of a linked list of edge streams that should each be considered.
  */
 static int
-circuit_resume_edge_reading_helper(connection_t *conn,
+circuit_resume_edge_reading_helper(edge_connection_t *conn,
                                    circuit_t *circ,
                                    crypt_path_t *layer_hint)
 {
   for ( ; conn; conn=conn->next_stream) {
-    if (conn->marked_for_close)
+    if (conn->_base.marked_for_close)
       continue;
     if ((!layer_hint && conn->package_window > 0) ||
         (layer_hint && conn->package_window > 0 &&
          conn->cpath_layer == layer_hint)) {
-      connection_start_reading(conn);
+      connection_start_reading(TO_CONN(conn));
       /* handle whatever might still be on the inbuf */
       if (connection_edge_package_raw_inbuf(conn, 1)<0) {
         /* (We already sent an end cell if possible) */
-        connection_mark_for_close(conn);
+        connection_mark_for_close(TO_CONN(conn));
         continue;
       }
 
@@ -1315,7 +1316,7 @@
 static int
 circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint)
 {
-  connection_t *conn = NULL;
+  edge_connection_t *conn = NULL;
   unsigned domain = layer_hint ? LD_APP : LD_EXIT;
 
   if (!layer_hint) {
@@ -1325,7 +1326,7 @@
     if (circ->package_window <= 0) {
       log_debug(domain,"yes, not-at-origin. stopped.");
       for (conn = or_circ->n_streams; conn; conn=conn->next_stream)
-        connection_stop_reading(conn);
+        connection_stop_reading(TO_CONN(conn));
       return 1;
     }
     return 0;
@@ -1344,7 +1345,7 @@
     for (conn = TO_ORIGIN_CIRCUIT(circ)->p_streams; conn;
          conn=conn->next_stream)
       if (conn->cpath_layer == layer_hint)
-        connection_stop_reading(conn);
+        connection_stop_reading(TO_CONN(conn));
     return 1;
   }
   return 0;

Modified: tor/trunk/src/or/rendclient.c
===================================================================
--- tor/trunk/src/or/rendclient.c	2006-07-26 19:07:23 UTC (rev 6905)
+++ tor/trunk/src/or/rendclient.c	2006-07-26 19:07:26 UTC (rev 6906)
@@ -430,7 +430,7 @@
 void
 rend_client_desc_here(const char *query)
 {
-  connection_t *conn;
+  edge_connection_t *conn;
   rend_cache_entry_t *entry;
   time_t now = time(NULL);
   int i, n_conns;
@@ -439,25 +439,26 @@
   get_connection_array(&carray, &n_conns);
 
   for (i = 0; i < n_conns; ++i) {
-    conn = carray[i];
-    if (conn->type != CONN_TYPE_AP ||
-        conn->state != AP_CONN_STATE_RENDDESC_WAIT ||
-        conn->marked_for_close ||
-        rend_cmp_service_ids(query, conn->rend_query))
+    if (carray[i]->type != CONN_TYPE_AP ||
+        carray[i]->state != AP_CONN_STATE_RENDDESC_WAIT ||
+        carray[i]->marked_for_close)
       continue;
-    assert_connection_ok(conn, now);
+    conn = TO_EDGE_CONN(carray[i]);
+    if (rend_cmp_service_ids(query, conn->rend_query))
+      continue;
+    assert_connection_ok(TO_CONN(conn), now);
     if (rend_cache_lookup_entry(conn->rend_query, -1, &entry) == 1 &&
         entry->parsed->n_intro_points > 0) {
       /* either this fetch worked, or it failed but there was a
        * valid entry from before which we should reuse */
       log_info(LD_REND,"Rend desc is usable. Launching circuits.");
-      conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
+      conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
 
       /* restart their timeout values, so they get a fair shake at
        * connecting to the hidden service. */
-      conn->timestamp_created = now;
-      conn->timestamp_lastread = now;
-      conn->timestamp_lastwritten = now;
+      conn->_base.timestamp_created = now;
+      conn->_base.timestamp_lastread = now;
+      conn->_base.timestamp_lastwritten = now;
 
       if (connection_ap_handshake_attach_circuit(conn) < 0) {
         /* it will never work */

Modified: tor/trunk/src/or/rendservice.c
===================================================================
--- tor/trunk/src/or/rendservice.c	2006-07-26 19:07:23 UTC (rev 6905)
+++ tor/trunk/src/or/rendservice.c	2006-07-26 19:07:26 UTC (rev 6906)
@@ -1121,7 +1121,7 @@
  * or 0 for success.
  */
 int
-rend_service_set_connection_addr_port(connection_t *conn,
+rend_service_set_connection_addr_port(edge_connection_t *conn,
                                       origin_circuit_t *circ)
 {
   rend_service_t *service;
@@ -1142,14 +1142,14 @@
   }
   for (i = 0; i < smartlist_len(service->ports); ++i) {
     p = smartlist_get(service->ports, i);
-    if (conn->port == p->virtual_port) {
-      conn->addr = p->real_addr;
-      conn->port = p->real_port;
+    if (conn->_base.port == p->virtual_port) {
+      conn->_base.addr = p->real_addr;
+      conn->_base.port = p->real_port;
       return 0;
     }
   }
   log_info(LD_REND, "No virtual port mapping exists for port %d on service %s",
-           conn->port,serviceid);
+           conn->_base.port,serviceid);
   return -1;
 }
 

Modified: tor/trunk/src/or/router.c
===================================================================
--- tor/trunk/src/or/router.c	2006-07-26 19:07:23 UTC (rev 6905)
+++ tor/trunk/src/or/router.c	2006-07-26 19:07:26 UTC (rev 6906)
@@ -650,16 +650,16 @@
  * conn.  Return 0 if we accept; non-0 if we reject.
  */
 int
-router_compare_to_my_exit_policy(connection_t *conn)
+router_compare_to_my_exit_policy(edge_connection_t *conn)
 {
   tor_assert(desc_routerinfo);
 
   /* make sure it's resolved to something. this way we can't get a
      'maybe' below. */
-  if (!conn->addr)
+  if (!conn->_base.addr)
     return -1;
 
-  return compare_addr_to_addr_policy(conn->addr, conn->port,
+  return compare_addr_to_addr_policy(conn->_base.addr, conn->_base.port,
                    desc_routerinfo->exit_policy) != ADDR_POLICY_ACCEPTED;
 }
 

Modified: tor/trunk/src/or/routerlist.c
===================================================================
--- tor/trunk/src/or/routerlist.c	2006-07-26 19:07:23 UTC (rev 6905)
+++ tor/trunk/src/or/routerlist.c	2006-07-26 19:07:26 UTC (rev 6906)
@@ -1705,13 +1705,13 @@
         /* mark-for-close connections using the old key, so we can
          * make new ones with the new key.
          */
-        connection_t *conn;
+        or_connection_t *conn;
         while ((conn = connection_or_get_by_identity_digest(
                       old_router->cache_info.identity_digest))) {
           log_info(LD_DIR,"Closing conn to router '%s'; there is now a named "
                    "router with that name.",
                    old_router->nickname);
-          connection_mark_for_close(conn);
+          connection_mark_for_close(TO_CONN(conn));
         }
         routerlist_remove(routerlist, old_router, i--, 0);
       } else if (old_router->is_named) {
@@ -3317,8 +3317,9 @@
     if (conn->type == CONN_TYPE_DIR &&
         conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC &&
         !conn->marked_for_close) {
-      if (!strcmpstart(conn->requested_resource, prefix))
-        dir_split_resource_into_fingerprints(conn->requested_resource+p_len,
+      dir_connection_t *dir_conn = TO_DIR_CONN(conn);
+      if (!strcmpstart(dir_conn->requested_resource, prefix))
+        dir_split_resource_into_fingerprints(dir_conn->requested_resource+p_len,
                                              tmp, NULL, 1, 0);
     }
   }