[CRIU] [PATCH 6/8] tests: check callback-s for dumping and restoring sockets (v2)

Andrey Vagin avagin at openvz.org
Thu Dec 12 09:12:57 PST 2013


Here are client, server programs and two libraries for dumping client
sockets and syslog socket.

The client can ask server to save a value and then request it later.
We suppose that after dumping and restoring the client will get
the same value.

So the dump callback requests the value and save it in a file.
The restore callback creates a new socket and ask server to save the
value from the file.

v2: open a syslog socket

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 test/unix-callback/Makefile          |  19 ++++
 test/unix-callback/lib/syslog-lib.so |   1 +
 test/unix-callback/lib/unix-lib.so   |   1 +
 test/unix-callback/run.sh            |  48 +++++++++
 test/unix-callback/syslog-lib.c      |  64 ++++++++++++
 test/unix-callback/unix-client.c     |  88 +++++++++++++++++
 test/unix-callback/unix-lib.c        | 182 +++++++++++++++++++++++++++++++++++
 test/unix-callback/unix-server.c     | 102 ++++++++++++++++++++
 test/unix-callback/unix.proto        |   4 +
 9 files changed, 509 insertions(+)
 create mode 100644 test/unix-callback/Makefile
 create mode 120000 test/unix-callback/lib/syslog-lib.so
 create mode 120000 test/unix-callback/lib/unix-lib.so
 create mode 100755 test/unix-callback/run.sh
 create mode 100644 test/unix-callback/syslog-lib.c
 create mode 100644 test/unix-callback/unix-client.c
 create mode 100644 test/unix-callback/unix-lib.c
 create mode 100644 test/unix-callback/unix-server.c
 create mode 100644 test/unix-callback/unix.proto

