+struct StatsThreadParameters {
+ string stats_file;
+ int stats_interval;
+};
+
+void *stats_thread_run(void *arg)
+{
+ const StatsThreadParameters *parms = reinterpret_cast<StatsThreadParameters *>(arg);
+ while (!hupped) {
+ int fd;
+ FILE *fp;
+ time_t now;
+ vector<ClientStats> client_stats;
+
+ // Open a new, temporary file.
+ char *filename = strdup((parms->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, parms->stats_file.c_str()) == -1) {
+ perror("rename");
+ unlink(filename);
+ }
+
+sleep:
+ int left_to_sleep = parms->stats_interval;
+ do {
+ left_to_sleep = sleep(left_to_sleep);
+ } while (left_to_sleep > 0);
+ }
+ return NULL;
+}
+