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, made_from_network);
219 extract_variable_length_string(payload, sk_str, pos,
220 "hello netcmd, server key");
221 server_key = rsa_pub_key(sk_str, made_from_network);
222 nonce = id(extract_substring(payload, pos,
223 constants::merkle_hash_length_in_bytes,
224 "hello netcmd, nonce"), made_from_network);
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, made_from_network);
279 extract_variable_length_string(payload, pattern_string, pos,
280 "anonymous(hmac) netcmd, exclude_pattern");
281 exclude_pattern = globish(pattern_string, made_from_network);
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, made_from_network);
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 rsa_sha1_signature & 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, made_from_network);
325 extract_variable_length_string(payload, pattern_string, pos,
326 "auth(hmac) netcmd, exclude_pattern");
327 exclude_pattern = globish(pattern_string, made_from_network);
328 client = id(extract_substring(payload, pos,
329 constants::merkle_hash_length_in_bytes,
330 "auth(hmac) netcmd, client identifier"),
331 made_from_network);
332 nonce1 = id(extract_substring(payload, pos,
333 constants::merkle_hash_length_in_bytes,
334 "auth(hmac) netcmd, nonce1"),
335 made_from_network);
336 string hmac_key;
337 extract_variable_length_string(payload, hmac_key, pos,
338 "auth(hmac) netcmd, hmac_key_encrypted");
339 hmac_key_encrypted = rsa_oaep_sha_data(hmac_key, made_from_network);
340 string sig_string;
341 extract_variable_length_string(payload, sig_string, pos,
342 "auth(hmac) netcmd, signature");
343 signature = rsa_sha1_signature(sig_string, made_from_network);
344 assert_end_of_buffer(payload, pos, "auth(hmac) netcmd payload");
345}
346
347void
348netcmd::write_auth_cmd(protocol_role role,
349 globish const & include_pattern,
350 globish const & exclude_pattern,
351 id const & client,
352 id const & nonce1,
353 rsa_oaep_sha_data const & hmac_key_encrypted,
354 rsa_sha1_signature const & signature)
355{
356 cmd_code = auth_cmd;
357 I(client().size() == constants::merkle_hash_length_in_bytes);
358 I(nonce1().size() == constants::merkle_hash_length_in_bytes);
359 payload += static_cast<char>(role);
360 insert_variable_length_string(include_pattern(), payload);
361 insert_variable_length_string(exclude_pattern(), payload);
362 payload += client();
363 payload += nonce1();
364 insert_variable_length_string(hmac_key_encrypted(), payload);
365 insert_variable_length_string(signature(), payload);
366}
367
368void
369netcmd::read_confirm_cmd() const
370{
371 size_t pos = 0;
372 assert_end_of_buffer(payload, pos, "confirm netcmd payload");
373}
374
375void
376netcmd::write_confirm_cmd()
377{
378 cmd_code = confirm_cmd;
379 payload.clear();
380}
381
382void
383netcmd::read_refine_cmd(refinement_type & ty, merkle_node & node) const
384{
385 // syntax is: <u8: refinement type> <node: a merkle tree node>
386 size_t pos = 0;
387 ty = static_cast<refinement_type>
388 (extract_datum_lsb<u8>
389 (payload, pos,
390 "refine netcmd, refinement type"));
391 read_node(payload, pos, node);
392 assert_end_of_buffer(payload, pos, "refine cmd");
393}
394
395void
396netcmd::write_refine_cmd(refinement_type ty, merkle_node const & node)
397{
398 cmd_code = refine_cmd;
399 payload.clear();
400 payload += static_cast<char>(ty);
401 write_node(node, payload);
402}
403
404void
405netcmd::read_done_cmd(netcmd_item_type & type, size_t & n_items) const
406{
407 size_t pos = 0;
408 // syntax is: <type: 1 byte> <n_items: uleb128>
409 type = read_netcmd_item_type(payload, pos, "done netcmd, item type");
410 n_items = extract_datum_uleb128<size_t>(payload, pos,
411 "done netcmd, item-to-send count");
412 assert_end_of_buffer(payload, pos, "done netcmd payload");
413}
414
415void
416netcmd::write_done_cmd(netcmd_item_type type,
417 size_t n_items)
418{
419 cmd_code = done_cmd;
420 payload.clear();
421 payload += static_cast<char>(type);
422 insert_datum_uleb128<size_t>(n_items, payload);
423}
424
425void
426netcmd::read_data_cmd(netcmd_item_type & type,
427 id & item, string & dat) const
428{
429 size_t pos = 0;
430 // syntax is: <type: 1 byte> <id: 20 bytes sha1>
431 // <compressed_p1: 1 byte> <dat: vstr>
432
433 type = read_netcmd_item_type(payload, pos, "data netcmd, item type");
434 item = id(extract_substring(payload, pos,
435 constants::merkle_hash_length_in_bytes,
436 "data netcmd, item identifier"),
437 made_from_network);
438
439 dat.clear();
440 u8 compressed_p = extract_datum_lsb<u8>(payload, pos,
441 "data netcmd, compression flag");
442 extract_variable_length_string(payload, dat, pos,
443 "data netcmd, data payload");
444 if (compressed_p == 1)
445 {
446 gzip<data> zdat(dat, made_from_network);
447 data tdat;
448 decode_gzip(zdat, tdat);
449 dat = tdat();
450 }
451 assert_end_of_buffer(payload, pos, "data netcmd payload");
452}
453
454void
455netcmd::write_data_cmd(netcmd_item_type type,
456 id const & item,
457 string const & dat)
458{
459 cmd_code = data_cmd;
460 I(item().size() == constants::merkle_hash_length_in_bytes);
461 payload += static_cast<char>(type);
462 payload += item();
463 if (dat.size() > constants::netcmd_minimum_bytes_to_bother_with_gzip)
464 {
465 gzip<data> zdat;
466 encode_gzip(data(dat), zdat);
467 payload += static_cast<char>(1); // compressed flag
468 insert_variable_length_string(zdat(), payload);
469 }
470 else
471 {
472 payload += static_cast<char>(0); // compressed flag
473 insert_variable_length_string(dat, payload);
474 }
475}
476
477
478void
479netcmd::read_delta_cmd(netcmd_item_type & type,
480 id & base, id & ident, delta & del) const
481{
482 size_t pos = 0;
483 // syntax is: <type: 1 byte> <src: 20 bytes sha1> <dst: 20 bytes sha1>
484 // <compressed_p: 1 byte> <del: vstr>
485 type = read_netcmd_item_type(payload, pos, "delta netcmd, item type");
486 base = id(extract_substring(payload, pos,
487 constants::merkle_hash_length_in_bytes,
488 "delta netcmd, base identifier"),
489 made_from_network);
490 ident = id(extract_substring(payload, pos,
491 constants::merkle_hash_length_in_bytes,
492 "delta netcmd, ident identifier"),
493 made_from_network);
494 u8 compressed_p = extract_datum_lsb<u8>(payload, pos,
495 "delta netcmd, compression flag");
496 string tmp;
497 extract_variable_length_string(payload, tmp, pos,
498 "delta netcmd, delta payload");
499 if (compressed_p == 1)
500 {
501 gzip<delta> zdel(tmp, made_from_network);
502 decode_gzip(zdel, del);
503 }
504 else
505 {
506 del = delta(tmp, made_from_network);
507 }
508 assert_end_of_buffer(payload, pos, "delta netcmd payload");
509}
510
511void
512netcmd::write_delta_cmd(netcmd_item_type & type,
513 id const & base, id const & ident,
514 delta const & del)
515{
516 cmd_code = delta_cmd;
517 I(base().size() == constants::merkle_hash_length_in_bytes);
518 I(ident().size() == constants::merkle_hash_length_in_bytes);
519 payload += static_cast<char>(type);
520 payload += base();
521 payload += ident();
522
523 string tmp;
524
525 if (del().size() > constants::netcmd_minimum_bytes_to_bother_with_gzip)
526 {
527 payload += static_cast<char>(1); // compressed flag
528 gzip<delta> zdel;
529 encode_gzip(del, zdel);
530 tmp = zdel();
531 }
532 else
533 {
534 payload += static_cast<char>(0); // compressed flag
535 tmp = del();
536 }
537 I(tmp.size() <= constants::netcmd_payload_limit);
538 insert_variable_length_string(tmp, payload);
539}
540
541void
542netcmd::read_usher_cmd(utf8 & greeting) const
543{
544 size_t pos = 0;
545 string str;
546 extract_variable_length_string(payload, str, pos, "error netcmd, message");
547 greeting = utf8(str, made_from_network);
548 assert_end_of_buffer(payload, pos, "error netcmd payload");
549}
550
551void
552netcmd::write_usher_reply_cmd(utf8 const & server, globish const & pattern)
553{
554 cmd_code = usher_reply_cmd;
555 payload.clear();
556 insert_variable_length_string(server(), payload);
557 insert_variable_length_string(pattern(), payload);
558}
559
560
561#ifdef BUILD_UNIT_TESTS
562
563#include "unit_tests.hh"
564#include "transforms.hh"
565#include "lexical_cast.hh"
566
567UNIT_TEST(netcmd, mac)
568{
569 netcmd out_cmd, in_cmd;
570 string buf;
571 netsync_session_key key(constants::netsync_key_initializer);
572 {
573 chained_hmac mac(key, true);
574 // mutates mac
575 out_cmd.write(buf, mac);
576 UNIT_TEST_CHECK_THROW(in_cmd.read_string(buf, mac), bad_decode);
577 }
578
579 {
580 chained_hmac mac(key, true);
581 out_cmd.write(buf, mac);
582 }
583 buf[0] ^= 0xff;
584 {
585 chained_hmac mac(key, true);
586 UNIT_TEST_CHECK_THROW(in_cmd.read_string(buf, mac), bad_decode);
587 }
588
589 {
590 chained_hmac mac(key, true);
591 out_cmd.write(buf, mac);
592 }
593 buf[buf.size() - 1] ^= 0xff;
594 {
595 chained_hmac mac(key, true);
596 UNIT_TEST_CHECK_THROW(in_cmd.read_string(buf, mac), bad_decode);
597 }
598
599 {
600 chained_hmac mac(key, true);
601 out_cmd.write(buf, mac);
602 }
603 buf += '\0';
604 {
605 chained_hmac mac(key, true);
606 UNIT_TEST_CHECK_THROW(in_cmd.read_string(buf, mac), bad_decode);
607 }
608}
609
610static void
611do_netcmd_roundtrip(netcmd const & out_cmd, netcmd & in_cmd, string & buf)
612{
613 netsync_session_key key(constants::netsync_key_initializer);
614 {
615 chained_hmac mac(key, true);
616 out_cmd.write(buf, mac);
617 }
618 {
619 chained_hmac mac(key, true);
620 UNIT_TEST_CHECK(in_cmd.read_string(buf, mac));
621 }
622 UNIT_TEST_CHECK(in_cmd == out_cmd);
623}
624
625UNIT_TEST(netcmd, functions)
626{
627
628 try
629 {
630
631 // error_cmd
632 {
633 L(FL("checking i/o round trip on error_cmd"));
634 netcmd out_cmd, in_cmd;
635 string out_errmsg("your shoelaces are untied"), in_errmsg;
636 string buf;
637 out_cmd.write_error_cmd(out_errmsg);
638 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
639 in_cmd.read_error_cmd(in_errmsg);
640 UNIT_TEST_CHECK(in_errmsg == out_errmsg);
641 L(FL("errmsg_cmd test done, buffer was %d bytes") % buf.size());
642 }
643
644 // hello_cmd
645 {
646 L(FL("checking i/o round trip on hello_cmd"));
647 netcmd out_cmd, in_cmd;
648 string buf;
649 rsa_keypair_id out_server_keyname("server@there"), in_server_keyname;
650 rsa_pub_key out_server_key("9387938749238792874"), in_server_key;
651 id out_nonce(raw_sha1("nonce it up")), in_nonce;
652 out_cmd.write_hello_cmd(out_server_keyname, out_server_key, out_nonce);
653 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
654 in_cmd.read_hello_cmd(in_server_keyname, in_server_key, in_nonce);
655 UNIT_TEST_CHECK(in_server_keyname == out_server_keyname);
656 UNIT_TEST_CHECK(in_server_key == out_server_key);
657 UNIT_TEST_CHECK(in_nonce == out_nonce);
658 L(FL("hello_cmd test done, buffer was %d bytes") % buf.size());
659 }
660
661 // bye_cmd
662 {
663 L(FL("checking i/o round trip on bye_cmd"));
664 netcmd out_cmd, in_cmd;
665 u8 out_phase(1), in_phase;
666 string buf;
667
668 out_cmd.write_bye_cmd(out_phase);
669 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
670 in_cmd.read_bye_cmd(in_phase);
671 UNIT_TEST_CHECK(in_phase == out_phase);
672 L(FL("bye_cmd test done, buffer was %d bytes") % buf.size());
673 }
674
675 // anonymous_cmd
676 {
677 L(FL("checking i/o round trip on anonymous_cmd"));
678 netcmd out_cmd, in_cmd;
679 protocol_role out_role = source_and_sink_role, in_role;
680 string buf;
681 // total cheat, since we don't actually verify that rsa_oaep_sha_data
682 // is sensible anywhere here...
683 rsa_oaep_sha_data out_key("nonce start my heart"), in_key;
684 globish out_include_pattern("radishes galore!"), in_include_pattern;
685 globish out_exclude_pattern("turnips galore!"), in_exclude_pattern;
686
687 out_cmd.write_anonymous_cmd(out_role, out_include_pattern, out_exclude_pattern, out_key);
688 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
689 in_cmd.read_anonymous_cmd(in_role, in_include_pattern, in_exclude_pattern, in_key);
690 UNIT_TEST_CHECK(in_key == out_key);
691 UNIT_TEST_CHECK(in_include_pattern() == out_include_pattern());
692 UNIT_TEST_CHECK(in_exclude_pattern() == out_exclude_pattern());
693 UNIT_TEST_CHECK(in_role == out_role);
694 L(FL("anonymous_cmd test done, buffer was %d bytes") % buf.size());
695 }
696
697 // auth_cmd
698 {
699 L(FL("checking i/o round trip on auth_cmd"));
700 netcmd out_cmd, in_cmd;
701 protocol_role out_role = source_and_sink_role, in_role;
702 string buf;
703 id out_client(raw_sha1("happy client day")), out_nonce1(raw_sha1("nonce me amadeus")),
704 in_client, in_nonce1;
705 // total cheat, since we don't actually verify that rsa_oaep_sha_data
706 // is sensible anywhere here...
707 rsa_oaep_sha_data out_key("nonce start my heart"), in_key;
708 rsa_sha1_signature out_signature(raw_sha1("burble") + raw_sha1("gorby")), in_signature;
709 globish out_include_pattern("radishes galore!"), in_include_pattern;
710 globish out_exclude_pattern("turnips galore!"), in_exclude_pattern;
711
712 out_cmd.write_auth_cmd(out_role, out_include_pattern, out_exclude_pattern
713 , out_client, out_nonce1, out_key, out_signature);
714 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
715 in_cmd.read_auth_cmd(in_role, in_include_pattern, in_exclude_pattern,
716 in_client, in_nonce1, in_key, in_signature);
717 UNIT_TEST_CHECK(in_client == out_client);
718 UNIT_TEST_CHECK(in_nonce1 == out_nonce1);
719 UNIT_TEST_CHECK(in_key == out_key);
720 UNIT_TEST_CHECK(in_signature == out_signature);
721 UNIT_TEST_CHECK(in_role == out_role);
722 UNIT_TEST_CHECK(in_include_pattern() == out_include_pattern());
723 UNIT_TEST_CHECK(in_exclude_pattern() == out_exclude_pattern());
724 L(FL("auth_cmd test done, buffer was %d bytes") % buf.size());
725 }
726
727 // confirm_cmd
728 {
729 L(FL("checking i/o round trip on confirm_cmd"));
730 netcmd out_cmd, in_cmd;
731 string buf;
732 out_cmd.write_confirm_cmd();
733 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
734 in_cmd.read_confirm_cmd();
735 L(FL("confirm_cmd test done, buffer was %d bytes") % buf.size());
736 }
737
738 // refine_cmd
739 {
740 L(FL("checking i/o round trip on refine_cmd"));
741 netcmd out_cmd, in_cmd;
742 string buf;
743 refinement_type out_ty (refinement_query), in_ty(refinement_response);
744 merkle_node out_node, in_node;
745
746 out_node.set_raw_slot(0, id(raw_sha1("The police pulled Kris Kringle over")));
747 out_node.set_raw_slot(3, id(raw_sha1("Kris Kringle tried to escape from the police")));
748 out_node.set_raw_slot(8, id(raw_sha1("He was arrested for auto theft")));
749 out_node.set_raw_slot(15, id(raw_sha1("He was whisked away to jail")));
750 out_node.set_slot_state(0, subtree_state);
751 out_node.set_slot_state(3, leaf_state);
752 out_node.set_slot_state(8, leaf_state);
753 out_node.set_slot_state(15, subtree_state);
754
755 out_cmd.write_refine_cmd(out_ty, out_node);
756 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
757 in_cmd.read_refine_cmd(in_ty, in_node);
758 UNIT_TEST_CHECK(in_ty == out_ty);
759 UNIT_TEST_CHECK(in_node == out_node);
760 L(FL("refine_cmd test done, buffer was %d bytes") % buf.size());
761 }
762
763 // done_cmd
764 {
765 L(FL("checking i/o round trip on done_cmd"));
766 netcmd out_cmd, in_cmd;
767 size_t out_n_items(12), in_n_items(0);
768 netcmd_item_type out_type(key_item), in_type(revision_item);
769 string buf;
770
771 out_cmd.write_done_cmd(out_type, out_n_items);
772 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
773 in_cmd.read_done_cmd(in_type, in_n_items);
774 UNIT_TEST_CHECK(in_n_items == out_n_items);
775 UNIT_TEST_CHECK(in_type == out_type);
776 L(FL("done_cmd test done, buffer was %d bytes") % buf.size());
777 }
778
779 // data_cmd
780 {
781 L(FL("checking i/o round trip on data_cmd"));
782 netcmd out_cmd, in_cmd;
783 netcmd_item_type out_type(file_item), in_type(key_item);
784 id out_id(raw_sha1("tuna is not yummy")), in_id;
785 string out_dat("thank you for flying northwest"), in_dat;
786 string buf;
787 out_cmd.write_data_cmd(out_type, out_id, out_dat);
788 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
789 in_cmd.read_data_cmd(in_type, in_id, in_dat);
790 UNIT_TEST_CHECK(in_id == out_id);
791 UNIT_TEST_CHECK(in_dat == out_dat);
792 L(FL("data_cmd test done, buffer was %d bytes") % buf.size());
793 }
794
795 // delta_cmd
796 {
797 L(FL("checking i/o round trip on delta_cmd"));
798 netcmd out_cmd, in_cmd;
799 netcmd_item_type out_type(file_item), in_type(key_item);
800 id out_head(raw_sha1("your seat cusion can be reused")), in_head;
801 id out_base(raw_sha1("as a floatation device")), in_base;
802 delta out_delta("goodness, this is not an xdelta"), in_delta;
803 string buf;
804
805 out_cmd.write_delta_cmd(out_type, out_head, out_base, out_delta);
806 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
807 in_cmd.read_delta_cmd(in_type, in_head, in_base, in_delta);
808 UNIT_TEST_CHECK(in_type == out_type);
809 UNIT_TEST_CHECK(in_head == out_head);
810 UNIT_TEST_CHECK(in_base == out_base);
811 UNIT_TEST_CHECK(in_delta == out_delta);
812 L(FL("delta_cmd test done, buffer was %d bytes") % buf.size());
813 }
814
815 }
816 catch (bad_decode & d)
817 {
818 L(FL("bad decode exception: '%s'") % d.what);
819 throw;
820 }
821}
822
823#endif // BUILD_UNIT_TESTS
824
825// Local Variables:
826// mode: C++
827// fill-column: 76
828// c-file-style: "gnu"
829// indent-tabs-mode: nil
830// End:
831// 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