|
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 |