diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/ip/gping.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/ip/gping.c')
-rwxr-xr-x | sys/src/cmd/ip/gping.c | 1063 |
1 files changed, 1063 insertions, 0 deletions
diff --git a/sys/src/cmd/ip/gping.c b/sys/src/cmd/ip/gping.c new file mode 100755 index 000000000..194f1f556 --- /dev/null +++ b/sys/src/cmd/ip/gping.c @@ -0,0 +1,1063 @@ +#include <u.h> +#include <libc.h> +#include <ctype.h> +#include <auth.h> +#include <fcall.h> +#include <draw.h> +#include <event.h> +#include <ip.h> +#include "icmp.h" + +#define MAXNUM 8 /* maximum number of numbers on data line */ + +typedef struct Graph Graph; +typedef struct Machine Machine; +typedef struct Req Req; + +enum { + Gmsglen = 16, +}; + +struct Graph +{ + int colindex; + Rectangle r; + long *data; + int ndata; + char *label; + void (*newvalue)(Machine*, long*, long*, long*); + void (*update)(Graph*, long, long, long); + Machine *mach; + int overflow; + Image *overtmp; + int overtmplen; + char msg[Gmsglen]; + int cursor; + int vmax; +}; + +enum +{ + MSGLEN = 64, + + Rttmax = 50, +}; + +struct Req +{ + int seq; /* sequence number */ + vlong time; /* time sent */ +// int rtt; + Req *next; +}; + +struct Machine +{ + Lock; + char *name; + int pingfd; + int nproc; + + int rttmsgs; + ulong rttsum; + ulong lastrtt; + + int lostmsgs; + int rcvdmsgs; + ulong lostavg; + int unreachable; + + ushort seq; + Req *first; + Req *last; + Req *rcvd; + + char buf[1024]; + char *bufp; + char *ebufp; +}; + +enum +{ + Ncolor = 6, + Ysqueeze = 2, /* vertical squeezing of label text */ + Labspace = 2, /* room around label */ + Dot = 2, /* height of dot */ + Opwid = 5, /* strlen("add ") or strlen("drop ") */ + NPROC = 128, + NMACH = 32, +}; + +enum Menu2 +{ + Mrtt, + Mlost, + Nmenu2, +}; + +char *menu2str[Nmenu2+1] = { + "add sec rtt", + "add % lost ", + nil, +}; + + +void rttval(Machine*, long*, long*, long*); +void lostval(Machine*, long*, long*, long*); + +Menu menu2 = {menu2str, nil}; +int present[Nmenu2]; +void (*newvaluefn[Nmenu2])(Machine*, long*, long*, long*) = { + rttval, + lostval, +}; + +Image *cols[Ncolor][3]; +Graph *graph; +Machine mach[NMACH]; +Font *mediumfont; +int pids[NPROC]; +int npid; +int parity; /* toggled to avoid patterns in textured background */ +int nmach; +int ngraph; /* totaly number is ngraph*nmach */ +long starttime; +int pinginterval; + +void dropgraph(int); +void addgraph(int); +void startproc(void (*)(void*), void*); +void resize(void); +long rttscale(long); +int which2index(int); +int index2which(int); + +void +killall(char *s) +{ + int i, pid; + + pid = getpid(); + for(i=0; i<NPROC; i++) + if(pids[i] && pids[i]!=pid) + postnote(PNPROC, pids[i], "kill"); + exits(s); +} + +void* +emalloc(ulong sz) +{ + void *v; + v = malloc(sz); + if(v == nil) { + fprint(2, "%s: out of memory allocating %ld: %r\n", argv0, sz); + killall("mem"); + } + memset(v, 0, sz); + return v; +} + +void* +erealloc(void *v, ulong sz) +{ + v = realloc(v, sz); + if(v == nil) { + fprint(2, "%s: out of memory reallocating %ld: %r\n", argv0, sz); + killall("mem"); + } + return v; +} + +char* +estrdup(char *s) +{ + char *t; + if((t = strdup(s)) == nil) { + fprint(2, "%s: out of memory in strdup(%.10s): %r\n", argv0, s); + killall("mem"); + } + return t; +} + +void +mkcol(int i, int c0, int c1, int c2) +{ + cols[i][0] = allocimagemix(display, c0, DWhite); + cols[i][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c1); + cols[i][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c2); +} + +void +colinit(void) +{ + mediumfont = openfont(display, "/lib/font/bit/pelm/latin1.8.font"); + if(mediumfont == nil) + mediumfont = font; + + /* Peach */ + mkcol(0, 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF); + /* Aqua */ + mkcol(1, DPalebluegreen, DPalegreygreen, DPurpleblue); + /* Yellow */ + mkcol(2, DPaleyellow, DDarkyellow, DYellowgreen); + /* Green */ + mkcol(3, DPalegreen, DMedgreen, DDarkgreen); + /* Blue */ + mkcol(4, 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF); + /* Grey */ + cols[5][0] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xEEEEEEFF); + cols[5][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCCCCCCFF); + cols[5][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x888888FF); +} + +int +loadbuf(Machine *m, int *fd) +{ + int n; + + + if(*fd < 0) + return 0; + seek(*fd, 0, 0); + n = read(*fd, m->buf, sizeof m->buf); + if(n <= 0){ + close(*fd); + *fd = -1; + return 0; + } + m->bufp = m->buf; + m->ebufp = m->buf+n; + return 1; +} + +void +label(Point p, int dy, char *text) +{ + char *s; + Rune r[2]; + int w, maxw, maxy; + + p.x += Labspace; + maxy = p.y+dy; + maxw = 0; + r[1] = '\0'; + for(s=text; *s; ){ + if(p.y+mediumfont->height-Ysqueeze > maxy) + break; + w = chartorune(r, s); + s += w; + w = runestringwidth(mediumfont, r); + if(w > maxw) + maxw = w; + runestring(screen, p, display->black, ZP, mediumfont, r); + p.y += mediumfont->height-Ysqueeze; + } +} + +void +hashmark(Point p, int dy, long v, long vmax, char *label) +{ + int y; + int x; + + x = p.x + Labspace; + y = p.y + (dy*(vmax-v))/vmax; + draw(screen, Rect(p.x, y-1, p.x+Labspace, y+1), display->black, nil, ZP); + if(dy > 5*mediumfont->height) + string(screen, Pt(x, y-mediumfont->height/2), + display->black, ZP, mediumfont, label); +} + +void +hashmarks(Point p, int dy, int which) +{ + switch(index2which(which)){ + case Mrtt: + hashmark(p, dy, rttscale(1000000), Rttmax, "1."); + hashmark(p, dy, rttscale(100000), Rttmax, "0.1"); + hashmark(p, dy, rttscale(10000), Rttmax, "0.01"); + hashmark(p, dy, rttscale(1000), Rttmax, "0.001"); + break; + case Mlost: + hashmark(p, dy, 75, 100, " 75%"); + hashmark(p, dy, 50, 100, " 50%"); + hashmark(p, dy, 25, 100, " 25%"); + break; + } +} + +Point +paritypt(int x) +{ + return Pt(x+parity, 0); +} + +Point +datapoint(Graph *g, int x, long v, long vmax) +{ + Point p; + + p.x = x; + p.y = g->r.max.y - Dy(g->r)*v/vmax - Dot; + if(p.y < g->r.min.y) + p.y = g->r.min.y; + if(p.y > g->r.max.y-Dot) + p.y = g->r.max.y-Dot; + return p; +} + +void +drawdatum(Graph *g, int x, long prev, long v, long vmax) +{ + int c; + Point p, q; + + c = g->colindex; + p = datapoint(g, x, v, vmax); + q = datapoint(g, x, prev, vmax); + if(p.y < q.y){ + draw(screen, Rect(p.x, g->r.min.y, p.x+1, p.y), cols[c][0], nil, paritypt(p.x)); + draw(screen, Rect(p.x, p.y, p.x+1, q.y+Dot), cols[c][2], nil, ZP); + draw(screen, Rect(p.x, q.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP); + }else{ + draw(screen, Rect(p.x, g->r.min.y, p.x+1, q.y), cols[c][0], nil, paritypt(p.x)); + draw(screen, Rect(p.x, q.y, p.x+1, p.y+Dot), cols[c][2], nil, ZP); + draw(screen, Rect(p.x, p.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP); + } + g->vmax = vmax; +} + +void +drawmark(Graph *g, int x) +{ + int c; + + c = (g->colindex+1)&Ncolor; + draw(screen, Rect(x, g->r.min.y, x+1, g->r.max.y), cols[c][2], nil, ZP); +} + +void +redraw(Graph *g, int vmax) +{ + int i, c; + + c = g->colindex; + draw(screen, g->r, cols[c][0], nil, paritypt(g->r.min.x)); + for(i=1; i<Dx(g->r); i++) + drawdatum(g, g->r.max.x-i, g->data[i-1], g->data[i], vmax); + drawdatum(g, g->r.min.x, g->data[i], g->data[i], vmax); +} + +void +clearmsg(Graph *g) +{ + if(g->overtmp != nil) + draw(screen, g->overtmp->r, g->overtmp, nil, g->overtmp->r.min); + g->overflow = 0; +} + +void +drawmsg(Graph *g, char *msg) +{ + if(g->overtmp == nil) + return; + + /* save previous contents of screen */ + draw(g->overtmp, g->overtmp->r, screen, nil, g->overtmp->r.min); + + /* draw message */ + if(strlen(msg) > g->overtmplen) + msg[g->overtmplen] = 0; + string(screen, g->overtmp->r.min, display->black, ZP, mediumfont, msg); +} + +void +clearcursor(Graph *g) +{ + int x; + long prev; + + if(g->overtmp == nil) + return; + + if(g->cursor > 0 && g->cursor < g->ndata){ + x = g->r.max.x - g->cursor; + prev = 0; + if(g->cursor > 0) + prev = g->data[g->cursor-1]; + drawdatum(g, x, prev, g->data[g->cursor], g->vmax); + g->cursor = -1; + } +} + +void +drawcursor(Graph *g, int x) +{ + if(g->overtmp == nil) + return; + + draw(screen, Rect(x, g->r.min.y, x+1, g->r.max.y), cols[g->colindex][2], nil, ZP); +} + +void +update1(Graph *g, long v, long vmax, long mark) +{ + char buf[Gmsglen]; + + /* put back screen value sans message */ + if(g->overflow || *g->msg){ + clearmsg(g); + g->overflow = 0; + } + + draw(screen, g->r, screen, nil, Pt(g->r.min.x+1, g->r.min.y)); + drawdatum(g, g->r.max.x-1, g->data[0], v, vmax); + if(mark) + drawmark(g, g->r.max.x-1); + memmove(g->data+1, g->data, (g->ndata-1)*sizeof(g->data[0])); + g->data[0] = v; + if(v>vmax){ + g->overflow = 1; + sprint(buf, "%ld", v); + drawmsg(g, buf); + } else if(*g->msg) + drawmsg(g, g->msg); + + if(g->cursor >= 0){ + g->cursor++; + if(g->cursor >= g->ndata){ + g->cursor = -1; + if(*g->msg){ + clearmsg(g); + *g->msg = 0; + } + } + } + +} + +void +pinglost(Machine *m, Req*) +{ + m->lostmsgs++; +} + +void +pingreply(Machine *m, Req *r) +{ + ulong x; + + x = r->time/1000LL; + m->rttsum += x; + m->rcvdmsgs++; + m->rttmsgs++; +} + + +void +pingclean(Machine *m, ushort seq, vlong now, int) +{ + Req **l, *r; + vlong x, y; + + y = 10LL*1000000000LL; + for(l = &m->first; *l; ){ + r = *l; + x = now - r->time; + if(x > y || r->seq == seq){ + *l = r->next; + r->time = x; + if(r->seq != seq) + pinglost(m, r); + else + pingreply(m, r); + free(r); + } else + l = &(r->next); + } +} + +/* IPv4 only */ +void +pingsend(Machine *m) +{ + int i; + char buf[128], err[ERRMAX]; + Icmphdr *ip; + Req *r; + + ip = (Icmphdr *)(buf + IPV4HDR_LEN); + memset(buf, 0, sizeof buf); + r = malloc(sizeof *r); + if(r == nil) + return; + + for(i = 32; i < MSGLEN; i++) + buf[i] = i; + ip->type = EchoRequest; + ip->code = 0; + ip->seq[0] = m->seq; + ip->seq[1] = m->seq>>8; + r->seq = m->seq; + r->next = nil; + lock(m); + pingclean(m, -1, nsec(), 0); + if(m->first == nil) + m->first = r; + else + m->last->next = r; + m->last = r; + r->time = nsec(); + unlock(m); + if(write(m->pingfd, buf, MSGLEN) < MSGLEN){ + errstr(err, sizeof err); + if(strstr(err, "unreach")||strstr(err, "exceed")) + m->unreachable++; + } + m->seq++; +} + +/* IPv4 only */ +void +pingrcv(void *arg) +{ + int i, n, fd; + uchar buf[512]; + ushort x; + vlong now; + Icmphdr *ip; + Ip4hdr *ip4; + Machine *m = arg; + + ip4 = (Ip4hdr *)buf; + ip = (Icmphdr *)(buf + IPV4HDR_LEN); + fd = dup(m->pingfd, -1); + for(;;){ + n = read(fd, buf, sizeof(buf)); + now = nsec(); + if(n <= 0) + continue; + if(n < MSGLEN){ + print("bad len %d/%d\n", n, MSGLEN); + continue; + } + for(i = 32; i < MSGLEN; i++) + if(buf[i] != (i&0xff)) + continue; + x = (ip->seq[1]<<8) | ip->seq[0]; + if(ip->type != EchoReply || ip->code != 0) + continue; + lock(m); + pingclean(m, x, now, ip4->ttl); + unlock(m); + } +} + +void +initmach(Machine *m, char *name) +{ + char *p; + + srand(time(0)); + p = strchr(name, '!'); + if(p){ + p++; + m->name = estrdup(p+1); + }else + p = name; + + m->name = estrdup(p); + m->nproc = 1; + m->pingfd = dial(netmkaddr(m->name, "icmp", "1"), 0, 0, 0); + if(m->pingfd < 0) + sysfatal("dialing %s: %r", m->name); + startproc(pingrcv, m); +} + +long +rttscale(long x) +{ + if(x == 0) + return 0; + x = 10.0*log10(x) - 20.0; + if(x < 0) + x = 0; + return x; +} + +double +rttunscale(long x) +{ + double dx; + + x += 20; + dx = x; + return pow(10.0, dx/10.0); +} + +void +rttval(Machine *m, long *v, long *vmax, long *mark) +{ + ulong x; + + if(m->rttmsgs == 0){ + x = m->lastrtt; + } else { + x = m->rttsum/m->rttmsgs; + m->rttsum = m->rttmsgs = 0; + m->lastrtt = x; + } + + *v = rttscale(x); + *vmax = Rttmax; + *mark = 0; +} + +void +lostval(Machine *m, long *v, long *vmax, long *mark) +{ + ulong x; + + if(m->rcvdmsgs+m->lostmsgs > 0) + x = (m->lostavg>>1) + (((m->lostmsgs*100)/(m->lostmsgs + m->rcvdmsgs))>>1); + else + x = m->lostavg; + m->lostavg = x; + m->lostmsgs = m->rcvdmsgs = 0; + + if(m->unreachable){ + m->unreachable = 0; + *mark = 100; + } else + *mark = 0; + + *v = x; + *vmax = 100; +} + +jmp_buf catchalarm; + +void +alarmed(void *a, char *s) +{ + if(strcmp(s, "alarm") == 0) + notejmp(a, catchalarm, 1); + noted(NDFLT); +} + +void +usage(void) +{ + fprint(2, "usage: %s machine [machine...]\n", argv0); + exits("usage"); +} + +void +addgraph(int n) +{ + Graph *g, *ograph; + int i, j; + static int nadd; + + if(n > nelem(menu2str)) + abort(); + /* avoid two adjacent graphs of same color */ + if(ngraph>0 && graph[ngraph-1].colindex==nadd%Ncolor) + nadd++; + ograph = graph; + graph = emalloc(nmach*(ngraph+1)*sizeof(Graph)); + for(i=0; i<nmach; i++) + for(j=0; j<ngraph; j++) + graph[i*(ngraph+1)+j] = ograph[i*ngraph+j]; + free(ograph); + ngraph++; + for(i=0; i<nmach; i++){ + g = &graph[i*ngraph+(ngraph-1)]; + memset(g, 0, sizeof(Graph)); + g->label = menu2str[n]+Opwid; + g->newvalue = newvaluefn[n]; + g->update = update1; /* no other update functions yet */ + g->mach = &mach[i]; + g->colindex = nadd%Ncolor; + } + present[n] = 1; + nadd++; +} + +int +which2index(int which) +{ + int i, n; + + n = -1; + for(i=0; i<ngraph; i++){ + if(strcmp(menu2str[which]+Opwid, graph[i].label) == 0){ + n = i; + break; + } + } + if(n < 0){ + fprint(2, "%s: internal error can't drop graph\n", argv0); + killall("error"); + } + return n; +} + +int +index2which(int index) +{ + int i, n; + + n = -1; + for(i=0; i<Nmenu2; i++){ + if(strcmp(menu2str[i]+Opwid, graph[index].label) == 0){ + n = i; + break; + } + } + if(n < 0){ + fprint(2, "%s: internal error can't identify graph\n", argv0); + killall("error"); + } + return n; +} + +void +dropgraph(int which) +{ + Graph *ograph; + int i, j, n; + + if(which > nelem(menu2str)) + abort(); + /* convert n to index in graph table */ + n = which2index(which); + ograph = graph; + graph = emalloc(nmach*(ngraph-1)*sizeof(Graph)); + for(i=0; i<nmach; i++){ + for(j=0; j<n; j++) + graph[i*(ngraph-1)+j] = ograph[i*ngraph+j]; + free(ograph[i*ngraph+j].data); + freeimage(ograph[i*ngraph+j].overtmp); + for(j++; j<ngraph; j++) + graph[i*(ngraph-1)+j-1] = ograph[i*ngraph+j]; + } + free(ograph); + ngraph--; + present[which] = 0; +} + +void +addmachine(char *name) +{ + if(ngraph > 0){ + fprint(2, "%s: internal error: ngraph>0 in addmachine()\n", argv0); + usage(); + } + if(nmach == NMACH) + sysfatal("too many machines"); + initmach(&mach[nmach++], name); +} + + +void +resize(void) +{ + int i, j, n, startx, starty, x, y, dx, dy, hashdx, ondata; + Graph *g; + Rectangle machr, r; + long v, vmax, mark; + char buf[128]; + + draw(screen, screen->r, display->white, nil, ZP); + + /* label left edge */ + x = screen->r.min.x; + y = screen->r.min.y + Labspace+mediumfont->height+Labspace; + dy = (screen->r.max.y - y)/ngraph; + dx = Labspace+stringwidth(mediumfont, "0")+Labspace; + startx = x+dx+1; + starty = y; + for(i=0; i<ngraph; i++,y+=dy){ + draw(screen, Rect(x, y-1, screen->r.max.x, y), display->black, nil, ZP); + draw(screen, Rect(x, y, x+dx, screen->r.max.y), cols[graph[i].colindex][0], nil, paritypt(x)); + label(Pt(x, y), dy, graph[i].label); + draw(screen, Rect(x+dx, y, x+dx+1, screen->r.max.y), cols[graph[i].colindex][2], nil, ZP); + } + + /* label right edge */ + dx = Labspace+stringwidth(mediumfont, "0.001")+Labspace; + hashdx = dx; + x = screen->r.max.x - dx; + y = screen->r.min.y + Labspace+mediumfont->height+Labspace; + for(i=0; i<ngraph; i++,y+=dy){ + draw(screen, Rect(x, y-1, screen->r.max.x, y), display->black, nil, ZP); + draw(screen, Rect(x, y, x+dx, screen->r.max.y), cols[graph[i].colindex][0], nil, paritypt(x)); + hashmarks(Pt(x, y), dy, i); + draw(screen, Rect(x+dx, y, x+dx+1, screen->r.max.y), cols[graph[i].colindex][2], nil, ZP); + } + + /* label top edge */ + dx = (screen->r.max.x - dx - startx)/nmach; + for(x=startx, i=0; i<nmach; i++,x+=dx){ + draw(screen, Rect(x-1, starty-1, x, screen->r.max.y), display->black, nil, ZP); + j = dx/stringwidth(mediumfont, "0"); + n = mach[i].nproc; + if(n>1 && j>=1+3+(n>10)+(n>100)){ /* first char of name + (n) */ + j -= 3+(n>10)+(n>100); + if(j <= 0) + j = 1; + snprint(buf, sizeof buf, "%.*s(%d)", j, mach[i].name, n); + }else + snprint(buf, sizeof buf, "%.*s", j, mach[i].name); + string(screen, Pt(x+Labspace, screen->r.min.y + Labspace), display->black, ZP, + mediumfont, buf); + } + /* draw last vertical line */ + draw(screen, + Rect(screen->r.max.x-hashdx-1, starty-1, screen->r.max.x-hashdx, screen->r.max.y), + display->black, nil, ZP); + + /* create graphs */ + for(i=0; i<nmach; i++){ + machr = Rect(startx+i*dx, starty, screen->r.max.x, screen->r.max.y); + if(i < nmach-1) + machr.max.x = startx+(i+1)*dx - 1; + else + machr.max.x = screen->r.max.x - hashdx - 1; + y = starty; + for(j=0; j<ngraph; j++, y+=dy){ + g = &graph[i*ngraph+j]; + /* allocate data */ + ondata = g->ndata; + g->ndata = Dx(machr)+1; /* may be too many if label will be drawn here; so what? */ + g->data = erealloc(g->data, g->ndata*sizeof(long)); + if(g->ndata > ondata) + memset(g->data+ondata, 0, (g->ndata-ondata)*sizeof(long)); + /* set geometry */ + g->r = machr; + g->r.min.y = y; + g->r.max.y = y+dy - 1; + if(j == ngraph-1) + g->r.max.y = screen->r.max.y; + draw(screen, g->r, cols[g->colindex][0], nil, paritypt(g->r.min.x)); + g->overflow = 0; + *g->msg = 0; + freeimage(g->overtmp); + g->overtmp = nil; + g->overtmplen = 0; + r = g->r; + r.max.y = r.min.y+mediumfont->height; + n = (g->r.max.x - r.min.x)/stringwidth(mediumfont, "9"); + if(n > 4){ + if(n > Gmsglen) + n = Gmsglen; + r.max.x = r.min.x+stringwidth(mediumfont, "9")*n; + g->overtmplen = n; + g->overtmp = allocimage(display, r, screen->chan, 0, -1); + } + g->newvalue(g->mach, &v, &vmax, &mark); + redraw(g, vmax); + } + } + + flushimage(display, 1); +} + +void +eresized(int new) +{ + lockdisplay(display); + if(new && getwindow(display, Refnone) < 0) { + fprint(2, "%s: can't reattach to window\n", argv0); + killall("reattach"); + } + resize(); + unlockdisplay(display); +} + +void +dobutton2(Mouse *m) +{ + int i; + + for(i=0; i<Nmenu2; i++) + if(present[i]) + memmove(menu2str[i], "drop ", Opwid); + else + memmove(menu2str[i], "add ", Opwid); + i = emenuhit(3, m, &menu2); + if(i >= 0){ + if(!present[i]) + addgraph(i); + else if(ngraph > 1) + dropgraph(i); + resize(); + } +} + +void +dobutton1(Mouse *m) +{ + int i, n, dx, dt; + Graph *g; + char *e; + double f; + + for(i = 0; i < ngraph*nmach; i++){ + if(ptinrect(m->xy, graph[i].r)) + break; + } + if(i == ngraph*nmach) + return; + + g = &graph[i]; + if(g->overtmp == nil) + return; + + /* clear any previous message and cursor */ + if(g->overflow || *g->msg){ + clearmsg(g); + *g->msg = 0; + clearcursor(g); + } + + dx = g->r.max.x - m->xy.x; + g->cursor = dx; + dt = dx*pinginterval; + e = &g->msg[sizeof(g->msg)]; + seprint(g->msg, e, "%s", ctime(starttime-dt/1000)+11); + g->msg[8] = 0; + n = 8; + + switch(index2which(i)){ + case Mrtt: + f = rttunscale(g->data[dx]); + seprint(g->msg+n, e, " %3.3g", f/1000000); + break; + case Mlost: + seprint(g->msg+n, e, " %ld%%", g->data[dx]); + break; + } + + drawmsg(g, g->msg); + drawcursor(g, m->xy.x); +} + +void +mouseproc(void*) +{ + Mouse mouse; + + for(;;){ + mouse = emouse(); + if(mouse.buttons == 4){ + lockdisplay(display); + dobutton2(&mouse); + unlockdisplay(display); + } else if(mouse.buttons == 1){ + lockdisplay(display); + dobutton1(&mouse); + unlockdisplay(display); + } + } +} + +void +startproc(void (*f)(void*), void *arg) +{ + int pid; + + switch(pid = rfork(RFPROC|RFMEM|RFNOWAIT)){ + case -1: + fprint(2, "%s: fork failed: %r\n", argv0); + killall("fork failed"); + case 0: + f(arg); + killall("process died"); + exits(nil); + } + pids[npid++] = pid; +} + +void +main(int argc, char *argv[]) +{ + int i, j; + long v, vmax, mark; + char flags[10], *f, *p; + + fmtinstall('V', eipfmt); + + f = flags; + pinginterval = 5000; /* 5 seconds */ + ARGBEGIN{ + case 'i': + p = ARGF(); + if(p == nil) + usage(); + pinginterval = atoi(p); + break; + default: + if(f - flags >= sizeof(flags)-1) + usage(); + *f++ = ARGC(); + break; + }ARGEND + *f = 0; + + for(i=0; i<argc; i++) + addmachine(argv[i]); + + for(f = flags; *f; f++) + switch(*f){ + case 'l': + addgraph(Mlost); + break; + case 'r': + addgraph(Mrtt); + break; + } + + if(nmach == 0) + usage(); + + if(ngraph == 0) + addgraph(Mrtt); + + for(i=0; i<nmach; i++) + for(j=0; j<ngraph; j++) + graph[i*ngraph+j].mach = &mach[i]; + + if(initdraw(nil, nil, argv0) < 0){ + fprint(2, "%s: initdraw failed: %r\n", argv0); + exits("initdraw"); + } + colinit(); + einit(Emouse); + notify(nil); + startproc(mouseproc, 0); + display->locking = 1; /* tell library we're using the display lock */ + + resize(); + + starttime = time(0); + + unlockdisplay(display); /* display is still locked from initdraw() */ + for(j = 0; ; j++){ + lockdisplay(display); + if(j == nmach){ + parity = 1-parity; + j = 0; + for(i=0; i<nmach*ngraph; i++){ + graph[i].newvalue(graph[i].mach, &v, &vmax, &mark); + graph[i].update(&graph[i], v, vmax, mark); + } + starttime = time(0); + } + flushimage(display, 1); + unlockdisplay(display); + pingsend(&mach[j%nmach]); + sleep(pinginterval/nmach); + } +} |