Simple TCP pair

From CRIU
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

This page describes step-by-step how to play with TCP dumping and restoring.

Compile and run simple TCP client and server

The below program is a simple echo server and a client, that pings server with increasing numbers once a second. In this howto we will dump and restore the client part.

tcp-howto.c
#include <sys/socket.h>
#include <linux/types.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>

static int serve_new_conn(int sk)
{
	int rd, wr;
	char buf[1024];

	printf("New connection\n");

	while (1) {
		rd = read(sk, buf, sizeof(buf));
		if (!rd)
			break;

		if (rd < 0) {
			perror("Can't read socket");
			return 1;
		}

		wr = 0;
		while (wr < rd) {
			int w;

			w = write(sk, buf + wr, rd - wr);
			if (w <= 0) {
				perror("Can't write socket");
				return 1;
			}

			wr += w;
		}
	}

	printf("Done\n");
	return 0;
}

static int main_srv(int argc, char **argv)
{
	int sk, port, ret;
	struct sockaddr_in addr;

	/*
	 * Let kids die themselves
	 */

	signal(SIGCHLD, SIG_IGN);

	sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sk < 0) {
		perror("Can't create socket");
		return -1;
	}

	port = atoi(argv[1]);
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	addr.sin_port = htons(port);

	printf("Binding to port %d\n", port);

	ret = bind(sk, (struct sockaddr *)&addr, sizeof(addr));
	if (ret < 0) {
		perror("Can't bind socket");
		return -1;
	}

	ret = listen(sk, 16);
	if (ret < 0) {
		perror("Can't put sock to listen");
		return -1;
	}

	printf("Waiting for connections\n");
	while (1) {
		int ask, pid;

		ask = accept(sk, NULL, NULL);
		if (ask < 0) {
			perror("Can't accept new conn");
			return -1;
		}

		pid = fork();
		if (pid < 0) {
			perror("Can't fork");
			return -1;
		}

		if (pid > 0)
			close(ask);
		else {
			close(sk);
			ret = serve_new_conn(ask);
			exit(ret);
		}
	}
}

static int main_cl(int argc, char **argv)
{
	int sk, port, ret, val = 1, rval;
	struct sockaddr_in addr;

	sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sk < 0) {
		perror("Can't create socket");
		return -1;
	}

	port = atoi(argv[2]);
	printf("Connecting to %s:%d\n", argv[1], port);
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	ret = inet_aton(argv[1], &addr.sin_addr);
	if (ret < 0) {
		perror("Can't convert addr");
		return -1;
	}
	addr.sin_port = htons(port);

	ret = connect(sk, (struct sockaddr *)&addr, sizeof(addr));
	if (ret < 0) {
		perror("Can't connect");
		return -1;
	}

	while (1) {
		write(sk, &val, sizeof(val));
		rval = -1;
		read(sk, &rval, sizeof(rval));
		printf("PP %d -> %d\n", val, rval);
		sleep(2);
		val++;
	}
}

int main(int argc, char **argv)
{
	if (argc == 2)
		return main_srv(argc, argv);
	else if (argc == 3)
		return main_cl(argc, argv);

	printf("Bad usage\n");
	return 1;
}

Compile it and run the server:

# ./tcp-howto <some-port>

On another terminal (for better output readability) run the client:

# ./tcp-howto 127.0.0.1 <some-port>

Try to dump the client

Create a directory for images (img-dir/ below) and dump the client

# criu dump --tree <tcp-howto-client-pid> --images-dir img-dir/ -v4 -o dump.log --shell-job --tcp-established

The --tcp-established option is a must, since client have active TCP connection and we should explicitly inform crtools about it.

The --shell-job option is also required, as the client was launched from shell and uses shell's session and terminal.

Then restore the client

It's done like this

# criu restore --images-dir img-dir/ -v4 -o rst.log --shell-job --tcp-established

That's it. After this in the terminal you launched criu from you should see the continuing output of the tcp client.

See also