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