diff -r 000000000000 -r 2b3e5ec03512 servlib/prophet/RIBDTLV.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlib/prophet/RIBDTLV.cc Thu Apr 21 14:57:45 2011 +0100 @@ -0,0 +1,204 @@ +/* + * Copyright 2007 Baylor University + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include // for hton[ls] and ntoh[ls] +#include "Util.h" +#include "RIBDTLV.h" + +namespace prophet +{ + +RIBDTLV::RIBDTLV(const Dictionary& ribd) + : BaseTLV(BaseTLV::RIBD_TLV), ribd_(ribd) +{ + length_ = RIBDTLVHeaderSize; + length_ += ribd_.guess_ribd_size(RoutingAddressStringSize); +} + +RIBDTLV::RIBDTLV() + : BaseTLV(BaseTLV::RIBD_TLV) {} + +size_t +RIBDTLV::write_ras_entry(u_int16_t sid, + const std::string& dest_id, + u_char* bp, size_t len) const +{ + // weed out the oddball + if (bp == NULL) return 0; + + // align length of dest_id to 4 byte boundary + size_t copylen = FOUR_BYTE_ALIGN(dest_id.length()); + + // make sure the lengths match up with the provided buffer + if (RoutingAddressStringSize + copylen > len) return 0; + + // initialize to sizeof overhead + size_t retval = RoutingAddressStringSize; + + // start writing out to buffer + RoutingAddressString* ras = (RoutingAddressString*) bp; + ras->string_id = htons(sid); + ras->length = dest_id.length() & 0xff; + memcpy(&ras->ra_string[0],dest_id.c_str(),dest_id.length()); + retval += copylen; // 32-bit alignment + + // zero out slack, if any + while (copylen-- > ras->length) + ras->ra_string[copylen] = '\0'; + + return retval; +} + +size_t +RIBDTLV::serialize(u_char* bp, size_t len) const +{ + // weed out the oddball + if (bp == NULL) return 0; + if (typecode_ != BaseTLV::RIBD_TLV) return 0; + + // estimate final size of TLV, check length of inbound buffer + size_t ribd_sz = ribd_.guess_ribd_size(RoutingAddressStringSize); + if (ribd_sz + RIBDTLVHeaderSize > len) return 0; + + // initialize accounting + size_t ribd_entry_count = 0; + length_ = 0; + RIBDTLVHeader* hdr = (RIBDTLVHeader*) bp; + memset(hdr,0,RIBDTLVHeaderSize); + + // write out to buffer, skipping header (for now) + bp += RIBDTLVHeaderSize; + length_ += RIBDTLVHeaderSize; + + // write out individual RIBD entries + for (Dictionary::const_iterator i = ribd_.begin(); i != ribd_.end(); i++) + { + // shouldn't happen, but test anyways + if ((*i).first < 2) + continue; // local and remote peers are implied as 0 and 1 + + size_t bytes_written = 0; + if ((bytes_written = + write_ras_entry((*i).first,(*i).second,bp,len)) == 0) + break; + + bp += bytes_written; + len -= bytes_written; + length_ += bytes_written; + + ribd_entry_count++; + } + + // fill in header for amounts successfully written + hdr->type = BaseTLV::RIBD_TLV; + hdr->flags = 0; + hdr->length = htons(length_); + hdr->entry_count = htons(ribd_entry_count); + + return length_; +} + +size_t +RIBDTLV::read_ras_entry(u_int16_t* sid, + std::string& dest_id, + const u_char* bp, size_t len) +{ + // weed out the oddball + if (sid == NULL || bp == NULL) return 0; + + // reject too-tight bounds + if (RoutingAddressStringSize > len) return 0; + + RoutingAddressString* ras = (RoutingAddressString*) bp; + + // initialize to sizeof overhead + size_t retval = RoutingAddressStringSize; + + // must be even multiple of 4 bytes + size_t copylen = FOUR_BYTE_ALIGN(ras->length); + + // make sure the lengths match up + if (copylen > len - retval) return retval; + + // read into memory + *sid = ntohs(ras->string_id); + dest_id.assign((char*)&ras->ra_string[0],ras->length); + + // count what we read + retval += copylen; + + return retval; +} + +bool +RIBDTLV::deserialize(const u_char* bp, size_t len) +{ + RIBDTLVHeader* hdr = (RIBDTLVHeader*) bp; + + // weed out the oddball + if (bp == NULL) return false; + + // Enforce typecode expectation + if (hdr->type != RIBD_TLV) return false; + + // Inbound buffer must be at least as big as the overhead + if (len < RIBDTLVHeaderSize) return false; + + // Fail out if lengths don't match up + length_ = ntohs(hdr->length); + if (len < length_) return false; + + flags_ = hdr->flags; + + size_t ribd_entry_count = ntohs(hdr->entry_count); + + // Now that the header is parsed, move past to the first RIBD entry + bp += RIBDTLVHeaderSize; + + size_t amt_read = RIBDTLVHeaderSize; + len -= RIBDTLVHeaderSize; + + u_int16_t sid; + std::string dest_id; + ribd_.clear(); + while (ribd_entry_count-- > 0) + { + // deserialize RAS from buffer + size_t bytes_read = read_ras_entry(&sid,dest_id,bp,len); + + // abort on error + if (bytes_read == 0) break; + + // store this dictionary entry + if(ribd_.assign(dest_id,sid) == false) break; + + len -= bytes_read; + bp += bytes_read; + amt_read += bytes_read; + } + + return (amt_read == length_); +} + +const Dictionary& +RIBDTLV::ribd(const std::string& sender, const std::string& receiver) +{ + ribd_.assign(sender,0); + ribd_.assign(receiver,1); + return ribd_; +} + +}; // namespace prophet