diff --git a/src/or/buffers.c b/src/or/buffers.c index 30b476e200..5b4053c90d 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -129,9 +129,9 @@ int write_to_buf(char *string, int string_len, } int fetch_from_buf(char *string, int string_len, - char **buf, int *buflen, int *buf_datalen) { + char **buf, int *buflen, int *buf_datalen) { - /* if there is string_len bytes in buf, write them onto string, + /* if there are string_len bytes in buf, write them onto string, * then memmove buf back (that is, remove them from buf) */ assert(string && buf && *buf && buflen && buf_datalen); @@ -147,3 +147,25 @@ int fetch_from_buf(char *string, int string_len, return *buf_datalen; } +int find_on_inbuf(char *string, int string_len, + char *buf, int buf_datalen) { + /* find first instance of needle 'string' on haystack 'buf'. return how + * many bytes from the beginning of buf to the end of string. + * If it's not there, return -1. + */ + + char *location; + char *last_possible = buf + buf_datalen - string_len; + + assert(string && string_len > 0 && buf); + + if(buf_datalen < string_len) + return -1; + + for(location = buf; location <= last_possible; location++) + if((*location == *string) && !memcmp(location+1, string+1, string_len-1)) + return location-buf+string_len; + + return -1; +} + diff --git a/src/or/connection.c b/src/or/connection.c index f4c3cb968a..d2445effea 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -352,6 +352,10 @@ int connection_fetch_from_buf(char *string, int len, connection_t *conn) { return fetch_from_buf(string, len, &conn->inbuf, &conn->inbuflen, &conn->inbuf_datalen); } +int connection_find_on_inbuf(char *string, int len, connection_t *conn) { + return find_on_inbuf(string, len, conn->inbuf, conn->inbuf_datalen); +} + int connection_wants_to_flush(connection_t *conn) { return conn->outbuf_flushlen; } diff --git a/src/or/directory.c b/src/or/directory.c index 861d3163cc..12e5f9dfac 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -12,8 +12,10 @@ extern or_options_t options; /* command-line and config-file options */ static char the_directory[MAX_DIR_SIZE+1]; static int directorylen=0; +static int reading_headers=0; -static char getstring[] = "GET / HTTP/1.0\n\r"; +static char getstring[] = "GET / HTTP/1.0\r\n\r\n"; +static char answerstring[] = "HTTP/1.0 200 OK\r\n\r\n"; /********* END VARIABLES ************/ @@ -22,11 +24,14 @@ void directory_initiate_fetch(routerinfo_t *router) { struct sockaddr_in router_addr; int s; - log(LOG_DEBUG,"directory_initiate_fetch(): initiating directory fetch"); - if(!router) /* i guess they didn't have one in mind for me to use */ return; + if(connection_get_by_type(CONN_TYPE_DIR)) /* there's already a fetch running */ + return; + + log(LOG_DEBUG,"directory_initiate_fetch(): initiating directory fetch"); + conn = connection_new(CONN_TYPE_DIR); if(!conn) return; @@ -107,7 +112,7 @@ int directory_send_command(connection_t *conn) { void directory_rebuild(void) { dump_directory_to_string(the_directory, MAX_DIR_SIZE); - log(LOG_DEBUG,"New directory:\n'%s'",the_directory); + log(LOG_DEBUG,"New directory:\n%s",the_directory); directorylen = strlen(the_directory); } @@ -155,6 +160,7 @@ int connection_dir_process_inbuf(connection_t *conn) { } int directory_handle_command(connection_t *conn) { + char buf[15]; assert(conn && conn->type == CONN_TYPE_DIR); @@ -163,7 +169,14 @@ int directory_handle_command(connection_t *conn) { return 0; /* not yet */ } - /* for now, don't bother reading it. */ + if(connection_fetch_from_buf(buf,strlen(getstring),conn) < 0) { + return -1; + } + + if(strncasecmp(buf,getstring,strlen("GET / HTTP/"))) { + log(LOG_DEBUG,"directory_handle_command(): Command doesn't seem to be a get. Closing,"); + return -1; + } if(directorylen == 0) { log(LOG_DEBUG,"directory_handle_command(): My directory is empty. Closing."); @@ -171,7 +184,8 @@ int directory_handle_command(connection_t *conn) { } log(LOG_DEBUG,"directory_handle_command(): Dumping directory to client."); - if(connection_write_to_buf(the_directory, directorylen, conn) < 0) { + if((connection_write_to_buf(answerstring, strlen(answerstring), conn) < 0) || + (connection_write_to_buf(the_directory, directorylen, conn) < 0)) { log(LOG_DEBUG,"directory_handle_command(): my outbuf is full. Oops."); return -1; } @@ -182,9 +196,24 @@ int directory_handle_command(connection_t *conn) { int directory_handle_reading(connection_t *conn) { int amt; + char *headers; assert(conn && conn->type == CONN_TYPE_DIR); + if(reading_headers) { + amt = connection_find_on_inbuf("\r\n\r\n", 4, conn); + if(amt < 0) /* not there yet */ + return 0; + headers = malloc(amt+1); + if(connection_fetch_from_buf(headers,amt,conn) < 0) { + log(LOG_DEBUG,"directory_handle_reading(): fetch_from_buf failed (reading headers)."); + return -1; + } + headers[amt] = 0; /* null terminate it, */ + free(headers); /* and then throw it away */ + reading_headers = 0; + } + amt = conn->inbuf_datalen; if(amt + directorylen >= MAX_DIR_SIZE) { @@ -196,7 +225,7 @@ int directory_handle_reading(connection_t *conn) { amt, directorylen); if(connection_fetch_from_buf(the_directory+directorylen,amt,conn) < 0) { - log(LOG_DEBUG,"directory_handle_reading(): fetch_from_buf failed."); + log(LOG_DEBUG,"directory_handle_reading(): fetch_from_buf failed (reading dir)."); return -1; } @@ -233,6 +262,7 @@ int connection_dir_finished_flushing(connection_t *conn) { case DIR_CONN_STATE_SENDING_COMMAND: log(LOG_DEBUG,"connection_dir_finished_flushing(): client finished sending command."); directorylen = 0; + reading_headers = 1; conn->state = DIR_CONN_STATE_READING; connection_watch_events(conn, POLLIN); return 0; diff --git a/src/or/or.h b/src/or/or.h index 0a9bf90c11..72eb79176f 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -387,8 +387,16 @@ int write_to_buf(char *string, int string_len, int fetch_from_buf(char *string, int string_len, char **buf, int *buflen, int *buf_datalen); - /* if there is string_len bytes in buf, write them onto string, - * * then memmove buf back (that is, remove them from buf) */ + /* if there is string_len bytes in buf, write them onto string, + * then memmove buf back (that is, remove them from buf) + */ + +int find_on_inbuf(char *string, int string_len, + char *buf, int buf_datalen); + /* find first instance of needle 'string' on haystack 'buf'. return how + * many bytes from the beginning of buf to the end of string. + * If it's not there, return -1. + */ /********************************* cell.c ***************************/ @@ -463,6 +471,7 @@ int connection_read_to_buf(connection_t *conn); int connection_fetch_from_buf(char *string, int len, connection_t *conn); int connection_outbuf_too_full(connection_t *conn); +int connection_find_on_inbuf(char *string, int len, connection_t *conn); int connection_wants_to_flush(connection_t *conn); int connection_flush_buf(connection_t *conn);