servlib/prophet/RIBDTLV.cc
changeset 0 2b3e5ec03512
equal deleted inserted replaced
-1:000000000000 0:2b3e5ec03512
       
     1 /*
       
     2  *    Copyright 2007 Baylor University
       
     3  *
       
     4  *    Licensed under the Apache License, Version 2.0 (the "License");
       
     5  *    you may not use this file except in compliance with the License.
       
     6  *    You may obtain a copy of the License at
       
     7  *
       
     8  *        http://www.apache.org/licenses/LICENSE-2.0
       
     9  *
       
    10  *    Unless required by applicable law or agreed to in writing, software
       
    11  *    distributed under the License is distributed on an "AS IS" BASIS,
       
    12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    13  *    See the License for the specific language governing permissions and
       
    14  *    limitations under the License.
       
    15  */
       
    16 
       
    17 #include <arpa/inet.h> // for hton[ls] and ntoh[ls]
       
    18 #include "Util.h"
       
    19 #include "RIBDTLV.h"
       
    20 
       
    21 namespace prophet
       
    22 {
       
    23 
       
    24 RIBDTLV::RIBDTLV(const Dictionary& ribd)
       
    25     : BaseTLV(BaseTLV::RIBD_TLV), ribd_(ribd)
       
    26 {
       
    27     length_  = RIBDTLVHeaderSize;
       
    28     length_ += ribd_.guess_ribd_size(RoutingAddressStringSize);
       
    29 }
       
    30 
       
    31 RIBDTLV::RIBDTLV()
       
    32     : BaseTLV(BaseTLV::RIBD_TLV) {}
       
    33 
       
    34 size_t
       
    35 RIBDTLV::write_ras_entry(u_int16_t sid,
       
    36                          const std::string& dest_id,
       
    37                          u_char* bp, size_t len) const
       
    38 {
       
    39     // weed out the oddball
       
    40     if (bp == NULL) return 0;
       
    41 
       
    42     // align length of dest_id to 4 byte boundary
       
    43     size_t copylen = FOUR_BYTE_ALIGN(dest_id.length());
       
    44 
       
    45     // make sure the lengths match up with the provided buffer
       
    46     if (RoutingAddressStringSize + copylen > len) return 0;
       
    47 
       
    48     // initialize to sizeof overhead
       
    49     size_t retval = RoutingAddressStringSize;
       
    50 
       
    51     // start writing out to buffer
       
    52     RoutingAddressString* ras = (RoutingAddressString*) bp;
       
    53     ras->string_id = htons(sid);
       
    54     ras->length    = dest_id.length() & 0xff;
       
    55     memcpy(&ras->ra_string[0],dest_id.c_str(),dest_id.length());
       
    56     retval += copylen; // 32-bit alignment
       
    57 
       
    58     // zero out slack, if any
       
    59     while (copylen-- > ras->length)
       
    60         ras->ra_string[copylen] = '\0';
       
    61 
       
    62     return retval;
       
    63 }
       
    64 
       
    65 size_t
       
    66 RIBDTLV::serialize(u_char* bp, size_t len) const
       
    67 {
       
    68     // weed out the oddball
       
    69     if (bp == NULL) return 0;
       
    70     if (typecode_ != BaseTLV::RIBD_TLV) return 0;
       
    71 
       
    72     // estimate final size of TLV, check length of inbound buffer
       
    73     size_t ribd_sz = ribd_.guess_ribd_size(RoutingAddressStringSize);
       
    74     if (ribd_sz + RIBDTLVHeaderSize > len) return 0;
       
    75 
       
    76     // initialize accounting
       
    77     size_t ribd_entry_count = 0;
       
    78     length_ = 0;
       
    79     RIBDTLVHeader* hdr = (RIBDTLVHeader*) bp;
       
    80     memset(hdr,0,RIBDTLVHeaderSize);
       
    81 
       
    82     // write out to buffer, skipping header (for now)
       
    83     bp += RIBDTLVHeaderSize;
       
    84     length_ += RIBDTLVHeaderSize;
       
    85 
       
    86     // write out individual RIBD entries 
       
    87     for (Dictionary::const_iterator i = ribd_.begin(); i != ribd_.end(); i++)
       
    88     {
       
    89         // shouldn't happen, but test anyways
       
    90         if ((*i).first < 2)
       
    91             continue; // local and remote peers are implied as 0 and 1
       
    92 
       
    93         size_t bytes_written = 0;
       
    94         if ((bytes_written =
       
    95                     write_ras_entry((*i).first,(*i).second,bp,len)) == 0)
       
    96             break;
       
    97 
       
    98         bp      += bytes_written;
       
    99         len     -= bytes_written;
       
   100         length_ += bytes_written;
       
   101 
       
   102         ribd_entry_count++;
       
   103     }
       
   104 
       
   105     // fill in header for amounts successfully written 
       
   106     hdr->type        = BaseTLV::RIBD_TLV;
       
   107     hdr->flags       = 0;
       
   108     hdr->length      = htons(length_);
       
   109     hdr->entry_count = htons(ribd_entry_count);
       
   110 
       
   111     return length_;
       
   112 }
       
   113 
       
   114 size_t
       
   115 RIBDTLV::read_ras_entry(u_int16_t* sid,
       
   116                         std::string& dest_id,
       
   117                         const u_char* bp, size_t len)
       
   118 {
       
   119     // weed out the oddball
       
   120     if (sid == NULL || bp == NULL) return 0;
       
   121 
       
   122     // reject too-tight bounds
       
   123     if (RoutingAddressStringSize > len) return 0;
       
   124 
       
   125     RoutingAddressString* ras = (RoutingAddressString*) bp;
       
   126 
       
   127     // initialize to sizeof overhead
       
   128     size_t retval = RoutingAddressStringSize;
       
   129 
       
   130     // must be even multiple of 4 bytes
       
   131     size_t copylen = FOUR_BYTE_ALIGN(ras->length);
       
   132 
       
   133     // make sure the lengths match up
       
   134     if (copylen > len - retval) return retval;
       
   135 
       
   136     // read into memory
       
   137     *sid = ntohs(ras->string_id); 
       
   138     dest_id.assign((char*)&ras->ra_string[0],ras->length);
       
   139 
       
   140     // count what we read
       
   141     retval += copylen;
       
   142 
       
   143     return retval;
       
   144 }
       
   145 
       
   146 bool
       
   147 RIBDTLV::deserialize(const u_char* bp, size_t len)
       
   148 {
       
   149     RIBDTLVHeader* hdr = (RIBDTLVHeader*) bp;
       
   150 
       
   151     // weed out the oddball
       
   152     if (bp == NULL) return false;
       
   153 
       
   154     // Enforce typecode expectation
       
   155     if (hdr->type != RIBD_TLV) return false;
       
   156 
       
   157     // Inbound buffer must be at least as big as the overhead
       
   158     if (len < RIBDTLVHeaderSize) return false;
       
   159 
       
   160     // Fail out if lengths don't match up
       
   161     length_ = ntohs(hdr->length);
       
   162     if (len < length_) return false;
       
   163 
       
   164     flags_  = hdr->flags;
       
   165 
       
   166     size_t ribd_entry_count = ntohs(hdr->entry_count);
       
   167 
       
   168     // Now that the header is parsed, move past to the first RIBD entry
       
   169     bp += RIBDTLVHeaderSize;
       
   170 
       
   171     size_t amt_read = RIBDTLVHeaderSize;
       
   172     len -= RIBDTLVHeaderSize;
       
   173 
       
   174     u_int16_t sid;
       
   175     std::string dest_id;
       
   176     ribd_.clear();
       
   177     while (ribd_entry_count-- > 0)
       
   178     {
       
   179         // deserialize RAS from buffer
       
   180         size_t bytes_read = read_ras_entry(&sid,dest_id,bp,len);
       
   181 
       
   182         // abort on error
       
   183         if (bytes_read == 0) break;
       
   184 
       
   185         // store this dictionary entry
       
   186         if(ribd_.assign(dest_id,sid) == false) break;
       
   187 
       
   188         len      -= bytes_read;
       
   189         bp       += bytes_read;
       
   190         amt_read += bytes_read;
       
   191     }
       
   192 
       
   193     return (amt_read == length_);
       
   194 }
       
   195 
       
   196 const Dictionary&
       
   197 RIBDTLV::ribd(const std::string& sender, const std::string& receiver)
       
   198 {
       
   199     ribd_.assign(sender,0);
       
   200     ribd_.assign(receiver,1);
       
   201     return ribd_;
       
   202 }
       
   203 
       
   204 }; // namespace prophet