2012-04-23 14:12:00 +04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/sendfile.h>
|
|
|
|
|
2013-01-09 17:02:47 +04:00
|
|
|
#include "asm/types.h"
|
2012-04-23 14:12:00 +04:00
|
|
|
#include "list.h"
|
|
|
|
#include "image.h"
|
|
|
|
#include "crtools.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "util-net.h"
|
2012-11-02 13:40:54 +04:00
|
|
|
#include "sockets.h"
|
2012-04-23 14:12:00 +04:00
|
|
|
|
|
|
|
#include "sk-queue.h"
|
|
|
|
|
2012-07-17 08:03:43 +04:00
|
|
|
#include "protobuf.h"
|
|
|
|
#include "protobuf/sk-packet.pb-c.h"
|
|
|
|
|
2012-07-13 21:05:00 +04:00
|
|
|
struct sk_packet {
|
|
|
|
struct list_head list;
|
2012-07-17 08:03:43 +04:00
|
|
|
SkPacketEntry *entry;
|
2012-07-13 21:05:00 +04:00
|
|
|
off_t img_off;
|
|
|
|
};
|
|
|
|
|
2012-04-23 14:12:00 +04:00
|
|
|
static LIST_HEAD(packets_list);
|
|
|
|
|
|
|
|
int read_sk_queues(void)
|
|
|
|
{
|
|
|
|
struct sk_packet *pkt;
|
|
|
|
int ret, fd;
|
|
|
|
|
|
|
|
pr_info("Trying to read socket queues image\n");
|
|
|
|
|
|
|
|
fd = open_image_ro(CR_FD_SK_QUEUES);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
while (1) {
|
2012-07-13 21:05:00 +04:00
|
|
|
ret = -1;
|
2012-04-23 14:12:00 +04:00
|
|
|
pkt = xmalloc(sizeof(*pkt));
|
|
|
|
if (!pkt) {
|
|
|
|
pr_err("Failed to allocate packet header\n");
|
2012-07-13 21:05:00 +04:00
|
|
|
break;
|
2012-04-23 14:12:00 +04:00
|
|
|
}
|
2012-08-07 02:42:58 +04:00
|
|
|
ret = pb_read_one_eof(fd, &pkt->entry, PB_SK_QUEUES);
|
2012-04-23 14:12:00 +04:00
|
|
|
if (ret <= 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
pkt->img_off = lseek(fd, 0, SEEK_CUR);
|
|
|
|
/*
|
|
|
|
* NOTE: packet must be added to the tail. Otherwise sequence
|
|
|
|
* will be broken.
|
|
|
|
*/
|
|
|
|
list_add_tail(&pkt->list, &packets_list);
|
2012-07-13 21:05:00 +04:00
|
|
|
lseek(fd, pkt->entry->length, SEEK_CUR);
|
2012-04-23 14:12:00 +04:00
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
xfree(pkt);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int dump_sk_queue(int sock_fd, int sock_id)
|
|
|
|
{
|
2012-07-17 08:03:43 +04:00
|
|
|
SkPacketEntry pe = SK_PACKET_ENTRY__INIT;
|
2012-07-13 17:57:00 +04:00
|
|
|
int ret, size, orig_peek_off;
|
2012-07-17 08:03:43 +04:00
|
|
|
void *data;
|
2012-04-23 14:12:00 +04:00
|
|
|
socklen_t tmp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Save original peek offset.
|
|
|
|
*/
|
|
|
|
tmp = sizeof(orig_peek_off);
|
2012-07-13 17:57:00 +04:00
|
|
|
orig_peek_off = 0;
|
2012-04-23 14:12:00 +04:00
|
|
|
ret = getsockopt(sock_fd, SOL_SOCKET, SO_PEEK_OFF, &orig_peek_off, &tmp);
|
|
|
|
if (ret < 0) {
|
|
|
|
pr_perror("getsockopt failed\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Discover max DGRAM size
|
|
|
|
*/
|
|
|
|
tmp = sizeof(size);
|
2012-07-13 17:57:00 +04:00
|
|
|
size = 0;
|
2012-04-23 14:12:00 +04:00
|
|
|
ret = getsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF, &size, &tmp);
|
|
|
|
if (ret < 0) {
|
|
|
|
pr_perror("getsockopt failed\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Note: 32 bytes will be used by kernel for protocol header. */
|
|
|
|
size -= 32;
|
2012-07-17 08:03:43 +04:00
|
|
|
|
2012-04-23 14:12:00 +04:00
|
|
|
/*
|
2012-07-17 08:03:43 +04:00
|
|
|
* Allocate data for a streem.
|
2012-04-23 14:12:00 +04:00
|
|
|
*/
|
2012-07-17 08:03:43 +04:00
|
|
|
data = xmalloc(size);
|
|
|
|
if (!data)
|
|
|
|
return -1;
|
2012-04-23 14:12:00 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Enable peek offset incrementation.
|
|
|
|
*/
|
|
|
|
ret = setsockopt(sock_fd, SOL_SOCKET, SO_PEEK_OFF, &ret, sizeof(int));
|
|
|
|
if (ret < 0) {
|
|
|
|
pr_perror("setsockopt fail\n");
|
|
|
|
goto err_brk;
|
|
|
|
}
|
|
|
|
|
2012-07-17 08:03:43 +04:00
|
|
|
pe.id_for = sock_id;
|
2012-04-23 14:12:00 +04:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
struct iovec iov = {
|
2012-07-17 08:03:43 +04:00
|
|
|
.iov_base = data,
|
2012-04-23 14:12:00 +04:00
|
|
|
.iov_len = size,
|
|
|
|
};
|
|
|
|
struct msghdr msg = {
|
|
|
|
.msg_iov = &iov,
|
|
|
|
.msg_iovlen = 1,
|
|
|
|
};
|
|
|
|
|
2012-07-17 08:03:43 +04:00
|
|
|
ret = pe.length = recvmsg(sock_fd, &msg, MSG_DONTWAIT | MSG_PEEK);
|
2012-04-23 14:12:00 +04:00
|
|
|
if (ret < 0) {
|
2012-09-28 14:02:04 +04:00
|
|
|
if (errno == EAGAIN)
|
2012-04-23 14:12:00 +04:00
|
|
|
break; /* we're done */
|
2012-09-28 14:02:04 +04:00
|
|
|
pr_perror("recvmsg fail: error\n");
|
2012-04-23 14:12:00 +04:00
|
|
|
goto err_set_sock;
|
|
|
|
}
|
|
|
|
if (msg.msg_flags & MSG_TRUNC) {
|
|
|
|
/*
|
|
|
|
* DGRAM thuncated. This should not happen. But we have
|
|
|
|
* to check...
|
|
|
|
*/
|
|
|
|
pr_err("sys_recvmsg failed: truncated\n");
|
|
|
|
ret = -E2BIG;
|
|
|
|
goto err_set_sock;
|
|
|
|
}
|
2012-07-17 08:03:43 +04:00
|
|
|
|
2012-08-07 02:26:50 +04:00
|
|
|
ret = pb_write_one(fdset_fd(glob_fdset, CR_FD_SK_QUEUES), &pe, PB_SK_QUEUES);
|
2012-07-17 08:03:43 +04:00
|
|
|
if (ret < 0) {
|
|
|
|
ret = -EIO;
|
|
|
|
goto err_set_sock;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = write_img_buf(fdset_fd(glob_fdset, CR_FD_SK_QUEUES), data, pe.length);
|
2012-04-23 14:12:00 +04:00
|
|
|
if (ret < 0) {
|
|
|
|
ret = -EIO;
|
|
|
|
goto err_set_sock;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
err_set_sock:
|
|
|
|
/*
|
|
|
|
* Restore original peek offset.
|
|
|
|
*/
|
2012-09-28 14:02:50 +04:00
|
|
|
if (setsockopt(sock_fd, SOL_SOCKET, SO_PEEK_OFF, &orig_peek_off, sizeof(int))) {
|
2012-04-23 14:12:00 +04:00
|
|
|
pr_perror("setsockopt failed on restore\n");
|
2012-09-28 14:02:50 +04:00
|
|
|
ret = -1;
|
|
|
|
}
|
2012-04-23 14:12:00 +04:00
|
|
|
err_brk:
|
2012-07-17 08:03:43 +04:00
|
|
|
xfree(data);
|
2012-04-23 14:12:00 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-07-26 12:43:00 +04:00
|
|
|
static void sk_queue_data_handler(int fd, void *obj, int show_pages_content)
|
2012-04-23 14:12:00 +04:00
|
|
|
{
|
2012-07-25 18:33:20 +04:00
|
|
|
SkPacketEntry *e = obj;
|
2012-12-10 18:57:54 +03:00
|
|
|
print_image_data(fd, e->length, show_pages_content);
|
2012-07-25 18:33:20 +04:00
|
|
|
}
|
2012-04-23 14:12:00 +04:00
|
|
|
|
2012-07-25 18:33:20 +04:00
|
|
|
void show_sk_queues(int fd, struct cr_options *o)
|
|
|
|
{
|
2012-08-07 02:51:34 +04:00
|
|
|
pb_show_plain_payload(fd, PB_SK_QUEUES,
|
2012-07-26 12:43:00 +04:00
|
|
|
sk_queue_data_handler, o->show_pages_content);
|
2012-04-23 14:12:00 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int restore_sk_queue(int fd, unsigned int peer_id)
|
|
|
|
{
|
|
|
|
struct sk_packet *pkt, *tmp;
|
2012-11-02 13:40:54 +04:00
|
|
|
int ret, img_fd;
|
2012-04-23 14:12:00 +04:00
|
|
|
|
|
|
|
pr_info("Trying to restore recv queue for %u\n", peer_id);
|
|
|
|
|
2012-11-02 13:40:54 +04:00
|
|
|
if (restore_prepare_socket(fd))
|
2012-09-28 16:42:15 +04:00
|
|
|
return -1;
|
|
|
|
|
2012-04-23 14:12:00 +04:00
|
|
|
img_fd = open_image_ro(CR_FD_SK_QUEUES);
|
|
|
|
if (img_fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
list_for_each_entry_safe(pkt, tmp, &packets_list, list) {
|
2012-07-17 08:03:43 +04:00
|
|
|
SkPacketEntry *entry = pkt->entry;
|
2012-09-28 16:44:05 +04:00
|
|
|
char *buf;
|
2012-04-23 14:12:00 +04:00
|
|
|
|
|
|
|
if (entry->id_for != peer_id)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
pr_info("\tRestoring %d-bytes skb for %u\n",
|
2012-07-17 08:03:43 +04:00
|
|
|
(unsigned int)entry->length, peer_id);
|
2012-04-23 14:12:00 +04:00
|
|
|
|
2012-09-28 16:44:05 +04:00
|
|
|
/*
|
|
|
|
* Don't try to use sendfile here, because it use sendpage() and
|
|
|
|
* all data are splitted on pages and a new skb is allocated for
|
|
|
|
* each page. It creates a big overhead on SNDBUF.
|
|
|
|
* sendfile() isn't suatable for DGRAM sockets, because message
|
|
|
|
* boundaries messages should be saved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
buf = xmalloc(entry->length);
|
|
|
|
if (buf ==NULL)
|
2012-10-24 16:51:50 +04:00
|
|
|
goto err;
|
2012-09-28 16:44:05 +04:00
|
|
|
|
|
|
|
if (lseek(img_fd, pkt->img_off, SEEK_SET) == -1) {
|
|
|
|
pr_perror("lseek() failed");
|
|
|
|
xfree(buf);
|
2012-10-24 16:51:50 +04:00
|
|
|
goto err;
|
2012-09-28 16:44:05 +04:00
|
|
|
}
|
|
|
|
if (read_img_buf(img_fd, buf, entry->length) != 1) {
|
|
|
|
xfree(buf);
|
2012-10-24 16:51:50 +04:00
|
|
|
goto err;
|
2012-09-28 16:44:05 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = write(fd, buf, entry->length);
|
|
|
|
xfree(buf);
|
2012-04-23 14:12:00 +04:00
|
|
|
if (ret < 0) {
|
2012-09-28 16:44:05 +04:00
|
|
|
pr_perror("Failed to send packet");
|
2012-10-24 16:51:50 +04:00
|
|
|
goto err;
|
2012-04-23 14:12:00 +04:00
|
|
|
}
|
|
|
|
if (ret != entry->length) {
|
|
|
|
pr_err("Restored skb trimmed to %d/%d\n",
|
2012-07-17 08:03:43 +04:00
|
|
|
ret, (unsigned int)entry->length);
|
2012-10-24 16:51:50 +04:00
|
|
|
goto err;
|
2012-04-23 14:12:00 +04:00
|
|
|
}
|
|
|
|
list_del(&pkt->list);
|
2012-07-17 08:03:43 +04:00
|
|
|
sk_packet_entry__free_unpacked(entry, NULL);
|
2012-04-23 14:12:00 +04:00
|
|
|
xfree(pkt);
|
|
|
|
}
|
|
|
|
|
|
|
|
close(img_fd);
|
|
|
|
return 0;
|
2012-10-24 16:51:50 +04:00
|
|
|
err:
|
|
|
|
close_safe(&img_fd);
|
|
|
|
return -1;
|
2012-04-23 14:12:00 +04:00
|
|
|
}
|