00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <string>
00018 #include <sys/types.h>
00019 #include <netinet/in.h>
00020
00021 #include "Bundle.h"
00022 #include "BundleProtocol.h"
00023 #include "PrimaryBlockProcessor.h"
00024 #include "naming/EndpointID.h"
00025 #include "SDNV.h"
00026
00027 namespace dtn {
00028
00029
00030 struct DictionaryEntry {
00031 DictionaryEntry(const std::string& s, size_t off)
00032 : str(s), offset(off) {}
00033
00034 std::string str;
00035 size_t offset;
00036 };
00037
00038 class DictionaryVector : public std::vector<DictionaryEntry> {};
00039
00040
00041 PrimaryBlockProcessor::PrimaryBlockProcessor()
00042 : BlockProcessor(BundleProtocol::PRIMARY_BLOCK)
00043 {
00044 }
00045
00046
00047 void
00048 PrimaryBlockProcessor::add_to_dictionary(const EndpointID& eid,
00049 DictionaryVector* dict,
00050 size_t* dictlen)
00051 {
00052
00053
00054
00055
00056
00057
00058 DictionaryVector::iterator iter;
00059 bool found_scheme = false;
00060 bool found_ssp = false;
00061
00062 for (iter = dict->begin(); iter != dict->end(); ++iter) {
00063 if (iter->str == eid.scheme_str())
00064 found_scheme = true;
00065
00066 if (iter->str == eid.ssp())
00067 found_ssp = true;
00068 }
00069
00070 if (found_scheme == false) {
00071 dict->push_back(DictionaryEntry(eid.scheme_str(), *dictlen));
00072 *dictlen += (eid.scheme_str().length() + 1);
00073 }
00074
00075 if (found_ssp == false) {
00076 dict->push_back(DictionaryEntry(eid.ssp(), *dictlen));
00077 *dictlen += (eid.ssp().length() + 1);
00078 }
00079 }
00080
00081
00082 void
00083 PrimaryBlockProcessor::get_dictionary_offsets(DictionaryVector *dict,
00084 const EndpointID& eid,
00085 u_int16_t* scheme_offset,
00086 u_int16_t* ssp_offset)
00087 {
00088 DictionaryVector::iterator iter;
00089 for (iter = dict->begin(); iter != dict->end(); ++iter) {
00090 if (iter->str == eid.scheme_str())
00091 *scheme_offset = htons(iter->offset);
00092
00093 if (iter->str == eid.ssp())
00094 *ssp_offset = htons(iter->offset);
00095 }
00096 }
00097
00098
00099 bool
00100 PrimaryBlockProcessor::extract_dictionary_eid(EndpointID* eid,
00101 const char* what,
00102 u_int16_t* scheme_offsetp,
00103 u_int16_t* ssp_offsetp,
00104 u_char* dictionary,
00105 u_int32_t dictionary_len)
00106 {
00107 static const char* log = "/dtn/bundle/protocol";
00108 u_int16_t scheme_offset, ssp_offset;
00109 memcpy(&scheme_offset, scheme_offsetp, 2);
00110 memcpy(&ssp_offset, ssp_offsetp, 2);
00111 scheme_offset = ntohs(scheme_offset);
00112 ssp_offset = ntohs(ssp_offset);
00113
00114 if (scheme_offset >= (dictionary_len - 1)) {
00115 log_err_p(log, "illegal offset for %s scheme dictionary offset: "
00116 "offset %d, total length %u", what,
00117 scheme_offset, dictionary_len);
00118 return false;
00119 }
00120
00121 if (ssp_offset >= (dictionary_len - 1)) {
00122 log_err_p(log, "illegal offset for %s ssp dictionary offset: "
00123 "offset %d, total length %u", what,
00124 ssp_offset, dictionary_len);
00125 return false;
00126 }
00127
00128 eid->assign((char*)&dictionary[scheme_offset],
00129 (char*)&dictionary[ssp_offset]);
00130
00131 if (! eid->valid()) {
00132 log_err_p(log, "invalid %s endpoint id '%s': "
00133 "scheme '%s' offset %u/%u ssp '%s' offset %u/%u",
00134 what, eid->c_str(),
00135 eid->scheme_str().c_str(),
00136 scheme_offset, dictionary_len,
00137 eid->ssp().c_str(),
00138 ssp_offset, dictionary_len);
00139 return false;
00140 }
00141
00142 log_debug_p(log, "parsed %s eid (offsets %u, %u) %s",
00143 what, scheme_offset, ssp_offset, eid->c_str());
00144 return true;
00145 }
00146
00147
00148 void
00149 PrimaryBlockProcessor::debug_dump_dictionary(const char* bp, size_t len,
00150 PrimaryBlock2* primary2)
00151 {
00152 #ifndef NDEBUG
00153 oasys::StringBuffer dict_copy;
00154
00155 const char* end = bp + len;
00156 ASSERT(end[-1] == '\0');
00157
00158 while (bp != end) {
00159 dict_copy.appendf("%s ", bp);
00160 bp += strlen(bp) + 1;
00161 }
00162
00163 log_debug_p("/dtn/bundle/protocol",
00164 "dictionary len %zu, value: '%s'", len, dict_copy.c_str());
00165
00166 log_debug_p("/dtn/bundle/protocol",
00167 "dictionary offsets: dest %u,%u source %u,%u, "
00168 "custodian %u,%u replyto %u,%u",
00169 ntohs(primary2->dest_scheme_offset),
00170 ntohs(primary2->dest_ssp_offset),
00171 ntohs(primary2->source_scheme_offset),
00172 ntohs(primary2->source_ssp_offset),
00173 ntohs(primary2->custodian_scheme_offset),
00174 ntohs(primary2->custodian_ssp_offset),
00175 ntohs(primary2->replyto_scheme_offset),
00176 ntohs(primary2->replyto_ssp_offset));
00177 #else
00178 (void)bp;
00179 (void)len;
00180 (void)primary2;
00181 #endif
00182 }
00183
00184
00185 u_int8_t
00186 PrimaryBlockProcessor::format_bundle_flags(const Bundle* bundle)
00187 {
00188 u_int8_t flags = 0;
00189
00190 if (bundle->is_fragment_) {
00191 flags |= BUNDLE_IS_FRAGMENT;
00192 }
00193
00194 if (bundle->is_admin_) {
00195 flags |= BUNDLE_IS_ADMIN;
00196 }
00197
00198 if (bundle->do_not_fragment_) {
00199 flags |= BUNDLE_DO_NOT_FRAGMENT;
00200 }
00201
00202 if (bundle->custody_requested_) {
00203 flags |= BUNDLE_CUSTODY_XFER_REQUESTED;
00204 }
00205
00206 if (bundle->singleton_dest_) {
00207 flags |= BUNDLE_SINGLETON_DESTINATION;
00208 }
00209
00210 return flags;
00211 }
00212
00213
00214 void
00215 PrimaryBlockProcessor::parse_bundle_flags(Bundle* bundle, u_int8_t flags)
00216 {
00217 if (flags & BUNDLE_IS_FRAGMENT) {
00218 bundle->is_fragment_ = true;
00219 }
00220
00221 if (flags & BUNDLE_IS_ADMIN) {
00222 bundle->is_admin_ = true;
00223 }
00224
00225 if (flags & BUNDLE_DO_NOT_FRAGMENT) {
00226 bundle->do_not_fragment_ = true;
00227 }
00228
00229 if (flags & BUNDLE_CUSTODY_XFER_REQUESTED) {
00230 bundle->custody_requested_ = true;
00231 }
00232
00233 if (flags & BUNDLE_SINGLETON_DESTINATION) {
00234 bundle->singleton_dest_ = true;
00235 }
00236 }
00237
00238
00239 u_int8_t
00240 PrimaryBlockProcessor::format_cos_flags(const Bundle* b)
00241 {
00242 u_int8_t cos_flags = 0;
00243
00244 cos_flags = ((b->priority_ & 0x3) << 6);
00245
00246 return cos_flags;
00247 }
00248
00249
00250 void
00251 PrimaryBlockProcessor::parse_cos_flags(Bundle* b, u_int8_t cos_flags)
00252 {
00253 b->priority_ = ((cos_flags >> 6) & 0x3);
00254 }
00255
00256
00257 u_int8_t
00258 PrimaryBlockProcessor::format_srr_flags(const Bundle* b)
00259 {
00260 u_int8_t srr_flags = 0;
00261
00262 if (b->receive_rcpt_)
00263 srr_flags |= BundleProtocol::STATUS_RECEIVED;
00264
00265 if (b->custody_rcpt_)
00266 srr_flags |= BundleProtocol::STATUS_CUSTODY_ACCEPTED;
00267
00268 if (b->forward_rcpt_)
00269 srr_flags |= BundleProtocol::STATUS_FORWARDED;
00270
00271 if (b->delivery_rcpt_)
00272 srr_flags |= BundleProtocol::STATUS_DELIVERED;
00273
00274 if (b->deletion_rcpt_)
00275 srr_flags |= BundleProtocol::STATUS_DELETED;
00276
00277 if (b->app_acked_rcpt_)
00278 srr_flags |= BundleProtocol::STATUS_ACKED_BY_APP;
00279
00280 return srr_flags;
00281 }
00282
00283
00284 void
00285 PrimaryBlockProcessor::parse_srr_flags(Bundle* b, u_int8_t srr_flags)
00286 {
00287 if (srr_flags & BundleProtocol::STATUS_RECEIVED)
00288 b->receive_rcpt_ = true;
00289
00290 if (srr_flags & BundleProtocol::STATUS_CUSTODY_ACCEPTED)
00291 b->custody_rcpt_ = true;
00292
00293 if (srr_flags & BundleProtocol::STATUS_FORWARDED)
00294 b->forward_rcpt_ = true;
00295
00296 if (srr_flags & BundleProtocol::STATUS_DELIVERED)
00297 b->delivery_rcpt_ = true;
00298
00299 if (srr_flags & BundleProtocol::STATUS_DELETED)
00300 b->deletion_rcpt_ = true;
00301
00302 if (srr_flags & BundleProtocol::STATUS_ACKED_BY_APP)
00303 b->app_acked_rcpt_ = true;
00304 }
00305
00306
00307 size_t
00308 PrimaryBlockProcessor::get_primary_len(const Bundle* bundle,
00309 DictionaryVector* dict,
00310 size_t* dictionary_len,
00311 size_t* primary_var_len)
00312 {
00313 static const char* log = "/dtn/bundle/protocol";
00314 size_t primary_len = 0;
00315 *dictionary_len = 0;
00316 *primary_var_len = 0;
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328 add_to_dictionary(bundle->dest_, dict, dictionary_len);
00329 add_to_dictionary(bundle->source_, dict, dictionary_len);
00330 add_to_dictionary(bundle->custodian_, dict, dictionary_len);
00331 add_to_dictionary(bundle->replyto_, dict, dictionary_len);
00332
00333 (void)log;
00334 log_debug_p(log, "generated dictionary length %zu", *dictionary_len);
00335
00336 *primary_var_len += SDNV::encoding_len(*dictionary_len);
00337 *primary_var_len += *dictionary_len;
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347 if (bundle->is_fragment_) {
00348 *primary_var_len += SDNV::encoding_len(bundle->frag_offset_);
00349 *primary_var_len += SDNV::encoding_len(bundle->orig_length_);
00350 }
00351
00352
00353
00354
00355 *primary_var_len += sizeof(PrimaryBlock2);
00356
00357
00358
00359
00360
00361
00362 primary_len = sizeof(PrimaryBlock1) +
00363 SDNV::encoding_len(*primary_var_len) +
00364 *primary_var_len;
00365
00366 log_debug_p(log, "get_primary_len(bundle %d): %zu",
00367 bundle->bundleid_, primary_len);
00368
00369 return primary_len;
00370 }
00371
00372
00373 size_t
00374 PrimaryBlockProcessor::get_primary_len(const Bundle* bundle)
00375 {
00376 DictionaryVector dict;
00377 size_t dictionary_len;
00378 size_t primary_var_len;
00379
00380 return get_primary_len(bundle, &dict, &dictionary_len, &primary_var_len);
00381 }
00382
00383
00384 int
00385 PrimaryBlockProcessor::consume(Bundle* bundle, BlockInfo* block, u_char* buf, size_t len)
00386 {
00387 static const char* log = "/dtn/bundle/protocol";
00388 size_t consumed = 0;
00389
00390 ASSERT(! block->complete());
00391
00392
00393
00394
00395
00396 if (block->data_length() == 0) {
00397 int cc = consume_preamble(block, buf, len, sizeof(PrimaryBlock1));
00398
00399 if (cc == -1) {
00400 return -1;
00401 }
00402
00403
00404
00405
00406 if (block->data_offset() == 0) {
00407 ASSERT(cc == (int)len);
00408 return cc;
00409 }
00410
00411
00412 log_debug_p(log, "parsed primary block length %u (preamble %u)",
00413 block->data_length(), block->data_offset());
00414 buf += cc;
00415 len -= cc;
00416
00417 consumed += cc;
00418
00419 if (block->data_length() == 0) {
00420 log_err_p(log, "got primary block with zero length");
00421 return -1;
00422 }
00423 }
00424
00425
00426
00427
00428
00429
00430 ASSERT(block->full_length() > block->contents().len());
00431 int cc = BlockProcessor::consume(bundle, block, buf, len);
00432
00433 if (cc == -1) {
00434 return -1;
00435 }
00436
00437 if (! block->complete()) {
00438 ASSERT(cc == (int)len);
00439 return consumed + cc;
00440 }
00441
00442
00443
00444
00445
00446
00447 consumed += cc;
00448
00449 size_t primary_len = block->full_length();
00450
00451 buf = block->writable_contents()->buf();
00452 len = block->writable_contents()->len();
00453
00454 ASSERT(primary_len == len);
00455
00456
00457
00458
00459 PrimaryBlock1* primary1 = (PrimaryBlock1*)buf;
00460 log_debug_p(log, "parsed primary block 1: version %d length %u",
00461 primary1->version, block->data_length());
00462
00463 if (primary1->version != BundleProtocol::CURRENT_VERSION) {
00464 log_warn_p(log, "protocol version mismatch %d != %d",
00465 primary1->version, BundleProtocol::CURRENT_VERSION);
00466 return -1;
00467 }
00468
00469 parse_bundle_flags(bundle, primary1->bundle_processing_flags);
00470 parse_cos_flags(bundle, primary1->class_of_service_flags);
00471 parse_srr_flags(bundle, primary1->status_report_request_flags);
00472
00473
00474
00475
00476
00477 buf += block->data_offset();
00478 len -= block->data_offset();
00479
00480 ASSERT(len == block->data_length());
00481
00482
00483
00484
00485
00486
00487 u_int32_t primary2_len = sizeof(PrimaryBlock2);
00488 int dict_sdnv_len = 0;
00489 u_int32_t dictionary_len = 0;
00490 int frag_offset_len = 0;
00491 int frag_length_len = 0;
00492 if (len < sizeof(PrimaryBlock2)) {
00493 tooshort:
00494 log_err_p(log, "primary block advertised incorrect length %u: "
00495 "fixed-length %u, dict_sdnv %d, dict %u, frag %d %d",
00496 block->data_length(), primary2_len, dict_sdnv_len,
00497 dictionary_len, frag_offset_len, frag_length_len);
00498 return -1;
00499 }
00500
00501
00502
00503
00504 PrimaryBlock2* primary2 = (PrimaryBlock2*)buf;
00505 buf += sizeof(PrimaryBlock2);
00506 len -= sizeof(PrimaryBlock2);
00507
00508 BundleProtocol::get_timestamp(&bundle->creation_ts_, &primary2->creation_ts);
00509 u_int32_t lifetime;
00510 memcpy(&lifetime, &primary2->lifetime, sizeof(lifetime));
00511 bundle->expiration_ = ntohl(lifetime);
00512
00513
00514
00515
00516 dict_sdnv_len = SDNV::decode(buf, len, &dictionary_len);
00517 if (dict_sdnv_len < 0) {
00518 goto tooshort;
00519 }
00520 buf += dict_sdnv_len;
00521 len -= dict_sdnv_len;
00522
00523
00524
00525
00526 if (len < dictionary_len) {
00527 goto tooshort;
00528 }
00529
00530
00531
00532
00533 if (buf[dictionary_len - 1] != '\0') {
00534 log_err_p(log, "dictionary does not end with a NULL character!");
00535 return -1;
00536 }
00537
00538
00539
00540
00541
00542
00543 u_char* dictionary = buf;
00544 buf += dictionary_len;
00545 len -= dictionary_len;
00546
00547 debug_dump_dictionary((char*)dictionary, dictionary_len, primary2);
00548
00549 extract_dictionary_eid(&bundle->source_, "source",
00550 &primary2->source_scheme_offset,
00551 &primary2->source_ssp_offset,
00552 dictionary, dictionary_len);
00553
00554 extract_dictionary_eid(&bundle->dest_, "dest",
00555 &primary2->dest_scheme_offset,
00556 &primary2->dest_ssp_offset,
00557 dictionary, dictionary_len);
00558
00559 extract_dictionary_eid(&bundle->replyto_, "replyto",
00560 &primary2->replyto_scheme_offset,
00561 &primary2->replyto_ssp_offset,
00562 dictionary, dictionary_len);
00563
00564 extract_dictionary_eid(&bundle->custodian_, "custodian",
00565 &primary2->custodian_scheme_offset,
00566 &primary2->custodian_ssp_offset,
00567 dictionary, dictionary_len);
00568
00569 if (bundle->is_fragment_) {
00570 frag_offset_len = SDNV::decode(buf, len, &bundle->frag_offset_);
00571 if (frag_offset_len == -1) {
00572 goto tooshort;
00573 }
00574 buf += frag_offset_len;
00575 len -= frag_offset_len;
00576
00577 frag_length_len = SDNV::decode(buf, len, &bundle->orig_length_);
00578 if (frag_length_len == -1) {
00579 goto tooshort;
00580 }
00581 buf += frag_length_len;
00582 len -= frag_length_len;
00583
00584 log_debug_p(log, "parsed fragmentation info: offset %u, orig_len %u",
00585 bundle->frag_offset_, bundle->orig_length_);
00586 }
00587
00588 return consumed;
00589 }
00590
00591
00592 void
00593 PrimaryBlockProcessor::generate(const Bundle* bundle,
00594 Link* link,
00595 BlockInfo* block,
00596 bool last)
00597 {
00598 (void)link;
00599
00600
00601
00602
00603 ASSERT(!last);
00604
00605 static const char* log = "/dtn/bundle/protocol";
00606 DictionaryVector dict;
00607 size_t primary_len = 0;
00608 size_t primary_var_len = 0;
00609 size_t dictionary_len = 0;
00610 int sdnv_len = 0;
00611
00612
00613
00614
00615 primary_len = get_primary_len(bundle, &dict, &dictionary_len,
00616 &primary_var_len);
00617 block->writable_contents()->reserve(primary_len);
00618 block->writable_contents()->set_len(primary_len);
00619 block->set_data_length(primary_len);
00620
00621
00622
00623
00624 u_char* buf = block->writable_contents()->buf();
00625 int len = primary_len;
00626
00627 (void)log;
00628 log_debug_p(log, "generating primary: length %zu (preamble %zu var length %zu)",
00629 primary_len,
00630 (sizeof(PrimaryBlock1) + SDNV::encoding_len(primary_var_len)),
00631 primary_var_len);
00632
00633
00634
00635
00636 PrimaryBlock1* primary1 = (PrimaryBlock1*)buf;
00637 primary1->version = BundleProtocol::CURRENT_VERSION;
00638 primary1->bundle_processing_flags = format_bundle_flags(bundle);
00639 primary1->class_of_service_flags = format_cos_flags(bundle);
00640 primary1->status_report_request_flags = format_srr_flags(bundle);
00641
00642 sdnv_len = SDNV::encode(primary_var_len,
00643 &primary1->block_length[0], len - 3);
00644 ASSERT(sdnv_len > 0);
00645 buf += (sizeof(PrimaryBlock1) + sdnv_len);
00646 len -= (sizeof(PrimaryBlock1) + sdnv_len);
00647
00648
00649
00650
00651 PrimaryBlock2* primary2 = (PrimaryBlock2*)buf;
00652
00653 get_dictionary_offsets(&dict, bundle->dest_,
00654 &primary2->dest_scheme_offset,
00655 &primary2->dest_ssp_offset);
00656
00657 get_dictionary_offsets(&dict, bundle->source_,
00658 &primary2->source_scheme_offset,
00659 &primary2->source_ssp_offset);
00660
00661 get_dictionary_offsets(&dict, bundle->custodian_,
00662 &primary2->custodian_scheme_offset,
00663 &primary2->custodian_ssp_offset);
00664
00665 get_dictionary_offsets(&dict, bundle->replyto_,
00666 &primary2->replyto_scheme_offset,
00667 &primary2->replyto_ssp_offset);
00668
00669 BundleProtocol::set_timestamp(&primary2->creation_ts, &bundle->creation_ts_);
00670 u_int32_t lifetime = htonl(bundle->expiration_);
00671 memcpy(&primary2->lifetime, &lifetime, sizeof(lifetime));
00672
00673 buf += sizeof(PrimaryBlock2);
00674 len -= sizeof(PrimaryBlock2);
00675
00676
00677
00678
00679 sdnv_len = SDNV::encode(dictionary_len, buf, len);
00680 ASSERT(sdnv_len > 0);
00681 buf += sdnv_len;
00682 len -= sdnv_len;
00683
00684 DictionaryVector::iterator dict_iter;
00685 for (dict_iter = dict.begin(); dict_iter != dict.end(); ++dict_iter) {
00686 strcpy((char*)buf, dict_iter->str.c_str());
00687 buf += dict_iter->str.length() + 1;
00688 len -= dict_iter->str.length() + 1;
00689 }
00690
00691 debug_dump_dictionary((char*)buf - dictionary_len, dictionary_len, primary2);
00692
00693
00694
00695
00696
00697 if (bundle->is_fragment_) {
00698 sdnv_len = SDNV::encode(bundle->frag_offset_, buf, len);
00699 ASSERT(sdnv_len > 0);
00700 buf += sdnv_len;
00701 len -= sdnv_len;
00702
00703 sdnv_len = SDNV::encode(bundle->orig_length_, buf, len);
00704 ASSERT(sdnv_len > 0);
00705 buf += sdnv_len;
00706 len -= sdnv_len;
00707 }
00708
00709 #ifndef NDEBUG
00710 {
00711 DictionaryVector dict2;
00712 size_t dict2_len = 0;
00713 size_t p2len;
00714 size_t len2 = get_primary_len(bundle, &dict2, &dict2_len, &p2len);
00715 ASSERT(len2 == primary_len);
00716 }
00717 #endif
00718
00719
00720
00721
00722
00723
00724 ASSERT(len == 0);
00725 }
00726
00727
00728 }