diff options
author | Roger Dingledine <arma@torproject.org> | 2003-09-17 20:09:06 +0000 |
---|---|---|
committer | Roger Dingledine <arma@torproject.org> | 2003-09-17 20:09:06 +0000 |
commit | b97945e41156f1da022c118d934e79c375d2a44e (patch) | |
tree | 8f9c7b4ec90bb60aa73c886e18f225c5b8e385a1 /src/or/directory.c | |
parent | a66669859e61ea3555dee60a77b11a3475bc7d6b (diff) | |
download | tor-b97945e41156f1da022c118d934e79c375d2a44e.tar tor-b97945e41156f1da022c118d934e79c375d2a44e.tar.gz |
add in directory 'post' support
svn:r471
Diffstat (limited to 'src/or/directory.c')
-rw-r--r-- | src/or/directory.c | 236 |
1 files changed, 124 insertions, 112 deletions
diff --git a/src/or/directory.c b/src/or/directory.c index 7d1d7d0f5..ac70ba08d 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -6,10 +6,9 @@ #define MAX_DIR_SIZE 50000 /* XXX, big enough? */ -static int directory_send_command(connection_t *conn); +static int directory_send_command(connection_t *conn, int command); static void directory_rebuild(void); static int directory_handle_command(connection_t *conn); -static int directory_handle_reading(connection_t *conn); /********* START VARIABLES **********/ @@ -17,7 +16,6 @@ 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 int directory_dirty=1; static char getstring[] = "GET / HTTP/1.0\r\n\r\n"; @@ -26,18 +24,21 @@ static char answerstring[] = "HTTP/1.0 200 OK\r\n\r\n"; /********* END VARIABLES ************/ -void directory_initiate_fetch(routerinfo_t *router) { +void directory_initiate_command(routerinfo_t *router, int command) { connection_t *conn; 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 */ - log_fn(LOG_DEBUG,"Canceling fetch, dir conn already active."); + if(connection_get_by_type(CONN_TYPE_DIR)) { /* there's already a dir conn running */ + log_fn(LOG_DEBUG,"Canceling connect, dir conn already active."); return; } - log_fn(LOG_DEBUG,"initiating directory fetch"); + if(command == DIR_CONN_STATE_CONNECTING_GET) + log_fn(LOG_DEBUG,"initiating directory get"); + else + log_fn(LOG_DEBUG,"initiating directory post"); conn = connection_new(CONN_TYPE_DIR); if(!conn) @@ -52,7 +53,7 @@ void directory_initiate_fetch(routerinfo_t *router) { if (router->signing_pkey) conn->pkey = crypto_pk_dup_key(router->signing_pkey); else { - log_fn(LOG_ERR, "No signing key known for directory %s; signature won't be checked", conn->address); + log_fn(LOG_ERR, "No signing key known for dirserver %s; signature won't be checked", conn->address); conn->pkey = NULL; } @@ -63,7 +64,7 @@ void directory_initiate_fetch(routerinfo_t *router) { switch(connection_connect(conn, router->address, router->addr, router->dir_port)) { case -1: - router_forget_router(conn->addr, conn->port); /* don't try him again */ + router_forget_router(conn->addr, conn->port); /* XXX don't try him again */ connection_free(conn); return; case 0: @@ -71,28 +72,45 @@ void directory_initiate_fetch(routerinfo_t *router) { connection_watch_events(conn, POLLIN | POLLOUT | POLLERR); /* writable indicates finish, readable indicates broken link, error indicates broken link in windowsland. */ - conn->state = DIR_CONN_STATE_CONNECTING; + conn->state = command; return; /* case 1: fall through */ } connection_set_poll_socket(conn); - if(directory_send_command(conn) < 0) { + if(directory_send_command(conn, command) < 0) { connection_remove(conn); connection_free(conn); } } -static int directory_send_command(connection_t *conn) { +static int directory_send_command(connection_t *conn, int command) { + char *s; assert(conn && conn->type == CONN_TYPE_DIR); - if(connection_write_to_buf(getstring, strlen(getstring), conn) < 0) { - log_fn(LOG_DEBUG,"Couldn't write command to buffer."); - return -1; + switch(command) { + case DIR_CONN_STATE_CONNECTING_GET: + if(connection_write_to_buf(getstring, strlen(getstring), conn) < 0) { + log_fn(LOG_DEBUG,"Couldn't write get to buffer."); + return -1; + } + conn->state = DIR_CONN_STATE_CLIENT_SENDING_GET; + break; + case DIR_CONN_STATE_CONNECTING_POST: + s = router_get_my_descriptor(); + if(!s) { + log_fn(LOG_DEBUG,"Failed to get my descriptor."); + return -1; + } + if(connection_write_to_buf(poststring, strlen(poststring), conn) < 0 || + connection_write_to_buf(s, strlen(s), conn) < 0) { + log_fn(LOG_DEBUG,"Couldn't write post/descriptor to buffer."); + return -1; + } + conn->state = DIR_CONN_STATE_CLIENT_SENDING_POST; + break; } - - conn->state = DIR_CONN_STATE_SENDING_COMMAND; return 0; } @@ -107,8 +125,8 @@ static void directory_rebuild(void) { log(LOG_ERR, "Error writing directory"); return; } - log(LOG_INFO,"New directory:\n%s",the_directory); directorylen = strlen(the_directory); + log(LOG_INFO,"New directory (size %d):\n%s",directorylen,the_directory); directory_dirty = 0; } else { log(LOG_INFO,"Directory still clean, reusing."); @@ -120,111 +138,101 @@ int connection_dir_process_inbuf(connection_t *conn) { assert(conn && conn->type == CONN_TYPE_DIR); if(conn->inbuf_reached_eof) { - if(conn->state != DIR_CONN_STATE_READING) { - log_fn(LOG_DEBUG,"conn reached eof, not reading. Closing."); - return -1; - } - /* eof reached, kill it, but first process the_directory and learn about new routers. */ - log_fn(LOG_DEBUG,"Received directory (size %d)\n%s", directorylen, the_directory); - if(directorylen == 0) { - log_fn(LOG_DEBUG,"Empty directory. Ignoring."); - return -1; - } - if(router_get_dir_from_string(the_directory, conn->pkey) < 0) { - log_fn(LOG_DEBUG,"...but parsing failed. Ignoring."); - } else { - log_fn(LOG_DEBUG,"and got an %s directory; updated routers.", - conn->pkey ? "authenticated" : "unauthenticated"); - } - - if(options.OnionRouter) { /* connect to them all */ - router_retry_connections(); + switch(conn->state) { + case DIR_CONN_STATE_CLIENT_READING_GET: + /* kill it, but first process the_directory and learn about new routers. */ + switch(connection_fetch_from_buf_http(conn, NULL, 0, the_directory, MAX_DIR_SIZE)) { + case -1: /* overflow */ + log_fn(LOG_DEBUG,"'get' response too large. Failing."); + return -1; + case 0: + log_fn(LOG_DEBUG,"'get' response not all here, but we're at eof. Closing."); + return -1; + /* case 1, fall through */ + } + directorylen = strlen(the_directory); + log_fn(LOG_DEBUG,"Received directory (size %d):\n%s", directorylen, the_directory); + if(directorylen == 0) { + log_fn(LOG_DEBUG,"Empty directory. Ignoring."); + return -1; + } + if(router_get_dir_from_string(the_directory, conn->pkey) < 0) { + log_fn(LOG_DEBUG,"...but parsing failed. Ignoring."); + } else { + log_fn(LOG_DEBUG,"and got an %s directory; updated routers.", + conn->pkey ? "authenticated" : "unauthenticated"); + } + if(options.OnionRouter) { /* connect to them all */ + router_retry_connections(); + } + return -1; + case DIR_CONN_STATE_CLIENT_READING_POST: + /* XXX make sure there's a 200 OK on the buffer */ + log_fn(LOG_DEBUG,"eof while reading post response. Finished."); + return -1; + default: + log_fn(LOG_DEBUG,"conn reached eof, not reading. Closing."); + return -1; } - return -1; } - switch(conn->state) { - case DIR_CONN_STATE_COMMAND_WAIT: - return directory_handle_command(conn); - case DIR_CONN_STATE_READING: - return directory_handle_reading(conn); - default: - log_fn(LOG_DEBUG,"Got data while writing; Ignoring."); - break; - } + if(conn->state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) + return directory_handle_command(conn); + + /* XXX for READ states, might want to make sure inbuf isn't too big */ + log_fn(LOG_DEBUG,"Got data, not eof. Leaving on inbuf."); return 0; } static int directory_handle_command(connection_t *conn) { - char buf[15]; + char headers[1024]; + char body[1024]; assert(conn && conn->type == CONN_TYPE_DIR); - if(conn->inbuf_datalen < (int)strlen(getstring)) { /* entire response available? */ - log_fn(LOG_DEBUG,"Entire command not here yet. Waiting."); - return 0; /* not yet */ - } - - connection_fetch_from_buf(buf,strlen(getstring),conn); - - if(strncasecmp(buf,getstring,strlen("GET / HTTP/"))) { - log_fn(LOG_DEBUG,"Command doesn't seem to be a get. Closing,"); - return -1; - } - - directory_rebuild(); /* rebuild it now, iff it's dirty */ - - if(directorylen == 0) { - log_fn(LOG_DEBUG,"My directory is empty. Closing."); - return -1; - } - - log_fn(LOG_DEBUG,"Dumping directory to client."); - if((connection_write_to_buf(answerstring, strlen(answerstring), conn) < 0) || - (connection_write_to_buf(the_directory, directorylen, conn) < 0)) { - log_fn(LOG_DEBUG,"my outbuf is full. Oops."); - return -1; + switch(connection_fetch_from_buf_http(conn, headers, sizeof(headers), body, sizeof(body))) { + case -1: /* overflow */ + log_fn(LOG_DEBUG,"input too large. Failing."); + return -1; + case 0: + log_fn(LOG_DEBUG,"command not all here yet."); + return 0; + /* case 1, fall through */ } - conn->state = DIR_CONN_STATE_WRITING; - return 0; -} + log_fn(LOG_DEBUG,"headers '%s', body '%s'.",headers,body); + if(!strncasecmp(headers,"GET",3)) { -static int directory_handle_reading(connection_t *conn) { - int amt; - char *headers; + directory_rebuild(); /* rebuild it now, iff it's dirty */ - assert(conn && conn->type == CONN_TYPE_DIR); + if(directorylen == 0) { + log_fn(LOG_DEBUG,"My directory is empty. Closing."); + return -1; + } - if(reading_headers) { - amt = connection_find_on_inbuf("\r\n\r\n", 4, conn); - if(amt < 0) /* not there yet */ - return 0; - headers = tor_malloc(amt+1); - connection_fetch_from_buf(headers,amt,conn); - headers[amt] = 0; /* null terminate it, */ - free(headers); /* and then throw it away */ - reading_headers = 0; + log_fn(LOG_DEBUG,"Dumping directory to client."); + if((connection_write_to_buf(answerstring, strlen(answerstring), conn) < 0) || + (connection_write_to_buf(the_directory, directorylen, conn) < 0)) { + log_fn(LOG_DEBUG,"Failed to write answerstring+directory to outbuf."); + return -1; + } + conn->state = DIR_CONN_STATE_SERVER_WRITING; + return 0; } - amt = conn->inbuf_datalen; - - if(amt + directorylen >= MAX_DIR_SIZE) { - log_fn(LOG_DEBUG,"Directory too large. Failing messily."); - return -1; + if(!strncasecmp(headers,"POST",4)) { + log_fn(LOG_DEBUG,"Received POST command, body '%s'", body); + if(connection_write_to_buf(answerstring, strlen(answerstring), conn) < 0) { + log_fn(LOG_DEBUG,"Failed to write answerstring to outbuf."); + return -1; + } + conn->state = DIR_CONN_STATE_SERVER_WRITING; + return 0; } - log_fn(LOG_DEBUG,"Pulling %d bytes in at offset %d.", - amt, directorylen); - - connection_fetch_from_buf(the_directory+directorylen,amt,conn); - - directorylen += amt; - - the_directory[directorylen] = 0; - - return 0; + log_fn(LOG_DEBUG,"Got headers with unknown command. Closing."); + return -1; } int connection_dir_finished_flushing(connection_t *conn) { @@ -233,7 +241,8 @@ int connection_dir_finished_flushing(connection_t *conn) { assert(conn && conn->type == CONN_TYPE_DIR); switch(conn->state) { - case DIR_CONN_STATE_CONNECTING: + case DIR_CONN_STATE_CONNECTING_GET: + case DIR_CONN_STATE_CONNECTING_POST: if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) { /* not yet */ if(!ERRNO_CONN_EINPROGRESS(errno)) { log_fn(LOG_DEBUG,"in-progress connect failed. Removing."); @@ -248,16 +257,19 @@ int connection_dir_finished_flushing(connection_t *conn) { log_fn(LOG_DEBUG,"Dir connection to router %s:%u established.", conn->address,conn->port); - return directory_send_command(conn); - case DIR_CONN_STATE_SENDING_COMMAND: - log_fn(LOG_DEBUG,"client finished sending command."); - directorylen = 0; - reading_headers = 1; - conn->state = DIR_CONN_STATE_READING; + return directory_send_command(conn, conn->state); + case DIR_CONN_STATE_CLIENT_SENDING_GET: + log_fn(LOG_DEBUG,"client finished sending 'get' command."); + conn->state = DIR_CONN_STATE_CLIENT_READING_GET; + connection_watch_events(conn, POLLIN); + return 0; + case DIR_CONN_STATE_CLIENT_SENDING_POST: + log_fn(LOG_DEBUG,"client finished sending 'post' command."); + conn->state = DIR_CONN_STATE_CLIENT_READING_POST; connection_watch_events(conn, POLLIN); return 0; - case DIR_CONN_STATE_WRITING: - log_fn(LOG_DEBUG,"Finished writing directory. Closing."); + case DIR_CONN_STATE_SERVER_WRITING: + log_fn(LOG_DEBUG,"Finished writing server response. Closing."); return -1; /* kill it */ default: log_fn(LOG_DEBUG,"BUG: called in unexpected state."); |