net.c (2727B)
1 #include <stdio.h> 2 #include <errno.h> 3 #include <string.h> 4 #include <net/if.h> 5 #include "util.h" 6 #include "net.h" 7 8 #define _STRINGIFY(x) #x 9 #define STRINGIFY(x) _STRINGIFY(x) 10 11 static int _net_read(struct net *n, FILE *f, char *linebuf, size_t bsz) 12 { 13 size_t i; 14 char namebuf[IF_NAMESIZE + 1]; 15 16 for (i = 0; fgets(linebuf, bsz, f); i++) { 17 if (sscanf(linebuf, " %" STRINGIFY(IF_NAMESIZE) "[^:]:" 18 UINT_SCAN(NET_FIELDS), namebuf 19 #define X(d, na) , &n->ifaces[i].d ## na 20 NET_FIELDS(X) 21 #undef X 22 ) < COUNT(NET_FIELDS)) 23 return ENODATA; 24 if (!(n->ifaces[i].ifidx = if_nametoindex(namebuf))) 25 i--; 26 } 27 n->n = i; 28 29 clock_gettime(CLOCK_REALTIME, &n->stamp); 30 31 return 0; 32 } 33 34 int net_init(struct net *n) 35 { 36 char linebuf[512]; 37 char *i; 38 FILE *f = fopen("/proc/net/dev", "r"); 39 int r = ENODATA; 40 41 if (!f) 42 return errno; 43 if (!fgets(linebuf, sizeof(linebuf), f) || 44 !fgets(linebuf, sizeof(linebuf), f)) 45 goto out; 46 if (!*(i = linebuf + strcspn(linebuf, "|"))) 47 goto out; 48 i++; 49 #define X(d, n) \ 50 if (memcmp(i, #n, sizeof(#n) - 1)) \ 51 goto out; \ 52 i += sizeof(#n) - 1; \ 53 if (*i != ' ' && *i != '|' && *i != '\n') \ 54 goto out; \ 55 i += strspn(i, " "); 56 57 NET_FIELDS_RX(X) 58 59 if (*i++ != '|') 60 goto out; 61 62 NET_FIELDS_TX(X) 63 #undef X 64 65 if (*i != '\n') 66 goto out; 67 r = _net_read(n, f, linebuf, sizeof(linebuf)); 68 out: 69 fclose(f); 70 return r; 71 } 72 73 int net_poll(struct net *n, struct json *j) 74 { 75 int r = ENODATA; 76 FILE *f = fopen("/proc/net/dev", "r"); 77 char linebuf[512]; 78 struct net n0 = *n; 79 size_t oi; 80 size_t ni; 81 82 if (!f) 83 return errno; 84 if (!fgets(linebuf, sizeof(linebuf), f) || 85 !fgets(linebuf, sizeof(linebuf), f)) 86 goto out; 87 88 if ((r = _net_read(n, f, linebuf, sizeof(linebuf)))) 89 goto out; 90 91 for (oi = 0, ni = 0; ni < n->n; ni++) { 92 char namebuf[IF_NAMESIZE + 1]; 93 while (oi < n0.n && n0.ifaces[oi].ifidx < n->ifaces[ni].ifidx) 94 oi++; 95 if (!if_indextoname(n->ifaces[ni].ifidx, namebuf)) 96 continue; 97 if ((r = json_obj_key(j, "milliseconds"))) 98 goto out; 99 if ((r = json_int(j, ((intmax_t)n->stamp.tv_sec - n0.stamp.tv_sec) * 1000 + ((intmax_t)n->stamp.tv_nsec - n0.stamp.tv_nsec) / 1000000))) 100 goto out; 101 if ((r = json_obj_key(j, namebuf))) 102 goto out; 103 if ((r = json_obj_open(j))) 104 goto out; 105 if (oi < n0.n && n->ifaces[ni].ifidx == n0.ifaces[oi].ifidx) { 106 #define X(d, na) \ 107 if ((r = json_obj_key(j, #d #na))) \ 108 goto out; \ 109 if ((r = json_int(j, n->ifaces[ni].d ## na - n0.ifaces[oi].d ## na))) \ 110 goto out; 111 NET_FIELDS(X) 112 #undef X 113 } else { 114 #define X(d, na) \ 115 if ((r = json_obj_key(j, #d #na))) \ 116 goto out; \ 117 if ((r = json_int(j, 0))) \ 118 goto out; 119 NET_FIELDS(X) 120 #undef X 121 } 122 if ((r = json_obj_close(j))) 123 goto out; 124 } 125 out: 126 fclose(f); 127 return r; 128 }