diff options
-rw-r--r-- | src/or/Makefile.am | 8 | ||||
-rw-r--r-- | src/or/circuit.c | 45 | ||||
-rw-r--r-- | src/or/connection_edge.c | 119 | ||||
-rw-r--r-- | src/or/directory.c | 4 | ||||
-rw-r--r-- | src/or/main.c | 2 | ||||
-rw-r--r-- | src/or/onion.c | 56 | ||||
-rw-r--r-- | src/or/or.h | 18 | ||||
-rw-r--r-- | src/or/rendclient.c | 50 | ||||
-rw-r--r-- | src/or/rendcommon.c | 4 | ||||
-rw-r--r-- | src/or/rendservice.c | 2 | ||||
-rw-r--r-- | src/or/routerlist.c | 53 |
11 files changed, 224 insertions, 137 deletions
diff --git a/src/or/Makefile.am b/src/or/Makefile.am index c96089eb8..afee6a713 100644 --- a/src/or/Makefile.am +++ b/src/or/Makefile.am @@ -7,8 +7,8 @@ bin_PROGRAMS = tor tor_SOURCES = buffers.c circuit.c command.c config.c \ connection.c connection_edge.c connection_or.c \ cpuworker.c directory.c dirserv.c dns.c main.c \ - onion.c rendcommon.c rendmid.c rendservice.c rephist.c \ - router.c routerlist.c \ + onion.c rendcommon.c rendclient.c rendmid.c \ + rendservice.c rephist.c router.c routerlist.c \ tor_main.c tor_LDADD = ../common/libor.a @@ -16,8 +16,8 @@ tor_LDADD = ../common/libor.a test_SOURCES = buffers.c circuit.c command.c config.c \ connection.c connection_edge.c connection_or.c \ cpuworker.c directory.c dirserv.c dns.c main.c \ - onion.c rendcommon.c rendmid.c rendservice.c rephist.c \ - router.c routerlist.c \ + onion.c rendcommon.c rendclient.c rendmid.c \ + rendservice.c rephist.c router.c routerlist.c \ test.c test_LDADD = ../common/libor.a diff --git a/src/or/circuit.c b/src/or/circuit.c index b7502cfca..cecc63e03 100644 --- a/src/or/circuit.c +++ b/src/or/circuit.c @@ -255,34 +255,56 @@ circuit_t *circuit_get_by_conn(connection_t *conn) { * If !conn, return newest. * * If must_be_open, ignore circs not in CIRCUIT_STATE_OPEN. - * If must_be_clean, ignore circs that have been used before. + * + * circ_purpose specifies what sort of circuit we must have. + * If circ_purpose is not GENERAL, then conn must be defined. */ circuit_t *circuit_get_newest(connection_t *conn, - int must_be_open, int must_be_clean) { + int must_be_open, uint8_t circ_purpose) { circuit_t *circ, *newest=NULL, *leastdirty=NULL; routerinfo_t *exitrouter; for (circ=global_circuitlist;circ;circ = circ->next) { if (!circ->cpath) continue; /* this circ doesn't start at us */ - if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL) - continue; /* don't pick rendezvous circuits */ if (must_be_open && (circ->state != CIRCUIT_STATE_OPEN || !circ->n_conn)) continue; /* ignore non-open circs */ if (circ->marked_for_close) continue; + + if (circ->purpose != circ_purpose) + continue; + +#if 0 if (must_be_clean && circ->timestamp_dirty) continue; /* ignore dirty circs */ +#endif + if(conn) { + /* decide if this circ is suitable for this conn */ + if(circ->state == CIRCUIT_STATE_OPEN && circ->n_conn) /* open */ - exitrouter = router_get_by_addr_port(circ->cpath->prev->addr, circ->cpath->prev->port); + exitrouter = router_get_by_addr_port(circ->cpath->prev->addr, + circ->cpath->prev->port); else /* not open */ exitrouter = router_get_by_nickname(circ->build_state->chosen_exit); - if(!exitrouter || connection_ap_can_use_exit(conn, exitrouter) == ADDR_POLICY_REJECTED) { - /* can't exit from this router */ - continue; + + if(!exitrouter) + continue; /* this circuit is screwed and doesn't know it yet */ + + if(circ_purpose == CIRCUIT_PURPOSE_C_GENERAL) { + if(connection_ap_can_use_exit(conn, exitrouter) == ADDR_POLICY_REJECTED) { + /* can't exit from this router */ + continue; + } + } else { /* not general */ + if(rend_cmp_service_ids(conn->socks_request->address, circ->rend_service)) { + /* this circ is not for this conn */ + continue; + } } } + if(!newest || newest->timestamp_created < circ->timestamp_created) { newest = circ; } @@ -1033,11 +1055,11 @@ static void circuit_is_ready(circuit_t *circ) { break; case CIRCUIT_PURPOSE_C_INTRODUCING: /* at Alice, connecting to intro point */ - // alice sends introduce1 relay cell + rend_client_intro_is_ready(circ); break; case CIRCUIT_PURPOSE_C_ESTABLISH_REND: /* at Alice, waiting for Bob */ - // alice launches a circuit to bob's intro point + rend_client_rendezvous_is_ready(circ); break; case CIRCUIT_PURPOSE_S_CONNECT_REND: /* at Bob, connecting to rend point */ @@ -1246,9 +1268,6 @@ int circuit_send_next_onion_skin(circuit_t *circ) { } circuit_rep_hist_note_result(circ); circuit_is_ready(circ); /* do other actions as necessary */ - /* Tell any AP connections that have been waiting for a new - * circuit that one is ready. */ - connection_ap_attach_pending(); return 0; } else if (r<0) { log_fn(LOG_INFO,"Unable to extend circuit path."); diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 5fdd7539b..f8a319bea 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -9,10 +9,7 @@ extern or_options_t options; /* command-line and config-file options */ extern char *conn_state_to_string[][_CONN_TYPE_MAX+1]; static int connection_ap_handshake_process_socks(connection_t *conn); -static int connection_ap_handshake_attach_circuit(connection_t *conn, - int must_be_clean); -static int connection_ap_handshake_attach_circuit_helper(connection_t *conn, - int must_be_clean); +static int connection_ap_handshake_attach_circuit(connection_t *conn); static void connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ); static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ); @@ -377,9 +374,10 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, memcpy(&addr, cell->payload+RELAY_HEADER_SIZE+1, 4); addr = ntohl(addr); client_dns_set_entry(conn->socks_request->address, addr); + /* conn->purpose is still set to general */ conn->state = AP_CONN_STATE_CIRCUIT_WAIT; /* attaching to a dirty circuit is fine */ - if(connection_ap_handshake_attach_circuit(conn, 0) >= 0) + if(connection_ap_handshake_attach_circuit(conn) >= 0) return 0; /* else, conn will get closed below */ } @@ -639,6 +637,7 @@ void connection_ap_expire_beginning(void) { conn->has_sent_end = 0; /* move it back into 'pending' state. */ conn->state = AP_CONN_STATE_CIRCUIT_WAIT; + /* conn->purpose is still set to general */ circuit_detach_stream(circ, conn); /* kludge to make us not try this circuit again, yet to allow * current streams on it to survive if they can: make it @@ -648,7 +647,7 @@ void connection_ap_expire_beginning(void) { /* give our stream another 15 seconds to try */ conn->timestamp_lastread += 15; /* attaching to a dirty circuit is fine */ - if(connection_ap_handshake_attach_circuit(conn,0)<0) { + if(connection_ap_handshake_attach_circuit(conn)<0) { /* it will never work */ /* Don't need to send end -- we're not connected */ connection_mark_for_close(conn, 0); @@ -672,7 +671,7 @@ void connection_ap_attach_pending(void) conn->state != AP_CONN_STATE_CIRCUIT_WAIT) continue; /* attaching to a dirty circuit is fine */ - if(connection_ap_handshake_attach_circuit(conn,0) < 0) { + if(connection_ap_handshake_attach_circuit(conn) < 0) { /* -1 means it will never work */ /* Don't send end; there is no 'other side' yet */ connection_mark_for_close(conn,0); @@ -738,8 +737,9 @@ static int connection_ap_handshake_process_socks(connection_t *conn) { if (rend_parse_rendezvous_address(socks->address) < 0) { /* normal request */ conn->state = AP_CONN_STATE_CIRCUIT_WAIT; + conn->purpose = AP_PURPOSE_GENERAL; /* attaching to a dirty circuit is fine */ - return connection_ap_handshake_attach_circuit(conn,0); + return connection_ap_handshake_attach_circuit(conn); } else { /* it's a hidden-service request */ const char *descp; @@ -747,59 +747,59 @@ static int connection_ap_handshake_process_socks(connection_t *conn) { /* see if we already have it cached */ if (rend_cache_lookup(socks->address, &descp, &desc_len) == 1) { - if(0){ //if a circuit already exists to this place, use it - - } else { - /* go into some other state maybe? */ - /* then launch a rendezvous circuit */ - circuit_launch_new(CIRCUIT_PURPOSE_C_ESTABLISH_REND, NULL); - } + conn->purpose = AP_PURPOSE_RENDPOINT_WAIT; + return connection_ap_handshake_attach_circuit(conn); + //circuit_launch_new(CIRCUIT_PURPOSE_C_ESTABLISH_REND, NULL); } else { + conn->purpose = AP_PURPOSE_RENDDESC_WAIT; /* initiate a dir hidserv desc lookup */ - /* go into a state where you'll be notified of the answer */ + directory_initiate_command(router_pick_directory_server(), + DIR_PURPOSE_FETCH_RENDDESC, + socks->address, strlen(socks->address)); + return 0; } } return 0; } -static int connection_ap_handshake_attach_circuit(connection_t *conn, - int must_be_clean) { - /* try attaching. launch new circuit if needed. - * return -1 if conn needs to die, else 0. */ - switch(connection_ap_handshake_attach_circuit_helper(conn, must_be_clean)) { - case -1: /* it will never work */ - return -1; - case 0: /* no useful circuits available */ - if(!circuit_get_newest(conn, 0, must_be_clean)) { - /* is one already on the way? */ - circuit_launch_new(CIRCUIT_PURPOSE_C_GENERAL, NULL); - } - return 0; - default: /* case 1, it succeeded, great */ - return 0; - } -} - /* Try to find a safe live circuit for CONN_TYPE_AP connection conn. If * we don't find one: if conn cannot be handled by any known nodes, - * warn and return -1; else tell conn to stop reading and return 0. - * Otherwise, associate conn with a safe live circuit, start - * sending a BEGIN cell down the circuit, and return 1. + * warn and return -1 (conn needs to die); + * else launch new circuit and return 0. + * Otherwise, associate conn with a safe live circuit, do the + * right next step, and return 1. */ -static int connection_ap_handshake_attach_circuit_helper(connection_t *conn, - int must_be_clean) { +static int connection_ap_handshake_attach_circuit(connection_t *conn) { circuit_t *circ; uint32_t addr; + int must_be_clean; + uint8_t desired_circuit_purpose; assert(conn); assert(conn->type == CONN_TYPE_AP); assert(conn->state == AP_CONN_STATE_CIRCUIT_WAIT); assert(conn->socks_request); + switch(conn->purpose) { + case AP_PURPOSE_GENERAL: + case AP_PURPOSE_RENDDESC_WAIT: + desired_circuit_purpose = CIRCUIT_PURPOSE_C_GENERAL; + break; + case AP_PURPOSE_RENDPOINT_WAIT: + desired_circuit_purpose = CIRCUIT_PURPOSE_C_ESTABLISH_REND; + break; + case AP_PURPOSE_INTROPOINT_WAIT: + desired_circuit_purpose = CIRCUIT_PURPOSE_C_INTRODUCING; + break; + default: + assert(0); /* never reached */ + } + /* find the circuit that we should use, if there is one. */ - circ = circuit_get_newest(conn, 1, must_be_clean); + circ = circuit_get_newest(conn, 1, desired_circuit_purpose); if(!circ) { +//XXX log_fn(LOG_INFO,"No safe circuit ready for edge connection; delaying."); addr = client_dns_lookup_entry(conn->socks_request->address); if(router_exit_policy_all_routers_reject(addr, conn->socks_request->port)) { @@ -807,29 +807,37 @@ static int connection_ap_handshake_attach_circuit_helper(connection_t *conn, conn->socks_request->address, conn->socks_request->port); return -1; } - connection_stop_reading(conn); /* don't read until the connected cell arrives */ + if(!circuit_get_newest(conn, 0, desired_circuit_purpose)) { + /* is one already on the way? */ + circuit_launch_new(desired_circuit_purpose, NULL); + } return 0; } - connection_start_reading(conn); - /* here, print the circ's path. so people can figure out which circs are sucking. */ circuit_log_path(LOG_INFO,circ); if(!circ->timestamp_dirty) circ->timestamp_dirty = time(NULL); - /* add it into the linked list of streams on this circuit */ - log_fn(LOG_DEBUG,"attaching new conn to circ. n_circ_id %d.", circ->n_circ_id); - conn->next_stream = circ->p_streams; - /* assert_connection_ok(conn, time(NULL)); */ - circ->p_streams = conn; + switch(conn->purpose) { + case AP_PURPOSE_GENERAL: + case AP_PURPOSE_RENDDESC_WAIT: + /* add it into the linked list of streams on this circuit */ + log_fn(LOG_DEBUG,"attaching new conn to circ. n_circ_id %d.", circ->n_circ_id); + conn->next_stream = circ->p_streams; + /* assert_connection_ok(conn, time(NULL)); */ + circ->p_streams = conn; - assert(circ->cpath && circ->cpath->prev); - assert(circ->cpath->prev->state == CPATH_STATE_OPEN); - conn->cpath_layer = circ->cpath->prev; + assert(circ->cpath && circ->cpath->prev); + assert(circ->cpath->prev->state == CPATH_STATE_OPEN); + conn->cpath_layer = circ->cpath->prev; - connection_ap_handshake_send_begin(conn, circ); + connection_ap_handshake_send_begin(conn, circ); + break; + case AP_PURPOSE_RENDPOINT_WAIT: + case AP_PURPOSE_INTROPOINT_WAIT: + } return 1; } @@ -894,11 +902,6 @@ static void connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t ap_conn->package_window = STREAMWINDOW_START; ap_conn->deliver_window = STREAMWINDOW_START; ap_conn->state = AP_CONN_STATE_CONNECT_WAIT; - /* XXX Right now, we rely on the socks client not to send us any data - * XXX until we've sent back a socks reply. (If it does, we could wind - * XXX up packaging that data and sending it to the exit, then later having - * XXX the exit refuse us.) - */ log_fn(LOG_INFO,"Address/port sent, ap socket %d, n_circ_id %d",ap_conn->s,circ->n_circ_id); return; } @@ -947,7 +950,7 @@ int connection_ap_make_bridge(char *address, uint16_t port) { connection_start_reading(conn); /* attaching to a dirty circuit is fine */ - if (connection_ap_handshake_attach_circuit(conn, 0) < 0) { + if (connection_ap_handshake_attach_circuit(conn) < 0) { connection_mark_for_close(conn, 0); close(fd[1]); return -1; diff --git a/src/or/directory.c b/src/or/directory.c index c953c6f06..d2a3126cd 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -275,11 +275,11 @@ int connection_dir_process_inbuf(connection_t *conn) { /* alice's ap_stream is just going to have to time out. */ } else { /* success. notify pending connections about this. */ - //alice_notify_desc_fetched(conn->rend_query); + rend_client_desc_fetched(conn->rend_query); } break; case 404: - //alice_notify_desc_not_fetched(conn->rend_query); + rend_client_desc_not_fetched(conn->rend_query); break; case 400: log_fn(LOG_WARN,"http status 400 (bad request). Dirserver didn't like our rendezvous query?"); diff --git a/src/or/main.c b/src/or/main.c index 38cf93a96..4b1d380a9 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -384,7 +384,7 @@ static void run_scheduled_events(time_t now) { /* Build a new test circuit every 5 minutes */ #define TESTING_CIRCUIT_INTERVAL 300 - circ = circuit_get_newest(NULL, 1, 0); + circ = circuit_get_newest(NULL, 1, CIRCUIT_PURPOSE_C_GENERAL); if(time_to_new_circuit < now) { client_dns_clean(); circuit_expire_unused_circuits(); diff --git a/src/or/onion.c b/src/or/onion.c index 2b68cc17c..36f76415a 100644 --- a/src/or/onion.c +++ b/src/or/onion.c @@ -8,6 +8,7 @@ * they're here to prevent precedence issues with the .h files */ void router_add_running_routers_to_smartlist(smartlist_t *sl); +void add_nickname_list_to_smartlist(smartlist_t *sl, char *list); extern or_options_t options; /* command-line and config-file options */ @@ -166,32 +167,6 @@ int onionskin_answer(circuit_t *circ, unsigned char *payload, unsigned char *key extern int has_fetched_directory; -static void add_nickname_list_to_smartlist(smartlist_t *sl, char *list) { - char *start,*end; - char nick[MAX_NICKNAME_LEN]; - routerinfo_t *router; - - while(isspace((int)*list) || *list==',') list++; - - start = list; - while(*start) { - end=start; while(*end && !isspace((int)*end) && *end != ',') end++; - memcpy(nick,start,end-start); - nick[end-start] = 0; /* null terminate it */ - router = router_get_by_nickname(nick); - if (router) { - if (router->is_running) - smartlist_add(sl,router); - else - log_fn(LOG_INFO,"Nickname list includes '%s' which is known but down.",nick); - } else - log_fn(has_fetched_directory ? LOG_WARN : LOG_INFO, - "Nickname list includes '%s' which isn't a known router.",nick); - while(isspace((int)*end) || *end==',') end++; - start = end; - } -} - static int new_route_len(double cw, routerinfo_t **rarray, int rarray_len) { int num_acceptable_routers; int routelen; @@ -227,33 +202,6 @@ static int new_route_len(double cw, routerinfo_t **rarray, int rarray_len) { return routelen; } -static routerinfo_t *choose_good_exit_server_rend(routerlist_t *dir) -{ - smartlist_t *sl, *excludednodes; - routerinfo_t *choice; - - excludednodes = smartlist_create(); - add_nickname_list_to_smartlist(excludednodes,options.RendExcludeNodes); - - /* try the nodes in RendNodes first */ - sl = smartlist_create(); - add_nickname_list_to_smartlist(sl,options.RendNodes); - smartlist_subtract(sl,excludednodes); - choice = smartlist_choose(sl); - smartlist_free(sl); - if(!choice) { - sl = smartlist_create(); - router_add_running_routers_to_smartlist(sl); - smartlist_subtract(sl,excludednodes); - choice = smartlist_choose(sl); - smartlist_free(sl); - } - smartlist_free(excludednodes); - if(!choice) - log_fn(LOG_WARN,"No available nodes when trying to choose rendezvous point. Failing."); - return choice; -} - static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir) { int *n_supported; @@ -386,7 +334,7 @@ static routerinfo_t *choose_good_exit_server(uint8_t purpose, routerlist_t *dir) if(purpose == CIRCUIT_PURPOSE_C_GENERAL) return choose_good_exit_server_general(dir); else - return choose_good_exit_server_rend(dir); + return router_choose_random_node(dir, options.RendNodes, options.RendExcludeNodes); } cpath_build_state_t *onion_new_cpath_build_state(uint8_t purpose, diff --git a/src/or/or.h b/src/or/or.h index 0686d4e05..41836c7b0 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -170,10 +170,13 @@ #define AP_CONN_STATE_OPEN 8 #define _AP_CONN_STATE_MAX 8 +/* only used if state==CIRCUIT_WAIT */ #define _AP_PURPOSE_MIN 1 #define AP_PURPOSE_GENERAL 1 -#define AP_PURPOSE_ -#define _AP_PURPOSE_MAX 1 +#define AP_PURPOSE_RENDDESC_WAIT 2 +#define AP_PURPOSE_RENDPOINT_WAIT 3 +#define AP_PURPOSE_INTROPOINT_WAIT 4 +#define _AP_PURPOSE_MAX 3 #define _DIR_CONN_STATE_MIN 1 #define DIR_CONN_STATE_CONNECTING 1 @@ -691,7 +694,7 @@ int _circuit_mark_for_close(circuit_t *circ); circuit_t *circuit_get_by_circ_id_conn(uint16_t circ_id, connection_t *conn); circuit_t *circuit_get_by_conn(connection_t *conn); circuit_t *circuit_get_newest(connection_t *conn, - int must_be_open, int must_be_clean); + int must_be_open, uint8_t conn_purpose); circuit_t *circuit_get_next_by_service_and_purpose(circuit_t *circuit, const char *servid, int purpose); circuit_t *circuit_get_rendezvous(const char *cookie); @@ -972,6 +975,7 @@ int router_dump_router_to_string(char *s, int maxlen, routerinfo_t *router, /********************************* routerlist.c ***************************/ routerinfo_t *router_pick_directory_server(void); +routerinfo_t *router_choose_random_node(routerlist_t *dir, char *preferred, char *excluded); routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port); routerinfo_t *router_get_by_link_pk(crypto_pk_env_t *pk); routerinfo_t *router_get_by_nickname(char *nickname); @@ -1016,10 +1020,15 @@ void rep_hist_note_connect_succeeded(const char* nickname, time_t when); void rep_hist_note_disconnect(const char* nickname, time_t when); void rep_hist_note_connection_died(const char* nickname, time_t when); void rep_hist_note_extend_succeeded(const char *from_name, - const char *to_name); + const char *to_name); void rep_hist_note_extend_failed(const char *from_name, const char *to_name); void rep_hist_dump_stats(time_t now, int severity); +/********************************* rendclient.c ***************************/ + +void rend_client_desc_fetched(char *query); +void rend_client_desc_not_fetched(char *query); + /********************************* rendcommon.c ***************************/ typedef struct rend_service_descriptor_t { @@ -1036,6 +1045,7 @@ int rend_encode_service_descriptor(rend_service_descriptor_t *desc, int *len_out); rend_service_descriptor_t *rend_parse_service_descriptor(const char *str, int len); int rend_get_service_id(crypto_pk_env_t *pk, char *out); +int rend_cmp_service_ids(char *one, char *two); void rend_cache_init(void); void rend_cache_clean(void); diff --git a/src/or/rendclient.c b/src/or/rendclient.c new file mode 100644 index 000000000..a71dce9d0 --- /dev/null +++ b/src/or/rendclient.c @@ -0,0 +1,50 @@ +/* Copyright 2004 Roger Dingledine */ +/* See LICENSE for licensing information */ +/* $Id$ */ + +#include "or.h" + +/* send the introduce cell */ +void +rend_client_intro_is_ready() +{ + + +} + +/* send the rendezvous cell */ +void +rend_client_rendezvous_is_ready() +{ + + +} + +/* bob sent us a rendezvous cell, join the circs. */ +void +rend_client_rendezvous() +{ + + +} + + + + +void rend_client_desc_fetched(char *query) { + + +} + +void rend_client_desc_not_fetched(char *query) { + + +} + +/* + Local Variables: + mode:c + indent-tabs-mode:nil + c-basic-offset:2 + End: +*/ diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c index 63c9abbe0..3b1d8fc45 100644 --- a/src/or/rendcommon.c +++ b/src/or/rendcommon.c @@ -121,6 +121,10 @@ int rend_get_service_id(crypto_pk_env_t *pk, char *out) return 0; } +int rend_cmp_service_ids(char *one, char *two) { + return strcasecmp(one,two); +} + /* ==== Rendezvous service descriptor cache. */ #define REND_CACHE_MAX_AGE 24*60*60 #define REND_CACHE_MAX_SKEW 60*60 diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 7e75827c0..9d4cd3bec 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -20,7 +20,7 @@ typedef struct rend_service_port_config_t { */ typedef struct rend_service_t { /* Fields specified in config file */ - char *directory; + char *directory; /* where in the filesystem it stores it */ smartlist_t *ports; char *intro_nodes; char *intro_exclude_nodes; diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 8c2f7103d..b913f9171 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -191,6 +191,32 @@ static routerinfo_t *router_pick_directory_server_impl(void) { return dirserver; } +void add_nickname_list_to_smartlist(smartlist_t *sl, char *list) { + char *start,*end; + char nick[MAX_NICKNAME_LEN]; + routerinfo_t *router; + + while(isspace((int)*list) || *list==',') list++; + + start = list; + while(*start) { + end=start; while(*end && !isspace((int)*end) && *end != ',') end++; + memcpy(nick,start,end-start); + nick[end-start] = 0; /* null terminate it */ + router = router_get_by_nickname(nick); + if (router) { + if (router->is_running) + smartlist_add(sl,router); + else + log_fn(LOG_INFO,"Nickname list includes '%s' which is known but down.",nick); + } else + log_fn(has_fetched_directory ? LOG_WARN : LOG_INFO, + "Nickname list includes '%s' which isn't a known router.",nick); + while(isspace((int)*end) || *end==',') end++; + start = end; + } +} + void router_add_running_routers_to_smartlist(smartlist_t *sl) { routerinfo_t *router; int i; @@ -207,6 +233,33 @@ void router_add_running_routers_to_smartlist(smartlist_t *sl) { } } +routerinfo_t *router_choose_random_node(routerlist_t *dir, char *preferred, char *excluded) +{ + smartlist_t *sl, *excludednodes; + routerinfo_t *choice; + + excludednodes = smartlist_create(); + add_nickname_list_to_smartlist(excludednodes,excluded); + + /* try the nodes in RendNodes first */ + sl = smartlist_create(); + add_nickname_list_to_smartlist(sl,preferred); + smartlist_subtract(sl,excludednodes); + choice = smartlist_choose(sl); + smartlist_free(sl); + if(!choice) { + sl = smartlist_create(); + router_add_running_routers_to_smartlist(sl); + smartlist_subtract(sl,excludednodes); + choice = smartlist_choose(sl); + smartlist_free(sl); + } + smartlist_free(excludednodes); + if(!choice) + log_fn(LOG_WARN,"No available nodes when trying to choose node. Failing."); + return choice; +} + routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port) { int i; routerinfo_t *router; |