Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include <cassert>
6 : #include <cctype>
7 : #include <cstdio>
8 : #include <stdexcept>
9 : #include <boost/static_assert.hpp>
10 : #include <boost/algorithm/string/replace.hpp>
11 :
12 : #include <base/logging.h>
13 : #include <base/util.h>
14 : #include <base/string_util.h>
15 :
16 : #include "TXMLProtocol.h"
17 :
18 : using std::string;
19 :
20 : #ifdef TXMLPROTOCOL_DEBUG_PRETTY_PRINT
21 : static const string endl = "\n";
22 : #else
23 : static const string endl = "";
24 : #endif // !TXMLPROTOCOL_DEBUG_PRETTY_PRINT
25 :
26 : namespace contrail { namespace sandesh { namespace protocol {
27 :
28 : // Static data
29 :
30 : static const uint8_t kcXMLTagO = '<';
31 : static const uint8_t kcXMLTagC = '>';
32 : static const uint8_t kcXMLSlash = '/';
33 : static const uint8_t kcXMLSBracketC = ']';
34 :
35 : static const std::string kXMLTagO("<");
36 : static const std::string kXMLTagC(">");
37 : static const std::string kXMLSoloTagC("/>");
38 : static const std::string kXMLEndTagO("</");
39 : static const std::string kXMLSlash("/");
40 : static const std::string kXMLType("type");
41 : static const std::string kXMLIdentifier("identifier");
42 : static const std::string kXMLName("name");
43 : static const std::string kXMLKey("key");
44 : static const std::string kXMLElementTagO("<element>");
45 : static const std::string kXMLElementTagC("</element>");
46 : static const std::string kXMLValue("value");
47 : static const std::string kXMLSize("size");
48 : static const std::string kXMLBoolTrue("true");
49 : static const std::string kXMLBoolFalse("false");
50 : static const std::string kXMLCDATAO("<![CDATA[");
51 : static const std::string kXMLCDATAC("]]>");
52 :
53 : static const std::string kTypeNameBool("bool");
54 : static const std::string kTypeNameByte("byte");
55 : static const std::string kTypeNameI16("i16");
56 : static const std::string kTypeNameI32("i32");
57 : static const std::string kTypeNameI64("i64");
58 : static const std::string kTypeNameU16("u16");
59 : static const std::string kTypeNameU32("u32");
60 : static const std::string kTypeNameU64("u64");
61 : static const std::string kTypeNameIPV4("ipv4");
62 : static const std::string kTypeNameIPADDR("ipaddr");
63 : static const std::string kTypeNameDouble("double");
64 : static const std::string kTypeNameStruct("struct");
65 : static const std::string kTypeNameString("string");
66 : static const std::string kTypeNameXML("xml");
67 : static const std::string kTypeNameUUID("uuid_t");
68 : static const std::string kTypeNameMap("map");
69 : static const std::string kTypeNameList("list");
70 : static const std::string kTypeNameSet("set");
71 : static const std::string kTypeNameSandesh("sandesh");
72 : static const std::string kTypeNameUnknown("unknown");
73 :
74 : static const std::string kAttrTypeSandesh("type=\"sandesh\"");
75 : static const std::string kXMLListTagO("<list ");
76 : static const std::string kXMLListTagC("</list>" + endl);
77 : static const std::string kXMLSetTagO("<set ");
78 : static const std::string kXMLSetTagC("</set>" + endl);
79 : static const std::string kXMLMapTagO("<map ");
80 : static const std::string kXMLMapTagC("</map>" + endl);
81 :
82 341044 : const std::string& TXMLProtocol::fieldTypeName(TType type) {
83 341044 : switch (type) {
84 1987 : case T_BOOL : return kTypeNameBool ;
85 0 : case T_BYTE : return kTypeNameByte ;
86 0 : case T_I16 : return kTypeNameI16 ;
87 73579 : case T_I32 : return kTypeNameI32 ;
88 12894 : case T_I64 : return kTypeNameI64 ;
89 66 : case T_U16 : return kTypeNameU16 ;
90 3984 : case T_U32 : return kTypeNameU32 ;
91 68316 : case T_U64 : return kTypeNameU64 ;
92 0 : case T_IPV4 : return kTypeNameIPV4 ;
93 0 : case T_IPADDR : return kTypeNameIPADDR ;
94 403 : case T_DOUBLE : return kTypeNameDouble ;
95 160249 : case T_STRING : return kTypeNameString ;
96 15627 : case T_STRUCT : return kTypeNameStruct ;
97 436 : case T_MAP : return kTypeNameMap ;
98 0 : case T_SET : return kTypeNameSet ;
99 3503 : case T_LIST : return kTypeNameList ;
100 0 : case T_SANDESH: return kTypeNameSandesh;
101 0 : case T_XML : return kTypeNameXML ;
102 0 : case T_UUID : return kTypeNameUUID ;
103 0 : default: return kTypeNameUnknown;
104 : }
105 : }
106 :
107 2174 : TType TXMLProtocol::getTypeIDForTypeName(const std::string &name) {
108 2174 : TType result = T_STOP; // Sentinel value
109 2174 : if (name.length() > 1) {
110 2174 : switch (name[0]) {
111 85 : case 'b':
112 85 : switch (name[1]) {
113 85 : case 'o':
114 85 : result = T_BOOL;
115 85 : break;
116 0 : case 'y':
117 0 : result = T_BYTE;
118 0 : break;
119 : }
120 85 : break;
121 0 : case 'd':
122 0 : result = T_DOUBLE;
123 0 : break;
124 732 : case 'i':
125 732 : switch (name[1]) {
126 0 : case '1':
127 0 : result = T_I16;
128 0 : break;
129 610 : case '3':
130 610 : result = T_I32;
131 610 : break;
132 122 : case '6':
133 122 : result = T_I64;
134 122 : break;
135 0 : case 'p':
136 0 : switch (name[2]) {
137 0 : case 'a':
138 0 : result = T_IPADDR;
139 0 : break;
140 0 : case 'v':
141 0 : result = T_IPV4;
142 0 : break;
143 : }
144 0 : break;
145 : }
146 732 : break;
147 122 : case 'l':
148 122 : result = T_LIST;
149 122 : break;
150 0 : case 'm':
151 0 : result = T_MAP;
152 0 : break;
153 1124 : case 's':
154 1124 : switch (name[1]) {
155 0 : case 'a':
156 0 : result = T_SANDESH;
157 0 : break;
158 0 : case 'e':
159 0 : result = T_SET;
160 0 : break;
161 1124 : case 't':
162 1124 : switch (name[3]) {
163 1039 : case 'i':
164 1039 : result = T_STRING;
165 1039 : break;
166 85 : case 'u':
167 85 : result = T_STRUCT;
168 85 : break;
169 : }
170 1124 : break;
171 : }
172 1124 : break;
173 111 : case 'u':
174 111 : switch(name[1]) {
175 0 : case '1':
176 0 : result = T_U16;
177 0 : break;
178 111 : case '3':
179 111 : result = T_U32;
180 111 : break;
181 0 : case '6':
182 0 : result = T_U64;
183 0 : break;
184 0 : case 'u':
185 0 : result = T_UUID;
186 0 : break;
187 : }
188 111 : break;
189 0 : case 'x':
190 0 : result = T_XML;
191 0 : break;
192 : }
193 : }
194 2174 : if (result == T_STOP) {
195 0 : LOG(ERROR, __func__ << "Unrecognized type: " << name);
196 : }
197 2174 : return result;
198 : }
199 :
200 695838 : static inline void formXMLAttr(std::string &dest, const std::string& name,
201 : const std::string & value) {
202 695838 : dest += name;
203 695838 : dest += "=\"";
204 695838 : dest += value;
205 695837 : dest += "\"";
206 695837 : }
207 :
208 49840 : void TXMLProtocol::indentUp() {
209 : #if TXMLPROTOCOL_DEBUG_PRETTY_PRINT
210 : indent_str_ += string(indent_inc, ' ');
211 : #endif // !TXMLPROTOCOL_DEBUG_PRETTY_PRINT
212 49840 : }
213 :
214 64509 : void TXMLProtocol::indentDown() {
215 : #if TXMLPROTOCOL_DEBUG_PRETTY_PRINT
216 : if (indent_str_.length() < (string::size_type)indent_inc) {
217 : LOG(ERROR, __func__ << "Indent string length " <<
218 : indent_str_.length() << " less than indent length " <<
219 : (string::size_type)indent_inc);
220 : return;
221 : }
222 : indent_str_.erase(indent_str_.length() - indent_inc);
223 : #endif // !TXMLPROTOOL_DEBUG_PRETTY_PRINT
224 64509 : }
225 :
226 : // Returns the number of bytes written on success, -1 otherwise
227 650516 : int32_t TXMLProtocol::writePlain(const string& str) {
228 650516 : int ret = trans_->write((uint8_t*)str.data(), str.length());
229 650516 : if (ret) {
230 0 : return -1;
231 : }
232 650516 : return str.length();
233 : }
234 :
235 : // Returns the number of bytes written on success, -1 otherwise
236 483747 : int32_t TXMLProtocol::writeIndented(const string& str) {
237 : int ret;
238 : #if TXMLPROTOCOL_DEBUG_PRETTY_PRINT
239 : ret = trans_->write((uint8_t*)indent_str_.data(), indent_str_.length());
240 : if (ret) {
241 : return -1;
242 : }
243 : #endif // !TXMLPROTOCOL_DEBUG_PRETTY_PRINT
244 483747 : ret = trans_->write((uint8_t*)str.data(), str.length());
245 483747 : if (ret) {
246 0 : return -1;
247 : }
248 483747 : return indent_str_.length() + str.length();
249 : }
250 :
251 0 : int32_t TXMLProtocol::writeMessageBegin(const std::string& name,
252 : const TMessageType messageType,
253 : const int32_t seqid) {
254 0 : return 0;
255 : }
256 :
257 0 : int32_t TXMLProtocol::writeMessageEnd() {
258 0 : return 0;
259 : }
260 :
261 32997 : int32_t TXMLProtocol::writeStructBegin(const char* name) {
262 32997 : int32_t size = 0, ret;
263 32997 : string sname(name);
264 32997 : string xml;
265 32997 : xml.reserve(512);
266 : // Form the xml tag
267 32997 : xml += kXMLTagO;
268 32997 : xml += sname;
269 32997 : xml += kXMLTagC;
270 32997 : xml += endl;
271 : // Write to transport
272 32997 : if ((ret = writeIndented(xml)) < 0) {
273 0 : LOG(ERROR, __func__ << ": " << sname << " FAILED");
274 0 : return ret;
275 : }
276 32997 : size += ret;
277 32997 : xml_state_.push_back(sname);
278 32997 : indentUp();
279 32997 : return size;
280 32997 : }
281 :
282 32997 : int32_t TXMLProtocol::writeStructEnd() {
283 32997 : indentDown();
284 32997 : int32_t size = 0, ret;
285 32997 : string etag(xml_state_.back());
286 32997 : xml_state_.pop_back();
287 32997 : string xml;
288 32997 : xml.reserve(128);
289 : // Form the xml tag
290 32997 : xml += kXMLEndTagO;
291 32997 : xml += etag;
292 32997 : xml += kXMLTagC;
293 32997 : xml += endl;
294 : // Write to transport
295 32997 : if ((ret = writeIndented(xml)) < 0) {
296 0 : LOG(ERROR, __func__ << ": " << etag << " FAILED");
297 0 : return ret;
298 : }
299 32997 : size += ret;
300 32997 : return size;
301 32997 : }
302 :
303 12904 : int32_t TXMLProtocol::writeSandeshBegin(const char* name) {
304 12904 : int32_t size = 0, ret;
305 12904 : string sname(name);
306 12904 : string xml;
307 12904 : xml.reserve(512);
308 : // Form the xml tag
309 12904 : xml += kXMLTagO;
310 12904 : xml += sname;
311 12904 : xml += " ";
312 12904 : xml += kAttrTypeSandesh;
313 12904 : xml += kXMLTagC;
314 12904 : xml += endl;
315 : // Write to transport
316 12904 : ret = writeIndented(xml);
317 12904 : if (ret < 0) {
318 0 : LOG(ERROR, __func__ << ": " << sname << " FAILED");
319 0 : return ret;
320 : }
321 12904 : size += ret;
322 12904 : xml_state_.push_back(sname);
323 12904 : indentUp();
324 12904 : return size;
325 12904 : }
326 :
327 12904 : int32_t TXMLProtocol::writeSandeshEnd() {
328 12904 : indentDown();
329 12904 : int32_t size = 0, ret;
330 12904 : string etag(xml_state_.back());
331 12904 : xml_state_.pop_back();
332 12904 : string exml;
333 12904 : exml.reserve(128);
334 : // Form the xml tag
335 12904 : exml += kXMLEndTagO;
336 12904 : exml += etag;
337 12904 : exml += kXMLTagC;
338 12904 : exml += endl;
339 : // Write to transport
340 12904 : if ((ret = writeIndented(exml)) < 0) {
341 0 : LOG(ERROR, __func__ << ": " << etag << " FAILED");
342 0 : return ret;
343 : }
344 12904 : size += ret;
345 12904 : return size;
346 12904 : }
347 :
348 14395 : int32_t TXMLProtocol::writeContainerElementBegin() {
349 14395 : return writeIndented(kXMLElementTagO);
350 : }
351 :
352 14395 : int32_t TXMLProtocol::writeContainerElementEnd() {
353 14395 : return writeIndented(kXMLElementTagC);
354 : }
355 :
356 336668 : int32_t TXMLProtocol::writeFieldBegin(const char *name,
357 : const TType fieldType,
358 : const int16_t fieldId,
359 : const std::map<std::string, std::string> *const amap) {
360 336668 : int32_t size = 0, ret;
361 336668 : string sname(name);
362 336668 : string xml;
363 336668 : xml.reserve(512);
364 : // Form the xml tag
365 336668 : xml += kXMLTagO;
366 336669 : xml += sname;
367 336669 : xml += " ";
368 336669 : formXMLAttr(xml, kXMLType, fieldTypeName(fieldType));
369 336669 : xml += " ";
370 336669 : formXMLAttr(xml, kXMLIdentifier, integerToString(fieldId));
371 336669 : if (amap != NULL) {
372 13742 : for (std::map<string, string>::const_iterator iter = amap->begin();
373 27928 : iter != amap->end(); iter++) {
374 14186 : xml += " ";
375 14186 : formXMLAttr(xml, (*iter).first, (*iter).second);
376 : }
377 : }
378 336669 : xml += kXMLTagC;
379 : // Write to transport
380 336669 : if ((ret = writeIndented(xml)) < 0) {
381 0 : LOG(ERROR, __func__ << ": " << xml << " FAILED");
382 0 : return ret;
383 : }
384 336669 : size += ret;
385 336669 : xml_state_.push_back(sname);
386 336669 : if (fieldType == T_STRUCT) {
387 14669 : write_state_.push_back(STRUCT);
388 : #ifdef TXMLPROTOCOL_DEBUG_PRETTY_PRINT
389 : if ((ret = writePlain(endl)) < 0) {
390 : LOG(ERROR, __func__ << ": " << fieldTypeName(fieldType) << " FAILED");
391 : return ret;
392 : }
393 : size += ret;
394 : indentUp();
395 : #endif // !TXMLPROTOCOL_DEBUG_PRETTY_PRINT
396 322000 : } else if (fieldType == T_SANDESH) {
397 0 : write_state_.push_back(SNDESH);
398 : #ifdef TXMLPROTOCOL_DEBUG_PRETTY_PRINT
399 : if ((ret = writePlain(endl)) < 0) {
400 : LOG(ERROR, __func__ << ": " << fieldTypeName(fieldType) << " FAILED");
401 : return ret;
402 : }
403 : size += ret;
404 : #endif // !TXMLPROTOCOL_DEBUG_PRETTY_PRINT
405 322000 : } else if (fieldType == T_LIST) {
406 3503 : write_state_.push_back(LIST);
407 : #ifdef TXMLPROTOCOL_DEBUG_PRETTY_PRINT
408 : if ((ret = writePlain(endl)) < 0) {
409 : LOG(ERROR, __func__ << ": " << fieldTypeName(fieldType) << " FAILED");
410 : return ret;
411 : }
412 : size += ret;
413 : #endif // !TXMLPROTOCOL_DEBUG_PRETTY_PRINT
414 318497 : } else if (fieldType == T_MAP) {
415 436 : write_state_.push_back(MAP);
416 : #ifdef TXMLPROTOCOL_DEBUG_PRETTY_PRINT
417 : if ((ret = writePlain(endl)) < 0) {
418 : LOG(ERROR, __func__ << ": " << fieldTypeName(fieldType) << " FAILED");
419 : return ret;
420 : }
421 : size += ret;
422 : #endif // !TXMLPROTOCOL_DEBUG_PRETTY_PRINT
423 318061 : } else if (fieldType == T_SET) {
424 0 : write_state_.push_back(SET);
425 : #ifdef TXMLPROTOCOL_DEBUG_PRETTY_PRINT
426 : if ((ret = writePlain(endl)) < 0) {
427 : LOG(ERROR, __func__ << ": " << fieldTypeName(fieldType) << " FAILED");
428 : return ret;
429 : }
430 : size += ret;
431 : #endif // !TXMLPROTOCOL_DEBUG_PRETTY_PRINT
432 : } else {
433 318061 : write_state_.push_back(UNINIT);
434 : }
435 336669 : return size;
436 336669 : }
437 :
438 336668 : int32_t TXMLProtocol::writeFieldEnd() {
439 336668 : int32_t size = 0, ret;
440 336668 : string etag(xml_state_.back());
441 336668 : xml_state_.pop_back();
442 336668 : string exml;
443 336668 : exml.reserve(128);
444 : // Form the xml tag
445 336669 : exml += kXMLEndTagO;
446 336669 : exml += etag;
447 336669 : exml += kXMLTagC;
448 336669 : exml += endl;
449 : // Write to transport
450 336669 : write_state_t state = write_state_.back();
451 336669 : if (state != STRUCT &&
452 322000 : state != SNDESH &&
453 318497 : state != LIST &&
454 318061 : state != MAP &&
455 : state != SET) {
456 318061 : if ((ret = writePlain(exml)) < 0) {
457 0 : LOG(ERROR, __func__ << ": " << etag << " " << state <<
458 : " FAILED");
459 0 : return ret;
460 : }
461 318061 : size += ret;
462 318061 : } else {
463 18608 : if (state == STRUCT) {
464 14669 : indentDown();
465 : }
466 18608 : if ((ret = writeIndented(exml)) < 0) {
467 0 : LOG(ERROR, __func__ << ": " << etag << " " << state <<
468 : " FAILED");
469 0 : return ret;
470 : }
471 18608 : size += ret;
472 : }
473 336669 : write_state_.pop_back();
474 336669 : return size;
475 336669 : }
476 :
477 45901 : int32_t TXMLProtocol::writeFieldStop() {
478 45901 : return 0;
479 : }
480 :
481 436 : int32_t TXMLProtocol::writeMapBegin(const TType keyType,
482 : const TType valType,
483 : const uint32_t size) {
484 436 : int32_t bsize = 0, ret;
485 436 : string xml;
486 436 : xml.reserve(256);
487 : // Form the xml tag
488 436 : xml += kXMLMapTagO;
489 436 : formXMLAttr(xml, kXMLKey, fieldTypeName(keyType));
490 436 : xml += " ";
491 436 : formXMLAttr(xml, kXMLValue, fieldTypeName(valType));
492 436 : xml += " ";
493 436 : formXMLAttr(xml, kXMLSize, integerToString(size));
494 436 : xml += kXMLTagC;
495 436 : xml += endl;
496 : // Write to transport
497 436 : ret = writeIndented(xml);
498 436 : if (ret < 0) {
499 0 : LOG(ERROR, __func__ << ": Key: " << fieldTypeName(keyType) <<
500 : " Value: " << fieldTypeName(valType) << " FAILED");
501 0 : return ret;
502 : }
503 436 : bsize += ret;
504 436 : indentUp();
505 436 : return bsize;
506 436 : }
507 :
508 436 : int32_t TXMLProtocol::writeMapEnd() {
509 436 : int32_t size = 0, ret;
510 436 : indentDown();
511 436 : if ((ret = writeIndented(kXMLMapTagC)) < 0) {
512 0 : LOG(ERROR, __func__ << " FAILED");
513 0 : return ret;
514 : }
515 436 : size += ret;
516 436 : return size;
517 : }
518 :
519 3503 : int32_t TXMLProtocol::writeListBegin(const TType elemType,
520 : const uint32_t size) {
521 3503 : int32_t bsize = 0, ret;
522 3503 : string xml;
523 3503 : xml.reserve(256);
524 : // Form the xml tag
525 3503 : xml += kXMLListTagO;
526 3503 : formXMLAttr(xml, kXMLType, fieldTypeName(elemType));
527 3503 : xml += " ";
528 3503 : formXMLAttr(xml, kXMLSize, integerToString(size));
529 3503 : xml += kXMLTagC;
530 3503 : xml += endl;
531 : // Write to transport
532 3503 : ret = writeIndented(xml);
533 3503 : if (ret < 0) {
534 0 : LOG(ERROR, __func__ << ": " << fieldTypeName(elemType) <<
535 : " FAILED");
536 0 : return ret;
537 : }
538 3503 : bsize += ret;
539 3503 : indentUp();
540 3503 : return bsize;
541 3503 : }
542 :
543 3503 : int32_t TXMLProtocol::writeListEnd() {
544 3503 : int32_t size = 0, ret;
545 3503 : indentDown();
546 3503 : ret = writeIndented(kXMLListTagC);
547 3503 : if (ret < 0) {
548 0 : LOG(ERROR, __func__ << " FAILED");
549 0 : return ret;
550 : }
551 3503 : size += ret;
552 3503 : return size;
553 : }
554 :
555 0 : int32_t TXMLProtocol::writeSetBegin(const TType elemType,
556 : const uint32_t size) {
557 0 : int32_t bsize = 0, ret;
558 0 : string xml;
559 0 : xml.reserve(256);
560 : // Form the xml tag
561 0 : xml += kXMLSetTagO;
562 0 : formXMLAttr(xml, kXMLType, fieldTypeName(elemType));
563 0 : xml += " ";
564 0 : formXMLAttr(xml, kXMLSize, integerToString(size));
565 0 : xml += kXMLTagC;
566 0 : xml += endl;
567 : // Write to transport
568 0 : ret = writeIndented(xml);
569 0 : if (ret < 0) {
570 0 : LOG(ERROR, __func__ << ": " << fieldTypeName(elemType) <<
571 : " FAILED");
572 0 : return ret;
573 : }
574 0 : bsize += ret;
575 0 : indentUp();
576 0 : return bsize;
577 0 : }
578 :
579 0 : int32_t TXMLProtocol::writeSetEnd() {
580 0 : int32_t size = 0, ret;
581 0 : indentDown();
582 0 : if ((ret = writeIndented(kXMLSetTagC)) < 0) {
583 0 : LOG(ERROR, __func__ << " FAILED");
584 0 : return ret;
585 : }
586 0 : size += ret;
587 0 : return size;
588 : }
589 :
590 1987 : int32_t TXMLProtocol::writeBool(const bool value) {
591 1987 : return writePlain(value ? kXMLBoolTrue : kXMLBoolFalse);
592 : }
593 :
594 0 : int32_t TXMLProtocol::writeByte(const int8_t byte) {
595 0 : return writePlain(integerToString(byte));
596 : }
597 :
598 0 : int32_t TXMLProtocol::writeI16(const int16_t i16) {
599 0 : return writePlain(integerToString(i16));
600 : }
601 :
602 73579 : int32_t TXMLProtocol::writeI32(const int32_t i32) {
603 73579 : return writePlain(integerToString(i32));
604 : }
605 :
606 12894 : int32_t TXMLProtocol::writeI64(const int64_t i64) {
607 12894 : return writePlain(integerToString(i64));
608 : }
609 :
610 66 : int32_t TXMLProtocol::writeU16(const uint16_t u16) {
611 66 : return writePlain(integerToString(u16));
612 : }
613 :
614 3984 : int32_t TXMLProtocol::writeU32(const uint32_t u32) {
615 3984 : return writePlain(integerToString(u32));
616 : }
617 :
618 70604 : int32_t TXMLProtocol::writeU64(const uint64_t u64) {
619 70604 : return writePlain(integerToString(u64));
620 : }
621 :
622 0 : int32_t TXMLProtocol::writeIPV4(const uint32_t ip4) {
623 0 : return writePlain(integerToString(ip4));
624 : }
625 :
626 0 : int32_t TXMLProtocol::writeIPADDR(const boost::asio::ip::address& ipaddress) {
627 0 : return writePlain(ipaddress.to_string());
628 : }
629 :
630 403 : int32_t TXMLProtocol::writeDouble(const double dub) {
631 403 : return writePlain(integerToString(dub));
632 : }
633 :
634 168939 : int32_t TXMLProtocol::writeString(const string& str) {
635 : // Escape XML control characters in the string before writing
636 168939 : return writePlain(escapeXMLControlChars(str));
637 : }
638 :
639 0 : int32_t TXMLProtocol::writeBinary(const string& str) {
640 : // XXX Hex?
641 0 : return writeString(str);
642 : }
643 :
644 0 : int32_t TXMLProtocol::writeXML(const string& str) {
645 0 : std::string xmlstr;
646 0 : xmlstr.reserve(str.length() + kXMLCDATAO.length() + kXMLCDATAC.length());
647 0 : xmlstr += kXMLCDATAO;
648 0 : xmlstr += str;
649 0 : xmlstr += kXMLCDATAC;
650 0 : return writePlain(xmlstr);
651 0 : }
652 :
653 0 : int32_t TXMLProtocol::writeUUID(const boost::uuids::uuid& uuid) {
654 0 : const std::string str = boost::uuids::to_string(uuid);
655 0 : return writeString(str);
656 0 : }
657 : /**
658 : * Reading functions
659 : */
660 :
661 : // Return true if the character ch is in [-+0-9]; false otherwise
662 6060 : static bool isXMLNumeric(uint8_t ch) {
663 6060 : switch (ch) {
664 5217 : case '+':
665 : case '-':
666 : case '0':
667 : case '1':
668 : case '2':
669 : case '3':
670 : case '4':
671 : case '5':
672 : case '6':
673 : case '7':
674 : case '8':
675 : case '9':
676 5217 : return true;
677 : }
678 843 : return false;
679 : }
680 :
681 : // Read 1 character from the transport trans and verify that it is the
682 : // expected character ch. Returns 1 if does, -1 if not
683 8045 : static int32_t readSyntaxChar(TXMLProtocol::LookaheadReader &reader,
684 : uint8_t ch) {
685 8045 : uint8_t ch2 = reader.read();
686 8045 : if (ch2 != ch) {
687 0 : LOG(ERROR, __func__ << ": Expected \'" << std::string((char *)&ch, 1) <<
688 : "\'; got \'" << std::string((char *)&ch2, 1) << "\'.");
689 0 : return -1;
690 : }
691 8045 : return 1;
692 : }
693 :
694 : // Reads string from the transport trans and verify that it is the
695 : // expected string str. Returns 1 if does, -1 if not
696 0 : static int32_t readSyntaxString(TXMLProtocol::LookaheadReader &reader,
697 : const std::string str) {
698 0 : int32_t result = 0, ret;
699 0 : for (std::string::const_iterator it = str.begin(); it != str.end(); it++) {
700 0 : if ((ret = readSyntaxChar(reader, *it)) < 0) {
701 0 : return ret;
702 : }
703 0 : result += ret;
704 : }
705 0 : return result;
706 : }
707 :
708 : // Reads 1 byte and verifies that it matches ch. Returns 1 if it does,
709 : // -1 otherwise
710 8045 : int32_t TXMLProtocol::readXMLSyntaxChar(uint8_t ch) {
711 8045 : return readSyntaxChar(reader_, ch);
712 : }
713 :
714 : // Reads a XML number or string and interprets it as a double.
715 0 : int32_t TXMLProtocol::readXMLDouble(double &num) {
716 0 : LOG(ERROR, __func__ << ": Not implemented in TXMLProtocol");
717 0 : assert(false);
718 : return -1;
719 : }
720 :
721 : // Reads string and verifies that it matches str. Returns 1 if it does,
722 : // -1 otherwise
723 0 : int32_t TXMLProtocol::readXMLSyntaxString(const std::string &str) {
724 0 : return readSyntaxString(reader_, str);
725 : }
726 :
727 0 : int32_t TXMLProtocol::readXMLCDATA(std::string &str) {
728 0 : int32_t result = 0, ret;
729 0 : str.clear();
730 : // Read <![CDATA[
731 0 : if ((ret = readXMLSyntaxString(kXMLCDATAO)) < 0) {
732 0 : return ret;
733 : }
734 0 : result += ret;
735 0 : uint8_t ch = 0, ch2 = 0, ch3;
736 0 : bool ch_read = false, ch2_read = false, ch3_read = false;
737 : while (true) {
738 0 : if (!ch_read) {
739 0 : ch = reader_.peek();
740 0 : reader_.read();
741 0 : ++result;
742 0 : ch_read = true;
743 : }
744 : // Did we read ]]> ?
745 0 : if (ch == kcXMLSBracketC) {
746 0 : if (!ch2_read) {
747 0 : ch2 = reader_.peek();
748 0 : reader_.read();
749 0 : ++result;
750 0 : ch2_read = true;
751 : }
752 0 : if (ch2 == kcXMLSBracketC) {
753 0 : if (!ch3_read) {
754 0 : ch3 = reader_.peek();
755 0 : reader_.read();
756 0 : ++result;
757 0 : ch3_read = true;
758 : }
759 0 : if (ch3 == kcXMLTagC) {
760 0 : break;
761 : } else {
762 : // Consume ch
763 0 : str += ch;
764 : // Rotate ch2 and ch3 and repeat
765 0 : ch = ch2;
766 0 : ch2 = ch3;
767 0 : ch3_read = false;
768 0 : continue;
769 : }
770 : } else {
771 : // Consume ch
772 0 : str += ch;
773 : // Rotate ch2 and repeat
774 0 : ch = ch2;
775 0 : ch2_read = false;
776 0 : continue;
777 : }
778 : } else {
779 0 : str += ch;
780 0 : ch_read = false;
781 : }
782 : }
783 0 : return result;
784 : }
785 :
786 : // Reads a sequence of characters, stopping at the first occurrence of xml
787 : // tag open delimiter which signals end of field and returns the string
788 : // via str.
789 1310 : int32_t TXMLProtocol::readXMLString(std::string &str) {
790 1310 : int32_t result = 0;
791 1310 : str.clear();
792 : while (true) {
793 15638 : uint8_t ch = reader_.peek();
794 15638 : if (ch == kcXMLTagO) {
795 1310 : break;
796 : }
797 14328 : reader_.read();
798 14328 : str += ch;
799 14328 : ++result;
800 14328 : }
801 1310 : return result;
802 : }
803 :
804 : // Decodes an XML tag and returns the string without the xml open
805 : // and close delimiters via str
806 5404 : int32_t TXMLProtocol::readXMLTag(std::string &str, bool endTag) {
807 5404 : int32_t result = 0, ret;
808 : uint8_t ch;
809 5404 : str.clear();
810 5404 : if ((ret = readXMLSyntaxChar(kcXMLTagO)) < 0) {
811 0 : return ret;
812 : }
813 5404 : result += ret;
814 5404 : if (endTag) {
815 2641 : if ((ret = readXMLSyntaxChar(kcXMLSlash)) < 0) {
816 0 : return ret;
817 : }
818 2641 : result += ret;
819 : }
820 : while (true) {
821 118561 : ch = reader_.read();
822 118561 : ++result;
823 118561 : if (ch == kcXMLTagC) {
824 5404 : break;
825 : }
826 113157 : str += ch;
827 : }
828 5404 : return result;
829 : }
830 :
831 : // Reads a sequence of characters, stopping at the first one that is not
832 : // a valid numeric character.
833 843 : int32_t TXMLProtocol::readXMLNumericChars(std::string &str) {
834 843 : uint32_t result = 0;
835 843 : str.clear();
836 : while (true) {
837 6060 : uint8_t ch = reader_.peek();
838 6060 : if (!isXMLNumeric(ch)) {
839 843 : break;
840 : }
841 5217 : reader_.read();
842 5217 : str += ch;
843 5217 : ++result;
844 5217 : }
845 843 : return result;
846 : }
847 :
848 : // Reads a sequence of characters and assembles them into a number,
849 : // returning them via num
850 : template <typename NumberType>
851 843 : int32_t TXMLProtocol::readXMLInteger(NumberType &num) {
852 843 : int32_t result = 0, ret;
853 843 : std::string str;
854 843 : if ((ret = readXMLNumericChars(str)) < 0) {
855 0 : return ret;
856 : }
857 843 : result += ret;
858 843 : stringToInteger(str, num);
859 843 : return result;
860 843 : }
861 :
862 0 : int32_t TXMLProtocol::readMessageBegin(std::string& name,
863 : TMessageType& messageType,
864 : int32_t& seqid) {
865 0 : LOG(ERROR, __func__ << ": Not implemented in TXMLProtocol");
866 0 : assert(false);
867 : return -1;
868 : }
869 :
870 0 : int32_t TXMLProtocol::readMessageEnd() {
871 0 : LOG(ERROR, __func__ << ": Not implemented in TXMLProtocol");
872 0 : assert(false);
873 : return -1;
874 : }
875 :
876 244 : int32_t TXMLProtocol::readSandeshBegin(std::string& name) {
877 244 : std::string str;
878 244 : int32_t result = 0, ret;
879 244 : if ((ret = readXMLTag(str)) < 0) {
880 0 : LOG(ERROR, __func__ << ": FAILED");
881 0 : return ret;
882 : }
883 244 : result += ret;
884 244 : boost::char_separator<char> sep("=\" ");
885 244 : tokenizer tokens(str, sep);
886 : // Extract the field name
887 244 : tokenizer::iterator it = tokens.begin();
888 244 : name = *it;
889 244 : ++it;
890 488 : for (; it != tokens.end(); ++it) {
891 244 : if (*it == kXMLType) {
892 244 : ++it;
893 244 : if (kTypeNameSandesh != *it) {
894 0 : LOG(ERROR, __func__ << ": Expected " << kTypeNameSandesh <<
895 : "; got " << *it);
896 0 : return -1;
897 : }
898 : }
899 : }
900 244 : return result;
901 244 : }
902 :
903 122 : int32_t TXMLProtocol::readSandeshEnd() {
904 122 : std::string name;
905 244 : return readXMLTag(name, true);
906 122 : }
907 :
908 122 : int32_t TXMLProtocol::readStructBegin(std::string& name) {
909 122 : return readXMLTag(name);
910 : }
911 :
912 122 : int32_t TXMLProtocol::readStructEnd() {
913 122 : std::string name;
914 244 : return readXMLTag(name, true);
915 122 : }
916 :
917 223 : int32_t TXMLProtocol::readContainerElementBegin() {
918 223 : std::string name;
919 446 : return readXMLTag(name);
920 223 : }
921 :
922 223 : int32_t TXMLProtocol::readContainerElementEnd() {
923 223 : std::string name;
924 446 : return readXMLTag(name, true);
925 223 : }
926 :
927 2296 : int32_t TXMLProtocol::readFieldBegin(std::string& name,
928 : TType& fieldType,
929 : int16_t& fieldId) {
930 2296 : int32_t result = 0, ret;
931 : // Check if we hit the end of the list
932 2296 : uint8_t ch = reader_.peek2();
933 2296 : uint8_t ch1 = reader_.peek2();
934 2296 : if (ch == kcXMLTagO && ch1 == kcXMLSlash) {
935 244 : fieldType = contrail::sandesh::protocol::T_STOP;
936 244 : return result;
937 : }
938 2052 : std::string str;
939 2052 : if ((ret = readXMLTag(str)) < 0) {
940 0 : LOG(ERROR, __func__ << ": FAILED");
941 0 : return ret;
942 : }
943 2052 : result += ret;
944 2052 : boost::char_separator<char> sep("=\" ");
945 2052 : tokenizer tokens(str, sep);
946 : // Extract the field name
947 2052 : tokenizer::iterator it = tokens.begin();
948 2052 : name = *it;
949 2052 : ++it;
950 6156 : for (; it != tokens.end(); ++it) {
951 4104 : if (*it == kXMLType) {
952 2052 : ++it;
953 2052 : fieldType = getTypeIDForTypeName(*it);
954 : }
955 4104 : if (*it == kXMLIdentifier) {
956 2052 : ++it;
957 2052 : stringToInteger(*it, fieldId);
958 : }
959 : }
960 2052 : return result;
961 2052 : }
962 :
963 2052 : int32_t TXMLProtocol::readFieldEnd() {
964 2052 : string str;
965 4104 : return readXMLTag(str, true);
966 2052 : }
967 :
968 0 : int32_t TXMLProtocol::readMapBegin(TType& keyType,
969 : TType& valType,
970 : uint32_t& size) {
971 0 : int32_t result = 0, ret;
972 0 : std::string str;
973 0 : if ((ret = readXMLTag(str)) < 0) {
974 0 : LOG(ERROR, __func__ << ": FAILED");
975 0 : return ret;
976 : }
977 0 : result += ret;
978 0 : boost::char_separator<char> sep("=\" ");
979 0 : tokenizer tokens(str, sep);
980 : // Extract the field name
981 0 : tokenizer::iterator it = tokens.begin();
982 0 : if (*it != kTypeNameMap) {
983 0 : LOG(ERROR, __func__ << ": Expected \"" << kTypeNameMap <<
984 : "\"; got \"" << *it << "\"");
985 0 : return -1;
986 : }
987 0 : ++it;
988 0 : for (; it != tokens.end(); ++it) {
989 0 : if (*it == kXMLKey) {
990 0 : ++it;
991 0 : keyType = getTypeIDForTypeName(*it);
992 : }
993 0 : if (*it == kXMLValue) {
994 0 : ++it;
995 0 : valType = getTypeIDForTypeName(*it);
996 : }
997 0 : if (*it == kXMLSize) {
998 0 : ++it;
999 0 : stringToInteger(*it, size);
1000 : }
1001 : }
1002 0 : return result;
1003 0 : }
1004 :
1005 0 : int32_t TXMLProtocol::readMapEnd() {
1006 0 : std::string str;
1007 0 : return readXMLTag(str, true);
1008 0 : }
1009 :
1010 122 : int32_t TXMLProtocol::readListBegin(TType& elemType,
1011 : uint32_t& size) {
1012 122 : int32_t result = 0, ret;
1013 122 : std::string str;
1014 122 : if ((ret = readXMLTag(str)) < 0) {
1015 0 : LOG(ERROR, __func__ << ": FAILED");
1016 0 : return ret;
1017 : }
1018 122 : result += ret;
1019 122 : boost::char_separator<char> sep("=\" ");
1020 122 : tokenizer tokens(str, sep);
1021 : // Extract the field name
1022 122 : tokenizer::iterator it = tokens.begin();
1023 122 : if (*it != kTypeNameList) {
1024 0 : LOG(ERROR, __func__ << ": Expected \"" << kTypeNameList <<
1025 : "\"; got \"" << *it << "\"");
1026 0 : return -1;
1027 : }
1028 122 : ++it;
1029 366 : for (; it != tokens.end(); ++it) {
1030 244 : if (*it == kXMLType) {
1031 122 : ++it;
1032 122 : elemType = getTypeIDForTypeName(*it);
1033 : }
1034 244 : if (*it == kXMLSize) {
1035 122 : ++it;
1036 122 : stringToInteger(*it, size);
1037 : }
1038 : }
1039 122 : return result;
1040 122 : }
1041 :
1042 122 : int32_t TXMLProtocol::readListEnd() {
1043 122 : std::string str;
1044 244 : return readXMLTag(str, true);
1045 122 : }
1046 :
1047 0 : int32_t TXMLProtocol::readSetBegin(TType& elemType,
1048 : uint32_t& size) {
1049 0 : int32_t result = 0, ret;
1050 0 : std::string str;
1051 0 : if ((ret = readXMLTag(str)) < 0) {
1052 0 : LOG(ERROR, __func__ << ": FAILED");
1053 0 : return ret;
1054 : }
1055 0 : result += ret;
1056 0 : boost::char_separator<char> sep("=\" ");
1057 0 : tokenizer tokens(str, sep);
1058 : // Extract the field name
1059 0 : tokenizer::iterator it = tokens.begin();
1060 0 : if (*it != kTypeNameSet) {
1061 0 : LOG(ERROR, __func__ << ": Expected \"" << kTypeNameSet <<
1062 : "\"; got \"" << *it << "\"");
1063 0 : return -1;
1064 : }
1065 0 : ++it;
1066 0 : for (; it != tokens.end(); ++it) {
1067 0 : if (*it == kXMLType) {
1068 0 : ++it;
1069 0 : elemType = getTypeIDForTypeName(*it);
1070 : }
1071 0 : if (*it == kXMLSize) {
1072 0 : ++it;
1073 0 : stringToInteger(*it, size);
1074 : }
1075 : }
1076 0 : return result;
1077 0 : }
1078 :
1079 0 : int32_t TXMLProtocol::readSetEnd() {
1080 0 : std::string str;
1081 0 : return readXMLTag(str, true);
1082 0 : }
1083 :
1084 0 : int32_t TXMLProtocol::readI16(int16_t& i16) {
1085 0 : return readXMLInteger(i16);
1086 : }
1087 :
1088 610 : int32_t TXMLProtocol::readI32(int32_t& i32) {
1089 610 : return readXMLInteger(i32);
1090 : }
1091 :
1092 122 : int32_t TXMLProtocol::readI64(int64_t& i64) {
1093 122 : return readXMLInteger(i64);
1094 : }
1095 :
1096 0 : int32_t TXMLProtocol::readU16(uint16_t& u16) {
1097 0 : return readXMLInteger(u16);
1098 : }
1099 :
1100 111 : int32_t TXMLProtocol::readU32(uint32_t& u32) {
1101 111 : return readXMLInteger(u32);
1102 : }
1103 :
1104 0 : int32_t TXMLProtocol::readU64(uint64_t& u64) {
1105 0 : return readXMLInteger(u64);
1106 : }
1107 :
1108 0 : int32_t TXMLProtocol::readIPV4(uint32_t& ip4) {
1109 0 : return readXMLInteger(ip4);
1110 : }
1111 :
1112 0 : int32_t TXMLProtocol::readIPADDR(boost::asio::ip::address& ipaddress) {
1113 : int32_t ret;
1114 0 : std::string str;
1115 0 : if ((ret = readXMLString(str)) < 0) {
1116 0 : return ret;
1117 : }
1118 0 : boost::system::error_code ec;
1119 0 : ipaddress = boost::asio::ip::address::from_string(str, ec);
1120 0 : if (ec) {
1121 0 : return -1;
1122 : }
1123 0 : return ret;
1124 0 : }
1125 :
1126 0 : int32_t TXMLProtocol::readDouble(double& dub) {
1127 0 : return readXMLDouble(dub);
1128 : }
1129 :
1130 1225 : int32_t TXMLProtocol::readString(std::string &str) {
1131 1225 : readXMLString(str);
1132 1225 : unescapeXMLControlChars(str);
1133 1225 : return str.size();
1134 : }
1135 :
1136 85 : int32_t TXMLProtocol::readBool(bool& value) {
1137 85 : std::string str;
1138 85 : int32_t result = 0, ret;
1139 85 : if ((ret = readXMLString(str)) < 0) {
1140 0 : return ret;
1141 : }
1142 85 : result += ret;
1143 85 : if (str == kXMLBoolTrue) {
1144 85 : value = true;
1145 0 : } else if (str == kXMLBoolFalse) {
1146 0 : value = false;
1147 : } else {
1148 0 : LOG(ERROR, __func__ << ": Expected \"" << kXMLBoolTrue <<
1149 : "\" or \"" << kXMLBoolFalse << "\"; got \"" << str << "\"");
1150 : }
1151 85 : return result;
1152 85 : }
1153 :
1154 0 : int32_t TXMLProtocol::readByte(int8_t& byte) {
1155 0 : return readXMLInteger(byte);
1156 : }
1157 :
1158 0 : int32_t TXMLProtocol::readBinary(std::string &str) {
1159 0 : return readXMLString(str);
1160 : }
1161 :
1162 0 : int32_t TXMLProtocol::readXML(std::string &str) {
1163 0 : return readXMLCDATA(str);
1164 : }
1165 :
1166 0 : int32_t TXMLProtocol::readUUID(boost::uuids::uuid &uuid) {
1167 : int32_t ret;
1168 0 : std::string str;
1169 0 : if ((ret = readXMLString(str)) < 0) {
1170 0 : return ret;
1171 : }
1172 0 : std::stringstream ss;
1173 0 : ss << str;
1174 0 : ss >> uuid;
1175 0 : return ret;
1176 0 : }
1177 :
1178 : }}} // contrail::sandesh::protocol
|