diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index bc18b2fbfa..9020a8028a 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -928,6 +928,10 @@ is non-zero):
seconds, we exit. If we get a second SIGINT, we exit immedi-
ately. (Default: 30 seconds)
+**HeartbeatPeriod** __N__ **minutes**|**hours**|**days**|**weeks**::
+ Log a heartbeat message every **HeartbeatPeriod** seconds. This is
+ a log level __info__ message, designed to let you know your Tor
+ instance is still alive and doing useful things. (Default: 6 hours)
**AccountingMax** __N__ **bytes**|**KB**|**MB**|**GB**|**TB**::
Never send more than the specified number of bytes in a given accounting
diff --git a/src/common/torlog.h b/src/common/torlog.h
index 1fe5806d16..4192a881cb 100644
--- a/src/common/torlog.h
+++ b/src/common/torlog.h
@@ -92,8 +92,10 @@
#define LD_HIST (1u<<18)
/** OR handshaking */
#define LD_HANDSHAKE (1u<<19)
+/** Heartbeat messages */
+#define LD_HEARTBEAT (1u<<20)
/** Number of logging domains in the code. */
-#define N_LOGGING_DOMAINS 20
+#define N_LOGGING_DOMAINS 21
/** This log message is not safe to send to a callback-based logger
* immediately. Used as a flag, not a log domain. */
diff --git a/src/or/Makefile.am b/src/or/Makefile.am
index b6637ba631..a49a86a607 100644
--- a/src/or/Makefile.am
+++ b/src/or/Makefile.am
@@ -52,7 +52,8 @@ libtor_a_SOURCES = \
routerparse.c \
$(evdns_source) \
$(tor_platform_source) \
- config_codedigest.c
+ config_codedigest.c \
+ status.c
#libtor_a_LIBADD = ../common/libor.a ../common/libor-crypto.a \
# ../common/libor-event.a
diff --git a/src/or/config.c b/src/or/config.c
index 65bc1d5fc6..e2b2b5ce5d 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -267,6 +267,7 @@ static config_var_t _option_vars[] = {
#endif
OBSOLETE("Group"),
V(HardwareAccel, BOOL, "0"),
+ V(HeartbeatPeriod, INTERVAL, "6 hours"),
V(AccelName, STRING, NULL),
V(AccelDir, FILENAME, NULL),
V(HashedControlPassword, LINELIST, NULL),
@@ -2915,6 +2916,10 @@ compute_publishserverdescriptor(or_options_t *options)
* will generate too many circuits and potentially overload the network. */
#define MIN_CIRCUIT_STREAM_TIMEOUT 10
+/** Lowest allowable value for HeartbeatPeriod; if this is too low, we might
+ * expose more information than we're comfortable with. */
+#define MIN_HEARTBEAT_PERIOD (30*60)
+
/** Return 0 if every setting in options is reasonable, and a
* permissible transition from old_options. Else return -1.
* Should have no side effects, except for normalizing the contents of
@@ -3376,6 +3381,14 @@ options_validate(or_options_t *old_options, or_options_t *options,
"raising to %d seconds.", MIN_CIRCUIT_STREAM_TIMEOUT);
options->CircuitStreamTimeout = MIN_CIRCUIT_STREAM_TIMEOUT;
}
+
+ if (options->HeartbeatPeriod &&
+ options->HeartbeatPeriod < MIN_HEARTBEAT_PERIOD) {
+ log_warn(LD_CONFIG, "HeartbeatPeriod option is too short; "
+ "raising to %d seconds.", MIN_HEARTBEAT_PERIOD);
+ options->HeartbeatPeriod = MIN_HEARTBEAT_PERIOD;
+ }
+
if (options->KeepalivePeriod < 1)
REJECT("KeepalivePeriod option must be positive.");
diff --git a/src/or/main.c b/src/or/main.c
index c6fd2c0593..6e3cb2b386 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -1050,6 +1050,7 @@ run_scheduled_events(time_t now)
static time_t time_to_check_port_forwarding = 0;
static int should_init_bridge_stats = 1;
static time_t time_to_retry_dns_init = 0;
+ static time_t time_last_written_heartbeat = 0;
or_options_t *options = get_options();
int is_server = server_mode(options);
int i;
@@ -1440,6 +1441,12 @@ run_scheduled_events(time_t now)
now);
time_to_check_port_forwarding = now+PORT_FORWARDING_CHECK_INTERVAL;
}
+
+ /** 11. write the heartbeat message */
+ if (options->HeartbeatPeriod &&
+ time_last_written_heartbeat + options->HeartbeatPeriod < now)
+ log_heartbeat(now);
+ time_last_written_heartbeat = now;
}
/** Timer: used to invoke second_elapsed_callback() once per second. */
diff --git a/src/or/or.h b/src/or/or.h
index 9bf46e9793..4f3fef036f 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2718,6 +2718,9 @@ typedef struct {
config_line_t *HidServAuth; /**< List of configuration lines for client-side
* authorizations for hidden services */
char *ContactInfo; /**< Contact info to be published in the directory. */
+
+ int HeartbeatPeriod; /**< Log heartbeat messages after this many seconds
+ * have passed. */
char *HTTPProxy; /**< hostname[:port] to use as http proxy, if any. */
tor_addr_t HTTPProxyAddr; /**< Parsed IPv4 addr for http proxy, if any. */
diff --git a/src/or/status.c b/src/or/status.c
new file mode 100644
index 0000000000..0cd9a07226
--- /dev/null
+++ b/src/or/status.c
@@ -0,0 +1,27 @@
+/* Copyright (c) 2010, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file status.c
+ * \brief Keep status information and log the heartbeat messages.
+ **/
+
+#include "or.h"
+
+
+/****************************************************************************/
+
+
+
+#define BEAT(x) log_fn(LOG_NOTICE, LD_HEARTBEAT, (x) )
+
+void
+log_heartbeat(time_t now) {
+ or_options_t *opt = get_options();
+
+ (void) now;
+ log_fn(LOG_NOTICE, LD_HEARTBEAT, "This is the Tor heartbeat message.");
+ if (!server_mode(opt))
+ BEAT("you are a client, hahaha");
+
+}