source: source/ariba/communication/modules/transport/protlib/network_message.cpp@ 5519

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