diff --git a/test/unix-callback/Makefile b/test/unix-callback/Makefile
new file mode 100644
index 0000000..191de67
--- /dev/null
+++ b/test/unix-callback/Makefile
@@ -0,0 +1,19 @@
+all: unix-lib.so unix-server unix-client syslog-lib.so
+
+unix.pb-c.c: unix.proto
+	protoc-c --proto_path=. --c_out=. unix.proto
+
+unix-lib.so: unix-lib.c unix.pb-c.c
+	gcc -g -Werror -Wall -shared -nostartfiles unix-lib.c unix.pb-c.c -o unix-lib.so -iquote ../../include -fPIC
+
+syslog-lib.so: syslog-lib.c
+	gcc -g -Werror -Wall -shared -nostartfiles syslog-lib.c -o syslog-lib.so -iquote ../../include -fPIC
+
+unix-server: unix-server.c
+	gcc -Werror -Wall -o unix-server unix-server.c
+
+unix-client: unix-client.c
+	gcc -Werror -Wall -o unix-client unix-client.c
+
+clean:
+	rm -rf data unix-lib.so unix-server unix-client syslog-lib.so output pid unix.pb-c.*
diff --git a/test/unix-callback/lib/syslog-lib.so b/test/unix-callback/lib/syslog-lib.so
new file mode 120000
index 0000000..6a2d849
--- /dev/null
+++ b/test/unix-callback/lib/syslog-lib.so
@@ -0,0 +1 @@
+../syslog-lib.so
\ No newline at end of file
diff --git a/test/unix-callback/lib/unix-lib.so b/test/unix-callback/lib/unix-lib.so
new file mode 120000
index 0000000..19c491e
--- /dev/null
+++ b/test/unix-callback/lib/unix-lib.so
@@ -0,0 +1 @@
+../unix-lib.so
\ No newline at end of file
diff --git a/test/unix-callback/run.sh b/test/unix-callback/run.sh
new file mode 100755
index 0000000..f9495ef
--- /dev/null
+++ b/test/unix-callback/run.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+cd `dirname $0`
+
+source ../env.sh || exit 1
+
+rm -rf /tmp/criu.unix.callback.test*
+test -f pid && unlink pid
+test -f output && unlink output
+rm -rf data
+mkdir -p data
+
+./unix-server &
+srv_pid=$!
+
+for i in `seq 20`; do
+	test -f /tmp/criu.unix.callback.test && break
+	sleep 0.1
+done
+
+( setsid ./unix-client < /dev/null &> output ) &
+
+while :; do
+	test -f pid && break
+	sleep 1
+done
+
+pid=`cat pid`
+
+${CRIU} dump --shell-job -D data -o dump.log -v4 --lib `pwd`/lib -t $pid || exit 1
+kill $srv_pid
+wait $srv_pid
+unlink /tmp/criu.unix.callback.test
+./unix-server &
+srv_pid=$!
+for i in `seq 20`; do
+	test -f /tmp/criu.unix.callback.test && break
+	sleep 0.1
+done
+${CRIU} restore --shell-job -D data -o restore.log -v4 --lib `pwd`/lib -d || exit 1
+kill $pid
+while :; do
+	cat output | grep PASS && break
+	sleep 1
+done
+
+cat output
+kill $srv_pid
diff --git a/test/unix-callback/syslog-lib.c b/test/unix-callback/syslog-lib.c
new file mode 100644
index 0000000..5cade98
--- /dev/null
+++ b/test/unix-callback/syslog-lib.c
@@ -0,0 +1,64 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "criu-plugin.h"
+
+extern cr_plugin_dump_unix_sk_t cr_plugin_dump_unix_sk;
+extern cr_plugin_restore_unix_sk_t cr_plugin_restore_unix_sk;
+
+int cr_plugin_dump_unix_sk(int sk, int id)
+{
+	struct sockaddr_un addr;
+	socklen_t addr_len = sizeof(addr);
+	char buf[4096];
+	int fd;
+
+	if (getsockname(sk, (struct sockaddr *) &addr, &addr_len) < 0)
+		return -1;
+
+	if (strncmp(addr.sun_path, "/dev/log", addr_len - sizeof(addr.sun_family)))
+		return CRIU_CB_SKIP;
+
+	snprintf(buf, sizeof(buf), "syslog-%x.img", id);
+	fd = open(buf, O_WRONLY | O_CREAT);
+	if (fd < 0)
+		return -1;
+	close(fd);
+
+	return 0;
+}
+
+int cr_plugin_restore_unix_sk(int id)
+{
+	struct sockaddr_un addr;
+	socklen_t addr_len;
+	char buf[4096];
+	int sk, fd;
+
+	snprintf(buf, sizeof(buf), "syslog-%x.img", id);
+	fd = open(buf, O_RDONLY);
+	if (fd < 0)
+		return CRIU_CB_SKIP;
+	close(fd);
+
+	sk = socket(AF_FILE, SOCK_DGRAM|SOCK_CLOEXEC, 0);
+	if (sk == -1)
+		return sk;
+
+	addr.sun_family = AF_FILE;
+	addr_len = strlen("/dev/log");
+	strncpy(addr.sun_path, "/dev/log", addr_len);
+	addr_len += sizeof(addr.sun_family);
+	if (connect(sk, (struct sockaddr *) &addr, addr_len) == -1) {
+		close(sk);
+		return -1;
+	}
+
+	return sk;
+}
diff --git a/test/unix-callback/unix-client.c b/test/unix-callback/unix-client.c
new file mode 100644
index 0000000..cf7ad4e
--- /dev/null
+++ b/test/unix-callback/unix-client.c
@@ -0,0 +1,88 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/un.h>
+#include <fcntl.h>
+
+#include <syslog.h>
+
+#define SK_NAME "/tmp/criu.unix.callback.test"
+
+int main()
+{
+	int sk, ret, id = getpid(), val = time(NULL), fd;
+	char buf[4096];
+	struct sockaddr_un addr;
+	socklen_t addr_len;
+	sigset_t set;
+	int sig;
+
+	sk = socket(AF_UNIX, SOCK_DGRAM, 0);
+	if (sk < 0)
+		return -1;
+
+	addr.sun_family = AF_UNIX;
+	addr_len = snprintf(addr.sun_path, UNIX_PATH_MAX, "%s%d", SK_NAME, id);
+	addr_len += sizeof(addr.sun_family);
+
+	if (bind(sk, (struct sockaddr *) &addr, addr_len) < 0) {
+		perror("bind");
+		return 1;
+	}
+
+	addr.sun_family = AF_UNIX;
+	addr_len = snprintf(addr.sun_path, UNIX_PATH_MAX, SK_NAME);
+	addr_len += sizeof(addr.sun_family);
+
+	if (connect(sk, (struct sockaddr *) &addr, addr_len) < 0) {
+		perror("connect");
+		return 1;
+	}
+
+	printf("init %d\n", val);
+	ret = sprintf(buf, "t%d", val);
+	if (send(sk, buf, ret, 0) < 0) {
+		perror("send");
+		return -1;
+	}
+
+	fd = open("pid", O_WRONLY | O_CREAT, 0666);
+	if (fd < 0)
+		return 1;
+	dprintf(fd, "%d\n", getpid());
+	close(fd);
+
+	openlog("test", LOG_NDELAY, LOG_USER );
+
+	sigemptyset(&set);
+	sigaddset(&set, SIGTERM);
+	sigprocmask(SIG_BLOCK, &set, NULL);
+	sigwait(&set, &sig);
+
+	syslog(LOG_CRIT, "test message");
+
+	if (send(sk, "r", 1, 0) < 0) {
+		perror("send(\"r\")");
+		return -1;
+	}
+
+	if (recv(sk, buf, sizeof(buf), 0) <= 0) {
+		perror("recv");
+		return -1;
+	}
+
+	printf("%s - %d\n", buf, val);
+	if (atoi(buf) == val)
+		printf("PASS\n");
+	else
+		return -1;
+
+	return 0;
+}
+
diff --git a/test/unix-callback/unix-lib.c b/test/unix-callback/unix-lib.c
new file mode 100644
index 0000000..ce52790
--- /dev/null
+++ b/test/unix-callback/unix-lib.c
@@ -0,0 +1,182 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <libgen.h>
+
+#include <sys/socket.h>
+#include <linux/un.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "criu-plugin.h"
+#include "unix.pb-c.h"
+
+extern cr_plugin_init_t cr_plugin_init;
+extern cr_plugin_dump_unix_sk_t cr_plugin_dump_unix_sk;
+extern cr_plugin_restore_unix_sk_t cr_plugin_restore_unix_sk;
+
+#define SK_NAME "/tmp/criu.unix.callback.test"
+static int get_srv_socket(void)
+{
+	struct sockaddr_un addr;
+	socklen_t addr_len;
+	int skd;
+
+	skd = socket(AF_UNIX, SOCK_DGRAM, 0);
+	if (skd < 0) {
+		pr_perror("socket");
+		return -1;
+	}
+
+	addr.sun_family = AF_UNIX;
+	addr_len = snprintf(addr.sun_path, UNIX_PATH_MAX, "%s.dump.%d", SK_NAME, getpid());
+	addr_len += sizeof(addr.sun_family);
+
+	unlink(addr.sun_path);
+	if (bind(skd, (struct sockaddr *) &addr, addr_len) < 0) {
+		pr_perror("bind");
+		return 1;
+	}
+
+	addr.sun_family = AF_UNIX;
+	addr_len = snprintf(addr.sun_path, UNIX_PATH_MAX, SK_NAME);
+	addr_len += sizeof(addr.sun_family);
+
+	if (connect(skd, (struct sockaddr *) &addr, addr_len) < 0) {
+		pr_perror("connect");
+		return -1;
+	}
+
+	return skd;
+}
+
+int cr_plugin_init(void)
+{
+	return 0;
+}
+
+int cr_plugin_dump_unix_sk(int sk, int sk_id)
+{
+	struct sockaddr_un addr;
+	socklen_t addr_len = sizeof(addr);
+	char buf[4096];
+	int skd, id, ret, fd, len;
+	UnixTest e = UNIX_TEST__INIT;
+
+	if (getpeername(sk, (struct sockaddr *) &addr, &addr_len)) {
+		pr_perror("getpeername");
+		return -1;
+	}
+
+	len = addr_len - sizeof(addr.sun_family);
+	if (addr.sun_path[len - 1] == 0)
+		len--;
+
+	if (len != strlen(SK_NAME) ||
+	    strncmp(addr.sun_path, SK_NAME, strlen(SK_NAME)))
+		return CRIU_CB_SKIP;
+
+	pr_info("Dump the socket %x\n", sk_id);
+	skd = get_srv_socket();
+	if (skd < 0)
+		return -1;
+
+	addr_len = sizeof(struct sockaddr_un);
+
+	if (getsockname(sk, (struct sockaddr *) &addr, &addr_len) < 0)
+		return -1;
+
+	id = atoi(addr.sun_path + strlen(SK_NAME));
+
+	ret = sprintf(buf, "d%d", id) + 1;
+	if (send(skd, buf, ret, 0) < 0) {
+		pr_perror("send");
+		return -1;
+	}
+
+	if (recv(skd, buf, sizeof(buf), 0) <= 0)
+		return -1;
+
+	close(skd);
+
+	e.val = atoi(buf);
+	e.name.data = (void *)addr.sun_path;
+	e.name.len = addr_len - sizeof(addr.sun_family);
+
+	snprintf(buf, sizeof(buf), "unix-test-%x.img", sk_id);
+	fd = openat(cr_get_image_dir(), buf, O_WRONLY | O_CREAT, 0600);
+	if (fd < 0)
+		return -1;
+
+	if (unix_test__get_packed_size(&e) > sizeof(buf)) {
+		pr_err("%ld\n", unix_test__get_packed_size(&e));
+		return -1;
+	}
+
+	ret = unix_test__pack(&e, (uint8_t *) buf);
+	if (write(fd, buf, ret) != ret)
+		return -1;
+	close(fd);
+
+	return 0;
+}
+
+int cr_plugin_restore_unix_sk(int sk_id)
+{
+	struct sockaddr_un addr;
+	socklen_t addr_len;
+	int fd, sk, ret;
+	char buf[4096];
+	UnixTest *e;
+
+	snprintf(buf, sizeof(buf), "unix-test-%x.img", sk_id);
+	fd = openat(cr_get_image_dir(), buf, O_RDONLY, 0600);
+	if (fd < 0)
+		return CRIU_CB_SKIP;
+
+	ret = read(fd, buf, sizeof(buf));
+	if (ret < 0) {
+		pr_perror("read");
+		return -1;
+	}
+	close(fd);
+
+	e = unix_test__unpack(NULL, ret, (uint8_t *) buf);
+	if (e == NULL)
+		return -1;
+
+	sk = socket(AF_UNIX, SOCK_DGRAM, 0);
+	if (sk < 0) {
+		pr_perror("socket");
+		return -1;
+	}
+
+	addr.sun_family = AF_UNIX;
+	memcpy(addr.sun_path, e->name.data, e->name.len);
+	addr_len = sizeof(addr.sun_family) + e->name.len;
+
+	if (bind(sk, (struct sockaddr *) &addr, addr_len) < 0) {
+		pr_perror("bind");
+		return -1;
+	}
+
+	addr.sun_family = AF_UNIX;
+	addr_len = snprintf(addr.sun_path, UNIX_PATH_MAX, SK_NAME);
+	addr_len += sizeof(addr.sun_family);
+
+	if (connect(sk, (struct sockaddr *) &addr, addr_len) < 0) {
+		pr_perror("connect");
+		return -1;
+	}
+
+	ret = sprintf(buf, "t%d", e->val);
+	if (send(sk, buf, ret, 0) < 0) {
+		pr_perror("send");
+		return -1;
+	}
+
+	return sk;
+}
diff --git a/test/unix-callback/unix-server.c b/test/unix-callback/unix-server.c
new file mode 100644
index 0000000..2d28aa6
--- /dev/null
+++ b/test/unix-callback/unix-server.c
@@ -0,0 +1,102 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <linux/un.h>
+
+struct ticket
+{
+	struct ticket *next;
+	int val;
+	int id;
+};
+
+struct ticket *tickets;
+
+#define SK_NAME "/tmp/criu.unix.callback.test"
+
+int main()
+{
+	int sk, ret, id;
+	char buf[4096];
+	struct ticket *t;
+	struct sockaddr_un addr;
+	socklen_t addr_len;
+	struct stat st;
+
+	unlink(SK_NAME);
+
+	sk = socket(AF_UNIX, SOCK_DGRAM, 0);
+	if (sk < 0) {
+		perror("socket");
+		return -1;
+	}
+
+	addr.sun_family = AF_UNIX;
+	addr_len = snprintf(addr.sun_path, UNIX_PATH_MAX, SK_NAME);
+	addr_len += sizeof(addr.sun_family);
+
+	if (bind(sk, (struct sockaddr *) &addr, addr_len) < 0) {
+		perror("bind");
+		return 1;
+	}
+
+	fstat(sk, &st);
+
+	while (1) {
+		addr_len = sizeof(struct sockaddr_un);
+		ret = recvfrom(sk, buf, sizeof(buf), 0, (struct sockaddr *) &addr, &addr_len);
+		if (ret == 0)
+			return 0;
+		if (ret < 0) {
+			perror("recvfrom");
+			return 1;
+		}
+		switch (buf[0]) {
+		id = 0;
+		case 'l':
+			ret = sprintf(buf, "%ld", st.st_ino);
+			if (sendto(sk, buf, ret + 1, 0, (struct sockaddr *) &addr, addr_len) < 0) {
+				perror("sendto");
+				return -1;
+			}
+			break;
+		case 't': /* ticket */
+			t = malloc(sizeof(struct ticket));
+			if (t == 0) {
+				perror("Can't allocate memory");
+				return 1;
+			}
+
+			t->val = atoi(buf + 1);
+			t->next = tickets;
+			t->id = atoi(addr.sun_path +strlen(SK_NAME));
+			tickets = t;
+			break;
+		case 'd': /* dump */
+			id = atoi(buf + 1);
+		case 'r': /* request */
+			if (!id)
+				id = atoi(addr.sun_path + strlen(SK_NAME));
+			for (t = tickets; t; t = t->next)
+				if (t->id == id)
+					break;
+			if (t == NULL)
+				return 1;
+			ret = sprintf(buf, "%d", t->val);
+			if (sendto(sk, buf, ret + 1, 0, (struct sockaddr *) &addr, addr_len) < 0) {
+				perror("sendto");
+				return 1;
+			}
+			break;
+		default:
+			return -1;
+		}
+	}
+
+	return 0;
+}
diff --git a/test/unix-callback/unix.proto b/test/unix-callback/unix.proto
new file mode 100644
index 0000000..fb06fc8
--- /dev/null
+++ b/test/unix-callback/unix.proto
@@ -0,0 +1,4 @@
+message unix_test {
+	required uint32 val = 1;
+	required bytes name = 2;
+}
-- 
1.8.3.1



More information about the CRIU mailing list