Line data Source code
1 : #include "../../burp.h"
2 : #include "../../action.h"
3 : #include "../../asfd.h"
4 : #include "../../async.h"
5 : #include "../../base64.h"
6 : #include "../../cmd.h"
7 : #include "../../cntr.h"
8 : #include "../../iobuf.h"
9 : #include "../../log.h"
10 : #include "../../protocol2/blk.h"
11 : #include "../../protocol2/blist.h"
12 : #include "../../protocol2/rabin/rabin.h"
13 : #include "../../slist.h"
14 : #include "rabin_read.h"
15 : #include "backup_phase2.h"
16 :
17 : #define END_SIGS 0x01
18 : #define END_BACKUP 0x02
19 : #define END_REQUESTS 0x04
20 : #define END_BLK_REQUESTS 0x08
21 :
22 22 : static int add_to_file_requests(struct slist *slist, struct iobuf *rbuf)
23 : {
24 : static uint64_t file_no=1;
25 : struct sbuf *sb;
26 :
27 22 : if(!(sb=sbuf_alloc(PROTO_2))) return -1;
28 :
29 22 : iobuf_move(&sb->path, rbuf);
30 : // Give it a number to simplify tracking.
31 22 : sb->protocol2->index=file_no++;
32 22 : slist_add_sbuf(slist, sb);
33 :
34 22 : return 0;
35 : }
36 :
37 3 : static int add_to_data_requests(struct blist *blist, struct iobuf *rbuf)
38 : {
39 : uint64_t index;
40 : struct blk *blk;
41 3 : index=base64_to_uint64(rbuf->buf);
42 :
43 : //printf("last_requested: %d\n", blist->last_requested->index);
44 :
45 : // Find the matching entry.
46 8 : for(blk=blist->last_requested; blk; blk=blk->next)
47 8 : if(index==blk->index) break;
48 3 : if(!blk)
49 : {
50 0 : logp("Could not find requested block %" PRIu64 "\n", index);
51 : return -1;
52 : }
53 3 : blk->requested=1;
54 3 : blist->last_requested=blk;
55 : //printf("Found %lu\n", index);
56 : return 0;
57 : }
58 :
59 38 : static int deal_with_read(struct iobuf *rbuf, struct slist *slist,
60 : struct cntr *cntr, uint8_t *end_flags)
61 : {
62 38 : int ret=0;
63 38 : switch(rbuf->cmd)
64 : {
65 : /* Incoming file request. */
66 : case CMD_FILE:
67 : case CMD_METADATA:
68 22 : if(add_to_file_requests(slist, rbuf)) goto error;
69 : return 0;
70 :
71 : /* Incoming data block request. */
72 : case CMD_DATA_REQ:
73 3 : if(add_to_data_requests(slist->blist, rbuf)) goto error;
74 : goto end;
75 :
76 : /* Incoming control/message stuff. */
77 : case CMD_WRAP_UP:
78 : {
79 : int64_t wrap_up;
80 : struct blk *blk;
81 1 : struct blist *blist=slist->blist;
82 1 : from_base64(&wrap_up, rbuf->buf);
83 2 : for(blk=blist->head; blk; blk=blk->next)
84 : {
85 2 : if(blk->index==(uint64_t)wrap_up)
86 : {
87 1 : blist->last_requested=blk;
88 1 : blist->last_sent=blk;
89 1 : break;
90 : }
91 : }
92 1 : if(!blk)
93 : {
94 0 : logp("Could not find wrap up index: %016" PRIX64 "\n",
95 : wrap_up);
96 : // goto error;
97 : }
98 : goto end;
99 : }
100 : case CMD_MESSAGE:
101 : case CMD_WARNING:
102 : {
103 1 : log_recvd(rbuf, cntr, 0);
104 1 : goto end;
105 : }
106 : case CMD_GEN:
107 9 : if(!strcmp(rbuf->buf, "requests_end"))
108 : {
109 3 : (*end_flags)|=END_REQUESTS;
110 3 : goto end;
111 : }
112 6 : else if(!strcmp(rbuf->buf, "blk_requests_end"))
113 : {
114 3 : (*end_flags)|=END_BLK_REQUESTS;
115 3 : goto end;
116 : }
117 3 : else if(!strcmp(rbuf->buf, "backup_end"))
118 : {
119 3 : (*end_flags)|=END_BACKUP;
120 3 : goto end;
121 : }
122 : break;
123 : default:
124 : break;
125 : }
126 :
127 2 : iobuf_log_unexpected(rbuf, __func__);
128 : error:
129 : ret=-1;
130 : end:
131 16 : iobuf_free_content(rbuf);
132 16 : return ret;
133 : }
134 :
135 92 : static int add_to_blks_list(struct asfd *asfd, struct conf **confs,
136 : struct slist *slist)
137 : {
138 92 : int just_opened=0;
139 92 : struct sbuf *sb=slist->last_requested;
140 92 : if(!sb) return 0;
141 :
142 41 : if(sb->protocol2->bfd.mode==BF_CLOSED)
143 : {
144 : char buf[32];
145 22 : struct cntr *cntr=NULL;
146 22 : if(confs) cntr=get_cntr(confs);
147 22 : switch(rabin_open_file(sb, asfd, cntr, confs))
148 : {
149 : case 1: // All OK.
150 : break;
151 : case 0: // Could not open file. Tell the server.
152 3 : base64_from_uint64(sb->protocol2->index, buf);
153 3 : if(asfd->write_str(asfd, CMD_INTERRUPT, buf))
154 3 : return -1;
155 3 : if(slist_del_sbuf(slist, sb))
156 : return -1;
157 3 : sbuf_free(&sb);
158 3 : return 0;
159 : default:
160 : return -1;
161 : }
162 19 : just_opened=1;
163 : }
164 :
165 38 : switch(blks_generate(sb, slist->blist, just_opened))
166 : {
167 : case 0: // All OK.
168 : break;
169 : case 1: // File ended.
170 19 : if(rabin_close_file(sb, asfd))
171 : {
172 0 : logp("Failed to close file %s\n",
173 0 : iobuf_to_printable(&sb->path));
174 0 : return -1;
175 : }
176 19 : slist->last_requested=sb->next;
177 19 : break;
178 : default:
179 : return -1;
180 : }
181 :
182 : return 0;
183 : }
184 :
185 97 : static void free_stuff(struct slist *slist)
186 : {
187 : struct blk *blk;
188 97 : struct blist *blist=slist->blist;
189 97 : blk=blist->head;
190 210 : while(blk && blk!=blist->last_sent)
191 : {
192 16 : if(blk==slist->head->protocol2->bstart)
193 0 : slist->head->protocol2->bstart=NULL;
194 16 : if(blk==slist->head->protocol2->bend)
195 : {
196 : struct sbuf *sb;
197 16 : sb=slist->head;
198 16 : sb->protocol2->bend=NULL;
199 16 : slist->head=slist->head->next;
200 16 : if(!slist->head)
201 0 : slist->tail=NULL;
202 16 : sbuf_free(&sb);
203 : }
204 16 : blk=blk->next;
205 16 : blk_free(&blist->head);
206 16 : blist->head=blk;
207 : }
208 97 : }
209 :
210 97 : static void get_wbuf_from_data(struct conf **confs,
211 : struct iobuf *wbuf, struct slist *slist, uint8_t end_flags)
212 : {
213 : struct blk *blk;
214 97 : struct blist *blist=slist->blist;
215 :
216 115 : for(blk=blist->last_sent; blk; blk=blk->next)
217 : {
218 99 : if(blk->requested)
219 : {
220 3 : iobuf_set(wbuf, CMD_DATA, blk->data, blk->length);
221 3 : blk->requested=0;
222 3 : blist->last_sent=blk;
223 3 : cntr_add(get_cntr(confs), CMD_DATA, 1);
224 3 : break;
225 : }
226 : else
227 : {
228 96 : cntr_add_same(get_cntr(confs), CMD_DATA);
229 96 : if(end_flags&END_BLK_REQUESTS)
230 : {
231 : // Force onwards when the server has said that
232 : // there are no more blocks to request.
233 13 : blist->last_sent=blk;
234 13 : continue;
235 : }
236 : }
237 83 : if(blk==blist->last_requested) break;
238 : }
239 : // Need to free stuff that is no longer needed.
240 97 : free_stuff(slist);
241 97 : }
242 :
243 : static int iobuf_from_blk_data(struct iobuf *wbuf, struct blk *blk)
244 : {
245 19 : if(blk_md5_update(blk)) return -1;
246 19 : blk_to_iobuf_sig(blk, wbuf);
247 : return 0;
248 : }
249 :
250 94 : static int get_wbuf_from_blks(struct iobuf *wbuf,
251 : struct slist *slist, uint8_t *end_flags)
252 : {
253 94 : struct sbuf *sb=slist->blks_to_send;
254 :
255 94 : if(!sb)
256 : {
257 43 : if((*end_flags)&END_REQUESTS && !((*end_flags)&END_SIGS))
258 : {
259 3 : iobuf_from_str(wbuf, CMD_GEN, (char *)"sigs_end");
260 3 : (*end_flags)|=END_SIGS;
261 : }
262 : return 0;
263 : }
264 51 : if(!sb->protocol2->bsighead) return 0;
265 :
266 38 : if(!(sb->flags & SBUF_SENT_STAT))
267 : {
268 19 : iobuf_copy(wbuf, &sb->attr);
269 19 : wbuf->cmd=CMD_ATTRIBS_SIGS; // hack
270 19 : sb->flags |= SBUF_SENT_STAT;
271 : return 0;
272 : }
273 :
274 38 : if(iobuf_from_blk_data(wbuf, sb->protocol2->bsighead)) return -1;
275 :
276 : // Move on.
277 19 : if(sb->protocol2->bsighead==sb->protocol2->bend)
278 : {
279 19 : slist->blks_to_send=sb->next;
280 19 : sb->protocol2->bsighead=sb->protocol2->bstart;
281 : }
282 : else
283 : {
284 0 : sb->protocol2->bsighead=sb->protocol2->bsighead->next;
285 : }
286 : return 0;
287 : }
288 :
289 8 : int backup_phase2_client_protocol2(struct asfd *asfd,
290 : struct conf **confs, int resume)
291 : {
292 8 : int ret=-1;
293 8 : uint8_t end_flags=0;
294 8 : struct slist *slist=NULL;
295 8 : struct iobuf *rbuf=NULL;
296 8 : struct iobuf *wbuf=NULL;
297 8 : struct cntr *cntr=NULL;
298 :
299 8 : if(confs) cntr=get_cntr(confs);
300 :
301 8 : if(!asfd || !asfd->as)
302 : {
303 1 : logp("%s() called without async structs!\n", __func__);
304 1 : goto end;
305 : }
306 :
307 7 : logp("Phase 2 begin (send backup data)\n");
308 7 : logfmt("\n");
309 :
310 7 : if(!(slist=slist_alloc())
311 7 : || !(wbuf=iobuf_alloc())
312 7 : || blks_generate_init())
313 : goto end;
314 7 : rbuf=asfd->rbuf;
315 :
316 7 : if(!resume)
317 : {
318 : // Only do this bit if the server did not tell us to resume.
319 7 : if(asfd->write_str(asfd, CMD_GEN, "backupphase2")
320 7 : || asfd_read_expect(asfd, CMD_GEN, "ok"))
321 : goto end;
322 : }
323 : else
324 : {
325 : // On resume, the server might update the client with cntr.
326 0 : if(cntr_recv(asfd, confs))
327 : goto end;
328 : }
329 :
330 97 : while(!(end_flags&END_BACKUP))
331 : {
332 97 : if(!wbuf->len)
333 : {
334 97 : get_wbuf_from_data(confs, wbuf, slist,
335 : end_flags);
336 97 : if(!wbuf->len)
337 : {
338 94 : if(get_wbuf_from_blks(wbuf, slist,
339 : &end_flags)) goto end;
340 : }
341 : }
342 :
343 97 : if(wbuf->len)
344 : {
345 44 : if(asfd->append_all_to_write_buffer(asfd, wbuf)
346 : ==APPEND_ERROR)
347 : goto end;
348 : }
349 97 : if(asfd->as->read_write(asfd->as))
350 : {
351 1 : logp("error in %s\n", __func__);
352 1 : goto end;
353 : }
354 :
355 96 : if(rbuf->buf && deal_with_read(rbuf, slist, cntr, &end_flags))
356 : goto end;
357 :
358 94 : if(slist->head
359 : // Need to limit how many blocks are allocated at once.
360 92 : && (!slist->blist->head
361 168 : || slist->blist->tail->index
362 84 : - slist->blist->head->index<BLKS_MAX_IN_MEM)
363 : )
364 : {
365 92 : if(add_to_blks_list(asfd, confs, slist))
366 : goto end;
367 : }
368 :
369 94 : if(end_flags&END_BLK_REQUESTS)
370 : {
371 : // If got to the end of the file request list
372 : // and the last block of the last file, and
373 : // the write buffer is empty, we got to the end.
374 6 : if(slist->head==slist->tail)
375 : {
376 3 : if(!slist->tail
377 6 : || slist->blist->last_sent==
378 3 : slist->tail->protocol2->bend)
379 : {
380 3 : if(!wbuf->len)
381 : break;
382 : }
383 : }
384 :
385 : }
386 : }
387 :
388 3 : if(asfd->write_str(asfd, CMD_GEN, "backup_end"))
389 : goto end;
390 :
391 3 : ret=0;
392 : end:
393 8 : slist_free(&slist);
394 8 : blks_generate_free();
395 8 : if(wbuf)
396 : {
397 : // Write buffer did not allocate 'buf'.
398 7 : wbuf->buf=NULL;
399 7 : iobuf_free(&wbuf);
400 : }
401 8 : cntr_print_end(cntr);
402 8 : cntr_print(cntr, ACTION_BACKUP, asfd);
403 8 : if(ret) logp("Error in backup\n");
404 8 : logp("End backup\n");
405 :
406 8 : return ret;
407 : }
|