Commit 1e4b8c8c authored by Andrey Vagin's avatar Andrey Vagin Committed by Pavel Emelyanov

tests: check callback-s for dumping and restoring sockets (v2)

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: 's avatarAndrey Vagin <avagin@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 9e3f4451
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.*
../syslog-lib.so
\ No newline at end of file
../unix-lib.so
\ No newline at end of file
#!/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
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "criu-plugin.h"
#include "criu-log.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 -ENOTSUP;
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 -ENOTSUP;
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;
}
#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"
#define SK_NR 2
struct {
int id;
int sk;
int val;
} sks[SK_NR];
static int create_sock(int i)
{
int ret, id, sk, val = time(NULL) + i * 314;
char buf[4096];
struct sockaddr_un addr;
socklen_t addr_len;
id = getpid() * 10 + i;
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;
}
sks[i].sk = sk;
sks[i].val = val;
return 0;
}
static int check_sock(int i)
{
int sk = sks[i].sk, val = sks[i].val;
char buf[4096];
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)
return -1;
return 0;
}
int main()
{
int i, fd;
sigset_t set;
int sig;
for (i = 0; i < SK_NR; i++)
if (create_sock(i))
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");
for (i = 0; i < SK_NR; i++)
if (check_sock(i))
return -1;
printf("PASS\n");
return 0;
}
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <libgen.h>
#include <errno.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 "criu-log.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 -ENOTSUP;
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);
pr_err("%x: val %d\n", sk_id, e.val);
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(criu_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(criu_get_image_dir(), buf, O_RDONLY, 0600);
if (fd < 0)
return -ENOTSUP;
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;
}
pr_err("id %d val %d\n", sk_id, e->val);
ret = sprintf(buf, "t%d", e->val);
if (send(sk, buf, ret, 0) < 0) {
pr_perror("send");
return -1;
}
return sk;
}
#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;
}
id = 0;
switch (buf[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));
printf("t: id %d val %d\n", t->id, t->val);
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;
printf("r: id %d val %d\n", id, t->val);
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;
}
message unix_test {
required uint32 val = 1;
required bytes name = 2;
}
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