Run include-what-you-use.
[cubemap] / stats.cpp
1 #include <fcntl.h>
2 #include <stddef.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <time.h>
7 #include <unistd.h>
8 #include <vector>
9
10 #include "client.h"
11 #include "log.h"
12 #include "serverpool.h"
13 #include "stats.h"
14 #include "util.h"
15
16 using namespace std;
17
18 extern ServerPool *servers;
19
20 StatsThread::StatsThread(const std::string &stats_file, int stats_interval)
21         : stats_file(stats_file),
22           stats_interval(stats_interval)
23 {
24 }
25
26 void StatsThread::do_work()
27 {
28         while (!should_stop()) {
29                 int fd;
30                 FILE *fp;
31                 time_t now;
32                 vector<ClientStats> client_stats;
33
34                 // Open a new, temporary file.
35                 char *filename = strdup((stats_file + ".new.XXXXXX").c_str());
36                 fd = mkostemp(filename, O_WRONLY);
37                 if (fd == -1) {
38                         log_perror(filename);
39                         free(filename);
40                         goto sleep;
41                 }
42
43                 fp = fdopen(fd, "w");
44                 if (fp == NULL) {
45                         log_perror("fdopen");
46                         safe_close(fd);
47                         if (unlink(filename) == -1) {
48                                 log_perror(filename);
49                         }
50                         free(filename);
51                         goto sleep;
52                 }
53
54                 now = time(NULL);
55                 client_stats = servers->get_client_stats();
56                 for (size_t i = 0; i < client_stats.size(); ++i) {
57                         fprintf(fp, "%s %d %d %s %d %llu %llu %llu\n",
58                                 client_stats[i].remote_addr.c_str(),
59                                 client_stats[i].sock,
60                                 client_stats[i].fwmark,
61                                 client_stats[i].url.c_str(),
62                                 int(now - client_stats[i].connect_time),
63                                 (long long unsigned)(client_stats[i].bytes_sent),
64                                 (long long unsigned)(client_stats[i].bytes_lost),
65                                 (long long unsigned)(client_stats[i].num_loss_events));
66                 }
67                 if (fclose(fp) == EOF) {
68                         log_perror("fclose");
69                         if (unlink(filename) == -1) {
70                                 log_perror(filename);
71                         }
72                         free(filename);
73                         goto sleep;
74                 }
75                 
76                 if (rename(filename, stats_file.c_str()) == -1) {
77                         log_perror("rename");
78                         if (unlink(filename) == -1) {
79                                 log_perror(filename);
80                         }
81                 }
82                 free(filename);
83
84 sleep:
85                 // Wait until we are asked to quit, stats_interval timeout,
86                 // or a spurious signal. (The latter will cause us to write stats
87                 // too often, but that's okay.)
88                 timespec timeout_ts;
89                 timeout_ts.tv_sec = stats_interval;
90                 timeout_ts.tv_nsec = 0;
91                 wait_for_wakeup(&timeout_ts);
92         }
93 }