directory.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. /* Copyright 2001,2002,2003 Roger Dingledine. */
  2. /* See LICENSE for licensing information */
  3. /* $Id$ */
  4. #include "or.h"
  5. /**
  6. * \file directory.c
  7. * \brief Implement directory HTTP protocol.
  8. **/
  9. /* In-points to directory.c:
  10. *
  11. * - directory_post_to_dirservers(), called from
  12. * router_upload_dir_desc_to_dirservers() in router.c
  13. * upload_service_descriptor() in rendservice.c
  14. * - directory_get_from_dirserver(), called from
  15. * rend_client_refetch_renddesc() in rendclient.c
  16. * run_scheduled_events() in main.c
  17. * do_hup() in main.c
  18. * - connection_dir_process_inbuf(), called from
  19. * connection_process_inbuf() in connection.c
  20. * - connection_dir_finished_flushing(), called from
  21. * connection_finished_flushing() in connection.c
  22. * - connection_dir_finished_connecting(), called from
  23. * connection_finished_connecting() in connection.c
  24. */
  25. static void
  26. directory_initiate_command(routerinfo_t *router, uint8_t purpose,
  27. const char *payload, int payload_len);
  28. static void directory_send_command(connection_t *conn, int purpose,
  29. const char *payload, int payload_len);
  30. static int directory_handle_command(connection_t *conn);
  31. /********* START VARIABLES **********/
  32. extern or_options_t options; /* command-line and config-file options */
  33. /** URL for publishing rendezvous descriptors. */
  34. char rend_publish_string[] = "/rendezvous/publish";
  35. /** Prefix for downloading rendezvous descriptors. */
  36. char rend_fetch_url[] = "/rendezvous/";
  37. #define MAX_HEADERS_SIZE 50000
  38. #define MAX_BODY_SIZE 500000
  39. /********* END VARIABLES ************/
  40. /** Start a connection to every known directory server, using
  41. * connection purpose 'purpose' and uploading the payload 'payload'
  42. * (length 'payload_len'). The purpose should be one of
  43. * 'DIR_PURPOSE_UPLOAD_DIR' or 'DIR_PURPOSE_UPLOAD_RENDDESC'.
  44. */
  45. void
  46. directory_post_to_dirservers(uint8_t purpose, const char *payload,
  47. int payload_len)
  48. {
  49. int i;
  50. routerinfo_t *router;
  51. routerlist_t *rl;
  52. router_get_routerlist(&rl);
  53. if(!rl)
  54. return;
  55. for(i=0; i < smartlist_len(rl->routers); i++) {
  56. router = smartlist_get(rl->routers, i);
  57. if(router->is_trusted_dir)
  58. directory_initiate_command(router, purpose, payload, payload_len);
  59. }
  60. }
  61. /** Start a connection to a random running directory server, using
  62. * connection purpose 'purpose' requesting 'payload' (length
  63. * 'payload_len'). The purpose should be one of
  64. * 'DIR_PURPOSE_FETCH_DIR' or 'DIR_PURPOSE_FETCH_RENDDESC'.
  65. */
  66. void
  67. directory_get_from_dirserver(uint8_t purpose, const char *payload,
  68. int payload_len)
  69. {
  70. directory_initiate_command(router_pick_directory_server(),
  71. purpose, payload, payload_len);
  72. }
  73. /** Launch a new connection to the directory server <b>router</b> to upload or
  74. * download a service or rendezvous descriptor. <b>purpose</b> determines what
  75. * kind of directory connection we're launching, and must be one of
  76. * DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC}.
  77. *
  78. * When uploading, <b>payload</b> and <b>payload_len</b> determine the content
  79. * of the HTTP post. When fetching a rendezvous descriptor, <b>payload</b>
  80. * and <b>payload_len</b> are the service ID we want to fetch.
  81. */
  82. static void
  83. directory_initiate_command(routerinfo_t *router, uint8_t purpose,
  84. const char *payload, int payload_len)
  85. {
  86. connection_t *conn;
  87. switch (purpose)
  88. {
  89. case DIR_PURPOSE_FETCH_DIR:
  90. log_fn(LOG_DEBUG,"initiating directory fetch");
  91. break;
  92. case DIR_PURPOSE_FETCH_RENDDESC:
  93. log_fn(LOG_DEBUG,"initiating hidden-service descriptor fetch");
  94. break;
  95. case DIR_PURPOSE_UPLOAD_DIR:
  96. log_fn(LOG_DEBUG,"initiating server descriptor upload");
  97. break;
  98. case DIR_PURPOSE_UPLOAD_RENDDESC:
  99. log_fn(LOG_DEBUG,"initiating hidden-service descriptor upload");
  100. break;
  101. default:
  102. log_fn(LOG_ERR, "Unrecognized directory connection purpose.");
  103. tor_assert(0);
  104. }
  105. if (!router) { /* i guess they didn't have one in mind for me to use */
  106. log_fn(LOG_WARN,"No running dirservers known. Not trying. (purpose %d)", purpose);
  107. return;
  108. }
  109. tor_assert(router->dir_port);
  110. conn = connection_new(CONN_TYPE_DIR);
  111. /* set up conn so it's got all the data we need to remember */
  112. conn->addr = router->addr;
  113. conn->port = router->dir_port;
  114. conn->address = tor_strdup(router->address);
  115. conn->nickname = tor_strdup(router->nickname);
  116. tor_assert(router->identity_pkey);
  117. conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey);
  118. conn->purpose = purpose;
  119. /* give it an initial state */
  120. conn->state = DIR_CONN_STATE_CONNECTING;
  121. if(purpose == DIR_PURPOSE_FETCH_DIR ||
  122. purpose == DIR_PURPOSE_UPLOAD_DIR) {
  123. /* then we want to connect directly */
  124. switch(connection_connect(conn, conn->address, conn->addr, conn->port)) {
  125. case -1:
  126. router_mark_as_down(conn->nickname); /* don't try him again */
  127. connection_free(conn);
  128. return;
  129. case 1:
  130. conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
  131. /* fall through */
  132. case 0:
  133. /* queue the command on the outbuf */
  134. directory_send_command(conn, purpose, payload, payload_len);
  135. connection_watch_events(conn, POLLIN | POLLOUT | POLLERR);
  136. /* writable indicates finish, readable indicates broken link,
  137. error indicates broken link in windowsland. */
  138. }
  139. } else { /* we want to connect via tor */
  140. /* make an AP connection
  141. * populate it and add it at the right state
  142. * socketpair and hook up both sides
  143. */
  144. conn->s = connection_ap_make_bridge(conn->address, conn->port);
  145. if(conn->s < 0) {
  146. log_fn(LOG_WARN,"Making AP bridge to dirserver failed.");
  147. connection_mark_for_close(conn);
  148. return;
  149. }
  150. conn->state = DIR_CONN_STATE_CLIENT_SENDING;
  151. connection_add(conn);
  152. /* queue the command on the outbuf */
  153. directory_send_command(conn, purpose, payload, payload_len);
  154. connection_watch_events(conn, POLLIN | POLLOUT | POLLERR);
  155. }
  156. }
  157. /** Queue an appropriate HTTP command on conn-\>outbuf. The args
  158. * <b>purpose</b>, <b>payload</b>, and <b>payload_len</b> are as in
  159. * directory_initiate_command.
  160. */
  161. static void directory_send_command(connection_t *conn, int purpose,
  162. const char *payload, int payload_len) {
  163. char fetchwholedir[] = "GET / HTTP/1.0\r\n\r\n";
  164. char fetchrunninglist[] = "GET /running-routers HTTP/1.0\r\n\r\n";
  165. char tmp[8192];
  166. tor_assert(conn && conn->type == CONN_TYPE_DIR);
  167. switch(purpose) {
  168. case DIR_PURPOSE_FETCH_DIR:
  169. tor_assert(payload == NULL);
  170. connection_write_to_buf(fetchwholedir, strlen(fetchwholedir), conn);
  171. break;
  172. case DIR_PURPOSE_FETCH_RUNNING_LIST:
  173. tor_assert(payload == NULL);
  174. connection_write_to_buf(fetchrunninglist, strlen(fetchrunninglist), conn);
  175. break;
  176. case DIR_PURPOSE_UPLOAD_DIR:
  177. tor_assert(payload);
  178. snprintf(tmp, sizeof(tmp), "POST / HTTP/1.0\r\nContent-Length: %d\r\n\r\n",
  179. payload_len);
  180. connection_write_to_buf(tmp, strlen(tmp), conn);
  181. connection_write_to_buf(payload, payload_len, conn);
  182. break;
  183. case DIR_PURPOSE_FETCH_RENDDESC:
  184. tor_assert(payload);
  185. /* this must be true or we wouldn't be doing the lookup */
  186. tor_assert(payload_len <= REND_SERVICE_ID_LEN);
  187. /* This breaks the function abstraction. */
  188. memcpy(conn->rend_query, payload, payload_len);
  189. conn->rend_query[payload_len] = 0;
  190. snprintf(tmp, sizeof(tmp), "GET %s%s HTTP/1.0\r\n\r\n", rend_fetch_url, payload);
  191. connection_write_to_buf(tmp, strlen(tmp), conn);
  192. break;
  193. case DIR_PURPOSE_UPLOAD_RENDDESC:
  194. tor_assert(payload);
  195. snprintf(tmp, sizeof(tmp),
  196. "POST %s HTTP/1.0\r\nContent-Length: %d\r\n\r\n", rend_publish_string, payload_len);
  197. connection_write_to_buf(tmp, strlen(tmp), conn);
  198. /* could include nuls, need to write it separately */
  199. connection_write_to_buf(payload, payload_len, conn);
  200. break;
  201. }
  202. }
  203. /** Parse an HTTP request string <b>headers</b> of the form "\%s \%s HTTP/1..."
  204. * If it's well-formed, point *<b>url</b> to the second \%s,
  205. * null-terminate it (this modifies headers!) and return 0.
  206. * Otherwise, return -1.
  207. */
  208. static int
  209. parse_http_url(char *headers, char **url)
  210. {
  211. char *s, *tmp;
  212. s = (char *)eat_whitespace_no_nl(headers);
  213. if (!*s) return -1;
  214. s = (char *)find_whitespace(s); /* get past GET/POST */
  215. if (!*s) return -1;
  216. s = (char *)eat_whitespace_no_nl(s);
  217. if (!*s) return -1;
  218. tmp = s; /* this is it, assuming it's valid */
  219. s = (char *)find_whitespace(s);
  220. if (!*s) return -1;
  221. *s = 0;
  222. *url = tmp;
  223. return 0;
  224. }
  225. /** Parse an HTTP response string <b>headers</b> of the form
  226. * "HTTP/1.\%d \%d\%s\r\n...".
  227. * If it's well-formed, assign *<b>code</b>, point *<b>message</b> to the first
  228. * non-space character after code if there is one and message is non-NULL
  229. * (else leave it alone), and return 0.
  230. * Otherwise, return -1.
  231. */
  232. static int
  233. parse_http_response(char *headers, int *code, char **message)
  234. {
  235. int n1, n2;
  236. tor_assert(headers && code);
  237. while(isspace((int)*headers)) headers++; /* tolerate leading whitespace */
  238. if(sscanf(headers, "HTTP/1.%d %d", &n1, &n2) < 2 ||
  239. (n1 != 0 && n1 != 1) ||
  240. (n2 < 100 || n2 >= 600)) {
  241. log_fn(LOG_WARN,"Failed to parse header '%s'",headers);
  242. return -1;
  243. }
  244. *code = n2;
  245. if(message) {
  246. /* XXX should set *message correctly */
  247. }
  248. return 0;
  249. }
  250. /** Read handler for directory connections. (That's connections <em>to</em>
  251. * directory servers and connections <em>at</em> directory servers.)
  252. */
  253. int connection_dir_process_inbuf(connection_t *conn) {
  254. char *body;
  255. char *headers;
  256. int body_len=0;
  257. int status_code;
  258. tor_assert(conn && conn->type == CONN_TYPE_DIR);
  259. /* Directory clients write, then read data until they receive EOF;
  260. * directory servers read data until they get an HTTP command, then
  261. * write their response (when it's finished flushing, they mark for
  262. * close).
  263. */
  264. if(conn->inbuf_reached_eof) {
  265. if(conn->state != DIR_CONN_STATE_CLIENT_READING) {
  266. log_fn(LOG_INFO,"conn reached eof, not reading. Closing.");
  267. connection_close_immediate(conn); /* it was an error; give up on flushing */
  268. connection_mark_for_close(conn);
  269. return -1;
  270. }
  271. switch(fetch_from_buf_http(conn->inbuf,
  272. &headers, MAX_HEADERS_SIZE,
  273. &body, &body_len, MAX_DIR_SIZE)) {
  274. case -1: /* overflow */
  275. log_fn(LOG_WARN,"'fetch' response too large. Failing.");
  276. connection_mark_for_close(conn);
  277. return -1;
  278. case 0:
  279. log_fn(LOG_INFO,"'fetch' response not all here, but we're at eof. Closing.");
  280. connection_mark_for_close(conn);
  281. return -1;
  282. /* case 1, fall through */
  283. }
  284. if(parse_http_response(headers, &status_code, NULL) < 0) {
  285. log_fn(LOG_WARN,"Unparseable headers. Closing.");
  286. free(body); free(headers);
  287. connection_mark_for_close(conn);
  288. return -1;
  289. }
  290. if(conn->purpose == DIR_PURPOSE_FETCH_DIR) {
  291. /* fetch/process the directory to learn about new routers. */
  292. log_fn(LOG_INFO,"Received directory (size %d):\n%s", body_len, body);
  293. if(status_code == 503 || body_len == 0) {
  294. log_fn(LOG_INFO,"Empty directory. Ignoring.");
  295. free(body); free(headers);
  296. connection_mark_for_close(conn);
  297. return 0;
  298. }
  299. if(status_code != 200) {
  300. log_fn(LOG_WARN,"Received http status code %d from dirserver. Failing.",
  301. status_code);
  302. free(body); free(headers);
  303. connection_mark_for_close(conn);
  304. return -1;
  305. }
  306. if(router_load_routerlist_from_directory(body, NULL) < 0){
  307. log_fn(LOG_INFO,"...but parsing failed. Ignoring.");
  308. } else {
  309. log_fn(LOG_INFO,"updated routers.");
  310. }
  311. directory_has_arrived(); /* do things we've been waiting to do */
  312. }
  313. if(conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
  314. running_routers_t *rrs;
  315. routerlist_t *rl;
  316. /* just update our list of running routers, if this list is new info */
  317. log_fn(LOG_INFO,"Received running-routers list (size %d):\n%s", body_len, body);
  318. if(status_code != 200) {
  319. log_fn(LOG_WARN,"Received http status code %d from dirserver. Failing.",
  320. status_code);
  321. free(body); free(headers);
  322. connection_mark_for_close(conn);
  323. return -1;
  324. }
  325. if (!(rrs = router_parse_runningrouters(body))) {
  326. log_fn(LOG_WARN, "Can't parse runningrouters list");
  327. free(body); free(headers);
  328. connection_mark_for_close(conn);
  329. return -1;
  330. }
  331. router_get_routerlist(&rl);
  332. routerlist_update_from_runningrouters(rl,rrs);
  333. running_routers_free(rrs);
  334. }
  335. if(conn->purpose == DIR_PURPOSE_UPLOAD_DIR) {
  336. switch(status_code) {
  337. case 200:
  338. log_fn(LOG_INFO,"eof (status 200) after uploading server descriptor: finished.");
  339. break;
  340. case 400:
  341. log_fn(LOG_WARN,"http status 400 (bad request) response from dirserver. Malformed server descriptor?");
  342. break;
  343. case 403:
  344. 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.");
  345. break;
  346. default:
  347. log_fn(LOG_WARN,"http status %d response unrecognized.", status_code);
  348. break;
  349. }
  350. }
  351. if(conn->purpose == DIR_PURPOSE_FETCH_RENDDESC) {
  352. log_fn(LOG_INFO,"Received rendezvous descriptor (size %d, status code %d)",
  353. body_len, status_code);
  354. switch(status_code) {
  355. case 200:
  356. if(rend_cache_store(body, body_len) < 0) {
  357. log_fn(LOG_WARN,"Failed to store rendezvous descriptor.");
  358. /* alice's ap_stream will notice when connection_mark_for_close
  359. * cleans it up */
  360. } else {
  361. /* success. notify pending connections about this. */
  362. rend_client_desc_fetched(conn->rend_query, 1);
  363. conn->purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
  364. }
  365. break;
  366. case 404:
  367. /* not there. pending connections will be notified when
  368. * connection_mark_for_close cleans it up. */
  369. break;
  370. case 400:
  371. log_fn(LOG_WARN,"http status 400 (bad request). Dirserver didn't like our rendezvous query?");
  372. break;
  373. }
  374. }
  375. if(conn->purpose == DIR_PURPOSE_UPLOAD_RENDDESC) {
  376. switch(status_code) {
  377. case 200:
  378. log_fn(LOG_INFO,"eof (status 200) after uploading rendezvous descriptor: finished.");
  379. break;
  380. case 400:
  381. log_fn(LOG_WARN,"http status 400 (bad request) response from dirserver. Malformed rendezvous descriptor?");
  382. break;
  383. default:
  384. log_fn(LOG_WARN,"http status %d response unrecognized.", status_code);
  385. break;
  386. }
  387. }
  388. free(body); free(headers);
  389. connection_mark_for_close(conn);
  390. return 0;
  391. } /* endif 'reached eof' */
  392. /* If we're on the dirserver side, look for a command. */
  393. if(conn->state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
  394. if (directory_handle_command(conn) < 0) {
  395. connection_mark_for_close(conn);
  396. return -1;
  397. }
  398. return 0;
  399. }
  400. /* XXX for READ states, might want to make sure inbuf isn't too big */
  401. log_fn(LOG_DEBUG,"Got data, not eof. Leaving on inbuf.");
  402. return 0;
  403. }
  404. static char answer200[] = "HTTP/1.0 200 OK\r\n\r\n";
  405. static char answer400[] = "HTTP/1.0 400 Bad request\r\n\r\n";
  406. static char answer403[] = "HTTP/1.0 403 Unapproved server\r\n\r\n";
  407. static char answer404[] = "HTTP/1.0 404 Not found\r\n\r\n";
  408. static char answer503[] = "HTTP/1.0 503 Directory unavailable\r\n\r\n";
  409. /** Helper function: called when a dirserver gets a complete HTTP GET
  410. * request. Look for a request for a directory or for a rendezvous
  411. * service descriptor. On finding one, write a response into
  412. * conn-\>outbuf. If the request is unrecognized, send a 404.
  413. * Always return 0. */
  414. static int
  415. directory_handle_command_get(connection_t *conn, char *headers,
  416. char *body, int body_len)
  417. {
  418. size_t dlen;
  419. const char *cp;
  420. char *url;
  421. char tmp[8192];
  422. log_fn(LOG_DEBUG,"Received GET command.");
  423. conn->state = DIR_CONN_STATE_SERVER_WRITING;
  424. if (parse_http_url(headers, &url) < 0) {
  425. connection_write_to_buf(answer400, strlen(answer400), conn);
  426. return 0;
  427. }
  428. if(!strcmp(url,"/")) { /* directory fetch */
  429. dlen = dirserv_get_directory(&cp);
  430. if(dlen == 0) {
  431. log_fn(LOG_WARN,"My directory is empty. Closing.");
  432. connection_write_to_buf(answer503, strlen(answer503), conn);
  433. return 0;
  434. }
  435. log_fn(LOG_DEBUG,"Dumping directory to client.");
  436. snprintf(tmp, sizeof(tmp), "HTTP/1.0 200 OK\r\nContent-Length: %d\r\nContent-Type: text/plain\r\n\r\n",
  437. (int)dlen);
  438. connection_write_to_buf(tmp, strlen(tmp), conn);
  439. connection_write_to_buf(cp, strlen(cp), conn);
  440. return 0;
  441. }
  442. if(!strcmp(url,"/running-routers")) { /* running-routers fetch */
  443. dlen = dirserv_get_runningrouters(&cp);
  444. snprintf(tmp, sizeof(tmp), "HTTP/1.0 200 OK\r\nContent-Length: %d\r\nContent-Type: text/plain\r\n\r\n",
  445. (int)dlen);
  446. connection_write_to_buf(tmp, strlen(tmp), conn);
  447. connection_write_to_buf(cp, strlen(cp), conn);
  448. return 0;
  449. }
  450. if(!strncmp(url,rend_fetch_url,strlen(rend_fetch_url))) {
  451. /* rendezvous descriptor fetch */
  452. const char *descp;
  453. int desc_len;
  454. switch(rend_cache_lookup_desc(url+strlen(rend_fetch_url), &descp, &desc_len)) {
  455. case 1: /* valid */
  456. snprintf(tmp, sizeof(tmp), "HTTP/1.0 200 OK\r\nContent-Length: %d\r\nContent-Type: application/octet-stream\r\n\r\n",
  457. desc_len); /* can't include descp here, because it's got nuls */
  458. connection_write_to_buf(tmp, strlen(tmp), conn);
  459. connection_write_to_buf(descp, desc_len, conn);
  460. break;
  461. case 0: /* well-formed but not present */
  462. connection_write_to_buf(answer404, strlen(answer404), conn);
  463. break;
  464. case -1: /* not well-formed */
  465. connection_write_to_buf(answer400, strlen(answer400), conn);
  466. break;
  467. }
  468. return 0;
  469. }
  470. /* we didn't recognize the url */
  471. connection_write_to_buf(answer404, strlen(answer404), conn);
  472. return 0;
  473. }
  474. /** Helper function: called when a dirserver gets a complete HTTP POST
  475. * request. Look for an uploaded server descriptor or rendezvous
  476. * service descriptor. On finding one, process it and write a
  477. * response into conn-\>outbuf. If the request is unrecognized, send a
  478. * 404. Always return 0. */
  479. static int
  480. directory_handle_command_post(connection_t *conn, char *headers,
  481. char *body, int body_len)
  482. {
  483. const char *cp;
  484. char *url;
  485. log_fn(LOG_DEBUG,"Received POST command.");
  486. conn->state = DIR_CONN_STATE_SERVER_WRITING;
  487. if (parse_http_url(headers, &url) < 0) {
  488. connection_write_to_buf(answer400, strlen(answer400), conn);
  489. return 0;
  490. }
  491. log_fn(LOG_INFO,"url '%s' posted to us.", url);
  492. if(!strcmp(url,"/")) { /* server descriptor post */
  493. cp = body;
  494. switch(dirserv_add_descriptor(&cp)) {
  495. case -1:
  496. /* malformed descriptor, or something wrong */
  497. connection_write_to_buf(answer400, strlen(answer400), conn);
  498. break;
  499. case 0:
  500. /* descriptor was well-formed but server has not been approved */
  501. connection_write_to_buf(answer403, strlen(answer403), conn);
  502. break;
  503. case 1:
  504. dirserv_get_directory(&cp); /* rebuild and write to disk */
  505. connection_write_to_buf(answer200, strlen(answer200), conn);
  506. break;
  507. }
  508. return 0;
  509. }
  510. if(!strncmp(url,rend_publish_string,strlen(rend_publish_string))) {
  511. /* rendezvous descriptor post */
  512. if(rend_cache_store(body, body_len) < 0)
  513. connection_write_to_buf(answer400, strlen(answer400), conn);
  514. else
  515. connection_write_to_buf(answer200, strlen(answer200), conn);
  516. return 0;
  517. }
  518. /* we didn't recognize the url */
  519. connection_write_to_buf(answer404, strlen(answer404), conn);
  520. return 0;
  521. }
  522. /** Called when a dirserver receives data on a directory connection;
  523. * looks for an HTTP request. If the request is complete, remove it
  524. * from the inbuf, try to process it; otherwise, leave it on the
  525. * buffer. Return a 0 on success, or -1 on error.
  526. */
  527. static int directory_handle_command(connection_t *conn) {
  528. char *headers=NULL, *body=NULL;
  529. int body_len=0;
  530. int r;
  531. tor_assert(conn && conn->type == CONN_TYPE_DIR);
  532. switch(fetch_from_buf_http(conn->inbuf,
  533. &headers, MAX_HEADERS_SIZE,
  534. &body, &body_len, MAX_BODY_SIZE)) {
  535. case -1: /* overflow */
  536. log_fn(LOG_WARN,"input too large. Failing.");
  537. return -1;
  538. case 0:
  539. log_fn(LOG_DEBUG,"command not all here yet.");
  540. return 0;
  541. /* case 1, fall through */
  542. }
  543. log_fn(LOG_DEBUG,"headers '%s', body '%s'.", headers, body);
  544. if(!strncasecmp(headers,"GET",3))
  545. r = directory_handle_command_get(conn, headers, body, body_len);
  546. else if (!strncasecmp(headers,"POST",4))
  547. r = directory_handle_command_post(conn, headers, body, body_len);
  548. else {
  549. log_fn(LOG_WARN,"Got headers '%s' with unknown command. Closing.", headers);
  550. r = -1;
  551. }
  552. tor_free(headers); tor_free(body);
  553. return r;
  554. }
  555. /** Write handler for directory connections; called when all data has
  556. * been flushed. Close the connection or wait for a response as
  557. * appropriate.
  558. */
  559. int connection_dir_finished_flushing(connection_t *conn) {
  560. tor_assert(conn && conn->type == CONN_TYPE_DIR);
  561. switch(conn->state) {
  562. case DIR_CONN_STATE_CLIENT_SENDING:
  563. log_fn(LOG_DEBUG,"client finished sending command.");
  564. conn->state = DIR_CONN_STATE_CLIENT_READING;
  565. connection_stop_writing(conn);
  566. return 0;
  567. case DIR_CONN_STATE_SERVER_WRITING:
  568. log_fn(LOG_INFO,"Finished writing server response. Closing.");
  569. connection_mark_for_close(conn);
  570. return 0;
  571. default:
  572. log_fn(LOG_WARN,"BUG: called in unexpected state %d.", conn->state);
  573. return -1;
  574. }
  575. return 0;
  576. }
  577. /** Connected handler for directory connections: begin sending data to the
  578. * server */
  579. int connection_dir_finished_connecting(connection_t *conn)
  580. {
  581. tor_assert(conn && conn->type == CONN_TYPE_DIR);
  582. tor_assert(conn->state == DIR_CONN_STATE_CONNECTING);
  583. log_fn(LOG_INFO,"Dir connection to router %s:%u established.",
  584. conn->address,conn->port);
  585. conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
  586. return 0;
  587. }
  588. /*
  589. Local Variables:
  590. mode:c
  591. indent-tabs-mode:nil
  592. c-basic-offset:2
  593. End:
  594. */