Skip to content

Instantly share code, notes, and snippets.

@darkk

darkk/Makefile

Last active Aug 7, 2016
Embed
What would you like to do?
latency on PPPoA ADSL Annex A on using Lantiq

Toolbox for the mailing list thread [LEDE-DEV] [OpenWrt-Devel] latency on PPPoA ADSL Annex A on using Lantiq.

echosrv -- trivial TCP and UDP echo-server that timestamps outgoing packet with gettimeofday() if it gets packet with known magic header

mturtt -- TCP and UDP echo-client sending timestamped and HMAC-ed garbage of various sizes to echosrv using host's TCP/IP stack

trace-2.* -- dumps recorded at adsl-router when mturtt --host 2.30.18.250 --port 4242 --count 4 --size 50 --tcp was running at 139.162.172.21, TZ=UTC

#define _GNU_SOURCE // for splice()
#include <arpa/inet.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/sendfile.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
void do_tcp(int port) {
int srv = socket(AF_INET, SOCK_STREAM, 0);
if (srv == -1)
err(EXIT_FAILURE, "socket");
const int on = 1;
const int off = 0;
if (setsockopt(srv, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0)
err(EXIT_FAILURE, "setsockopt(SO_REUSEADDR)");
if (setsockopt(srv, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) != 0)
err(EXIT_FAILURE, "setsockopt(srv, TCP_NODELAY)");
struct sockaddr_in bindaddr = {
.sin_family = AF_INET,
};
bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);
bindaddr.sin_port = htons(port);
if (bind(srv, (struct sockaddr*)&bindaddr, sizeof(bindaddr)) != 0)
err(EXIT_FAILURE, "bind");
if (listen(srv, 1) != 0)
err(EXIT_FAILURE, "listen");
struct sockaddr_in cliaddr;
socklen_t cliaddrlen = sizeof(cliaddr);
int client = accept(srv, (struct sockaddr*)&cliaddr, &cliaddrlen);
if (client == -1)
err(EXIT_FAILURE, "client");
printf("Got client from %s:%d\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
if (setsockopt(client, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) != 0)
err(EXIT_FAILURE, "setsockopt(client, TCP_NODELAY)");
close(srv);
for (;;) {
static const char *magic = "MTU\0RTT\0""\0\0\0\0""\0\0\0\0";
const ssize_t mlen = 16, moff = 8;
char buf[14600*2]; // RFC6928 initcwnd * 2
const ssize_t got = recv(client, buf, sizeof(buf), 0);
if (got == -1)
err(EXIT_FAILURE, "recv");
else if (got == 0)
errx(EXIT_SUCCESS, "EOF from client");
else if (got > mlen && memcmp(buf, magic, mlen) == 0) {
struct timeval tv;
if (gettimeofday(&tv, NULL) != 0)
err(EXIT_FAILURE, "gettimeofday");
*(uint32_t*)(buf+moff) = htonl(tv.tv_sec);
*(uint32_t*)(buf+moff+4) = htonl(tv.tv_usec);
}
usleep(5000);
if (setsockopt(client, IPPROTO_TCP, TCP_CORK, &on, sizeof(on)) != 0)
err(EXIT_FAILURE, "setsockopt(client, TCP_CORK, on)");
const ssize_t sent = send(client, buf, got, 0);
if (sent != got)
err(EXIT_FAILURE, "send: sent (%zd) != got (%zd)", sent, got);
if (setsockopt(client, IPPROTO_TCP, TCP_CORK, &off, sizeof(off)) != 0)
err(EXIT_FAILURE, "setsockopt(client, TCP_CORK, off)");
}
}
void do_udp(int port) {
int srv = socket(AF_INET, SOCK_DGRAM, 0);
if (srv == -1)
err(EXIT_FAILURE, "socket");
const int on = 1;
if (setsockopt(srv, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0)
err(EXIT_FAILURE, "setsockopt(SO_REUSEADDR)");
struct sockaddr_in bindaddr = {
.sin_family = AF_INET,
};
bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);
bindaddr.sin_port = htons(port);
if (bind(srv, (struct sockaddr*)&bindaddr, sizeof(bindaddr)) != 0)
err(EXIT_FAILURE, "bind");
for (;;) {
struct sockaddr_in cliaddr;
socklen_t cliaddrlen = sizeof(cliaddr);
static const char *magic = "MTU\0RTT\0""\0\0\0\0""\0\0\0\0";
const ssize_t mlen = 16, moff = 8;
char buf[0x20000]; // ui16*2
const ssize_t got = recvfrom(srv, buf, sizeof(buf), 0, (struct sockaddr*)&cliaddr, &cliaddrlen);
if (got == -1)
err(EXIT_FAILURE, "recv");
else if (got == 0)
errx(EXIT_SUCCESS, "EOF from client");
else if (got > mlen && memcmp(buf, magic, mlen) == 0) {
struct timeval tv;
if (gettimeofday(&tv, NULL) != 0)
err(EXIT_FAILURE, "gettimeofday");
*(uint32_t*)(buf+moff) = htonl(tv.tv_sec);
*(uint32_t*)(buf+moff+4) = htonl(tv.tv_usec);
const ssize_t sent = sendto(srv, buf, got, 0, (struct sockaddr*)&cliaddr, cliaddrlen);
if (sent != got)
err(EXIT_FAILURE, "send: sent (%zd) != got (%zd)", sent, got);
} else if (got <= 50) {
const ssize_t sent = sendto(srv, buf, got, 0, (struct sockaddr*)&cliaddr, cliaddrlen);
if (sent != got)
err(EXIT_FAILURE, "send: sent (%zd) != got (%zd)", sent, got);
} else {
errx(EXIT_FAILURE, "Got strange packet %zd bytes long, die to avoid flood", got);
}
}
}
int main(int argc, const char* argv[]) {
if (argc != 3)
errx(EXIT_SUCCESS, "Usage: %s <tcp|udp> port", argv[0]);
int port = atoi(argv[2]);
if (port <= 0 || 0xffff < port)
errx(EXIT_SUCCESS, "bad port value <%s>", argv[2]);
if (signal(SIGPIPE, SIG_IGN) != 0)
err(EXIT_FAILURE, "signal");
if (strcmp(argv[1], "tcp") == 0) {
do_tcp(port);
} else if (strcmp(argv[1], "udp") == 0) {
do_udp(port);
} else {
errx(EXIT_SUCCESS, "bad protocol <%s>", argv[1]);
}
return EXIT_SUCCESS;
}
SHELL=/bin/bash
OUT=echosrv.x86_64 echosrv.mips
CFLAGS=-Wall -Wextra -Wpedantic -O2
.PHONY: all clean upload
all: $(OUT)
clean:
rm -f $(OUT)
echosrv.x86_64: echosrv.c
gcc $(CFLAGS) $^ -o $@ && strip $@
echosrv.mips: echosrv.c
mips-openwrt-linux-gcc $(CFLAGS) $^ -o $@ && mips-openwrt-linux-strip $@
#!/usr/bin/env python
import argparse
import contextlib
import functools
import hashlib
import hmac
import os
import random
import socket
import struct
import sys
import time
def getrandstr(n):
s = ''
while len(s) < n:
s += struct.pack('Q', random.getrandbits(64))
return s[:n]
class Payload(object):
MAGIC = 'MTU\0RTT\0'
SRV = struct.Struct('>II')
HEADER = struct.Struct('>IIIIH')
HASH = hashlib.md5 # good enough to catch bit errors
DIGEST_SIZE = HASH().digest_size
MINSIZE = len(MAGIC) + SRV.size + HEADER.size + DIGEST_SIZE
def __init__(self):
self.nonce = random.randint(0, 2**32-1)
self.seq = 0
self.key = os.urandom(self.DIGEST_SIZE)
def gen(self, sz):
if sz < self.MINSIZE:
raise RuntimeError('Header + HMAC are longer then requested size', self.MINSIZE, sz)
self.seq += 1
now = time.time()
sec, usec = int(now), int((now - int(now))*1000000)
pkt = self.MAGIC + self.SRV.pack(0, 0) + self.HEADER.pack(self.nonce, self.seq, sec, usec, sz)
garbage = sz - len(pkt) - self.DIGEST_SIZE
if garbage > 0:
pkt += getrandstr(garbage)
pkt += hmac.HMAC(key=self.key, msg=pkt, digestmod=self.HASH).digest()
assert len(pkt) == sz
return pkt
def rtt(self, pkt, now=None):
if now is None:
now = time.time()
if len(pkt) < self.MINSIZE:
raise RuntimeError('Truncated packet', self.MINSIZE, len(pkt))
msg = pkt[:len(self.MAGIC)] + self.SRV.pack(0, 0) + pkt[len(self.MAGIC)+self.SRV.size:-self.DIGEST_SIZE]
sign = pkt[-self.DIGEST_SIZE:]
good = hmac.HMAC(key=self.key, msg=msg, digestmod=self.HASH).digest()
if not hmac.compare_digest(sign, good):
raise RuntimeError('BAD HMAC, someone is tricking you')
if not pkt.startswith(self.MAGIC):
raise RuntimeError('BAD MAGIC')
sec_srv, usec_srv = self.SRV.unpack_from(pkt, offset=len(self.MAGIC))
nonce, seq, sec_me, usec_me, sz = self.HEADER.unpack_from(pkt, offset=len(self.MAGIC)+self.SRV.size)
if nonce != self.nonce:
raise RuntimeError('BAD nonce', self.nonce, nonce)
if sz != len(pkt):
raise RuntimeError('BAD size', len(pkt), sz)
begin = sec_me + usec_me * 1e-6
srv = sec_srv + usec_srv * 1e-6
return (seq, now - begin, srv - begin, now - srv)
def tcpv4():
return socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def rw_echo_server(port): # because of NAT
with contextlib.closing(tcpv4()) as srv:
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind(('0.0.0.0', port))
srv.listen(1)
fd, ai = srv.accept()
print 'Got client from', repr(ai)
return fd
def rw_echo_client(host, port):
fd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
fd.connect((host, port))
return fd
def rw_echo_udp(host, port):
fd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
fd.connect((host, port))
return fd
def recvall(fd, sz):
buf = []
while True:
got = sum((len(_) for _ in buf), 0)
if got == sz:
return ''.join(buf)
assert got < sz
pkt = fd.recv(sz - got)
if len(pkt):
buf.append(pkt)
else:
raise RuntimeError('Got EOF')
def main():
dat = Payload()
p = argparse.ArgumentParser(description='Poor-man L4 ping')
group = p.add_mutually_exclusive_group()
group.add_argument('--tcp', action='store_true', help='use TCP (default)')
group.add_argument('--udp', action='store_true', help='use UDP')
p.add_argument('--delay', type=float, default=0)
p.add_argument('--timeout', type=float, default=None)
p.add_argument('--host', type=str, default=None)
p.add_argument('--port', type=int, default=7)
p.add_argument('-s', '--size', nargs='+', type=int, default=[dat.MINSIZE], help='TCP payload size [%(default)s]')
p.add_argument('-c', '--count', type=int, default=20, help='pings per payload size [%(default)s]')
o = p.parse_args()
for sz in o.size:
if sz < dat.MINSIZE:
print >>sys.stderr, 'No server-side RTT for packets less then', dat.MINSIZE
break
if not o.tcp and not o.udp:
o.tcp = True
if not o.host and o.tcp:
gen = functools.partial(rw_echo_server, o.port)
elif o.host and o.tcp:
gen = functools.partial(rw_echo_client, o.host, o.port)
elif o.host and o.udp:
gen = functools.partial(rw_echo_udp, o.host, o.port)
NAN = float('nan')
with contextlib.closing(gen()) as fd:
if o.tcp:
fd.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
fd.settimeout(o.timeout)
sys.stdout.write('sz\tseq\trtt\tthere\tback\n')
for sz in o.size:
for _ in xrange(o.count):
if sz >= dat.MINSIZE:
pkt = dat.gen(sz)
else:
begin = time.time()
pkt = getrandstr(sz)
fd.sendall(pkt)
if o.udp:
try:
reply = recvall(fd, sz)
except socket.timeout:
sys.stdout.write('%d\t%d\t%.3f\t%.3f\t%.3f\n' % (sz, -1, NAN, NAN, NAN))
sys.stdout.flush()
continue
else:
reply = recvall(fd, sz) # timeout is fatal for TCP stream
if sz >= dat.MINSIZE:
seq, rtt, there, back = dat.rtt(reply)
else:
if reply != pkt:
raise RuntimeError('Short-packet mismatch')
seq, rtt, there, back = -1, time.time() - begin, NAN, NAN
sys.stdout.write('%d\t%d\t%.3f\t%.3f\t%.3f\n' % (sz, seq, rtt, there, back))
sys.stdout.flush()
time.sleep(o.delay)
if __name__ == '__main__':
main()
19:51:26.549217 IP brie.darkk.net.ru.52566 > 2.30.18.250.4242: Flags [S], seq 2422862909, win 29200, options [mss 1460,sackOK,TS val 1141259943 ecr 0,nop,wscale 7], length 0
19:51:26.549531 IP 2.30.18.250.4242 > brie.darkk.net.ru.52566: Flags [S.], seq 4132184401, ack 2422862910, win 28800, options [mss 1452,sackOK,TS val 3539818 ecr 1141259943,nop,wscale 3], length 0
19:51:26.571758 IP brie.darkk.net.ru.52566 > 2.30.18.250.4242: Flags [.], ack 1, win 229, options [nop,nop,TS val 1141259950 ecr 3539818], length 0
19:51:26.572216 IP brie.darkk.net.ru.52566 > 2.30.18.250.4242: Flags [P.], seq 1:51, ack 1, win 229, options [nop,nop,TS val 1141259950 ecr 3539818], length 50
19:51:26.572409 IP 2.30.18.250.4242 > brie.darkk.net.ru.52566: Flags [.], ack 51, win 3600, options [nop,nop,TS val 3539824 ecr 1141259950], length 0
19:51:26.578744 IP 2.30.18.250.4242 > brie.darkk.net.ru.52566: Flags [P.], seq 1:51, ack 51, win 3600, options [nop,nop,TS val 3539826 ecr 1141259950], length 50
19:51:26.601333 IP brie.darkk.net.ru.52566 > 2.30.18.250.4242: Flags [.], ack 51, win 229, options [nop,nop,TS val 1141259959 ecr 3539826], length 0
19:51:27.103082 IP brie.darkk.net.ru.52566 > 2.30.18.250.4242: Flags [P.], seq 51:101, ack 51, win 229, options [nop,nop,TS val 1141260110 ecr 3539826], length 50
19:51:27.105942 IP 2.30.18.250.4242 > brie.darkk.net.ru.52566: Flags [P.], seq 51:101, ack 101, win 3600, options [nop,nop,TS val 3539957 ecr 1141260110], length 50
19:51:27.128347 IP brie.darkk.net.ru.52566 > 2.30.18.250.4242: Flags [.], ack 101, win 229, options [nop,nop,TS val 1141260117 ecr 3539957], length 0
19:51:27.629862 IP brie.darkk.net.ru.52566 > 2.30.18.250.4242: Flags [P.], seq 101:151, ack 101, win 229, options [nop,nop,TS val 1141260267 ecr 3539957], length 50
19:51:27.670076 IP 2.30.18.250.4242 > brie.darkk.net.ru.52566: Flags [.], ack 151, win 3600, options [nop,nop,TS val 3540099 ecr 1141260267], length 0
19:51:27.854104 IP 2.30.18.250.4242 > brie.darkk.net.ru.52566: Flags [P.], seq 101:151, ack 151, win 3600, options [nop,nop,TS val 3540145 ecr 1141260267], length 50
19:51:27.876527 IP brie.darkk.net.ru.52566 > 2.30.18.250.4242: Flags [.], ack 151, win 229, options [nop,nop,TS val 1141260341 ecr 3540145], length 0
19:51:28.377593 IP brie.darkk.net.ru.52566 > 2.30.18.250.4242: Flags [P.], seq 151:201, ack 151, win 229, options [nop,nop,TS val 1141260492 ecr 3540145], length 50
19:51:28.377823 IP 2.30.18.250.4242 > brie.darkk.net.ru.52566: Flags [.], ack 201, win 3600, options [nop,nop,TS val 3540275 ecr 1141260492], length 0
19:51:28.602074 IP 2.30.18.250.4242 > brie.darkk.net.ru.52566: Flags [P.], seq 151:201, ack 201, win 3600, options [nop,nop,TS val 3540332 ecr 1141260492], length 50
19:51:28.624478 IP brie.darkk.net.ru.52566 > 2.30.18.250.4242: Flags [.], ack 201, win 229, options [nop,nop,TS val 1141260566 ecr 3540332], length 0
19:51:29.125323 IP brie.darkk.net.ru.52566 > 2.30.18.250.4242: Flags [F.], seq 201, ack 201, win 229, options [nop,nop,TS val 1141260716 ecr 3540332], length 0
19:51:29.162085 IP 2.30.18.250.4242 > brie.darkk.net.ru.52566: Flags [.], ack 202, win 3600, options [nop,nop,TS val 3540472 ecr 1141260716], length 0
19:51:29.350082 IP 2.30.18.250.4242 > brie.darkk.net.ru.52566: Flags [FP.], seq 201, ack 202, win 3600, options [nop,nop,TS val 3540519 ecr 1141260716], length 0
19:51:29.372209 IP brie.darkk.net.ru.52566 > 2.30.18.250.4242: Flags [.], ack 202, win 229, options [nop,nop,TS val 1141260790 ecr 3540519], length 0
19:51:04.691756 execve("./echosrv.mips", ["./echosrv.mips", "tcp", "4242"], [/* 13 vars */]) = 0
19:51:04.694261 set_thread_area(0x77ffbe48) = 0
19:51:04.694799 set_tid_address(0x77ff4d88) = 3156
19:51:04.695490 open("/etc/ld-musl-mips-sf.path", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = -1 ENOENT (No such file or directory)
19:51:04.696196 open("/lib/libgcc_s.so.1", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
19:51:04.696903 fcntl64(3, F_SETFD, FD_CLOEXEC) = 0
19:51:04.697439 fstat64(3, {st_mode=S_IFREG|0644, st_size=76476, ...}) = 0
19:51:04.698253 read(3, "\177ELF\1\2\1\0\0\0\0\0\0\0\0\0\0\3\0\10\0\0\0\1\0\0(p\0\0\0004"..., 936) = 936
19:51:04.698970 mmap2(NULL, 143360, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x77f2e000
19:51:04.699598 mmap2(0x77f50000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x12000) = 0x77f50000
19:51:04.700427 close(3) = 0
19:51:04.701330 rt_sigaction(SIGPIPE, {SIG_IGN, [RT_68 RT_71 RT_72 RT_73 RT_75 RT_76 RT_82 RT_83 RT_85 RT_86 RT_87 RT_88 RT_89 RT_90 RT_91 RT_93 RT_94 RT_95], SA_RESTORER|SA_RESTART, 0}, {SIG_DFL, [RT_78 RT_81 RT_82 RT_83 RT_84 RT_85 RT_86 RT_87 RT_88 RT_89 RT_90 RT_91 RT_93 RT_94 RT_95], 0}, 16) = 0
19:51:04.702664 socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3
19:51:04.703277 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
19:51:04.703877 setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = 0
19:51:04.704450 bind(3, {sa_family=AF_INET, sin_port=htons(4242), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
19:51:04.705064 listen(3, 1) = 0
19:51:04.705606 accept(3, {sa_family=AF_INET, sin_port=htons(52566), sin_addr=inet_addr("139.162.172.21")}, [16]) = 4
19:51:26.572695 ioctl(1, TIOCGWINSZ, 0x7f82dcc8) = 0
19:51:26.573276 writev(1, [{"Got client from 139.162.172.21:5"..., 36}, {"\n", 1}], 2) = 37
19:51:26.574414 setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0
19:51:26.575001 close(3) = 0
19:51:26.575606 recvfrom(4, "MTU\0RTT\0\0\0\0\0\0\0\0\0[h\25R\0\0\0\1W\246?\276\0\10\244G"..., 29200, 0, NULL, NULL) = 50
19:51:26.576259 clock_gettime(CLOCK_REALTIME, {1470513086, 576622664}) = 0
19:51:26.576848 setsockopt(4, SOL_TCP, TCP_CORK, [1], 4) = 0
19:51:26.577447 sendto(4, "MTU\0RTT\0W\246?\276\0\10\314n[h\25R\0\0\0\1W\246?\276\0\10\244G"..., 50, 0, NULL, 0) = 50
19:51:26.578205 setsockopt(4, SOL_TCP, TCP_CORK, [0], 4) = 0
19:51:26.579004 recvfrom(4, "MTU\0RTT\0\0\0\0\0\0\0\0\0[h\25R\0\0\0\2W\246?\277\0\1|\7"..., 29200, 0, NULL, NULL) = 50
19:51:27.103522 clock_gettime(CLOCK_REALTIME, {1470513087, 103903585}) = 0
19:51:27.104127 setsockopt(4, SOL_TCP, TCP_CORK, [1], 4) = 0
19:51:27.104725 sendto(4, "MTU\0RTT\0W\246?\277\0\1\225\337[h\25R\0\0\0\2W\246?\277\0\1|\7"..., 50, 0, NULL, 0) = 50
19:51:27.105411 setsockopt(4, SOL_TCP, TCP_CORK, [0], 4) = 0
19:51:27.106273 recvfrom(4, "MTU\0RTT\0\0\0\0\0\0\0\0\0[h\25R\0\0\0\3W\246?\277\0\t\204\317"..., 29200, 0, NULL, NULL) = 50
19:51:27.630358 clock_gettime(CLOCK_REALTIME, {1470513087, 630742061}) = 0
19:51:27.630970 setsockopt(4, SOL_TCP, TCP_CORK, [1], 4) = 0
19:51:27.631567 sendto(4, "MTU\0RTT\0W\246?\277\0\t\237\326[h\25R\0\0\0\3W\246?\277\0\t\204\317"..., 50, 0, NULL, 0) = 50
19:51:27.632254 setsockopt(4, SOL_TCP, TCP_CORK, [0], 4) = 0
19:51:27.632871 recvfrom(4, "MTU\0RTT\0\0\0\0\0\0\0\0\0[h\25R\0\0\0\4W\246?\300\0\5\254\302"..., 29200, 0, NULL, NULL) = 50
19:51:28.378237 clock_gettime(CLOCK_REALTIME, {1470513088, 378621411}) = 0
19:51:28.378845 setsockopt(4, SOL_TCP, TCP_CORK, [1], 4) = 0
19:51:28.379442 sendto(4, "MTU\0RTT\0W\246?\300\0\5\306\375[h\25R\0\0\0\4W\246?\300\0\5\254\302"..., 50, 0, NULL, 0) = 50
19:51:28.380130 setsockopt(4, SOL_TCP, TCP_CORK, [0], 4) = 0
19:51:28.380743 recvfrom(4, "", 29200, 0, NULL, NULL) = 0
19:51:29.125710 writev(2, [{"echosrv.mips: ", 14}, {NULL, 0}], 2) = 14
19:51:29.126749 writev(2, [{"EOF from client", 15}, {NULL, 0}], 2) = 15
19:51:29.127725 writev(2, [{"", 0}, {"\n", 1}], 2) = 1
19:51:29.128703 exit_group(0) = ?
19:51:29.129469 +++ exited with 0 +++
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.