Commit 1fb852bb authored by Andrei Vagin's avatar Andrei Vagin Committed by Pavel Emelyanov

soccr: add a test

This test construct both ends of tcp connections and
check that it works in both directions.

travis-ci: success for soccr: add a test
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
parent d9132d45
CFLAGS += -Wall -g -I../../
LDFLAGS += -L../ -lsoccr ../libsoccr.a -lnet
RUN ?= tcp-constructor
run:
./local.sh
tcp-constructor: tcp-constructor.c ../libsoccr.a
$(CC) $(CFLAGS) tcp-constructor.c -o tcp-constructor $(LDFLAGS)
clean:
rm -f tcp-constructor
test: tcp-constructor
python run.py ./$(RUN)
.PHONY: test
unshare -Urn sh -c 'ip link set up dev lo && make test'
#!/usr/bin/env python2
import sys, os
import hashlib
from subprocess import Popen, PIPE
str2 = "test_test" * (1 << 20)
str1 = "Test_Test!"
src = os.getenv("TCP_SRC", "127.0.0.1")
dst = os.getenv("TCP_DST", "127.0.0.1")
sport = os.getenv("TCP_SPORT", "12345")
dport = os.getenv("TCP_DPORT", "54321")
print sys.argv[1]
args = [sys.argv[1],
"--addr", src, "--port", sport, "--seq", "555",
"--next",
"--addr", dst, "--port", dport, "--seq", "666",
"--reverse", "--", "./tcp-test.py"]
p1 = Popen(args + ["dst"], stdout = PIPE, stdin = PIPE)
args.remove("--reverse");
p2 = Popen(args + ["src"], stdout = PIPE, stdin = PIPE)
p1.stdout.read(5)
p2.stdout.read(5)
p1.stdin.write("start")
p2.stdin.write("start")
p1.stdin.write(str1)
p1.stdin.close()
p2.stdin.write(str2)
p2.stdin.close()
s = p1.stdout.read()
m = hashlib.md5()
m.update(str2)
str2 = m.hexdigest()
if str2 != eval(s):
print "FAIL", repr(str2), repr(s)
sys.exit(5);
s = p1.stdout.read()
m = hashlib.md5()
m.update(str1)
str1 = m.hexdigest()
s = p2.stdout.read()
if str1 != eval(s):
print "FAIL", repr(str1), s
sys.exit(5);
if p1.wait():
sys.exit(1)
if p2.wait():
sys.exit(1)
print "PASS"
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <linux/socket.h>
#include <netinet/tcp.h>
#include <string.h>
#include <getopt.h>
#include <stdlib.h>
#include "soccr/soccr.h"
#define pr_perror(fmt, ...) ({ fprintf(stderr, "%s:%d: " fmt " : %m\n", __func__, __LINE__, ##__VA_ARGS__); 1; })
struct tcp {
char *addr;
uint32_t port;
uint32_t seq;
uint16_t mss_clamp;
uint16_t wscale;
};
static void usage()
{
printf(
"Usage: --addr ADDR -port PORT --seq SEQ --next --addr ADDR -port PORT --seq SEQ -- CMD ...\n"
"\t Describe a source side of a connection, then set the --next option\n"
"\t and describe a destination side.\n"
"\t --reverse - swap source and destination sides\n"
"\t The idea is that the same command line is execute on both sides,\n"
"\t but the --reverse is added to one of them.\n"
"\n"
"\t CMD ... - a user command to handle a socket, which is the descriptor 3.\n"
"\n"
"\t It prints the \"start\" on stdout when a socket is created and\n"
"\t resumes it when you write \"start\" to stdin.\n"
);
}
int main(int argc, char **argv)
{
static const char short_opts[] = "";
static struct option long_opts[] = {
{ "addr", required_argument, 0, 'a' },
{ "port", required_argument, 0, 'p' },
{ "seq", required_argument, 0, 's' },
{ "next", no_argument, 0, 'n'},
{ "reverse", no_argument, 0, 'r'},
{},
};
struct tcp tcp[2] = {
{"127.0.0.1", 12345, 5000000, 1460, 7},
{"127.0.0.1", 54321, 6000000, 1460, 7}
};
int sk, yes = 1, val, idx, opt, i, src = 0, dst = 1;
union libsoccr_addr src_addr, dst_addr;
struct libsoccr_sk_data data = {};
struct libsoccr_sk *so;
char buf[1024];
i = 0;
while (1) {
idx = -1;
opt = getopt_long(argc, argv, short_opts, long_opts, &idx);
if (opt == -1)
break;
switch (opt) {
case 'a':
tcp[i].addr = optarg;
break;
case 'p':
tcp[i].port = atol(optarg);
break;
case 's':
tcp[i].seq = atol(optarg);
break;
case 'n':
i++;
if (i > 1)
return pr_perror("--next is used twice or more");
break;
case 'r':
src = 1; dst = 0;
break;
default:
usage();
return 3;
}
}
if (i != 1)
return pr_perror("--next is required");
if (optind == argc) {
usage();
return 1;
}
for (i = 0; i < 2; i++)
fprintf(stderr, "%s:%d:%d\n", tcp[i].addr, tcp[i].port, tcp[i].seq);
data.state = TCP_ESTABLISHED;
data.inq_seq = tcp[dst].seq;
data.outq_seq = tcp[src].seq;
sk = socket(AF_INET, SOCK_STREAM, 0);
if (sk < 0)
return pr_perror("socket");
so = libsoccr_pause(sk);
if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1)
return pr_perror("setsockopt");
src_addr.v4.sin_family = AF_INET;
src_addr.v4.sin_port = htons(tcp[src].port);
if (inet_pton(AF_INET, tcp[src].addr, &src_addr.v4.sin_addr) != 1)
return pr_perror("inet_pton");
dst_addr.v4.sin_family = AF_INET;
dst_addr.v4.sin_port = htons(tcp[dst].port);
if (inet_pton(AF_INET, tcp[dst].addr, &(dst_addr.v4.sin_addr)) != 1)
return pr_perror("inet_pton");
libsoccr_set_addr(so, 1, &src_addr, 0);
libsoccr_set_addr(so, 0, &dst_addr, 0);
data.snd_wscale = tcp[src].wscale;
data.rcv_wscale = tcp[dst].wscale;
data.mss_clamp = tcp[src].mss_clamp;
data.opt_mask = TCPI_OPT_WSCALE | TCPOPT_MAXSEG;
if (libsoccr_restore(so, &data, sizeof(data)))
return 1;
/* Let's go */
if (write(STDOUT_FILENO, "start", 5) != 5)
return pr_perror("write");
if (read(STDIN_FILENO, buf, 5) != 5)
return pr_perror("read");
val = 0;
if (setsockopt(sk, SOL_TCP, TCP_REPAIR, &val, sizeof(val)))
return pr_perror("TCP_REPAIR");
execv(argv[optind], argv + optind);
return pr_perror("Unable to exec %s", argv[optind]);
}
#!/usr/bin/env python2
import os, sys, socket
import hashlib
sk = socket.fromfd(3, socket.AF_INET, socket.SOCK_STREAM)
s = sys.stdin.read()
ret = sk.send(s)
print >> sys.stderr, "%s: send() -> %d" % (sys.argv[1], ret)
sk.shutdown(socket.SHUT_WR)
m = hashlib.md5()
while True:
s = sk.recv((1 << 20) * 10)
if not s:
break
print >> sys.stderr, "%s: recv() -> %d" % (sys.argv[1], len(s))
m.update(s)
print repr(m.hexdigest())
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment