Branch data Line data Source code
1 : : #include <stdio.h>
2 : : #include <stdlib.h>
3 : : #include <errno.h>
4 : : #include <unistd.h>
5 : : #include <fcntl.h>
6 : : #include <limits.h>
7 : :
8 : : #include <sys/types.h>
9 : : #include <sys/stat.h>
10 : : #include <sys/socket.h>
11 : : #include <sys/sendfile.h>
12 : :
13 : : #include "types.h"
14 : : #include "list.h"
15 : : #include "image.h"
16 : : #include "crtools.h"
17 : : #include "util.h"
18 : : #include "util-net.h"
19 : : #include "sockets.h"
20 : :
21 : : #include "sk-queue.h"
22 : :
23 : : #include "protobuf.h"
24 : : #include "protobuf/sk-packet.pb-c.h"
25 : :
26 : : struct sk_packet {
27 : : struct list_head list;
28 : : SkPacketEntry *entry;
29 : : off_t img_off;
30 : : };
31 : :
32 : : static LIST_HEAD(packets_list);
33 : :
34 : 355 : int read_sk_queues(void)
35 : : {
36 : : struct sk_packet *pkt;
37 : : int ret, fd;
38 : :
39 : 355 : pr_info("Trying to read socket queues image\n");
40 : :
41 : 355 : fd = open_image_ro(CR_FD_SK_QUEUES);
42 [ + - ]: 355 : if (fd < 0)
43 : : return -1;
44 : :
45 : : while (1) {
46 : 382 : ret = -1;
47 [ - + ]: 382 : pkt = xmalloc(sizeof(*pkt));
48 [ - + ]: 382 : if (!pkt) {
49 : 0 : pr_err("Failed to allocate packet header\n");
50 : 0 : break;
51 : : }
52 : 382 : ret = pb_read_one_eof(fd, &pkt->entry, PB_SK_QUEUES);
53 [ + + ]: 382 : if (ret <= 0)
54 : : break;
55 : :
56 : 27 : pkt->img_off = lseek(fd, 0, SEEK_CUR);
57 : : /*
58 : : * NOTE: packet must be added to the tail. Otherwise sequence
59 : : * will be broken.
60 : : */
61 : 27 : list_add_tail(&pkt->list, &packets_list);
62 : 27 : lseek(fd, pkt->entry->length, SEEK_CUR);
63 : 27 : }
64 : 355 : close(fd);
65 [ + - ]: 355 : xfree(pkt);
66 : :
67 : 355 : return ret;
68 : : }
69 : :
70 : 10 : int dump_sk_queue(int sock_fd, int sock_id)
71 : : {
72 : 10 : SkPacketEntry pe = SK_PACKET_ENTRY__INIT;
73 : : int ret, size, orig_peek_off;
74 : : void *data;
75 : : socklen_t tmp;
76 : :
77 : : /*
78 : : * Save original peek offset.
79 : : */
80 : 10 : tmp = sizeof(orig_peek_off);
81 : 10 : orig_peek_off = 0;
82 : 10 : ret = getsockopt(sock_fd, SOL_SOCKET, SO_PEEK_OFF, &orig_peek_off, &tmp);
83 [ - + ]: 10 : if (ret < 0) {
84 : 0 : pr_perror("getsockopt failed\n");
85 : 0 : return ret;
86 : : }
87 : : /*
88 : : * Discover max DGRAM size
89 : : */
90 : 10 : tmp = sizeof(size);
91 : 10 : size = 0;
92 : 10 : ret = getsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF, &size, &tmp);
93 [ - + ]: 10 : if (ret < 0) {
94 : 0 : pr_perror("getsockopt failed\n");
95 : 0 : return ret;
96 : : }
97 : :
98 : : /* Note: 32 bytes will be used by kernel for protocol header. */
99 : 10 : size -= 32;
100 : :
101 : : /*
102 : : * Allocate data for a streem.
103 : : */
104 [ - + ]: 10 : data = xmalloc(size);
105 [ + - ]: 10 : if (!data)
106 : : return -1;
107 : :
108 : : /*
109 : : * Enable peek offset incrementation.
110 : : */
111 : 10 : ret = setsockopt(sock_fd, SOL_SOCKET, SO_PEEK_OFF, &ret, sizeof(int));
112 [ - + ]: 10 : if (ret < 0) {
113 : 0 : pr_perror("setsockopt fail\n");
114 : 0 : goto err_brk;
115 : : }
116 : :
117 : 10 : pe.id_for = sock_id;
118 : :
119 : : while (1) {
120 : 28 : struct iovec iov = {
121 : : .iov_base = data,
122 : : .iov_len = size,
123 : : };
124 : 28 : struct msghdr msg = {
125 : : .msg_iov = &iov,
126 : : .msg_iovlen = 1,
127 : : };
128 : :
129 : 28 : ret = pe.length = recvmsg(sock_fd, &msg, MSG_DONTWAIT | MSG_PEEK);
130 [ + + ]: 28 : if (ret < 0) {
131 [ - + ]: 10 : if (errno == EAGAIN)
132 : : break; /* we're done */
133 : 0 : pr_perror("recvmsg fail: error\n");
134 : : goto err_set_sock;
135 : : }
136 [ - + ]: 18 : if (msg.msg_flags & MSG_TRUNC) {
137 : : /*
138 : : * DGRAM thuncated. This should not happen. But we have
139 : : * to check...
140 : : */
141 : 0 : pr_err("sys_recvmsg failed: truncated\n");
142 : 0 : ret = -E2BIG;
143 : : goto err_set_sock;
144 : : }
145 : :
146 : 18 : ret = pb_write_one(fdset_fd(glob_fdset, CR_FD_SK_QUEUES), &pe, PB_SK_QUEUES);
147 [ - + ]: 18 : if (ret < 0) {
148 : 0 : ret = -EIO;
149 : : goto err_set_sock;
150 : : }
151 : :
152 : 18 : ret = write_img_buf(fdset_fd(glob_fdset, CR_FD_SK_QUEUES), data, pe.length);
153 [ - + ]: 18 : if (ret < 0) {
154 : 0 : ret = -EIO;
155 : : goto err_set_sock;
156 : : }
157 : 18 : }
158 : 10 : ret = 0;
159 : :
160 : : err_set_sock:
161 : : /*
162 : : * Restore original peek offset.
163 : : */
164 [ - + ]: 10 : if (setsockopt(sock_fd, SOL_SOCKET, SO_PEEK_OFF, &orig_peek_off, sizeof(int))) {
165 : 0 : pr_perror("setsockopt failed on restore\n");
166 : 0 : ret = -1;
167 : : }
168 : : err_brk:
169 [ + - ]: 10 : xfree(data);
170 : 10 : return ret;
171 : : }
172 : :
173 : 0 : static void sk_queue_data_handler(int fd, void *obj, int show_pages_content)
174 : : {
175 : 0 : SkPacketEntry *e = obj;
176 : 0 : print_image_data(fd, e->length, show_pages_content);
177 : 0 : }
178 : :
179 : 0 : void show_sk_queues(int fd, struct cr_options *o)
180 : : {
181 : 0 : pb_show_plain_payload(fd, PB_SK_QUEUES,
182 : : sk_queue_data_handler, o->show_pages_content);
183 : 0 : }
184 : :
185 : 45 : int restore_sk_queue(int fd, unsigned int peer_id)
186 : : {
187 : : struct sk_packet *pkt, *tmp;
188 : : int ret, img_fd;
189 : :
190 : 45 : pr_info("Trying to restore recv queue for %u\n", peer_id);
191 : :
192 [ + - ]: 45 : if (restore_prepare_socket(fd))
193 : : return -1;
194 : :
195 : 45 : img_fd = open_image_ro(CR_FD_SK_QUEUES);
196 [ + - ]: 45 : if (img_fd < 0)
197 : : return -1;
198 : :
199 [ + + ]: 103 : list_for_each_entry_safe(pkt, tmp, &packets_list, list) {
200 : 58 : SkPacketEntry *entry = pkt->entry;
201 : : char *buf;
202 : :
203 [ + + ]: 58 : if (entry->id_for != peer_id)
204 : 40 : continue;
205 : :
206 : 18 : pr_info("\tRestoring %d-bytes skb for %u\n",
207 : : (unsigned int)entry->length, peer_id);
208 : :
209 : : /*
210 : : * Don't try to use sendfile here, because it use sendpage() and
211 : : * all data are splitted on pages and a new skb is allocated for
212 : : * each page. It creates a big overhead on SNDBUF.
213 : : * sendfile() isn't suatable for DGRAM sockets, because message
214 : : * boundaries messages should be saved.
215 : : */
216 : :
217 [ - + ]: 18 : buf = xmalloc(entry->length);
218 [ + - ]: 18 : if (buf ==NULL)
219 : : goto err;
220 : :
221 [ - + ]: 18 : if (lseek(img_fd, pkt->img_off, SEEK_SET) == -1) {
222 : 0 : pr_perror("lseek() failed");
223 [ # # ]: 0 : xfree(buf);
224 : : goto err;
225 : : }
226 [ - + ]: 18 : if (read_img_buf(img_fd, buf, entry->length) != 1) {
227 [ # # ]: 0 : xfree(buf);
228 : : goto err;
229 : : }
230 : :
231 : 18 : ret = write(fd, buf, entry->length);
232 [ + - ]: 18 : xfree(buf);
233 [ - + ]: 18 : if (ret < 0) {
234 : 0 : pr_perror("Failed to send packet");
235 : 0 : goto err;
236 : : }
237 [ - + ]: 18 : if (ret != entry->length) {
238 : 0 : pr_err("Restored skb trimmed to %d/%d\n",
239 : : ret, (unsigned int)entry->length);
240 : 0 : goto err;
241 : : }
242 : 18 : list_del(&pkt->list);
243 : 18 : sk_packet_entry__free_unpacked(entry, NULL);
244 [ + - ]: 18 : xfree(pkt);
245 : : }
246 : :
247 : 45 : close(img_fd);
248 : : return 0;
249 : : err:
250 : 45 : close_safe(&img_fd);
251 : : return -1;
252 : : }
|