2
0
mirror of https://github.com/checkpoint-restore/criu synced 2025-08-23 10:28:05 +00:00
criu/soccr/test/tcp-constructor.c
Adrian Reber 93dd984ca0 Run 'make indent' on all C files
Acked-by: Mike Rapoport <rppt@linux.ibm.com>
Signed-off-by: Adrian Reber <areber@redhat.com>
2021-09-03 10:31:00 -07:00

149 lines
3.9 KiB
C

#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(void)
{
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]);
}