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