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 :
16 : #define END_SIGS 0x01
17 : #define END_BACKUP 0x02
18 : #define END_REQUESTS 0x04
19 : #define END_BLK_REQUESTS 0x08
20 :
21 22 : static int add_to_file_requests(struct slist *slist, struct iobuf *rbuf)
22 : {
23 : static uint64_t file_no=1;
24 : struct sbuf *sb;
25 :
26 22 : if(!(sb=sbuf_alloc(PROTO_2))) return -1;
27 :
28 22 : iobuf_move(&sb->path, rbuf);
29 : // Give it a number to simplify tracking.
30 22 : sb->protocol2->index=file_no++;
31 22 : slist_add_sbuf(slist, sb);
32 :
33 22 : return 0;
34 : }
35 :
36 3 : static int add_to_data_requests(struct blist *blist, struct iobuf *rbuf)
37 : {
38 : uint64_t index;
39 : struct blk *blk;
40 3 : index=base64_to_uint64(rbuf->buf);
41 :
42 : //printf("last_requested: %d\n", blist->last_requested->index);
43 :
44 : // Find the matching entry.
45 8 : for(blk=blist->last_requested; blk; blk=blk->next)
46 8 : if(index==blk->index) break;
47 3 : if(!blk)
48 : {
49 0 : logp("Could not find requested block %" PRIu64 "\n", index);
50 : return -1;
51 : }
52 3 : blk->requested=1;
53 3 : blist->last_requested=blk;
54 : //printf("Found %lu\n", index);
55 : return 0;
56 : }
57 :
58 41 : static int deal_with_read(struct iobuf *rbuf, struct slist *slist,
59 : struct cntr *cntr, uint8_t *end_flags)
60 : {
61 38 : int ret=0;
62 38 : switch(rbuf->cmd)
63 : {
64 : /* Incoming file request. */
65 : case CMD_FILE:
66 : case CMD_METADATA:
67 22 : if(add_to_file_requests(slist, rbuf)) goto error;
68 : return 0;
69 :
70 : /* Incoming data block request. */
71 : case CMD_DATA_REQ:
72 6 : if(add_to_data_requests(slist->blist, rbuf)) goto error;
73 : goto end;
74 :
75 : /* Incoming control/message stuff. */
76 : case CMD_WRAP_UP:
77 : {
78 : int64_t wrap_up;
79 : struct blk *blk;
80 1 : struct blist *blist=slist->blist;
81 1 : from_base64(&wrap_up, rbuf->buf);
82 2 : for(blk=blist->head; blk; blk=blk->next)
83 : {
84 2 : if(blk->index==(uint64_t)wrap_up)
85 : {
86 1 : blist->last_requested=blk;
87 1 : blist->last_sent=blk;
88 1 : break;
89 : }
90 : }
91 1 : if(!blk)
92 : {
93 : logp("Could not find wrap up index: %016" PRIX64 "\n",
94 0 : wrap_up);
95 : // goto error;
96 : }
97 : goto end;
98 : }
99 : case CMD_MESSAGE:
100 : case CMD_WARNING:
101 : {
102 1 : log_recvd(rbuf, cntr, 0);
103 1 : goto end;
104 : }
105 : case CMD_GEN:
106 9 : if(!strcmp(rbuf->buf, "requests_end"))
107 : {
108 3 : (*end_flags)|=END_REQUESTS;
109 3 : goto end;
110 : }
111 6 : else if(!strcmp(rbuf->buf, "blk_requests_end"))
112 : {
113 3 : (*end_flags)|=END_BLK_REQUESTS;
114 3 : goto end;
115 : }
116 3 : else if(!strcmp(rbuf->buf, "backup_end"))
117 : {
118 3 : (*end_flags)|=END_BACKUP;
119 3 : goto end;
120 : }
121 : break;
122 : default:
123 : break;
124 : }
125 :
126 2 : iobuf_log_unexpected(rbuf, __func__);
127 : error:
128 : ret=-1;
129 : end:
130 16 : iobuf_free_content(rbuf);
131 16 : return ret;
132 : }
133 :
134 92 : static int add_to_blks_list(struct asfd *asfd, struct conf **confs,
135 : struct slist *slist)
136 : {
137 92 : int just_opened=0;
138 92 : struct sbuf *sb=slist->last_requested;
139 92 : if(!sb) return 0;
140 :
141 41 : if(sb->protocol2->bfd.mode==BF_CLOSED)
142 : {
143 22 : struct cntr *cntr=NULL;
144 22 : if(confs) cntr=get_cntr(confs);
145 22 : switch(rabin_open_file(sb, asfd, cntr, confs))
146 : {
147 : case 1: // All OK.
148 19 : break;
149 : case 0: // Could not open file. Tell the server.
150 : char buf[32];
151 3 : base64_from_uint64(sb->protocol2->index, buf);
152 3 : if(asfd->write_str(asfd, CMD_INTERRUPT, buf))
153 3 : return -1;
154 3 : if(slist_del_sbuf(slist, sb))
155 : return -1;
156 3 : sbuf_free(&sb);
157 3 : return 0;
158 : default:
159 : return -1;
160 : }
161 19 : just_opened=1;
162 : }
163 :
164 38 : switch(blks_generate(asfd, confs, sb, slist->blist, just_opened))
165 : {
166 : case 0: // All OK.
167 : break;
168 : case 1: // File ended.
169 19 : if(rabin_close_file(sb, asfd))
170 : {
171 : logp("Failed to close file %s\n",
172 0 : sb->path.buf);
173 0 : return -1;
174 : }
175 19 : slist->last_requested=sb->next;
176 19 : break;
177 : default:
178 : return -1;
179 : }
180 :
181 : return 0;
182 : }
183 :
184 97 : static void free_stuff(struct slist *slist)
185 : {
186 : struct blk *blk;
187 97 : struct blist *blist=slist->blist;
188 97 : blk=blist->head;
189 210 : while(blk && blk!=blist->last_sent)
190 : {
191 16 : if(blk==slist->head->protocol2->bstart)
192 0 : slist->head->protocol2->bstart=NULL;
193 16 : if(blk==slist->head->protocol2->bend)
194 : {
195 : struct sbuf *sb;
196 16 : sb=slist->head;
197 16 : sb->protocol2->bend=NULL;
198 16 : slist->head=slist->head->next;
199 16 : if(!slist->head)
200 0 : slist->tail=NULL;
201 16 : sbuf_free(&sb);
202 : }
203 16 : blk=blk->next;
204 16 : blk_free(&blist->head);
205 16 : blist->head=blk;
206 : }
207 97 : }
208 :
209 97 : static void get_wbuf_from_data(struct conf **confs,
210 : struct iobuf *wbuf, struct slist *slist, uint8_t end_flags)
211 : {
212 : struct blk *blk;
213 97 : struct blist *blist=slist->blist;
214 :
215 115 : for(blk=blist->last_sent; blk; blk=blk->next)
216 : {
217 99 : if(blk->requested)
218 : {
219 3 : iobuf_set(wbuf, CMD_DATA, blk->data, blk->length);
220 3 : blk->requested=0;
221 3 : blist->last_sent=blk;
222 3 : cntr_add(get_cntr(confs), CMD_DATA, 1);
223 3 : cntr_add_sentbytes(get_cntr(confs), blk->length);
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 19 : 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 19 : 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 19 : 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 : logf("\n");
309 :
310 14 : if(!(slist=slist_alloc())
311 7 : || !(wbuf=iobuf_alloc())
312 14 : || 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 14 : if(asfd->write_str(asfd, CMD_GEN, "backupphase2")
320 7 : || asfd_read_expect(asfd, CMD_GEN, "ok"))
321 : goto end;
322 : }
323 0 : else if(get_int(confs[OPT_SEND_CLIENT_CNTR]))
324 : {
325 : // On resume, the server might update the client with the
326 : // counters.
327 0 : if(cntr_recv(asfd, confs))
328 : goto end;
329 : }
330 :
331 97 : while(!(end_flags&END_BACKUP))
332 : {
333 97 : if(!wbuf->len)
334 : {
335 : get_wbuf_from_data(confs, wbuf, slist,
336 97 : end_flags);
337 97 : if(!wbuf->len)
338 : {
339 94 : if(get_wbuf_from_blks(wbuf, slist,
340 94 : &end_flags)) goto end;
341 : }
342 : }
343 :
344 97 : if(wbuf->len)
345 : {
346 44 : if(asfd->append_all_to_write_buffer(asfd, wbuf)
347 44 : ==APPEND_ERROR)
348 : goto end;
349 : }
350 97 : if(asfd->as->read_write(asfd->as))
351 : {
352 1 : logp("error in %s\n", __func__);
353 1 : goto end;
354 : }
355 :
356 96 : if(rbuf->buf && deal_with_read(rbuf, slist, cntr, &end_flags))
357 : goto end;
358 :
359 94 : if(slist->head
360 : // Need to limit how many blocks are allocated at once.
361 92 : && (!slist->blist->head
362 84 : || slist->blist->tail->index
363 84 : - slist->blist->head->index<BLKS_MAX_IN_MEM)
364 : )
365 : {
366 92 : if(add_to_blks_list(asfd, confs, slist))
367 : goto end;
368 : }
369 :
370 94 : if(end_flags&END_BLK_REQUESTS)
371 : {
372 : // If got to the end of the file request list
373 : // and the last block of the last file, and
374 : // the write buffer is empty, we got to the end.
375 6 : if(slist->head==slist->tail)
376 : {
377 3 : if(!slist->tail
378 3 : || slist->blist->last_sent==
379 : slist->tail->protocol2->bend)
380 : {
381 3 : if(!wbuf->len)
382 : break;
383 : }
384 : }
385 :
386 : }
387 : }
388 :
389 3 : if(asfd->write_str(asfd, CMD_GEN, "backup_end"))
390 : goto end;
391 :
392 3 : ret=0;
393 : end:
394 8 : slist_free(&slist);
395 8 : blks_generate_free();
396 8 : if(wbuf)
397 : {
398 : // Write buffer did not allocate 'buf'.
399 7 : wbuf->buf=NULL;
400 7 : iobuf_free(&wbuf);
401 : }
402 8 : cntr_print_end(cntr);
403 8 : cntr_print(cntr, ACTION_BACKUP);
404 8 : if(ret) logp("Error in backup\n");
405 8 : logp("End backup\n");
406 :
407 8 : return ret;
408 : }
|