ProphetTLV.cc

Go to the documentation of this file.
00001 /*
00002  *    Copyright 2006 Baylor University
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 #include "ProphetTLV.h"
00018 #include "bundling/BundleDaemon.h"
00019 
00020 namespace dtn {
00021 
00022 void
00023 BaseTLV::dump(oasys::StringBuffer* buf)
00024 {
00025     buf->appendf("-+-+-+-\nTLV Type: %s\n" 
00026                  "Flags: %d\n"
00027                  "Length: %d\n",
00028                  Prophet::tlv_to_str(typecode_),flags_,length_);
00029 }
00030 
00031 void
00032 HelloTLV::dump(oasys::StringBuffer* buf)
00033 {
00034     BaseTLV::dump(buf);
00035     buf->appendf("HF: %s\n"
00036                  "Timer: %d\n"
00037                  "Sender: %s\n",
00038                  Prophet::hf_to_str(hf_),timer_,sender_.c_str());
00039 }
00040 
00041 void
00042 RIBDTLV::dump(oasys::StringBuffer* buf)
00043 {
00044     BaseTLV::dump(buf);
00045     buf->appendf("RIBD Entries: %zu\n",ribd_.size());
00046     // ProphetDictionary
00047     ribd_.dump(buf);
00048 }
00049 
00050 void
00051 RIBTLV::dump(oasys::StringBuffer* buf)
00052 {
00053     BaseTLV::dump(buf);
00054     buf->appendf("Relay: %s\n"
00055                  "Custody: %s\n"
00056                  "Internet GW: %s\n"
00057                  "RIB Entries: %zu\n",
00058                  relay_ ? "true" : "false",
00059                  custody_ ? "true" : "false",
00060                  internet_ ? "true" : "false",
00061                  nodes_.size());
00062     for(PointerList<RIBNode>::iterator i = nodes_.begin();
00063         i != nodes_.end();
00064         i++)
00065     {
00066         (*i)->dump(buf);
00067     }
00068 }
00069 
00070 void
00071 BundleTLV::dump(oasys::StringBuffer* buf)
00072 {
00073     BaseTLV::dump(buf);
00074     buf->appendf("Type: %s\n"
00075                  "Bundle Entries: %zu\n",
00076                  BundleOffer::type_to_str(list_.type()),
00077                  list_.size());
00078     // BundleOfferList
00079     list_.dump(buf);
00080 }
00081 
00082 void
00083 ProphetTLV::dump(oasys::StringBuffer* buf)
00084 {
00085     buf->appendf("ProphetTLV Header\n-----------------\n" 
00086                  "Result: %s\n"
00087                  "Sender: %d\n"
00088                  "Receiver: %d\n"
00089                  "TransactionID: %d\n"
00090                  "Length: %d\n"
00091                  "Entries: %zu\n",
00092                  Prophet::result_to_str(result_),
00093                  sender_instance_,
00094                  receiver_instance_,
00095                  tid_,
00096                  parsedlen_,
00097                  num_tlv());
00098     for(iterator i = list_.begin(); i != list_.end(); i++)
00099     {
00100         switch((*i)->typecode())
00101         {
00102             case Prophet::HELLO_TLV:
00103             {
00104                 HelloTLV* p = dynamic_cast<HelloTLV*>(*i);
00105                 p->dump(buf);
00106                 break;
00107             }
00108             case Prophet::RIBD_TLV:
00109             {
00110                 RIBDTLV* p = dynamic_cast<RIBDTLV*>(*i);
00111                 p->dump(buf);
00112                 break;
00113             }
00114             case Prophet::RIB_TLV:
00115             {
00116                 RIBTLV* p = dynamic_cast<RIBTLV*>(*i);
00117                 p->dump(buf);
00118                 break;
00119             }
00120             case Prophet::BUNDLE_TLV:
00121             {
00122                 BundleTLV* p = dynamic_cast<BundleTLV*>(*i);
00123                 p->dump(buf);
00124                 break;
00125             }
00126             case Prophet::UNKNOWN_TLV:
00127             default:
00128                 buf->appendf("Unknown TLV\n");
00129                 break;
00130         }
00131     }
00132 }
00133 
00134 bool
00135 HelloTLV::deserialize(u_char* buffer, size_t len)
00136 {
00137     size_t hdrsz = Prophet::HelloTLVHeaderSize;
00138     Prophet::HelloTLVHeader *hdr = (Prophet::HelloTLVHeader*) buffer;
00139 
00140     // shouldn't be here if not HELLO!!
00141     if (hdr->type != Prophet::HELLO_TLV) {
00142         log_err("looking for TLV type %u but got %u",
00143                 Prophet::HELLO_TLV,hdr->type);
00144         return false;
00145     }
00146 
00147     // need at lease header size to parse out this TLV
00148     if (len < hdrsz)
00149         return false;
00150 
00151     // something's wrong if TLV shows greater length than inbound buffer
00152     size_t hello_len = ntohs(hdr->length);
00153     if (len < hello_len)
00154         return false;
00155 
00156     // don't want to read past the end of the buffer
00157     if (hello_len < hdr->name_length)
00158         return false;
00159 
00160     hf_     = (Prophet::hello_hf_t) hdr->HF;
00161     length_ = hello_len;
00162     timer_  = hdr->timer;
00163 
00164     std::string name((char*)&hdr->sender_name[0],(int)hdr->name_length);
00165     sender_.assign(name);
00166 
00167     return true;
00168 }
00169 
00170 size_t
00171 RIBDTLV::read_ras_entry(u_int16_t* sid,
00172                         EndpointID* eid,
00173                         u_char* buffer,
00174                         size_t len)
00175 {
00176     size_t ras_sz = Prophet::RoutingAddressStringSize;
00177     if (len <= ras_sz)
00178         return 0;
00179     Prophet::RoutingAddressString* ras =
00180         (Prophet::RoutingAddressString*) buffer;
00181     size_t retval = ras_sz;
00182     *sid = ntohs(ras->string_id);
00183     // must be even multiple of 4 bytes
00184     size_t copylen = FOUR_BYTE_ALIGN(ras->length);
00185     if (len - retval >= copylen) {
00186         std::string eidstr((char*)&ras->ra_string[0],ras->length);
00187         eid->assign(eidstr);
00188         ASSERT(eid->equals(EndpointID::NULL_EID())==false);
00189         retval += copylen;
00190     }
00191     log_debug("read_ras_entry: read %zu bytes from %zu byte buffer",
00192               retval,len);
00193     return retval;
00194 }
00195 
00196 bool
00197 RIBDTLV::deserialize(u_char* buffer, size_t len)
00198 {
00199     Prophet::RIBDTLVHeader* hdr = (Prophet::RIBDTLVHeader*) buffer;
00200     if (hdr->type != typecode_) {
00201         log_err("looking for TLV type %u but got %u",
00202                 typecode_,hdr->type);
00203         return false;
00204     }
00205 
00206     if (len < Prophet::RIBDTLVHeaderSize)
00207         return false;
00208     
00209     length_ = ntohs(hdr->length);
00210 
00211     if (len < length_)
00212         return false;
00213 
00214     flags_  = hdr->flags;
00215 
00216     size_t ribd_entry_count = ntohs(hdr->entry_count);
00217     u_char* bp = buffer + Prophet::RIBDTLVHeaderSize;
00218 
00219     size_t amt_read = Prophet::RIBDTLVHeaderSize;
00220     len -= Prophet::RIBDTLVHeaderSize;
00221 
00222     u_int16_t sid;
00223     EndpointID eid;
00224     ribd_.clear();
00225     while (ribd_entry_count-- > 0) {
00226 
00227         // deserialize RAS from buffer
00228         size_t bytes_read = read_ras_entry(&sid,&eid,bp,len);
00229         if (bytes_read == 0) {
00230             // log an error?
00231             break;
00232         }
00233 
00234         // store this dictionary entry
00235         if(ribd_.assign(eid,sid) == false) {
00236             // log an error
00237             break;
00238         }
00239 
00240         len      -= bytes_read;
00241         bp       += bytes_read;
00242         amt_read += bytes_read;
00243     }
00244 
00245     return (amt_read == length_);
00246 }
00247 
00248 size_t
00249 RIBTLV::read_rib_entry(u_int16_t* sid, double* pvalue, bool* relay,
00250                        bool* custody, bool* internet,
00251                        u_char* buffer, size_t len)
00252 {
00253     size_t rib_sz = Prophet::RIBEntrySize;
00254     if (len < rib_sz)
00255         return 0;
00256     Prophet::RIBEntry* rib = (Prophet::RIBEntry*) buffer;
00257     *sid = ntohs(rib->string_id);
00258     *pvalue   = ((rib->pvalue & 0xff) + 0.0) / (256.0);
00259     *relay    = ((rib->flags & Prophet::RELAY_NODE) ==
00260                                Prophet::RELAY_NODE);
00261     *custody  = ((rib->flags & Prophet::CUSTODY_NODE) ==
00262                                Prophet::CUSTODY_NODE);
00263     *internet = ((rib->flags & Prophet::INTERNET_GW_NODE) ==
00264                                Prophet::INTERNET_GW_NODE);
00265     log_debug("read_rib_entry: read %zu bytes from %zu byte buffer",
00266               rib_sz,len);
00267     return rib_sz;
00268 }
00269 
00270 bool
00271 RIBTLV::deserialize(u_char* buffer, size_t len)
00272 {
00273     size_t hdrsz = Prophet::RIBTLVHeaderSize;
00274     Prophet::RIBTLVHeader* hdr = (Prophet::RIBTLVHeader*) buffer;
00275     if (hdr->type != typecode_) {
00276         log_err("looking for TLV type %u but got %u",
00277                 typecode_,hdr->type);
00278         return 0;
00279     }
00280 
00281     if (len < hdrsz)
00282         return 0;
00283 
00284     length_ = ntohs(hdr->length);
00285 
00286     if (len < length_)
00287         return 0;
00288 
00289     flags_  = hdr->flags;
00290 
00291     size_t rib_entry_count = ntohs(hdr->rib_string_count);
00292     u_char* bp = buffer + hdrsz;
00293 
00294     size_t amt_read = hdrsz;
00295     len -= hdrsz;
00296 
00297     // local represents our copy of ProphetNode 
00298     // remote represents the remote copy (from the TLV)
00299     size_t ribsz = Prophet::RIBEntrySize;
00300     while (rib_entry_count-- > 0) {
00301 
00302         RIBNode remote; 
00303         u_int16_t sid = 0;
00304         double pvalue = 0;
00305         bool relay = false;
00306         bool custody = false;
00307         bool internet = false;
00308 
00309         // deserialize RIBEntry from buffer
00310         size_t bytes_read = read_rib_entry(&sid, &pvalue, &relay,
00311                                            &custody, &internet, bp, len);
00312         if (bytes_read != ribsz) {
00313             // log an error
00314             break;
00315         }
00316 
00317         remote.set_pvalue(pvalue);
00318         remote.set_relay(relay);
00319         remote.set_custody(custody);
00320         remote.set_internet_gw(internet);
00321         remote.sid_ = sid;
00322 
00323         // store this RIBEntry in nodes_
00324         nodes_.push_back(new RIBNode(remote));
00325 
00326         len      -= bytes_read;
00327         bp       += bytes_read;
00328         amt_read += bytes_read; 
00329     }
00330 
00331     return (amt_read == length_);
00332 }
00333 
00334 size_t
00335 BundleTLV::read_bundle_offer(u_int32_t *cts, u_int16_t *sid,
00336                              bool *custody, bool *accept, bool *ack,
00337                              BundleOffer::bundle_offer_t *type,
00338                              u_char* bp, size_t len)
00339 {
00340     size_t boe_sz = Prophet::BundleOfferEntrySize;
00341     if (len < boe_sz) {
00342         log_debug("not enough buffer to parse in Bundle entry, "
00343                   "needed %zu but got %zu",boe_sz,len);
00344         return 0;
00345     }
00346     Prophet::BundleOfferEntry* p =
00347         (Prophet::BundleOfferEntry*) bp;
00348 
00349     u_int8_t offer_mask =
00350         (Prophet::CUSTODY_OFFERED | Prophet::PROPHET_ACK) & 0xff;
00351 
00352     u_int8_t response_mask =
00353         (Prophet::CUSTODY_ACCEPTED | Prophet::BUNDLE_ACCEPTED) & 0xff; 
00354 
00355     u_int8_t flags = p->b_flags & 0xff; // mask out one byte
00356 
00357     // infer whether Bundle offer or Bundle response or error
00358     if ((flags & offer_mask) == flags)
00359     {
00360         *type = BundleOffer::OFFER;
00361         *custody = ((flags & Prophet::CUSTODY_OFFERED) == 
00362                             Prophet::CUSTODY_OFFERED);
00363         *ack = ((flags & Prophet::PROPHET_ACK) ==
00364                          Prophet::PROPHET_ACK);
00365     }
00366     else
00367     if ((flags & response_mask) == flags)
00368     {
00369         *type = BundleOffer::RESPONSE;
00370         *custody = ((flags & Prophet::CUSTODY_ACCEPTED) == 
00371                              Prophet::CUSTODY_ACCEPTED);
00372         *accept = ((flags & Prophet::BUNDLE_ACCEPTED) ==
00373                             Prophet::BUNDLE_ACCEPTED);
00374     }
00375     else
00376     {
00377         *type = BundleOffer::UNDEFINED;
00378         log_debug("illegal flag on Bundle entry: %x",flags);
00379         return 0;
00380     }
00381 
00382     *sid = ntohs(p->dest_string_id);
00383     *cts = ntohl(p->creation_timestamp);
00384     return boe_sz;
00385 }
00386 
00387 bool
00388 BundleTLV::deserialize(u_char* buffer, size_t len)
00389 {
00390     Prophet::BundleOfferTLVHeader* hdr = 
00391         (Prophet::BundleOfferTLVHeader*) buffer;
00392 
00393     size_t hdrlen = Prophet::BundleOfferTLVHeaderSize;
00394     size_t amt_read = 0;
00395     if (hdr->type != typecode_) {
00396         log_debug("read_bundle_offer: looking for TLV type %u but got %u",
00397                   typecode_,hdr->type);
00398         return false;
00399     }
00400 
00401     if (len < hdrlen) {
00402         return false;
00403     }
00404 
00405     length_ = ntohs(hdr->length);
00406 
00407     if (len < length_) {
00408         return false;
00409     }
00410 
00411     flags_  = hdr->flags;
00412 
00413     size_t offer_count = ntohs(hdr->offer_count);
00414 
00415     buffer     += hdrlen;
00416     len        -= hdrlen;
00417     amt_read   += hdrlen;
00418 
00419     ASSERT(list_.empty());
00420     ASSERT(list_.type() == BundleOffer::UNDEFINED);
00421 
00422     size_t entrylen = Prophet::BundleOfferEntrySize;
00423     while (len >= entrylen &&
00424            amt_read + entrylen <= length_ &&
00425            offer_count-- > 0)
00426     {
00427         u_int32_t cts = 0;
00428         u_int16_t sid = 0;
00429         bool custody = false,
00430              accept = false,
00431              ack = false;
00432         BundleOffer::bundle_offer_t type = BundleOffer::UNDEFINED;
00433 
00434         if (read_bundle_offer(&cts,&sid,&custody,&accept,&ack,&type,
00435                     buffer,len) == 0)
00436             break;
00437 
00438         // initialize to inferred type, if not yet defined
00439         if (list_.type() == BundleOffer::UNDEFINED) { 
00440             ASSERT(list_.empty());
00441             list_.set_type(type);
00442         }
00443 
00444         ASSERTF(list_.type() == type,"\n%s != %s\n"
00445                 "cts %d\n"
00446                 "sid %d\n"
00447                 "custody %s\n"
00448                 "accept %s\n"
00449                 "ack %s\n"
00450                 "offer_count %d\n",
00451                 BundleOffer::type_to_str(list_.type()),
00452                 BundleOffer::type_to_str(type),
00453                 cts,sid,
00454                 custody ? "true" : "false",
00455                 accept ? "true" : "false",
00456                 ack ? "true" : "false",
00457                 ntohs(hdr->offer_count));
00458 
00459         list_.add_offer(cts,sid,custody,accept,ack);
00460 
00461         len        -= entrylen;
00462         amt_read   += entrylen;
00463         buffer     += entrylen;
00464     }
00465 
00466     return (amt_read == length_);
00467 }
00468 
00469 ProphetTLV::ProphetTLV(const char* logpath) :
00470     oasys::Logger("ProphetTLV",logpath),
00471     result_(Prophet::UnknownResult),
00472     sender_instance_(0),
00473     receiver_instance_(0),
00474     tid_(0),
00475     parsedlen_(0)
00476 {
00477     list_.clear();
00478 }
00479 
00480 ProphetTLV::ProphetTLV(Prophet::header_result_t result,
00481                        u_int16_t local_instance,
00482                        u_int16_t remote_instance,
00483                        u_int32_t tid,
00484                        const char* logpath) :
00485     oasys::Logger("ProphetTLV",logpath),
00486     result_(result),
00487     sender_instance_(local_instance),
00488     receiver_instance_(remote_instance),
00489     tid_(tid),
00490     parsedlen_(Prophet::ProphetHeaderSize)
00491 {
00492     ASSERTF(local_instance != 0, "0 is not a valid sender_instance id");
00493     list_.clear();
00494 }
00495 
00496 ProphetTLV::~ProphetTLV()
00497 {
00498     for(iterator i = list_.begin();
00499         i != list_.end();
00500         i++)
00501     {
00502         BaseTLV* b = *i;
00503         switch(b->typecode()) {
00504             case Prophet::HELLO_TLV:
00505                 delete (HelloTLV*) b;
00506                 break;
00507             case Prophet::RIBD_TLV:
00508                 delete (RIBDTLV*) b;
00509                 break;
00510             case Prophet::RIB_TLV:
00511                 delete (RIBTLV*) b;
00512                 break;
00513             case Prophet::BUNDLE_TLV:
00514                 delete (BundleTLV*) b;
00515                 break;
00516             case Prophet::UNKNOWN_TLV:
00517             default:
00518                 PANIC("Unexpected typecode in ~ProphetTLV");
00519                 break;
00520         }
00521     }
00522 }
00523 
00524 BaseTLV*
00525 ProphetTLV::get_tlv()
00526 {
00527     if (list_.empty())
00528         return NULL;
00529     BaseTLV* t = list_.front();
00530     list_.pop_front(); 
00531     return t;
00532 }
00533 
00534 void
00535 ProphetTLV::add_tlv(BaseTLV* tlv)
00536 {
00537     ASSERT(tlv != NULL);
00538     parsedlen_ += tlv->length();
00539     list_.push_back(tlv);
00540 }
00541 
00542 ProphetTLV*
00543 ProphetTLV::deserialize(Bundle* b,
00544                         EndpointID* local,
00545                         EndpointID* remote,
00546                         const char* logpath)
00547 {
00548     // set up the ScratchBuffer
00549     size_t buflen = b->payload_.length();
00550     oasys::ScratchBuffer<u_char*> buf(buflen);
00551 
00552     // read out the bundle payload
00553     u_char* bp = (u_char*)b->payload_.read_data(0, buflen,
00554                                 (u_char*)buf.buf(buflen));
00555 
00556     ProphetTLV* pt = new ProphetTLV(logpath);
00557     if (local != NULL) local->assign(b->dest_);
00558     if (remote != NULL) remote->assign(b->source_);
00559 
00560     if ( pt->deserialize(bp,buflen) ) {
00561         return pt;
00562     }
00563 
00564     // error in deserializing 
00565     delete pt;
00566     return NULL;
00567 }
00568 
00569 bool
00570 ProphetTLV::deserialize(u_char* bp, size_t buflen)
00571 {
00572     // shouldn't get here otherwise
00573     ASSERT(parsedlen_ == 0);
00574 
00575     if (bp == NULL)
00576     {
00577         log_err("can't deserialize with uninitialized pointer");
00578         return false;
00579     }
00580 
00581     if (buflen < Prophet::ProphetHeaderSize)
00582     {
00583         log_err("not enough buffer to deserialize: got %zu need "
00584                 "more than %zu",buflen,Prophet::ProphetHeaderSize);
00585         return false;
00586     }
00587 
00588     Prophet::ProphetHeader* hdr = (Prophet::ProphetHeader*) bp;
00589 
00590     if (hdr->version != Prophet::PROPHET_VERSION)
00591     {
00592         log_err("unsupported Prophet version %x",hdr->version);
00593         return false;
00594     }
00595 
00596     if (hdr->flags != 0)
00597     {
00598         log_err("unsupported Prophet header flags %x",hdr->flags);
00599         return false;
00600     }
00601 
00602     if (hdr->code != 0)
00603     {
00604         log_err("unsupported Prophet header code %x",hdr->code);
00605         return false;
00606     }
00607 
00608     if (ntohs(hdr->length) != buflen)
00609     {
00610         log_err("badly formatted Prophet header");
00611         return false;
00612     }
00613 
00614     result_            = (Prophet::header_result_t) hdr->result;
00615     sender_instance_   = ntohs(hdr->sender_instance);
00616     receiver_instance_ = ntohs(hdr->receiver_instance);
00617     tid_               = ntohl(hdr->transaction_id);
00618     bool submessage_flag = (hdr->submessage_flag == 0x1);
00619     u_int16_t submessage_num = ntohs(hdr->submessage_num);
00620 
00621     if (submessage_flag == true || submessage_num != 0) {
00622         // log something ... Prophet fragmentation is unsupported
00623         return false;
00624     }
00625 
00626     // move past header
00627     size_t hdrsz = Prophet::ProphetHeaderSize;
00628     parsedlen_ = hdrsz;
00629     u_char* p = bp + hdrsz;
00630 
00631     // now peel off however many TLV's
00632     Prophet::prophet_tlv_t typecode = Prophet::UNKNOWN_TLV;
00633     size_t len = buflen - hdrsz;
00634     BaseTLV* tlv = NULL;
00635 
00636     while (len > 0) {
00637         typecode = (Prophet::prophet_tlv_t)*p;
00638         switch (typecode) {
00639             case Prophet::HELLO_TLV:
00640                 tlv = TLVFactory<HelloTLV>::deserialize(p,len,logpath_);
00641                 break;
00642             case Prophet::RIBD_TLV:
00643                 tlv = TLVFactory<RIBDTLV>::deserialize(p,len,logpath_);
00644                 break;
00645             case Prophet::RIB_TLV:
00646                 tlv = TLVFactory<RIBTLV>::deserialize(p,len,logpath_);
00647                 break;
00648             case Prophet::BUNDLE_TLV:
00649                 tlv = TLVFactory<BundleTLV>::deserialize(p,len,logpath_);
00650                 break;
00651             default:
00652                 break;
00653         }
00654         if (tlv == NULL)
00655             break;
00656         // increments parsedlen_ by tlv->length()
00657         add_tlv(tlv);
00658         // move pointer forward by appropriate length
00659         p += tlv->length();
00660         len -= tlv->length();
00661     }
00662 
00663     return (parsedlen_ == buflen);
00664 }
00665 
00666 bool
00667 ProphetTLV::create_bundle(Bundle* b,
00668                           const EndpointID& local, 
00669                           const EndpointID& remote) const
00670 {
00671     // set up the ScratchBuffer
00672     oasys::ScratchBuffer<u_char*> buf(parsedlen_);
00673 
00674     u_char* bp = buf.buf(parsedlen_);
00675     if (serialize(bp,parsedlen_) != parsedlen_) {
00676         return false;
00677     }
00678 
00679     ASSERT (b != NULL);
00680 
00681     EndpointID src(local), dest(remote);
00682     src.append_service_tag("prophet");
00683     dest.append_service_tag("prophet");
00684 
00685     b->source_.assign(src);
00686     b->dest_.assign(dest);
00687     b->replyto_.assign(EndpointID::NULL_EID());
00688     b->custodian_.assign(EndpointID::NULL_EID());
00689     b->expiration_ = 3600;
00690 
00691     b->payload_.set_data(bp,parsedlen_);
00692 
00693     return true;
00694 }
00695 
00696 size_t
00697 ProphetTLV::serialize(u_char* bp, size_t len) const
00698 {
00699     size_t hdr_sz = Prophet::ProphetHeaderSize;
00700     size_t buflen = hdr_sz;
00701 
00702     if (len < parsedlen_) {
00703         // log something
00704         return 0;
00705     }
00706 
00707     // skip past the header, for now
00708     u_char* p = bp + hdr_sz;
00709     len -= hdr_sz;
00710 
00711     // iterate over the TLVs and serialize each one to the buffer
00712     for(const_iterator ti = (const_iterator) list_.begin();
00713         ti != (const_iterator) list_.end() && len > 0;
00714         ti++)
00715     {
00716         BaseTLV* tlv = *ti;
00717         size_t tlvsize = tlv->serialize(p, len);
00718         if (tlvsize != tlv->length())
00719             break;
00720         buflen += tlvsize;
00721         len -= tlvsize;
00722         p += tlvsize;
00723     }
00724 
00725     // if all were successful, the math should line up
00726     if(parsedlen_ != buflen) {
00727         // log something
00728         return 0;
00729     }
00730 
00731     // now write out the Prophet header
00732     Prophet::ProphetHeader* hdr = (Prophet::ProphetHeader*) bp;
00733     memset(hdr,0,hdr_sz);
00734     hdr->version           = Prophet::PROPHET_VERSION;
00735     hdr->flags             = 0; // TBD
00736     hdr->result            = result_;
00737     hdr->code              = 0; // TBD
00738     hdr->sender_instance   = htons(sender_instance_);
00739     hdr->receiver_instance = htons(receiver_instance_);
00740     hdr->transaction_id    = htonl(tid_);
00741     hdr->length            = htons(parsedlen_);
00742 
00743     return parsedlen_;
00744 }
00745 
00746 size_t
00747 HelloTLV::serialize(u_char* bp, size_t len)
00748 {
00749     size_t eidsz = sender_.length();
00750     size_t hdrsz = Prophet::HelloTLVHeaderSize;
00751 
00752     // align to four-byte boundary
00753     size_t hello_sz = FOUR_BYTE_ALIGN(hdrsz + eidsz);
00754 
00755     // not enough buffer space to serialize into
00756     if (len < hello_sz) 
00757         return 0;
00758 
00759     length_ = hello_sz;
00760 
00761     Prophet::HelloTLVHeader *hdr = (Prophet::HelloTLVHeader*) bp;
00762     // baseline the header to zero
00763     memset(bp,0,length_);
00764     hdr->type = typecode_;
00765     hdr->HF = hf_;
00766     hdr->length = htons(length_);
00767     hdr->timer = timer_;
00768     // mask out one-byte value
00769     hdr->name_length = eidsz & 0xff;
00770     
00771     size_t buflen = hello_sz;
00772     memcpy(&hdr->sender_name[0],sender_.c_str(),eidsz);
00773 
00774     // zero out slack in packet
00775     while(buflen-- > hdrsz + eidsz)
00776         bp[buflen] = '\0';
00777 
00778     return hello_sz;
00779 }
00780 
00781 size_t
00782 RIBDTLV::write_ras_entry(u_int16_t sid,
00783                          EndpointID eid,
00784                          u_char* buffer,
00785                          size_t len)
00786 {
00787     size_t ras_sz = Prophet::RoutingAddressStringSize;
00788     if (len <= ras_sz)
00789         return 0;
00790 
00791     // baseline to zero
00792     memset(buffer,0,ras_sz);
00793 
00794     Prophet::RoutingAddressString* ras =
00795         (Prophet::RoutingAddressString*) buffer;
00796 
00797     ASSERT(eid.equals(EndpointID::NULL_EID())==false);
00798     size_t retval = ras_sz;
00799     ras->string_id = htons(sid);
00800     ras->length = eid.length() & 0xff;
00801     // must be even multiple of 4
00802     size_t copylen = FOUR_BYTE_ALIGN(ras->length);
00803     if (len - retval >= copylen) {
00804         memcpy(&ras->ra_string[0],eid.c_str(),ras->length);
00805         retval += copylen;
00806         // zero out slack
00807         while (--copylen > ras->length)
00808             ras->ra_string[copylen] = 0;
00809     }
00810 
00811     log_debug("write_ras_entry: wrote %zu bytes to %zu byte buffer",
00812               retval,len);
00813     return retval;
00814 }
00815 
00816 size_t
00817 RIBDTLV::serialize(u_char* bp, size_t len)
00818 {
00819     // estimate size of RIBD
00820     size_t ribd_sz = ribd_.guess_ribd_size();
00821     size_t hdrsz = Prophet::RIBDTLVHeaderSize;
00822     if ( len < ribd_sz + hdrsz) {
00823         log_err("serialize buffer length too short - needed > %zu, got %zu",
00824                 ribd_sz + hdrsz,len);
00825         return 0;
00826     }
00827 
00828     Prophet::RIBDTLVHeader* hdr = (Prophet::RIBDTLVHeader*) bp;
00829     size_t ribd_entry_count = 0;
00830     length_ = 0;
00831 
00832     // baseline the header to zero
00833     memset(hdr,0,hdrsz);
00834 
00835     // advance buffer pointer past the header
00836     bp += hdrsz;
00837     length_ += hdrsz;
00838 
00839     // iterate over ProphetDictionary
00840     for (ProphetDictionary::const_iterator it = ribd_.begin();
00841          it != ribd_.end();
00842          it++) {
00843 
00844         if ((*it).first == 0 || (*it).first == 1)
00845             continue; // local and remote are implied as 0, 1
00846 
00847         size_t bytes_written = 0;
00848         // serialize node out to buffer
00849         if ((bytes_written=write_ras_entry((*it).first,
00850                                            (*it).second,
00851                                            bp,len)) == 0)
00852             break;
00853 
00854         bp      += bytes_written;
00855         len     -= bytes_written;
00856         length_ += bytes_written;
00857 
00858         ribd_entry_count++;
00859     }
00860 
00861     // Now that sizes are known, fill in the header
00862     hdr->type = Prophet::RIBD_TLV;
00863     hdr->flags = 0;
00864     hdr->length = htons(length_);
00865     hdr->entry_count = htons(ribd_entry_count);
00866 
00867     log_debug("serialize wrote %zu of %zu RAS entries for a total %d bytes",
00868               ribd_entry_count,ribd_.size(),length_);
00869     return length_;
00870 }
00871 
00872 size_t
00873 RIBTLV::write_rib_entry(u_int16_t sid, double pvalue,
00874                         bool relay, bool custody, bool internet,
00875                         u_char* buffer, size_t len)
00876 {
00877     size_t rib_sz = Prophet::RIBEntrySize;
00878     if (len < rib_sz)
00879         return 0;
00880 
00881     // baseline to zero
00882     memset(buffer,0,rib_sz);
00883 
00884     Prophet::RIBEntry* rib = (Prophet::RIBEntry*) buffer;
00885 
00886     rib->string_id = htons(sid);
00887     rib->pvalue = (u_int8_t) ( (int) (pvalue * (256.0)) ) & 0xff;
00888     rib->flags = 0;
00889     if (relay)    rib->flags |= Prophet::RELAY_NODE;
00890     if (custody)  rib->flags |= Prophet::CUSTODY_NODE;
00891     if (internet) rib->flags |= Prophet::INTERNET_GW_NODE;
00892     log_debug("write_rib_entry: wrote %zu bytes to %zu byte buffer",
00893               rib_sz,len);
00894     return rib_sz;
00895 }
00896 
00897 size_t
00898 RIBTLV::serialize(u_char* bp, size_t len)
00899 {
00900     size_t hdrsz = Prophet::RIBTLVHeaderSize;
00901     size_t rib_entry_count = nodes_.size();
00902     length_ = hdrsz + rib_entry_count * Prophet::RIBEntrySize;
00903 
00904     // buffer must be large enough to contain header + all RIB entries
00905     if ( len < length_ ) {
00906         log_err("serialize buffer length too short - needed %d got %zu",
00907                 length_,len);
00908         return 0;
00909     }
00910 
00911     Prophet::RIBTLVHeader* hdr = (Prophet::RIBTLVHeader*) bp;
00912 
00913     // just guesses; zero out and calculate actual values
00914     length_ = 0;
00915     rib_entry_count = 0;
00916 
00917     // move buffer pointer past the header; encode each entry
00918     bp += hdrsz;
00919     length_ += hdrsz;
00920 
00921     RIBNode *node = NULL;
00922 
00923     for(iterator it = nodes_.begin(); 
00924         it != nodes_.end();
00925         it++) {
00926 
00927         node = (*it);
00928 
00929         size_t bytes_written = 0;
00930         if ((bytes_written=write_rib_entry(node->sid_,
00931                                            node->p_value(),
00932                                            node->relay(),
00933                                            node->custody(),
00934                                            node->internet_gw(),
00935                                            bp,
00936                                            len)) == 0) {
00937             break;
00938         }
00939 
00940         bp      += bytes_written;
00941         len     -= bytes_written;
00942         length_ += bytes_written;
00943 
00944         rib_entry_count++;
00945 
00946         node = NULL;
00947     }
00948 
00949     // fill out the header
00950     hdr->type = typecode_;
00951     hdr->length = htons(length_);
00952     hdr->rib_string_count = htons(rib_entry_count);
00953     hdr->flags = 0;
00954 
00955     if (relay_)    hdr->flags |= Prophet::RELAY_NODE;
00956     if (custody_)  hdr->flags |= Prophet::CUSTODY_NODE;
00957     if (internet_) hdr->flags |= Prophet::INTERNET_GW_NODE;
00958 
00959     return length_;
00960 }
00961 
00962 size_t
00963 BundleTLV::write_bundle_offer(u_int32_t cts, u_int16_t sid,
00964                               bool custody, bool accept, bool ack,
00965                               BundleOffer::bundle_offer_t type,
00966                               u_char* bp, size_t len)
00967 {
00968     size_t boe_sz = Prophet::BundleOfferEntrySize;
00969     if (len < boe_sz) {
00970         log_debug("not enough buffer to write out Bundle entry, "
00971                   "needed %zu but got %zu",boe_sz,len);
00972         return 0;
00973     }
00974     Prophet::BundleOfferEntry* p = (Prophet::BundleOfferEntry*) bp;
00975     memset(p,0,boe_sz);
00976     if (type == BundleOffer::OFFER) {
00977         if (custody)
00978             p->b_flags |= Prophet::CUSTODY_OFFERED;
00979         if (ack)
00980             p->b_flags |= Prophet::PROPHET_ACK;
00981     }
00982     else
00983     if (type == BundleOffer::RESPONSE) {
00984         if (custody)
00985             p->b_flags |= Prophet::CUSTODY_ACCEPTED;
00986         if (accept)
00987             p->b_flags |= Prophet::BUNDLE_ACCEPTED;
00988     }
00989     else 
00990     {
00991         log_debug("Bundle entry with undefined type (%d), skipping",
00992                   (int)type);
00993         return 0;
00994     }
00995     p->dest_string_id = htons(sid);
00996     p->creation_timestamp = htonl(cts);
00997     return boe_sz;
00998 }
00999 
01000 size_t
01001 BundleTLV::serialize(u_char* bp, size_t len)
01002 {
01003     // estimate output size
01004     size_t tlv_size = Prophet::BundleOfferTLVHeaderSize +
01005                       list_.guess_size();
01006     length_ = 0;
01007 
01008     // all or nothing
01009     if(len < tlv_size)
01010         return 0;
01011 
01012     // fill in the header
01013     Prophet::BundleOfferTLVHeader* hdr =
01014         (Prophet::BundleOfferTLVHeader*) bp;
01015     memset(hdr,0,Prophet::BundleOfferTLVHeaderSize);
01016     hdr->type = Prophet::BUNDLE_TLV;
01017     hdr->flags = 0; // TBD
01018     hdr->offer_count = htons(list_.size());
01019 
01020     length_ += Prophet::BundleOfferTLVHeaderSize;
01021     bp += Prophet::BundleOfferTLVHeaderSize;
01022     len -= Prophet::BundleOfferTLVHeaderSize;
01023 
01024     // iterate over the bundle offer and serialize the offer entries
01025     oasys::ScopeLock l(list_.lock(),"BundleTLV::serialize");
01026     BundleOfferList::iterator i = list_.begin();
01027     while (i != list_.end()) {
01028         BundleOffer* bo = *i;
01029 
01030         size_t boe_sz = write_bundle_offer(bo->creation_ts(),bo->sid(),
01031                             bo->custody(),bo->accept(),bo->ack(),
01032                             bo->type(),bp,len);
01033 
01034         if (boe_sz == 0)
01035             break;
01036 
01037         length_ += boe_sz;
01038         bp += boe_sz;
01039         len -= boe_sz;
01040         i++;
01041     }
01042 
01043     hdr->length = htons(length_);
01044     return length_; 
01045 }
01046 
01047 } // namespace dtn

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