BundleStatusReport.cc

Go to the documentation of this file.
00001 /*
00002  *    Copyright 2004-2006 Intel Corporation
00003  * 
00004  *    Licensed under the Apache License, Version 2.0 (the "License");
00005  *    you may not use this file except in compliance with the License.
00006  *    You may obtain a copy of the License at
00007  * 
00008  *        http://www.apache.org/licenses/LICENSE-2.0
00009  * 
00010  *    Unless required by applicable law or agreed to in writing, software
00011  *    distributed under the License is distributed on an "AS IS" BASIS,
00012  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *    See the License for the specific language governing permissions and
00014  *    limitations under the License.
00015  */
00016 
00017 
00018 #include "BundleStatusReport.h"
00019 #include "SDNV.h"
00020 #include <netinet/in.h>
00021 #include <oasys/util/ScratchBuffer.h>
00022 
00023 namespace dtn {
00024 
00025 //----------------------------------------------------------------------
00026 void
00027 BundleStatusReport::create_status_report(Bundle*           bundle,
00028                                          const Bundle*     orig_bundle,
00029                                          const EndpointID& source,
00030                                          flag_t            status_flags,
00031                                          reason_t          reason)
00032 {
00033     bundle->source_.assign(source);
00034     if (orig_bundle->replyto_.equals(EndpointID::NULL_EID())){
00035         bundle->dest_.assign(orig_bundle->source_);
00036     } else {
00037         bundle->dest_.assign(orig_bundle->replyto_);
00038     }
00039     bundle->replyto_.assign(EndpointID::NULL_EID());
00040     bundle->custodian_.assign(EndpointID::NULL_EID());
00041     
00042     bundle->is_admin_ = true;
00043 
00044     // use the expiration time from the original bundle
00045     // XXX/demmer maybe something more clever??
00046     bundle->expiration_ = orig_bundle->expiration_;
00047 
00048     // store the original bundle's source eid
00049     EndpointID orig_source(orig_bundle->source_);
00050 
00051     int sdnv_encoding_len = 0;  // use an int to handle -1 return values
00052     int report_length = 0;
00053     
00054     // we generally don't expect the Status Peport length to be > 256 bytes
00055     oasys::ScratchBuffer<u_char*, 256> scratch;
00056 
00057     //
00058     // Structure of bundle status reports:
00059     //
00060     // 1 byte Admin Payload type and flags
00061     // 1 byte Status Flags
00062     // 1 byte Reason Code
00063     // SDNV   [Fragment Offset (if present)]
00064     // SDNV   [Fragment Length (if present)]
00065     // 8 byte Time of {receipt/forwarding/delivery/deletion/custody/app-ack}
00066     //        of bundle X
00067     // 8 byte Copy of bundle X's Creation Timestamp
00068     // SDNV   Length of X's source endpoint ID
00069     // vari   Source endpoint ID of bundle X
00070 
00071     // note that the spec allows for all 6 of the "Time of..." fields
00072     // to be present in a single Status Report, but for this
00073     // implementation we will always have one and only one of the 6
00074     // timestamp fields
00075     // XXX/matt we may want to change to allow multiple-timestamps per SR
00076 
00077     // the non-optional, fixed-length fields above:
00078     report_length = 1 + 1 + 1 + 8 + 8;
00079 
00080     // the 2 SDNV fragment fields:
00081     if (orig_bundle->is_fragment_) {
00082         report_length += SDNV::encoding_len(orig_bundle->frag_offset_);
00083         report_length += SDNV::encoding_len(orig_bundle->orig_length_);
00084     }
00085 
00086     // the Source Endpoint ID:
00087     report_length += SDNV::encoding_len(orig_source.length()) + orig_source.length();
00088 
00089     //
00090     // Done calculating length, now create the report payload
00091     //
00092     
00093     u_char* bp = scratch.buf(report_length);
00094     int len = report_length;
00095     
00096     // Admin Payload Type and flags
00097     *bp = BundleProtocol::ADMIN_STATUS_REPORT << 4;
00098     if (orig_bundle->is_fragment_) {
00099         *bp |= BundleProtocol::ADMIN_IS_FRAGMENT;
00100     }
00101     bp++;
00102     len--;
00103     
00104     // Status Flags
00105     *bp++ = status_flags;
00106     len--;
00107 
00108     // Reason Code
00109     *bp++ = reason;
00110     len--;
00111     
00112     // The 2 Fragment Fields
00113     if (orig_bundle->is_fragment_) {
00114         sdnv_encoding_len = SDNV::encode(orig_bundle->frag_offset_, bp, len);
00115         ASSERT(sdnv_encoding_len > 0);
00116         bp  += sdnv_encoding_len;
00117         len -= sdnv_encoding_len;
00118         
00119         sdnv_encoding_len = SDNV::encode(orig_bundle->orig_length_, bp, len);
00120         ASSERT(sdnv_encoding_len > 0);
00121         bp  += sdnv_encoding_len;
00122         len -= sdnv_encoding_len;
00123     }   
00124 
00125     // Time field, set to the current time (with no sub-second
00126     // accuracy defined at all)
00127     BundleTimestamp now;
00128     now.seconds_ = BundleTimestamp::get_current_time();
00129     now.seqno_   = 0;
00130     BundleProtocol::set_timestamp(bp, &now);
00131     len -= sizeof(u_int64_t);
00132     bp  += sizeof(u_int64_t);
00133 
00134     // Copy of bundle X's Creation Timestamp
00135     BundleProtocol::set_timestamp(bp, &orig_bundle->creation_ts_);
00136     len -= sizeof(u_int64_t);
00137     bp  += sizeof(u_int64_t);
00138     
00139     // The 2 Endpoint ID fields:
00140     sdnv_encoding_len = SDNV::encode(orig_source.length(), bp, len);
00141     ASSERT(sdnv_encoding_len > 0);
00142     len -= sdnv_encoding_len;
00143     bp  += sdnv_encoding_len;
00144     
00145     ASSERT((u_int)len == orig_source.length());
00146     memcpy(bp, orig_source.c_str(), orig_source.length());
00147     
00148     // 
00149     // Finished generating the payload
00150     //
00151     bundle->payload_.set_data(scratch.buf(), report_length);
00152 }
00153 
00154 //----------------------------------------------------------------------
00155 bool BundleStatusReport::parse_status_report(data_t* data,
00156                                              const u_char* bp, u_int len)
00157 {
00158     // 1 byte Admin Payload Type + Flags:
00159     if (len < 1) { return false; }
00160     data->admin_type_  = (*bp >> 4);
00161     data->admin_flags_ = *bp & 0xf;
00162     bp++;
00163     len--;
00164 
00165     // validate the admin type
00166     if (data->admin_type_ != BundleProtocol::ADMIN_STATUS_REPORT) {
00167         return false;
00168     }
00169 
00170     // 1 byte Status Flags:
00171     if (len < 1) { return false; }
00172     data->status_flags_ = *bp++;
00173     len--;
00174     
00175     // 1 byte Reason Code:
00176     if (len < 1) { return false; }
00177     data->reason_code_ = *bp++;
00178     len--;
00179     
00180     // Fragment SDNV Fields (offset & length), if present:
00181     if (data->admin_flags_ & BundleProtocol::ADMIN_IS_FRAGMENT) {
00182         int sdnv_bytes = SDNV::decode(bp, len, &data->orig_frag_offset_);
00183         if (sdnv_bytes == -1) { return false; }
00184         bp  += sdnv_bytes;
00185         len -= sdnv_bytes;
00186         sdnv_bytes = SDNV::decode(bp, len, &data->orig_frag_length_);
00187         if (sdnv_bytes == -1) { return false; }
00188         bp  += sdnv_bytes;
00189         len -= sdnv_bytes;
00190     }
00191 
00192     // The 6 Optional ACK Timestamps:
00193     
00194     if (data->status_flags_ & BundleProtocol::STATUS_RECEIVED) {
00195         if (len < sizeof(u_int64_t)) { return false; }
00196         BundleProtocol::get_timestamp(&data->receipt_tv_, bp);
00197         bp  += sizeof(u_int64_t);
00198         len -= sizeof(u_int64_t);
00199     }
00200 
00201     if (data->status_flags_ & BundleProtocol::STATUS_CUSTODY_ACCEPTED) {
00202         if (len < sizeof(u_int64_t)) { return false; }
00203         BundleProtocol::get_timestamp(&data->custody_tv_, bp);
00204         bp  += sizeof(u_int64_t);
00205         len -= sizeof(u_int64_t);
00206     }
00207 
00208     if (data->status_flags_ & BundleProtocol::STATUS_FORWARDED) {
00209         if (len < sizeof(u_int64_t)) { return false; }
00210         BundleProtocol::get_timestamp(&data->forwarding_tv_, bp);
00211         bp  += sizeof(u_int64_t);
00212         len -= sizeof(u_int64_t);
00213     }
00214 
00215     if (data->status_flags_ & BundleProtocol::STATUS_DELIVERED) {
00216         if (len < sizeof(u_int64_t)) { return false; }
00217         BundleProtocol::get_timestamp(&data->delivery_tv_, bp);
00218         bp  += sizeof(u_int64_t);
00219         len -= sizeof(u_int64_t);
00220     }
00221 
00222     if (data->status_flags_ & BundleProtocol::STATUS_DELETED) {
00223         if (len < sizeof(u_int64_t)) { return false; }
00224         BundleProtocol::get_timestamp(&data->deletion_tv_, bp);
00225         bp  += sizeof(u_int64_t);
00226         len -= sizeof(u_int64_t);
00227     }
00228 
00229     if (data->status_flags_ & BundleProtocol::STATUS_ACKED_BY_APP) {
00230         if (len < sizeof(u_int64_t)) { return false; }
00231         BundleProtocol::get_timestamp(&data->acknowledgement_tv_, bp);
00232         bp  += sizeof(u_int64_t);
00233         len -= sizeof(u_int64_t);
00234     }
00235 
00236     
00237     // Bundle Creation Timestamp
00238     if (len < sizeof(u_int64_t)) { return false; }
00239     BundleProtocol::get_timestamp(&data->orig_creation_tv_, bp);
00240     bp  += sizeof(u_int64_t);
00241     len -= sizeof(u_int64_t);
00242 
00243     
00244     // EID of Bundle
00245     u_int64_t EID_len;
00246     int num_bytes = SDNV::decode(bp, len, &EID_len);
00247     if (num_bytes == -1) { return false; }
00248     bp  += num_bytes;
00249     len -= num_bytes;
00250 
00251     if (len != EID_len) { return false; }
00252     bool ok = data->orig_source_eid_.assign(std::string((const char*)bp, len));
00253     if (!ok) {
00254         return false;
00255     }
00256     
00257     return true;
00258 }
00259 
00260 //----------------------------------------------------------------------
00261 bool
00262 BundleStatusReport::parse_status_report(data_t* data,
00263                                         const Bundle* bundle)
00264 {
00265     BundleProtocol::admin_record_type_t admin_type;
00266     if (! BundleProtocol::get_admin_type(bundle, &admin_type)) {
00267         return false;
00268     }
00269 
00270     if (admin_type != BundleProtocol::ADMIN_STATUS_REPORT) {
00271         return false;
00272     }
00273 
00274     size_t payload_len = bundle->payload_.length();
00275     if (payload_len > 16384) {
00276         log_err_p("/dtn/bundle/protocol",
00277                   "status report length %zu too big to be parsed!!",
00278                   payload_len);
00279         return false;
00280     }
00281 
00282     oasys::ScratchBuffer<u_char*, 256> buf;
00283     buf.reserve(payload_len);
00284     const u_char* bp = bundle->payload_.read_data(0, payload_len, buf.buf());
00285     return parse_status_report(data, bp, payload_len);
00286 }
00287 
00288 //----------------------------------------------------------------------
00289 const char*
00290 BundleStatusReport::reason_to_str(u_int8_t reason)
00291 {
00292     switch (reason) {
00293     case BundleProtocol::REASON_NO_ADDTL_INFO:
00294         return "no additional information";
00295 
00296     case BundleProtocol::REASON_LIFETIME_EXPIRED:
00297         return "lifetime expired";
00298 
00299     case BundleProtocol::REASON_FORWARDED_UNIDIR_LINK:
00300         return "forwarded over unidirectional link";
00301 
00302     case BundleProtocol::REASON_TRANSMISSION_CANCELLED:
00303         return "transmission cancelled";
00304 
00305     case BundleProtocol::REASON_DEPLETED_STORAGE:
00306         return "depleted storage";
00307 
00308     case BundleProtocol::REASON_ENDPOINT_ID_UNINTELLIGIBLE:
00309         return "endpoint id unintelligible";
00310 
00311     case BundleProtocol::REASON_NO_ROUTE_TO_DEST:
00312         return "no known route to destination";
00313 
00314     case BundleProtocol::REASON_NO_TIMELY_CONTACT:
00315         return "no timely contact";
00316 
00317     case BundleProtocol::REASON_BLOCK_UNINTELLIGIBLE:
00318         return "block unintelligible";
00319 
00320     default:
00321         return "(unknown reason)";
00322     }
00323 }
00324 
00325 } // namespace dtn

Generated on Sat Sep 8 08:43:25 2007 for DTN Reference Implementation by  doxygen 1.5.3