directory.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /* Copyright 2001,2002,2003 Roger Dingledine. */
  2. /* See LICENSE for licensing information */
  3. /* $Id$ */
  4. #include "or.h"
  5. static int directory_send_command(connection_t *conn, int command);
  6. static int directory_handle_command(connection_t *conn);
  7. /********* START VARIABLES **********/
  8. extern or_options_t options; /* command-line and config-file options */
  9. static char fetchstring[] = "GET / HTTP/1.0\r\n\r\n";
  10. static char answerstring[] = "HTTP/1.0 200 OK\r\n\r\n";
  11. /********* END VARIABLES ************/
  12. void directory_initiate_command(routerinfo_t *router, int command) {
  13. connection_t *conn;
  14. if (command == DIR_CONN_STATE_CONNECTING_FETCH)
  15. log_fn(LOG_DEBUG,"initiating directory fetch");
  16. else
  17. log_fn(LOG_DEBUG,"initiating directory upload");
  18. if (!router) { /* i guess they didn't have one in mind for me to use */
  19. log_fn(LOG_WARN,"No running dirservers known. Not trying.");
  20. return;
  21. }
  22. conn = connection_new(CONN_TYPE_DIR);
  23. /* set up conn so it's got all the data we need to remember */
  24. conn->addr = router->addr;
  25. conn->port = router->dir_port;
  26. conn->address = tor_strdup(router->address);
  27. conn->nickname = tor_strdup(router->nickname);
  28. assert(router->identity_pkey);
  29. conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey);
  30. if(connection_add(conn) < 0) { /* no space, forget it */
  31. connection_free(conn);
  32. return;
  33. }
  34. switch(connection_connect(conn, router->address, router->addr, router->dir_port)) {
  35. case -1:
  36. router_mark_as_down(conn->nickname); /* don't try him again */
  37. connection_remove(conn);
  38. connection_free(conn);
  39. return;
  40. case 0:
  41. connection_set_poll_socket(conn);
  42. connection_watch_events(conn, POLLIN | POLLOUT | POLLERR);
  43. /* writable indicates finish, readable indicates broken link,
  44. error indicates broken link in windowsland. */
  45. conn->state = command;
  46. return;
  47. /* case 1: fall through */
  48. }
  49. connection_set_poll_socket(conn);
  50. if(directory_send_command(conn, command) < 0) {
  51. connection_remove(conn);
  52. connection_free(conn);
  53. }
  54. }
  55. static int directory_send_command(connection_t *conn, int command) {
  56. const char *s;
  57. char tmp[8192];
  58. assert(conn && conn->type == CONN_TYPE_DIR);
  59. switch(command) {
  60. case DIR_CONN_STATE_CONNECTING_FETCH:
  61. connection_write_to_buf(fetchstring, strlen(fetchstring), conn);
  62. conn->state = DIR_CONN_STATE_CLIENT_SENDING_FETCH;
  63. break;
  64. case DIR_CONN_STATE_CONNECTING_UPLOAD:
  65. s = router_get_my_descriptor();
  66. if(!s) {
  67. log_fn(LOG_WARN,"Failed to get my descriptor.");
  68. return -1;
  69. }
  70. snprintf(tmp, sizeof(tmp), "POST / HTTP/1.0\r\nContent-Length: %d\r\n\r\n%s",
  71. (int)strlen(s), s);
  72. connection_write_to_buf(tmp, strlen(tmp), conn);
  73. conn->state = DIR_CONN_STATE_CLIENT_SENDING_UPLOAD;
  74. break;
  75. }
  76. return 0;
  77. }
  78. int connection_dir_process_inbuf(connection_t *conn) {
  79. char *directory;
  80. int directorylen=0;
  81. assert(conn && conn->type == CONN_TYPE_DIR);
  82. if(conn->inbuf_reached_eof) {
  83. switch(conn->state) {
  84. case DIR_CONN_STATE_CLIENT_READING_FETCH:
  85. /* kill it, but first fetch/process the directory to learn about new routers. */
  86. switch(fetch_from_buf_http(conn->inbuf,
  87. NULL, 0, &directory, MAX_DIR_SIZE)) {
  88. case -1: /* overflow */
  89. log_fn(LOG_WARN,"'fetch' response too large. Failing.");
  90. return -1;
  91. case 0:
  92. log_fn(LOG_INFO,"'fetch' response not all here, but we're at eof. Closing.");
  93. return -1;
  94. /* case 1, fall through */
  95. }
  96. /* XXX check headers, at least make sure returned 2xx */
  97. directorylen = strlen(directory);
  98. log_fn(LOG_INFO,"Received directory (size %d):\n%s", directorylen, directory);
  99. if(directorylen == 0) {
  100. log_fn(LOG_INFO,"Empty directory. Ignoring.");
  101. free(directory);
  102. return -1;
  103. }
  104. if(router_set_routerlist_from_directory(directory, conn->identity_pkey) < 0){
  105. log_fn(LOG_INFO,"...but parsing failed. Ignoring.");
  106. } else {
  107. log_fn(LOG_INFO,"updated routers.");
  108. }
  109. if(options.ORPort) { /* connect to them all */
  110. router_retry_connections();
  111. }
  112. free(directory);
  113. return -1;
  114. case DIR_CONN_STATE_CLIENT_READING_UPLOAD:
  115. /* XXX make sure there's a 200 OK on the buffer */
  116. log_fn(LOG_INFO,"eof while reading upload response. Finished.");
  117. return -1;
  118. default:
  119. log_fn(LOG_INFO,"conn reached eof, not reading. Closing.");
  120. return -1;
  121. }
  122. }
  123. if(conn->state == DIR_CONN_STATE_SERVER_COMMAND_WAIT)
  124. return directory_handle_command(conn);
  125. /* XXX for READ states, might want to make sure inbuf isn't too big */
  126. log_fn(LOG_DEBUG,"Got data, not eof. Leaving on inbuf.");
  127. return 0;
  128. }
  129. static int directory_handle_command_get(connection_t *conn,
  130. char *headers, char *body) {
  131. size_t dlen;
  132. const char *cp;
  133. /* XXX should check url and http version */
  134. log_fn(LOG_DEBUG,"Received GET command.");
  135. dlen = dirserv_get_directory(&cp);
  136. if(dlen == 0) {
  137. log_fn(LOG_WARN,"My directory is empty. Closing.");
  138. return -1; /* XXX send some helpful http error code */
  139. }
  140. log_fn(LOG_DEBUG,"Dumping directory to client.");
  141. connection_write_to_buf(answerstring, strlen(answerstring), conn);
  142. connection_write_to_buf(cp, dlen, conn);
  143. conn->state = DIR_CONN_STATE_SERVER_WRITING;
  144. return 0;
  145. }
  146. static int directory_handle_command_post(connection_t *conn,
  147. char *headers, char *body) {
  148. const char *cp;
  149. /* XXX should check url and http version */
  150. log_fn(LOG_DEBUG,"Received POST command.");
  151. cp = body;
  152. if(dirserv_add_descriptor(&cp) < 0) {
  153. log_fn(LOG_WARN,"dirserv_add_descriptor() failed. Dropping.");
  154. return -1; /* XXX should write an http failed code */
  155. }
  156. dirserv_get_directory(&cp); /* rebuild and write to disk */
  157. connection_write_to_buf(answerstring, strlen(answerstring), conn);
  158. conn->state = DIR_CONN_STATE_SERVER_WRITING;
  159. return 0;
  160. }
  161. static int directory_handle_command(connection_t *conn) {
  162. char *headers=NULL, *body=NULL;
  163. int r;
  164. #define MAX_HEADERS_SIZE 2048
  165. #define MAX_BODY_SIZE 500000
  166. assert(conn && conn->type == CONN_TYPE_DIR);
  167. switch(fetch_from_buf_http(conn->inbuf,
  168. &headers, MAX_HEADERS_SIZE, &body, MAX_BODY_SIZE)) {
  169. case -1: /* overflow */
  170. log_fn(LOG_WARN,"input too large. Failing.");
  171. return -1;
  172. case 0:
  173. log_fn(LOG_DEBUG,"command not all here yet.");
  174. return 0;
  175. /* case 1, fall through */
  176. }
  177. log_fn(LOG_DEBUG,"headers '%s', body '%s'.", headers, body);
  178. if(!strncasecmp(headers,"GET",3))
  179. r = directory_handle_command_get(conn, headers, body);
  180. else if (!strncasecmp(headers,"POST",4))
  181. r = directory_handle_command_post(conn, headers, body);
  182. else {
  183. log_fn(LOG_WARN,"Got headers '%s' with unknown command. Closing.", headers);
  184. r = -1;
  185. }
  186. tor_free(headers); tor_free(body);
  187. return r;
  188. }
  189. int connection_dir_finished_flushing(connection_t *conn) {
  190. int e, len=sizeof(e);
  191. assert(conn && conn->type == CONN_TYPE_DIR);
  192. switch(conn->state) {
  193. case DIR_CONN_STATE_CONNECTING_FETCH:
  194. case DIR_CONN_STATE_CONNECTING_UPLOAD:
  195. if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) { /* not yet */
  196. if(!ERRNO_CONN_EINPROGRESS(errno)) {
  197. log_fn(LOG_DEBUG,"in-progress connect failed. Removing.");
  198. router_mark_as_down(conn->nickname); /* don't try him again */
  199. return -1;
  200. } else {
  201. return 0; /* no change, see if next time is better */
  202. }
  203. }
  204. /* the connect has finished. */
  205. log_fn(LOG_INFO,"Dir connection to router %s:%u established.",
  206. conn->address,conn->port);
  207. return directory_send_command(conn, conn->state);
  208. case DIR_CONN_STATE_CLIENT_SENDING_FETCH:
  209. log_fn(LOG_DEBUG,"client finished sending fetch command.");
  210. conn->state = DIR_CONN_STATE_CLIENT_READING_FETCH;
  211. connection_watch_events(conn, POLLIN);
  212. return 0;
  213. case DIR_CONN_STATE_CLIENT_SENDING_UPLOAD:
  214. log_fn(LOG_DEBUG,"client finished sending upload command.");
  215. conn->state = DIR_CONN_STATE_CLIENT_READING_UPLOAD;
  216. connection_watch_events(conn, POLLIN);
  217. return 0;
  218. case DIR_CONN_STATE_SERVER_WRITING:
  219. log_fn(LOG_INFO,"Finished writing server response. Closing.");
  220. return -1; /* kill it */
  221. default:
  222. log_fn(LOG_WARN,"BUG: called in unexpected state.");
  223. return -1;
  224. }
  225. return 0;
  226. }
  227. /*
  228. Local Variables:
  229. mode:c
  230. indent-tabs-mode:nil
  231. c-basic-offset:2
  232. End:
  233. */