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
13#include "app_state.hh"
14#include "network.hh"
15#include "packet.hh"
16#include "sanity.hh"
17#include "transforms.hh"
18
19using namespace boost;
20using namespace std;
21
22// --- packet db writer --
23
24packet_db_writer::packet_db_writer(app_state & app, bool take_keys)
25 : app(app), take_keys(take_keys), count(0)
26{}
27
28void packet_db_writer::consume_file_data(file_id const & ident,
29 file_data const & dat)
30{
31 if (!app.db.file_version_exists(ident))
32 app.db.put_file(ident, dat);
33 else
34 L(F("skipping existing file version %s\n") % ident);
35 ++count;
36}
37
38void packet_db_writer::consume_file_delta(file_id const & old_id,
39 file_id const & new_id,
40 file_delta const & del)
41{
42 if (!app.db.file_version_exists(new_id))
43 {
44 if (app.db.file_version_exists(old_id))
45app.db.put_file_version(old_id, new_id, del);
46 else
47W(F("warning: file delta pre-image '%s' not found in database\n")
48 % old_id);
49 }
50 else
51 L(F("skipping delta to existing file version %s\n") % new_id);
52 ++count;
53}
54
55void packet_db_writer::consume_file_cert(file<cert> const & t)
56{
57 if (!app.db.file_cert_exists(t))
58 app.db.put_file_cert(t);
59 else
60 {
61 string s;
62 cert_signable_text(t.inner(), s);
63 L(F("skipping existing file cert %s\n") % s);
64 }
65 ++count;
66}
67
68void packet_db_writer::consume_manifest_data(manifest_id const & ident,
69 manifest_data const & dat)
70{
71 if (!app.db.manifest_version_exists(ident))
72 app.db.put_manifest(ident, dat);
73 else
74 L(F("skipping existing manifest version %s\n") % ident);
75
76 ++count;
77
78 if (server)
79 app.db.note_manifest_on_netserver (*server, ident);
80}
81
82void packet_db_writer::consume_manifest_delta(manifest_id const & old_id,
83 manifest_id const & new_id,
84 manifest_delta const & del)
85{
86 if (!app.db.manifest_version_exists(new_id))
87 {
88 if (app.db.manifest_version_exists(old_id))
89app.db.put_manifest_version(old_id, new_id, del);
90 else
91W(F("manifest delta pre-image '%s' not found in database\n")
92 % old_id);
93 }
94 else
95 L(F("skipping delta to existing manifest version %s\n") % new_id);
96
97 ++count;
98
99 if (server)
100 {
101 app.db.note_manifest_on_netserver (*server, old_id);
102 app.db.note_manifest_on_netserver (*server, new_id);
103 }
104}
105
106void packet_db_writer::consume_manifest_cert(manifest<cert> const & t)
107{
108 if (!app.db.manifest_cert_exists(t))
109 app.db.put_manifest_cert(t);
110 else
111 {
112 string s;
113 cert_signable_text(t.inner(), s);
114 L(F("skipping existing manifest cert %s\n") % s);
115 }
116 ++count;
117}
118
119void packet_db_writer::consume_public_key(rsa_keypair_id const & ident,
120 base64< rsa_pub_key > const & k)
121{
122 if (!take_keys)
123 {
124 W(F("skipping prohibited public key %s\n") % ident);
125 return;
126 }
127 if (!app.db.public_key_exists(ident))
128 app.db.put_key(ident, k);
129 else
130 L(F("skipping existing public key %s\n") % ident);
131 ++count;
132}
133
134void packet_db_writer::consume_private_key(rsa_keypair_id const & ident,
135 base64< arc4<rsa_priv_key> > const & k)
136{
137 if (!take_keys)
138 {
139 W(F("skipping prohibited private key %s\n") % ident);
140 return;
141 }
142 if (!app.db.private_key_exists(ident))
143 app.db.put_key(ident, k);
144 else
145 L(F("skipping existing private key %s\n") % ident);
146 ++count;
147}
148
149
150// --- packet writer ---
151
152packet_writer::packet_writer(ostream & o) : ost(o) {}
153
154void packet_writer::consume_file_data(file_id const & ident,
155 file_data const & dat)
156{
157 ost << "[fdata " << ident.inner()() << "]" << endl
158 << trim_ws(dat.inner()()) << endl
159 << "[end]" << endl;
160}
161
162void packet_writer::consume_file_delta(file_id const & old_id,
163 file_id const & new_id,
164 file_delta const & del)
165{
166 ost << "[fdelta " << old_id.inner()() << endl
167 << " " << new_id.inner()() << "]" << endl
168 << trim_ws(del.inner()()) << endl
169 << "[end]" << endl;
170}
171
172void packet_writer::consume_file_cert(file<cert> const & t)
173{
174 ost << "[fcert " << t.inner().ident() << endl
175 << " " << t.inner().name() << endl
176 << " " << t.inner().key() << endl
177 << " " << trim_ws(t.inner().value()) << "]" << endl
178 << trim_ws(t.inner().sig()) << endl
179 << "[end]" << endl;
180}
181
182void packet_writer::consume_manifest_data(manifest_id const & ident,
183 manifest_data const & dat)
184{
185 ost << "[mdata " << ident.inner()() << "]" << endl
186 << trim_ws(dat.inner()()) << endl
187 << "[end]" << endl;
188}
189
190void packet_writer::consume_manifest_delta(manifest_id const & old_id,
191 manifest_id const & new_id,
192 manifest_delta const & del)
193{
194 ost << "[mdelta " << old_id.inner()() << endl
195 << " " << new_id.inner()() << "]" << endl
196 << trim_ws(del.inner()()) << endl
197 << "[end]" << endl;
198}
199
200void packet_writer::consume_manifest_cert(manifest<cert> const & t)
201{
202 ost << "[mcert " << t.inner().ident() << endl
203 << " " << t.inner().name() << endl
204 << " " << t.inner().key() << endl
205 << " " << trim_ws(t.inner().value()) << "]" << endl
206 << trim_ws(t.inner().sig()) << endl
207 << "[end]" << endl;
208}
209
210void packet_writer::consume_public_key(rsa_keypair_id const & ident,
211 base64< rsa_pub_key > const & k)
212{
213 ost << "[pubkey " << ident() << "]" << endl
214 << trim_ws(k()) << endl
215 << "[end]" << endl;
216}
217
218void packet_writer::consume_private_key(rsa_keypair_id const & ident,
219base64< arc4<rsa_priv_key> > const & k)
220{
221 ost << "[privkey " << ident() << "]" << endl
222 << trim_ws(k()) << endl
223 << "[end]" << endl;
224}
225
226
227// --- packet writer ---
228
229queueing_packet_writer::queueing_packet_writer(app_state & a, set<url> const & t) :
230 app(a), targets(t), n_bytes("bytes"), n_packets("packets")
231{
232 for (set<url>::const_iterator targ = targets.begin();
233 targ != targets.end(); ++targ)
234 {
235 P(F("queueing packets for target %s\n") % *targ);
236 }
237}
238
239
240void queueing_packet_writer::queue_blob_for_network(string const & str)
241{
242 ++n_packets;
243 n_bytes += str.size();
244 for (set<url>::const_iterator targ = targets.begin();
245 targ != targets.end(); ++targ)
246 {
247 if (rev)
248rev->reverse_queue_posting(*targ, str);
249 else
250app.db.queue_posting(*targ, str);
251 }
252}
253
254void queueing_packet_writer::consume_file_data(file_id const & ident,
255 file_data const & dat)
256{
257 ostringstream oss;
258 packet_writer pw(oss);
259 pw.consume_file_data(ident, dat);
260 queue_blob_for_network(oss.str());
261}
262
263void queueing_packet_writer::consume_file_delta(file_id const & old_id,
264file_id const & new_id,
265file_delta const & del)
266{
267 ostringstream oss;
268 packet_writer pw(oss);
269 pw.consume_file_delta(old_id, new_id, del);
270 queue_blob_for_network(oss.str());
271}
272
273void queueing_packet_writer::consume_file_cert(file<cert> const & t)
274{
275 ostringstream oss;
276 packet_writer pw(oss);
277 pw.consume_file_cert(t);
278 queue_blob_for_network(oss.str());
279}
280
281void queueing_packet_writer::consume_manifest_data(manifest_id const & ident,
282 manifest_data const & dat)
283{
284 ostringstream oss;
285 packet_writer pw(oss);
286 pw.consume_manifest_data(ident, dat);
287 queue_blob_for_network(oss.str());
288}
289
290void queueing_packet_writer::consume_manifest_delta(manifest_id const & old_id,
291 manifest_id const & new_id,
292 manifest_delta const & del)
293{
294 ostringstream oss;
295 packet_writer pw(oss);
296 pw.consume_manifest_delta(old_id, new_id, del);
297 queue_blob_for_network(oss.str());
298}
299
300void queueing_packet_writer::consume_manifest_cert(manifest<cert> const & t)
301{
302 ostringstream oss;
303 packet_writer pw(oss);
304 pw.consume_manifest_cert(t);
305 queue_blob_for_network(oss.str());
306}
307
308void queueing_packet_writer::consume_public_key(rsa_keypair_id const & ident,
309base64< rsa_pub_key > const & k)
310{
311 ostringstream oss;
312 packet_writer pw(oss);
313 pw.consume_public_key(ident, k);
314 queue_blob_for_network(oss.str());
315}
316
317void queueing_packet_writer::consume_private_key(rsa_keypair_id const & ident,
318 base64< arc4<rsa_priv_key> > const & k)
319{
320 ostringstream oss;
321 packet_writer pw(oss);
322 pw.consume_private_key(ident, k);
323 queue_blob_for_network(oss.str());
324}
325
326// -- remainder just deals with the regexes for reading packets off streams
327
328struct feed_packet_consumer
329{
330 size_t & count;
331 packet_consumer & cons;
332 feed_packet_consumer(size_t & count, packet_consumer & c) : count(count), cons(c)
333 {}
334 bool operator()(match_results<std::string::const_iterator, regex::alloc_type> const & res) const
335 {
336 if (res.size() != 17)
337 throw oops("matched impossible packet with "
338 + lexical_cast<string>(res.size()) + " matching parts: " +
339 string(res[0].first, res[0].second));
340
341 if (res[1].matched)
342 {
343L(F("read data packet\n"));
344I(res[2].matched);
345I(res[3].matched);
346string head(res[1].first, res[1].second);
347string ident(res[2].first, res[2].second);
348string body(trim_ws(string(res[3].first, res[3].second)));
349if (head == "mdata")
350 cons.consume_manifest_data(manifest_id(hexenc<id>(ident)),
351 manifest_data(body));
352else if (head == "fdata")
353 cons.consume_file_data(file_id(hexenc<id>(ident)),
354 file_data(body));
355else
356 throw oops("matched impossible data packet with head '" + head + "'");
357 }
358 else if (res[4].matched)
359 {
360L(F("read delta packet\n"));
361I(res[5].matched);
362I(res[6].matched);
363I(res[7].matched);
364string head(res[4].first, res[4].second);
365string old_id(res[5].first, res[5].second);
366string new_id(res[6].first, res[6].second);
367string body(trim_ws(string(res[7].first, res[7].second)));
368if (head == "mdelta")
369 cons.consume_manifest_delta(manifest_id(hexenc<id>(old_id)),
370 manifest_id(hexenc<id>(new_id)),
371 manifest_delta(body));
372else if (head == "fdelta")
373 cons.consume_file_delta(file_id(hexenc<id>(old_id)),
374 file_id(hexenc<id>(new_id)),
375 file_delta(body));
376else
377 throw oops("matched impossible delta packet with head '" + head + "'");
378 }
379 else if (res[8].matched)
380 {
381L(F("read cert packet\n"));
382I(res[9].matched);
383I(res[10].matched);
384I(res[11].matched);
385I(res[12].matched);
386I(res[13].matched);
387string head(res[8].first, res[8].second);
388string ident(res[9].first, res[9].second);
389string certname(res[10].first, res[10].second);
390string key(res[11].first, res[11].second);
391string val(res[12].first, res[12].second);
392string body(res[13].first, res[13].second);
393
394// canonicalize the base64 encodings to permit searches
395cert t = cert(hexenc<id>(ident),
396 cert_name(certname),
397 base64<cert_value>(canonical_base64(val)),
398 rsa_keypair_id(key),
399 base64<rsa_sha1_signature>(canonical_base64(body)));
400if (head == "mcert")
401 cons.consume_manifest_cert(manifest<cert>(t));
402else if (head == "fcert")
403 cons.consume_file_cert(file<cert>(t));
404else
405 throw oops("matched impossible cert packet with head '" + head + "'");
406 }
407 else if (res[14].matched)
408 {
409L(F("read key data packet\n"));
410I(res[15].matched);
411I(res[16].matched);
412string head(res[14].first, res[14].second);
413string ident(res[15].first, res[15].second);
414string body(trim_ws(string(res[16].first, res[16].second)));
415if (head == "pubkey")
416 cons.consume_public_key(rsa_keypair_id(ident),
417 base64<rsa_pub_key>(body));
418else if (head == "privkey")
419 cons.consume_private_key(rsa_keypair_id(ident),
420 base64< arc4<rsa_priv_key> >(body));
421else
422 throw oops("matched impossible key data packet with head '" + head + "'");
423 }
424 else
425 return true;
426 ++count;
427 return true;
428 }
429};
430
431static size_t extract_packets(string const & s, packet_consumer & cons)
432{
433 string const ident("([[:xdigit:]]{40})");
434 string const sp("[[:space:]]+");
435 string const bra("\\[");
436 string const ket("\\]");
437 string const certhead("(mcert|fcert)");
438 string const datahead("(mdata|fdata)");
439 string const deltahead("(mdelta|fdelta)");
440 string const keyhead("(pubkey|privkey)");
441 string const key("([-a-zA-Z0-9\\.@]+)");
442 string const certname("([-a-zA-Z0-9]+)");
443 string const base64("([a-zA-Z0-9+/=[:space:]]+)");
444 string const end("\\[end\\]");
445 string const data = bra + datahead + sp + ident + ket + base64 + end;
446 string const delta = bra + deltahead + sp + ident + sp + ident + ket + base64 + end;
447 string const cert = bra
448 + certhead + sp + ident + sp + certname + sp + key + sp + base64
449 + ket
450 + base64 + end;
451 string const keydata = bra + keyhead + sp + key + ket + base64 + end;
452 string const biggie = (data + "|" + delta + "|" + cert + "|" + keydata);
453 regex expr(biggie);
454 size_t count = 0;
455 regex_grep(feed_packet_consumer(count, cons), s, expr, match_default);
456 return count;
457}
458
459
460size_t read_packets(istream & in, packet_consumer & cons)
461{
462 string accum, tmp;
463 size_t count = 0;
464 size_t const bufsz = 0xff;
465 char buf[bufsz];
466 string const end("[end]");
467 while(in)
468 {
469 in.read(buf, bufsz);
470 accum.append(buf, in.gcount());
471 string::size_type endpos = string::npos;
472 endpos = accum.rfind(end);
473 if (endpos != string::npos)
474{
475 endpos += end.size();
476 string tmp = accum.substr(0, endpos);
477 count += extract_packets(tmp, cons);
478 if (endpos < accum.size() - 1)
479 accum = accum.substr(endpos+1);
480 else
481 accum.clear();
482}
483 }
484 return count;
485}
486
487
488#ifdef BUILD_UNIT_TESTS
489#include "unit_tests.hh"
490#include "transforms.hh"
491#include "manifest.hh"
492
493static void packet_roundabout_test()
494{
495 string tmp;
496
497 {
498 ostringstream oss;
499 packet_writer pw(oss);
500
501 // an fdata packet
502 base64< gzip<data> > gzdata;
503 pack(data("this is some file data"), gzdata);
504 file_data fdata(gzdata);
505 file_id fid;
506 calculate_ident(fdata, fid);
507 pw.consume_file_data(fid, fdata);
508
509 // an fdelta packet
510 base64< gzip<data> > gzdata2;
511 pack(data("this is some file data which is not the same as the first one"), gzdata2);
512 file_data fdata2(gzdata2);
513 file_id fid2;
514 calculate_ident(fdata2, fid);
515 base64< gzip<delta> > del;
516 diff(fdata.inner(), fdata2.inner(), del);
517 pw.consume_file_delta(fid, fid2, file_delta(del));
518
519 // a file cert packet
520 base64<cert_value> val;
521 encode_base64(cert_value("peaches"), val);
522 base64<rsa_sha1_signature> sig;
523 encode_base64(rsa_sha1_signature("blah blah there is no way this is a valid signature"), sig);
524 cert c(fid.inner(), cert_name("smell"), val,
525 rsa_keypair_id("fun@moonman.com"), sig);
526 pw.consume_file_cert(file<cert>(c));
527
528 // a manifest cert packet
529 pw.consume_manifest_cert(manifest<cert>(c));
530
531 // a manifest data packet
532 manifest_map mm;
533 manifest_data mdata;
534 manifest_id mid;
535 mm.insert(make_pair(file_path("foo/bar.txt"),
536file_id(hexenc<id>("cfb81b30ab3133a31b52eb50bd1c86df67eddec4"))));
537 write_manifest_map(mm, mdata);
538 calculate_ident(mdata, mid);
539 pw.consume_manifest_data(mid, mdata);
540
541 // a manifest delta packet
542 manifest_map mm2;
543 manifest_data mdata2;
544 manifest_id mid2;
545 manifest_delta mdelta;
546 mm2.insert(make_pair(file_path("foo/bar.txt"),
547 file_id(hexenc<id>("5b20eb5e5bdd9cd674337fc95498f468d80ef7bc"))));
548 mm2.insert(make_pair(file_path("bunk.txt"),
549 file_id(hexenc<id>("54f373ed07b4c5a88eaa93370e1bbac02dc432a8"))));
550 write_manifest_map(mm2, mdata2);
551 calculate_ident(mdata2, mid2);
552 base64< gzip<delta> > del2;
553 diff(mdata.inner(), mdata2.inner(), del2);
554 pw.consume_manifest_delta(mid, mid2, manifest_delta(del));
555
556 // a public key packet
557 base64<rsa_pub_key> puk;
558 encode_base64(rsa_pub_key("this is not a real rsa key"), puk);
559 pw.consume_public_key(rsa_keypair_id("test@lala.com"), puk);
560
561 // a private key packet
562 base64< arc4<rsa_priv_key> > pik;
563 encode_base64(arc4<rsa_priv_key>
564 (rsa_priv_key("this is not a real rsa key either!")), pik);
565
566 pw.consume_private_key(rsa_keypair_id("test@lala.com"), pik);
567
568 }
569
570 for (int i = 0; i < 10; ++i)
571 {
572 // now spin around sending and receiving this a few times
573 ostringstream oss;
574 packet_writer pw(oss);
575 istringstream iss(tmp);
576 read_packets(iss, pw);
577 BOOST_CHECK(oss.str() == tmp);
578 tmp = oss.str();
579 }
580}
581
582void add_packet_tests(test_suite * suite)
583{
584 I(suite);
585 suite->add(BOOST_TEST_CASE(&packet_roundabout_test));
586}
587
588#endif // BUILD_UNIT_TESTS

Archive Download this file

Branches

Tags

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