1 /*********************************************************************/
2 // dar - disk archive - a backup/restoration program
3 // Copyright (C) 2002-2052 Denis Corbin
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 //
19 // to contact the author : http://dar.linux.free.fr/email.html
20 /*********************************************************************/
21 
22 #include "../my_config.h"
23 
24 extern "C"
25 {
26 } // end extern "C"
27 
28 #include "messaging.hpp"
29 #include "tools.hpp"
30 
31 using namespace std;
32 
33 namespace libdar
34 {
35 
msg_equivalent(msg_type arg1,msg_type arg2)36     bool msg_equivalent(msg_type arg1, msg_type arg2)
37     {
38 	bool ret = false;
39 	switch(arg1)
40 	{
41 	case msg_type::order_read_ahead:
42 	case msg_type::order_read_ahead_begin:
43 	    if(arg2 == msg_type::order_read_ahead
44 	       || arg2 == msg_type::order_read_ahead_begin)
45 		ret = true;
46 	    break;
47 	case msg_type::order_skip:
48 	case msg_type::order_skip_begin:
49 	    if(arg2 == msg_type::order_skip
50 	       || arg2 == msg_type::order_skip_begin)
51 		ret = true;
52 	    break;
53 	case msg_type::order_skippable_fwd:
54 	case msg_type::order_skippable_fwd_begin:
55 	    if(arg2 == msg_type::order_skippable_fwd
56 	       || arg2 == msg_type::order_skippable_fwd_begin)
57 		ret = true;
58 	    break;
59 	case msg_type::order_skippable_bkd:
60 	case msg_type::order_skippable_bkd_begin:
61 	    if(arg2 == msg_type::order_skippable_bkd
62 	       || arg2 == msg_type::order_skippable_bkd_begin)
63 		ret = true;
64 	    break;
65 	case msg_type::answr_position:
66 	case msg_type::answr_position_begin:
67 	    if(arg2 == msg_type::answr_position
68 	       || arg2 == msg_type::answr_position_begin)
69 		ret = true;
70 	    break;
71 	case msg_type::unset:
72 	case msg_type::order_read:
73 	case msg_type::order_sync_write:
74 	case msg_type::answr_sync_write_done:
75 	case msg_type::order_skip_to_eof:
76 	case msg_type::order_skip_fwd:
77 	case msg_type::order_skip_bkd:
78 	case msg_type::answr_skip_done:
79 	case msg_type::answr_skippable:
80 	case msg_type::order_get_position:
81 	case msg_type::answr_exception:
82 	case msg_type::order_end_of_xmit:
83 	case msg_type::order_stop_readahead:
84 	case msg_type::answr_readahead_stopped:
85 	case msg_type::order_wakeup:
86 	    ret = (arg1 == arg2);
87 	    break;
88 	case msg_type::data_partial:
89 	case msg_type::data_completed:
90 	    if(arg2 == msg_type::data_partial
91 	       || arg2 == msg_type::data_completed)
92 		ret = true;
93 	    break;
94 	default:
95 	    throw SRC_BUG;
96 	}
97 
98 	return ret;
99     }
100 
msg_continues(msg_type msg)101     bool msg_continues(msg_type msg)
102     {
103 	switch(msg)
104 	{
105 	case msg_type::order_read_ahead_begin:
106 	case msg_type::order_skip_begin:
107 	case msg_type::order_skippable_fwd_begin:
108 	case msg_type::order_skippable_bkd_begin:
109 	case msg_type::answr_position_begin:
110 	    return true;
111 	case msg_type::unset:
112 	case msg_type::order_read_ahead:
113 	case msg_type::order_read:
114 	case msg_type::order_sync_write:
115 	case msg_type::answr_sync_write_done:
116 	case msg_type::order_skip:
117 	case msg_type::order_skip_to_eof:
118 	case msg_type::order_skip_fwd:
119 	case msg_type::order_skip_bkd:
120 	case msg_type::answr_skip_done:
121 	case msg_type::order_skippable_fwd:
122 	case msg_type::order_skippable_bkd:
123 	case msg_type::answr_skippable:
124 	case msg_type::order_get_position:
125 	case msg_type::answr_position:
126 	case msg_type::answr_exception:
127 	case msg_type::order_end_of_xmit:
128 	case msg_type::order_stop_readahead:
129 	case msg_type::answr_readahead_stopped:
130 	case msg_type::order_wakeup:
131 	case msg_type::data_partial: // this is not an error
132 	case msg_type::data_completed:
133 	    return false;
134 	default:
135 	    throw SRC_BUG;
136 	}
137     }
138 
msg_type2char(msg_type x)139     char msg_type2char(msg_type x)
140     {
141 	switch(x)
142 	{
143 	case msg_type::unset:
144 	    throw SRC_BUG;
145 	case msg_type::order_read_ahead:
146 	    return 'a';
147 	case msg_type::order_read_ahead_begin:
148 	    return 'A';
149 	case msg_type::order_read:
150 	    return 'r';
151 	case msg_type::order_sync_write:
152 	    return 'y';
153 	case msg_type::answr_sync_write_done:
154 	    return 'Y';
155 	case msg_type::order_skip:
156 	    return 's';
157 	case msg_type::order_skip_begin:
158 	    return 'S';
159 	case msg_type::order_skip_to_eof:
160 	    return 'z';
161 	case msg_type::order_skip_fwd:
162 	    return 'g';
163 	case msg_type::order_skip_bkd:
164 	    return 'c';
165 	case msg_type::answr_skip_done:
166 	    return 'o';
167 	case msg_type::order_skippable_fwd:
168 	    return 'f';
169 	case msg_type::order_skippable_fwd_begin:
170 	    return 'F';
171 	case msg_type::order_skippable_bkd:
172 	    return 'b';
173 	case msg_type::order_skippable_bkd_begin:
174 	    return 'B';
175 	case msg_type::answr_skippable:
176 	    return 'i';
177 	case msg_type::order_get_position:
178 	    return 'q';
179 	case msg_type::answr_position:
180 	    return 'p';
181 	case msg_type::answr_position_begin:
182 	    return 'P';
183 	case msg_type::answr_exception:
184 	    return 'X';
185 	case msg_type::order_end_of_xmit:
186 	    return 'Z';
187 	case msg_type::order_stop_readahead:
188 	    return 'W';
189 	case msg_type::answr_readahead_stopped:
190 	    return 'w';
191 	case msg_type::order_wakeup:
192 	    return 'h';
193 	case msg_type::data_partial:
194 	    return 'd';
195 	case msg_type::data_completed:
196 	    return 'D';
197 	default:
198 	    throw SRC_BUG;
199 	}
200     }
201 
char2msg_type(char x)202     msg_type char2msg_type(char x)
203     {
204 	switch(x)
205 	{
206 	case 'a':
207 	    return msg_type::order_read_ahead;
208 	case 'A':
209 	    return msg_type::order_read_ahead_begin;
210 	case 'r':
211 	    return msg_type::order_read;
212 	case 'y':
213 	    return msg_type::order_sync_write;
214 	case 'Y':
215 	    return msg_type::answr_sync_write_done;
216 	case 's':
217 	    return msg_type::order_skip;
218 	case 'S':
219 	    return msg_type::order_skip_begin;
220 	case 'z':
221 	    return msg_type::order_skip_to_eof;
222 	case 'g':
223 	    return msg_type::order_skip_fwd;
224 	case 'c':
225 	    return msg_type::order_skip_bkd;
226 	case 'o':
227 	    return msg_type::answr_skip_done;
228 	case 'f':
229 	    return msg_type::order_skippable_fwd;
230 	case 'F':
231 	    return msg_type::order_skippable_fwd_begin;
232 	case 'b':
233 	    return msg_type::order_skippable_bkd;
234 	case 'B':
235 	    return msg_type::order_skippable_bkd_begin;
236 	case 'i':
237 	    return msg_type::answr_skippable;
238 	case 'q':
239 	    return msg_type::order_get_position;
240 	case 'p':
241 	    return msg_type::answr_position;
242 	case 'P':
243 	    return msg_type::answr_position_begin;
244 	case 'X':
245 	    return msg_type::answr_exception;
246 	case 'Z':
247 	    return msg_type::order_end_of_xmit;
248 	case 'W':
249 	    return msg_type::order_stop_readahead;
250 	case 'w':
251 	    return msg_type::answr_readahead_stopped;
252 	case 'h':
253 	    return msg_type::order_wakeup;
254 	case 'd':
255 	    return msg_type::data_partial;
256 	case 'D':
257 	    return msg_type::data_completed;
258 	default:
259 	    throw SRC_BUG;
260 	}
261     }
262 
msg_continuation_of(msg_type x)263     msg_type msg_continuation_of(msg_type x)
264     {
265 	switch(x)
266 	{
267 	case msg_type::order_read_ahead_begin:
268 	    throw SRC_BUG;
269 	case msg_type::order_skip_begin:
270 	    throw SRC_BUG;
271 	case msg_type::order_skippable_fwd_begin:
272 	    throw SRC_BUG;
273 	case msg_type::order_skippable_bkd_begin:
274 	    throw SRC_BUG;
275 	case msg_type::answr_position_begin:
276 	    throw SRC_BUG;
277 	case msg_type::unset:
278 	    throw SRC_BUG;
279 	case msg_type::order_read_ahead:
280 	    return msg_type::order_read_ahead_begin;
281 	case msg_type::order_read:
282 	    throw SRC_BUG;
283 	case msg_type::order_sync_write:
284 	    throw SRC_BUG;
285 	case msg_type::answr_sync_write_done:
286 	    throw SRC_BUG;
287 	case msg_type::order_skip:
288 	    return msg_type::order_skip_begin;
289 	case msg_type::order_skip_to_eof:
290 	    throw SRC_BUG;
291 	case msg_type::order_skip_fwd:
292 	    throw SRC_BUG;
293 	case msg_type::order_skip_bkd:
294 	    throw SRC_BUG;
295 	case msg_type::answr_skip_done:
296 	    throw SRC_BUG;
297 	case msg_type::order_skippable_fwd:
298 	    return msg_type::order_skippable_fwd_begin;
299 	case msg_type::order_skippable_bkd:
300 	    return msg_type::order_skippable_bkd_begin;
301 	case msg_type::answr_skippable:
302 	    throw SRC_BUG;
303 	case msg_type::order_get_position:
304 	    throw SRC_BUG;
305 	case msg_type::answr_position:
306 	    return msg_type::answr_position_begin;
307 	case msg_type::answr_exception:
308 	    throw SRC_BUG;
309 	case msg_type::order_end_of_xmit:
310 	    throw SRC_BUG;
311 	case msg_type::order_stop_readahead:
312 	    throw SRC_BUG;
313 	case msg_type::answr_readahead_stopped:
314 	    throw SRC_BUG;
315 	case msg_type::order_wakeup:
316 	    throw SRC_BUG;
317 	case msg_type::data_partial:
318 	    return msg_type::data_partial;
319 	case msg_type::data_completed:
320 	    return msg_type::data_partial;
321 	default:
322 	    throw SRC_BUG;
323 	}
324     }
325 
326 	//////////////////////////////////////////////////////////////////////
327 
clear()328     void messaging_decode::clear()
329     {
330 	buffer.reset();
331 	msgt = msg_type::unset;
332     }
333 
add_block(const char * x_input,U_I size)334     bool messaging_decode::add_block(const char *x_input, U_I size)
335     {
336 	if(size < 1)
337 	    throw SRC_BUG;
338 	else
339 	{
340 	    msg_type tmp = char2msg_type(x_input[0]);
341 	    if(msgt == msg_type::unset
342 	       || msg_equivalent(msgt, tmp))
343 		msgt = tmp;
344 	}
345 
346 	if(msgt != msg_type::data_partial && msgt != msg_type::data_completed)
347 	{
348 	    buffer.skip_to_eof();
349 	    buffer.write(x_input + 1, size - 1);
350 	}
351 
352 	return !msg_continues(msgt);
353     }
354 
get_infinint() const355     infinint messaging_decode::get_infinint() const
356     {
357 	infinint ret;
358 
359 	messaging_decode *me = const_cast<messaging_decode *>(this);
360 	if(me == nullptr)
361 	    throw SRC_BUG;
362 
363 	me->buffer.skip(0);
364 	ret.read(me->buffer);
365 
366 	return ret;
367     }
368 
get_U_I() const369     U_I messaging_decode::get_U_I() const
370     {
371 	U_I lu;
372 	U_I ret;
373 
374 	messaging_decode *me = const_cast<messaging_decode *>(this);
375 	if(me == nullptr)
376 	    throw SRC_BUG;
377 
378 	    // no ending conversion, we stay in the same process on the same host
379 
380 	me->buffer.skip(0);
381 	lu = me->buffer.read((char *)(&ret), sizeof(ret));
382 
383 	if(lu < sizeof(ret))
384 	    throw SRC_BUG;
385 
386 	return ret;
387     }
388 
389 
get_string() const390     string messaging_decode::get_string() const
391     {
392 	string ret;
393 
394 	messaging_decode *me = const_cast<messaging_decode *>(this);
395 	if(me == nullptr)
396 	    throw SRC_BUG;
397 
398 	me->buffer.skip(0);
399 	tools_read_string(me->buffer, ret);
400 
401 	return ret;
402     }
403 
get_bool() const404     bool messaging_decode::get_bool() const
405     {
406 	char tmp;
407 	U_I lu;
408 
409 	messaging_decode *me = const_cast<messaging_decode *>(this);
410 	if(me == nullptr)
411 	    throw SRC_BUG;
412 
413 	    // no ending conversion, we stay in the same process on the same host
414 
415 	me->buffer.skip(0);
416 	lu = me->buffer.read(&tmp, sizeof(tmp));
417 	if(lu < sizeof(tmp))
418 	    throw SRC_BUG;
419 
420 	return tmp != 0;
421     }
422 
423 
get_label() const424     label messaging_decode::get_label() const
425     {
426 	label ret;
427 
428 	messaging_decode *me = const_cast<messaging_decode *>(this);
429 	if(me == nullptr)
430 	    throw SRC_BUG;
431 
432 	me->buffer.skip(0);
433 	ret.read(me->buffer);
434 
435 	return ret;
436     }
437 
438 
439 	//////////////////////////////////////////////////////////////////////
440 
441 
clear()442     void messaging_encode::clear()
443     {
444 	buffer.reset();
445 	msgt = msg_type::unset;
446     }
447 
448 
set_infinint(const infinint & val)449     void messaging_encode::set_infinint(const infinint & val)
450     {
451 	buffer.skip_to_eof();
452 	val.dump(buffer);
453     }
454 
455 
set_U_I(U_I val)456     void messaging_encode::set_U_I(U_I val)
457     {
458 	    // no ending conversion, we stay in the same process on the same host
459 
460 	buffer.skip_to_eof();
461 	buffer.write((char *)(&val), sizeof(val));
462     }
463 
set_string(const string & val)464     void messaging_encode::set_string(const string & val)
465     {
466 	buffer.skip_to_eof();
467 	tools_write_string(buffer, val);
468     }
469 
set_bool(bool val)470     void messaging_encode::set_bool(bool val)
471     {
472 	char tmp = val ? 1 : 0;
473 
474 	buffer.skip_to_eof();
475 	buffer.write(&tmp, sizeof(tmp));
476     }
477 
set_label(const label & val)478     void messaging_encode::set_label(const label & val)
479     {
480 	buffer.skip_to_eof();
481 	val.dump(buffer);
482     }
483 
reset_get_block()484     void messaging_encode::reset_get_block()
485     {
486 	buffer.skip(0);
487     }
488 
get_block(char * ptr,unsigned int & size)489     bool messaging_encode::get_block(char *ptr, unsigned int & size)
490     {
491 	U_I wrote;
492 	bool completed = true;
493 
494 	if(size < 1)
495 	    throw SRC_BUG;
496 	ptr[0] = msg_type2char(msgt);
497 	wrote = buffer.read(ptr + 1, size - 1);
498 
499 	if(wrote == size - 1) // filled the buffer
500 	{
501 	    if(buffer.get_position() < buffer.size())
502 	    {
503 		    // some data remains to be written
504 
505 		ptr[0] = msg_type2char(msg_continuation_of(msgt));
506 		completed = false;
507 	    }
508 	}
509 
510 	size = wrote + 1;
511 
512 	return completed;
513     }
514 
515 } // end of generic_thread::namespace
516 
517