[CRIU] [PATCH 4/4] tests: check callback-s for dumping and restoring sockets
Andrey Vagin
avagin at openvz.org
Sat Nov 30 09:43:56 PST 2013
Here are client, server programs and a library for dumping client
sockets.
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.
Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
test/unix-callback/Makefile | 10 +++
test/unix-callback/run.sh | 40 +++++++++
test/unix-callback/unix-client.c | 85 +++++++++++++++++++
test/unix-callback/unix-lib.c | 175 +++++++++++++++++++++++++++++++++++++++
test/unix-callback/unix-server.c | 88 ++++++++++++++++++++
5 files changed, 398 insertions(+)
create mode 100644 test/unix-callback/Makefile
create mode 100755 test/unix-callback/run.sh
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
diff --git a/test/unix-callback/Makefile b/test/unix-callback/Makefile
new file mode 100644
index 0000000..bf6f216
--- /dev/null
+++ b/test/unix-callback/Makefile
@@ -0,0 +1,10 @@
+all: unix-lib unix-server unix-client
+
+unix-lib: unix-lib.c
+ gcc -Wall -shared -nostartfiles unix-lib.c -o unix-lib.so -iquote ../../include -fPIC
+
+unix-server: unix-server.c
+ gcc -Wall -o unix-server unix-server.c
+
+unix-client: unix-client.c
+ gcc -Wall -o unix-client unix-client.c
diff --git a/test/unix-callback/run.sh b/test/unix-callback/run.sh
new file mode 100755
index 0000000..ed2d18e
--- /dev/null
+++ b/test/unix-callback/run.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+cd `dirname $0`
+
+source ../env.sh || exit 1
+
+test -f pid && unlink pid
+test -f output && unlink output
+rm -rf data
+mkdir -p data
+
+./unix-server &
+srv_pid=$!
+
+sleep 1
+
+( 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 ./unix-lib.so -t $pid &&
+kill $srv_pid
+wait $srv_pid
+./unix-server &
+srv_pid=$!
+sleep 1
+${CRIU} restore --shell-job -D data -o restore.log -v4 --lib ./unix-lib.so --ext-unix-sk -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/unix-client.c b/test/unix-callback/unix-client.c
new file mode 100644
index 0000000..e101aa3
--- /dev/null
+++ b/test/unix-callback/unix-client.c
@@ -0,0 +1,85 @@
+#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 <sys/un.h>
+#include <fcntl.h>
+
+struct ticket *tickets;
+
+#define SK_NAME "Xcriu.unix.callback.test"
+static int go = 1;
+static void sighndlr(int signo)
+{
+ go = 0;
+}
+
+int main()
+{
+ int sk, ret, id = getpid(), val = time(NULL), fd;
+ char buf[4096];
+ struct sockaddr_un addr;
+ socklen_t addr_len;
+
+ signal(SIGTERM, sighndlr);
+ sk = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return -1;
+
+ addr.sun_family = AF_UNIX;
+ addr_len = snprintf(addr.sun_path, 108, "%s%d", SK_NAME, id);
+ addr_len += sizeof(addr.sun_family);
+ addr.sun_path[0] = 0;
+
+ if (bind(sk, (struct sockaddr *) &addr, addr_len) < 0) {
+ perror("bind");
+ return 1;
+ }
+
+ addr.sun_family = AF_UNIX;
+ addr_len = snprintf(addr.sun_path, 108, SK_NAME);
+ addr_len += sizeof(addr.sun_family);
+ addr.sun_path[0] = 0;
+
+ if (connect(sk, (struct sockaddr *) &addr, addr_len) < 0) {
+ perror("connect");
+ return 1;
+ }
+
+ 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);
+
+ while (go);
+
+ if (send(sk, "r", 1, 0) < 0) {
+ perror("send(\"r\")");
+ return -1;
+ }
+
+ if (recv(sk, buf, sizeof(buf), 0) <= 0) {
+ perror("recv");
+ return -1;
+ }
+
+ 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..e3672df
--- /dev/null
+++ b/test/unix-callback/unix-lib.c
@@ -0,0 +1,175 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "log.h"
+#include "cr-lib.h"
+
+extern cr_init_t cr_init;
+extern cr_dump_unix_sk_t cr_dump_unix_sk;
+extern cr_restore_unix_sk_t cr_restore_unix_sk;
+
+#define SK_NAME "Xcriu.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, 108, "%s.dump.%d", SK_NAME, getpid());
+ addr_len += sizeof(addr.sun_family);
+ addr.sun_path[0] = 0;
+
+ 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, 108, SK_NAME);
+ addr_len += sizeof(addr.sun_family);
+ addr.sun_path[0] = 0;
+
+ if (connect(skd, (struct sockaddr *) &addr, addr_len) < 0) {
+ pr_perror("connect");
+ return -1;
+ }
+
+ return skd;
+}
+
+static unsigned long srv_ino = -1L;
+int cr_init(void)
+{
+ int sk;
+ char buf[4096];
+
+ sk = get_srv_socket();
+ if (sk < 0)
+ return 0;
+
+ if (send(sk, "l", 1, 0) != 1)
+ goto out;;
+
+ if (recv(sk, buf, sizeof(buf), 0) < 0)
+ goto out;;
+
+ srv_ino = atoi(buf);
+ pr_err("srv_ino = %ld", srv_ino);
+
+out:
+ close(sk);
+ return 0;
+}
+
+int cr_dump_unix_sk(int sk, int ino, int peer_ino)
+{
+ struct sockaddr_un addr;
+ socklen_t addr_len;
+ char buf[4096];
+ int skd, id, ret, fd;
+
+ if (srv_ino != peer_ino)
+ return CR_CB_SKIP;
+
+ 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);
+
+ addr.sun_path[addr_len - sizeof(addr.sun_family)] = 0;
+ fd = open(addr.sun_path + 1, O_WRONLY | O_CREAT, 0600);
+ if (fd < 0) {
+ pr_perror("open");
+ return -1;
+ }
+
+ dprintf(fd, "%d\n", atoi(buf));
+ close(fd);
+
+ return 0;
+}
+
+int cr_restore_unix_sk(int ino, char *addr_n, int len)
+{
+ struct sockaddr_un addr;
+ socklen_t addr_len;
+ int fd, val, sk, ret;
+ char buf[4096];
+
+ snprintf(buf, sizeof(buf), "%.*s", len - 1, addr_n + 1);
+ pr_err("%s\n", buf);
+ fd = open(buf, O_RDONLY);
+ if (fd < 0)
+ return CR_CB_SKIP;
+
+ if (read(fd, buf, sizeof(buf)) < 0)
+ return -1;
+ close(fd);
+
+ val = atoi(buf);
+
+ sk = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (sk < 0) {
+ pr_perror("socket");
+ return -1;
+ }
+
+ addr.sun_family = AF_UNIX;
+ addr_len = snprintf(addr.sun_path, 108, "X%s", addr_n + 1);
+ addr_len += sizeof(addr.sun_family);
+ addr.sun_path[0] = 0;
+
+ if (bind(sk, (struct sockaddr *) &addr, addr_len) < 0)
+ return -1;
+
+ addr.sun_family = AF_UNIX;
+ addr_len = snprintf(addr.sun_path, 108, SK_NAME);
+ addr_len += sizeof(addr.sun_family);
+ addr.sun_path[0] = 0;
+
+ if (connect(sk, (struct sockaddr *) &addr, addr_len) < 0) {
+ pr_perror("socket");
+ return -1;
+ }
+
+ ret = sprintf(buf, "t%d", 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..ac3445e
--- /dev/null
+++ b/test/unix-callback/unix-server.c
@@ -0,0 +1,88 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+struct ticket
+{
+ struct ticket *next;
+ int val;
+ int id;
+};
+
+struct ticket *tickets;
+
+#define SK_NAME "Xcriu.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;
+
+ sk = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return -1;
+
+ addr.sun_family = AF_UNIX;
+ addr_len = snprintf(addr.sun_path, 108, SK_NAME);
+ addr_len += sizeof(addr.sun_family);
+ addr.sun_path[0] = 0;
+
+ if (bind(sk, (struct sockaddr *) &addr, addr_len) < 0)
+ 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)
+ 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)
+ return -1;
+ break;
+ case 't': /* ticket */
+ t = malloc(sizeof(struct ticket));
+ if (t == 0)
+ 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)
+ return 1;
+ break;
+ default:
+ return -1;
+ }
+ }
+
+ return 0;
+}
--
1.8.3.1
More information about the CRIU
mailing list