diff --git a/mud b/mud index a4e7291..faeb599 160000 --- a/mud +++ b/mud @@ -1 +1 @@ -Subproject commit a4e72918dff95644dc8d1de8d3d9d23c3f3ae167 +Subproject commit faeb599a19cfec8d327dba51b60d51fc369bcb9f diff --git a/src/bind.c b/src/bind.c index c3b0c74..55fab05 100644 --- a/src/bind.c +++ b/src/bind.c @@ -310,6 +310,7 @@ gt_bind(int argc, char **argv) case CTL_CONF: if (mud_set_conf(mud, &req.conf)) res.ret = errno; + res.conf = req.conf; break; case CTL_STATUS: memcpy(res.status.tun_name, tun_name, sizeof(tun_name)); // XXX diff --git a/src/common.c b/src/common.c index 3728284..149f226 100644 --- a/src/common.c +++ b/src/common.c @@ -114,3 +114,79 @@ gt_toaddr(char *str, size_t size, struct sockaddr *sa) errno = EAFNOSUPPORT; return -1; } + +int +gt_totime(char *str, size_t size, unsigned long long t) +{ + if (!str || size < 4) { + errno = EINVAL; + return -1; + } + + if (!t) { + memcpy(str, "now", 4); + return 0; + } + + struct { + unsigned long long v; + unsigned long long n; + char *name; + } u[] = { + {0, 1000, "ms"}, + {0, 60, "s"}, + {0, 60, "m"}, + {0, 24, "h"}, + {0, 0, "d"}, + }; + + size_t len = 0; + unsigned i = 0; + + while (u[i].n) { + u[i].v = t % u[i].n; + t /= u[i].n; + i++; + } + + u[i++].v = t; + + while (i--) + if (u[i].v) { + int ret = snprintf(str + len, size - len, "%llu%s", u[i].v, u[i].name); + if (ret <= 0 || (size_t)ret >= size - len) { + errno = EINVAL; + return -1; + } + len += ret; + } + + return 0; +} + +int +gt_torate(char *str, size_t size, unsigned long long r) +{ + if (!str || size < 5) { + errno = EINVAL; + return -1; + } + + unsigned k = 0; + + while (r && k < 4 && !(r % 1000)) { + r /= 1000; + k++; + } + + int ret = snprintf(str, size, "%llu%sbit%s", r, + &"\0\0k\0M\0G\0T"[k << 1], + &"s"[r <= 1]); + + if (ret <= 0 || (size_t)ret >= size) { + errno = EINVAL; + return -1; + } + + return 0; +} diff --git a/src/common.h b/src/common.h index 0eefc95..f517197 100644 --- a/src/common.h +++ b/src/common.h @@ -61,6 +61,8 @@ void gt_set_port (struct sockaddr *, uint16_t); uint16_t gt_get_port (struct sockaddr *); int gt_toaddr (char *, size_t, struct sockaddr *); +int gt_totime (char *, size_t, unsigned long long); +int gt_torate (char *, size_t, unsigned long long); int gt_list (int, char **); int gt_show (int, char **); diff --git a/src/path.c b/src/path.c index bb07f49..0b82779 100644 --- a/src/path.c +++ b/src/path.c @@ -10,6 +10,8 @@ gt_path_print(struct mud_path *path, int term) { const char *statestr = NULL; char bindstr[INET6_ADDRSTRLEN]; + char beatstr[32]; + char txstr[32], rxstr[32]; switch (path->state) { case MUD_UP: statestr = "up"; break; @@ -22,15 +24,23 @@ gt_path_print(struct mud_path *path, int term) (struct sockaddr *)&path->local_addr)) return; - printf(term ? "path %s %s losslimit %u%% beat %"PRIu64"ms " - "rate %s tx %"PRIu64" rx %"PRIu64"\n" - : "path %s %s %u %"PRIu64" %s %"PRIu64" %"PRIu64"\n", + if (gt_totime(beatstr, sizeof(beatstr), path->conf.beat / 1000)) + return; + + if (gt_torate(txstr, sizeof(txstr), path->conf.tx_max_rate * 8)) + return; + + if (gt_torate(rxstr, sizeof(rxstr), path->conf.rx_max_rate * 8)) + return; + + printf(term ? "path %s %s losslimit %u%% beat %s " + "rate %s tx %s rx %s\n" + : "path %s %s %u %s %s %s %s\n", statestr, bindstr, path->conf.loss_limit * 100U / 255U, - path->conf.beat / 1000, + beatstr, path->conf.fixed_rate ? "fixed" : "auto", - path->conf.tx_max_rate, - path->conf.rx_max_rate); + txstr, rxstr); } static int diff --git a/src/set.c b/src/set.c index 6a0daab..398e81b 100644 --- a/src/set.c +++ b/src/set.c @@ -26,7 +26,7 @@ gt_argz_tc(void *data, int argc, char **argv) } else return -1; if (data) - *(int *)data = (val << 1) | 1; + *(int *)data = val; return 1; } @@ -35,22 +35,32 @@ int gt_set(int argc, char **argv) { const char *dev = NULL; - - struct ctl_msg req = { - .type = CTL_CONF, - }, res = {0}; + unsigned long kxtimeout; + unsigned long timetolerance; + unsigned long keepalive; + int tc; struct argz pathz[] = { {"dev", "NAME", &dev, argz_str}, - {"tc", "CS|AF|EF", &req.conf.tc, gt_argz_tc}, - {"kxtimeout", "SECONDS", &req.conf.kxtimeout, argz_time}, - {"timetolerance", "SECONDS", &req.conf.timetolerance, argz_time}, - {"keepalive", "SECONDS", &req.conf.keepalive, argz_time}, + {"tc", "CS|AF|EF", &tc, gt_argz_tc}, + {"kxtimeout", "SECONDS", &kxtimeout, argz_time}, + {"timetolerance", "SECONDS", &timetolerance, argz_time}, + {"keepalive", "SECONDS", &keepalive, argz_time}, {NULL}}; if (argz(pathz, argc, argv)) return 1; + struct ctl_msg req = { + .type = CTL_CONF, + .conf = { + .tc = tc ? (tc << 1) | 1 : 0, + .kxtimeout = kxtimeout * UINT64_C(1000), + .timetolerance = timetolerance * UINT64_C(1000), + .keepalive = keepalive * UINT64_C(1000), + }, + }, res = {0}; + int fd = ctl_connect(dev); if (fd < 0) { @@ -60,6 +70,16 @@ gt_set(int argc, char **argv) int ret = ctl_reply(fd, &res, &req); + char t0[32]; + char t1[32]; + char t2[32]; + + gt_totime(t0, sizeof(t0), res.conf.kxtimeout / 1000); + gt_totime(t1, sizeof(t1), res.conf.timetolerance / 1000); + gt_totime(t2, sizeof(t2), res.conf.keepalive / 1000); + + printf("set kxtimeout %s timetolerance %s keepalive %s tc %i\n", t0, t1, t2, res.conf.tc); + if (ret) perror("set");