--- /dev/null
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <vector>
+
+#include "client.h"
+#include "log.h"
+#include "input.h"
+#include "input_stats.h"
+#include "util.h"
+
+using namespace std;
+
+InputStatsThread::InputStatsThread(const string &stats_file, int stats_interval, const vector<Input*> &inputs)
+ : stats_file(stats_file),
+ stats_interval(stats_interval),
+ inputs(inputs)
+{
+}
+
+void InputStatsThread::do_work()
+{
+ while (!should_stop()) {
+ int fd;
+ FILE *fp;
+ vector<ClientStats> client_stats;
+
+ // Open a new, temporary file.
+ char *filename = strdup((stats_file + ".new.XXXXXX").c_str());
+ fd = mkostemp(filename, O_WRONLY);
+ if (fd == -1) {
+ log_perror(filename);
+ free(filename);
+ goto sleep;
+ }
+
+ fp = fdopen(fd, "w");
+ if (fp == NULL) {
+ log_perror("fdopen");
+ safe_close(fd);
+ if (unlink(filename) == -1) {
+ log_perror(filename);
+ }
+ free(filename);
+ goto sleep;
+ }
+
+ for (size_t i = 0; i < inputs.size(); ++i) {
+ InputStats stats = inputs[i]->get_stats();
+ fprintf(fp, "%s %llu %llu\n", stats.url.c_str(),
+ (long long unsigned)(stats.bytes_received),
+ (long long unsigned)(stats.data_bytes_received));
+ }
+ if (fclose(fp) == EOF) {
+ log_perror("fclose");
+ if (unlink(filename) == -1) {
+ log_perror(filename);
+ }
+ free(filename);
+ goto sleep;
+ }
+
+ if (rename(filename, stats_file.c_str()) == -1) {
+ log_perror("rename");
+ if (unlink(filename) == -1) {
+ log_perror(filename);
+ }
+ }
+ free(filename);
+
+sleep:
+ // Wait until we are asked to quit, stats_interval timeout,
+ // or a spurious signal. (The latter will cause us to write stats
+ // too often, but that's okay.)
+ timespec timeout_ts;
+ timeout_ts.tv_sec = stats_interval;
+ timeout_ts.tv_nsec = 0;
+ wait_for_wakeup(&timeout_ts);
+ }
+}