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