]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
divorce circuit building from user connections
authorRoger Dingledine <arma@torproject.org>
Wed, 16 Apr 2003 06:18:31 +0000 (06:18 +0000)
committerRoger Dingledine <arma@torproject.org>
Wed, 16 Apr 2003 06:18:31 +0000 (06:18 +0000)
now we rebuild the circuit periodically (but only if it's been used),
and we can further abstract it to do incremental circuit building, etc.

svn:r233

src/or/circuit.c
src/or/config.c
src/or/connection_ap.c
src/or/connection_or.c
src/or/main.c
src/or/onion.c
src/or/or.h
src/or/test.c

index 593c5bddf372929819ee0beb0425e774df6ff95e..2157be0f2646927699f7a321e020e922710c9bfe 100644 (file)
@@ -4,6 +4,8 @@
 
 #include "or.h"
 
+extern or_options_t options; /* command-line and config-file options */
+
 /********* START VARIABLES **********/
 
 static circuit_t *global_circuitlist=NULL;
@@ -49,12 +51,18 @@ void circuit_remove(circuit_t *circ) {
 
 circuit_t *circuit_new(aci_t p_aci, connection_t *p_conn) {
   circuit_t *circ; 
+  struct timeval now;
+
+  if(gettimeofday(&now,NULL) < 0)
+    return NULL;
 
   circ = (circuit_t *)malloc(sizeof(circuit_t));
   if(!circ)
     return NULL;
   memset(circ,0,sizeof(circuit_t)); /* zero it out */
 
+  circ->timestamp_created = now.tv_sec;
+
   circ->p_aci = p_aci;
   circ->p_conn = p_conn;
 
@@ -252,20 +260,24 @@ circuit_t *circuit_get_by_conn(connection_t *conn) {
   return NULL;
 }
 
-circuit_t *circuit_get_by_edge_type(char edge_type) {
-  circuit_t *circ;
+circuit_t *circuit_get_newest_by_edge_type(char edge_type) {
+  circuit_t *circ, *bestcirc=NULL;
 
   for(circ=global_circuitlist;circ;circ = circ->next) {
-    if(edge_type == EDGE_AP && circ->n_conn && circ->n_conn->type == CONN_TYPE_OR) {
-      log(LOG_DEBUG,"circuit_get_by_edge_type(): Choosing n_aci %d.", circ->n_aci);
-      return circ;
+    if(edge_type == EDGE_AP && (!circ->p_conn || circ->p_conn->type == CONN_TYPE_AP)) {
+      if(!bestcirc ||
+        (circ->state == CIRCUIT_STATE_OPEN && bestcirc->timestamp_created < circ->timestamp_created)) {
+        log(LOG_DEBUG,"circuit_get_newest_by_edge_type(): Choosing n_aci %d.", circ->n_aci);
+        bestcirc = circ;
+      }
     }
-    if(edge_type == EDGE_EXIT && circ->p_conn && circ->p_conn->type == CONN_TYPE_OR) {
-      return circ;
+    if(edge_type == EDGE_EXIT && (!circ->n_conn || circ->n_conn->type == CONN_TYPE_EXIT)) {
+      if(!bestcirc ||
+        (circ->state == CIRCUIT_STATE_OPEN && bestcirc->timestamp_created < circ->timestamp_created))
+        bestcirc = circ;
     }
-    log(LOG_DEBUG,"circuit_get_by_edge_type(): Skipping p_aci %d / n_aci %d.", circ->p_aci, circ->n_aci);
   }
-  return NULL;
+  return bestcirc;
 }
 
 int circuit_deliver_data_cell_from_edge(cell_t *cell, circuit_t *circ, char edge_type) {
@@ -517,8 +529,11 @@ int circuit_consider_sending_sendme(circuit_t *circ, int edge_type) {
 
 void circuit_close(circuit_t *circ) {
   connection_t *conn;
+  circuit_t *youngest;
 
   assert(circ);
+  if(options.APPort)
+    youngest = circuit_get_newest_by_edge_type(EDGE_AP);
   circuit_remove(circ);
   for(conn=circ->n_conn; conn; conn=conn->next_topic) {
     connection_send_destroy(circ->n_aci, circ->n_conn); 
@@ -526,6 +541,11 @@ void circuit_close(circuit_t *circ) {
   for(conn=circ->p_conn; conn; conn=conn->next_topic) {
     connection_send_destroy(circ->p_aci, circ->p_conn); 
   }
+  if(options.APPort && youngest == circ) { /* check this after we've sent the destroys, to reduce races */
+    /* our current circuit just died. Launch another one pronto. */
+    log(LOG_INFO,"circuit_close(): Youngest circuit dying. Launching a replacement.");
+    circuit_launch_new(1);
+  }
   circuit_free(circ);
 }
 
@@ -610,6 +630,210 @@ void circuit_dump_by_conn(connection_t *conn) {
   }
 }
 
+void circuit_expire_unused_circuits(void) {
+  circuit_t *circ, *tmpcirc;
+  circuit_t *youngest;
+
+  youngest = circuit_get_newest_by_edge_type(EDGE_AP);
+
+  circ = global_circuitlist;
+  while(circ) {
+    tmpcirc = circ;
+    circ = circ->next;
+    if(tmpcirc != youngest && (!tmpcirc->p_conn || tmpcirc->p_conn->type == CONN_TYPE_AP)) {
+      log(LOG_DEBUG,"circuit_expire_unused_circuits(): Closing n_aci %d",tmpcirc->n_aci);
+      circuit_close(tmpcirc);
+    }
+  }
+}
+
+/* failure_status code: negative means reset failures to 0. Other values mean
+ * add that value to the current number of failures, then if we don't have too
+ * many failures on record, try to make a new circuit.
+ */
+void circuit_launch_new(int failure_status) {
+  static int failures=0;
+
+  if(failure_status == -1) { /* I was called because a circuit succeeded */
+    failures = 0;
+    return;
+  }
+
+  failures += failure_status;
+
+retry_circuit:
+
+  if(failures > 5) {
+    log(LOG_INFO,"circuit_launch_new(): Giving up, %d failures.", failures);
+    return;
+  }
+
+  if(circuit_create_onion() < 0) {
+    failures++;
+    goto retry_circuit;
+  }
+
+  failures = 0;
+  return;
+}
+
+int circuit_create_onion(void) {
+  int i;
+  int routelen; /* length of the route */
+  unsigned int *route; /* hops in the route as an array of indexes into rarray */
+  unsigned char *onion; /* holds the onion */
+  int onionlen; /* onion length in host order */
+  crypt_path_t **cpath; /* defines the crypt operations that need to be performed on incoming/outgoing data */
+
+  /* choose a route */
+  route = (unsigned int *)router_new_route(&routelen);
+  if (!route) { 
+    log(LOG_ERR,"circuit_create_onion(): Error choosing a route through the OR network.");
+    return -1;
+  }
+  log(LOG_DEBUG,"circuit_create_onion(): Chosen a route of length %u : ",routelen);
+
+  /* allocate memory for the crypt path */
+  cpath = malloc(routelen * sizeof(crypt_path_t *));
+  if (!cpath) { 
+    log(LOG_ERR,"circuit_create_onion(): Error allocating memory for cpath.");
+    free(route);
+    return -1;
+  }
+
+  /* create an onion and calculate crypto keys */
+  onion = router_create_onion(route,routelen,&onionlen,cpath);
+  if (!onion) {
+    log(LOG_ERR,"circuit_create_onion(): Error creating an onion.");
+    free(route);
+    free(cpath); /* it's got nothing in it, since !onion */
+    return -1;
+  }
+  log(LOG_DEBUG,"circuit_create_onion(): Created an onion of size %u bytes.",onionlen);
+  log(LOG_DEBUG,"circuit_create_onion(): Crypt path :");
+  for (i=0;i<routelen;i++) {
+    log(LOG_DEBUG,"circuit_create_onion() : %u/%u",(cpath[i])->forwf, (cpath[i])->backf);
+  }
+
+  return circuit_establish_circuit(route, routelen, onion, onionlen, cpath);
+}
+
+int circuit_establish_circuit(unsigned int *route, int routelen, char *onion,
+                                   int onionlen, crypt_path_t **cpath) {
+  routerinfo_t *firsthop;
+  connection_t *n_conn;
+  circuit_t *circ;
+
+  /* now see if we're already connected to the first OR in 'route' */
+  firsthop = router_get_first_in_route(route, routelen);
+  assert(firsthop); /* should always be defined */
+  free(route); /* we don't need it anymore */
+
+  circ = circuit_new(0, NULL); /* sets circ->p_aci and circ->p_conn */
+  circ->state = CIRCUIT_STATE_OR_WAIT;
+  circ->onion = onion;
+  circ->onionlen = onionlen;
+  circ->cpath = cpath;
+  circ->cpathlen = routelen;
+
+  log(LOG_DEBUG,"circuit_establish_circuit(): Looking for firsthop '%s:%u'",
+      firsthop->address,firsthop->or_port);
+  n_conn = connection_twin_get_by_addr_port(firsthop->addr,firsthop->or_port);
+  if(!n_conn || n_conn->state != OR_CONN_STATE_OPEN) { /* not currently connected */
+    circ->n_addr = firsthop->addr;
+    circ->n_port = firsthop->or_port;
+    if(options.ORPort) { /* we would be connected if he were up. but he's not. */
+      log(LOG_DEBUG,"circuit_establish_circuit(): Route's firsthop isn't connected.");
+      circuit_close(circ); 
+      return -1;
+    }
+
+    if(!n_conn) { /* launch the connection */
+      n_conn = connection_or_connect_as_op(firsthop);
+      if(!n_conn) { /* connect failed, forget the whole thing */
+        log(LOG_DEBUG,"circuit_establish_circuit(): connect to firsthop failed. Closing.");
+        circuit_close(circ);
+        return -1;
+      }
+    }
+
+    return 0; /* return success. The onion/circuit/etc will be taken care of automatically
+               * (may already have been) whenever n_conn reaches OR_CONN_STATE_OPEN.
+               */ 
+  } else { /* it (or a twin) is already open. use it. */
+    circ->n_addr = n_conn->addr;
+    circ->n_port = n_conn->port;
+    return circuit_send_onion(n_conn, circ);
+  }
+}
+
+/* find circuits that are waiting on me, if any, and get them to send the onion */
+void circuit_n_conn_open(connection_t *or_conn) {
+  circuit_t *circ;
+
+  log(LOG_DEBUG,"circuit_n_conn_open(): Starting.");
+  circ = circuit_enumerate_by_naddr_nport(NULL, or_conn->addr, or_conn->port);
+  for(;;) {
+    if(!circ)
+      return;
+
+    log(LOG_DEBUG,"circuit_n_conn_open(): Found circ, sending onion.");
+    if(circuit_send_onion(or_conn, circ) < 0) {
+      log(LOG_DEBUG,"circuit_n_conn_open(): circuit marked for closing.");
+      circuit_close(circ);
+      return; /* FIXME will want to try the other circuits too? */
+    }
+    circ = circuit_enumerate_by_naddr_nport(circ, or_conn->addr, or_conn->port);
+  }
+}
+
+int circuit_send_onion(connection_t *n_conn, circuit_t *circ) {
+  cell_t cell;
+  int tmpbuflen, dataleft;
+  char *tmpbuf;
+
+  circ->n_aci = get_unique_aci_by_addr_port(circ->n_addr, circ->n_port, ACI_TYPE_BOTH);
+  circ->n_conn = n_conn;
+  log(LOG_DEBUG,"circuit_send_onion(): n_conn is %s:%u",n_conn->address,n_conn->port);
+
+  /* deliver the onion as one or more create cells */
+  cell.command = CELL_CREATE;
+  cell.aci = circ->n_aci;
+
+  tmpbuflen = circ->onionlen+4;
+  tmpbuf = malloc(tmpbuflen);
+  if(!tmpbuf)
+    return -1;
+  *(uint32_t*)tmpbuf = htonl(circ->onionlen);
+  memcpy(tmpbuf+4, circ->onion, circ->onionlen);
+
+  dataleft = tmpbuflen;
+  while(dataleft) {
+    cell.command = CELL_CREATE;
+    cell.aci = circ->n_aci;
+    log(LOG_DEBUG,"circuit_send_onion(): Sending a create cell for the onion...");
+    if(dataleft >= CELL_PAYLOAD_SIZE) {
+      cell.length = CELL_PAYLOAD_SIZE;
+      memcpy(cell.payload, tmpbuf + tmpbuflen - dataleft, CELL_PAYLOAD_SIZE);
+      connection_write_cell_to_buf(&cell, n_conn);
+      dataleft -= CELL_PAYLOAD_SIZE;
+    } else { /* last cell */
+      cell.length = dataleft;
+      memcpy(cell.payload, tmpbuf + tmpbuflen - dataleft, dataleft);
+      /* fill extra space with 0 bytes */
+      memset(cell.payload + dataleft, 0, CELL_PAYLOAD_SIZE - dataleft);
+      connection_write_cell_to_buf(&cell, n_conn);
+      dataleft = 0;
+    }
+  }
+  free(tmpbuf);
+
+  circ->state = CIRCUIT_STATE_OPEN;
+  /* FIXME should set circ->expire to something here */
+
+  return 0;
+}
+
 /*
   Local Variables:
   mode:c
index d8828bdd3b7a8ba62f0156cd9df6677b7d1c8195..f6c0bda5423440e233d085c0221dca4d9c227370 100644 (file)
@@ -187,6 +187,7 @@ void config_assign(or_options_t *options, struct config_line *list) {
     config_compare(list, "DirFetchPeriod",  CONFIG_TYPE_INT, &options->DirFetchPeriod) ||
     config_compare(list, "KeepalivePeriod", CONFIG_TYPE_INT, &options->KeepalivePeriod) ||
     config_compare(list, "MaxOnionsPending",CONFIG_TYPE_INT, &options->MaxOnionsPending) ||
+    config_compare(list, "NewCircuitPeriod",CONFIG_TYPE_INT, &options->NewCircuitPeriod) ||
 
     config_compare(list, "Daemon",          CONFIG_TYPE_BOOL, &options->Daemon) ||
     config_compare(list, "TrafficShaping",  CONFIG_TYPE_BOOL, &options->TrafficShaping) ||
@@ -224,6 +225,7 @@ int getconfig(int argc, char **argv, or_options_t *options) {
   options->DirFetchPeriod = 600;
   options->KeepalivePeriod = 300;
   options->MaxOnionsPending = 10;
+  options->NewCircuitPeriod = 60; /* once a minute */
 //  options->ReconnectPeriod = 6001;
 
 /* get config lines from /etc/torrc and assign them */
index 831dd9b16f7632f1c46cd6732377c5cdba983763..2a98537b80d811189f427278c735381fdbad6a0a 100644 (file)
@@ -4,8 +4,6 @@
 
 #include "or.h"
 
-extern or_options_t options; /* command-line and config-file options */
-
 int ap_handshake_process_socks(connection_t *conn) {
   char c;
   socks4_t socks4_info; 
@@ -96,211 +94,25 @@ int ap_handshake_process_socks(connection_t *conn) {
   }
 
   /* find the circuit that we should use, if there is one. */
-  circ = circuit_get_by_edge_type(EDGE_AP);
+  circ = circuit_get_newest_by_edge_type(EDGE_AP);
+  circ->dirty = 1;
 
   /* now we're all ready to make an onion or send a begin */
 
-  if(circ && circ->state == CIRCUIT_STATE_OPEN) {
-    /* FIXME if circ not yet open, figure out how to queue this begin? */
-    /* add it into the linked list of topics on this circuit */
-    log(LOG_DEBUG,"ap_handshake_process_socks(): attaching new conn to circ. n_aci %d.", circ->n_aci);
-    conn->next_topic = circ->p_conn;
-    circ->p_conn = conn;
-
-    if(ap_handshake_send_begin(conn, circ) < 0) {
-      circuit_close(circ);
-      return -1;
-    }
-  } else {
-    if(ap_handshake_create_onion(conn) < 0) {
-      if(circ)
-        circuit_close(circ);
-      return -1;
-    }
-  }
-  return 0;
-}
-
-int ap_handshake_create_onion(connection_t *conn) {
-  int i;
-  int routelen = 0; /* length of the route */
-  unsigned int *route = NULL; /* hops in the route as an array of indexes into rarray */
-  unsigned char *onion = NULL; /* holds the onion */
-  int onionlen = 0; /* onion length in host order */
-  crypt_path_t **cpath = NULL; /* defines the crypt operations that need to be performed on incoming/outgoing data */
-
-  assert(conn);
-
-  /* choose a route */
-  route = (unsigned int *)router_new_route(&routelen);
-  if (!route) { 
-    log(LOG_ERR,"ap_handshake_create_onion(): Error choosing a route through the OR network.");
+  if(!circ) {
+    log(LOG_INFO,"ap_handshake_process_socks(): No circuit ready. Closing.");
     return -1;
   }
-  log(LOG_DEBUG,"ap_handshake_create_onion(): Chosen a route of length %u : ",routelen);
-#if 0
-  for (i=routelen-1;i>=0;i--)
-  { 
-    log(LOG_DEBUG,"ap_handshake_process_ss() : %u : %s:%u, %u",routelen-i,(routerarray[route[i]])->address,ntohs((routerarray[route[i]])->port),RSA_size((routerarray[route[i]])->pkey));
-  }
-#endif
 
-  /* allocate memory for the crypt path */
-  cpath = malloc(routelen * sizeof(crypt_path_t *));
-  if (!cpath) { 
-    log(LOG_ERR,"ap_handshake_create_onion(): Error allocating memory for cpath.");
-    free(route);
-    return -1;
-  }
+  /* add it into the linked list of topics on this circuit */
+  log(LOG_DEBUG,"ap_handshake_process_socks(): attaching new conn to circ. n_aci %d.", circ->n_aci);
+  conn->next_topic = circ->p_conn;
+  circ->p_conn = conn;
 
-  /* create an onion and calculate crypto keys */
-  onion = router_create_onion(route,routelen,&onionlen,cpath);
-  if (!onion) {
-    log(LOG_ERR,"ap_handshake_create_onion(): Error creating an onion.");
-    free(route);
-    free(cpath); /* it's got nothing in it, since !onion */
+  if(ap_handshake_send_begin(conn, circ) < 0) {
+    circuit_close(circ);
     return -1;
   }
-  log(LOG_DEBUG,"ap_handshake_create_onion(): Created an onion of size %u bytes.",onionlen);
-  log(LOG_DEBUG,"ap_handshake_create_onion(): Crypt path :");
-  for (i=0;i<routelen;i++) {
-    log(LOG_DEBUG,"ap_handshake_create_onion() : %u/%u",(cpath[i])->forwf, (cpath[i])->backf);
-  }
-
-  return ap_handshake_establish_circuit(conn, route, routelen, onion, onionlen, cpath);
-}
-
-int ap_handshake_establish_circuit(connection_t *conn, unsigned int *route, int routelen, char *onion,
-                                   int onionlen, crypt_path_t **cpath) {
-  routerinfo_t *firsthop;
-  connection_t *n_conn;
-  circuit_t *circ;
-
-  /* now see if we're already connected to the first OR in 'route' */
-  firsthop = router_get_first_in_route(route, routelen);
-  assert(firsthop); /* should always be defined */
-  free(route); /* we don't need it anymore */
-
-  circ = circuit_new(0, conn); /* sets circ->p_aci and circ->p_conn */
-  circ->state = CIRCUIT_STATE_OR_WAIT;
-  circ->onion = onion;
-  circ->onionlen = onionlen;
-  circ->cpath = cpath;
-  circ->cpathlen = routelen;
-
-  log(LOG_DEBUG,"ap_handshake_establish_circuit(): Looking for firsthop '%s:%u'",
-      firsthop->address,firsthop->or_port);
-  n_conn = connection_twin_get_by_addr_port(firsthop->addr,firsthop->or_port);
-  if(!n_conn || n_conn->state != OR_CONN_STATE_OPEN) { /* not currently connected */
-    circ->n_addr = firsthop->addr;
-    circ->n_port = firsthop->or_port;
-    if(options.ORPort) { /* we would be connected if he were up. but he's not. */
-      log(LOG_DEBUG,"ap_handshake_establish_circuit(): Route's firsthop isn't connected.");
-      circuit_close(circ); 
-      return -1;
-    }
-
-    conn->state = AP_CONN_STATE_OR_WAIT;
-    connection_stop_reading(conn); /* Stop listening for input from the AP! */
-
-    if(!n_conn) { /* launch the connection */
-      n_conn = connection_or_connect_as_op(firsthop);
-      if(!n_conn) { /* connect failed, forget the whole thing */
-        log(LOG_DEBUG,"ap_handshake_establish_circuit(): connect to firsthop failed. Closing.");
-        circuit_close(circ);
-        return -1;
-      }   
-    }
-
-    return 0; /* return success. The onion/circuit/etc will be taken care of automatically
-               * (may already have been) whenever n_conn reaches OR_CONN_STATE_OPEN.
-               */ 
-  } else { /* it (or a twin) is already open. use it. */
-    circ->n_addr = n_conn->addr;
-    circ->n_port = n_conn->port;
-    return ap_handshake_send_onion(conn, n_conn, circ);
-  }
-}
-
-/* find circuits that are waiting on me, if any, and get them to send the onion */
-void ap_handshake_n_conn_open(connection_t *or_conn) {
-  circuit_t *circ;
-  connection_t *p_conn;
-
-  log(LOG_DEBUG,"ap_handshake_n_conn_open(): Starting.");
-  circ = circuit_enumerate_by_naddr_nport(NULL, or_conn->addr, or_conn->port);
-  for(;;) {
-    if(!circ)
-      return;
-
-    p_conn = circ->p_conn;
-    if(p_conn->state != AP_CONN_STATE_OR_WAIT) {
-      log(LOG_WARNING,"Bug: ap_handshake_n_conn_open() got an ap_conn not in OR_WAIT state.");
-    }
-    connection_start_reading(p_conn); /* resume listening for reads */
-    log(LOG_DEBUG,"ap_handshake_n_conn_open(): Found circ, sending onion.");
-    if(ap_handshake_send_onion(p_conn, or_conn, circ) < 0) {
-      log(LOG_DEBUG,"ap_handshake_n_conn_open(): circuit marked for closing.");
-      circuit_close(circ);
-      return; /* FIXME will want to try the other circuits too? */
-    }
-    for(p_conn = p_conn->next_topic; p_conn; p_conn = p_conn->next_topic) { /* start up any other pending topics */
-      if(ap_handshake_send_begin(p_conn, circ) < 0) {
-        circuit_close(circ);
-        return;
-      }
-    }
-    circ = circuit_enumerate_by_naddr_nport(circ, or_conn->addr, or_conn->port);
-  }
-}
-
-int ap_handshake_send_onion(connection_t *ap_conn, connection_t *n_conn, circuit_t *circ) {
-  cell_t cell;
-  int tmpbuflen, dataleft;
-  char *tmpbuf;
-
-  circ->n_aci = get_unique_aci_by_addr_port(circ->n_addr, circ->n_port, ACI_TYPE_BOTH);
-  circ->n_conn = n_conn;
-  log(LOG_DEBUG,"ap_handshake_send_onion(): n_conn is %s:%u",n_conn->address,n_conn->port);
-
-  /* deliver the onion as one or more create cells */
-  cell.command = CELL_CREATE;
-  cell.aci = circ->n_aci;
-
-  tmpbuflen = circ->onionlen+4;
-  tmpbuf = malloc(tmpbuflen);
-  if(!tmpbuf)
-    return -1;
-  *(uint32_t*)tmpbuf = htonl(circ->onionlen);
-  memcpy(tmpbuf+4, circ->onion, circ->onionlen);
-
-  dataleft = tmpbuflen;
-  while(dataleft) {
-    cell.command = CELL_CREATE;
-    cell.aci = circ->n_aci;
-    log(LOG_DEBUG,"ap_handshake_send_onion(): Sending a create cell for the onion...");
-    if(dataleft >= CELL_PAYLOAD_SIZE) {
-      cell.length = CELL_PAYLOAD_SIZE;
-      memcpy(cell.payload, tmpbuf + tmpbuflen - dataleft, CELL_PAYLOAD_SIZE);
-      connection_write_cell_to_buf(&cell, n_conn);
-      dataleft -= CELL_PAYLOAD_SIZE;
-    } else { /* last cell */
-      cell.length = dataleft;
-      memcpy(cell.payload, tmpbuf + tmpbuflen - dataleft, dataleft);
-      /* fill extra space with 0 bytes */
-      memset(cell.payload + dataleft, 0, CELL_PAYLOAD_SIZE - dataleft);
-      connection_write_cell_to_buf(&cell, n_conn);
-      dataleft = 0;
-    }
-  }
-  free(tmpbuf);
-
-  if(ap_handshake_send_begin(ap_conn, circ) < 0) {
-    return -1;
-  }
-
-  circ->state = CIRCUIT_STATE_OPEN;
-  /* FIXME should set circ->expire to something here */
 
   return 0;
 }
index 9cac2c9caeba47944daa7162995bf141a8133f8d..15ad3839d6c8e732973adbe54a514b76da438cd9 100644 (file)
@@ -334,7 +334,7 @@ int or_handshake_op_finished_sending_keys(connection_t *conn) {
   conn_or_init_crypto(conn);
 
   connection_or_set_open(conn);
-  ap_handshake_n_conn_open(conn); /* send the pending onions */
+  circuit_n_conn_open(conn); /* send the pending onion(s) */
   return 0;
 }
 
index 44660362708209f9b3144c5ac3315ef1dcc1455b..023836d4bf3c13b77a0fd13abbe5f550cfbbab86 100644 (file)
@@ -302,8 +302,10 @@ int prepare_for_poll(int *timeout) {
   struct timeval now; //soonest;
   static long current_second = 0; /* from previous calls to gettimeofday */
   static long time_to_fetch_directory = 0;
+  static long time_to_new_circuit = 0;
 //  int ms_until_conn;
   cell_t cell;
+  circuit_t *circ;
 
   if(gettimeofday(&now,NULL) < 0)
     return -1;
@@ -321,6 +323,17 @@ int prepare_for_poll(int *timeout) {
       }
     }
 
+    if(options.APPort && time_to_new_circuit < now.tv_sec) {
+      circuit_expire_unused_circuits();
+      circuit_launch_new(-1); /* tell it to forget about previous failures */
+      circ = circuit_get_newest_by_edge_type(EDGE_AP);
+      if(!circ || circ->dirty) {
+        log(LOG_INFO,"prepare_for_poll(): Youngest circuit missing or dirty; launching replacement.");
+        circuit_launch_new(0); /* make an onion and lay the circuit */
+      }
+      time_to_new_circuit = now.tv_sec + options.NewCircuitPeriod;
+    }
+
     /* do housekeeping for each connection */
     for(i=0;i<nfds;i++) {
       tmpconn = connection_array[i];
@@ -514,7 +527,7 @@ static void catch(int the_signal) {
   }
 }
 
-void dumpstats (void) { /* dump stats to stdout */
+void dumpstats(void) { /* dump stats to stdout */
   int i;
   connection_t *conn;
   struct timeval now;
@@ -638,7 +651,7 @@ void dump_directory_to_string(char *s, int maxlen) {
 
 }
 
-void daemonize() {
+void daemonize(void) {
   /* Fork; parent exits. */
   if (fork())
     exit(0);
index 6d920052af27ef10b78c9b9aa9b7d4c41b956c33..d2cc6839b3abd4c48acd4c54d31dd1ec48484312 100644 (file)
@@ -337,9 +337,9 @@ unsigned int *new_route(double cw, routerinfo_t **rarray, int rarray_len, int *r
 {
   int i, j;
   int num_acceptable_routers;
-  unsigned int *route = NULL;
+  unsigned int *route;
   unsigned int oldchoice, choice;
-  
+
   assert((cw >= 0) && (cw < 1) && (rarray) && (routelen) ); /* valid parameters */
 
   *routelen = chooselen(cw);
@@ -351,6 +351,11 @@ unsigned int *new_route(double cw, routerinfo_t **rarray, int rarray_len, int *r
 
   num_acceptable_routers = count_acceptable_routers(rarray, rarray_len);
 
+  if(num_acceptable_routers < 2) {
+    log(LOG_INFO,"new_route(): Not enough acceptable routers. Failing.");
+    return NULL;
+  }
+
   if(num_acceptable_routers < *routelen) {
     log(LOG_DEBUG,"new_route(): Cutting routelen from %d to %d.",*routelen, num_acceptable_routers);
     *routelen = num_acceptable_routers;
@@ -399,13 +404,16 @@ unsigned int *new_route(double cw, routerinfo_t **rarray, int rarray_len, int *r
 static int count_acceptable_routers(routerinfo_t **rarray, int rarray_len) {
   int i, j;
   int num=0;
+  connection_t *conn;
 
   for(i=0;i<rarray_len;i++) {
     log(LOG_DEBUG,"Contemplating whether router %d is a new option...",i);
-    if(options.ORPort &&
-      !connection_exact_get_by_addr_port(rarray[i]->addr, rarray[i]->or_port)) {
-      log(LOG_DEBUG,"Nope, %d is not connected.",i);
-      goto next_i_loop;
+    if(options.ORPort) {
+      conn = connection_exact_get_by_addr_port(rarray[i]->addr, rarray[i]->or_port);
+      if(!conn || conn->type != CONN_TYPE_OR || conn->state != OR_CONN_STATE_OPEN) {
+        log(LOG_DEBUG,"Nope, %d is not connected.",i);
+        goto next_i_loop;
+      }
     }
     for(j=0;j<i;j++) {
       if(!crypto_pk_cmp_keys(rarray[i]->pkey, rarray[j]->pkey)) {
index cc8f0461e8a5a0c4dbd6da273bf915ff12c84a81..fcd3acff8a8b6006d5ec276c08ae8f5dad12de44 100644 (file)
@@ -341,7 +341,7 @@ struct data_queue_t {
   struct data_queue_t *next;
 };
 
-/* per-anonymous-connection struct */
+/* struct for a path (circuit) through the network */
 typedef struct {
   uint32_t n_addr;
   uint16_t n_port;
@@ -365,6 +365,8 @@ typedef struct {
   int cpathlen; 
 
   uint32_t expire; /* expiration time for the corresponding onion */
+  long timestamp_created;
+  char dirty; /* whether this circuit has been used yet */
 
   int state;
 
@@ -381,20 +383,6 @@ struct onion_queue_t {
   struct onion_queue_t *next;
 };
 
-#if 0
-typedef struct
-{ 
-  int zero:1;
-  int version:7;
-  int backf:4;
-  int forwf:4;
-  uint16_t port;
-  uint32_t addr;
-  uint32_t expire;
-  unsigned char keyseed[16];
-} onion_layer_t;
-#endif
-
 #define ONION_LAYER_SIZE 28
 #define ONION_PADDING_SIZE (128-ONION_LAYER_SIZE)
 
@@ -415,11 +403,11 @@ typedef struct {
    int DirFetchPeriod;
    int KeepalivePeriod;
    int MaxOnionsPending;
+   int NewCircuitPeriod;
    int Role;
    int loglevel;
 } or_options_t;
 
-
     /* all the function prototypes go here */
 
 /********************************* buffers.c ***************************/
@@ -491,7 +479,7 @@ aci_t get_unique_aci_by_addr_port(uint32_t addr, uint16_t port, int aci_type);
 
 circuit_t *circuit_get_by_aci_conn(aci_t aci, connection_t *conn);
 circuit_t *circuit_get_by_conn(connection_t *conn);
-circuit_t *circuit_get_by_edge_type(char edge_type);
+circuit_t *circuit_get_newest_by_edge_type(char edge_type);
 circuit_t *circuit_enumerate_by_naddr_nport(circuit_t *start, uint32_t naddr, uint16_t nport);
 
 int circuit_deliver_data_cell_from_edge(cell_t *cell, circuit_t *circ, char edge_type);
@@ -506,8 +494,6 @@ int circuit_init(circuit_t *circ, int aci_type);
 void circuit_free(circuit_t *circ);
 void circuit_free_cpath(crypt_path_t **cpath, int cpathlen);
 
-
-
 void circuit_close(circuit_t *circ);
 
 void circuit_about_to_close_connection(connection_t *conn);
@@ -515,6 +501,13 @@ void circuit_about_to_close_connection(connection_t *conn);
 
 void circuit_dump_by_conn(connection_t *conn);
 
+void circuit_launch_new(int failure_status);
+int circuit_create_onion(void);
+int circuit_establish_circuit(unsigned int *route, int routelen, char *onion,
+                                   int onionlen, crypt_path_t **cpath);
+void circuit_n_conn_open(connection_t *or_conn);
+int circuit_send_onion(connection_t *or_conn, circuit_t *circ);
+
 /********************************* command.c ***************************/
 
 void command_process_cell(cell_t *cell, connection_t *conn);
@@ -611,14 +604,6 @@ int connection_finished_flushing(connection_t *conn);
 
 int ap_handshake_process_socks(connection_t *conn);
 
-int ap_handshake_create_onion(connection_t *conn);
-
-int ap_handshake_establish_circuit(connection_t *conn, unsigned int *route, int routelen, char *onion,
-                                   int onionlen, crypt_path_t **cpath);
-
-void ap_handshake_n_conn_open(connection_t *or_conn);
-
-int ap_handshake_send_onion(connection_t *ap_conn, connection_t *or_conn, circuit_t *circ);
 int ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ);
 
 int ap_handshake_socks_reply(connection_t *conn, char result);
index 5453f4b18805d891c01bb72262d0d5d8b729b0a9..3ff3fb6f660beb19164cb6522af53323da8c4f27 100644 (file)
@@ -182,7 +182,7 @@ test_buffers() {
   j = decompress_buf_to_buf(&buf, &buflen, &buf_datalen,
                             &buf2, &buf2len, &buf2_datalen,
                             decomp, 1);
-  /*XXXX check result *
+  /*XXXX check result */
   
   /* Now compress more, into less room. */
   for (i = 0; i < 20; ++i) {