|  | @@ -17,6 +17,8 @@ const char dirserv_c_id[] = "$Id$";
 | 
	
		
			
				|  |  |  /** How many seconds do we wait before regenerating the directory? */
 | 
	
		
			
				|  |  |  #define DIR_REGEN_SLACK_TIME 5
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +extern long stats_n_seconds_working;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /** Do we need to regenerate the directory when someone asks for it? */
 | 
	
		
			
				|  |  |  static int the_directory_is_dirty = 1;
 | 
	
		
			
				|  |  |  static int runningrouters_is_dirty = 1;
 | 
	
	
		
			
				|  | @@ -393,8 +395,9 @@ dirserv_add_descriptor(const char **desc, const char **msg)
 | 
	
		
			
				|  |  |        *desc = end;
 | 
	
		
			
				|  |  |        return verified;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    /* We don't alrady have a newer one; we'll update this one. */
 | 
	
		
			
				|  |  | +    /* We don't already have a newer one; we'll update this one. */
 | 
	
		
			
				|  |  |      log_fn(LOG_INFO,"Dirserv updating desc for server %s (nickname '%s')",hex_digest,ri->nickname);
 | 
	
		
			
				|  |  | +    ri->last_reachable = ri_old->last_reachable; /* this carries over */
 | 
	
		
			
				|  |  |      *msg = verified?"Verified server updated":"Unverified server updated. (Have you sent us your key fingerprint?)";
 | 
	
		
			
				|  |  |      routerinfo_free(ri_old);
 | 
	
		
			
				|  |  |      smartlist_del_keeporder(descriptor_list, found);
 | 
	
	
		
			
				|  | @@ -546,6 +549,9 @@ list_single_server_status(routerinfo_t *desc, int is_live)
 | 
	
		
			
				|  |  |    return tor_strdup(buf);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#define REACHABLE_TIMEOUT (60*60) /* an hour */
 | 
	
		
			
				|  |  | +/* Make sure this is 3 times the value of get_dir_fetch_period() */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /** Based on the routerinfo_ts in <b>routers</b>, allocate the
 | 
	
		
			
				|  |  |   * contents of a router-status line, and store it in
 | 
	
		
			
				|  |  |   * *<b>router_status_out</b>.  Return 0 on success, -1 on failure.
 | 
	
	
		
			
				|  | @@ -556,6 +562,7 @@ list_server_status(smartlist_t *routers, char **router_status_out)
 | 
	
		
			
				|  |  |    /* List of entries in a router-status style: An optional !, then an optional
 | 
	
		
			
				|  |  |     * equals-suffixed nickname, then a dollar-prefixed hexdigest. */
 | 
	
		
			
				|  |  |    smartlist_t *rs_entries;
 | 
	
		
			
				|  |  | +  time_t now = time(NULL);
 | 
	
		
			
				|  |  |    int authdir_mode = get_options()->AuthoritativeDir;
 | 
	
		
			
				|  |  |    tor_assert(router_status_out);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -563,16 +570,25 @@ list_server_status(smartlist_t *routers, char **router_status_out)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    SMARTLIST_FOREACH(routers, routerinfo_t *, ri,
 | 
	
		
			
				|  |  |    {
 | 
	
		
			
				|  |  | -    int is_live;
 | 
	
		
			
				|  |  | +    int is_live = 0;
 | 
	
		
			
				|  |  |      connection_t *conn;
 | 
	
		
			
				|  |  |      conn = connection_get_by_identity_digest(
 | 
	
		
			
				|  |  |                      ri->identity_digest, CONN_TYPE_OR);
 | 
	
		
			
				|  |  |      if (authdir_mode) {
 | 
	
		
			
				|  |  |        /* Treat a router as alive if
 | 
	
		
			
				|  |  |         *    - It's me, and I'm not hibernating.
 | 
	
		
			
				|  |  | -       * or - we're connected to it. */
 | 
	
		
			
				|  |  | -      is_live = (router_is_me(ri) && !we_are_hibernating()) ||
 | 
	
		
			
				|  |  | -        (conn && conn->state == OR_CONN_STATE_OPEN);
 | 
	
		
			
				|  |  | +       * or - we're connected to it and we've found it reachable recently. */
 | 
	
		
			
				|  |  | +      if (router_is_me(ri) && !we_are_hibernating()) {
 | 
	
		
			
				|  |  | +        is_live = 1;
 | 
	
		
			
				|  |  | +      } else if (conn && conn->state == OR_CONN_STATE_OPEN) {
 | 
	
		
			
				|  |  | +        if (now < ri->last_reachable + REACHABLE_TIMEOUT) {
 | 
	
		
			
				|  |  | +          is_live = 1;
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +          log_fn(stats_n_seconds_working>REACHABLE_TIMEOUT ? LOG_NOTICE : LOG_INFO,
 | 
	
		
			
				|  |  | +                 "Router %s (%s:%d) is connected to us but not reachable by us.",
 | 
	
		
			
				|  |  | +                 ri->nickname, ri->address, ri->or_port);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  |        is_live = ri->is_running;
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -982,7 +998,7 @@ dirserv_orconn_tls_done(const char *address,
 | 
	
		
			
				|  |  |                          uint16_t or_port,
 | 
	
		
			
				|  |  |                          const char *digest_rcvd,
 | 
	
		
			
				|  |  |                          const char *nickname_rcvd,
 | 
	
		
			
				|  |  | -                        int as_advertised) //XXXRD
 | 
	
		
			
				|  |  | +                        int as_advertised)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    int i;
 | 
	
		
			
				|  |  |    tor_assert(address);
 | 
	
	
		
			
				|  | @@ -995,10 +1011,9 @@ dirserv_orconn_tls_done(const char *address,
 | 
	
		
			
				|  |  |    for (i = 0; i < smartlist_len(descriptor_list); ++i) {
 | 
	
		
			
				|  |  |      routerinfo_t *ri = smartlist_get(descriptor_list, i);
 | 
	
		
			
				|  |  |      int drop = 0;
 | 
	
		
			
				|  |  | -    if (ri->is_verified)
 | 
	
		
			
				|  |  | +    if (strcasecmp(address, ri->address) || or_port != ri->or_port)
 | 
	
		
			
				|  |  |        continue;
 | 
	
		
			
				|  |  | -    if (!strcasecmp(address, ri->address) &&
 | 
	
		
			
				|  |  | -        or_port == ri->or_port) {
 | 
	
		
			
				|  |  | +    if (!ri->is_verified) {
 | 
	
		
			
				|  |  |        /* We have a router at the same address! */
 | 
	
		
			
				|  |  |        if (strcasecmp(ri->nickname, nickname_rcvd)) {
 | 
	
		
			
				|  |  |          log_fn(LOG_NOTICE, "Dropping descriptor: nickname '%s' does not match nickname '%s' in cert from %s:%d",
 | 
	
	
		
			
				|  | @@ -1009,11 +1024,14 @@ dirserv_orconn_tls_done(const char *address,
 | 
	
		
			
				|  |  |                 address, or_port);
 | 
	
		
			
				|  |  |          drop = 1;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | -      if (drop) {
 | 
	
		
			
				|  |  | -        routerinfo_free(ri);
 | 
	
		
			
				|  |  | -        smartlist_del(descriptor_list, i--);
 | 
	
		
			
				|  |  | -        directory_set_dirty();
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if (drop) {
 | 
	
		
			
				|  |  | +      routerinfo_free(ri);
 | 
	
		
			
				|  |  | +      smartlist_del(descriptor_list, i--);
 | 
	
		
			
				|  |  | +      directory_set_dirty();
 | 
	
		
			
				|  |  | +    } else { /* correct nickname and digest. mark this router reachable! */
 | 
	
		
			
				|  |  | +      log_fn(LOG_INFO,"Found router %s to be reachable. Yay.", ri->nickname);
 | 
	
		
			
				|  |  | +      ri->last_reachable = time(NULL);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 |