]> git.meshlink.io Git - meshlink/blob - examples/monitor.c
When resetting timers that use CLOCK_MONOTONIC, use a negative value.
[meshlink] / examples / monitor.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <strings.h>
5 #include <curses.h>
6 #include <math.h>
7 #include <assert.h>
8 #include <sys/socket.h>
9 #include <netdb.h>
10
11 #include "../src/meshlink.h"
12 #include "../src/devtools.h"
13
14 static WINDOW *topwin;
15 static WINDOW *nodewin;
16 static WINDOW *splitwin;
17 static WINDOW *logwin;
18 static WINDOW *statuswin;
19 static float splitpoint = 0.5;
20
21 static meshlink_handle_t *mesh;
22 static meshlink_node_t **nodes;
23 static size_t nnodes;
24
25 static void log_message(meshlink_handle_t *mesh, meshlink_log_level_t level, const char *text) {
26         (void)mesh;
27
28         wattron(logwin, COLOR_PAIR(level));
29         wprintw(logwin, "%s\n", text);
30         wattroff(logwin, COLOR_PAIR(level));
31         wrefresh(logwin);
32 }
33
34 static void do_resize() {
35         const int nodelines = lrintf((LINES - 3) * splitpoint);
36         const int loglines = (LINES - 3) - nodelines;
37         assert(nodelines > 1);
38         assert(loglines > 1);
39         assert(COLS > 1);
40
41         mvwin(topwin, 0, 0);
42         wresize(topwin, 1, COLS);
43
44         mvwin(nodewin, 1, 0);
45         wresize(nodewin, nodelines, COLS);
46
47         mvwin(splitwin, 1 + nodelines, 0);
48         wresize(splitwin, 1, COLS);
49
50         mvwin(logwin, 2 + nodelines, 0);
51         wresize(logwin, loglines, COLS);
52
53         mvwin(statuswin, LINES - 1, 0);
54         wresize(statuswin, 1, COLS);
55 }
56
57
58 static void do_redraw_nodes() {
59         werase(nodewin);
60         nodes = meshlink_get_all_nodes(mesh, nodes, &nnodes);
61
62         for(size_t i = 0; i < nnodes; i++) {
63                 devtool_node_status_t status;
64                 devtool_get_node_status(mesh, nodes[i], &status);
65                 char host[NI_MAXHOST] = "";
66                 char serv[NI_MAXSERV] = "";
67                 getnameinfo((struct sockaddr *)&status.address, sizeof status.address, host, sizeof host, serv, sizeof serv, NI_NUMERICHOST | NI_NUMERICSERV);
68                 const char *desc;
69
70                 switch(status.udp_status) {
71                 case DEVTOOL_UDP_FAILED:
72                         desc = "UDP failed";
73                         break;
74
75                 case DEVTOOL_UDP_IMPOSSIBLE:
76                         desc = "unreachable";
77                         break;
78
79                 case DEVTOOL_UDP_TRYING:
80                         desc = "probing";
81                         break;
82
83                 case DEVTOOL_UDP_WORKING:
84                         desc = "UDP working";
85                         break;
86
87                 case DEVTOOL_UDP_UNKNOWN:
88                 default:
89                         desc = "unknown";
90                         break;
91                 };
92
93                 if(!strcmp(nodes[i]->name, mesh->name)) {
94                         desc = "myself";
95                 }
96
97                 char mtustate = ' ';
98
99                 if(status.minmtu) {
100                         if(status.minmtu != status.maxmtu) {
101                                 mtustate = '~';
102                         }
103                 };
104
105                 mvwprintw(nodewin, i, 0, "%-16s  %-12s  %-32s %5s  %c%5d", nodes[i]->name, desc, host, serv, mtustate, status.maxmtu);
106         }
107
108         wnoutrefresh(nodewin);
109 }
110
111 static void do_redraw() {
112         // Draw top line
113         werase(topwin);
114         mvwprintw(topwin, 0, 0, "%-16s  %-12s  %-32s %5s  %6s", "Node:", "Status:", "UDP address:", "Port:", "MTU:");
115         wnoutrefresh(topwin);
116
117         // Draw middle line
118         werase(splitwin);
119         mvwprintw(splitwin, 0, 0, "Log output:");
120         wnoutrefresh(splitwin);
121
122         // Draw bottom line
123         werase(statuswin);
124         mvwprintw(statuswin, 0, 0, "Status bar");
125         wnoutrefresh(statuswin);
126
127         wnoutrefresh(logwin);
128
129         do_redraw_nodes();
130 }
131
132 static void node_status(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) {
133         (void)mesh;
134         (void)node;
135         (void)reachable;
136         do_redraw_nodes();
137         doupdate();
138 }
139
140 int main(int argc, char *argv[]) {
141         const char *confbase = ".monitor";
142         const char *id = NULL;
143
144         if(argc > 1) {
145                 confbase = argv[1];
146         }
147
148         if(argc > 2) {
149                 id = argv[2];
150         }
151
152         initscr();
153         start_color();
154         curs_set(false);
155         noecho();
156
157         topwin = newwin(1, COLS, 0, 0);
158         nodewin = newwin(1, COLS, 1, 0);
159         splitwin = newwin(1, COLS, 2, 0);
160         logwin = newwin(1, COLS, 3, 0);
161         statuswin = newwin(1, COLS, 4, 0);
162
163         leaveok(topwin, true);
164         leaveok(nodewin, true);
165         leaveok(splitwin, true);
166         leaveok(logwin, true);
167         leaveok(statuswin, true);
168
169         wattrset(topwin, A_REVERSE);
170         wattrset(splitwin, A_REVERSE);
171         wattrset(statuswin, A_REVERSE);
172
173         wbkgdset(topwin, ' ' | A_REVERSE);
174         wbkgdset(splitwin, ' ' | A_REVERSE);
175         wbkgdset(statuswin, ' ' | A_REVERSE);
176
177         init_pair(1, COLOR_GREEN, -1);
178         init_pair(2, COLOR_YELLOW, -1);
179         init_pair(3, COLOR_RED, -1);
180         init_pair(4, COLOR_RED, -1);
181
182         scrollok(logwin, true);
183
184         do_resize();
185         do_redraw();
186         doupdate();
187
188         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_message);
189
190         mesh = meshlink_open(confbase, id, "monitor", DEV_CLASS_STATIONARY);
191
192         if(!mesh) {
193                 endwin();
194                 fprintf(stderr, "Could not open MeshLink: %s\n", meshlink_strerror(meshlink_errno));
195                 return 1;
196         }
197
198         meshlink_set_log_cb(mesh, MESHLINK_DEBUG, log_message);
199         meshlink_set_node_status_cb(mesh, node_status);
200
201         if(!meshlink_start(mesh)) {
202                 endwin();
203                 fprintf(stderr, "Could not start MeshLink: %s\n", meshlink_strerror(meshlink_errno));
204                 return 1;
205         }
206
207         bool running = true;
208         timeout(500);
209         wtimeout(topwin, 500);
210
211         do_redraw();
212         doupdate();
213
214         while(running) {
215                 int key = wgetch(topwin);
216
217                 switch(key) {
218                 case 'q':
219                 case 27:
220                 case KEY_BREAK:
221                         running = false;
222                         break;
223
224                 case KEY_RESIZE:
225                         do_resize();
226                         break;
227
228                 case 'r':
229                 case KEY_REFRESH:
230                         clearok(topwin, true);
231                         clearok(nodewin, true);
232                         clearok(splitwin, true);
233                         clearok(logwin, true);
234                         clearok(statuswin, true);
235                         break;
236                 }
237
238                 do_redraw();
239                 doupdate();
240         }
241
242         meshlink_stop(mesh);
243         meshlink_close(mesh);
244
245         endwin();
246
247         return 0;
248 }