monotone

monotone Mtn Source Tree

Root/netcmd.cc

1// Copyright (C) 2004 Graydon Hoare <graydon@pobox.com>
2//
3// This program is made available under the GNU GPL version 2.0 or
4// greater. See the accompanying file COPYING for details.
5//
6// This program is distributed WITHOUT ANY WARRANTY; without even the
7// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8// PURPOSE.
9
10#include "base.hh"
11#include "vector.hh"
12#include <utility>
13
14#include "constants.hh"
15#include "netcmd.hh"
16#include "netio.hh"
17#include "numeric_vocab.hh"
18#include "sanity.hh"
19#include "transforms.hh"
20#include "hmac.hh"
21#include "globish.hh"
22
23using std::string;
24
25static netcmd_item_type
26read_netcmd_item_type(string const & in,
27 size_t & pos,
28 string const & name)
29{
30 u8 tmp = extract_datum_lsb<u8>(in, pos, name);
31 switch (tmp)
32 {
33 case static_cast<u8>(revision_item):
34 return revision_item;
35 case static_cast<u8>(file_item):
36 return file_item;
37 case static_cast<u8>(cert_item):
38 return cert_item;
39 case static_cast<u8>(key_item):
40 return key_item;
41 case static_cast<u8>(epoch_item):
42 return epoch_item;
43 default:
44 throw bad_decode(F("unknown item type 0x%x for '%s'")
45 % static_cast<int>(tmp) % name);
46 }
47}
48
49netcmd::netcmd() : version(constants::netcmd_current_protocol_version),
50 cmd_code(error_cmd)
51{}
52
53size_t netcmd::encoded_size()
54{
55 string tmp;
56 insert_datum_uleb128<size_t>(payload.size(), tmp);
57 return 1 + 1 + tmp.size() + payload.size() + 4;
58}
59
60bool
61netcmd::operator==(netcmd const & other) const
62{
63 return version == other.version &&
64 cmd_code == other.cmd_code &&
65 payload == other.payload;
66}
67
68// note: usher_reply_cmd does not get included in the hmac.
69void
70netcmd::write(string & out, chained_hmac & hmac) const
71{
72 size_t oldlen = out.size();
73 out += static_cast<char>(version);
74 out += static_cast<char>(cmd_code);
75 insert_variable_length_string(payload, out);
76
77 if (hmac.is_active() && cmd_code != usher_reply_cmd)
78 {
79 string digest = hmac.process(out, oldlen);
80 I(hmac.hmac_length == constants::netsync_hmac_value_length_in_bytes);
81 out.append(digest);
82 }
83}
84
85// note: usher_cmd does not get included in the hmac.
86bool
87netcmd::read(string_queue & inbuf, chained_hmac & hmac)
88{
89 size_t pos = 0;
90
91 if (inbuf.size() < constants::netcmd_minsz)
92 return false;
93
94 u8 extracted_ver = extract_datum_lsb<u8>(inbuf, pos, "netcmd protocol number");
95
96 u8 cmd_byte = extract_datum_lsb<u8>(inbuf, pos, "netcmd code");
97 switch (cmd_byte)
98 {
99 case static_cast<u8>(hello_cmd):
100 case static_cast<u8>(bye_cmd):
101 case static_cast<u8>(anonymous_cmd):
102 case static_cast<u8>(auth_cmd):
103 case static_cast<u8>(error_cmd):
104 case static_cast<u8>(confirm_cmd):
105 case static_cast<u8>(refine_cmd):
106 case static_cast<u8>(done_cmd):
107 case static_cast<u8>(data_cmd):
108 case static_cast<u8>(delta_cmd):
109 case static_cast<u8>(usher_cmd):
110 cmd_code = static_cast<netcmd_code>(cmd_byte);
111 break;
112 default:
113 // if the versions don't match, we will throw the more descriptive
114 // error immediately after this switch.
115 if (extracted_ver == version)
116 throw bad_decode(F("unknown netcmd code 0x%x")
117 % widen<u32,u8>(cmd_byte));
118 }
119 // Ignore the version on usher_cmd packets.
120 if (extracted_ver != version && cmd_code != usher_cmd)
121 throw bad_decode(F("protocol version mismatch: wanted '%d' got '%d'\n"
122 "%s")
123 % widen<u32,u8>(version)
124 % widen<u32,u8>(extracted_ver)
125 % ((version < extracted_ver)
126 ? _("the remote side has a newer, incompatible version of monotone")
127 : _("the remote side has an older, incompatible version of monotone")));
128
129 // check to see if we have even enough bytes for a complete uleb128
130 size_t payload_len = 0;
131 if (!try_extract_datum_uleb128<size_t>(inbuf, pos, "netcmd payload length",
132 payload_len))
133 return false;
134
135 // they might have given us a bogus size
136 if (payload_len > constants::netcmd_payload_limit)
137 throw bad_decode(F("oversized payload of '%d' bytes") % payload_len);
138
139 // there might not be enough data yet in the input buffer
140 unsigned int minsize;
141 if (hmac.is_active() && cmd_code != usher_cmd)
142 minsize = pos + payload_len + constants::netsync_hmac_value_length_in_bytes;
143 else
144 minsize = pos + payload_len;
145
146 if (inbuf.size() < minsize)
147 {
148 return false;
149 }
150
151 string digest;
152 string cmd_digest;
153
154 if (hmac.is_active() && cmd_code != usher_cmd)
155 {
156 // grab it before the data gets munged
157 I(hmac.hmac_length == constants::netsync_hmac_value_length_in_bytes);
158 digest = hmac.process(inbuf, 0, pos + payload_len);
159 }
160
161 payload = extract_substring(inbuf, pos, payload_len, "netcmd payload");
162
163 if (hmac.is_active() && cmd_code != usher_cmd)
164 {
165 // they might have given us bogus data
166 cmd_digest = extract_substring(inbuf, pos,
167 constants::netsync_hmac_value_length_in_bytes,
168 "netcmd HMAC");
169 }
170
171 inbuf.pop_front(pos);
172
173 if (hmac.is_active()
174 && cmd_code != usher_cmd
175 && cmd_digest != digest)
176 {
177 throw bad_decode(F("bad HMAC checksum (got %s, wanted %s)\n"
178 "this suggests data was corrupted in transit")
179 % encode_hexenc(cmd_digest)
180 % encode_hexenc(digest));
181 }
182
183 return true;
184}
185
186////////////////////////////////////////////
187// payload reader/writer functions follow //
188////////////////////////////////////////////
189
190void
191netcmd::read_error_cmd(string & errmsg) const
192{
193 size_t pos = 0;
194 // syntax is: <errmsg:vstr>
195 extract_variable_length_string(payload, errmsg, pos, "error netcmd, message");
196 assert_end_of_buffer(payload, pos, "error netcmd payload");
197}
198
199void
200netcmd::write_error_cmd(string const & errmsg)
201{
202 cmd_code = error_cmd;
203 payload.clear();
204 insert_variable_length_string(errmsg, payload);
205}
206
207
208void
209netcmd::read_hello_cmd(rsa_keypair_id & server_keyname,
210 rsa_pub_key & server_key,
211 id & nonce) const
212{
213 size_t pos = 0;
214 // syntax is: <server keyname:vstr> <server pubkey:vstr> <nonce:20 random bytes>
215 string skn_str, sk_str;
216 extract_variable_length_string(payload, skn_str, pos,
217 "hello netcmd, server key name");
218 server_keyname = rsa_keypair_id(skn_str);
219 extract_variable_length_string(payload, sk_str, pos,
220 "hello netcmd, server key");
221 server_key = rsa_pub_key(sk_str);
222 nonce = id(extract_substring(payload, pos,
223 constants::merkle_hash_length_in_bytes,
224 "hello netcmd, nonce"));
225 assert_end_of_buffer(payload, pos, "hello netcmd payload");
226}
227
228void
229netcmd::write_hello_cmd(rsa_keypair_id const & server_keyname,
230 rsa_pub_key const & server_key,
231 id const & nonce)
232{
233 cmd_code = hello_cmd;
234 payload.clear();
235 I(nonce().size() == constants::merkle_hash_length_in_bytes);
236 insert_variable_length_string(server_keyname(), payload);
237 insert_variable_length_string(server_key(), payload);
238 payload += nonce();
239}
240
241
242void
243netcmd::read_bye_cmd(u8 & phase) const
244{
245 size_t pos = 0;
246 // syntax is: <phase: 1 byte>
247 phase = extract_datum_lsb<u8>(payload, pos, "bye netcmd, phase number");
248 assert_end_of_buffer(payload, pos, "bye netcmd payload");
249}
250
251
252void
253netcmd::write_bye_cmd(u8 phase)
254{
255 cmd_code = bye_cmd;
256 payload.clear();
257 payload += phase;
258}
259
260
261void
262netcmd::read_anonymous_cmd(protocol_role & role,
263 globish & include_pattern,
264 globish & exclude_pattern,
265 rsa_oaep_sha_data & hmac_key_encrypted) const
266{
267 size_t pos = 0;
268 // syntax is: <role:1 byte> <include_pattern: vstr> <exclude_pattern: vstr> <hmac_key_encrypted: vstr>
269 u8 role_byte = extract_datum_lsb<u8>(payload, pos, "anonymous(hmac) netcmd, role");
270 if (role_byte != static_cast<u8>(source_role)
271 && role_byte != static_cast<u8>(sink_role)
272 && role_byte != static_cast<u8>(source_and_sink_role))
273 throw bad_decode(F("unknown role specifier %d") % widen<u32,u8>(role_byte));
274 role = static_cast<protocol_role>(role_byte);
275 string pattern_string;
276 extract_variable_length_string(payload, pattern_string, pos,
277 "anonymous(hmac) netcmd, include_pattern");
278 include_pattern = globish(pattern_string);
279 extract_variable_length_string(payload, pattern_string, pos,
280 "anonymous(hmac) netcmd, exclude_pattern");
281 exclude_pattern = globish(pattern_string);
282 string hmac_key_string;
283 extract_variable_length_string(payload, hmac_key_string, pos,
284 "anonymous(hmac) netcmd, hmac_key_encrypted");
285 hmac_key_encrypted = rsa_oaep_sha_data(hmac_key_string);
286 assert_end_of_buffer(payload, pos, "anonymous(hmac) netcmd payload");
287}
288
289void
290netcmd::write_anonymous_cmd(protocol_role role,
291 globish const & include_pattern,
292 globish const & exclude_pattern,
293 rsa_oaep_sha_data const & hmac_key_encrypted)
294{
295 cmd_code = anonymous_cmd;
296 payload += static_cast<char>(role);
297 insert_variable_length_string(include_pattern(), payload);
298 insert_variable_length_string(exclude_pattern(), payload);
299 insert_variable_length_string(hmac_key_encrypted(), payload);
300}
301
302void
303netcmd::read_auth_cmd(protocol_role & role,
304 globish & include_pattern,
305 globish & exclude_pattern,
306 id & client,
307 id & nonce1,
308 rsa_oaep_sha_data & hmac_key_encrypted,
309 string & signature) const
310{
311 size_t pos = 0;
312 // syntax is: <role:1 byte> <include_pattern: vstr> <exclude_pattern: vstr>
313 // <client: 20 bytes sha1> <nonce1: 20 random bytes>
314 // <hmac_key_encrypted: vstr> <signature: vstr>
315 u8 role_byte = extract_datum_lsb<u8>(payload, pos, "auth netcmd, role");
316 if (role_byte != static_cast<u8>(source_role)
317 && role_byte != static_cast<u8>(sink_role)
318 && role_byte != static_cast<u8>(source_and_sink_role))
319 throw bad_decode(F("unknown role specifier %d") % widen<u32,u8>(role_byte));
320 role = static_cast<protocol_role>(role_byte);
321 string pattern_string;
322 extract_variable_length_string(payload, pattern_string, pos,
323 "auth(hmac) netcmd, include_pattern");
324 include_pattern = globish(pattern_string);
325 extract_variable_length_string(payload, pattern_string, pos,
326 "auth(hmac) netcmd, exclude_pattern");
327 exclude_pattern = globish(pattern_string);
328 client = id(extract_substring(payload, pos,
329 constants::merkle_hash_length_in_bytes,
330 "auth(hmac) netcmd, client identifier"));
331 nonce1 = id(extract_substring(payload, pos,
332 constants::merkle_hash_length_in_bytes,
333 "auth(hmac) netcmd, nonce1"));
334 string hmac_key;
335 extract_variable_length_string(payload, hmac_key, pos,
336 "auth(hmac) netcmd, hmac_key_encrypted");
337 hmac_key_encrypted = rsa_oaep_sha_data(hmac_key);
338 extract_variable_length_string(payload, signature, pos,
339 "auth(hmac) netcmd, signature");
340 assert_end_of_buffer(payload, pos, "auth(hmac) netcmd payload");
341}
342
343void
344netcmd::write_auth_cmd(protocol_role role,
345 globish const & include_pattern,
346 globish const & exclude_pattern,
347 id const & client,
348 id const & nonce1,
349 rsa_oaep_sha_data const & hmac_key_encrypted,
350 string const & signature)
351{
352 cmd_code = auth_cmd;
353 I(client().size() == constants::merkle_hash_length_in_bytes);
354 I(nonce1().size() == constants::merkle_hash_length_in_bytes);
355 payload += static_cast<char>(role);
356 insert_variable_length_string(include_pattern(), payload);
357 insert_variable_length_string(exclude_pattern(), payload);
358 payload += client();
359 payload += nonce1();
360 insert_variable_length_string(hmac_key_encrypted(), payload);
361 insert_variable_length_string(signature, payload);
362}
363
364void
365netcmd::read_confirm_cmd() const
366{
367 size_t pos = 0;
368 assert_end_of_buffer(payload, pos, "confirm netcmd payload");
369}
370
371void
372netcmd::write_confirm_cmd()
373{
374 cmd_code = confirm_cmd;
375 payload.clear();
376}
377
378void
379netcmd::read_refine_cmd(refinement_type & ty, merkle_node & node) const
380{
381 // syntax is: <u8: refinement type> <node: a merkle tree node>
382 size_t pos = 0;
383 ty = static_cast<refinement_type>
384 (extract_datum_lsb<u8>
385 (payload, pos,
386 "refine netcmd, refinement type"));
387 read_node(payload, pos, node);
388 assert_end_of_buffer(payload, pos, "refine cmd");
389}
390
391void
392netcmd::write_refine_cmd(refinement_type ty, merkle_node const & node)
393{
394 cmd_code = refine_cmd;
395 payload.clear();
396 payload += static_cast<char>(ty);
397 write_node(node, payload);
398}
399
400void
401netcmd::read_done_cmd(netcmd_item_type & type, size_t & n_items) const
402{
403 size_t pos = 0;
404 // syntax is: <type: 1 byte> <n_items: uleb128>
405 type = read_netcmd_item_type(payload, pos, "done netcmd, item type");
406 n_items = extract_datum_uleb128<size_t>(payload, pos,
407 "done netcmd, item-to-send count");
408 assert_end_of_buffer(payload, pos, "done netcmd payload");
409}
410
411void
412netcmd::write_done_cmd(netcmd_item_type type,
413 size_t n_items)
414{
415 cmd_code = done_cmd;
416 payload.clear();
417 payload += static_cast<char>(type);
418 insert_datum_uleb128<size_t>(n_items, payload);
419}
420
421void
422netcmd::read_data_cmd(netcmd_item_type & type,
423 id & item, string & dat) const
424{
425 size_t pos = 0;
426 // syntax is: <type: 1 byte> <id: 20 bytes sha1>
427 // <compressed_p1: 1 byte> <dat: vstr>
428
429 type = read_netcmd_item_type(payload, pos, "data netcmd, item type");
430 item = id(extract_substring(payload, pos,
431 constants::merkle_hash_length_in_bytes,
432 "data netcmd, item identifier"));
433
434 dat.clear();
435 u8 compressed_p = extract_datum_lsb<u8>(payload, pos,
436 "data netcmd, compression flag");
437 extract_variable_length_string(payload, dat, pos,
438 "data netcmd, data payload");
439 if (compressed_p == 1)
440 {
441 gzip<data> zdat(dat);
442 data tdat;
443 decode_gzip(zdat, tdat);
444 dat = tdat();
445 }
446 assert_end_of_buffer(payload, pos, "data netcmd payload");
447}
448
449void
450netcmd::write_data_cmd(netcmd_item_type type,
451 id const & item,
452 string const & dat)
453{
454 cmd_code = data_cmd;
455 I(item().size() == constants::merkle_hash_length_in_bytes);
456 payload += static_cast<char>(type);
457 payload += item();
458 if (dat.size() > constants::netcmd_minimum_bytes_to_bother_with_gzip)
459 {
460 gzip<data> zdat;
461 encode_gzip(data(dat), zdat);
462 payload += static_cast<char>(1); // compressed flag
463 insert_variable_length_string(zdat(), payload);
464 }
465 else
466 {
467 payload += static_cast<char>(0); // compressed flag
468 insert_variable_length_string(dat, payload);
469 }
470}
471
472
473void
474netcmd::read_delta_cmd(netcmd_item_type & type,
475 id & base, id & ident, delta & del) const
476{
477 size_t pos = 0;
478 // syntax is: <type: 1 byte> <src: 20 bytes sha1> <dst: 20 bytes sha1>
479 // <compressed_p: 1 byte> <del: vstr>
480 type = read_netcmd_item_type(payload, pos, "delta netcmd, item type");
481 base = id(extract_substring(payload, pos,
482 constants::merkle_hash_length_in_bytes,
483 "delta netcmd, base identifier"));
484 ident = id(extract_substring(payload, pos,
485 constants::merkle_hash_length_in_bytes,
486 "delta netcmd, ident identifier"));
487 u8 compressed_p = extract_datum_lsb<u8>(payload, pos,
488 "delta netcmd, compression flag");
489 string tmp;
490 extract_variable_length_string(payload, tmp, pos,
491 "delta netcmd, delta payload");
492 if (compressed_p == 1)
493 {
494 gzip<delta> zdel(tmp);
495 decode_gzip(zdel, del);
496 }
497 else
498 {
499 del = delta(tmp);
500 }
501 assert_end_of_buffer(payload, pos, "delta netcmd payload");
502}
503
504void
505netcmd::write_delta_cmd(netcmd_item_type & type,
506 id const & base, id const & ident,
507 delta const & del)
508{
509 cmd_code = delta_cmd;
510 I(base().size() == constants::merkle_hash_length_in_bytes);
511 I(ident().size() == constants::merkle_hash_length_in_bytes);
512 payload += static_cast<char>(type);
513 payload += base();
514 payload += ident();
515
516 string tmp;
517
518 if (del().size() > constants::netcmd_minimum_bytes_to_bother_with_gzip)
519 {
520 payload += static_cast<char>(1); // compressed flag
521 gzip<delta> zdel;
522 encode_gzip(del, zdel);
523 tmp = zdel();
524 }
525 else
526 {
527 payload += static_cast<char>(0); // compressed flag
528 tmp = del();
529 }
530 I(tmp.size() <= constants::netcmd_payload_limit);
531 insert_variable_length_string(tmp, payload);
532}
533
534void
535netcmd::read_usher_cmd(utf8 & greeting) const
536{
537 size_t pos = 0;
538 string str;
539 extract_variable_length_string(payload, str, pos, "error netcmd, message");
540 greeting = utf8(str);
541 assert_end_of_buffer(payload, pos, "error netcmd payload");
542}
543
544void
545netcmd::write_usher_reply_cmd(utf8 const & server, globish const & pattern)
546{
547 cmd_code = usher_reply_cmd;
548 payload.clear();
549 insert_variable_length_string(server(), payload);
550 insert_variable_length_string(pattern(), payload);
551}
552
553
554#ifdef BUILD_UNIT_TESTS
555
556#include "unit_tests.hh"
557#include "transforms.hh"
558#include "lexical_cast.hh"
559
560UNIT_TEST(netcmd, mac)
561{
562 netcmd out_cmd, in_cmd;
563 string buf;
564 netsync_session_key key(constants::netsync_key_initializer);
565 {
566 chained_hmac mac(key, true);
567 // mutates mac
568 out_cmd.write(buf, mac);
569 UNIT_TEST_CHECK_THROW(in_cmd.read_string(buf, mac), bad_decode);
570 }
571
572 {
573 chained_hmac mac(key, true);
574 out_cmd.write(buf, mac);
575 }
576 buf[0] ^= 0xff;
577 {
578 chained_hmac mac(key, true);
579 UNIT_TEST_CHECK_THROW(in_cmd.read_string(buf, mac), bad_decode);
580 }
581
582 {
583 chained_hmac mac(key, true);
584 out_cmd.write(buf, mac);
585 }
586 buf[buf.size() - 1] ^= 0xff;
587 {
588 chained_hmac mac(key, true);
589 UNIT_TEST_CHECK_THROW(in_cmd.read_string(buf, mac), bad_decode);
590 }
591
592 {
593 chained_hmac mac(key, true);
594 out_cmd.write(buf, mac);
595 }
596 buf += '\0';
597 {
598 chained_hmac mac(key, true);
599 UNIT_TEST_CHECK_THROW(in_cmd.read_string(buf, mac), bad_decode);
600 }
601}
602
603static void
604do_netcmd_roundtrip(netcmd const & out_cmd, netcmd & in_cmd, string & buf)
605{
606 netsync_session_key key(constants::netsync_key_initializer);
607 {
608 chained_hmac mac(key, true);
609 out_cmd.write(buf, mac);
610 }
611 {
612 chained_hmac mac(key, true);
613 UNIT_TEST_CHECK(in_cmd.read_string(buf, mac));
614 }
615 UNIT_TEST_CHECK(in_cmd == out_cmd);
616}
617
618UNIT_TEST(netcmd, functions)
619{
620
621 try
622 {
623
624 // error_cmd
625 {
626 L(FL("checking i/o round trip on error_cmd"));
627 netcmd out_cmd, in_cmd;
628 string out_errmsg("your shoelaces are untied"), in_errmsg;
629 string buf;
630 out_cmd.write_error_cmd(out_errmsg);
631 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
632 in_cmd.read_error_cmd(in_errmsg);
633 UNIT_TEST_CHECK(in_errmsg == out_errmsg);
634 L(FL("errmsg_cmd test done, buffer was %d bytes") % buf.size());
635 }
636
637 // hello_cmd
638 {
639 L(FL("checking i/o round trip on hello_cmd"));
640 netcmd out_cmd, in_cmd;
641 string buf;
642 rsa_keypair_id out_server_keyname("server@there"), in_server_keyname;
643 rsa_pub_key out_server_key("9387938749238792874"), in_server_key;
644 id out_nonce(raw_sha1("nonce it up")), in_nonce;
645 out_cmd.write_hello_cmd(out_server_keyname, out_server_key, out_nonce);
646 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
647 in_cmd.read_hello_cmd(in_server_keyname, in_server_key, in_nonce);
648 UNIT_TEST_CHECK(in_server_keyname == out_server_keyname);
649 UNIT_TEST_CHECK(in_server_key == out_server_key);
650 UNIT_TEST_CHECK(in_nonce == out_nonce);
651 L(FL("hello_cmd test done, buffer was %d bytes") % buf.size());
652 }
653
654 // bye_cmd
655 {
656 L(FL("checking i/o round trip on bye_cmd"));
657 netcmd out_cmd, in_cmd;
658 u8 out_phase(1), in_phase;
659 string buf;
660
661 out_cmd.write_bye_cmd(out_phase);
662 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
663 in_cmd.read_bye_cmd(in_phase);
664 UNIT_TEST_CHECK(in_phase == out_phase);
665 L(FL("bye_cmd test done, buffer was %d bytes") % buf.size());
666 }
667
668 // anonymous_cmd
669 {
670 L(FL("checking i/o round trip on anonymous_cmd"));
671 netcmd out_cmd, in_cmd;
672 protocol_role out_role = source_and_sink_role, in_role;
673 string buf;
674 // total cheat, since we don't actually verify that rsa_oaep_sha_data
675 // is sensible anywhere here...
676 rsa_oaep_sha_data out_key("nonce start my heart"), in_key;
677 globish out_include_pattern("radishes galore!"), in_include_pattern;
678 globish out_exclude_pattern("turnips galore!"), in_exclude_pattern;
679
680 out_cmd.write_anonymous_cmd(out_role, out_include_pattern, out_exclude_pattern, out_key);
681 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
682 in_cmd.read_anonymous_cmd(in_role, in_include_pattern, in_exclude_pattern, in_key);
683 UNIT_TEST_CHECK(in_key == out_key);
684 UNIT_TEST_CHECK(in_include_pattern() == out_include_pattern());
685 UNIT_TEST_CHECK(in_exclude_pattern() == out_exclude_pattern());
686 UNIT_TEST_CHECK(in_role == out_role);
687 L(FL("anonymous_cmd test done, buffer was %d bytes") % buf.size());
688 }
689
690 // auth_cmd
691 {
692 L(FL("checking i/o round trip on auth_cmd"));
693 netcmd out_cmd, in_cmd;
694 protocol_role out_role = source_and_sink_role, in_role;
695 string buf;
696 id out_client(raw_sha1("happy client day")), out_nonce1(raw_sha1("nonce me amadeus")),
697 in_client, in_nonce1;
698 // total cheat, since we don't actually verify that rsa_oaep_sha_data
699 // is sensible anywhere here...
700 rsa_oaep_sha_data out_key("nonce start my heart"), in_key;
701 string out_signature(raw_sha1("burble") + raw_sha1("gorby")), in_signature;
702 globish out_include_pattern("radishes galore!"), in_include_pattern;
703 globish out_exclude_pattern("turnips galore!"), in_exclude_pattern;
704
705 out_cmd.write_auth_cmd(out_role, out_include_pattern, out_exclude_pattern
706 , out_client, out_nonce1, out_key, out_signature);
707 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
708 in_cmd.read_auth_cmd(in_role, in_include_pattern, in_exclude_pattern,
709 in_client, in_nonce1, in_key, in_signature);
710 UNIT_TEST_CHECK(in_client == out_client);
711 UNIT_TEST_CHECK(in_nonce1 == out_nonce1);
712 UNIT_TEST_CHECK(in_key == out_key);
713 UNIT_TEST_CHECK(in_signature == out_signature);
714 UNIT_TEST_CHECK(in_role == out_role);
715 UNIT_TEST_CHECK(in_include_pattern() == out_include_pattern());
716 UNIT_TEST_CHECK(in_exclude_pattern() == out_exclude_pattern());
717 L(FL("auth_cmd test done, buffer was %d bytes") % buf.size());
718 }
719
720 // confirm_cmd
721 {
722 L(FL("checking i/o round trip on confirm_cmd"));
723 netcmd out_cmd, in_cmd;
724 string buf;
725 out_cmd.write_confirm_cmd();
726 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
727 in_cmd.read_confirm_cmd();
728 L(FL("confirm_cmd test done, buffer was %d bytes") % buf.size());
729 }
730
731 // refine_cmd
732 {
733 L(FL("checking i/o round trip on refine_cmd"));
734 netcmd out_cmd, in_cmd;
735 string buf;
736 refinement_type out_ty (refinement_query), in_ty(refinement_response);
737 merkle_node out_node, in_node;
738
739 out_node.set_raw_slot(0, id(raw_sha1("The police pulled Kris Kringle over")));
740 out_node.set_raw_slot(3, id(raw_sha1("Kris Kringle tried to escape from the police")));
741 out_node.set_raw_slot(8, id(raw_sha1("He was arrested for auto theft")));
742 out_node.set_raw_slot(15, id(raw_sha1("He was whisked away to jail")));
743 out_node.set_slot_state(0, subtree_state);
744 out_node.set_slot_state(3, leaf_state);
745 out_node.set_slot_state(8, leaf_state);
746 out_node.set_slot_state(15, subtree_state);
747
748 out_cmd.write_refine_cmd(out_ty, out_node);
749 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
750 in_cmd.read_refine_cmd(in_ty, in_node);
751 UNIT_TEST_CHECK(in_ty == out_ty);
752 UNIT_TEST_CHECK(in_node == out_node);
753 L(FL("refine_cmd test done, buffer was %d bytes") % buf.size());
754 }
755
756 // done_cmd
757 {
758 L(FL("checking i/o round trip on done_cmd"));
759 netcmd out_cmd, in_cmd;
760 size_t out_n_items(12), in_n_items(0);
761 netcmd_item_type out_type(key_item), in_type(revision_item);
762 string buf;
763
764 out_cmd.write_done_cmd(out_type, out_n_items);
765 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
766 in_cmd.read_done_cmd(in_type, in_n_items);
767 UNIT_TEST_CHECK(in_n_items == out_n_items);
768 UNIT_TEST_CHECK(in_type == out_type);
769 L(FL("done_cmd test done, buffer was %d bytes") % buf.size());
770 }
771
772 // data_cmd
773 {
774 L(FL("checking i/o round trip on data_cmd"));
775 netcmd out_cmd, in_cmd;
776 netcmd_item_type out_type(file_item), in_type(key_item);
777 id out_id(raw_sha1("tuna is not yummy")), in_id;
778 string out_dat("thank you for flying northwest"), in_dat;
779 string buf;
780 out_cmd.write_data_cmd(out_type, out_id, out_dat);
781 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
782 in_cmd.read_data_cmd(in_type, in_id, in_dat);
783 UNIT_TEST_CHECK(in_id == out_id);
784 UNIT_TEST_CHECK(in_dat == out_dat);
785 L(FL("data_cmd test done, buffer was %d bytes") % buf.size());
786 }
787
788 // delta_cmd
789 {
790 L(FL("checking i/o round trip on delta_cmd"));
791 netcmd out_cmd, in_cmd;
792 netcmd_item_type out_type(file_item), in_type(key_item);
793 id out_head(raw_sha1("your seat cusion can be reused")), in_head;
794 id out_base(raw_sha1("as a floatation device")), in_base;
795 delta out_delta("goodness, this is not an xdelta"), in_delta;
796 string buf;
797
798 out_cmd.write_delta_cmd(out_type, out_head, out_base, out_delta);
799 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
800 in_cmd.read_delta_cmd(in_type, in_head, in_base, in_delta);
801 UNIT_TEST_CHECK(in_type == out_type);
802 UNIT_TEST_CHECK(in_head == out_head);
803 UNIT_TEST_CHECK(in_base == out_base);
804 UNIT_TEST_CHECK(in_delta == out_delta);
805 L(FL("delta_cmd test done, buffer was %d bytes") % buf.size());
806 }
807
808 }
809 catch (bad_decode & d)
810 {
811 L(FL("bad decode exception: '%s'") % d.what);
812 throw;
813 }
814}
815
816#endif // BUILD_UNIT_TESTS
817
818// Local Variables:
819// mode: C++
820// fill-column: 76
821// c-file-style: "gnu"
822// indent-tabs-mode: nil
823// End:
824// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status