1 /* Copyright 2001,2002 Roger Dingledine, Matej Pfajfar. */
2 /* See LICENSE for licensing information */
7 /********* START PROTOTYPES **********/
9 static void dumpstats(void); /* dump stats to stdout */
11 /********* START VARIABLES **********/
13 extern char *conn_type_to_string
[];
14 extern char *conn_state_to_string
[][15];
16 or_options_t options
; /* command-line and config-file options */
17 int global_read_bucket
; /* max number of bytes I can read this second */
19 static connection_t
*connection_array
[MAXCONNECTIONS
] =
22 static struct pollfd poll_array
[MAXCONNECTIONS
];
24 static int nfds
=0; /* number of connections currently active */
26 #ifndef MS_WINDOWS /* do signal stuff only on unix */
27 static int please_dumpstats
=0; /* whether we should dump stats during the loop */
28 static int please_fetch_directory
=0; /* whether we should fetch a new directory */
29 static int please_reap_children
=0; /* whether we should waitpid for exited children*/
30 #endif /* signal stuff */
33 static crypto_pk_env_t
*privatekey
=NULL
;
34 static crypto_pk_env_t
*signing_privatekey
=NULL
;
36 routerinfo_t
*my_routerinfo
=NULL
;
38 /********* END VARIABLES ************/
40 void set_privatekey(crypto_pk_env_t
*k
) {
44 crypto_pk_env_t
*get_privatekey(void) {
49 void set_signing_privatekey(crypto_pk_env_t
*k
) {
50 signing_privatekey
= k
;
53 crypto_pk_env_t
*get_signing_privatekey(void) {
54 assert(signing_privatekey
);
55 return signing_privatekey
;
58 /****************************************************************************
60 * This section contains accessors and other methods on the connection_array
61 * and poll_array variables (which are global within this file and unavailable
64 ****************************************************************************/
66 int connection_add(connection_t
*conn
) {
68 if(nfds
>= options
.MaxConn
-1) {
69 log(LOG_INFO
,"connection_add(): failing because nfds is too high.");
73 conn
->poll_index
= nfds
;
74 connection_set_poll_socket(conn
);
75 connection_array
[nfds
] = conn
;
77 /* zero these out here, because otherwise we'll inherit values from the previously freed one */
78 poll_array
[nfds
].events
= 0;
79 poll_array
[nfds
].revents
= 0;
83 log(LOG_INFO
,"connection_add(): new conn type %d, socket %d, nfds %d.",conn
->type
, conn
->s
, nfds
);
88 void connection_set_poll_socket(connection_t
*conn
) {
89 poll_array
[conn
->poll_index
].fd
= conn
->s
;
92 int connection_remove(connection_t
*conn
) {
98 log(LOG_INFO
,"connection_remove(): removing socket %d, nfds now %d",conn
->s
, nfds
-1);
99 circuit_about_to_close_connection(conn
); /* if it's an edge conn, remove it from the list
100 * of conn's on this circuit. If it's not on an edge,
101 * flush and send destroys for all circuits on this conn
104 current_index
= conn
->poll_index
;
105 if(current_index
== nfds
-1) { /* this is the end */
110 /* we replace this one with the one at the end, then free it */
112 poll_array
[current_index
].fd
= poll_array
[nfds
].fd
;
113 poll_array
[current_index
].events
= poll_array
[nfds
].events
;
114 poll_array
[current_index
].revents
= poll_array
[nfds
].revents
;
115 connection_array
[current_index
] = connection_array
[nfds
];
116 connection_array
[current_index
]->poll_index
= current_index
;
121 connection_t
*connection_twin_get_by_addr_port(uint32_t addr
, uint16_t port
) {
122 /* Find a connection to the router described by addr and port,
123 * or alternately any router which knows its key.
124 * This connection *must* be in 'open' state.
125 * If not, return NULL.
129 routerinfo_t
*router
;
131 /* first check if it's there exactly */
132 conn
= connection_exact_get_by_addr_port(addr
,port
);
133 if(conn
&& connection_state_is_open(conn
)) {
134 log(LOG_INFO
,"connection_twin_get_by_addr_port(): Found exact match.");
138 /* now check if any of the other open connections are a twin for this one */
140 router
= router_get_by_addr_port(addr
,port
);
144 for(i
=0;i
<nfds
;i
++) {
145 conn
= connection_array
[i
];
147 if(connection_state_is_open(conn
) &&
148 !conn
->marked_for_close
&&
149 !crypto_pk_cmp_keys(conn
->pkey
, router
->pkey
)) {
150 log(LOG_INFO
,"connection_twin_get_by_addr_port(): Found twin (%s).",conn
->address
);
159 connection_t
*connection_exact_get_by_addr_port(uint32_t addr
, uint16_t port
) {
163 for(i
=0;i
<nfds
;i
++) {
164 conn
= connection_array
[i
];
165 if(conn
->addr
== addr
&& conn
->port
== port
&& !conn
->marked_for_close
)
171 connection_t
*connection_get_by_type(int type
) {
175 for(i
=0;i
<nfds
;i
++) {
176 conn
= connection_array
[i
];
177 if(conn
->type
== type
&& !conn
->marked_for_close
)
183 connection_t
*connection_get_by_type_state(int type
, int state
) {
187 for(i
=0;i
<nfds
;i
++) {
188 conn
= connection_array
[i
];
189 if(conn
->type
== type
&& conn
->state
== state
&& !conn
->marked_for_close
)
195 connection_t
*connection_get_by_type_state_lastwritten(int type
, int state
) {
197 connection_t
*conn
, *best
=NULL
;
199 for(i
=0;i
<nfds
;i
++) {
200 conn
= connection_array
[i
];
201 if(conn
->type
== type
&& conn
->state
== state
&& !conn
->marked_for_close
)
202 if(!best
|| conn
->timestamp_lastwritten
< best
->timestamp_lastwritten
)
208 void connection_watch_events(connection_t
*conn
, short events
) {
210 assert(conn
&& conn
->poll_index
< nfds
);
212 poll_array
[conn
->poll_index
].events
= events
;
215 void connection_stop_reading(connection_t
*conn
) {
217 assert(conn
&& conn
->poll_index
< nfds
);
219 log(LOG_DEBUG
,"connection_stop_reading() called.");
220 if(poll_array
[conn
->poll_index
].events
& POLLIN
)
221 poll_array
[conn
->poll_index
].events
-= POLLIN
;
224 void connection_start_reading(connection_t
*conn
) {
226 assert(conn
&& conn
->poll_index
< nfds
);
228 poll_array
[conn
->poll_index
].events
|= POLLIN
;
231 void connection_stop_writing(connection_t
*conn
) {
233 assert(conn
&& conn
->poll_index
< nfds
);
235 if(poll_array
[conn
->poll_index
].events
& POLLOUT
)
236 poll_array
[conn
->poll_index
].events
-= POLLOUT
;
239 void connection_start_writing(connection_t
*conn
) {
241 assert(conn
&& conn
->poll_index
< nfds
);
243 poll_array
[conn
->poll_index
].events
|= POLLOUT
;
246 static void conn_read(int i
) {
250 conn
= connection_array
[i
];
252 // log_fn(LOG_DEBUG,"socket %d has something to read.",conn->s);
255 if (poll_array
[i
].revents
& POLLERR
) {
261 if (conn
->type
== CONN_TYPE_OR_LISTENER
) {
262 retval
= connection_or_handle_listener_read(conn
);
263 } else if (conn
->type
== CONN_TYPE_AP_LISTENER
) {
264 retval
= connection_ap_handle_listener_read(conn
);
265 } else if (conn
->type
== CONN_TYPE_DIR_LISTENER
) {
266 retval
= connection_dir_handle_listener_read(conn
);
268 retval
= connection_read_to_buf(conn
);
269 if (retval
< 0 && conn
->type
== CONN_TYPE_DIR
&& conn
->state
== DIR_CONN_STATE_CONNECTING
) {
270 /* it's a directory server and connecting failed: forget about this router */
271 router_forget_router(conn
->addr
,conn
->port
); /* FIXME i don't think this function works. */
273 if (retval
>= 0) { /* all still well */
274 retval
= connection_process_inbuf(conn
);
275 // log_fn(LOG_DEBUG,"connection_process_inbuf returned %d.",retval);
276 if(retval
>= 0 && !connection_state_is_open(conn
) && conn
->receiver_bucket
== 0) {
277 log(LOG_DEBUG
,"conn_read(): receiver bucket reached 0 before handshake finished. Closing.");
286 if(retval
< 0) { /* this connection is broken. remove it */
287 log_fn(LOG_INFO
,"%s connection broken, removing.", conn_type_to_string
[conn
->type
]);
288 connection_remove(conn
);
289 connection_free(conn
);
290 if(i
<nfds
) { /* we just replaced the one at i with a new one.
292 if(poll_array
[i
].revents
& (POLLIN
|POLLHUP
|POLLERR
))
293 /* something to read */
299 static void conn_write(int i
) {
303 conn
= connection_array
[i
];
304 // log_fn(LOG_DEBUG,"socket %d wants to write.",conn->s);
306 if(connection_is_listener(conn
)) {
307 log_fn(LOG_DEBUG
,"Got a listener socket. Can't happen!");
310 /* else it's an OP, OR, or exit */
311 retval
= connection_flush_buf(conn
); /* conns in CONNECTING state will fall through... */
312 if(retval
== 0) { /* it's done flushing */
313 retval
= connection_finished_flushing(conn
); /* ...and get handled here. */
317 if(retval
< 0) { /* this connection is broken. remove it. */
318 log_fn(LOG_DEBUG
,"%s connection broken, removing.", conn_type_to_string
[conn
->type
]);
319 connection_remove(conn
);
320 connection_free(conn
);
321 if(i
<nfds
) { /* we just replaced the one at i with a new one.
323 if(poll_array
[i
].revents
& POLLOUT
) /* something to write */
329 static void check_conn_marked(int i
) {
332 conn
= connection_array
[i
];
334 if(conn
->marked_for_close
) {
335 log(LOG_DEBUG
,"check_conn_marked(): Cleaning up connection.");
336 if(conn
->s
>= 0) { /* might be an incomplete exit connection */
337 /* FIXME there's got to be a better way to check for this -- and make other checks? */
338 connection_flush_buf(conn
); /* flush it first */
340 connection_remove(conn
);
341 connection_free(conn
);
342 if(i
<nfds
) { /* we just replaced the one at i with a new one.
344 check_conn_marked(i
);
349 static int prepare_for_poll(int *timeout
) {
351 // connection_t *conn = NULL;
352 connection_t
*tmpconn
;
353 struct timeval now
; //soonest;
354 static long current_second
= 0; /* from previous calls to gettimeofday */
355 static long time_to_fetch_directory
= 0;
356 static long time_to_new_circuit
= 0;
357 // int ms_until_conn;
361 my_gettimeofday(&now
);
363 if(now
.tv_sec
> current_second
) { /* the second has rolled over. check more stuff. */
365 if(!options
.DirPort
) {
366 if(time_to_fetch_directory
< now
.tv_sec
) {
367 /* it's time to fetch a new directory */
368 /* NOTE directory servers do not currently fetch directories.
369 * Hope this doesn't bite us later.
371 directory_initiate_fetch(router_pick_directory_server());
372 time_to_fetch_directory
= now
.tv_sec
+ options
.DirFetchPeriod
;
376 if(options
.APPort
&& time_to_new_circuit
< now
.tv_sec
) {
377 circuit_expire_unused_circuits();
378 circuit_launch_new(-1); /* tell it to forget about previous failures */
379 circ
= circuit_get_newest_ap();
380 if(!circ
|| circ
->dirty
) {
381 log(LOG_INFO
,"prepare_for_poll(): Youngest circuit %s; launching replacement.", circ
? "dirty" : "missing");
382 circuit_launch_new(0); /* make an onion and lay the circuit */
384 time_to_new_circuit
= now
.tv_sec
+ options
.NewCircuitPeriod
;
387 if(global_read_bucket
< 9*options
.TotalBandwidth
) {
388 global_read_bucket
+= options
.TotalBandwidth
;
389 log_fn(LOG_DEBUG
,"global_read_bucket now %d.", global_read_bucket
);
392 /* do housekeeping for each connection */
393 for(i
=0;i
<nfds
;i
++) {
394 tmpconn
= connection_array
[i
];
395 if(connection_receiver_bucket_should_increase(tmpconn
)) {
396 tmpconn
->receiver_bucket
+= tmpconn
->bandwidth
;
397 // log_fn(LOG_DEBUG,"Receiver bucket %d now %d.", i, tmpconn->receiver_bucket);
400 if(tmpconn
->wants_to_read
== 1 /* it's marked to turn reading back on now */
401 && global_read_bucket
> 0 /* and we're allowed to read */
402 && tmpconn
->receiver_bucket
!= 0) { /* and either an edge conn or non-empty bucket */
403 tmpconn
->wants_to_read
= 0;
404 connection_start_reading(tmpconn
);
407 /* check connections to see whether we should send a keepalive, expire, or wait */
408 if(!connection_speaks_cells(tmpconn
))
409 continue; /* this conn type doesn't send cells */
410 if(now
.tv_sec
>= tmpconn
->timestamp_lastwritten
+ options
.KeepalivePeriod
) {
411 if((!options
.OnionRouter
&& !circuit_get_by_conn(tmpconn
)) ||
412 (!connection_state_is_open(tmpconn
))) {
413 /* we're an onion proxy, with no circuits; or our handshake has expired. kill it. */
414 log(LOG_DEBUG
,"prepare_for_poll(): Expiring connection to %d (%s:%d).",
415 i
,tmpconn
->address
, tmpconn
->port
);
416 tmpconn
->marked_for_close
= 1;
418 /* either a full router, or we've got a circuit. send a padding cell. */
419 // log(LOG_DEBUG,"prepare_for_poll(): Sending keepalive to (%s:%d)",
420 // tmpconn->address, tmpconn->port);
421 memset(&cell
,0,sizeof(cell_t
));
422 cell
.command
= CELL_PADDING
;
423 if(connection_write_cell_to_buf(&cell
, tmpconn
) < 0)
424 tmpconn
->marked_for_close
= 1;
428 /* blow away any connections that need to die. can't do this later
429 * because we might open up a circuit and not realize it we're about to cull it.
432 check_conn_marked(i
);
434 current_second
= now
.tv_sec
; /* remember which second it is, for next time */
437 if(onion_pending_check()) {
438 /* there's an onion pending. check for new things to do, but don't wait any time */
441 *timeout
= 1000 - (now
.tv_usec
/ 1000); /* how many milliseconds til the next second? */
449 /* Link padding stuff left here for fun. Not used now. */
451 if(options
.LinkPadding
) {
452 /* now check which conn wants to speak soonest */
453 for(i
=0;i
<nfds
;i
++) {
454 tmpconn
= connection_array
[i
];
455 if(!connection_speaks_cells(tmpconn
))
456 continue; /* this conn type doesn't send cells */
457 if(!connection_state_is_open(tmpconn
))
458 continue; /* only conns in state 'open' have a valid send_timeval */
459 while(tv_cmp(&tmpconn
->send_timeval
,&now
) <= 0) { /* send_timeval has already passed, let it send a cell */
460 connection_send_cell(tmpconn
);
462 if(!conn
|| tv_cmp(&tmpconn
->send_timeval
, &soonest
) < 0) { /* this is the best choice so far */
464 soonest
.tv_sec
= conn
->send_timeval
.tv_sec
;
465 soonest
.tv_usec
= conn
->send_timeval
.tv_usec
;
469 if(conn
) { /* we might want to set *timeout sooner */
470 ms_until_conn
= (soonest
.tv_sec
- now
.tv_sec
)*1000 +
471 (soonest
.tv_usec
- now
.tv_usec
)/1000;
472 // log(LOG_DEBUG,"prepare_for_poll(): conn %d times out in %d ms.",conn->s, ms_until_conn);
473 if(ms_until_conn
< *timeout
) { /* use the new one */
474 // log(LOG_DEBUG,"prepare_for_poll(): conn %d soonest, in %d ms.",conn->s,ms_until_conn);
475 *timeout
= ms_until_conn
;
481 static int do_main_loop(void) {
485 crypto_pk_env_t
*prkey
;
487 /* load the routers file */
488 if(router_get_list_from_file(options
.RouterFile
) < 0) {
489 log(LOG_ERR
,"Error loading router list.");
493 /* load the private key, if we're supposed to have one */
494 if(options
.OnionRouter
) {
495 prkey
= crypto_new_pk_env(CRYPTO_PK_RSA
);
497 log(LOG_ERR
,"Error creating a crypto environment.");
500 if (crypto_pk_read_private_key_from_filename(prkey
, options
.PrivateKeyFile
)) {
501 log(LOG_ERR
,"Error loading private key.");
504 set_privatekey(prkey
);
507 /* load the private key, if we're supposed to have one */
508 if(options
.DirPort
) {
509 prkey
= crypto_new_pk_env(CRYPTO_PK_RSA
);
511 log(LOG_ERR
,"Error creating a crypto environment.");
514 if (crypto_pk_read_private_key_from_filename(prkey
, options
.SigningPrivateKeyFile
)) {
515 log(LOG_ERR
,"Error loading private key.");
518 set_signing_privatekey(prkey
);
521 /* start up the necessary connections based on which ports are
522 * non-zero. This is where we try to connect to all the other ORs,
523 * and start the listeners
525 retry_all_connections((uint16_t) options
.ORPort
,
526 (uint16_t) options
.APPort
,
527 (uint16_t) options
.DirPort
);
530 #ifndef MS_WIN32 /* do signal stuff only on unix */
531 if(please_dumpstats
) {
533 please_dumpstats
= 0;
535 if(please_fetch_directory
) {
536 if(options
.DirPort
) {
537 if(router_get_list_from_file(options
.RouterFile
) < 0) {
538 log(LOG_ERR
,"Error reloading router list. Continuing with old list.");
541 directory_initiate_fetch(router_pick_directory_server());
543 please_fetch_directory
= 0;
545 if(please_reap_children
) {
546 while(waitpid(-1,NULL
,WNOHANG
)) ; /* keep reaping until no more zombies */
547 please_reap_children
= 0;
549 #endif /* signal stuff */
550 if(prepare_for_poll(&timeout
) < 0) {
551 log(LOG_DEBUG
,"do_main_loop(): prepare_for_poll failed, exiting.");
554 /* now timeout is the value we'll hand to poll. It's either -1, meaning
555 * don't timeout, else it indicates the soonest event (either the
556 * one-second rollover for refilling receiver buckets, or the soonest
557 * conn that needs to send a cell)
560 /* poll until we have an event, or it's time to do something */
561 poll_result
= poll(poll_array
, nfds
, timeout
);
563 #if 0 /* let catch() handle things like ^c, and otherwise don't worry about it */
564 if(poll_result
< 0) {
565 log(LOG_ERR
,"do_main_loop(): poll failed.");
566 if(errno
!= EINTR
) /* let the program survive things like ^z */
571 if(poll_result
== 0) {
572 /* poll timed out without anything to do. process a pending onion, if any. */
573 onion_pending_process_one();
576 if(poll_result
> 0) { /* we have at least one connection to deal with */
577 /* do all the reads and errors first, so we can detect closed sockets */
579 if(poll_array
[i
].revents
& (POLLIN
|POLLHUP
|POLLERR
))
580 /* something to read, or an error. */
581 conn_read(i
); /* this also blows away broken connections */
582 /* see http://www.greenend.org.uk/rjk/2001/06/poll.html for discussion
583 * of POLLIN vs POLLHUP */
585 /* then do the writes */
587 if(poll_array
[i
].revents
& POLLOUT
) /* something to write */
590 /* any of the conns need to be closed now? */
592 check_conn_marked(i
);
594 /* refilling buckets and sending cells happens at the beginning of the
595 * next iteration of the loop, inside prepare_for_poll()
600 static void catch(int the_signal
) {
602 #ifndef MS_WIN32 /* do signal stuff only on unix */
607 log(LOG_NOTICE
,"Catching signal %d, exiting cleanly.", the_signal
);
610 please_fetch_directory
= 1;
613 please_dumpstats
= 1;
616 please_reap_children
= 1;
618 log(LOG_ERR
,"Caught signal that we can't handle??");
620 #endif /* signal stuff */
623 static void dumpstats(void) { /* dump stats to stdout */
628 printf("Dumping stats:\n");
629 my_gettimeofday(&now
);
631 for(i
=0;i
<nfds
;i
++) {
632 conn
= connection_array
[i
];
633 printf("Conn %d (socket %d) type %d (%s), state %d (%s), created %ld secs ago\n",
634 i
, conn
->s
, conn
->type
, conn_type_to_string
[conn
->type
],
635 conn
->state
, conn_state_to_string
[conn
->type
][conn
->state
], now
.tv_sec
- conn
->timestamp_created
);
636 if(!connection_is_listener(conn
)) {
637 printf("Conn %d is to '%s:%d'.\n",i
,conn
->address
, conn
->port
);
638 printf("Conn %d: %d bytes waiting on inbuf (last read %ld secs ago)\n",i
,conn
->inbuf_datalen
,
639 now
.tv_sec
- conn
->timestamp_lastread
);
640 printf("Conn %d: %d bytes waiting on outbuf (last written %ld secs ago)\n",i
,conn
->outbuf_datalen
,
641 now
.tv_sec
- conn
->timestamp_lastwritten
);
643 circuit_dump_by_conn(conn
); /* dump info about all the circuits using this conn */
649 int dump_router_to_string(char *s
, int maxlen
, routerinfo_t
*router
) {
651 char *signing_pkey
, *signing_pkey_tag
;
652 int pkeylen
, signing_pkeylen
;
655 struct exit_policy_t
*tmpe
;
657 if(crypto_pk_write_public_key_to_string(router
->pkey
,&pkey
,&pkeylen
)<0) {
658 log(LOG_ERR
,"dump_router_to_string(): write pkey to string failed!");
663 signing_pkey_tag
= "";
664 if (router
->signing_pkey
) {
665 if(crypto_pk_write_public_key_to_string(router
->signing_pkey
,
666 &signing_pkey
,&signing_pkeylen
)<0) {
667 log(LOG_ERR
,"dump_router_to_string(): write signing_pkey to string failed!");
670 signing_pkey_tag
= "signing-key\n";
673 result
= snprintf(s
, maxlen
, "router %s %d %d %d %d %d\n%s%s%s",
681 signing_pkey_tag
, signing_pkey
);
687 if(result
< 0 || result
> maxlen
) {
688 /* apparently different glibcs do different things on snprintf error.. so check both */
693 for(tmpe
=router
->exit_policy
; tmpe
; tmpe
=tmpe
->next
) {
694 result
= snprintf(s
+written
, maxlen
-written
, "%s %s:%s\n",
695 tmpe
->policy_type
== EXIT_POLICY_ACCEPT
? "accept" : "reject",
696 tmpe
->address
, tmpe
->port
);
697 if(result
< 0 || result
+written
> maxlen
) {
698 /* apparently different glibcs do different things on snprintf error.. so check both */
704 if(written
> maxlen
-2) {
705 return -1; /* not enough space for \n\0 */
707 /* XXX count fenceposts here. They're probably wrong. In general,
708 * we need a better way to handle overruns in building the directory
709 * string, and a better way to handle directory string size in general. */
711 /* include a last '\n' */
719 build_directory(directory_t
*dir
) {
720 routerinfo_t
**routers
= NULL
;
722 routerinfo_t
*router
;
725 routers
= (routerinfo_t
**)tor_malloc(sizeof(routerinfo_t
*) * (nfds
+1));
727 log(LOG_INFO
, "build_directory(): adding self (%s:%d)",
728 my_routerinfo
->address
, my_routerinfo
->or_port
);
729 routers
[n
++] = my_routerinfo
;
731 for(i
= 0; i
<nfds
; ++i
) {
732 conn
= connection_array
[i
];
734 if(conn
->type
!= CONN_TYPE_OR
)
735 continue; /* we only want to list ORs */
736 if(conn
->state
!= OR_CONN_STATE_OPEN
)
737 continue; /* we only want to list ones that successfully handshaked */
738 router
= router_get_by_addr_port(conn
->addr
,conn
->port
);
740 log(LOG_ERR
,"build_directory(): couldn't find router %d:%d!",
741 conn
->addr
,conn
->port
);
744 log(LOG_INFO
, "build_directory(): adding router (%s:%d)",
745 router
->address
, router
->or_port
);
746 routers
[n
++] = router
;
748 dir
->routers
= routers
;
754 dump_signed_directory_to_string(char *s
, int maxlen
,
755 crypto_pk_env_t
*private_key
)
758 if (build_directory(&dir
)) {
759 log(LOG_ERR
,"dump_signed_directory_to_string(): build_directory failed.");
762 return dump_signed_directory_to_string_impl(s
, maxlen
, &dir
, private_key
);
766 dump_signed_directory_to_string_impl(char *s
, int maxlen
, directory_t
*dir
,
767 crypto_pk_env_t
*private_key
)
773 routerinfo_t
*router
;
777 "recommended-software 0.0.2pre4,0.0.2pre5,0.0.2pre6\n" /* XXX make this real */
782 for (i
= 0; i
< dir
->n_routers
; ++i
) {
783 router
= dir
->routers
[i
];
784 written
= dump_router_to_string(cp
, eos
-cp
, router
);
787 log(LOG_ERR
,"dump_signed_directory_to_string(): tried to exceed string length.");
788 cp
[maxlen
-1] = 0; /* make sure it's null terminated */
794 free(dir
->routers
); /* not needed anymore */
796 /* These multiple strlen calls are inefficient, but dwarfed by the RSA
800 strncat(s
, "directory-signature\n", maxlen
-i
);
804 if (crypto_SHA_digest(s
, i
, digest
)) {
805 log(LOG_ERR
,"dump_signed_directory_to_string(): couldn't compute digest");
808 if (crypto_pk_private_sign(private_key
, digest
, 20, signature
) < 0) {
809 log(LOG_ERR
,"dump_signed_directory_to_string(): couldn't sign digest");
814 "-----BEGIN SIGNATURE-----\n", maxlen
-i
);
818 if (base64_encode(cp
, maxlen
-i
, signature
, 128) < 0) {
819 log_fn(LOG_ERR
," couldn't base64-encode signature");
825 strncat(cp
, "-----END SIGNATURE-----\n", maxlen
-i
);
828 log(LOG_ERR
,"dump_signed_directory_to_string(): tried to exceed string length.");
835 void daemonize(void) {
837 /* Fork; parent exits. */
841 /* Create new session; make sure we never get a terminal */
850 fclose(stdout
); /* XXX Nick: this closes our log, right? is it safe to leave this open? */
855 int tor_main(int argc
, char *argv
[]) {
858 if(getconfig(argc
,argv
,&options
))
860 log_set_severity(options
.loglevel
); /* assign logging severity level from options */
861 global_read_bucket
= options
.TotalBandwidth
; /* start it at 1 second of traffic */
866 if(options
.OnionRouter
) { /* only spawn dns handlers if we're a router */
867 dns_init(); /* initialize the dns resolve tree, and spawn workers */
870 #ifndef MS_WINDOWS /* do signal stuff only on unix */
871 signal (SIGINT
, catch); /* catch kills so we can exit cleanly */
872 signal (SIGTERM
, catch);
873 signal (SIGUSR1
, catch); /* to dump stats to stdout */
874 signal (SIGHUP
, catch); /* to reload directory */
875 signal (SIGCHLD
, catch); /* for exiting dns/cpu workers */
876 #endif /* signal stuff */
878 crypto_global_init();
880 retval
= do_main_loop();
881 crypto_global_cleanup();