source: source/ariba/utility/transport/tcpip/protlib/network_message.cpp@ 10643

Last change on this file since 10643 was 10394, checked in by mayer@…, 13 years ago

-can define protlib message size at configure time using CPPFLAGS='-DPROTLIBMESSAGESIZE=200000'

File size: 18.3 KB
Line 
1/// ----------------------------------------*- mode: C++; -*--
2/// @file network_message.cpp
3/// generic class for network messages represented as byte stream
4/// ----------------------------------------------------------
5/// $Id: network_message.cpp 3247 2008-07-28 20:54:54Z bless $
6/// $HeadURL: https://svn.ipv6.tm.uka.de/nsis/protlib/trunk/src/network_message.cpp $
7// ===========================================================
8//
9// Copyright (C) 2005-2007, all rights reserved by
10// - Institute of Telematics, Universitaet Karlsruhe (TH)
11//
12// More information and contact:
13// https://projekte.tm.uka.de/trac/NSIS
14//
15// This program is free software; you can redistribute it and/or modify
16// it under the terms of the GNU General Public License as published by
17// the Free Software Foundation; version 2 of the License
18//
19// This program is distributed in the hope that it will be useful,
20// but WITHOUT ANY WARRANTY; without even the implied warranty of
21// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22// GNU General Public License for more details.
23//
24// You should have received a copy of the GNU General Public License along
25// with this program; if not, write to the Free Software Foundation, Inc.,
26// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27//
28// ===========================================================
29/** @ingroup protlib
30 * This is a generic class for network messages,
31 * represented as a byte stream (buffer containing bytes).
32 */
33
34#include <netinet/in.h>
35#include <string.h>
36#include <cctype>
37#include <fstream>
38#include <ostream>
39#include <sstream>
40#include <iomanip>
41
42#include "network_message.h"
43#include "logfile.h" // only required for color definitions
44
45namespace protlib {
46
47
48 using namespace protlib::log;
49/** @addtogroup protlib
50 * @{
51 */
52
53/** @param e error code */
54NetMsgError::NetMsgError(error_t e) : err(e) {}
55
56const char* NetMsgError::getstr() const { return errstr[err]; }
57
58/** NetMsg error strings */
59const char* const NetMsgError::errstr[] =
60{
61 "Network message too long.",
62 "Not enough memory to allocate network message.",
63 "Operation not valid because of pointer position in NetMsg buffer.",
64 "NULL pointer argument in call to NetMsg constructor.",
65 "Invalid start offset.",
66 "NetMsg buffer too short.",
67 "Invalid buffer size: zero"
68}; // end network message error strings
69
70/** Maximum size of a network message. This is set to 128000 to prevent
71 * very large messages.
72 */
73const uint32 NetMsg::max_size =
74 #ifdef PROTLIBMESSAGESIZE
75 PROTLIBMESSAGESIZE
76 #else
77 128000
78 #endif
79;
80
81/** Creates a network message object of the desired size if possible.
82 * @param s buffer size.
83 */
84NetMsg::NetMsg(uint32 s) {
85 if (s>max_size) throw NetMsgError(NetMsgError::ERROR_TOO_LONG);
86 if (s==0) throw NetMsgError(NetMsgError::ERROR_INVALID_BUFSIZE);
87 buf = new(nothrow) uchar[s];
88 if (!buf) throw NetMsgError(NetMsgError::ERROR_NO_MEM);
89 memset(buf,0,s);
90 buf_len = s;
91 pos = buf;
92 buf_end = buf+(s-1);
93} // end constructor
94
95/** Creates a network message object of the desired size if possible.
96 * @param b pointer to a buffer to initialize the NetMsg.
97 * @param s buffer size
98 * @param copy copy the buffer or use the buffer without copying.
99 */
100NetMsg::NetMsg(uchar *b, uint32 s, bool copy) {
101 if (s>max_size) throw NetMsgError(NetMsgError::ERROR_TOO_LONG);
102 if (s==0) throw NetMsgError(NetMsgError::ERROR_INVALID_BUFSIZE);
103 if (copy) {
104 buf = new(nothrow) uchar[s];
105 if (!buf) throw NetMsgError(NetMsgError::ERROR_NO_MEM);
106 memcpy(buf,b,s);
107 } else {
108 buf=b;
109 if (!buf) throw NetMsgError(NetMsgError::ERROR_NULL_POINTER);
110 } // end if copy
111 buf_len = s;
112 pos = buf;
113 buf_end = buf+(s-1);
114} // end constructor
115
116NetMsg::NetMsg(const NetMsg& n) {
117 buf_len = n.buf_len;
118 if (buf_len == 0)
119 throw NetMsgError(NetMsgError::ERROR_INVALID_BUFSIZE);
120
121 buf = new(nothrow) uchar[buf_len];
122 if (!buf) throw NetMsgError(NetMsgError::ERROR_NO_MEM);
123 memcpy(buf,n.buf,buf_len);
124 pos = buf+(n.pos-n.buf);
125 buf_end = buf+(buf_len-1);
126} // end copy constructor
127
128/** Frees the message buffer. */
129NetMsg::~NetMsg() {
130 if (buf) { delete[] buf; buf= 0; }
131} // end destructor
132
133/** @return the size of the network message buffer. */
134uint32 NetMsg::get_size() const {
135 return buf_len;
136} // end get_size
137
138/** Returns the number of bytes left, that is the number of bytes from the
139 * current position to the end of the buffer.
140 */
141uint32 NetMsg::get_bytes_left() const {
142 if (buf<=pos)
143 {
144 if (pos<=buf_end)
145 return (buf_end-pos)+1;
146 else
147 return 0;
148 }
149 else /// should never happen
150 throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
151} // end get_size
152
153/** Returns the offset of the buffer pointer.
154 * Note that an offset of buf_len means that the pointer is one byte behind
155 * the end of the buffer. This means that you reached the buffer end.
156 * This leads to a get-pos result of buf_len.
157 */
158uint32 NetMsg::get_pos() const {
159 if ((buf<=pos) && (pos<=(buf_end+1)))
160 return (pos-buf);
161 else
162 throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
163} // end get_pos
164
165/** Move pointer to the given offset.
166 * @param p pointer offset
167 * @note if p==buf_len then the pointer is one byte behind the buffer end.
168 * This is correct and signals that all data has been read from the buffer.
169 */
170NetMsg& NetMsg::set_pos(uint32 p) {
171 if (p<=buf_len)
172 {
173 pos = buf+p;
174 return *this;
175 }
176 else
177 throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
178} // end set_pos
179
180/** Move pointer relative to current position.
181 * @param rp offset relative to current position.
182 */
183NetMsg& NetMsg::set_pos_r(int32 rp)
184{
185 if (((pos+rp)>=buf) && ((pos+rp)<=(buf_end+1))) {
186 pos += rp;
187 }
188 else
189 throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
190 return *this;
191} // end set_pos_r
192
193/** Set current position to buffer start. */
194NetMsg& NetMsg::to_start() {
195 pos=buf;
196 return *this;
197} // end to_start
198
199/** Copy n bytes into NetMsg buffer.
200 * @param b source
201 * @param n number of bytes to copy
202 */
203uint32 NetMsg::copy_from(const uchar *b, uint32 n) {
204 return copy_from(b,0,n);
205} // end copy_from
206
207/** Copy bytes into NetMsg buffer.
208 * @param b source
209 * @param start offset of first byte to copy
210 * @param n number of bytes to copy
211 */
212uint32 NetMsg::copy_from(const uchar *b, uint32 start, uint32 n) {
213 if ((n+start)>buf_len) throw NetMsgError(NetMsgError::ERROR_TOO_SHORT);
214 // TH: I BELIEVE THIS IS WRONG !!
215 //memmove(buf,b+start,n);
216 memmove(buf+start,b,n);
217 return n;
218} // end copy_from
219
220/** Copy n bytes from NetMsg buffer into b. If the NetMsg buffer is smaller
221 * than n, less bytes are copied.
222 * @param b destination buffer
223 * @param n number of bytes to be copied
224 * @return number of copied bytes
225 */
226uint32 NetMsg::copy_to(uchar *b, uint32 n) const {
227 try {
228 return copy_to(b,0,n);
229 } catch(NetMsgError& e) {
230 // ERROR, should not happen
231 } // end try-catch
232 return 0;
233} // end copy_to
234
235/** Copy n bytes from NetMsg buffer into b. If the NetMsg buffer is smaller
236 * than n, less bytes are copied.
237 * @param b destination buffer
238 * @param start offset into NetMsg buffer
239 * @param n number of bytes to be copied
240 * @return number of copied bytes
241 */
242uint32 NetMsg::copy_to(uchar *b, uint32 start, uint32 n) const {
243 if (start>=buf_len) throw NetMsgError(NetMsgError::ERROR_INVALID_START_OFFSET);
244 if ((n+start)>buf_len) n=buf_len-start;
245 memmove(b,buf+start,n);
246 return n;
247} // end copy_to
248
249/** returns a pointer to the NetMsg buffer. */
250uchar* NetMsg::get_buffer() const {
251 return buf;
252} // end get_buffer
253
254
255
256/** Decode an uint8 integer.
257 * @param move determines if current position in buffer is changed or not.
258 */
259uint8 NetMsg::decode8(bool move) {
260 register uint8 i;
261 if (pos<=buf_end)
262 {
263 i = *pos;
264 if (move) pos+=1;
265 }
266 else
267 throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
268
269 return i;
270} // end decode uint8
271
272/** Decode an uint16 integer.
273 * @param move determines if current position in buffer is changed or not.
274 */
275uint16 NetMsg::decode16(bool move) {
276 register uint16 i;
277 if ((pos+1)<=buf_end) {
278 i = ntohs(*((uint16*)pos));
279 if (move) pos+=2;
280 }
281 else
282 throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
283 return i;
284} // end decode uint16
285
286/** Decode an uint32 integer.
287 * @param move determines if current position in buffer is changed or not.
288 */
289uint32 NetMsg::decode32(bool move) {
290 register uint32 i;
291 if ((pos+3)<=buf_end) {
292 i = ntohl(*((uint32*)pos));
293 if (move) pos+=4;
294 }
295 else
296 throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
297 return i;
298} // end decode uint32
299
300/** Decode an uint64 integer.
301 * @param move determines if current position in buffer is changed or not.
302 */
303uint64 NetMsg::decode64(bool move) {
304 uint64 hi = 0;
305 uint64 lo = 0;
306 uint64 res = 0;
307 uint32* p = (uint32*)pos;
308 if ((pos+7)<=buf_end) {
309 hi = ntohl(*p);
310 lo = ntohl(*(p+1));
311 res = (hi<<32)+lo;
312 if (move) pos+=8;
313 } else throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
314 return res;
315} // end decode uint64
316
317/** Decode an uint128 integer.
318 * @param move determines if current position in buffer is changed or not.
319 */
320uint128 NetMsg::decode128(bool move) {
321 uint32 word1, word2, word3, word4;
322 uint128 res;
323 word1 = NetMsg::decode32();
324 word2 = NetMsg::decode32();
325 word3 = NetMsg::decode32();
326 word4 = NetMsg::decode32();
327 res.w1 = word1;
328 res.w2 = word2;
329 res.w3 = word3;
330 res.w4 = word4;
331
332 return res;
333} // end decode uint128
334
335/** Encode an uint8 integer.
336 * @param i an uint8
337 * @param move determines if current position in buffer is changed or not.
338 */
339void NetMsg::encode8(uint8 i, bool move) {
340 if (pos<=buf_end) {
341 *pos = i;
342 if (move) pos+=1;
343 } else throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
344} // end encode uint8
345
346/** Encode an uint16 integer.
347 * @param i an uint16
348 * @param move determines if current position in buffer is changed or not.
349 */
350void NetMsg::encode16(uint16 i, bool move) {
351 if ((pos+1)<=buf_end) {
352 *((uint16*)pos) = htons(i);
353 if (move) pos+=2;
354 } else throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
355} // end encode uint16
356
357/** Encode an uint32 integer.
358 * @param i an uint32
359 * @param move determines if current position in buffer is changed or not.
360 */
361void NetMsg::encode32(uint32 i, bool move) {
362 if ((pos+3)<=buf_end) {
363 *((uint32*)pos) = htonl(i);
364 if (move) pos+=4;
365 } else throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
366} // end encode uint32
367
368/** Encode an uint64 integer.
369 * @param i an uint64
370 * @param move determines if current position in buffer is changed or not.
371 */
372void NetMsg::encode64(uint64 i, bool move) {
373 uint32 hi = 0;
374 uint32 lo = 0;
375 uint32* p = (uint32*)pos;
376 if ((pos+7)<=buf_end) {
377 lo = i;
378 hi = (i>>32);
379 *p = htonl(hi);
380 *(p+1) = htonl(lo);
381 if (move) pos+=8;
382 } else throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
383} // end encode uint64
384
385/** Encode an uint128 integer.
386 * @param i an uint128
387 * @param move determines if current position in buffer is changed or not.
388 */
389void NetMsg::encode128(uint128 i, bool move) {
390 encode32(i.w1);
391 encode32(i.w2);
392 encode32(i.w3);
393 encode32(i.w4);
394} // end encode uint128
395
396/** Decode uchars.
397 * @param c pointer to uchar array
398 * @param len uchar array size
399 * @param move determines if current position in buffer is changed or not.
400 */
401void NetMsg::decode(uchar *c, uint32 len, bool move) {
402 if ((pos+(len-1))<=buf_end) {
403 memmove(c,pos,len);
404 if (move) pos+=len;
405 } else throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
406} // end decode uchars
407
408/** Encode uchars.
409 * @param c pointer to uchar array
410 * @param len uchar array size
411 * @param move determines if current position in buffer is changed or not.
412 */
413void NetMsg::encode(const uchar *c, uint32 len, bool move) {
414 if ((pos+(len-1))<=buf_end) {
415 memmove(pos,c,len);
416 if (move) pos+=len;
417 } else throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
418} // end encode uchars
419
420/** Decode string.
421 * @param s string reference
422 * @param len number of bytes to decode
423 * @param move determines if current position in buffer is changed or not.
424 * @return string length.
425 */
426uint32 NetMsg::decode(string& s, uint32 len, bool move) {
427 if (len==0) {
428 s.clear();
429 return 0;
430 } else if ((pos+(len-1))<=buf_end) {
431 s.clear();
432 s.assign((const char*)pos,0,len);
433 if (move) pos+=len;
434 return s.length();
435 } else throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
436} // end decode string
437
438/** Encode string.
439 * @param s string reference
440 * @param move determines if current position in buffer is changed or not.
441 */
442uint32 NetMsg::encode(const string& s, bool move) {
443 uint32 len = s.length();
444 if ((pos+(len-1))<=buf_end) {
445 memmove(pos,s.c_str(),len);
446 if (move) pos+=len;
447 return len;
448 } else throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
449} // end encode string
450
451/** Decode an IPv4 address.
452 * @param in reference to in_addr
453 * @param move determines if current position in buffer is changed or not.
454 */
455void NetMsg::decode(struct in_addr& in, bool move) {
456 //in.s_addr = decode32(move);
457 if ((pos+3)<=buf_end) {
458 in.s_addr = *((uint32*)pos);
459 if (move) pos+=4;
460 }
461 else
462 throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
463} // end decode(in_addr)
464
465/** Encode an IPv4 address.
466 * @param in reference to const in_addr
467 * @param move determines if current position in buffer is changed or not.
468 */
469void NetMsg::encode(const struct in_addr& in, bool move) {
470 //encode32(in.s_addr,move);
471 if ((pos+3)<=buf_end) {
472 *((uint32*)pos) = in.s_addr;
473 if (move) pos+=4;
474 } else throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
475} // end encode(in_addr)
476
477/** Decode an IPv6 address.
478 * @param in reference to in6_addr
479 * @param move determines if current position in buffer is changed or not.
480 */
481void NetMsg::decode(struct in6_addr& in, bool move) {
482 if ((pos+15)<=buf_end) {
483 memmove(in.s6_addr,pos,16);
484 if (move) pos+=16;
485 } else throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
486} // end decode(in6_addr)
487
488/** Encode an IPv6 address.
489 * @param in reference to const in6_addr
490 * @param move determines if current position in buffer is changed or not.
491 */
492void NetMsg::encode(const struct in6_addr& in, bool move) {
493 if ((pos+15)<=buf_end) {
494 memmove(pos,in.s6_addr,16);
495 if (move) pos+=16;
496 } else throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
497} // end encode(in6_addr)
498
499
500
501
502
503
504/** Truncates the buffer at the current position and sets the current
505 * position to buffer start.
506 * @return new buffer size.
507 */
508uint32 NetMsg::truncate() {
509 if ((pos>=buf) && (pos<=(buf_end+1))) {
510 buf_len = (pos-buf);
511 buf_end = pos-1;
512 to_start();
513 } else {
514 throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
515 } // end if buf
516 return buf_len;
517} // end truncate
518
519/** Truncates the buffer at given offset. */
520uint32 NetMsg::truncate(uint32 t) {
521 set_pos(t);
522 return truncate();
523} // end truncate
524
525/** Set padding bytes to 0.
526 * @param len padding length
527 * @param move determines if current position in buffer is changed or not.
528 */
529void NetMsg::padding(uint32 len, bool move) {
530 if (len==0) return;
531 else if ((pos+(len-1))<=buf_end) {
532 memset(pos,0,len);
533 if (move) pos+=len;
534 } else throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
535} // end padding
536
537/** Two network messages are equal if their buffers and states are equal. */
538bool NetMsg::operator==(const NetMsg& n) const
539{
540 // buffer size equal
541 if (buf_len==n.buf_len)
542 {
543 // empty buffers are considered equal
544 if ((buf==NULL) && (n.buf==NULL))
545 return true;
546 else
547 if (buf && n.buf)
548 {
549 // compare buffer content
550 if (memcmp(buf,n.buf,buf_len)==0)
551 {
552 // last check: position must be equal
553 return ((pos-buf)==(n.pos-n.buf));
554 }
555 else
556 return false;
557 }
558 else
559 return false;
560 }
561 else
562 return false;
563} // end operator==
564
565/** Decode NetMsg.
566 * @param m NetMsg reference
567 * @param move determines if current position in buffer is changed or not.
568 */
569void NetMsg::decode(NetMsg& m, bool move) {
570 uint32 len = m.get_size();
571 if ((pos+(len-1))<=buf_end) {
572 // copy buffer
573 m.to_start();
574 memmove(m.buf,pos,len);
575 if (move) pos+=len;
576 } else throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
577} // end decode NetMsg
578
579/** Encode NetMsg.
580 * @param m NetMsg reference
581 * @param len length of data to encode
582 * @param move determines if current position in buffer is changed or not.
583 */
584void NetMsg::encode(const NetMsg& m, uint32 len, bool move) {
585 if ((pos+(len-1))<=buf_end) {
586 memmove(pos,m.buf,len);
587 if (move) pos+=len;
588 } else throw NetMsgError(NetMsgError::ERROR_INVALID_POS);
589} // end encode NetMsg
590
591
592/** hex of dump buffer contents
593 * if startpos is 0, the beginning of the buffer is used
594 */
595ostream&
596NetMsg::hexdump(ostream& os, uchar *startpos, uint32 length) const
597{
598 if (length==0)
599 length=buf_len;
600
601 if (startpos == 0)
602 startpos= buf;
603
604 ios_base::fmtflags flags = os.flags(); // save stream flags
605
606 os << color[blue] << "[dump: start=" << static_cast<void *>(startpos) << ", length:" << length;
607 if (startpos > buf_end)
608 return os << "ERROR: start position behind last buffer byte ]" << color[clear] << endl;
609 else
610 if (startpos < buf)
611 return os << "ERROR: start position before first buffer byte ]" << color[clear] << endl;
612
613 os << endl;
614
615 while ( length > 0 && startpos <= buf_end )
616 {
617 os << setw(4) << startpos-buf << ": ";
618
619 // alphanumeric characters are printed directly
620 for (uint8 index=0; index <= 3; index++) {
621 if ( startpos+index <= buf_end ) {
622 uchar c = *(startpos+index);
623 os << ( isalnum(c) ? static_cast<char>(c) : '.');
624 }
625 else
626 os << ' ';
627 }
628
629 os << " : " << hex << noshowbase;
630
631 // dump hex numbers
632 for (uint8 index=0; index <= 3; index++) {
633 if ( startpos+index <= buf_end )
634 os << setw(2) << setfill('0')
635 << static_cast<unsigned short>(*(startpos+index)) << ' ';
636 else
637 os << " ";
638 }
639
640 os << setfill(' ') << " ";
641
642 // print in base 2
643 for (uint8 index=0; index <= 3 && (startpos+index <= buf_end); index++)
644 {
645 unsigned short val = static_cast<unsigned short>(*(startpos+index));
646
647 for (int i=7; i >= 0; i--)
648 os << ((val >> i) & 1);
649
650 os << ' ';
651 }
652
653 startpos += 4;
654 length = ( length >= 4 ) ? length-4 : 0;
655
656 // reset formatting
657 os.width(0);
658 os << dec << setfill(' ') << endl;
659 }
660
661 os.setf(flags); // reset stream flags
662
663 return os << ']' << color[clear] << endl;
664}
665
666ostream& operator<<(ostream& os, NetMsg& msg)
667{
668
669 ostringstream hexdumpstr;
670 msg.hexdump(hexdumpstr);
671 return os << hexdumpstr.str();
672
673}
674
675//@}
676
677} // end namespace protlib
Note: See TracBrowser for help on using the repository browser.