Revert "Rewrite the entire internal signal handling/wakeup."
[cubemap] / stats.cpp
1 #include <errno.h>
2 #include <fcntl.h>
3 #include <poll.h>
4 #include <stddef.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <time.h>
9 #include <unistd.h>
10 #include <vector>
11
12 #include "client.h"
13 #include "log.h"
14 #include "serverpool.h"
15 #include "stats.h"
16
17 using namespace std;
18
19 extern ServerPool *servers;
20
21 StatsThread::StatsThread(const std::string &stats_file, int stats_interval)
22         : stats_file(stats_file),
23           stats_interval(stats_interval)
24 {
25 }
26
27 void StatsThread::do_work()
28 {
29         while (!should_stop) {
30                 int fd;
31                 FILE *fp;
32                 time_t now;
33                 vector<ClientStats> client_stats;
34
35                 // Open a new, temporary file.
36                 char *filename = strdup((stats_file + ".new.XXXXXX").c_str());
37                 fd = mkostemp(filename, O_WRONLY);
38                 if (fd == -1) {
39                         log_perror(filename);
40                         free(filename);
41                         goto sleep;
42                 }
43
44                 fp = fdopen(fd, "w");
45                 if (fp == NULL) {
46                         log_perror("fdopen");
47                         if (close(fd) == -1) {
48                                 log_perror("close");
49                         }
50                         if (unlink(filename) == -1) {
51                                 log_perror(filename);
52                         }
53                         free(filename);
54                         goto sleep;
55                 }
56
57                 now = time(NULL);
58                 client_stats = servers->get_client_stats();
59                 for (size_t i = 0; i < client_stats.size(); ++i) {
60                         fprintf(fp, "%s %d %d %s %d %llu %llu %llu\n",
61                                 client_stats[i].remote_addr.c_str(),
62                                 client_stats[i].sock,
63                                 client_stats[i].fwmark,
64                                 client_stats[i].stream_id.c_str(),
65                                 int(now - client_stats[i].connect_time),
66                                 (long long unsigned)(client_stats[i].bytes_sent),
67                                 (long long unsigned)(client_stats[i].bytes_lost),
68                                 (long long unsigned)(client_stats[i].num_loss_events));
69                 }
70                 if (fclose(fp) == EOF) {
71                         log_perror("fclose");
72                         if (unlink(filename) == -1) {
73                                 log_perror(filename);
74                         }
75                         free(filename);
76                         goto sleep;
77                 }
78                 
79                 if (rename(filename, stats_file.c_str()) == -1) {
80                         log_perror("rename");
81                         if (unlink(filename) == -1) {
82                                 log_perror(filename);
83                         }
84                 }
85                 free(filename);
86
87 sleep:
88                 // Wait until the stop_fd pipe is closed, stats_interval timeout,
89                 // or a spurious signal. (The latter will cause us to write stats
90                 // too often, but that's okay.)
91                 pollfd pfd;
92                 pfd.fd = stop_fd_read;
93                 pfd.events = POLLIN | POLLRDHUP;
94
95                 int nfds = poll(&pfd, 1, stats_interval * 1000);
96                 if (nfds == 0 || (nfds == -1 && errno == EINTR)) {
97                         continue;
98                 }
99                 if (nfds == 1) {
100                         // Should stop.
101                         break;
102                 }
103                 if (nfds == -1) {
104                         log_perror("poll");
105                         usleep(100000);
106                         continue;
107                 }
108         }
109 }