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