BundleProtocol.cc

Go to the documentation of this file.
00001 /*
00002  * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By
00003  * downloading, copying, installing or using the software you agree to
00004  * this license. If you do not agree to this license, do not download,
00005  * install, copy or use the software.
00006  *
00007  * Intel Open Source License
00008  *
00009  * Copyright (c) 2004 Intel Corporation. All rights reserved.
00010  *
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions are
00013  * met:
00014  *
00015  *   Redistributions of source code must retain the above copyright
00016  *   notice, this list of conditions and the following disclaimer.
00017  *
00018  *   Redistributions in binary form must reproduce the above copyright
00019  *   notice, this list of conditions and the following disclaimer in the
00020  *   documentation and/or other materials provided with the distribution.
00021  *
00022  *   Neither the name of the Intel Corporation nor the names of its
00023  *   contributors may be used to endorse or promote products derived from
00024  *   this software without specific prior written permission.
00025  *
00026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00027  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00028  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00029  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
00030  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00031  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00032  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00033  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00034  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00035  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00036  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037  */
00038 
00039 #include <sys/types.h>
00040 #include <netinet/in.h>
00041 #include <algorithm>
00042 
00043 #include <oasys/debug/DebugUtils.h>
00044 #include <oasys/util/StringUtils.h>
00045 
00046 #include "Bundle.h"
00047 #include "BundleProtocol.h"
00048 #include "BundleTimestamp.h"
00049 #include "SDNV.h"
00050 
00051 namespace dtn {
00052 
00053 //----------------------------------------------------------------------
00054 struct DictionaryEntry {
00055     DictionaryEntry(const std::string& s, size_t off)
00056         : str(s), offset(off) {}
00057 
00058     std::string str;
00059     size_t offset;
00060 };
00061 
00062 class DictionaryVector : public std::vector<DictionaryEntry> {};
00063 
00064 //----------------------------------------------------------------------
00065 void
00066 BundleProtocol::add_to_dictionary(const EndpointID& eid,
00067                                   DictionaryVector* dict,
00068                                   size_t* dictlen)
00069 {
00070     /*
00071      * For the scheme and ssp parts of the given endpoint id, see if
00072      * they've already appeared in the vector. If not, add them, and
00073      * record their length (with the null terminator) in the running
00074      * length total.
00075      */
00076     DictionaryVector::iterator iter;
00077     bool found_scheme = false;
00078     bool found_ssp = false;
00079 
00080     for (iter = dict->begin(); iter != dict->end(); ++iter) {
00081         if (iter->str == eid.scheme_str())
00082             found_scheme = true;
00083 
00084         if (iter->str == eid.ssp())
00085             found_ssp = true;
00086     }
00087 
00088     if (found_scheme == false) {
00089         dict->push_back(DictionaryEntry(eid.scheme_str(), *dictlen));
00090         *dictlen += (eid.scheme_str().length() + 1);
00091     }
00092 
00093     if (found_ssp == false) {
00094         dict->push_back(DictionaryEntry(eid.ssp(), *dictlen));
00095         *dictlen += (eid.ssp().length() + 1);
00096     }
00097 }
00098 
00099 //----------------------------------------------------------------------
00100 void
00101 BundleProtocol::get_dictionary_offsets(DictionaryVector *dict,
00102                                        EndpointID eid,
00103                                        u_int16_t* scheme_offset,
00104                                        u_int16_t* ssp_offset)
00105 {
00106     DictionaryVector::iterator iter;
00107     for (iter = dict->begin(); iter != dict->end(); ++iter) {
00108         if (iter->str == eid.scheme_str())
00109             *scheme_offset = htons(iter->offset);
00110 
00111         if (iter->str == eid.ssp())
00112             *ssp_offset = htons(iter->offset);
00113     }
00114 }
00115 
00116 //----------------------------------------------------------------------
00117 size_t
00118 BundleProtocol::get_primary_len(const Bundle* bundle,
00119                                 DictionaryVector* dict,
00120                                 size_t* dictionary_len,
00121                                 size_t* primary_var_len)
00122 {
00123     static const char* log = "/dtn/bundle/protocol";
00124     size_t primary_len = 0;
00125     *dictionary_len = 0;
00126     *primary_var_len = 0;
00127     
00128     /*
00129      * We need to figure out the total length of the primary block,
00130      * except for the SDNV used to encode the length itself and the
00131      * three byte preamble (PrimaryBlock1).
00132      *
00133      * First, we determine the size of the dictionary by first
00134      * figuring out all the unique strings, and in the process,
00135      * remembering their offsets and summing up their lengths
00136      * (including the null terminator for each).
00137      */
00138     add_to_dictionary(bundle->dest_,      dict, dictionary_len);
00139     add_to_dictionary(bundle->source_,    dict, dictionary_len);
00140     add_to_dictionary(bundle->custodian_, dict, dictionary_len);
00141     add_to_dictionary(bundle->replyto_,   dict, dictionary_len);
00142 
00143     (void)log; // in case NDEBUG is defined
00144     log_debug(log, "generated dictionary length %zu", *dictionary_len);
00145 
00146     *primary_var_len += SDNV::encoding_len(*dictionary_len);
00147     *primary_var_len += *dictionary_len;
00148 
00149     /*
00150      * If the bundle is a fragment, we need to include space for the
00151      * fragment offset and the original payload length.
00152      *
00153      * Note: Any changes to this protocol must be reflected into the
00154      * FragmentManager since it depends on this length when
00155      * calculating fragment sizes.
00156      */
00157     if (bundle->is_fragment_) {
00158         *primary_var_len += SDNV::encoding_len(bundle->frag_offset_);
00159         *primary_var_len += SDNV::encoding_len(bundle->orig_length_);
00160     }
00161 
00162     /*
00163      * Tack on the size of the PrimaryBlock2, 
00164      */
00165     *primary_var_len += sizeof(PrimaryBlock2);
00166 
00167     /*
00168      * Finally, add up the initial PrimaryBlock1 plus the size of the
00169      * SDNV to encode the variable length part, plus the variable
00170      * length part itself.
00171      */
00172     primary_len = sizeof(PrimaryBlock1) +
00173                   SDNV::encoding_len(*primary_var_len) +
00174                   *primary_var_len;
00175     
00176     log_debug(log, "get_primary_len(bundle %d): %zu",
00177               bundle->bundleid_, primary_len);
00178     
00179     return primary_len;
00180 }
00181 
00182 //----------------------------------------------------------------------
00183 size_t
00184 BundleProtocol::get_payload_block_len(const Bundle* bundle)
00185 {
00186     return (sizeof(BlockPreamble) +
00187             SDNV::encoding_len(bundle->payload_.length()));
00188 }
00189 
00190 //----------------------------------------------------------------------
00191 int
00192 BundleProtocol::format_header_blocks(const Bundle* bundle,
00193                                      u_char* buf, size_t len)
00194 {
00195     static const char* log = "/dtn/bundle/protocol";
00196     DictionaryVector dict;
00197     size_t orig_len = len;      // original length of the buffer
00198     size_t primary_len = 0;     // total length of the primary block
00199     size_t primary_var_len = 0; // length of the variable part of the primary
00200     size_t dictionary_len = 0;  // length of the dictionary
00201     int encoding_len = 0;       // use an int to handle -1 return values
00202 
00203     /*
00204      * Grab the primary block length and make sure we have enough
00205      * space in the buffer for it.
00206      */
00207     primary_len = get_primary_len(bundle, &dict, &dictionary_len,
00208                                   &primary_var_len);
00209     if (len < primary_len) {
00210         return -1;
00211     }
00212     
00213     (void)log; // in case NDEBUG is defined
00214     log_debug(log, "primary length %zu (preamble %zu var length %zu)",
00215               primary_len,
00216               (sizeof(PrimaryBlock1) + SDNV::encoding_len(primary_var_len)),
00217               primary_var_len);
00218     
00219     /*
00220      * Ok, stuff in the preamble and the total block length.
00221      */
00222     PrimaryBlock1* primary1              = (PrimaryBlock1*)buf;
00223     primary1->version                     = CURRENT_VERSION;
00224     primary1->bundle_processing_flags     = format_bundle_flags(bundle);
00225     primary1->class_of_service_flags      = format_cos_flags(bundle);
00226     primary1->status_report_request_flags = format_srr_flags(bundle);
00227     
00228     encoding_len = SDNV::encode(primary_var_len,
00229                                 &primary1->block_length[0], len - 3);
00230     ASSERT(encoding_len > 0);
00231     buf += (sizeof(PrimaryBlock1) + encoding_len);
00232     len -= (sizeof(PrimaryBlock1) + encoding_len);
00233 
00234     /*
00235      * Now fill in the PrimaryBlock2.
00236      */
00237     PrimaryBlock2* primary2 = (PrimaryBlock2*)buf;
00238 
00239     get_dictionary_offsets(&dict, bundle->dest_,
00240                            &primary2->dest_scheme_offset,
00241                            &primary2->dest_ssp_offset);
00242 
00243     get_dictionary_offsets(&dict, bundle->source_,
00244                            &primary2->source_scheme_offset,
00245                            &primary2->source_ssp_offset);
00246 
00247     get_dictionary_offsets(&dict, bundle->custodian_,
00248                            &primary2->custodian_scheme_offset,
00249                            &primary2->custodian_ssp_offset);
00250 
00251     get_dictionary_offsets(&dict, bundle->replyto_,
00252                            &primary2->replyto_scheme_offset,
00253                            &primary2->replyto_ssp_offset);
00254 
00255     set_timestamp(&primary2->creation_ts, &bundle->creation_ts_);
00256     u_int32_t lifetime = htonl(bundle->expiration_);
00257     memcpy(&primary2->lifetime, &lifetime, sizeof(lifetime));
00258 
00259     buf += sizeof(PrimaryBlock2);
00260     len -= sizeof(PrimaryBlock2);
00261 
00262     /*
00263      * Stuff in the dictionary length and dictionary bytes.
00264      */
00265     encoding_len = SDNV::encode(dictionary_len, buf, len);
00266     ASSERT(encoding_len > 0);
00267     buf += encoding_len;
00268     len -= encoding_len;
00269 
00270     DictionaryVector::iterator dict_iter;
00271     for (dict_iter = dict.begin(); dict_iter != dict.end(); ++dict_iter) {
00272         strcpy((char*)buf, dict_iter->str.c_str());
00273         buf += dict_iter->str.length() + 1;
00274         len -= dict_iter->str.length() + 1;
00275     }
00276     
00277     if (oasys::__log_enabled(oasys::LOG_DEBUG, "/dtn/bundle/protocol/dictionary")) {
00278         oasys::StringBuffer dict_copy;
00279         ASSERT(buf[-1] == '\0');
00280         char* bp = (char*)buf - dictionary_len;
00281         while (bp != (char*)buf) {
00282             dict_copy.appendf("%s ", bp);
00283             bp += strlen(bp) + 1;
00284         }
00285 
00286         log_debug("/dtn/bundle/protocol/dictionary",
00287                   "len %zu, value: '%s'", dictionary_len, dict_copy.c_str());
00288                   
00289         log_debug("/dtn/bundle/protocol/dictionary",
00290                   "offsets: dest %u,%u source %u,%u, "
00291                   "custodian %u,%u replyto %u,%u",
00292                   ntohs(primary2->dest_scheme_offset),
00293                   ntohs(primary2->dest_ssp_offset),
00294                   ntohs(primary2->source_scheme_offset),
00295                   ntohs(primary2->source_ssp_offset),
00296                   ntohs(primary2->custodian_scheme_offset),
00297                   ntohs(primary2->custodian_ssp_offset),
00298                   ntohs(primary2->replyto_scheme_offset),
00299                   ntohs(primary2->replyto_ssp_offset));
00300     }
00301 
00302     /*
00303      * If the bundle is a fragment, stuff in SDNVs for the fragment
00304      * offset and original length.
00305      */
00306     if (bundle->is_fragment_) {
00307         encoding_len = SDNV::encode(bundle->frag_offset_, buf, len);
00308         ASSERT(encoding_len > 0);
00309         buf += encoding_len;
00310         len -= encoding_len;
00311 
00312         encoding_len = SDNV::encode(bundle->orig_length_, buf, len);
00313         ASSERT(encoding_len > 0);
00314         buf += encoding_len;
00315         len -= encoding_len;
00316     }
00317 
00318 #ifndef NDEBUG
00319     {
00320         DictionaryVector dict2;
00321         size_t dict2_len = 0;
00322         size_t p2len;
00323         size_t len2 = get_primary_len(bundle, &dict2, &dict2_len, &p2len);
00324         ASSERT(len2 == (orig_len - len));
00325     }
00326 #endif
00327 
00328     // safety assertion
00329     ASSERT(primary_len == (orig_len - len));
00330 
00331     // XXX/demmer deal with other experimental blocks
00332 
00333     /*
00334      * Handle the payload block. Note that we don't stuff in the
00335      * actual payload here, even though it's technically part of the
00336      * "payload block".
00337      */
00338     u_int32_t payload_len = bundle->payload_.length();
00339     if (len < (sizeof(BlockPreamble) +
00340                SDNV::encoding_len(payload_len)))
00341     {
00342         return -1;
00343     }
00344 
00345     BlockPreamble* payload_block = (BlockPreamble*)buf;
00346     payload_block->type  = PAYLOAD_BLOCK;
00347     payload_block->flags = BLOCK_FLAG_LAST_BLOCK;
00348     buf += sizeof(BlockPreamble);
00349     len -= sizeof(BlockPreamble);
00350 
00351     encoding_len = SDNV::encode(payload_len, buf, len);
00352     ASSERT(encoding_len > 0);
00353     buf += encoding_len;
00354     len -= encoding_len;
00355 
00356     // return the total buffer length consumed
00357     log_debug(log, "encoding done -- total length %zu", (orig_len - len));
00358     return orig_len - len;
00359 }
00360 
00361 //----------------------------------------------------------------------
00362 int
00363 BundleProtocol::parse_header_blocks(Bundle* bundle,
00364                                     u_char* buf, size_t len)
00365 {
00366     static const char* log = "/dtn/bundle/protocol";
00367     size_t origlen = len;
00368     int encoding_len;
00369 
00370     /*
00371      * First the three bytes of the PrimaryBlock1
00372      */
00373     PrimaryBlock1* primary1;
00374     if (len < sizeof(PrimaryBlock1)) {
00375  tooshort1:
00376         log_debug(log, "buffer too short (parsed %zu/%zu)",
00377                   (origlen - len), origlen);
00378         return -1;
00379     }
00380 
00381     primary1 = (PrimaryBlock1*)buf;
00382     buf += sizeof(PrimaryBlock1);
00383     len -= sizeof(PrimaryBlock1);
00384 
00385     log_debug(log, "parsed primary block 1: version %d", primary1->version);
00386 
00387     if (primary1->version != CURRENT_VERSION) {
00388         log_warn(log, "protocol version mismatch %d != %d",
00389                  primary1->version, CURRENT_VERSION);
00390         return -1;
00391     }
00392 
00393     parse_bundle_flags(bundle, primary1->bundle_processing_flags);
00394     parse_cos_flags(bundle, primary1->class_of_service_flags);
00395     parse_srr_flags(bundle, primary1->status_report_request_flags);
00396 
00397     /*
00398      * Now parse the SDNV that describes the total primary block
00399      * length.
00400      */
00401     u_int32_t primary_len;
00402     encoding_len = SDNV::decode(buf, len, &primary_len);
00403     if (encoding_len == -1) {
00404         goto tooshort1;
00405     }
00406 
00407     buf += encoding_len;
00408     len -= encoding_len;
00409 
00410     log_debug(log, "parsed primary block length %u", primary_len);
00411 
00412     /*
00413      * Check if the advertised length is bigger than the amount we
00414      * have.
00415      */
00416     if (len < primary_len) {
00417         goto tooshort1;
00418     }
00419 
00420     /*
00421      * Still, we need to make sure that the sender didn't lie and that
00422      * we really do have enough for the decoding...
00423      */
00424     if (len < sizeof(PrimaryBlock2)) {
00425  tooshort2:
00426         log_err(log, "primary block advertised incorrect length: "
00427                 "advertised %u, total buffer %zu", primary_len, len);
00428         return -1;
00429     }
00430 
00431     /*
00432      * Parse the PrimaryBlock2
00433      */
00434     PrimaryBlock2* primary2    = (PrimaryBlock2*)buf;
00435     buf += sizeof(PrimaryBlock2);
00436     len -= sizeof(PrimaryBlock2);
00437 
00438     get_timestamp(&bundle->creation_ts_, &primary2->creation_ts);
00439     u_int32_t lifetime;
00440     memcpy(&lifetime, &primary2->lifetime, sizeof(lifetime));
00441     bundle->expiration_ = ntohl(lifetime);
00442 
00443     /*
00444      * Read the dictionary length.
00445      */
00446     u_int32_t dictionary_len = 0;
00447     encoding_len = SDNV::decode(buf, len, &dictionary_len);
00448     if (encoding_len < 0) {
00449         goto tooshort2;
00450     }
00451     buf += encoding_len;
00452     len -= encoding_len;
00453 
00454     /*
00455      * Verify that we have the whole dictionary.
00456      */
00457     if (len < dictionary_len) {
00458         goto tooshort2;
00459     }
00460 
00461     /*
00462      * Make sure that the dictionary ends with a null byte.
00463      */
00464     if (buf[dictionary_len - 1] != '\0') {
00465         log_err(log, "dictionary does not end with a NULL character!");
00466         return -1;
00467     }
00468 
00469     /*
00470      * Now use the dictionary buffer to parse out the various endpoint
00471      * identifiers, making sure that none of them peeks past the end
00472      * of the dictionary block.
00473      */
00474     u_char* dictionary = buf;
00475     buf += dictionary_len;
00476     len -= dictionary_len;
00477 
00478     u_int16_t scheme_offset, ssp_offset;
00479 
00480     if (oasys::__log_enabled(oasys::LOG_DEBUG, "/dtn/bundle/protocol/dictionary")) {
00481         oasys::StringBuffer dict_copy;
00482         ASSERT(buf[-1] == '\0');
00483         char* bp = (char*)buf - dictionary_len;
00484         while (bp != (char*)buf) {
00485             dict_copy.appendf("%s ", bp);
00486             bp += strlen(bp) + 1;
00487         }
00488 
00489         log_debug("/dtn/bundle/protocol/dictionary",
00490                   "len %u, value: '%s'", dictionary_len, dict_copy.c_str());
00491     }
00492                   
00493 
00494 #define EXTRACT_DICTIONARY_EID(_what)                                   \
00495     memcpy(&scheme_offset, &primary2->_what##_scheme_offset, 2);        \
00496     memcpy(&ssp_offset, &primary2->_what##_ssp_offset, 2);              \
00497     scheme_offset = ntohs(scheme_offset);                               \
00498     ssp_offset = ntohs(ssp_offset);                                     \
00499                                                                         \
00500     if (scheme_offset >= (dictionary_len - 1)) {                        \
00501         log_err(log, "illegal offset for %s scheme dictionary offset: " \
00502                 "offset %d, total length %u", #_what,                   \
00503                 scheme_offset, dictionary_len);                         \
00504         return -1;                                                      \
00505     }                                                                   \
00506                                                                         \
00507     if (ssp_offset >= (dictionary_len - 1)) {                           \
00508         log_err(log, "illegal offset for %s ssp dictionary offset: "    \
00509                 "offset %d, total length %u", #_what,                   \
00510                 ssp_offset, dictionary_len);                            \
00511         return -1;                                                      \
00512     }                                                                   \
00513     bundle->_what##_.assign((char*)&dictionary[scheme_offset],          \
00514                             (char*)&dictionary[ssp_offset]);            \
00515                                                                         \
00516                                                                         \
00517     if (! bundle->_what##_.valid()) {                                   \
00518         log_err(log, "invalid %s endpoint id '%s': "                    \
00519                 "scheme '%s' offset %u ssp '%s' offset %u/%u", #_what,  \
00520                 bundle->_what##_.c_str(),                               \
00521                 bundle->_what##_.scheme_str().c_str(),                  \
00522                 scheme_offset,                                          \
00523                 bundle->_what##_.ssp().c_str(),                         \
00524                 ssp_offset, dictionary_len);                            \
00525         return -1;                                                      \
00526     }                                                                   \
00527                                                                         \
00528     log_debug(log, "parsed %s eid (offsets %d, %d) %s", #_what,         \
00529               scheme_offset, ssp_offset, bundle->_what##_.c_str());     \
00530 
00531     EXTRACT_DICTIONARY_EID(source);
00532     EXTRACT_DICTIONARY_EID(dest);
00533     EXTRACT_DICTIONARY_EID(custodian);
00534     EXTRACT_DICTIONARY_EID(replyto);
00535 
00536     if (bundle->is_fragment_) {
00537         encoding_len = SDNV::decode(buf, len, &bundle->frag_offset_);
00538         if (encoding_len == -1) {
00539             goto tooshort2;
00540         }
00541         buf += encoding_len;
00542         len -= encoding_len;
00543 
00544         encoding_len = SDNV::decode(buf, len, &bundle->orig_length_);
00545         if (encoding_len == -1) {
00546             goto tooshort2;
00547         }
00548         buf += encoding_len;
00549         len -= encoding_len;
00550 
00551         log_debug(log, "parsed fragmentation info: offset %u, orig_len %u",
00552                   bundle->frag_offset_, bundle->orig_length_);
00553     }
00554 
00555     /*
00556      * Parse the other blocks, all of which have a preamble and an
00557      * SDNV for their length.
00558      */
00559     while (len != 0) {
00560         if (len <= sizeof(BlockPreamble)) {
00561             goto tooshort1;
00562         }
00563 
00564         BlockPreamble* preamble = (BlockPreamble*)buf;
00565         buf += sizeof(BlockPreamble);
00566         len -= sizeof(BlockPreamble);
00567 
00568         // note that we don't support lengths bigger than 4 bytes
00569         // here. this should be fixed when the bundle payload class
00570         // supports big payloads.
00571         u_int32_t block_len;
00572         encoding_len = SDNV::decode(buf, len, &block_len);
00573         if (encoding_len == -1) {
00574             goto tooshort1;
00575         }
00576         buf += encoding_len;
00577         len -= encoding_len;
00578 
00579         switch (preamble->type) {
00580         case PAYLOAD_BLOCK: {
00581             bundle->payload_.set_length(block_len);
00582             log_debug(log, "parsed payload length %zu",
00583                       bundle->payload_.length());
00584 
00585             // XXX/demmer add support for blocks after the payload block
00586             if (! (preamble->flags & BLOCK_FLAG_LAST_BLOCK)) {
00587                 log_crit(log,
00588                          "this implementation cannot handle blocks after "
00589                          "the payload!!");
00590             }
00591             
00592             // note that we don't actually snarf in the payload here
00593             // since it's handled by the caller, and since the payload
00594             // must be the last thing we handle in this function,
00595             // we're done.
00596             goto done;
00597         }
00598             
00599         default:
00600             // XXX/demmer handle extension blocks.
00601             log_err(log, "unknown block code 0x%x", preamble->type);
00602             return -1;
00603         }
00604     }
00605 
00606     // that's all we parse, return the amount we consumed
00607  done:
00608     return origlen - len;
00609 }
00610 
00611 //----------------------------------------------------------------------
00612 size_t
00613 BundleProtocol::header_block_length(const Bundle* bundle)
00614 {
00615     DictionaryVector dict;
00616     size_t dictionary_len;
00617     size_t primary_var_len;
00618 
00619     // XXX/demmer if this ends up being slow, we can cache it in the bundle
00620     
00621     return (get_primary_len(bundle, &dict, &dictionary_len, &primary_var_len) +
00622             get_payload_block_len(bundle));
00623 }
00624 
00625 //----------------------------------------------------------------------
00626 size_t
00627 BundleProtocol::formatted_length(const Bundle* bundle)
00628 {
00629     return header_block_length(bundle) +
00630         bundle->payload_.length() +
00631         tail_block_length(bundle);
00632 }
00633 
00634 //----------------------------------------------------------------------
00635 int
00636 BundleProtocol::format_bundle(const Bundle* bundle, u_char* buf, size_t len)
00637 {
00638     size_t origlen = len;
00639     
00640     // first the header blocks
00641     int ret = format_header_blocks(bundle, buf, len);
00642     if (ret < 0) {
00643         return ret;
00644     }
00645     buf += ret;
00646     len -= ret;
00647 
00648     // then the payload
00649     size_t payload_len = bundle->payload_.length();
00650     if (payload_len > len) {
00651         return -1;
00652     }
00653     bundle->payload_.read_data(0, payload_len, buf,
00654                                BundlePayload::FORCE_COPY);
00655     len -= payload_len;
00656     buf += payload_len;
00657 
00658     ret = format_tail_blocks(bundle, buf, len);
00659     if (ret < 0) {
00660         return ret;
00661     }
00662     len -= ret;
00663     buf += ret;
00664 
00665     return origlen - len;
00666 }
00667     
00668 //----------------------------------------------------------------------
00669 int
00670 BundleProtocol::parse_bundle(Bundle* bundle, u_char* buf, size_t len)
00671 {
00672     size_t origlen = len;
00673     
00674     // first the header blocks
00675     int ret = parse_header_blocks(bundle, buf, len);
00676     if (ret < 0) {
00677         return ret;
00678     }
00679     buf += ret;
00680     len -= ret;
00681 
00682     // then the payload
00683     size_t payload_len = bundle->payload_.length();
00684     if (payload_len > len) {
00685         return -1;
00686     }
00687     bundle->payload_.set_data(buf, payload_len);
00688     len -= payload_len;
00689     buf += payload_len;
00690 
00691     ret = parse_tail_blocks(bundle, buf, len);
00692     if (ret < 0) {
00693         return ret;
00694     }
00695     len -= ret;
00696     buf += ret;
00697 
00698     return origlen - len;
00699 }
00700     
00701 //----------------------------------------------------------------------
00702 void
00703 BundleProtocol::set_timestamp(u_char* ts, const BundleTimestamp* tv)
00704 {
00705     u_int32_t tmp;
00706 
00707     tmp = htonl(tv->seconds_);
00708     memcpy(ts, &tmp, sizeof(u_int32_t));
00709     ts += sizeof(u_int32_t);
00710 
00711     tmp = htonl(tv->seqno_);
00712     memcpy(ts, &tmp, sizeof(u_int32_t));
00713 }
00714 
00715 //----------------------------------------------------------------------
00716 void
00717 BundleProtocol::get_timestamp(BundleTimestamp* tv, const u_char* ts)
00718 {
00719     u_int32_t tmp;
00720 
00721     memcpy(&tmp, ts, sizeof(u_int32_t));
00722     tv->seconds_  = ntohl(tmp);
00723     ts += sizeof(u_int32_t);
00724     
00725     memcpy(&tmp, ts, sizeof(u_int32_t));
00726     tv->seqno_ = ntohl(tmp);
00727 }
00728 
00729 //----------------------------------------------------------------------
00730 u_int8_t
00731 BundleProtocol::format_bundle_flags(const Bundle* bundle)
00732 {
00733     u_int8_t flags = 0;
00734 
00735     if (bundle->is_fragment_) {
00736         flags |= BUNDLE_IS_FRAGMENT;
00737     }
00738 
00739     if (bundle->is_admin_) {
00740         flags |= BUNDLE_IS_ADMIN;
00741     }
00742 
00743     if (bundle->do_not_fragment_) {
00744         flags |= BUNDLE_DO_NOT_FRAGMENT;
00745     }
00746 
00747     if (bundle->custody_requested_) {
00748         flags |= BUNDLE_CUSTODY_XFER_REQUESTED;
00749     }
00750 
00751     if (bundle->singleton_dest_) {
00752         flags |= BUNDLE_SINGLETON_DESTINATION;
00753     }
00754 
00755     return flags;
00756 }
00757 
00758 //----------------------------------------------------------------------
00759 void
00760 BundleProtocol::parse_bundle_flags(Bundle* bundle, u_int8_t flags)
00761 {
00762     if (flags & BUNDLE_IS_FRAGMENT) {
00763         bundle->is_fragment_ = true;
00764     }
00765 
00766     if (flags & BUNDLE_IS_ADMIN) {
00767         bundle->is_admin_ = true;
00768     }
00769 
00770     if (flags & BUNDLE_DO_NOT_FRAGMENT) {
00771         bundle->do_not_fragment_ = true;
00772     }
00773 
00774     if (flags & BUNDLE_CUSTODY_XFER_REQUESTED) {
00775         bundle->custody_requested_ = true;
00776     }
00777 
00778     if (flags & BUNDLE_SINGLETON_DESTINATION) {
00779         bundle->singleton_dest_ = true;
00780     }
00781 }
00782 
00783 //----------------------------------------------------------------------
00784 u_int8_t
00785 BundleProtocol::format_cos_flags(const Bundle* b)
00786 {
00787     u_int8_t cos_flags = 0;
00788 
00789     cos_flags = ((b->priority_ & 0x3) << 6);
00790 
00791     return cos_flags;
00792 }
00793 
00794 //----------------------------------------------------------------------
00795 void
00796 BundleProtocol::parse_cos_flags(Bundle* b, u_int8_t cos_flags)
00797 {
00798     b->priority_ = ((cos_flags >> 6) & 0x3);
00799 }
00800 
00801 //----------------------------------------------------------------------
00802 u_int8_t
00803 BundleProtocol::format_srr_flags(const Bundle* b)
00804 {
00805     u_int8_t srr_flags = 0;
00806     
00807     if (b->receive_rcpt_)
00808         srr_flags |= STATUS_RECEIVED;
00809 
00810     if (b->custody_rcpt_)
00811         srr_flags |= STATUS_CUSTODY_ACCEPTED;
00812 
00813     if (b->forward_rcpt_)
00814         srr_flags |= STATUS_FORWARDED;
00815 
00816     if (b->delivery_rcpt_)
00817         srr_flags |= STATUS_DELIVERED;
00818 
00819     if (b->deletion_rcpt_)
00820         srr_flags |= STATUS_DELETED;
00821 
00822     if (b->app_acked_rcpt_)
00823         srr_flags |= STATUS_ACKED_BY_APP;
00824 
00825     return srr_flags;
00826 }
00827     
00828 //----------------------------------------------------------------------
00829 void
00830 BundleProtocol::parse_srr_flags(Bundle* b, u_int8_t srr_flags)
00831 {
00832     if (srr_flags & STATUS_RECEIVED)
00833         b->receive_rcpt_ = true;
00834 
00835     if (srr_flags & STATUS_CUSTODY_ACCEPTED)
00836         b->custody_rcpt_ = true;
00837 
00838     if (srr_flags & STATUS_FORWARDED)
00839         b->forward_rcpt_ = true;
00840 
00841     if (srr_flags & STATUS_DELIVERED)
00842         b->delivery_rcpt_ = true;
00843 
00844     if (srr_flags & STATUS_DELETED)
00845         b->deletion_rcpt_ = true;
00846 
00847     if (srr_flags & STATUS_ACKED_BY_APP)
00848         b->app_acked_rcpt_ = true;
00849 }
00850 
00851 //----------------------------------------------------------------------
00852 bool
00853 BundleProtocol::get_admin_type(const Bundle* bundle, admin_record_type_t* type)
00854 {
00855     if (! bundle->is_admin_) {
00856         return false;
00857     }
00858 
00859     u_char buf[16];
00860     const u_char* bp = bundle->payload_.read_data(0, sizeof(buf), buf);
00861 
00862     switch (bp[0] >> 4)
00863     {
00864 #define CASE(_what) case _what: *type = _what; return true;
00865 
00866         CASE(ADMIN_STATUS_REPORT);
00867         CASE(ADMIN_CUSTODY_SIGNAL);
00868         CASE(ADMIN_ECHO);
00869         CASE(ADMIN_NULL);
00870         CASE(ADMIN_ANNOUNCE);
00871 
00872 #undef  CASE
00873     default:
00874         return false; // unknown type
00875     }
00876 
00877     NOTREACHED;
00878 }
00879 
00880 } // namespace dtn

Generated on Fri Dec 22 14:47:58 2006 for DTN Reference Implementation by  doxygen 1.5.1