An Overlay-based
Virtual Network Substrate
SpoVNet

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

Last change on this file since 9686 was 9686, checked in by mies, 8 years ago

put protlib doc to protlib module

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
44#include "logfile.h" // only required for color definitions
45
46namespace protlib {
47
48
49  using namespace protlib::log;
50/** @addtogroup protlib
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.