diff --git a/src/or/directory.c b/src/or/directory.c index e7f2608d36..5e9c399b3a 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -4,6 +4,10 @@ #include "or.h" +/***** + * directory.c: Implement directory HTTP protocol. + *****/ + static void directory_send_command(connection_t *conn, int purpose, const char *payload, int payload_len); static int directory_handle_command(connection_t *conn); @@ -12,7 +16,9 @@ static int directory_handle_command(connection_t *conn); extern or_options_t options; /* command-line and config-file options */ +/* URL for publishing rendezvous descriptors. */ char rend_publish_string[] = "/rendezvous/publish"; +/* Prefix for downloading rendezvous descriptors. */ char rend_fetch_url[] = "/rendezvous/"; #define MAX_HEADERS_SIZE 2048 @@ -20,18 +26,37 @@ char rend_fetch_url[] = "/rendezvous/"; /********* END VARIABLES ************/ +/* Launch a new connection to the directory server 'router' to upload + * or download a service or rendezvous descriptor. 'purpose' determines what + * kind of directory connection we're launching, and must be one of + * DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC}. + * + * When uploading, 'payload' and 'payload_len' determine the content + * of the HTTP post. When fetching a rendezvous descriptor, 'payload' + * and 'payload_len' are the service ID we want to fetch. + */ void directory_initiate_command(routerinfo_t *router, int purpose, const char *payload, int payload_len) { connection_t *conn; - if(purpose == DIR_PURPOSE_FETCH_DIR) - log_fn(LOG_DEBUG,"initiating directory fetch"); - if(purpose == DIR_PURPOSE_FETCH_RENDDESC) - log_fn(LOG_DEBUG,"initiating hidden-service descriptor fetch"); - if(purpose == DIR_PURPOSE_UPLOAD_DIR) - log_fn(LOG_DEBUG,"initiating server descriptor upload"); - if(purpose == DIR_PURPOSE_UPLOAD_RENDDESC) - log_fn(LOG_DEBUG,"initiating hidden-service descriptor upload"); + switch (purpose) + { + case DIR_PURPOSE_FETCH_DIR: + log_fn(LOG_DEBUG,"initiating directory fetch"); + break; + case DIR_PURPOSE_FETCH_RENDDESC: + log_fn(LOG_DEBUG,"initiating hidden-service descriptor fetch"); + break; + case DIR_PURPOSE_UPLOAD_DIR: + log_fn(LOG_DEBUG,"initiating server descriptor upload"); + break; + case DIR_PURPOSE_UPLOAD_RENDDESC: + log_fn(LOG_DEBUG,"initiating hidden-service descriptor upload"); + break; + default: + log_fn(LOG_ERR, "Unrecognized directory connection purpose."); + tor_assert(0); + } if (!router) { /* i guess they didn't have one in mind for me to use */ log_fn(LOG_WARN,"No running dirservers known. Not trying. (purpose %d)", purpose); @@ -90,6 +115,10 @@ void directory_initiate_command(routerinfo_t *router, int purpose, } } +/* Queue an appropriate HTTP command on conn->outbuf. The args + * 'purpose', 'payload', and 'payload_len' are as in + * directory_initiate_command. + */ static void directory_send_command(connection_t *conn, int purpose, const char *payload, int payload_len) { char fetchstring[] = "GET / HTTP/1.0\r\n\r\n"; @@ -114,6 +143,7 @@ static void directory_send_command(connection_t *conn, int purpose, /* this must be true or we wouldn't be doing the lookup */ tor_assert(payload_len <= REND_SERVICE_ID_LEN); + /* This breaks the function abstraction. */ memcpy(conn->rend_query, payload, payload_len); conn->rend_query[payload_len] = 0; @@ -131,7 +161,7 @@ static void directory_send_command(connection_t *conn, int purpose, } } -/* Parse "%s %s HTTP/1..." +/* Parse an HTTP request string 'headers' of the form "%s %s HTTP/1..." * If it's well-formed, point *url to the second %s, * null-terminate it (this modifies headers!) and return 0. * Otherwise, return -1. @@ -153,7 +183,7 @@ int parse_http_url(char *headers, char **url) { return 0; } -/* Parse "HTTP/1.%d %d%s\r\n". +/* Parse an HTTP response string 'headers' of the form "HTTP/1.%d %d%s\r\n...". * If it's well-formed, assign *code, point *message to the first * non-space character after code if there is one and message is non-NULL * (else leave it alone), and return 0. @@ -178,6 +208,9 @@ int parse_http_response(char *headers, int *code, char **message) { return 0; } +/* Read handler for directory connections. (That's connections *to* + * directory servers and connections *at* directory servers.) + */ int connection_dir_process_inbuf(connection_t *conn) { char *body; char *headers; @@ -186,6 +219,11 @@ int connection_dir_process_inbuf(connection_t *conn) { 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, mark the conn for close (?) and hold the + * conn open till it's flushed. (??)XXXXNMNM + */ if(conn->inbuf_reached_eof) { if(conn->state != DIR_CONN_STATE_CLIENT_READING) { log_fn(LOG_INFO,"conn reached eof, not reading. Closing."); @@ -298,8 +336,9 @@ int connection_dir_process_inbuf(connection_t *conn) { free(body); free(headers); connection_mark_for_close(conn,0); return 0; - } + } /* endif 'reached eof' */ + /* If we're on the dirserver side, look for a command. */ if(conn->state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) { if (directory_handle_command(conn) < 0) { connection_mark_for_close(conn,0); @@ -320,7 +359,11 @@ static char answer403[] = "HTTP/1.0 403 Unapproved server\r\n\r\n"; static char answer404[] = "HTTP/1.0 404 Not found\r\n\r\n"; static char answer503[] = "HTTP/1.0 503 Directory unavailable\r\n\r\n"; -/* always returns 0 */ +/* Helper function: called when a dirserver gets a complete HTTP GET + * request. Looks for a request for a directory or for a rendezvous + * service descriptor. On finding one, writes a response into + * conn->outbuf. If the request is unrecognized, send a 404. + * Always returns 0. */ static int directory_handle_command_get(connection_t *conn, char *headers, char *body, int body_len) { @@ -382,7 +425,11 @@ static int directory_handle_command_get(connection_t *conn, return 0; } -/* always returns 0 */ +/* Helper function: called when a dirserver gets a complete HTTP GET + * request. Looks for an uploaded server descriptor or rendezvous + * service descriptor. On finding one, processes it and writes a + * response into conn->outbuf. If the request is unrecognized, sends a + * 404. Always returns 0. */ static int directory_handle_command_post(connection_t *conn, char *headers, char *body, int body_len) { @@ -432,6 +479,11 @@ static int directory_handle_command_post(connection_t *conn, return 0; } +/* Called when a dirserver receives data on a directory connection; + * looks for an HTTP request. If the request is complete, remove it + * from the inbuf, try to process it; otherwise, leave it on the + * buffer. Return a 0 on success, or -1 on error. + */ static int directory_handle_command(connection_t *conn) { char *headers=NULL, *body=NULL; int body_len=0; @@ -466,6 +518,10 @@ static int directory_handle_command(connection_t *conn) { return r; } +/* Write handler for directory connections; called when all data has + * been flushed. Handle a completed connection; close the connection, + * or wait for a response as appropriate. + */ int connection_dir_finished_flushing(connection_t *conn) { int e, len=sizeof(e); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index d8cf1a0c78..61a6ecd892 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -226,7 +226,7 @@ static routerinfo_t *router_pick_directory_server_impl(void) { * currently running. Add the routerinfos for those routers to 'sl'. */ void add_nickname_list_to_smartlist(smartlist_t *sl, const char *list) { - char *start,*end; + const char *start,*end; char nick[MAX_NICKNAME_LEN+1]; routerinfo_t *router;