monotone

monotone Mtn Source Tree

Root/packet.cc

1// copyright (C) 2002, 2003 graydon hoare <graydon@pobox.com>
2// all rights reserved.
3// licensed to the public under the terms of the GNU GPL (>= 2)
4// see the file COPYING for details
5
6#include <iostream>
7#include <string>
8
9#include <boost/optional.hpp>
10#include <boost/regex.hpp>
11#include <boost/lexical_cast.hpp>
12#include <boost/shared_ptr.hpp>
13
14#include "app_state.hh"
15#include "change_set.hh"
16#include "packet.hh"
17#include "revision.hh"
18#include "sanity.hh"
19#include "transforms.hh"
20#include "keys.hh"
21
22using namespace std;
23using boost::shared_ptr;
24using boost::lexical_cast;
25using boost::match_default;
26using boost::match_results;
27using boost::regex;
28
29// --- packet db writer --
30//
31// FIXME: this comment is out of date, and untrustworthy.
32//
33// the packet_db_writer::impl class (see below) manages writes to the
34// database. it also ensures that those writes follow the semantic
35// dependencies implied by the objects being written.
36//
37// an incoming manifest delta has three states:
38//
39// when it is first received, it is (probably) "non-constructable".
40// this means that we do not have a way of building its preimage from either
41// the database or from the memory cache of deltas we keep in this class
42//
43// a non-constructable manifest delta is given a prerequisite of
44// constructibility on its preimage.
45//
46// when the preimage becomes constructable, the manifest delta (probably)
47// changes to "non-writable" state. this means that we have a way to build
48// the manifest, we haven't received all the files which depend on it yet,
49// so we won't write it to the database.
50//
51// when a manifest becomes constructable (but not necessarily writable) we
52// call an analyzer back, if we have one, with the pre- and post-states of
53// the delta. this happens in order to give the netsync layer a chance to
54// request all the file deltas which accompany the manifest delta.
55//
56// a non-writable manifest delta is given prerequisites on all its
57// non-existing underlying files, and delayed again.
58//
59// when all the files arrive, a non-writable manifest is written to the
60// database.
61//
62// files are delayed to depend on their preimage, like non-constructable
63// manifests. however, once they are constructable they are immediately
64// written to the database.
65//
66/////////////////////////////////////////////////////////////////
67//
68// how it's done:
69//
70// each manifest or file has a companion class called a "prerequisite". a
71// prerequisite has a set of delayed packets which depend on it. these
72// delayed packets are also called dependents. a prerequisite can either be
73// "unsatisfied" or "satisfied". when it is first constructed, it is
74// unsatisfied. when it is satisfied, it calls all its dependents to inform
75// them that it has become satisfied.
76//
77// when all the prerequisites of a given dependent is satisfied, the
78// dependent writes itself back to the db writer. the dependent is then
79// dead, and the prerequisite will forget about it.
80//
81// dependents' lifetimes are managed by prerequisites. when all
82// prerequisites forget about their dependents, the dependent is destroyed
83// (it is reference counted with a shared pointer). similarly, the
84// packet_db_writer::impl holds references to prerequisites, and when
85// a prerequisite no longer has any dependents, it is dropped from the
86// packet_db_writer::impl, destroying it.
87//
88/////////////////////////////////////////////////////////////////
89//
90// this same machinery is also re-used for the "valved" packet writer, as a
91// convenient way to queue up commands in memory while the valve is closed.
92// in this usage, we simply never add any prerequisites to any packet, and
93// just call apply_delayed_packet when the valve opens.
94
95typedef enum
96 {
97 prereq_revision,
98 prereq_manifest,
99 prereq_file
100 }
101prereq_type;
102
103class delayed_packet;
104
105class
106prerequisite
107{
108 hexenc<id> ident;
109 prereq_type type;
110 set< shared_ptr<delayed_packet> > delayed;
111public:
112 prerequisite(hexenc<id> const & i, prereq_type pt)
113 : ident(i), type(pt)
114 {}
115 void add_dependent(shared_ptr<delayed_packet> p);
116 bool has_live_dependents();
117 void satisfy(shared_ptr<prerequisite> self,
118 packet_db_writer & pw);
119 bool operator<(prerequisite const & other)
120 {
121 return type < other.type ||
122 (type == other.type && ident < other.ident);
123 }
124 // we need to be able to avoid circular dependencies between prerequisite and
125 // delayed_packet shared_ptrs.
126 void cleanup() { delayed.clear(); }
127};
128
129class
130delayed_packet
131{
132 set< shared_ptr<prerequisite> > unsatisfied_prereqs;
133 set< shared_ptr<prerequisite> > satisfied_prereqs;
134public:
135 void add_prerequisite(shared_ptr<prerequisite> p);
136 bool all_prerequisites_satisfied();
137 void prerequisite_satisfied(shared_ptr<prerequisite> p,
138 packet_db_writer & pw);
139 virtual void apply_delayed_packet(packet_db_writer & pw) = 0;
140 virtual ~delayed_packet() {}
141};
142
143void
144prerequisite::add_dependent(shared_ptr<delayed_packet> d)
145{
146 delayed.insert(d);
147}
148
149void
150prerequisite::satisfy(shared_ptr<prerequisite> self,
151 packet_db_writer & pw)
152{
153 set< shared_ptr<delayed_packet> > dead;
154 for (set< shared_ptr<delayed_packet> >::const_iterator i = delayed.begin();
155 i != delayed.end(); ++i)
156 {
157 (*i)->prerequisite_satisfied(self, pw);
158 if ((*i)->all_prerequisites_satisfied())
159 dead.insert(*i);
160 }
161 for (set< shared_ptr<delayed_packet> >::const_iterator i = dead.begin();
162 i != dead.end(); ++i)
163 {
164 delayed.erase(*i);
165 }
166}
167
168void
169delayed_packet::add_prerequisite(shared_ptr<prerequisite> p)
170{
171 unsatisfied_prereqs.insert(p);
172}
173
174bool
175delayed_packet::all_prerequisites_satisfied()
176{
177 return unsatisfied_prereqs.empty();
178}
179
180void
181delayed_packet::prerequisite_satisfied(shared_ptr<prerequisite> p,
182 packet_db_writer & pw)
183{
184 I(unsatisfied_prereqs.find(p) != unsatisfied_prereqs.end());
185 unsatisfied_prereqs.erase(p);
186 satisfied_prereqs.insert(p);
187 if (all_prerequisites_satisfied())
188 {
189 apply_delayed_packet(pw);
190 }
191}
192
193
194// concrete delayed packets
195
196class
197delayed_revision_data_packet
198 : public delayed_packet
199{
200 revision_id ident;
201 revision_data dat;
202public:
203 delayed_revision_data_packet(revision_id const & i,
204 revision_data const & md)
205 : ident(i), dat(md)
206 {}
207 virtual void apply_delayed_packet(packet_db_writer & pw);
208 virtual ~delayed_revision_data_packet();
209};
210
211class
212delayed_manifest_data_packet
213 : public delayed_packet
214{
215 manifest_id ident;
216 manifest_data dat;
217public:
218 delayed_manifest_data_packet(manifest_id const & i,
219 manifest_data const & md)
220 : ident(i), dat(md)
221 {}
222 virtual void apply_delayed_packet(packet_db_writer & pw);
223 virtual ~delayed_manifest_data_packet();
224};
225
226class
227delayed_file_data_packet
228 : public delayed_packet
229{
230 file_id ident;
231 file_data dat;
232public:
233 delayed_file_data_packet(file_id const & i,
234 file_data const & fd)
235 : ident(i), dat(fd)
236 {}
237 virtual void apply_delayed_packet(packet_db_writer & pw);
238 virtual ~delayed_file_data_packet();
239};
240
241class
242delayed_file_delta_packet
243 : public delayed_packet
244{
245 file_id old_id;
246 file_id new_id;
247 file_delta del;
248 bool forward_delta;
249public:
250 delayed_file_delta_packet(file_id const & oi,
251 file_id const & ni,
252 file_delta const & md,
253 bool fwd)
254 : old_id(oi), new_id(ni), del(md), forward_delta(fwd)
255 {}
256 virtual void apply_delayed_packet(packet_db_writer & pw);
257 virtual ~delayed_file_delta_packet();
258};
259
260class
261delayed_manifest_delta_packet
262 : public delayed_packet
263{
264 manifest_id old_id;
265 manifest_id new_id;
266 manifest_delta del;
267 bool forward_delta;
268public:
269 delayed_manifest_delta_packet(manifest_id const & oi,
270 manifest_id const & ni,
271 manifest_delta const & md,
272 bool fwd)
273 : old_id(oi), new_id(ni), del(md), forward_delta(fwd)
274 {}
275 virtual void apply_delayed_packet(packet_db_writer & pw);
276 virtual ~delayed_manifest_delta_packet();
277};
278
279class
280delayed_revision_cert_packet
281 : public delayed_packet
282{
283 revision<cert> c;
284public:
285 delayed_revision_cert_packet(revision<cert> const & c)
286 : c(c)
287 {}
288 virtual void apply_delayed_packet(packet_db_writer & pw);
289 virtual ~delayed_revision_cert_packet();
290};
291
292class
293delayed_public_key_packet
294 : public delayed_packet
295{
296 rsa_keypair_id id;
297 base64<rsa_pub_key> key;
298public:
299 delayed_public_key_packet(rsa_keypair_id const & id,
300 base64<rsa_pub_key> key)
301 : id(id), key(key)
302 {}
303 virtual void apply_delayed_packet(packet_db_writer & pw);
304 virtual ~delayed_public_key_packet();
305};
306
307class
308delayed_private_key_packet
309 : public delayed_packet
310{
311 rsa_keypair_id id;
312 base64< arc4<rsa_priv_key> > key;
313public:
314 delayed_private_key_packet(rsa_keypair_id const & id,
315 base64< arc4<rsa_priv_key> > key)
316 : id(id), key(key)
317 {}
318 virtual void apply_delayed_packet(packet_db_writer & pw);
319 virtual ~delayed_private_key_packet();
320};
321
322void
323delayed_revision_data_packet::apply_delayed_packet(packet_db_writer & pw)
324{
325 L(F("writing delayed revision data packet for %s\n") % ident);
326 pw.consume_revision_data(ident, dat);
327}
328
329delayed_revision_data_packet::~delayed_revision_data_packet()
330{
331 if (!all_prerequisites_satisfied())
332 W(F("discarding revision data packet %s with unmet dependencies\n") % ident);
333}
334
335void
336delayed_manifest_data_packet::apply_delayed_packet(packet_db_writer & pw)
337{
338 L(F("writing delayed manifest data packet for %s\n") % ident);
339 pw.consume_manifest_data(ident, dat);
340}
341
342delayed_manifest_data_packet::~delayed_manifest_data_packet()
343{
344 if (!all_prerequisites_satisfied())
345 W(F("discarding manifest data packet %s with unmet dependencies\n") % ident);
346}
347
348void
349delayed_file_data_packet::apply_delayed_packet(packet_db_writer & pw)
350{
351 L(F("writing delayed file data packet for %s\n") % ident);
352 pw.consume_file_data(ident, dat);
353}
354
355delayed_file_data_packet::~delayed_file_data_packet()
356{
357 // files have no prerequisites
358 I(all_prerequisites_satisfied());
359}
360
361void
362delayed_manifest_delta_packet::apply_delayed_packet(packet_db_writer & pw)
363{
364 L(F("writing delayed manifest %s packet for %s -> %s\n")
365 % (forward_delta ? "delta" : "reverse delta")
366 % (forward_delta ? old_id : new_id)
367 % (forward_delta ? new_id : old_id));
368 if (forward_delta)
369 pw.consume_manifest_delta(old_id, new_id, del);
370 else
371 pw.consume_manifest_reverse_delta(new_id, old_id, del);
372}
373
374delayed_manifest_delta_packet::~delayed_manifest_delta_packet()
375{
376 if (!all_prerequisites_satisfied())
377 W(F("discarding manifest delta packet %s -> %s with unmet dependencies\n")
378 % old_id % new_id);
379}
380
381void
382delayed_file_delta_packet::apply_delayed_packet(packet_db_writer & pw)
383{
384 L(F("writing delayed file %s packet for %s -> %s\n")
385 % (forward_delta ? "delta" : "reverse delta")
386 % (forward_delta ? old_id : new_id)
387 % (forward_delta ? new_id : old_id));
388 if (forward_delta)
389 pw.consume_file_delta(old_id, new_id, del);
390 else
391 pw.consume_file_reverse_delta(new_id, old_id, del);
392}
393
394delayed_file_delta_packet::~delayed_file_delta_packet()
395{
396 if (!all_prerequisites_satisfied())
397 W(F("discarding file delta packet %s -> %s with unmet dependencies\n")
398 % old_id % new_id);
399}
400
401void
402delayed_revision_cert_packet::apply_delayed_packet(packet_db_writer & pw)
403{
404 L(F("writing delayed revision cert on %s\n") % c.inner().ident);
405 pw.consume_revision_cert(c);
406}
407
408delayed_revision_cert_packet::~delayed_revision_cert_packet()
409{
410 if (!all_prerequisites_satisfied())
411 W(F("discarding revision cert packet %s with unmet dependencies\n")
412 % c.inner().ident);
413}
414
415void
416delayed_public_key_packet::apply_delayed_packet(packet_db_writer & pw)
417{
418 L(F("writing delayed public key %s\n") % id());
419 pw.consume_public_key(id, key);
420}
421
422delayed_public_key_packet::~delayed_public_key_packet()
423{
424 // keys don't have dependencies
425 I(all_prerequisites_satisfied());
426}
427
428void
429delayed_private_key_packet::apply_delayed_packet(packet_db_writer & pw)
430{
431 L(F("writing delayed private key %s\n") % id());
432 pw.consume_private_key(id, key);
433}
434
435delayed_private_key_packet::~delayed_private_key_packet()
436{
437 // keys don't have dependencies
438 I(all_prerequisites_satisfied());
439}
440
441
442void
443packet_consumer::set_on_revision_written(boost::function1<void,
444 revision_id> const & x)
445{
446 on_revision_written=x;
447}
448
449void
450packet_consumer::set_on_cert_written(boost::function1<void,
451 cert const &> const & x)
452{
453 on_cert_written=x;
454}
455
456void
457packet_consumer::set_on_pubkey_written(boost::function1<void, rsa_keypair_id>
458 const & x)
459{
460 on_pubkey_written=x;
461}
462
463void
464packet_consumer::set_on_privkey_written(boost::function1<void, rsa_keypair_id>
465 const & x)
466{
467 on_privkey_written=x;
468}
469
470
471struct packet_db_writer::impl
472{
473 app_state & app;
474 bool take_keys;
475 size_t count;
476
477 map<revision_id, shared_ptr<prerequisite> > revision_prereqs;
478 map<manifest_id, shared_ptr<prerequisite> > manifest_prereqs;
479 map<file_id, shared_ptr<prerequisite> > file_prereqs;
480
481 // ticker cert;
482 // ticker manc;
483 // ticker manw;
484 // ticker filec;
485
486 bool revision_exists_in_db(revision_id const & r);
487 bool manifest_version_exists_in_db(manifest_id const & m);
488 bool file_version_exists_in_db(file_id const & f);
489
490 void get_revision_prereq(revision_id const & revision, shared_ptr<prerequisite> & p);
491 void get_manifest_prereq(manifest_id const & manifest, shared_ptr<prerequisite> & p);
492 void get_file_prereq(file_id const & file, shared_ptr<prerequisite> & p);
493
494 void accepted_revision(revision_id const & r, packet_db_writer & dbw);
495 void accepted_manifest(manifest_id const & m, packet_db_writer & dbw);
496 void accepted_file(file_id const & f, packet_db_writer & dbw);
497
498 impl(app_state & app, bool take_keys)
499 : app(app), take_keys(take_keys), count(0)
500 // cert("cert", 1), manc("manc", 1), manw("manw", 1), filec("filec", 1)
501 {}
502
503 ~impl();
504};
505
506packet_db_writer::packet_db_writer(app_state & app, bool take_keys)
507 : pimpl(new impl(app, take_keys))
508{}
509
510packet_db_writer::~packet_db_writer()
511{}
512
513packet_db_writer::impl::~impl()
514{
515
516 // break any circular dependencies for unsatisfied prerequisites
517 for (map<revision_id, shared_ptr<prerequisite> >::const_iterator i =
518 revision_prereqs.begin(); i != revision_prereqs.end(); i++)
519 {
520 i->second->cleanup();
521 }
522 for (map<manifest_id, shared_ptr<prerequisite> >::const_iterator i =
523 manifest_prereqs.begin(); i != manifest_prereqs.end(); i++)
524 {
525 i->second->cleanup();
526 }
527 for (map<file_id, shared_ptr<prerequisite> >::const_iterator i =
528 file_prereqs.begin(); i != file_prereqs.end(); i++)
529 {
530 i->second->cleanup();
531 }
532}
533
534bool
535packet_db_writer::impl::revision_exists_in_db(revision_id const & r)
536{
537 return app.db.revision_exists(r);
538}
539
540bool
541packet_db_writer::impl::manifest_version_exists_in_db(manifest_id const & m)
542{
543 return app.db.manifest_version_exists(m);
544}
545
546bool
547packet_db_writer::impl::file_version_exists_in_db(file_id const & f)
548{
549 return app.db.file_version_exists(f);
550}
551
552void
553packet_db_writer::impl::get_file_prereq(file_id const & file,
554 shared_ptr<prerequisite> & p)
555{
556 map<file_id, shared_ptr<prerequisite> >::const_iterator i;
557 i = file_prereqs.find(file);
558 if (i != file_prereqs.end())
559 p = i->second;
560 else
561 {
562 p = shared_ptr<prerequisite>(new prerequisite(file.inner(), prereq_file));
563 file_prereqs.insert(make_pair(file, p));
564 }
565}
566
567void
568packet_db_writer::impl::get_manifest_prereq(manifest_id const & man,
569 shared_ptr<prerequisite> & p)
570{
571 map<manifest_id, shared_ptr<prerequisite> >::const_iterator i;
572 i = manifest_prereqs.find(man);
573 if (i != manifest_prereqs.end())
574 p = i->second;
575 else
576 {
577 p = shared_ptr<prerequisite>(new prerequisite(man.inner(), prereq_manifest));
578 manifest_prereqs.insert(make_pair(man, p));
579 }
580}
581
582void
583packet_db_writer::impl::get_revision_prereq(revision_id const & rev,
584 shared_ptr<prerequisite> & p)
585{
586 map<revision_id, shared_ptr<prerequisite> >::const_iterator i;
587 i = revision_prereqs.find(rev);
588 if (i != revision_prereqs.end())
589 p = i->second;
590 else
591 {
592 p = shared_ptr<prerequisite>(new prerequisite(rev.inner(), prereq_revision));
593 revision_prereqs.insert(make_pair(rev, p));
594 }
595}
596
597
598void
599packet_db_writer::impl::accepted_revision(revision_id const & r, packet_db_writer & dbw)
600{
601 L(F("noting acceptence of revision %s\n") % r);
602 map<revision_id, shared_ptr<prerequisite> >::iterator i = revision_prereqs.find(r);
603 if (i != revision_prereqs.end())
604 {
605 shared_ptr<prerequisite> prereq = i->second;
606 revision_prereqs.erase(i);
607 prereq->satisfy(prereq, dbw);
608 }
609}
610
611void
612packet_db_writer::impl::accepted_manifest(manifest_id const & m, packet_db_writer & dbw)
613{
614 L(F("noting acceptence of manifest %s\n") % m);
615 map<manifest_id, shared_ptr<prerequisite> >::iterator i = manifest_prereqs.find(m);
616 if (i != manifest_prereqs.end())
617 {
618 shared_ptr<prerequisite> prereq = i->second;
619 manifest_prereqs.erase(i);
620 prereq->satisfy(prereq, dbw);
621 }
622}
623
624void
625packet_db_writer::impl::accepted_file(file_id const & f, packet_db_writer & dbw)
626{
627 L(F("noting acceptence of file %s\n") % f);
628 map<file_id, shared_ptr<prerequisite> >::iterator i = file_prereqs.find(f);
629 if (i != file_prereqs.end())
630 {
631 shared_ptr<prerequisite> prereq = i->second;
632 file_prereqs.erase(i);
633 prereq->satisfy(prereq, dbw);
634 }
635}
636
637
638void
639packet_db_writer::consume_file_data(file_id const & ident,
640 file_data const & dat)
641{
642 transaction_guard guard(pimpl->app.db);
643 if (! pimpl->file_version_exists_in_db(ident))
644 {
645 pimpl->app.db.put_file(ident, dat);
646 pimpl->accepted_file(ident, *this);
647 }
648 else
649 L(F("skipping existing file version %s\n") % ident);
650 ++(pimpl->count);
651 guard.commit();
652}
653
654void
655packet_db_writer::consume_file_delta(file_id const & old_id,
656 file_id const & new_id,
657 file_delta const & del)
658{
659 transaction_guard guard(pimpl->app.db);
660 if (! pimpl->file_version_exists_in_db(new_id))
661 {
662 if (pimpl->file_version_exists_in_db(old_id))
663 {
664 file_id confirm;
665 file_data old_dat;
666 data new_dat;
667 pimpl->app.db.get_file_version(old_id, old_dat);
668 patch(old_dat.inner(), del.inner(), new_dat);
669 calculate_ident(file_data(new_dat), confirm);
670 if (confirm == new_id)
671 {
672 pimpl->app.db.put_file_version(old_id, new_id, del);
673 pimpl->accepted_file(new_id, *this);
674 }
675 else
676 {
677 W(F("reconstructed file from delta '%s' -> '%s' has wrong id '%s'\n")
678 % old_id % new_id % confirm);
679 }
680 }
681 else
682 {
683 L(F("delaying file delta %s -> %s for preimage\n") % old_id % new_id);
684 shared_ptr<delayed_packet> dp;
685 dp = shared_ptr<delayed_packet>(new delayed_file_delta_packet(old_id, new_id, del, true));
686 shared_ptr<prerequisite> fp;
687 pimpl->get_file_prereq(old_id, fp);
688 dp->add_prerequisite(fp);
689 fp->add_dependent(dp);
690 }
691 }
692 else
693 L(F("skipping delta to existing file version %s\n") % new_id);
694 ++(pimpl->count);
695 guard.commit();
696}
697
698void
699packet_db_writer::consume_file_reverse_delta(file_id const & new_id,
700 file_id const & old_id,
701 file_delta const & del)
702{
703 transaction_guard guard(pimpl->app.db);
704 if (! pimpl->file_version_exists_in_db(old_id))
705 {
706 if (pimpl->file_version_exists_in_db(new_id))
707 {
708 file_id confirm;
709 file_data new_dat;
710 data old_dat;
711 pimpl->app.db.get_file_version(new_id, new_dat);
712 patch(new_dat.inner(), del.inner(), old_dat);
713 calculate_ident(file_data(old_dat), confirm);
714 if (confirm == old_id)
715 {
716 pimpl->app.db.put_file_reverse_version(new_id, old_id, del);
717 pimpl->accepted_file(old_id, *this);
718 }
719 else
720 {
721 W(F("reconstructed file from reverse delta '%s' -> '%s' has wrong id '%s'\n")
722 % new_id % old_id % confirm);
723 }
724 }
725 else
726 {
727 L(F("delaying reverse file delta %s -> %s for preimage\n") % new_id % old_id);
728 shared_ptr<delayed_packet> dp;
729 dp = shared_ptr<delayed_packet>(new delayed_file_delta_packet(old_id, new_id, del, false));
730 shared_ptr<prerequisite> fp;
731 pimpl->get_file_prereq(new_id, fp);
732 dp->add_prerequisite(fp);
733 fp->add_dependent(dp);
734 }
735 }
736 else
737 L(F("skipping reverse delta to existing file version %s\n") % old_id);
738 ++(pimpl->count);
739 guard.commit();
740}
741
742
743void
744packet_db_writer::consume_manifest_data(manifest_id const & ident,
745 manifest_data const & dat)
746{
747 transaction_guard guard(pimpl->app.db);
748 if (! pimpl->manifest_version_exists_in_db(ident))
749 {
750 pimpl->app.db.put_manifest(ident, dat);
751 pimpl->accepted_manifest(ident, *this);
752 }
753 else
754 L(F("skipping existing manifest version %s\n") % ident);
755 ++(pimpl->count);
756 guard.commit();
757}
758
759void
760packet_db_writer::consume_manifest_delta(manifest_id const & old_id,
761 manifest_id const & new_id,
762 manifest_delta const & del)
763{
764 transaction_guard guard(pimpl->app.db);
765 if (! pimpl->manifest_version_exists_in_db(new_id))
766 {
767 if (pimpl->manifest_version_exists_in_db(old_id))
768 {
769 manifest_id confirm;
770 manifest_data old_dat;
771 data new_dat;
772 pimpl->app.db.get_manifest_version(old_id, old_dat);
773 patch(old_dat.inner(), del.inner(), new_dat);
774 calculate_ident(manifest_data(new_dat), confirm);
775 if (confirm == new_id)
776 {
777 pimpl->app.db.put_manifest_version(old_id, new_id, del);
778 pimpl->accepted_manifest(new_id, *this);
779 }
780 else
781 {
782 W(F("reconstructed manifest from delta '%s' -> '%s' has wrong id '%s'\n")
783 % old_id % new_id % confirm);
784 }
785 }
786 else
787 {
788 L(F("delaying manifest delta %s -> %s for preimage\n") % old_id % new_id);
789 shared_ptr<delayed_packet> dp;
790 dp = shared_ptr<delayed_packet>(new delayed_manifest_delta_packet(old_id, new_id, del, true));
791 shared_ptr<prerequisite> fp;
792 pimpl->get_manifest_prereq(old_id, fp);
793 dp->add_prerequisite(fp);
794 fp->add_dependent(dp);
795 }
796 }
797 else
798 L(F("skipping delta to existing manifest version %s\n") % new_id);
799 ++(pimpl->count);
800 guard.commit();
801}
802
803void
804packet_db_writer::consume_manifest_reverse_delta(manifest_id const & new_id,
805 manifest_id const & old_id,
806 manifest_delta const & del)
807{
808 transaction_guard guard(pimpl->app.db);
809 if (! pimpl->manifest_version_exists_in_db(old_id))
810 {
811 if (pimpl->manifest_version_exists_in_db(new_id))
812 {
813 manifest_id confirm;
814 manifest_data new_dat;
815 data old_dat;
816 pimpl->app.db.get_manifest_version(new_id, new_dat);
817 patch(new_dat.inner(), del.inner(), old_dat);
818 calculate_ident(manifest_data(old_dat), confirm);
819 if (confirm == old_id)
820 {
821 pimpl->app.db.put_manifest_reverse_version(new_id, old_id, del);
822 pimpl->accepted_manifest(old_id, *this);
823 }
824 else
825 {
826 W(F("reconstructed manifest from reverse delta '%s' -> '%s' has wrong id '%s'\n")
827 % new_id % old_id % confirm);
828 }
829 }
830 else
831 {
832 L(F("delaying manifest reverse delta %s -> %s for preimage\n") % new_id % old_id);
833 shared_ptr<delayed_packet> dp;
834 dp = shared_ptr<delayed_packet>(new delayed_manifest_delta_packet(old_id, new_id, del, false));
835 shared_ptr<prerequisite> fp;
836 pimpl->get_manifest_prereq(new_id, fp);
837 dp->add_prerequisite(fp);
838 fp->add_dependent(dp);
839 }
840 }
841 else
842 L(F("skipping reverse delta to existing manifest version %s\n") % old_id);
843 ++(pimpl->count);
844 guard.commit();
845}
846
847
848void
849packet_db_writer::consume_revision_data(revision_id const & ident,
850 revision_data const & dat)
851{
852 transaction_guard guard(pimpl->app.db);
853 if (! pimpl->revision_exists_in_db(ident))
854 {
855
856 shared_ptr<delayed_packet> dp;
857 dp = shared_ptr<delayed_packet>(new delayed_revision_data_packet(ident, dat));
858
859 revision_set rev;
860 read_revision_set(dat, rev);
861
862 if (! pimpl->manifest_version_exists_in_db(rev.new_manifest))
863 {
864 L(F("delaying revision %s for new manifest %s\n")
865 % ident % rev.new_manifest);
866 shared_ptr<prerequisite> fp;
867 pimpl->get_manifest_prereq(rev.new_manifest, fp);
868 dp->add_prerequisite(fp);
869 fp->add_dependent(dp);
870 }
871
872 for (edge_map::const_iterator i = rev.edges.begin();
873 i != rev.edges.end(); ++i)
874 {
875 if (! (edge_old_manifest(i).inner()().empty()
876 || pimpl->manifest_version_exists_in_db(edge_old_manifest(i))))
877 {
878 L(F("delaying revision %s for old manifest %s\n")
879 % ident % edge_old_manifest(i));
880 shared_ptr<prerequisite> fp;
881 pimpl->get_manifest_prereq(edge_old_manifest(i), fp);
882 dp->add_prerequisite(fp);
883 fp->add_dependent(dp);
884 }
885 if (! (edge_old_revision(i).inner()().empty()
886 || pimpl->revision_exists_in_db(edge_old_revision(i))))
887 {
888 L(F("delaying revision %s for old revision %s\n")
889 % ident % edge_old_revision(i));
890 shared_ptr<prerequisite> fp;
891 pimpl->get_revision_prereq(edge_old_revision(i), fp);
892 dp->add_prerequisite(fp);
893 fp->add_dependent(dp);
894 }
895 for (change_set::delta_map::const_iterator d = edge_changes(i).deltas.begin();
896 d != edge_changes(i).deltas.end(); ++d)
897 {
898 if (! (delta_entry_src(d).inner()().empty()
899 || pimpl->file_version_exists_in_db(delta_entry_src(d))))
900 {
901 L(F("delaying revision %s for old file %s\n")
902 % ident % delta_entry_src(d));
903 shared_ptr<prerequisite> fp;
904 pimpl->get_file_prereq(delta_entry_src(d), fp);
905 dp->add_prerequisite(fp);
906 fp->add_dependent(dp);
907 }
908 I(!delta_entry_dst(d).inner()().empty());
909 if (! pimpl->file_version_exists_in_db(delta_entry_dst(d)))
910 {
911 L(F("delaying revision %s for new file %s\n")
912 % ident % delta_entry_dst(d));
913 shared_ptr<prerequisite> fp;
914 pimpl->get_file_prereq(delta_entry_dst(d), fp);
915 dp->add_prerequisite(fp);
916 fp->add_dependent(dp);
917 }
918 }
919 }
920
921 if (dp->all_prerequisites_satisfied())
922 {
923 pimpl->app.db.put_revision(ident, dat);
924 if(on_revision_written) on_revision_written(ident);
925 pimpl->accepted_revision(ident, *this);
926 }
927 }
928 else
929 L(F("skipping existing revision %s\n") % ident);
930 ++(pimpl->count);
931 guard.commit();
932}
933
934void
935packet_db_writer::consume_revision_cert(revision<cert> const & t)
936{
937 transaction_guard guard(pimpl->app.db);
938 if (! pimpl->app.db.revision_cert_exists(t))
939 {
940 if (pimpl->revision_exists_in_db(revision_id(t.inner().ident)))
941 {
942 pimpl->app.db.put_revision_cert(t);
943 if(on_cert_written) on_cert_written(t.inner());
944 }
945 else
946 {
947 L(F("delaying revision cert on %s\n") % t.inner().ident);
948 shared_ptr<delayed_packet> dp;
949 dp = shared_ptr<delayed_packet>(new delayed_revision_cert_packet(t));
950 shared_ptr<prerequisite> fp;
951 pimpl->get_revision_prereq(revision_id(t.inner().ident), fp);
952 dp->add_prerequisite(fp);
953 fp->add_dependent(dp);
954 }
955 }
956 else
957 {
958 string s;
959 cert_signable_text(t.inner(), s);
960 L(F("skipping existing revision cert %s\n") % s);
961 }
962 ++(pimpl->count);
963 guard.commit();
964}
965
966
967void
968packet_db_writer::consume_public_key(rsa_keypair_id const & ident,
969 base64< rsa_pub_key > const & k)
970{
971 transaction_guard guard(pimpl->app.db);
972 if (! pimpl->take_keys)
973 {
974 W(F("skipping prohibited public key %s\n") % ident);
975 return;
976 }
977 if (! pimpl->app.db.public_key_exists(ident))
978 {
979 pimpl->app.db.put_key(ident, k);
980 if(on_pubkey_written) on_pubkey_written(ident);
981 }
982 else
983 {
984 base64<rsa_pub_key> tmp;
985 pimpl->app.db.get_key(ident, tmp);
986 if (!keys_match(ident, tmp, ident, k))
987 W(F("key '%s' is not equal to key '%s' in database\n") % ident % ident);
988 L(F("skipping existing public key %s\n") % ident);
989 }
990 ++(pimpl->count);
991 guard.commit();
992}
993
994void
995packet_db_writer::consume_private_key(rsa_keypair_id const & ident,
996 base64< arc4<rsa_priv_key> > const & k)
997{
998 transaction_guard guard(pimpl->app.db);
999 if (! pimpl->take_keys)
1000 {
1001 W(F("skipping prohibited private key %s\n") % ident);
1002 return;
1003 }
1004 if (! pimpl->app.db.private_key_exists(ident))
1005 {
1006 pimpl->app.db.put_key(ident, k);
1007 if(on_privkey_written) on_privkey_written(ident);
1008 }
1009 else
1010 L(F("skipping existing private key %s\n") % ident);
1011 ++(pimpl->count);
1012 guard.commit();
1013}
1014
1015
1016// --- valved packet writer ---
1017
1018struct packet_db_valve::impl
1019{
1020 packet_db_writer writer;
1021 std::vector< boost::shared_ptr<delayed_packet> > packets;
1022 bool valve_is_open;
1023 impl(app_state & app, bool take_keys)
1024 : writer(app, take_keys),
1025 valve_is_open(false)
1026 {}
1027 void do_packet(boost::shared_ptr<delayed_packet> packet)
1028 {
1029 if (valve_is_open)
1030 packet->apply_delayed_packet(writer);
1031 else
1032 packets.push_back(packet);
1033 }
1034};
1035
1036packet_db_valve::packet_db_valve(app_state & app, bool take_keys)
1037 : pimpl(new impl(app, take_keys))
1038{}
1039
1040packet_db_valve::~packet_db_valve()
1041{}
1042
1043void
1044packet_db_valve::open_valve()
1045{
1046 L(F("packet valve opened\n"));
1047 pimpl->valve_is_open = true;
1048 int written = 0;
1049 for (std::vector< boost::shared_ptr<delayed_packet> >::reverse_iterator
1050 i = pimpl->packets.rbegin();
1051 i != pimpl->packets.rend();
1052 ++i)
1053 {
1054 pimpl->do_packet(*i);
1055 ++written;
1056 }
1057 pimpl->packets.clear();
1058 L(F("wrote %i queued packets\n") % written);
1059}
1060
1061#define DOIT(x) pimpl->do_packet(boost::shared_ptr<delayed_packet>(new x));
1062
1063void
1064packet_db_valve::set_on_revision_written(boost::function1<void,
1065 revision_id> const & x)
1066{
1067 on_revision_written=x;
1068 pimpl->writer.set_on_revision_written(x);
1069}
1070
1071void
1072packet_db_valve::set_on_cert_written(boost::function1<void,
1073 cert const &> const & x)
1074{
1075 on_cert_written=x;
1076 pimpl->writer.set_on_cert_written(x);
1077}
1078
1079void
1080packet_db_valve::set_on_pubkey_written(boost::function1<void, rsa_keypair_id>
1081 const & x)
1082{
1083 on_pubkey_written=x;
1084 pimpl->writer.set_on_pubkey_written(x);
1085}
1086
1087void
1088packet_db_valve::set_on_privkey_written(boost::function1<void, rsa_keypair_id>
1089 const & x)
1090{
1091 on_privkey_written=x;
1092 pimpl->writer.set_on_privkey_written(x);
1093}
1094
1095void
1096packet_db_valve::consume_file_data(file_id const & ident,
1097 file_data const & dat)
1098{
1099 DOIT(delayed_file_data_packet(ident, dat));
1100}
1101
1102void
1103packet_db_valve::consume_file_delta(file_id const & id_old,
1104 file_id const & id_new,
1105 file_delta const & del)
1106{
1107 DOIT(delayed_file_delta_packet(id_old, id_new, del, true));
1108}
1109
1110void
1111packet_db_valve::consume_file_reverse_delta(file_id const & id_new,
1112 file_id const & id_old,
1113 file_delta const & del)
1114{
1115 DOIT(delayed_file_delta_packet(id_old, id_new, del, false));
1116}
1117
1118void
1119packet_db_valve::consume_manifest_data(manifest_id const & ident,
1120 manifest_data const & dat)
1121{
1122 DOIT(delayed_manifest_data_packet(ident, dat));
1123}
1124
1125void
1126packet_db_valve::consume_manifest_delta(manifest_id const & id_old,
1127 manifest_id const & id_new,
1128 manifest_delta const & del)
1129{
1130 DOIT(delayed_manifest_delta_packet(id_old, id_new, del, true));
1131}
1132
1133void
1134packet_db_valve::consume_manifest_reverse_delta(manifest_id const & id_new,
1135 manifest_id const & id_old,
1136 manifest_delta const & del)
1137{
1138 DOIT(delayed_manifest_delta_packet(id_old, id_new, del, false));
1139}
1140
1141void
1142packet_db_valve::consume_revision_data(revision_id const & ident,
1143 revision_data const & dat)
1144{
1145 DOIT(delayed_revision_data_packet(ident, dat));
1146}
1147
1148void
1149packet_db_valve::consume_revision_cert(revision<cert> const & t)
1150{
1151 DOIT(delayed_revision_cert_packet(t));
1152}
1153
1154void
1155packet_db_valve::consume_public_key(rsa_keypair_id const & ident,
1156 base64< rsa_pub_key > const & k)
1157{
1158 DOIT(delayed_public_key_packet(ident, k));
1159}
1160
1161void
1162packet_db_valve::consume_private_key(rsa_keypair_id const & ident,
1163 base64< arc4<rsa_priv_key> > const & k)
1164{
1165 DOIT(delayed_private_key_packet(ident, k));
1166}
1167
1168#undef DOIT
1169
1170// --- packet writer ---
1171
1172packet_writer::packet_writer(ostream & o) : ost(o) {}
1173
1174void
1175packet_writer::consume_file_data(file_id const & ident,
1176 file_data const & dat)
1177{
1178 base64<gzip<data> > packed;
1179 pack(dat.inner(), packed);
1180 ost << "[fdata " << ident.inner()() << "]" << endl
1181 << trim_ws(packed()) << endl
1182 << "[end]" << endl;
1183}
1184
1185void
1186packet_writer::consume_file_delta(file_id const & old_id,
1187 file_id const & new_id,
1188 file_delta const & del)
1189{
1190 base64<gzip<delta> > packed;
1191 pack(del.inner(), packed);
1192 ost << "[fdelta " << old_id.inner()() << endl
1193 << " " << new_id.inner()() << "]" << endl
1194 << trim_ws(packed()) << endl
1195 << "[end]" << endl;
1196}
1197
1198void
1199packet_writer::consume_file_reverse_delta(file_id const & new_id,
1200 file_id const & old_id,
1201 file_delta const & del)
1202{
1203 base64<gzip<delta> > packed;
1204 pack(del.inner(), packed);
1205 ost << "[frdelta " << new_id.inner()() << endl
1206 << " " << old_id.inner()() << "]" << endl
1207 << trim_ws(packed()) << endl
1208 << "[end]" << endl;
1209}
1210
1211void
1212packet_writer::consume_manifest_data(manifest_id const & ident,
1213 manifest_data const & dat)
1214{
1215 base64<gzip<data> > packed;
1216 pack(dat.inner(), packed);
1217 ost << "[mdata " << ident.inner()() << "]" << endl
1218 << trim_ws(packed()) << endl
1219 << "[end]" << endl;
1220}
1221
1222void
1223packet_writer::consume_revision_data(revision_id const & ident,
1224 revision_data const & dat)
1225{
1226 base64<gzip<data> > packed;
1227 pack(dat.inner(), packed);
1228 ost << "[rdata " << ident.inner()() << "]" << endl
1229 << trim_ws(packed()) << endl
1230 << "[end]" << endl;
1231}
1232
1233void
1234packet_writer::consume_manifest_delta(manifest_id const & old_id,
1235 manifest_id const & new_id,
1236 manifest_delta const & del)
1237{
1238 base64<gzip<delta> > packed;
1239 pack(del.inner(), packed);
1240 ost << "[mdelta " << old_id.inner()() << endl
1241 << " " << new_id.inner()() << "]" << endl
1242 << trim_ws(packed()) << endl
1243 << "[end]" << endl;
1244}
1245
1246void
1247packet_writer::consume_manifest_reverse_delta(manifest_id const & new_id,
1248 manifest_id const & old_id,
1249 manifest_delta const & del)
1250{
1251 base64<gzip<delta> > packed;
1252 pack(del.inner(), packed);
1253 ost << "[mrdelta " << new_id.inner()() << endl
1254 << " " << old_id.inner()() << "]" << endl
1255 << trim_ws(packed()) << endl
1256 << "[end]" << endl;
1257}
1258
1259void
1260packet_writer::consume_revision_cert(revision<cert> const & t)
1261{
1262 ost << "[rcert " << t.inner().ident() << endl
1263 << " " << t.inner().name() << endl
1264 << " " << t.inner().key() << endl
1265 << " " << trim_ws(t.inner().value()) << "]" << endl
1266 << trim_ws(t.inner().sig()) << endl
1267 << "[end]" << endl;
1268}
1269
1270void
1271packet_writer::consume_public_key(rsa_keypair_id const & ident,
1272 base64< rsa_pub_key > const & k)
1273{
1274 ost << "[pubkey " << ident() << "]" << endl
1275 << trim_ws(k()) << endl
1276 << "[end]" << endl;
1277}
1278
1279void
1280packet_writer::consume_private_key(rsa_keypair_id const & ident,
1281 base64< arc4<rsa_priv_key> > const & k)
1282{
1283 ost << "[privkey " << ident() << "]" << endl
1284 << trim_ws(k()) << endl
1285 << "[end]" << endl;
1286}
1287
1288
1289// -- remainder just deals with the regexes for reading packets off streams
1290
1291struct
1292feed_packet_consumer
1293{
1294 size_t & count;
1295 packet_consumer & cons;
1296 feed_packet_consumer(size_t & count, packet_consumer & c) : count(count), cons(c)
1297 {}
1298 bool operator()(match_results<std::string::const_iterator> const & res) const
1299 {
1300 if (res.size() != 17)
1301 throw oops("matched impossible packet with "
1302 + lexical_cast<string>(res.size()) + " matching parts: " +
1303 string(res[0].first, res[0].second));
1304
1305 if (res[1].matched)
1306 {
1307 L(F("read data packet\n"));
1308 I(res[2].matched);
1309 I(res[3].matched);
1310 string head(res[1].first, res[1].second);
1311 string ident(res[2].first, res[2].second);
1312 base64<gzip<data> > body_packed(trim_ws(string(res[3].first, res[3].second)));
1313 data body;
1314 unpack(body_packed, body);
1315 if (head == "rdata")
1316 cons.consume_revision_data(revision_id(hexenc<id>(ident)),
1317 revision_data(body));
1318 else if (head == "mdata")
1319 cons.consume_manifest_data(manifest_id(hexenc<id>(ident)),
1320 manifest_data(body));
1321 else if (head == "fdata")
1322 cons.consume_file_data(file_id(hexenc<id>(ident)),
1323 file_data(body));
1324 else
1325 throw oops("matched impossible data packet with head '" + head + "'");
1326 }
1327 else if (res[4].matched)
1328 {
1329 L(F("read delta packet\n"));
1330 I(res[5].matched);
1331 I(res[6].matched);
1332 I(res[7].matched);
1333 string head(res[4].first, res[4].second);
1334 string src_id(res[5].first, res[5].second);
1335 string dst_id(res[6].first, res[6].second);
1336 base64<gzip<delta> > body_packed(trim_ws(string(res[7].first, res[7].second)));
1337 delta body;
1338 unpack(body_packed, body);
1339 if (head == "mdelta")
1340 cons.consume_manifest_delta(manifest_id(hexenc<id>(src_id)),
1341 manifest_id(hexenc<id>(dst_id)),
1342 manifest_delta(body));
1343 else if (head == "fdelta")
1344 cons.consume_file_delta(file_id(hexenc<id>(src_id)),
1345 file_id(hexenc<id>(dst_id)),
1346 file_delta(body));
1347 else if (head == "mrdelta")
1348 cons.consume_manifest_reverse_delta(manifest_id(hexenc<id>(src_id)),
1349 manifest_id(hexenc<id>(dst_id)),
1350 manifest_delta(body));
1351 else if (head == "frdelta")
1352 cons.consume_file_reverse_delta(file_id(hexenc<id>(src_id)),
1353 file_id(hexenc<id>(dst_id)),
1354 file_delta(body));
1355 else
1356 throw oops("matched impossible delta packet with head '" + head + "'");
1357 }
1358 else if (res[8].matched)
1359 {
1360 L(F("read cert packet\n"));
1361 I(res[9].matched);
1362 I(res[10].matched);
1363 I(res[11].matched);
1364 I(res[12].matched);
1365 I(res[13].matched);
1366 string head(res[8].first, res[8].second);
1367 string ident(res[9].first, res[9].second);
1368 string certname(res[10].first, res[10].second);
1369 string key(res[11].first, res[11].second);
1370 string val(res[12].first, res[12].second);
1371 string body(trim_ws(string(res[13].first, res[13].second)));
1372
1373 // canonicalize the base64 encodings to permit searches
1374 cert t = cert(hexenc<id>(ident),
1375 cert_name(certname),
1376 base64<cert_value>(canonical_base64(val)),
1377 rsa_keypair_id(key),
1378 base64<rsa_sha1_signature>(canonical_base64(body)));
1379 if (head == "rcert")
1380 cons.consume_revision_cert(revision<cert>(t));
1381 else
1382 throw oops("matched impossible cert packet with head '" + head + "'");
1383 }
1384 else if (res[14].matched)
1385 {
1386 L(F("read key data packet\n"));
1387 I(res[15].matched);
1388 I(res[16].matched);
1389 string head(res[14].first, res[14].second);
1390 string ident(res[15].first, res[15].second);
1391 string body(trim_ws(string(res[16].first, res[16].second)));
1392 if (head == "pubkey")
1393 cons.consume_public_key(rsa_keypair_id(ident),
1394 base64<rsa_pub_key>(body));
1395 else if (head == "privkey")
1396 cons.consume_private_key(rsa_keypair_id(ident),
1397 base64< arc4<rsa_priv_key> >(body));
1398 else
1399 throw oops("matched impossible key data packet with head '" + head + "'");
1400 }
1401 else
1402 return true;
1403 ++count;
1404 return true;
1405 }
1406};
1407
1408static size_t
1409extract_packets(string const & s, packet_consumer & cons)
1410{
1411 string const ident("([[:xdigit:]]{40})");
1412 string const sp("[[:space:]]+");
1413 string const bra("\\[");
1414 string const ket("\\]");
1415 string const certhead("(rcert)");
1416 string const datahead("([mfr]data)");
1417 string const deltahead("([mf]r?delta)");
1418 string const keyhead("(pubkey|privkey)");
1419 string const key("([-a-zA-Z0-9\\.@]+)");
1420 string const certname("([-a-zA-Z0-9]+)");
1421 string const base64("([a-zA-Z0-9+/=[:space:]]+)");
1422 string const end("\\[end\\]");
1423 string const data = bra + datahead + sp + ident + ket + base64 + end;
1424 string const delta = bra + deltahead + sp + ident + sp + ident + ket + base64 + end;
1425 string const cert = bra
1426 + certhead + sp + ident + sp + certname + sp + key + sp + base64
1427 + ket
1428 + base64 + end;
1429 string const keydata = bra + keyhead + sp + key + ket + base64 + end;
1430 string const biggie = (data + "|" + delta + "|" + cert + "|" + keydata);
1431 regex expr(biggie);
1432 size_t count = 0;
1433 regex_grep(feed_packet_consumer(count, cons), s, expr, match_default);
1434 return count;
1435}
1436
1437
1438size_t
1439read_packets(istream & in, packet_consumer & cons)
1440{
1441 string accum, tmp;
1442 size_t count = 0;
1443 size_t const bufsz = 0xff;
1444 char buf[bufsz];
1445 string const end("[end]");
1446 while(in)
1447 {
1448 in.read(buf, bufsz);
1449 accum.append(buf, in.gcount());
1450 string::size_type endpos = string::npos;
1451 endpos = accum.rfind(end);
1452 if (endpos != string::npos)
1453 {
1454 endpos += end.size();
1455 string tmp = accum.substr(0, endpos);
1456 count += extract_packets(tmp, cons);
1457 if (endpos < accum.size() - 1)
1458 accum = accum.substr(endpos+1);
1459 else
1460 accum.clear();
1461 }
1462 }
1463 return count;
1464}
1465
1466
1467#ifdef BUILD_UNIT_TESTS
1468#include "unit_tests.hh"
1469#include "transforms.hh"
1470#include "manifest.hh"
1471
1472static void
1473packet_roundabout_test()
1474{
1475 string tmp;
1476
1477 {
1478 ostringstream oss;
1479 packet_writer pw(oss);
1480
1481 // an fdata packet
1482 file_data fdata(data("this is some file data"));
1483 file_id fid;
1484 calculate_ident(fdata, fid);
1485 pw.consume_file_data(fid, fdata);
1486
1487 // an fdelta packet
1488 file_data fdata2(data("this is some file data which is not the same as the first one"));
1489 file_id fid2;
1490 calculate_ident(fdata2, fid);
1491 delta del;
1492 diff(fdata.inner(), fdata2.inner(), del);
1493 pw.consume_file_delta(fid, fid2, file_delta(del));
1494
1495 // a cert packet
1496 base64<cert_value> val;
1497 encode_base64(cert_value("peaches"), val);
1498 base64<rsa_sha1_signature> sig;
1499 encode_base64(rsa_sha1_signature("blah blah there is no way this is a valid signature"), sig);
1500 // should be a type violation to use a file id here instead of a revision
1501 // id, but no-one checks...
1502 cert c(fid.inner(), cert_name("smell"), val,
1503 rsa_keypair_id("fun@moonman.com"), sig);
1504 pw.consume_revision_cert(revision<cert>(c));
1505
1506 // a manifest data packet
1507 manifest_map mm;
1508 manifest_data mdata;
1509 manifest_id mid;
1510 mm.insert(make_pair(file_path_internal("foo/bar.txt"),
1511 file_id(hexenc<id>("cfb81b30ab3133a31b52eb50bd1c86df67eddec4"))));
1512 write_manifest_map(mm, mdata);
1513 calculate_ident(mdata, mid);
1514 pw.consume_manifest_data(mid, mdata);
1515
1516 // a manifest delta packet
1517 manifest_map mm2;
1518 manifest_data mdata2;
1519 manifest_id mid2;
1520 manifest_delta mdelta;
1521 mm2.insert(make_pair(file_path_internal("foo/bar.txt"),
1522 file_id(hexenc<id>("5b20eb5e5bdd9cd674337fc95498f468d80ef7bc"))));
1523 mm2.insert(make_pair(file_path_internal("bunk.txt"),
1524 file_id(hexenc<id>("54f373ed07b4c5a88eaa93370e1bbac02dc432a8"))));
1525 write_manifest_map(mm2, mdata2);
1526 calculate_ident(mdata2, mid2);
1527 delta del2;
1528 diff(mdata.inner(), mdata2.inner(), del2);
1529 pw.consume_manifest_delta(mid, mid2, manifest_delta(del));
1530
1531 // a public key packet
1532 base64<rsa_pub_key> puk;
1533 encode_base64(rsa_pub_key("this is not a real rsa key"), puk);
1534 pw.consume_public_key(rsa_keypair_id("test@lala.com"), puk);
1535
1536 // a private key packet
1537 base64< arc4<rsa_priv_key> > pik;
1538 encode_base64(arc4<rsa_priv_key>
1539 (rsa_priv_key("this is not a real rsa key either!")), pik);
1540
1541 pw.consume_private_key(rsa_keypair_id("test@lala.com"), pik);
1542
1543 }
1544
1545 for (int i = 0; i < 10; ++i)
1546 {
1547 // now spin around sending and receiving this a few times
1548 ostringstream oss;
1549 packet_writer pw(oss);
1550 istringstream iss(tmp);
1551 read_packets(iss, pw);
1552 BOOST_CHECK(oss.str() == tmp);
1553 tmp = oss.str();
1554 }
1555}
1556
1557void
1558add_packet_tests(test_suite * suite)
1559{
1560 I(suite);
1561 suite->add(BOOST_TEST_CASE(&packet_roundabout_test));
1562}
1563
1564#endif // BUILD_UNIT_TESTS

Archive Download this file

Branches

Tags

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