1 /* Copyright 2001,2002,2003 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
[][_CONN_TYPE_MAX
+1];
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 int stats_prev_global_read_bucket
;
20 static uint64_t stats_n_bytes_read
= 0;
21 static long stats_n_seconds_reading
= 0;
23 static connection_t
*connection_array
[MAXCONNECTIONS
] =
26 static struct pollfd poll_array
[MAXCONNECTIONS
];
28 static int nfds
=0; /* number of connections currently active */
30 #ifndef MS_WINDOWS /* do signal stuff only on unix */
31 static int please_dumpstats
=0; /* whether we should dump stats during the loop */
32 static int please_reset
=0; /* whether we just got a sighup */
33 static int please_reap_children
=0; /* whether we should waitpid for exited children*/
34 #endif /* signal stuff */
37 static crypto_pk_env_t
*onionkey
=NULL
;
38 static crypto_pk_env_t
*linkkey
=NULL
;
39 static crypto_pk_env_t
*identitykey
=NULL
;
41 /********* END VARIABLES ************/
43 void set_onion_key(crypto_pk_env_t
*k
) {
47 crypto_pk_env_t
*get_onion_key(void) {
52 void set_link_key(crypto_pk_env_t
*k
)
57 crypto_pk_env_t
*get_link_key(void)
63 void set_identity_key(crypto_pk_env_t
*k
) {
67 crypto_pk_env_t
*get_identity_key(void) {
72 /****************************************************************************
74 * This section contains accessors and other methods on the connection_array
75 * and poll_array variables (which are global within this file and unavailable
78 ****************************************************************************/
80 int connection_add(connection_t
*conn
) {
82 if(nfds
>= options
.MaxConn
-1) {
83 log(LOG_WARNING
,"connection_add(): failing because nfds is too high.");
87 conn
->poll_index
= nfds
;
88 connection_set_poll_socket(conn
);
89 connection_array
[nfds
] = conn
;
91 /* zero these out here, because otherwise we'll inherit values from the previously freed one */
92 poll_array
[nfds
].events
= 0;
93 poll_array
[nfds
].revents
= 0;
97 log(LOG_INFO
,"connection_add(): new conn type %d, socket %d, nfds %d.",conn
->type
, conn
->s
, nfds
);
102 void connection_set_poll_socket(connection_t
*conn
) {
103 poll_array
[conn
->poll_index
].fd
= conn
->s
;
106 /* Remove the current function from the global list, and remove the
107 * corresponding poll entry. Calling this function will shift the last
108 * connection (if any) into the position occupied by conn.
110 int connection_remove(connection_t
*conn
) {
116 log(LOG_INFO
,"connection_remove(): removing socket %d, nfds now %d",conn
->s
, nfds
-1);
117 circuit_about_to_close_connection(conn
); /* if it's an edge conn, remove it from the list
118 * of conn's on this circuit. If it's not on an edge,
119 * flush and send destroys for all circuits on this conn
122 current_index
= conn
->poll_index
;
123 if(current_index
== nfds
-1) { /* this is the end */
128 /* we replace this one with the one at the end, then free it */
130 poll_array
[current_index
].fd
= poll_array
[nfds
].fd
;
131 poll_array
[current_index
].events
= poll_array
[nfds
].events
;
132 poll_array
[current_index
].revents
= poll_array
[nfds
].revents
;
133 connection_array
[current_index
] = connection_array
[nfds
];
134 connection_array
[current_index
]->poll_index
= current_index
;
139 void get_connection_array(connection_t
***array
, int *n
) {
140 *array
= connection_array
;
144 void connection_watch_events(connection_t
*conn
, short events
) {
146 assert(conn
&& conn
->poll_index
< nfds
);
148 poll_array
[conn
->poll_index
].events
= events
;
151 int connection_is_reading(connection_t
*conn
) {
152 return poll_array
[conn
->poll_index
].events
& POLLIN
;
155 void connection_stop_reading(connection_t
*conn
) {
157 assert(conn
&& conn
->poll_index
< nfds
);
159 log(LOG_DEBUG
,"connection_stop_reading() called.");
160 if(poll_array
[conn
->poll_index
].events
& POLLIN
)
161 poll_array
[conn
->poll_index
].events
-= POLLIN
;
164 void connection_start_reading(connection_t
*conn
) {
166 assert(conn
&& conn
->poll_index
< nfds
);
168 poll_array
[conn
->poll_index
].events
|= POLLIN
;
171 void connection_stop_writing(connection_t
*conn
) {
173 assert(conn
&& conn
->poll_index
< nfds
);
175 if(poll_array
[conn
->poll_index
].events
& POLLOUT
)
176 poll_array
[conn
->poll_index
].events
-= POLLOUT
;
179 void connection_start_writing(connection_t
*conn
) {
181 assert(conn
&& conn
->poll_index
< nfds
);
183 poll_array
[conn
->poll_index
].events
|= POLLOUT
;
186 static void conn_read(int i
) {
187 connection_t
*conn
= connection_array
[i
];
189 /* see http://www.greenend.org.uk/rjk/2001/06/poll.html for
190 * discussion of POLLIN vs POLLHUP */
191 if(!(poll_array
[i
].revents
& (POLLIN
|POLLHUP
|POLLERR
)))
192 if(!connection_is_reading(conn
) ||
193 !connection_has_pending_tls_data(conn
))
194 return; /* this conn should not read */
196 log_fn(LOG_DEBUG
,"socket %d wants to read.",conn
->s
);
198 assert_connection_ok(conn
, time(NULL
));
201 /* XXX does POLLHUP also mean it's definitely broken? */
203 (poll_array
[i
].revents
& POLLERR
) ||
205 connection_handle_read(conn
) < 0)
207 /* this connection is broken. remove it */
208 log_fn(LOG_INFO
,"%s connection broken, removing.", conn_type_to_string
[conn
->type
]);
209 connection_remove(conn
);
210 connection_free(conn
);
211 if(i
<nfds
) { /* we just replaced the one at i with a new one. process it too. */
214 } else assert_connection_ok(conn
, time(NULL
));
217 static void conn_write(int i
) {
220 if(!(poll_array
[i
].revents
& POLLOUT
))
221 return; /* this conn doesn't want to write */
223 conn
= connection_array
[i
];
224 log_fn(LOG_DEBUG
,"socket %d wants to write.",conn
->s
);
226 assert_connection_ok(conn
, time(NULL
));
228 if(connection_handle_write(conn
) < 0) { /* this connection is broken. remove it. */
229 log_fn(LOG_INFO
,"%s connection broken, removing.", conn_type_to_string
[conn
->type
]);
230 connection_remove(conn
);
231 connection_free(conn
);
232 if(i
<nfds
) { /* we just replaced the one at i with a new one. process it too. */
235 } else assert_connection_ok(conn
, time(NULL
));
238 static void conn_close_if_marked(int i
) {
241 conn
= connection_array
[i
];
242 assert_connection_ok(conn
, time(NULL
));
243 if(conn
->marked_for_close
) {
244 log_fn(LOG_INFO
,"Cleaning up connection (fd %d).",conn
->s
);
245 if(conn
->s
>= 0) { /* might be an incomplete edge connection */
246 /* FIXME there's got to be a better way to check for this -- and make other checks? */
247 if(connection_speaks_cells(conn
)) {
248 if(conn
->state
== OR_CONN_STATE_OPEN
)
249 flush_buf_tls(conn
->tls
, conn
->outbuf
, &conn
->outbuf_flushlen
);
251 flush_buf(conn
->s
, conn
->outbuf
, &conn
->outbuf_flushlen
);
253 if(connection_wants_to_flush(conn
)) /* not done flushing */
254 log_fn(LOG_WARNING
,"Conn (socket %d) still wants to flush. Losing %d bytes!",conn
->s
, (int)buf_datalen(conn
->inbuf
));
256 connection_remove(conn
);
257 connection_free(conn
);
258 if(i
<nfds
) { /* we just replaced the one at i with a new one.
260 conn_close_if_marked(i
);
265 /* Perform regulare maintenance tasks for a single connection. This
266 * function gets run once per second per connection by run_housekeeping.
268 static void run_connection_housekeeping(int i
, time_t now
) {
270 connection_t
*conn
= connection_array
[i
];
271 if(connection_receiver_bucket_should_increase(conn
)) {
272 conn
->receiver_bucket
+= conn
->bandwidth
;
273 // log_fn(LOG_DEBUG,"Receiver bucket %d now %d.", i, conn->receiver_bucket);
276 if(conn
->wants_to_read
== 1 /* it's marked to turn reading back on now */
277 && global_read_bucket
> 0 /* and we're allowed to read */
278 && (!connection_speaks_cells(conn
) || conn
->receiver_bucket
> 0)) {
279 /* and either a non-cell conn or a cell conn with non-empty bucket */
280 conn
->wants_to_read
= 0;
281 connection_start_reading(conn
);
282 if(conn
->wants_to_write
== 1) {
283 conn
->wants_to_write
= 0;
284 connection_start_writing(conn
);
288 /* check connections to see whether we should send a keepalive, expire, or wait */
289 if(!connection_speaks_cells(conn
))
292 if(now
>= conn
->timestamp_lastwritten
+ options
.KeepalivePeriod
) {
293 if((!options
.OnionRouter
&& !circuit_get_by_conn(conn
)) ||
294 (!connection_state_is_open(conn
))) {
295 /* we're an onion proxy, with no circuits; or our handshake has expired. kill it. */
296 log_fn(LOG_INFO
,"Expiring connection to %d (%s:%d).",
297 i
,conn
->address
, conn
->port
);
298 conn
->marked_for_close
= 1;
300 /* either a full router, or we've got a circuit. send a padding cell. */
301 log_fn(LOG_DEBUG
,"Sending keepalive to (%s:%d)",
302 conn
->address
, conn
->port
);
303 memset(&cell
,0,sizeof(cell_t
));
304 cell
.command
= CELL_PADDING
;
305 connection_or_write_cell_to_buf(&cell
, conn
);
310 /* Perform regular maintenance tasks. This function gets run once per
311 * second by prepare_for_poll.
313 static void run_scheduled_events(time_t now
) {
314 static long time_to_fetch_directory
= 0;
315 static long time_to_new_circuit
= 0;
319 /* 1. Every DirFetchPostPeriod seconds, we get a new directory and upload
320 * our descriptor (if any). */
321 if(time_to_fetch_directory
< now
) {
322 /* it's time to fetch a new directory and/or post our descriptor */
323 if(options
.OnionRouter
) {
324 router_rebuild_descriptor();
325 router_upload_desc_to_dirservers();
327 if(!options
.DirPort
) {
328 /* NOTE directory servers do not currently fetch directories.
329 * Hope this doesn't bite us later. */
330 directory_initiate_command(router_pick_directory_server(),
331 DIR_CONN_STATE_CONNECTING_FETCH
);
333 time_to_fetch_directory
= now
+ options
.DirFetchPostPeriod
;
336 /* 2. Every NewCircuitPeriod seconds, we expire old ciruits and make a
339 if(options
.APPort
&& time_to_new_circuit
< now
) {
340 circuit_expire_unused_circuits();
341 circuit_launch_new(-1); /* tell it to forget about previous failures */
342 circ
= circuit_get_newest_open();
343 if(!circ
|| circ
->dirty
) {
344 log_fn(LOG_INFO
,"Youngest circuit %s; launching replacement.", circ
? "dirty" : "missing");
345 circuit_launch_new(0); /* make an onion and lay the circuit */
347 time_to_new_circuit
= now
+ options
.NewCircuitPeriod
;
350 /* 3. Every second, we check how much bandwidth we've consumed and
351 * increment global_read_bucket.
353 stats_n_bytes_read
+= stats_prev_global_read_bucket
-global_read_bucket
;
354 if(global_read_bucket
< 9*options
.TotalBandwidth
) {
355 global_read_bucket
+= options
.TotalBandwidth
;
356 log_fn(LOG_DEBUG
,"global_read_bucket now %d.", global_read_bucket
);
358 stats_prev_global_read_bucket
= global_read_bucket
;
361 /* 4. We do houskeeping for each connection... */
362 for(i
=0;i
<nfds
;i
++) {
363 run_connection_housekeeping(i
, now
);
366 /* 5. and blow away any connections that need to die. can't do this later
367 * because we might open up a circuit and not realize we're about to cull
368 * the connection it's running over.
371 conn_close_if_marked(i
);
374 static int prepare_for_poll(void) {
375 static long current_second
= 0; /* from previous calls to gettimeofday */
380 tor_gettimeofday(&now
);
382 if(now
.tv_sec
> current_second
) { /* the second has rolled over. check more stuff. */
384 ++stats_n_seconds_reading
;
385 run_scheduled_events(now
.tv_sec
);
387 current_second
= now
.tv_sec
; /* remember which second it is, for next time */
390 for(i
=0;i
<nfds
;i
++) {
391 conn
= connection_array
[i
];
392 if(connection_has_pending_tls_data(conn
)) {
393 log_fn(LOG_DEBUG
,"sock %d has pending bytes.",conn
->s
);
394 return 0; /* has pending bytes to read; don't let poll wait. */
398 return (1000 - (now
.tv_usec
/ 1000)); /* how many milliseconds til the next second? */
401 static crypto_pk_env_t
*init_key_from_file(const char *fname
)
403 crypto_pk_env_t
*prkey
= NULL
;
407 if (!(prkey
= crypto_new_pk_env(CRYPTO_PK_RSA
))) {
408 log(LOG_ERR
, "Error creating crypto environment.");
412 switch(file_status(fname
)) {
415 log(LOG_ERR
, "Can't read key from %s", fname
);
418 log(LOG_INFO
, "No key found in %s; generating fresh key.", fname
);
419 if (crypto_pk_generate_key(prkey
)) {
420 log(LOG_ERR
, "Error generating key: %s", crypto_perror());
423 if (crypto_pk_check_key(prkey
) <= 0) {
424 log(LOG_ERR
, "Generated key seems invalid");
427 log(LOG_INFO
, "Generated key seems valid");
428 if (crypto_pk_write_private_key_to_filename(prkey
, fname
)) {
429 log(LOG_ERR
, "Couldn't write generated key to %s.", fname
);
434 if (crypto_pk_read_private_key_from_filename(prkey
, fname
)) {
435 log(LOG_ERR
, "Error loading private key.");
445 crypto_free_pk_env(prkey
);
446 if (fd
>= 0 && !file
)
453 static int init_keys(void)
456 char fingerprint
[FINGERPRINT_LEN
+MAX_NICKNAME_LEN
+3];
458 const char *tmp
, *mydesc
;
459 crypto_pk_env_t
*prkey
;
461 /* OP's don't need keys. Just initialize the TLS context.*/
462 if (!options
.OnionRouter
) {
463 assert(!options
.DirPort
);
464 if (tor_tls_context_new(NULL
, 0, NULL
)<0) {
465 log_fn(LOG_ERR
, "Error creating TLS context for OP.");
470 assert(options
.DataDirectory
);
471 if (strlen(options
.DataDirectory
) > (512-128)) {
472 log_fn(LOG_ERR
, "DataDirectory is too long.");
475 if (check_private_dir(options
.DataDirectory
, 1)) {
478 sprintf(keydir
,"%s/keys",options
.DataDirectory
);
479 if (check_private_dir(keydir
, 1)) {
482 cp
= keydir
+ strlen(keydir
); /* End of string. */
484 /* 1. Read identity key. Make it if none is found. */
485 strcpy(cp
, "/identity.key");
486 log_fn(LOG_INFO
,"Reading/making identity key %s...",keydir
);
487 prkey
= init_key_from_file(keydir
);
488 if (!prkey
) return -1;
489 set_identity_key(prkey
);
490 /* 2. Read onion key. Make it if none is found. */
491 strcpy(cp
, "/onion.key");
492 log_fn(LOG_INFO
,"Reading/making onion key %s...",keydir
);
493 prkey
= init_key_from_file(keydir
);
494 if (!prkey
) return -1;
495 set_onion_key(prkey
);
497 /* 3. Initialize link key and TLS context. */
498 strcpy(cp
, "/link.key");
499 log_fn(LOG_INFO
,"Reading/making link key %s...",keydir
);
500 prkey
= init_key_from_file(keydir
);
501 if (!prkey
) return -1;
503 if (tor_tls_context_new(prkey
, 1, options
.Nickname
) < 0) {
504 log_fn(LOG_ERR
, "Error initializing TLS context");
507 /* 4. Dump router descriptor to 'router.desc' */
508 /* Must be called after keys are initialized. */
509 if (!(router_get_my_descriptor())) {
510 log_fn(LOG_ERR
, "Error initializing descriptor.");
513 /* We need to add our own fingerprint so it gets recognized. */
514 if (dirserv_add_own_fingerprint(options
.Nickname
, get_identity_key())) {
515 log_fn(LOG_ERR
, "Error adding own fingerprint to approved set");
518 tmp
= mydesc
= router_get_my_descriptor();
519 if (dirserv_add_descriptor(&tmp
)) {
520 log(LOG_ERR
, "Unable to add own descriptor to directory.");
523 sprintf(keydir
,"%s/router.desc", options
.DataDirectory
);
524 log_fn(LOG_INFO
,"Dumping descriptor to %s...",keydir
);
525 if (write_str_to_file(keydir
, mydesc
)) {
528 /* 5. Dump fingerprint to 'fingerprint' */
529 sprintf(keydir
,"%s/fingerprint", options
.DataDirectory
);
530 log_fn(LOG_INFO
,"Dumping fingerprint to %s...",keydir
);
531 assert(strlen(options
.Nickname
) <= MAX_NICKNAME_LEN
);
532 strcpy(fingerprint
, options
.Nickname
);
533 strcat(fingerprint
, " ");
534 if (crypto_pk_get_fingerprint(get_identity_key(),
535 fingerprint
+strlen(fingerprint
))<0) {
536 log_fn(LOG_ERR
, "Error computing fingerprint");
539 strcat(fingerprint
, "\n");
540 if (write_str_to_file(keydir
, fingerprint
))
544 /* 6. [dirserver only] load approved-routers file */
545 sprintf(keydir
,"%s/approved-routers", options
.DataDirectory
);
546 log_fn(LOG_INFO
,"Loading approved fingerprints from %s...",keydir
);
547 if(dirserv_parse_fingerprint_file(keydir
) < 0) {
548 log_fn(LOG_ERR
, "Error loading fingerprints");
551 /* 7. [dirserver only] load old directory, if it's there */
552 sprintf(keydir
,"%s/cached-directory", options
.DataDirectory
);
553 log_fn(LOG_INFO
,"Loading cached directory from %s...",keydir
);
554 cp
= read_file_to_str(keydir
);
556 log_fn(LOG_INFO
,"Cached directory %s not present. Ok.",keydir
);
558 if(dirserv_init_from_directory_string(cp
) < 0) {
559 log_fn(LOG_ERR
, "Cached directory %s is corrupt", keydir
);
569 static int do_main_loop(void) {
574 /* load the routers file */
575 if(router_get_list_from_file(options
.RouterFile
) < 0) {
576 log_fn(LOG_ERR
,"Error loading router list.");
580 /* load the private keys, if we're supposed to have them, and set up the
582 if (init_keys() < 0) {
583 log_fn(LOG_ERR
,"Error initializing keys; exiting");
587 if(options
.OnionRouter
) {
588 cpu_init(); /* launch cpuworkers. Need to do this *after* we've read the onion key. */
589 router_upload_desc_to_dirservers(); /* upload our descriptor to all dirservers */
592 /* start up the necessary connections based on which ports are
593 * non-zero. This is where we try to connect to all the other ORs,
594 * and start the listeners.
596 retry_all_connections((uint16_t) options
.ORPort
,
597 (uint16_t) options
.APPort
,
598 (uint16_t) options
.DirPort
);
601 #ifndef MS_WIN32 /* do signal stuff only on unix */
602 if(please_dumpstats
) {
604 please_dumpstats
= 0;
607 /* fetch a new directory */
608 if(options
.DirPort
) {
609 if(router_get_list_from_file(options
.RouterFile
) < 0) {
610 log(LOG_WARNING
,"Error reloading router list. Continuing with old list.");
613 directory_initiate_command(router_pick_directory_server(), DIR_CONN_STATE_CONNECTING_FETCH
);
616 /* close and reopen the log files */
621 if(please_reap_children
) {
622 while(waitpid(-1,NULL
,WNOHANG
)) ; /* keep reaping until no more zombies */
623 please_reap_children
= 0;
625 #endif /* signal stuff */
627 timeout
= prepare_for_poll();
629 /* poll until we have an event, or the second ends */
630 poll_result
= poll(poll_array
, nfds
, timeout
);
632 #if 0 /* let catch() handle things like ^c, and otherwise don't worry about it */
633 if(poll_result
< 0) {
634 log(LOG_ERR
,"do_main_loop(): poll failed.");
635 if(errno
!= EINTR
) /* let the program survive things like ^z */
640 /* do all the reads and errors first, so we can detect closed sockets */
642 conn_read(i
); /* this also blows away broken connections */
644 /* then do the writes */
648 /* any of the conns need to be closed now? */
650 conn_close_if_marked(i
);
652 /* refilling buckets and sending cells happens at the beginning of the
653 * next iteration of the loop, inside prepare_for_poll()
658 static void catch(int the_signal
) {
660 #ifndef MS_WIN32 /* do signal stuff only on unix */
665 log(LOG_ERR
,"Catching signal %d, exiting cleanly.", the_signal
);
666 /* we don't care if there was an error when we unlink,
667 nothing we could do about it anyways */
668 unlink(options
.PidFile
);
674 please_dumpstats
= 1;
677 please_reap_children
= 1;
680 log(LOG_WARNING
,"Caught signal %d that we can't handle??", the_signal
);
682 #endif /* signal stuff */
685 static void dumpstats(void) { /* dump stats to stdout */
688 time_t now
= time(NULL
);
690 printf("Dumping stats:\n");
692 for(i
=0;i
<nfds
;i
++) {
693 conn
= connection_array
[i
];
694 printf("Conn %d (socket %d) type %d (%s), state %d (%s), created %ld secs ago\n",
695 i
, conn
->s
, conn
->type
, conn_type_to_string
[conn
->type
],
696 conn
->state
, conn_state_to_string
[conn
->type
][conn
->state
], now
- conn
->timestamp_created
);
697 if(!connection_is_listener(conn
)) {
698 printf("Conn %d is to '%s:%d'.\n",i
,conn
->address
, conn
->port
);
699 printf("Conn %d: %d bytes waiting on inbuf (last read %ld secs ago)\n",i
,
700 (int)buf_datalen(conn
->inbuf
),
701 now
- conn
->timestamp_lastread
);
702 printf("Conn %d: %d bytes waiting on outbuf (last written %ld secs ago)\n",i
,
703 (int)buf_datalen(conn
->outbuf
), now
- conn
->timestamp_lastwritten
);
705 circuit_dump_by_conn(conn
); /* dump info about all the circuits using this conn */
708 printf("Cells processed: %10lu padding\n"
713 " (%10lu delivered)\n"
715 stats_n_padding_cells_processed
,
716 stats_n_create_cells_processed
,
717 stats_n_created_cells_processed
,
718 stats_n_relay_cells_processed
,
719 stats_n_relay_cells_relayed
,
720 stats_n_relay_cells_delivered
,
721 stats_n_destroy_cells_processed
);
722 if (stats_n_data_cells_packaged
)
723 printf("Average outgoing cell fullness: %2.3f%%\n",
724 100*(((double)stats_n_data_bytes_packaged
) /
725 (stats_n_data_cells_packaged
*(CELL_PAYLOAD_SIZE
-RELAY_HEADER_SIZE
))) );
726 if (stats_n_data_cells_packaged
)
727 printf("Average incoming cell fullness: %2.3f%%\n",
728 100*(((double)stats_n_data_bytes_received
) /
729 (stats_n_data_cells_received
*(CELL_PAYLOAD_SIZE
-RELAY_HEADER_SIZE
))) );
731 if (stats_n_seconds_reading
)
732 printf("Average bandwidth used: %d bytes/sec\n",
733 (int) (stats_n_bytes_read
/stats_n_seconds_reading
));
736 void daemonize(void) {
738 /* Fork; parent exits. */
742 /* Create new session; make sure we never get a terminal */
751 fclose(stdout
); /* XXX Nick: this closes our log, right? is it safe to leave this open? */
756 void write_pidfile(char *filename
) {
759 if ((pidfile
= fopen(filename
, "w")) == NULL
) {
760 log_fn(LOG_WARNING
, "unable to open %s for writing: %s", filename
,
763 fprintf(pidfile
, "%d", getpid());
768 int tor_main(int argc
, char *argv
[]) {
770 if(getconfig(argc
,argv
,&options
)) {
771 log_fn(LOG_ERR
,"Reading config file failed. exiting.");
774 log_set_severity(options
.loglevel
); /* assign logging severity level from options */
775 global_read_bucket
= options
.TotalBandwidth
; /* start it at 1 second of traffic */
776 stats_prev_global_read_bucket
= global_read_bucket
;
778 /* write our pid to the pid file */
779 write_pidfile(options
.PidFile
);
784 if(options
.OnionRouter
) { /* only spawn dns handlers if we're a router */
785 dns_init(); /* initialize the dns resolve tree, and spawn workers */
788 #ifndef MS_WINDOWS /* do signal stuff only on unix */
789 signal (SIGINT
, catch); /* catch kills so we can exit cleanly */
790 signal (SIGTERM
, catch);
791 signal (SIGUSR1
, catch); /* to dump stats to stdout */
792 signal (SIGHUP
, catch); /* to reload directory */
793 signal (SIGCHLD
, catch); /* for exiting dns/cpu workers */
794 #endif /* signal stuff */
796 crypto_global_init();
799 crypto_global_cleanup();