--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <pthread.h>
+
+#include "serverpool.h"
+#include "stats.h"
+
+using namespace std;
+
+extern ServerPool *servers;
+
+StatsThread::StatsThread(const std::string &stats_file, int stats_interval)
+ : stats_file(stats_file),
+ stats_interval(stats_interval)
+{
+}
+
+void StatsThread::run()
+{
+ should_stop = false;
+ pthread_create(&worker_thread, NULL, do_work_thunk, this);
+}
+
+void StatsThread::stop()
+{
+ should_stop = true;
+ pthread_kill(worker_thread, SIGHUP);
+ if (pthread_join(worker_thread, NULL) == -1) {
+ perror("pthread_join");
+ exit(1);
+ }
+}
+
+void *StatsThread::do_work_thunk(void *arg)
+{
+ StatsThread *stats_thread = reinterpret_cast<StatsThread *>(arg);
+ stats_thread->do_work();
+ return NULL;
+}
+
+void StatsThread::do_work()
+{
+ while (!should_stop) {
+ int fd;
+ FILE *fp;
+ time_t now;
+ 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) {
+ perror(filename);
+ free(filename);
+ goto sleep;
+ }
+
+ fp = fdopen(fd, "w");
+ if (fp == NULL) {
+ perror("fdopen");
+ close(fd);
+ unlink(filename);
+ free(filename);
+ goto sleep;
+ }
+
+ now = time(NULL);
+ client_stats = servers->get_client_stats();
+ for (size_t i = 0; i < client_stats.size(); ++i) {
+ fprintf(fp, "%s %s %d %llu\n",
+ client_stats[i].remote_addr.c_str(),
+ client_stats[i].stream_id.c_str(),
+ int(now - client_stats[i].connect_time),
+ (long long unsigned)(client_stats[i].bytes_sent));
+ }
+ if (fclose(fp) == EOF) {
+ perror("fclose");
+ unlink(filename);
+ free(filename);
+ goto sleep;
+ }
+
+ if (rename(filename, stats_file.c_str()) == -1) {
+ perror("rename");
+ unlink(filename);
+ }
+
+sleep:
+ int left_to_sleep = stats_interval;
+ do {
+ left_to_sleep = sleep(left_to_sleep);
+ } while (left_to_sleep > 0 && !should_stop);
+ }
+}
--- /dev/null
+#ifndef _STATS_H
+#define _STATS_H 1
+
+#include <pthread.h>
+#include <string>
+
+// A thread that regularly writes out statistics, ie. a list of all connected clients
+// with some information about each.
+
+class StatsThread {
+public:
+ StatsThread(const std::string &stats_file, int stats_interval);
+ void run();
+ void stop();
+
+private:
+ // Recover the this pointer, and call do_work().
+ static void *do_work_thunk(void *arg);
+
+ void do_work();
+
+ std::string stats_file;
+ int stats_interval;
+
+ pthread_t worker_thread;
+ volatile bool should_stop;
+};
+
+#endif // !defined(_STATS_H)