aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/or/directory.c261
1 files changed, 134 insertions, 127 deletions
diff --git a/src/or/directory.c b/src/or/directory.c
index 2168bf029..2bb27b1e7 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -290,157 +290,164 @@ parse_http_response(char *headers, int *code, char **message)
return 0;
}
-/** Read handler for directory connections. (That's connections <em>to</em>
- * directory servers and connections <em>at</em> directory servers.)
+/** We are a client, and we've finished reading the server's
+ * response. Parse and it and act appropriately.
+ *
+ * Return -1 if an error has occurred, or 0 normally. The caller
+ * will take care of marking the connection for close.
*/
-int connection_dir_process_inbuf(connection_t *conn) {
+static int
+connection_dir_client_finished_reading(connection_t *conn)
+{
char *body;
char *headers;
int body_len=0;
int status_code;
- tor_assert(conn && conn->type == CONN_TYPE_DIR);
+ switch(fetch_from_buf_http(conn->inbuf,
+ &headers, MAX_HEADERS_SIZE,
+ &body, &body_len, MAX_DIR_SIZE)) {
+ case -1: /* overflow */
+ log_fn(LOG_WARN,"'fetch' response too large. Failing.");
+ return -1;
+ case 0:
+ log_fn(LOG_INFO,"'fetch' response not all here, but we're at eof. Closing.");
+ return -1;
+ /* case 1, fall through */
+ }
- /* Directory clients write, then read data until they receive EOF;
- * directory servers read data until they get an HTTP command, then
- * write their response (when it's finished flushing, they mark for
- * close).
- */
- if(conn->inbuf_reached_eof) {
- if(conn->state != DIR_CONN_STATE_CLIENT_READING) {
- log_fn(LOG_INFO,"conn reached eof, not reading. Closing.");
- connection_close_immediate(conn); /* it was an error; give up on flushing */
- connection_mark_for_close(conn);
+ if(parse_http_response(headers, &status_code, NULL) < 0) {
+ log_fn(LOG_WARN,"Unparseable headers. Closing.");
+ free(body); free(headers);
+ return -1;
+ }
+
+ if(conn->purpose == DIR_PURPOSE_FETCH_DIR) {
+ /* fetch/process the directory to learn about new routers. */
+ log_fn(LOG_INFO,"Received directory (size %d):\n%s", body_len, body);
+ if(status_code == 503 || body_len == 0) {
+ log_fn(LOG_INFO,"Empty directory. Ignoring.");
+ free(body); free(headers);
+ return 0;
+ }
+ if(status_code != 200) {
+ log_fn(LOG_WARN,"Received http status code %d from dirserver. Failing.",
+ status_code);
+ free(body); free(headers);
return -1;
}
-
- switch(fetch_from_buf_http(conn->inbuf,
- &headers, MAX_HEADERS_SIZE,
- &body, &body_len, MAX_DIR_SIZE)) {
- case -1: /* overflow */
- log_fn(LOG_WARN,"'fetch' response too large. Failing.");
- connection_mark_for_close(conn);
- return -1;
- case 0:
- log_fn(LOG_INFO,"'fetch' response not all here, but we're at eof. Closing.");
- connection_mark_for_close(conn);
- return -1;
- /* case 1, fall through */
+ if(router_load_routerlist_from_directory(body, NULL) < 0){
+ log_fn(LOG_INFO,"...but parsing failed. Ignoring.");
+ } else {
+ log_fn(LOG_INFO,"updated routers.");
}
+ directory_has_arrived(); /* do things we've been waiting to do */
+ }
- if(parse_http_response(headers, &status_code, NULL) < 0) {
- log_fn(LOG_WARN,"Unparseable headers. Closing.");
+ if(conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
+ running_routers_t *rrs;
+ routerlist_t *rl;
+ /* just update our list of running routers, if this list is new info */
+ log_fn(LOG_INFO,"Received running-routers list (size %d):\n%s", body_len, body);
+ if(status_code != 200) {
+ log_fn(LOG_WARN,"Received http status code %d from dirserver. Failing.",
+ status_code);
free(body); free(headers);
- connection_mark_for_close(conn);
return -1;
}
-
- if(conn->purpose == DIR_PURPOSE_FETCH_DIR) {
- /* fetch/process the directory to learn about new routers. */
- log_fn(LOG_INFO,"Received directory (size %d):\n%s", body_len, body);
- if(status_code == 503 || body_len == 0) {
- log_fn(LOG_INFO,"Empty directory. Ignoring.");
- free(body); free(headers);
- connection_mark_for_close(conn);
- return 0;
- }
- if(status_code != 200) {
- log_fn(LOG_WARN,"Received http status code %d from dirserver. Failing.",
- status_code);
- free(body); free(headers);
- connection_mark_for_close(conn);
- return -1;
- }
- if(router_load_routerlist_from_directory(body, NULL) < 0){
- log_fn(LOG_INFO,"...but parsing failed. Ignoring.");
- } else {
- log_fn(LOG_INFO,"updated routers.");
- }
- directory_has_arrived(); /* do things we've been waiting to do */
+ if (!(rrs = router_parse_runningrouters(body))) {
+ log_fn(LOG_WARN, "Can't parse runningrouters list");
+ free(body); free(headers);
+ return -1;
}
+ router_get_routerlist(&rl);
+ routerlist_update_from_runningrouters(rl,rrs);
+ running_routers_free(rrs);
+ }
- if(conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
- running_routers_t *rrs;
- routerlist_t *rl;
- /* just update our list of running routers, if this list is new info */
- log_fn(LOG_INFO,"Received running-routers list (size %d):\n%s", body_len, body);
- if(status_code != 200) {
- log_fn(LOG_WARN,"Received http status code %d from dirserver. Failing.",
- status_code);
- free(body); free(headers);
- connection_mark_for_close(conn);
- return -1;
- }
- if (!(rrs = router_parse_runningrouters(body))) {
- log_fn(LOG_WARN, "Can't parse runningrouters list");
- free(body); free(headers);
- connection_mark_for_close(conn);
- return -1;
- }
- router_get_routerlist(&rl);
- routerlist_update_from_runningrouters(rl,rrs);
- running_routers_free(rrs);
+ if(conn->purpose == DIR_PURPOSE_UPLOAD_DIR) {
+ switch(status_code) {
+ case 200:
+ log_fn(LOG_INFO,"eof (status 200) after uploading server descriptor: finished.");
+ break;
+ case 400:
+ log_fn(LOG_WARN,"http status 400 (bad request) response from dirserver. Malformed server descriptor?");
+ break;
+ case 403:
+ log_fn(LOG_WARN,"http status 403 (unapproved server) response from dirserver. Is your clock skewed? Have you mailed us your identity fingerprint? Are you using the right key? See README.");
+ break;
+ default:
+ log_fn(LOG_WARN,"http status %d response unrecognized.", status_code);
+ break;
}
+ }
- if(conn->purpose == DIR_PURPOSE_UPLOAD_DIR) {
- switch(status_code) {
- case 200:
- log_fn(LOG_INFO,"eof (status 200) after uploading server descriptor: finished.");
- break;
- case 400:
- log_fn(LOG_WARN,"http status 400 (bad request) response from dirserver. Malformed server descriptor?");
- break;
- case 403:
- log_fn(LOG_WARN,"http status 403 (unapproved server) response from dirserver. Is your clock skewed? Have you mailed us your identity fingerprint? Are you using the right key? See README.");
-
- break;
- default:
- log_fn(LOG_WARN,"http status %d response unrecognized.", status_code);
- break;
- }
+ if(conn->purpose == DIR_PURPOSE_FETCH_RENDDESC) {
+ log_fn(LOG_INFO,"Received rendezvous descriptor (size %d, status code %d)",
+ body_len, status_code);
+ switch(status_code) {
+ case 200:
+ if(rend_cache_store(body, body_len) < 0) {
+ log_fn(LOG_WARN,"Failed to store rendezvous descriptor.");
+ /* alice's ap_stream will notice when connection_mark_for_close
+ * cleans it up */
+ } else {
+ /* success. notify pending connections about this. */
+ rend_client_desc_fetched(conn->rend_query, 1);
+ conn->purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
+ }
+ break;
+ case 404:
+ /* not there. pending connections will be notified when
+ * connection_mark_for_close cleans it up. */
+ break;
+ case 400:
+ log_fn(LOG_WARN,"http status 400 (bad request). Dirserver didn't like our rendezvous query?");
+ break;
}
+ }
- if(conn->purpose == DIR_PURPOSE_FETCH_RENDDESC) {
- log_fn(LOG_INFO,"Received rendezvous descriptor (size %d, status code %d)",
- body_len, status_code);
- switch(status_code) {
- case 200:
- if(rend_cache_store(body, body_len) < 0) {
- log_fn(LOG_WARN,"Failed to store rendezvous descriptor.");
- /* alice's ap_stream will notice when connection_mark_for_close
- * cleans it up */
- } else {
- /* success. notify pending connections about this. */
- rend_client_desc_fetched(conn->rend_query, 1);
- conn->purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
- }
- break;
- case 404:
- /* not there. pending connections will be notified when
- * connection_mark_for_close cleans it up. */
- break;
- case 400:
- log_fn(LOG_WARN,"http status 400 (bad request). Dirserver didn't like our rendezvous query?");
- break;
- }
+ if(conn->purpose == DIR_PURPOSE_UPLOAD_RENDDESC) {
+ switch(status_code) {
+ case 200:
+ log_fn(LOG_INFO,"eof (status 200) after uploading rendezvous descriptor: finished.");
+ break;
+ case 400:
+ log_fn(LOG_WARN,"http status 400 (bad request) response from dirserver. Malformed rendezvous descriptor?");
+ break;
+ default:
+ log_fn(LOG_WARN,"http status %d response unrecognized.", status_code);
+ break;
}
+ }
+ free(body); free(headers);
+ return 0;
+}
- if(conn->purpose == DIR_PURPOSE_UPLOAD_RENDDESC) {
- switch(status_code) {
- case 200:
- log_fn(LOG_INFO,"eof (status 200) after uploading rendezvous descriptor: finished.");
- break;
- case 400:
- log_fn(LOG_WARN,"http status 400 (bad request) response from dirserver. Malformed rendezvous descriptor?");
- break;
- default:
- log_fn(LOG_WARN,"http status %d response unrecognized.", status_code);
- break;
- }
+/** Read handler for directory connections. (That's connections <em>to</em>
+ * directory servers and connections <em>at</em> directory servers.)
+ */
+int connection_dir_process_inbuf(connection_t *conn) {
+ int retval;
+
+ tor_assert(conn && conn->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
+ * write their response (when it's finished flushing, they mark for
+ * close).
+ */
+ if(conn->inbuf_reached_eof) {
+ if(conn->state != DIR_CONN_STATE_CLIENT_READING) {
+ log_fn(LOG_INFO,"conn reached eof, not reading. Closing.");
+ connection_close_immediate(conn); /* it was an error; give up on flushing */
+ connection_mark_for_close(conn);
+ return -1;
}
- free(body); free(headers);
+
+ retval = connection_dir_client_finished_reading(conn);
connection_mark_for_close(conn);
- return 0;
+ return retval;
} /* endif 'reached eof' */
/* If we're on the dirserver side, look for a command. */