servlib/prophet/ProphetTLV.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 
       
    19 #include "ProphetTLV.h"
       
    20 #include "HelloTLV.h"
       
    21 #include "RIBDTLV.h"
       
    22 #include "RIBTLV.h"
       
    23 #include "OfferTLV.h"
       
    24 #include "ResponseTLV.h"
       
    25 #include "Params.h"
       
    26 
       
    27 namespace prophet
       
    28 {
       
    29 
       
    30 ProphetTLV::ProphetTLV()
       
    31     : result_(UnknownResult), sender_instance_(0), receiver_instance_(0),
       
    32       tid_(0), length_(ProphetHeaderSize)
       
    33 {
       
    34 }
       
    35 
       
    36 ProphetTLV::ProphetTLV(const std::string& src, const std::string& dst, 
       
    37                        header_result_t result, u_int16_t local_instance,
       
    38                        u_int16_t remote_instance, u_int32_t tid)
       
    39     : src_(src), dst_(dst), result_(result),
       
    40       sender_instance_(local_instance), 
       
    41       receiver_instance_(remote_instance), tid_(tid),
       
    42       length_(ProphetHeaderSize)
       
    43 {
       
    44 }
       
    45 
       
    46 ProphetTLV::ProphetTLV(const ProphetTLV& p)
       
    47     : src_(p.src_), dst_(p.dst_), result_(p.result_),
       
    48       sender_instance_(p.sender_instance_),
       
    49       receiver_instance_(p.receiver_instance_),
       
    50       tid_(p.tid_), length_(p.length_)
       
    51 {
       
    52     list_.assign(p.list_.begin(),p.list_.end());
       
    53 }
       
    54 
       
    55 ProphetTLV::~ProphetTLV()
       
    56 {
       
    57     for (iterator i = list_.begin(); i != list_.end(); i++)
       
    58         delete *i;
       
    59 }
       
    60 
       
    61 size_t
       
    62 ProphetTLV::serialize(u_char* bp, size_t len) const
       
    63 {
       
    64     // weed out the oddball
       
    65     if (bp == NULL) return 0;
       
    66 
       
    67     // check that lengths match up
       
    68     if (ProphetHeaderSize > len) return 0;
       
    69 
       
    70     // initialize some accounting
       
    71     length_ = 0;
       
    72 
       
    73     // save pointer to header
       
    74     ProphetHeader* hdr = (ProphetHeader*) bp;
       
    75     memset(hdr,0,ProphetHeaderSize);
       
    76 
       
    77     // skip past header for now
       
    78     bp += ProphetHeaderSize;
       
    79 
       
    80     // write out each TLV to buffer
       
    81     for (const_iterator i = list_.begin(); i != list_.end(); i++)
       
    82     {
       
    83         BaseTLV* tlv = *i;
       
    84         size_t bytes_written = tlv->serialize(bp,len);
       
    85         if (bytes_written != tlv->length())
       
    86             break;
       
    87 
       
    88         length_ += bytes_written;
       
    89         len     -= bytes_written;
       
    90         bp      += bytes_written;
       
    91     }
       
    92 
       
    93     // if all went well, the math should line up
       
    94     if (ProphetHeaderSize > len) return 0;
       
    95 
       
    96     // now write out the header
       
    97     length_ += ProphetHeaderSize;
       
    98     len     -= ProphetHeaderSize;
       
    99 
       
   100     hdr->version           = ProphetParams::PROPHET_VERSION;
       
   101     hdr->flags             = 0;
       
   102     hdr->result            = result_;
       
   103     hdr->code              = 0;
       
   104     hdr->sender_instance   = htons(sender_instance_);
       
   105     hdr->receiver_instance = htons(receiver_instance_);
       
   106     hdr->transaction_id    = htonl(tid_);
       
   107     hdr->length            = htons(length_);
       
   108 
       
   109     return length_;
       
   110 }
       
   111 
       
   112 ProphetTLV*
       
   113 ProphetTLV::deserialize(const std::string& src,
       
   114                         const std::string& dst,
       
   115                         const u_char* bp, size_t len)
       
   116 {
       
   117     // weed out the oddball
       
   118     if (bp == NULL) return NULL;
       
   119 
       
   120     // check that lengths match up
       
   121     if (ProphetHeaderSize > len) return NULL;
       
   122 
       
   123     // start reading and validating header from buffer
       
   124     ProphetHeader* hdr = (ProphetHeader*) bp; 
       
   125     if (hdr->version != ProphetParams::PROPHET_VERSION) return NULL;
       
   126     if (hdr->flags != 0) return NULL;
       
   127     if (hdr->code != 0) return NULL;
       
   128     if (static_cast<size_t>(ntohs(hdr->length)) > len) return NULL;
       
   129 
       
   130     // Create object and begin copying in from buffer
       
   131     ProphetTLV* p = new ProphetTLV();
       
   132     p->src_               = src;
       
   133     p->dst_               = dst;
       
   134     p->result_            = (header_result_t) hdr->result;
       
   135     p->sender_instance_   = ntohs(hdr->sender_instance);
       
   136     p->receiver_instance_ = ntohs(hdr->receiver_instance);
       
   137     p->tid_               = ntohl(hdr->transaction_id);
       
   138     bool submessage_flag = (hdr->submessage_flag == 0x1);
       
   139     u_int16_t submessage_num = ntohs(hdr->submessage_num);
       
   140 
       
   141     // prophet tlv fragmentation is not supported by this implementation
       
   142     if (submessage_flag == true || submessage_num != 0)
       
   143     {
       
   144         delete p;
       
   145         return NULL;
       
   146     }
       
   147 
       
   148     // move past header
       
   149     p->length_  = ProphetHeaderSize;
       
   150     len        -= ProphetHeaderSize;
       
   151     bp         += ProphetHeaderSize;
       
   152 
       
   153     // begin reading TLVs in from buffer
       
   154     BaseTLV::prophet_tlv_t typecode = BaseTLV::UNKNOWN_TLV;
       
   155     BaseTLV* tlv = NULL;
       
   156     while (len > 0)
       
   157     {
       
   158         typecode = (BaseTLV::prophet_tlv_t)*bp;
       
   159         switch (typecode)
       
   160         {
       
   161             case BaseTLV::HELLO_TLV:
       
   162                 tlv = TLVFactory<HelloTLV>::deserialize(bp,len);
       
   163                 break;
       
   164             case BaseTLV::RIBD_TLV:
       
   165                 tlv = TLVFactory<RIBDTLV>::deserialize(bp,len);
       
   166                 break;
       
   167             case BaseTLV::RIB_TLV:
       
   168                 tlv = TLVFactory<RIBTLV>::deserialize(bp,len);
       
   169                 break;
       
   170             case BaseTLV::OFFER_TLV:
       
   171                 tlv = TLVFactory<OfferTLV>::deserialize(bp,len);
       
   172                 break;
       
   173             case BaseTLV::RESPONSE_TLV:
       
   174                 tlv = TLVFactory<ResponseTLV>::deserialize(bp,len);
       
   175                 break;
       
   176             default:
       
   177                 tlv = NULL;
       
   178                 break;
       
   179         }
       
   180         if (tlv == NULL) break;
       
   181         // increments length_ by tlv->length()
       
   182         p->add_tlv(tlv);
       
   183         // move pointer past the parsed TLV
       
   184         bp  += tlv->length();
       
   185         len -= tlv->length();
       
   186     }
       
   187     return p;
       
   188 }
       
   189 
       
   190 BaseTLV*
       
   191 ProphetTLV::get_tlv()
       
   192 {
       
   193     if (list_.empty())
       
   194         return NULL;
       
   195     BaseTLV* t = list_.front();
       
   196     list_.pop_front();
       
   197     return t;
       
   198 }
       
   199 
       
   200 bool
       
   201 ProphetTLV::add_tlv(BaseTLV* tlv)
       
   202 {
       
   203     // weed out the oddball
       
   204     if (tlv == NULL) return false;
       
   205 
       
   206     length_ += tlv->length();
       
   207     list_.push_back(tlv);
       
   208     return true;
       
   209 }
       
   210 
       
   211 }; // namespace prophet