main.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. #include "or.h"
  2. /********* START VARIABLES **********/
  3. static or_options_t options; /* command-line and config-file options */
  4. int global_role;
  5. static connection_t *connection_array[MAXCONNECTIONS] =
  6. { NULL };
  7. static struct pollfd poll_array[MAXCONNECTIONS] =
  8. { [0 ... MAXCONNECTIONS-1] = { -1, 0, 0 } };
  9. static int nfds=0; /* number of connections currently active */
  10. /* private key */
  11. static RSA *prkey = NULL;
  12. /* router array */
  13. static routerinfo_t **router_array = NULL;
  14. static int rarray_len = 0;
  15. /********* END VARIABLES ************/
  16. /****************************************************************************
  17. *
  18. * This section contains accessors and other methods on the connection_array
  19. * and poll_array variables (which are global within this file and unavailable
  20. * outside it).
  21. *
  22. ****************************************************************************/
  23. int connection_add(connection_t *conn) {
  24. if(nfds >= MAXCONNECTIONS-2) { /* 2, for some breathing room. should count the fenceposts. */
  25. /* FIXME should use the 'max connections' option */
  26. log(LOG_DEBUG,"connection_add(): failing because nfds is too high.");
  27. return -1;
  28. }
  29. conn->poll_index = nfds;
  30. connection_set_poll_socket(conn);
  31. connection_array[nfds] = conn;
  32. /* zero these out here, because otherwise we'll inherit values from the previously freed one */
  33. poll_array[nfds].events = 0;
  34. poll_array[nfds].revents = 0;
  35. nfds++;
  36. log(LOG_DEBUG,"connection_add(): new conn type %d, socket %d, nfds %d.",conn->type, conn->s, nfds);
  37. return 0;
  38. }
  39. void connection_set_poll_socket(connection_t *conn) {
  40. poll_array[conn->poll_index].fd = conn->s;
  41. }
  42. int connection_remove(connection_t *conn) {
  43. int current_index;
  44. assert(conn);
  45. assert(nfds>0);
  46. circuit_about_to_close_connection(conn); /* flush and send destroys for all circuits on this conn */
  47. current_index = conn->poll_index;
  48. if(current_index == nfds-1) { /* this is the end */
  49. // connection_free(conn);
  50. nfds--;
  51. log(LOG_DEBUG,"connection_remove(): nfds now %d.",nfds);
  52. return 0;
  53. }
  54. /* we replace this one with the one at the end, then free it */
  55. nfds--;
  56. poll_array[current_index].fd = poll_array[nfds].fd;
  57. poll_array[current_index].events = poll_array[nfds].events;
  58. poll_array[current_index].revents = poll_array[nfds].revents;
  59. connection_array[current_index] = connection_array[nfds];
  60. connection_array[current_index]->poll_index = current_index;
  61. log(LOG_DEBUG,"connection_remove(): nfds now %d.",nfds);
  62. return 0;
  63. }
  64. connection_t *connection_twin_get_by_addr_port(uint32_t addr, uint16_t port) {
  65. int i;
  66. connection_t *conn;
  67. /* first check if it's there exactly */
  68. conn = connection_exact_get_by_addr_port(addr,port);
  69. if(conn)
  70. return conn;
  71. /* now check if any of the other open connections are a twin for this one */
  72. /* XXX */
  73. /* guess not */
  74. return NULL;
  75. }
  76. connection_t *connection_exact_get_by_addr_port(uint32_t addr, uint16_t port) {
  77. int i;
  78. connection_t *conn;
  79. for(i=0;i<nfds;i++) {
  80. conn = connection_array[i];
  81. assert(conn);
  82. if(conn->addr == addr && conn->port == port)
  83. return conn;
  84. }
  85. return NULL;
  86. }
  87. connection_t *connection_get_by_type(int type) {
  88. int i;
  89. connection_t *conn;
  90. for(i=0;i<nfds;i++) {
  91. conn = connection_array[i];
  92. if(conn->type == type)
  93. return conn;
  94. }
  95. return NULL;
  96. }
  97. /* the next 4 functions should move to routers.c once we get it
  98. * cleaned up more. The router_array and rarray_len variables should
  99. * move there too.
  100. */
  101. routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port) {
  102. int i;
  103. routerinfo_t *router;
  104. assert(router_array);
  105. for(i=0;i<rarray_len;i++) {
  106. router = router_array[i];
  107. if ((router->addr == addr) && (router->or_port == port))
  108. return router;
  109. }
  110. return NULL;
  111. }
  112. routerinfo_t *router_get_first_in_route(unsigned int *route, size_t routelen) {
  113. return router_array[route[routelen-1]];
  114. }
  115. /* a wrapper around new_route. put all these in routers.c perhaps? */
  116. unsigned int *router_new_route(size_t *rlen) {
  117. return new_route(options.CoinWeight, router_array,rarray_len, rlen);
  118. }
  119. /* a wrapper around create_onion */
  120. unsigned char *router_create_onion(unsigned int *route, size_t routelen, size_t *lenp, crypt_path_t **cpathp) {
  121. return create_onion(router_array,rarray_len,route,routelen,lenp,cpathp);
  122. }
  123. connection_t *connect_to_router_as_op(routerinfo_t *router) {
  124. return connection_connect_to_router_as_op(router, prkey, options.ORPort);
  125. }
  126. void connection_watch_events(connection_t *conn, short events) {
  127. assert(conn && conn->poll_index < nfds);
  128. poll_array[conn->poll_index].events = events;
  129. }
  130. void check_conn_read(int i) {
  131. int retval;
  132. connection_t *conn;
  133. if(poll_array[i].revents & POLLIN) { /* something to read */
  134. conn = connection_array[i];
  135. assert(conn);
  136. log(LOG_DEBUG,"check_conn_read(): socket %d has something to read.",conn->s);
  137. if (conn->type == CONN_TYPE_OP_LISTENER) {
  138. retval = connection_op_handle_listener_read(conn);
  139. } else if (conn->type == CONN_TYPE_OR_LISTENER) {
  140. retval = connection_or_handle_listener_read(conn);
  141. } else if (conn->type == CONN_TYPE_AP_LISTENER) {
  142. retval = connection_ap_handle_listener_read(conn);
  143. } else {
  144. /* else it's an OP, OR, or exit */
  145. retval = connection_read_to_buf(conn);
  146. if (retval >= 0) { /* all still well */
  147. retval = connection_process_inbuf(conn);
  148. log(LOG_DEBUG,"check_conn_read(): connection_process_inbuf returned %d.",retval);
  149. }
  150. }
  151. if(retval < 0) { /* this connection is broken. remove it */
  152. log(LOG_DEBUG,"check_conn_read(): Connection broken, removing.");
  153. connection_remove(conn);
  154. connection_free(conn);
  155. if(i<nfds) { /* we just replaced the one at i with a new one.
  156. process it too. */
  157. check_conn_read(i);
  158. }
  159. }
  160. }
  161. }
  162. void check_conn_write(int i) {
  163. int retval;
  164. connection_t *conn;
  165. if(poll_array[i].revents & POLLOUT) { /* something to write */
  166. conn = connection_array[i];
  167. log(LOG_DEBUG,"check_conn_write(): socket %d wants to write.",conn->s);
  168. if(conn->type == CONN_TYPE_OP_LISTENER ||
  169. conn->type == CONN_TYPE_OR_LISTENER) {
  170. log(LOG_DEBUG,"check_conn_write(): Got a listener socket. Can't happen!");
  171. retval = -1;
  172. } else {
  173. /* else it's an OP, OR, or exit */
  174. retval = connection_flush_buf(conn); /* conns in CONNECTING state will fall through... */
  175. if(retval == 0) { /* it's done flushing */
  176. retval = connection_finished_flushing(conn); /* ...and get handled here. */
  177. }
  178. }
  179. if(retval < 0) { /* this connection is broken. remove it. */
  180. log(LOG_DEBUG,"check_conn_write(): Connection broken, removing.");
  181. connection_remove(conn);
  182. connection_free(conn);
  183. if(i<nfds) { /* we just replaced the one at i with a new one.
  184. process it too. */
  185. check_conn_read(i);
  186. }
  187. }
  188. }
  189. }
  190. void check_conn_marked(int i) {
  191. connection_t *conn;
  192. conn = connection_array[i];
  193. assert(conn);
  194. if(conn->marked_for_close) {
  195. log(LOG_DEBUG,"check_conn_marked(): Cleaning up connection.");
  196. if(conn->s >= 0) { /* might be an incomplete exit connection */
  197. /* FIXME there's got to be a better way to check for this -- and make other checks? */
  198. connection_flush_buf(conn); /* flush it first */
  199. }
  200. connection_remove(conn);
  201. connection_free(conn);
  202. if(i<nfds) { /* we just replaced the one at i with a new one.
  203. process it too. */
  204. check_conn_marked(i);
  205. }
  206. }
  207. }
  208. int do_main_loop(void) {
  209. int i;
  210. /* load the routers file */
  211. router_array = getrouters(options.RouterFile,&rarray_len, options.ORPort);
  212. if (!router_array)
  213. {
  214. log(LOG_ERR,"Error loading router list.");
  215. exit(1);
  216. }
  217. /* load the private key */
  218. prkey = load_prkey(options.PrivateKeyFile);
  219. if (!prkey)
  220. {
  221. log(LOG_ERR,"Error loading private key.");
  222. exit(1);
  223. }
  224. log(LOG_DEBUG,"core : Loaded private key of size %u bytes.",RSA_size(prkey));
  225. /* start-up the necessary connections based on global_role. This is where we
  226. * try to connect to all the other ORs, and start the listeners */
  227. retry_all_connections(options.GlobalRole, router_array, rarray_len, prkey,
  228. options.ORPort, options.OPPort, options.APPort);
  229. for(;;) {
  230. poll(poll_array, nfds, -1); /* poll until we have an event */
  231. /* do all the reads first, so we can detect closed sockets */
  232. for(i=0;i<nfds;i++)
  233. check_conn_read(i); /* this also blows away broken connections */
  234. /* then do the writes */
  235. for(i=0;i<nfds;i++)
  236. check_conn_write(i);
  237. /* any of the conns need to be closed now? */
  238. for(i=0;i<nfds;i++)
  239. check_conn_marked(i);
  240. }
  241. }
  242. void catch () {
  243. errno = 0; /* netcat does this. it looks fun. */
  244. log(LOG_DEBUG,"Catching ^c, exiting cleanly.");
  245. exit(0);
  246. }
  247. int main(int argc, char *argv[]) {
  248. int retval = 0;
  249. signal (SIGINT, catch); /* to catch ^c so we can exit cleanly */
  250. if ( getoptions(argc,argv,&options) ) exit(1);
  251. log(options.loglevel,NULL); /* assign logging severity level from options */
  252. global_role = options.GlobalRole; /* assign global_role from options. FIX: remove from global namespace later. */
  253. ERR_load_crypto_strings();
  254. retval = do_main_loop();
  255. ERR_free_strings();
  256. return retval;
  257. }