1 #ifndef _NORM_MESSAGE
2 #define _NORM_MESSAGE
3
4 // PROTOLIB includes
5 #include "protokit.h"
6
7 // standard includes
8 #include <string.h> // for memcpy(), etc
9 #include <math.h>
10 #include <stdlib.h> // for rand(), etc
11
12 #ifdef _WIN32_WCE
13 #include <stdio.h>
14 #else
15 #include <sys/types.h> // for off_t
16 #endif // if/else _WIN32_WCE
17
18 #ifdef SIMULATE
19 // IMPORTANT! This _assumes_ that the message header of interest _will_ be
20 // aligned with a NormSegment (i.e. flush mode of active or passive
21 // is used with flushing after _each_ message written to a
22 // NORM_OBJECT_STREAM!
23 #define SIM_PAYLOAD_MAX (36+8) // MGEN message size + StreamPayloadHeaderLen()
24 #endif // SIMULATE
25
26 const UINT8 NORM_PROTOCOL_VERSION = 1;
27
28 // This value is used in a couple places in the code as
29 // a safety check where some critical timeouts may be
30 // less than expected operating system clock resolution
31 const double NORM_TICK_MIN = 0.100; // in seconds
32
33 // Pick a random number from 0..max
UniformRand(double max)34 inline double UniformRand(double max)
35 {return (max * ((double)rand() / (double)RAND_MAX));}
36
37 // Pick a random number from 0..max
38 // (truncated exponential dist. lambda = log(groupSize) + 1)
ExponentialRand(double max,double groupSize)39 inline double ExponentialRand(double max, double groupSize)
40 {
41 double lambda = log(groupSize) + 1;
42 double x = UniformRand(lambda/max)+lambda/(max*(exp(lambda)-1));
43 return ((max/lambda)*log(x*(exp(lambda)-1)*(max/lambda)));
44 }
45
46 // These are the GRTT estimation bounds set for the current
47 // NORM protocol. (Note that our Grtt quantization routines
48 // are good for the range of 1.0e-06 <= 1000.0 seconds)
49
50 const double NORM_GRTT_MIN = 0.001; // 1 msec
51 const double NORM_GRTT_MAX = 15.0; // 15 sec
52 const double NORM_RTT_MIN = 1.0e-06;
53 const double NORM_RTT_MAX = 1000.0;
54 extern const double NORM_RTT[];
NormUnquantizeRtt(UINT8 qrtt)55 inline double NormUnquantizeRtt(UINT8 qrtt)
56 {return NORM_RTT[qrtt];}
57 UINT8 NormQuantizeRtt(double rtt);
58
59 extern const double NORM_GSIZE[];
NormUnquantizeGroupSize(UINT8 gsize)60 inline double NormUnquantizeGroupSize(UINT8 gsize)
61 {return NORM_GSIZE[gsize];}
62
63 UINT8 NormQuantizeGroupSize(double gsize);
64
NormQuantizeLoss(double lossFraction)65 inline UINT16 NormQuantizeLoss(double lossFraction)
66 {
67 lossFraction = MAX(lossFraction, 0.0);
68 lossFraction = lossFraction*65535.0 + 0.5;
69 lossFraction = MIN(lossFraction, 65535.0);
70 return (UINT16)lossFraction;
71 } // end NormQuantizeLossFraction()
NormUnquantizeLoss(UINT16 lossQuantized)72 inline double NormUnquantizeLoss(UINT16 lossQuantized)
73 {
74 return (((double)lossQuantized) / 65535.0);
75 } // end NormUnquantizeLossFraction()
76
77
78 // Extended precision Norm loss quantize/unquantize with
79 // 32-bit precision (needed for low BER, high bandwidth*delay)
NormQuantizeLoss32(double lossFraction)80 inline UINT32 NormQuantizeLoss32(double lossFraction)
81 {
82 const double MAX_SCALE = (double)((unsigned int)0xffffffff);
83 lossFraction = MAX(lossFraction, 0.0);
84 lossFraction = lossFraction*MAX_SCALE + 0.5;
85 lossFraction = MIN(lossFraction, MAX_SCALE);
86 return (UINT32)lossFraction;
87 } // end NormQuantizeLossFraction32()
NormUnquantizeLoss32(UINT32 lossQuantized)88 inline double NormUnquantizeLoss32(UINT32 lossQuantized)
89 {
90 const double MAX_SCALE = (double)((unsigned int)0xffffffff);
91 return (((double)lossQuantized) / MAX_SCALE);
92 } // end NormUnquantizeLossFraction32()
93
94
NormQuantizeRate(double rate)95 inline UINT16 NormQuantizeRate(double rate)
96 {
97 if (rate <= 0.0) return 0x01; // rate = 0.0
98 UINT16 exponent = (UINT16)log10(rate);
99 UINT16 mantissa = (UINT16)((4096.0/10.0) * (rate / pow(10.0, (double)exponent)) + 0.5);
100 return ((mantissa << 4) | exponent);
101 }
NormUnquantizeRate(UINT16 rate)102 inline double NormUnquantizeRate(UINT16 rate)
103 {
104 double mantissa = ((double)(rate >> 4)) * (10.0/4096.0);
105 double exponent = (double)(rate & 0x000f);
106 return mantissa * pow(10.0, exponent);
107 }
108
109 class NormObjectSize
110 {
111 public:
112 #ifdef WIN32
113 #define _FILE_OFFSET_BITS 64
114 typedef __int64 Offset;
115 #else
116 typedef off_t Offset;
117 #endif // if/else WIN32
NormObjectSize()118 NormObjectSize() : size(0) {}
NormObjectSize(Offset theSize)119 NormObjectSize(Offset theSize) : size(theSize) {}
NormObjectSize(UINT16 msb,UINT32 lsb)120 NormObjectSize(UINT16 msb, UINT32 lsb)
121 {
122 size = (Offset)lsb;
123 #if (_FILE_OFFSET_BITS > 32) && !defined(ANDROID)
124 size |= ((Offset)msb) << 32;
125 #endif
126 }
GetOffset()127 Offset GetOffset() const {return size;}
128 #if (_FILE_OFFSET_BITS > 32) && !defined(ANDROID)
MSB()129 UINT16 MSB() const {return ((UINT16)((size >> 32) & 0x0000ffff));}
130 #else
MSB()131 UINT16 MSB() const {return 0;}
132 #endif
LSB()133 UINT32 LSB() const {return ((UINT32)(size & 0xffffffff));}
134 // Operators
135 bool operator==(const NormObjectSize& b) const
136 {return (b.size == size);}
137 NormObjectSize operator+(const NormObjectSize& b) const
138 {
139 NormObjectSize result(size);
140 result.size += b.size;
141 return result;
142 }
143 void operator+=(const NormObjectSize& b)
144 {size += b.size;}
145 NormObjectSize operator-(const NormObjectSize& b) const
146 {
147 NormObjectSize result(size);
148 result.size -= b.size;
149 return result;
150 }
151 void operator-=(const NormObjectSize& b)
152 {size -= b.size;}
153 void operator+=(Offset increment)
154 {size += increment;}
155 bool operator>(const NormObjectSize& b) const
156 {return (size > b.size);}
157 NormObjectSize operator*(const NormObjectSize& b) const
158 {
159 NormObjectSize result(size);
160 result.size *= b.size;
161 return result;
162 }
163 // Note: this is a "round-upwards" division operator
164 NormObjectSize operator/(const NormObjectSize& b) const
165 {
166 NormObjectSize result(size);
167 result.size /= b.size;
168 result.size = ((result.size * b.size) < size) ? result.size + 1 : result.size;
169 return result;
170 }
171 private:
172 Offset size;
173 }; // end class NormObjectSize
174
175 #ifndef _NORM_API
176 typedef UINT32 NormNodeId;
177 const NormNodeId NORM_NODE_NONE = 0x00000000;
178 const NormNodeId NORM_NODE_ANY = 0xffffffff;
179 #endif // !_NORM_API
180
181 class NormObjectId
182 {
183 public:
NormObjectId()184 NormObjectId() {};
NormObjectId(UINT16 id)185 NormObjectId(UINT16 id) {value = id;}
NormObjectId(const NormObjectId & id)186 NormObjectId(const NormObjectId& id) {value = id.value;}
UINT16()187 operator UINT16() const {return value;}
188 //INT16 operator-(const NormObjectId& id) const
189 // {return ((INT16)(value - id.value));}
190
191 bool operator<(const NormObjectId& id) const
192 {
193 UINT16 diff = value - id.value;
194 return ((diff > 0x8000) || ((0x8000 == diff) && (value > id.value)));
195 }
196
197 bool operator>(const NormObjectId& id) const
198 {
199 UINT16 diff = id.value - value;
200 return ((diff > 0x8000) || ((0x8000 == diff) && (id.value > value)));
201 }
202
203 bool operator<=(const NormObjectId& id) const
204 {return ((value == id.value) || (*this<id));}
205 bool operator>=(const NormObjectId& id) const
206 {return ((value == id.value) || (*this>id));}
207 bool operator==(const NormObjectId& id) const
208 {return (value == id.value);}
209 bool operator!=(const NormObjectId& id) const
210 {return (value != id.value);}
211
212 void operator-=(UINT16 delta)
213 {value -= delta;}
214
215
216 NormObjectId& operator++(int) {value++; return *this;}
217 NormObjectId& operator--(int) {value--; return *this;}
218
219 private:
220 UINT16 value;
221 }; // end class NormObjectId
222
223 class NormBlockId
224 {
225 public:
NormBlockId()226 NormBlockId() {};
NormBlockId(UINT32 id)227 NormBlockId(UINT32 id) {value = id;}
NormBlockId(const NormObjectId & id)228 NormBlockId(const NormObjectId& id) {value = (UINT32)id;}
UINT32()229 operator UINT32() const {return value;}
230 bool operator==(const NormBlockId& id) const
231 {return (value == (UINT32)id);}
232 bool operator!=(const NormBlockId& id) const
233 {return (value != (UINT32)id);}
234
235
236 //INT32 operator-(const NormBlockId& id) const
237 // {return ((INT32)value - id.value);}
238
239 bool operator<(const NormBlockId& id) const
240 {
241 UINT32 diff = value - id.value;
242 return ((diff > 0x80000000) || ((0x80000000 == diff) && (value > id.value)));
243 }
244
245 bool operator>(const NormBlockId& id) const
246 {
247 UINT32 diff = id.value - value;
248 return ((diff > 0x80000000) || ((0x80000000 == diff) && (id.value > value)));
249 }
250
251
252 NormBlockId& operator++(int ) {value++; return *this;}
253
254 private:
255 UINT32 value;
256 }; // end class NormBlockId
257
258 typedef UINT16 NormSymbolId;
259 typedef NormSymbolId NormSegmentId;
260
261 // Base class for NORM header extensions
262 class NormHeaderExtension
263 {
264 public:
265 enum Type
266 {
267 INVALID = 0,
268 FTI = 64, // FEC Object Transmission Information (FTI) extension
269 CC_FEEDBACK = 3, // NORM-CC Feedback extension
270 CC_RATE = 128 // NORM-CC Rate extension
271 };
272
273 NormHeaderExtension();
~NormHeaderExtension()274 virtual ~NormHeaderExtension() {}
Init(UINT32 * theBuffer)275 virtual void Init(UINT32* theBuffer)
276 {
277 buffer = theBuffer;
278 SetType(INVALID);
279 SetWords(0);
280 }
SetType(Type type)281 void SetType(Type type)
282 {((UINT8*)buffer)[TYPE_OFFSET] = (UINT8)type;}
SetWords(UINT8 words)283 void SetWords(UINT8 words)
284 {((UINT8*)buffer)[LENGTH_OFFSET] = words;}
285
AttachBuffer(const UINT32 * theBuffer)286 void AttachBuffer(const UINT32* theBuffer) {buffer = (UINT32*)theBuffer;}
GetBuffer()287 const UINT32* GetBuffer() {return buffer;}
288
GetType()289 Type GetType() const
290 {
291 return buffer ? (Type)(((UINT8*)buffer)[TYPE_OFFSET]) : INVALID;
292 }
GetLength()293 UINT16 GetLength() const
294 {
295 return (buffer ?
296 ((GetType() < 128) ?
297 ((((UINT8*)buffer)[LENGTH_OFFSET]) << 2) : 4) :
298 0);
299 }
300
301 protected:
302 enum
303 {
304 TYPE_OFFSET = 0, // UINT8 offset
305 LENGTH_OFFSET = TYPE_OFFSET + 1 // UINT8 offset
306 };
307 UINT32* buffer;
308 }; // end class NormHeaderExtension
309
310
311 // This class is some we use to set/get
312 // FEC Payload Id content. The FEC Payload
313 // Id format is dependent upon the "fec_id" (FEC Type)
314 // and, in some cases, its field size ("m") parameter
315 class NormPayloadId
316 {
317 public:
318 enum FecType
319 {
320 RS = 2, // fully-specified, general purpose Reed-Solomon
321 RS8 = 5, // fully-specified 8-bit Reed-Solmon per RFC 5510
322 SB = 129 // partially-specified "small block" codes
323 };
IsValid(UINT8 fecId)324 static bool IsValid(UINT8 fecId)
325 {
326 switch (fecId)
327 {
328 case 2:
329 case 5:
330 case 129:
331 return true;
332 default:
333 return false;
334 }
335 }
NormPayloadId(UINT8 fecId,UINT8 m,UINT32 * theBuffer)336 NormPayloadId(UINT8 fecId, UINT8 m, UINT32* theBuffer)
337 : fec_id(fecId), fec_m(m), buffer(theBuffer) {}
NormPayloadId(UINT8 fecId,UINT8 m,const UINT32 * theBuffer)338 NormPayloadId(UINT8 fecId, UINT8 m, const UINT32* theBuffer)
339 : fec_id(fecId), fec_m(m), cbuffer(theBuffer) {}
340
GetLength(UINT8 fecId)341 static UINT16 GetLength(UINT8 fecId)
342 {
343 switch (fecId)
344 {
345 case 2:
346 case 5:
347 return 4;
348 case 129:
349 return 8;
350 default:
351 return 0;
352 }
353 }
354
GetFecBlockMask(UINT8 fecId,UINT8 fecM)355 static UINT32 GetFecBlockMask(UINT8 fecId, UINT8 fecM)
356 {
357 switch (fecId)
358 {
359 case 2:
360 if (8 == fecM)
361 return 0x00ffffff; // 24-bit blockId, 8-bit symbolId
362 else // (16 == fec_m)
363 return 0x0000ffff; // 16-bit blockId,, 16-bit symbolId
364 case 5:
365 return 0x00ffffff; // 24-bit blockId
366 case 129:
367 return 0xffffffff; // 32-bit blockId
368 default:
369 return 0x00000000; // invalid fecId
370 }
371 }
372
SetFecPayloadId(UINT32 blockId,UINT16 symbolId,UINT16 blockLen)373 void SetFecPayloadId(UINT32 blockId, UINT16 symbolId, UINT16 blockLen)
374 {
375 switch (fec_id)
376 {
377 case 2:
378 if (8 == fec_m)
379 {
380 blockId = (blockId << 8) | (symbolId & 0x00ff);
381 *buffer = htonl(blockId); // 3 + 1 bytes
382 }
383 else // (16 == fec_m)
384 {
385 UINT16* payloadId = (UINT16*)buffer;
386 payloadId[0] = htons(blockId); // 2 bytes
387 payloadId[1] = htons(symbolId); // 2 bytes
388 }
389 break;
390 case 5:
391 blockId = (blockId << 8) | (symbolId & 0x00ff);
392 *buffer = htonl(blockId); // 3 + 1 bytes
393 break;
394 case 129:
395 *buffer = htonl(blockId); // 4 bytes
396 UINT16* ptr = (UINT16*)(buffer + 1);
397 ptr[0] = htons(blockLen); // 2 bytes
398 ptr[1] = htons(symbolId); // 2 bytes
399 break;
400 }
401 }
402
403 // Message processing methods
GetFecBlockId()404 NormBlockId GetFecBlockId() const
405 {
406 switch (fec_id)
407 {
408 case 2:
409 if (8 == fec_m)
410 {
411 UINT32 blockId = ntohl(*cbuffer);
412 return (0x00ffffff & (blockId >> 8));
413 }
414 else // (16 == fec_m)
415 {
416 UINT16* blockId = (UINT16*)cbuffer;
417 return ntohs(*blockId);
418 }
419 case 5:
420 {
421 UINT32 blockId = ntohl(*cbuffer);
422 return (0x00ffffff & (blockId >> 8));
423 }
424 case 129:
425 return ntohl(*cbuffer);
426 default:
427 ASSERT(0);
428 return 0;
429 }
430 }
431
GetFecSymbolId()432 UINT16 GetFecSymbolId() const
433 {
434 switch (fec_id)
435 {
436 case 2:
437 if (8 == fec_m)
438 {
439 UINT32 payloadId = ntohl(*cbuffer);
440 return (0x000000ff & payloadId); // lsb is symbolId
441 }
442 else // ( 16 == fec_m)
443 {
444 UINT16* payloadId = (UINT16*)cbuffer;
445 return ntohs(payloadId[1]);
446 }
447 case 5:
448 {
449 UINT32 payloadId = ntohl(*cbuffer);
450 return (0x000000ff & payloadId); // lsb is symbolId
451 }
452 case 129:
453 {
454 UINT16* ptr = (UINT16*)(cbuffer + 1);
455 return ntohs(ptr[1]);
456 }
457 default:
458 ASSERT(0);
459 return 0;
460 }
461 }
462
GetFecBlockLength()463 UINT16 GetFecBlockLength() const
464 {
465 if (129 == fec_id)
466 {
467 UINT16* blockLen = (UINT16*)(cbuffer + 1);
468 return ntohs(*blockLen);
469 }
470 else
471 {
472 return 0;
473 }
474 }
475
476
477
478 private:
479 UINT8 fec_id;
480 UINT8 fec_m;
481 union
482 {
483 UINT32* buffer;
484 const UINT32* cbuffer;
485 };
486 }; // end class NormPayloadId
487
488 class NormMsg
489 {
490 friend class NormMessageQueue;
491
492 public:
493 enum Type
494 {
495 INVALID = 0,
496 INFO = 1,
497 DATA = 2,
498 CMD = 3,
499 NACK = 4,
500 ACK = 5,
501 REPORT = 6
502 };
503 enum {MAX_SIZE = 65536};
504
505 NormMsg();
506
507 // Message building routines
SetVersion(UINT8 version)508 void SetVersion(UINT8 version)
509 {
510 ((UINT8*)buffer)[VERSION_OFFSET] =
511 (((UINT8*)buffer)[VERSION_OFFSET] & 0x0f) | (version << 4);
512 }
SetType(NormMsg::Type type)513 void SetType(NormMsg::Type type)
514 {
515 ((UINT8*)buffer)[TYPE_OFFSET] =
516 (((UINT8*)buffer)[VERSION_OFFSET] & 0xf0) | (type & 0x0f);
517 }
SetSequence(UINT16 sequence)518 void SetSequence(UINT16 sequence)
519 {
520 ((UINT16*)buffer)[SEQUENCE_OFFSET] = htons(sequence);
521 }
SetSourceId(NormNodeId sourceId)522 void SetSourceId(NormNodeId sourceId)
523 {
524 buffer[SOURCE_ID_OFFSET] = htonl(sourceId);
525 }
SetDestination(const ProtoAddress & dst)526 void SetDestination(const ProtoAddress& dst) {addr = dst;}
527
AttachExtension(NormHeaderExtension & extension)528 void AttachExtension(NormHeaderExtension& extension)
529 {
530 extension.Init(buffer+(header_length/4));
531 ExtendHeaderLength(extension.GetLength());
532 }
533
534 // Message processing routines
535 bool InitFromBuffer(UINT16 msgLength);
CopyFromBuffer(const char * theBuffer,unsigned int theLength)536 bool CopyFromBuffer(const char* theBuffer, unsigned int theLength)
537 {
538 if (theLength > MAX_SIZE) return false;
539 memcpy(buffer, theBuffer, theLength);
540 return InitFromBuffer(theLength);
541 }
GetVersion()542 UINT8 GetVersion() const
543 {return (((UINT8*)buffer)[VERSION_OFFSET] >> 4);}
GetType()544 NormMsg::Type GetType() const
545 {return (Type)(((UINT8*)buffer)[TYPE_OFFSET] & 0x0f);}
GetHeaderLength()546 UINT16 GetHeaderLength()
547 {return ((UINT8*)buffer)[HDR_LEN_OFFSET] << 2;}
GetSequence()548 UINT16 GetSequence() const
549 {
550 return (ntohs((((UINT16*)buffer)[SEQUENCE_OFFSET])));
551 }
GetSourceId()552 NormNodeId GetSourceId() const
553 {
554 return (ntohl(buffer[SOURCE_ID_OFFSET]));
555 }
GetDestination()556 const ProtoAddress& GetDestination() const {return addr;}
GetSource()557 const ProtoAddress& GetSource() const {return addr;}
GetBuffer()558 const char* GetBuffer() {return ((char*)buffer);}
GetLength()559 UINT16 GetLength() const {return length;}
560
561 // To retrieve any attached header extensions
HasExtensions()562 bool HasExtensions() const {return (header_length > header_length_base);}
GetNextExtension(NormHeaderExtension & ext)563 bool GetNextExtension(NormHeaderExtension& ext) const
564 {
565 const UINT32* currentBuffer = ext.GetBuffer();
566 UINT16 nextOffset =
567 (UINT16)(currentBuffer ? (currentBuffer - buffer + (ext.GetLength()/4)) :
568 (header_length_base/4));
569 bool result = (nextOffset < (header_length/4));
570 ext.AttachBuffer(result ? (buffer+nextOffset) : (UINT32*)NULL);
571 return result;
572 }
573
574 // For message reception and misc.
AccessBuffer()575 char* AccessBuffer() {return ((char*)buffer);}
AccessAddress()576 ProtoAddress& AccessAddress() {return addr;}
577
GetNext()578 NormMsg* GetNext() {return next;}
579
580 protected:
581 // Common message header offsets
582 // All of our offsets reflect their offset based on the field size!
583 // (So we can efficiently dereference msg fields with proper alignment)
584 enum
585 {
586 VERSION_OFFSET = 0,
587 TYPE_OFFSET = VERSION_OFFSET,
588 HDR_LEN_OFFSET = VERSION_OFFSET+1,
589 SEQUENCE_OFFSET = (HDR_LEN_OFFSET+1)/2,
590 SOURCE_ID_OFFSET = ((SEQUENCE_OFFSET*2)+2)/4,
591 MSG_OFFSET = (SOURCE_ID_OFFSET*4)+4
592 };
593
SetBaseHeaderLength(UINT16 len)594 void SetBaseHeaderLength(UINT16 len)
595 {
596 ((UINT8*)buffer)[HDR_LEN_OFFSET] = len >> 2;
597 length = header_length_base = header_length = len;
598 }
ExtendHeaderLength(UINT16 len)599 void ExtendHeaderLength(UINT16 len)
600 {
601 header_length += len;
602 length += len;
603 ((UINT8*)buffer)[HDR_LEN_OFFSET] = header_length >> 2;
604 }
605
606 UINT32 buffer[MAX_SIZE / sizeof(UINT32)];
607 UINT16 length; // in bytes
608 UINT16 header_length;
609 UINT16 header_length_base;
610 ProtoAddress addr; // src or dst address
611
612 NormMsg* prev;
613 NormMsg* next;
614 }; // end class NormMsg
615
616 // "NormObjectMsg" is a base class for the similar "NormInfoMsg"
617 // and "NormDataMsg" types
618
619 class NormObjectMsg : public NormMsg
620 {
621 friend class NormMsg;
622 public:
623 enum Flag
624 {
625 FLAG_REPAIR = 0x01,
626 FLAG_EXPLICIT = 0x02,
627 FLAG_INFO = 0x04,
628 FLAG_UNRELIABLE = 0x08,
629 FLAG_FILE = 0x10,
630 FLAG_STREAM = 0x20
631 //FLAG_MSG_START = 0x40 deprecated
632 };
GetInstanceId()633 UINT16 GetInstanceId() const
634 {return (ntohs(((UINT16*)buffer)[INSTANCE_ID_OFFSET]));}
GetGrtt()635 UINT8 GetGrtt() const
636 {return ((UINT8*)buffer)[GRTT_OFFSET];}
GetBackoffFactor()637 UINT8 GetBackoffFactor() const
638 {return ((((UINT8*)buffer)[GSIZE_OFFSET] >> 4) & 0x0f);}
GetGroupSize()639 UINT8 GetGroupSize() const
640 {return (((UINT8*)buffer)[GSIZE_OFFSET] & 0x0f);}
FlagIsSet(NormObjectMsg::Flag flag)641 bool FlagIsSet(NormObjectMsg::Flag flag) const
642 {return (0 != (flag & ((UINT8*)buffer)[FLAGS_OFFSET]));}
IsStream()643 bool IsStream() const
644 {return FlagIsSet(FLAG_STREAM);}
GetFecId()645 UINT8 GetFecId() const
646 {return ((UINT8*)buffer)[FEC_ID_OFFSET];}
GetObjectId()647 NormObjectId GetObjectId() const
648 {return (ntohs(((UINT16*)buffer)[OBJ_ID_OFFSET]));}
649
650 // Message building routines
SetInstanceId(UINT16 instanceId)651 void SetInstanceId(UINT16 instanceId)
652 {((UINT16*)buffer)[INSTANCE_ID_OFFSET] = htons(instanceId);}
SetGrtt(UINT8 grtt)653 void SetGrtt(UINT8 grtt) {((UINT8*)buffer)[GRTT_OFFSET] = grtt;}
SetBackoffFactor(UINT8 backoff)654 void SetBackoffFactor(UINT8 backoff)
655 {((UINT8*)buffer)[BACKOFF_OFFSET] = (((UINT8*)buffer)[GSIZE_OFFSET] & 0x0f) | (backoff << 4);}
SetGroupSize(UINT8 gsize)656 void SetGroupSize(UINT8 gsize)
657 {((UINT8*)buffer)[GSIZE_OFFSET] = (((UINT8*)buffer)[GSIZE_OFFSET] & 0xf0) | gsize;}
ResetFlags()658 void ResetFlags() {((UINT8*)buffer)[FLAGS_OFFSET] = 0;}
SetFlag(NormObjectMsg::Flag flag)659 void SetFlag(NormObjectMsg::Flag flag) {((UINT8*)buffer)[FLAGS_OFFSET] |= flag;}
SetObjectId(const NormObjectId & objectId)660 void SetObjectId(const NormObjectId& objectId)
661 {((UINT16*)buffer)[OBJ_ID_OFFSET] = htons((UINT16)objectId);}
662
663 protected:
664 enum
665 {
666 INSTANCE_ID_OFFSET = MSG_OFFSET/2,
667 GRTT_OFFSET = (INSTANCE_ID_OFFSET*2)+2,
668 BACKOFF_OFFSET = GRTT_OFFSET+1,
669 GSIZE_OFFSET = BACKOFF_OFFSET,
670 FLAGS_OFFSET = GSIZE_OFFSET+1,
671 FEC_ID_OFFSET = FLAGS_OFFSET+1,
672 OBJ_ID_OFFSET = (FEC_ID_OFFSET+1)/2,
673 OBJ_MSG_OFFSET = (OBJ_ID_OFFSET*2)+2
674 };
675 }; // end class NormObjectMsg
676
677
678 // This FEC Object Transmission Information assumes "fec_id" == 2 (RFC 5510)
679 // (This is an m-bit Reed-Solomon codec (we use it in NORM for m == 16)
680 class NormFtiExtension2 : public NormHeaderExtension
681 {
682 public:
683 // To build the FTI Header Extension
Init(UINT32 * theBuffer)684 virtual void Init(UINT32* theBuffer)
685 {
686 AttachBuffer(theBuffer);
687 SetType(FTI); // HET = 64
688 SetWords(4);
689 }
SetObjectSize(const NormObjectSize & objectSize)690 void SetObjectSize(const NormObjectSize& objectSize)
691 {
692 ((UINT16*)buffer)[OBJ_SIZE_MSB_OFFSET] = htons(objectSize.MSB());
693 buffer[OBJ_SIZE_LSB_OFFSET] = htonl(objectSize.LSB());
694 }
SetFecFieldSize(UINT8 numBits)695 void SetFecFieldSize(UINT8 numBits)
696 {((UINT8*)buffer)[FEC_M_OFFSET] = numBits;} // usually 16 for this FTI
SetFecGroupSize(UINT8 symbolsPerPkt)697 void SetFecGroupSize(UINT8 symbolsPerPkt)
698 {((UINT8*)buffer)[FEC_G_OFFSET] = symbolsPerPkt;} // usually one
SetSegmentSize(UINT16 segmentSize)699 void SetSegmentSize(UINT16 segmentSize)
700 {((UINT16*)buffer)[SEG_SIZE_OFFSET] = htons(segmentSize);}
SetFecMaxBlockLen(UINT16 ndata)701 void SetFecMaxBlockLen(UINT16 ndata)
702 {((UINT16*)buffer)[FEC_NDATA_OFFSET] = htons(ndata);}
SetFecNumParity(UINT16 nparity)703 void SetFecNumParity(UINT16 nparity)
704 {((UINT16*)buffer)[FEC_NPARITY_OFFSET] = htons(nparity);}
705
706 // FTI Extension parsing methods
GetObjectSize()707 NormObjectSize GetObjectSize() const
708 {
709 return NormObjectSize(ntohs(((UINT16*)buffer)[OBJ_SIZE_MSB_OFFSET]),
710 ntohl(buffer[OBJ_SIZE_LSB_OFFSET]));
711 }
GetFecFieldSize()712 UINT8 GetFecFieldSize() const
713 {return ((UINT8*)buffer)[FEC_M_OFFSET];} // usually 16 for this FTI
GetFecGroupSize()714 UINT8 GetFecGroupSize() const
715 {return ((UINT8*)buffer)[FEC_G_OFFSET];} // usually 1
GetSegmentSize()716 UINT16 GetSegmentSize() const
717 {return (ntohs(((UINT16*)buffer)[SEG_SIZE_OFFSET]));}
GetFecMaxBlockLen()718 UINT16 GetFecMaxBlockLen() const
719 {return (ntohs(((UINT16*)buffer)[FEC_NDATA_OFFSET]));}
GetFecNumParity()720 UINT16 GetFecNumParity() const
721 {return (ntohs(((UINT16*)buffer)[FEC_NPARITY_OFFSET]));}
722
723 private:
724 enum
725 {
726 OBJ_SIZE_MSB_OFFSET = (LENGTH_OFFSET + 1)/2,
727 OBJ_SIZE_LSB_OFFSET = ((OBJ_SIZE_MSB_OFFSET*2)+2)/4,
728 FEC_M_OFFSET = ((OBJ_SIZE_LSB_OFFSET*4)+4),
729 FEC_G_OFFSET = FEC_M_OFFSET + 1,
730 SEG_SIZE_OFFSET = (FEC_G_OFFSET+1)/2,
731 FEC_NDATA_OFFSET = ((SEG_SIZE_OFFSET*2)+2)/2,
732 FEC_NPARITY_OFFSET = ((FEC_NDATA_OFFSET*2)+2)/2
733 };
734 }; // end class NormFtiExtension2
735
736
737 // This FEC Object Transmission Information assumes "fec_id" == 5 (RFC 5510)
738 // (this is the fully-defined 8-bit Reed-Solomon codec)
739 class NormFtiExtension5 : public NormHeaderExtension
740 {
741 public:
742 // To build the fec_id=5 FTI Header Extension
Init(UINT32 * theBuffer)743 virtual void Init(UINT32* theBuffer)
744 {
745 AttachBuffer(theBuffer);
746 SetType(FTI); // HET = 64
747 SetWords(3);
748 }
SetObjectSize(const NormObjectSize & objectSize)749 void SetObjectSize(const NormObjectSize& objectSize)
750 {
751 ((UINT16*)buffer)[OBJ_SIZE_MSB_OFFSET] = htons(objectSize.MSB());
752 buffer[OBJ_SIZE_LSB_OFFSET] = htonl(objectSize.LSB());
753 }
SetSegmentSize(UINT16 segmentSize)754 void SetSegmentSize(UINT16 segmentSize)
755 {((UINT16*)buffer)[SEG_SIZE_OFFSET] = htons(segmentSize);}
SetFecMaxBlockLen(UINT8 ndata)756 void SetFecMaxBlockLen(UINT8 ndata)
757 {((UINT8*)buffer)[FEC_NDATA_OFFSET] = ndata;}
SetFecNumParity(UINT8 nparity)758 void SetFecNumParity(UINT8 nparity)
759 {((UINT8*)buffer)[FEC_NPARITY_OFFSET] = nparity;}
760
761 // FTI Extension parsing methods
GetObjectSize()762 NormObjectSize GetObjectSize() const
763 {
764 return NormObjectSize(ntohs(((UINT16*)buffer)[OBJ_SIZE_MSB_OFFSET]),
765 ntohl(buffer[OBJ_SIZE_LSB_OFFSET]));
766 }
GetSegmentSize()767 UINT16 GetSegmentSize() const
768 {return (ntohs(((UINT16*)buffer)[SEG_SIZE_OFFSET]));}
GetFecMaxBlockLen()769 UINT8 GetFecMaxBlockLen() const
770 {return (((UINT8*)buffer)[FEC_NDATA_OFFSET]);}
GetFecNumParity()771 UINT8 GetFecNumParity() const
772 {return (((UINT8*)buffer)[FEC_NPARITY_OFFSET]);}
773
774 private:
775 enum
776 {
777 OBJ_SIZE_MSB_OFFSET = (LENGTH_OFFSET + 1)/2,
778 OBJ_SIZE_LSB_OFFSET = ((OBJ_SIZE_MSB_OFFSET*2)+2)/4,
779 SEG_SIZE_OFFSET = ((OBJ_SIZE_LSB_OFFSET*4)+4)/2,
780 FEC_NDATA_OFFSET = ((SEG_SIZE_OFFSET+1)*2),
781 FEC_NPARITY_OFFSET = (FEC_NDATA_OFFSET+1)
782 };
783 }; // end class NormFtiExtension5
784
785
786 // This FEC Object Transmission Information assumes "fec_id" == 129
787 class NormFtiExtension129 : public NormHeaderExtension
788 {
789 public:
790 // To build the FTI Header Extension
791 // (TBD) allow for different "fec_id" types in the future
Init(UINT32 * theBuffer)792 virtual void Init(UINT32* theBuffer)
793 {
794 AttachBuffer(theBuffer);
795 SetType(FTI);
796 SetWords(4);
797 }
SetFecInstanceId(UINT16 instanceId)798 void SetFecInstanceId(UINT16 instanceId)
799 { ((UINT16*)buffer)[FEC_INSTANCE_OFFSET] = htons(instanceId);}
SetFecMaxBlockLen(UINT16 ndata)800 void SetFecMaxBlockLen(UINT16 ndata)
801 {((UINT16*)buffer)[FEC_NDATA_OFFSET] = htons(ndata);}
SetFecNumParity(UINT16 nparity)802 void SetFecNumParity(UINT16 nparity)
803 {((UINT16*)buffer)[FEC_NPARITY_OFFSET] = htons(nparity);}
SetSegmentSize(UINT16 segmentSize)804 void SetSegmentSize(UINT16 segmentSize)
805 {((UINT16*)buffer)[SEG_SIZE_OFFSET] = htons(segmentSize);}
SetObjectSize(const NormObjectSize & objectSize)806 void SetObjectSize(const NormObjectSize& objectSize)
807 {
808 ((UINT16*)buffer)[OBJ_SIZE_MSB_OFFSET] = htons(objectSize.MSB());
809 buffer[OBJ_SIZE_LSB_OFFSET] = htonl(objectSize.LSB());
810 }
811
812 // FTI Extension parsing methods
GetFecInstanceId()813 UINT16 GetFecInstanceId() const
814 {
815 return (ntohs(((UINT16*)buffer)[FEC_INSTANCE_OFFSET]));
816 }
GetFecMaxBlockLen()817 UINT16 GetFecMaxBlockLen() const
818 {return (ntohs(((UINT16*)buffer)[FEC_NDATA_OFFSET]));}
GetFecNumParity()819 UINT16 GetFecNumParity() const
820 {return (ntohs(((UINT16*)buffer)[FEC_NPARITY_OFFSET]));}
GetSegmentSize()821 UINT16 GetSegmentSize() const
822 {return (ntohs(((UINT16*)buffer)[SEG_SIZE_OFFSET]));}
GetObjectSize()823 NormObjectSize GetObjectSize() const
824 {
825 return NormObjectSize(ntohs(((UINT16*)buffer)[OBJ_SIZE_MSB_OFFSET]),
826 ntohl(buffer[OBJ_SIZE_LSB_OFFSET]));
827 }
828
829 private:
830 enum
831 {
832 OBJ_SIZE_MSB_OFFSET = (LENGTH_OFFSET + 1)/2,
833 OBJ_SIZE_LSB_OFFSET = ((OBJ_SIZE_MSB_OFFSET*2)+2)/4,
834 FEC_INSTANCE_OFFSET = ((OBJ_SIZE_LSB_OFFSET*4)+4)/2,
835 SEG_SIZE_OFFSET = ((FEC_INSTANCE_OFFSET*2)+2)/2,
836 FEC_NDATA_OFFSET = ((SEG_SIZE_OFFSET*2)+2)/2,
837 FEC_NPARITY_OFFSET = ((FEC_NDATA_OFFSET*2)+2)/2
838 };
839 }; // end class NormFtiExtension129
840
841
842 class NormInfoMsg : public NormObjectMsg
843 {
844 public:
Init()845 void Init()
846 {
847 SetType(INFO);
848 SetBaseHeaderLength(INFO_HEADER_LEN);
849 ResetFlags();
850 }
851
GetInfoLen()852 UINT16 GetInfoLen() const
853 {return (length - header_length);}
GetInfo()854 const char* GetInfo() const
855 {return (((char*)buffer) + header_length);}
856
857 // Message building methods (in addition to NormObjectMsg fields)
SetFecId(UINT8 fecId)858 void SetFecId(UINT8 fecId)
859 {((UINT8*)buffer)[FEC_ID_OFFSET] = fecId;}
860
861 // Note: apply any header extensions first
SetInfo(const char * data,UINT16 size)862 void SetInfo(const char* data, UINT16 size)
863 {
864 memcpy(((char*)buffer)+header_length, data, size);
865 length = size + header_length;
866 }
867
868 private:
869 enum {INFO_HEADER_LEN = OBJ_MSG_OFFSET};
870 }; // end class NormInfoMsg
871
872 class NormDataMsg : public NormObjectMsg
873 {
874 public:
Init()875 void Init()
876 {
877 SetType(DATA);
878 ResetFlags();
879 // Note: for NORM_DATA base header length depends on fec_id
880 }
881
882 // Message building methods (in addition to NormObjectMsg fields)
SetFecId(UINT8 fecId)883 void SetFecId(UINT8 fecId)
884 {
885 ((UINT8*)buffer)[FEC_ID_OFFSET] = fecId;
886 SetBaseHeaderLength(OBJ_MSG_OFFSET + NormPayloadId::GetLength(fecId));
887 }
888
SetFecPayloadId(UINT8 fecId,UINT32 blockId,UINT16 symbolId,UINT16 blockLen,UINT8 m)889 void SetFecPayloadId(UINT8 fecId, UINT32 blockId, UINT16 symbolId, UINT16 blockLen, UINT8 m)
890 {
891 NormPayloadId payloadId(fecId, m, buffer + FEC_PAYLOAD_ID_OFFSET);
892 payloadId.SetFecPayloadId(blockId, symbolId, blockLen);
893 }
894
895 // Two ways to set payload content:
896 // 1) Directly access payload to copy segment, then set data message length
897 // (Note NORM_STREAM_OBJECT segments must already include "payload_len"
898 // and "payload_offset" with the "payload_data"
AccessPayload()899 char* AccessPayload() {return (((char*)buffer)+header_length);}
900 // For NORM_STREAM_OBJECT segments, "dataLength" must include the PAYLOAD_HEADER_LENGTH
SetPayloadLength(UINT16 payloadLength)901 void SetPayloadLength(UINT16 payloadLength)
902 {length = header_length + payloadLength;}
903 // Set "payload" directly (useful for FEC parity segments)
SetPayload(char * payload,UINT16 payloadLength)904 void SetPayload(char* payload, UINT16 payloadLength)
905 {
906 memcpy(((char*)buffer)+header_length, payload, payloadLength);
907 length = header_length + payloadLength;
908 }
909 // AccessPayloadData() (useful for setting ZERO padding)
AccessPayloadData()910 char* AccessPayloadData()
911 {
912 UINT16 payloadIndex = IsStream() ? header_length+PAYLOAD_DATA_OFFSET : header_length;
913 return (((char*)buffer)+payloadIndex);
914 }
915
916 // Message processing methods
GetFecBlockId(UINT8 m)917 NormBlockId GetFecBlockId(UINT8 m) const
918 {
919 NormPayloadId payloadId(GetFecId(), m, buffer + FEC_PAYLOAD_ID_OFFSET);
920 return payloadId.GetFecBlockId();
921 }
GetFecSymbolId(UINT8 m)922 UINT16 GetFecSymbolId(UINT8 m) const
923 {
924 NormPayloadId payloadId(GetFecId(), m, buffer + FEC_PAYLOAD_ID_OFFSET);
925 return payloadId.GetFecSymbolId();
926 }
GetFecBlockLength()927 UINT16 GetFecBlockLength() const
928 {
929 NormPayloadId payloadId(GetFecId(), 8, buffer + FEC_PAYLOAD_ID_OFFSET);
930 return payloadId.GetFecBlockLength();
931 }
932
933 // Note: For NORM_OBJECT_STREAM, "payload" includes "payload_reserved",
934 // "payload_len", "payload_offset", and "payload_data" fields
935 // For NORM_OBJECT_FILE and NORM_OBJECT_DATA, "payload" includes
936 // "payload_data" only
GetPayload()937 const char* GetPayload()
938 const {return (((char*)buffer)+header_length);}
GetPayloadLength()939 UINT16 GetPayloadLength()
940 const {return (length - header_length);}
941
GetPayloadData()942 const char* GetPayloadData() const
943 {
944 UINT16 dataIndex = IsStream() ? header_length+PAYLOAD_DATA_OFFSET : header_length;
945 return (((char*)buffer)+dataIndex);
946 }
GetPayloadDataLength()947 UINT16 GetPayloadDataLength() const
948 {
949 UINT16 dataIndex = IsStream() ? header_length+PAYLOAD_DATA_OFFSET : header_length;
950 return (length - dataIndex);
951 }
952
953 // These routines are only applicable to messages containing NORM_OBJECT_STREAM content
954 // Some static helper routines for reading/writing embedded payload length/offsets
GetStreamPayloadHeaderLength()955 static UINT16 GetStreamPayloadHeaderLength()
956 {return (PAYLOAD_DATA_OFFSET);}
957
WriteStreamPayloadLength(char * payload,UINT16 len)958 static void WriteStreamPayloadLength(char* payload, UINT16 len)
959 {
960 UINT16 temp16 = htons(len);
961 memcpy(payload+PAYLOAD_LENGTH_OFFSET, &temp16, 2);
962 }
WriteStreamPayloadMsgStart(char * payload,UINT16 msgStartOffset)963 static void WriteStreamPayloadMsgStart(char* payload, UINT16 msgStartOffset)
964 {
965 UINT16 temp16 = htons(msgStartOffset);
966 memcpy(payload+PAYLOAD_MSG_START_OFFSET, &temp16, 2);
967 }
WriteStreamPayloadOffset(char * payload,UINT32 offset)968 static void WriteStreamPayloadOffset(char* payload, UINT32 offset)
969 {
970 UINT32 temp32 = htonl(offset);
971 memcpy(payload+PAYLOAD_OFFSET_OFFSET, &temp32, 4);
972 }
ReadStreamPayloadLength(const char * payload)973 static UINT16 ReadStreamPayloadLength(const char* payload)
974 {
975 UINT16 temp16;
976 memcpy(&temp16, payload+PAYLOAD_LENGTH_OFFSET, 2);
977 return (ntohs(temp16));
978 }
ReadStreamPayloadMsgStart(const char * payload)979 static UINT16 ReadStreamPayloadMsgStart(const char* payload)
980 {
981 UINT16 temp16;
982 memcpy(&temp16, payload+PAYLOAD_MSG_START_OFFSET, 2);
983 return (ntohs(temp16));
984 }
ReadStreamPayloadOffset(const char * payload)985 static UINT32 ReadStreamPayloadOffset(const char* payload)
986 {
987 UINT32 temp32;
988 memcpy(&temp32, payload+PAYLOAD_OFFSET_OFFSET, 4);
989 return (ntohl(temp32));
990 }
991
992 private:
993 enum
994 {
995 FEC_PAYLOAD_ID_OFFSET = OBJ_MSG_OFFSET/4
996 };
997
998 // IMPORTANT: These offsets are _relative_ to the NORM_DATA header
999 // (incl. any extensions)
1000 enum
1001 {
1002 PAYLOAD_LENGTH_OFFSET = 0,
1003 PAYLOAD_MSG_START_OFFSET = PAYLOAD_LENGTH_OFFSET+2,
1004 PAYLOAD_OFFSET_OFFSET = PAYLOAD_MSG_START_OFFSET+2,
1005 PAYLOAD_DATA_OFFSET = PAYLOAD_OFFSET_OFFSET+4
1006 };
1007 }; // end class NormDataMsg
1008
1009
1010 class NormCmdMsg : public NormMsg
1011 {
1012 public:
1013 enum Flavor
1014 {
1015 INVALID = 0,
1016 FLUSH = 1,
1017 EOT = 2,
1018 SQUELCH = 3,
1019 CC = 4,
1020 REPAIR_ADV = 5,
1021 ACK_REQ = 6,
1022 APPLICATION = 7
1023 };
1024
1025 // Message build
SetInstanceId(UINT16 instanceId)1026 void SetInstanceId(UINT16 instanceId)
1027 {((UINT16*)buffer)[INSTANCE_ID_OFFSET] = htons(instanceId);}
SetGrtt(UINT8 quantizedGrtt)1028 void SetGrtt(UINT8 quantizedGrtt)
1029 {((UINT8*)buffer)[GRTT_OFFSET] = quantizedGrtt;}
SetBackoffFactor(UINT8 backoff)1030 void SetBackoffFactor(UINT8 backoff)
1031 {((UINT8*)buffer)[BACKOFF_OFFSET] = (((UINT8*)buffer)[GSIZE_OFFSET] & 0x0f) | (backoff << 4);}
SetGroupSize(UINT8 gsize)1032 void SetGroupSize(UINT8 gsize)
1033 {((UINT8*)buffer)[GSIZE_OFFSET] = (((UINT8*)buffer)[GSIZE_OFFSET] & 0xf0) | gsize;}
SetFlavor(NormCmdMsg::Flavor flavor)1034 void SetFlavor(NormCmdMsg::Flavor flavor)
1035 {((UINT8*)buffer)[FLAVOR_OFFSET] = (UINT8)flavor;}
1036
1037 // Message parse
GetInstanceId()1038 UINT16 GetInstanceId() const
1039 {return (ntohs(((UINT16*)buffer)[INSTANCE_ID_OFFSET]));}
GetGrtt()1040 UINT8 GetGrtt() const
1041 {return ((UINT8*)buffer)[GRTT_OFFSET];}
GetBackoffFactor()1042 UINT8 GetBackoffFactor() const
1043 {return ((((UINT8*)buffer)[GSIZE_OFFSET] >> 4) & 0x0f);}
GetGroupSize()1044 UINT8 GetGroupSize() const
1045 {return (((UINT8*)buffer)[GSIZE_OFFSET] & 0x0f);}
GetFlavor()1046 NormCmdMsg::Flavor GetFlavor() const
1047 {return (Flavor)((UINT8*)buffer)[FLAVOR_OFFSET];}
1048
1049 protected:
1050 friend class NormMsg;
1051 enum
1052 {
1053 INSTANCE_ID_OFFSET = MSG_OFFSET/2,
1054 GRTT_OFFSET = (INSTANCE_ID_OFFSET+1)*2,
1055 BACKOFF_OFFSET = GRTT_OFFSET + 1,
1056 GSIZE_OFFSET = BACKOFF_OFFSET,
1057 FLAVOR_OFFSET = GSIZE_OFFSET + 1
1058 };
1059 }; // end class NormCmdMsg
1060
1061 class NormCmdFlushMsg : public NormCmdMsg
1062 {
1063 friend class NormMsg;
1064
1065 public:
Init()1066 void Init()
1067 {
1068 SetType(CMD);
1069 SetFlavor(FLUSH);
1070 // base header length depends on fec payload id
1071 }
1072
SetFecId(UINT8 fecId)1073 void SetFecId(UINT8 fecId)
1074 {((UINT8*)buffer)[FEC_ID_OFFSET] = fecId;}
SetObjectId(const NormObjectId & objectId)1075 void SetObjectId(const NormObjectId& objectId)
1076 {((UINT16*)buffer)[OBJ_ID_OFFSET] = htons((UINT16)objectId);}
SetFecPayloadId(UINT8 fecId,UINT32 blockId,UINT16 symbolId,UINT16 blockLen,UINT8 m)1077 void SetFecPayloadId(UINT8 fecId, UINT32 blockId, UINT16 symbolId, UINT16 blockLen, UINT8 m)
1078 {
1079 SetFecId(fecId);
1080 SetBaseHeaderLength(4*FEC_PAYLOAD_ID_OFFSET + NormPayloadId::GetLength(fecId));
1081 NormPayloadId payloadId(fecId, m, buffer + FEC_PAYLOAD_ID_OFFSET);
1082 payloadId.SetFecPayloadId(blockId, symbolId, blockLen);
1083 ResetAckingNodeList();
1084 }
1085
ResetAckingNodeList()1086 void ResetAckingNodeList()
1087 {length = header_length;}
AppendAckingNode(NormNodeId nodeId,UINT16 segmentSize)1088 bool AppendAckingNode(NormNodeId nodeId, UINT16 segmentSize)
1089 {
1090 if ((length-header_length+ 4) > segmentSize) return false;
1091 buffer[length/4] = htonl((UINT32)nodeId);
1092 length += 4;
1093 return true;
1094 }
1095
1096 // Message processing
GetFecId()1097 UINT8 GetFecId() const
1098 {return ((UINT8*)buffer)[FEC_ID_OFFSET];}
GetObjectId()1099 NormObjectId GetObjectId() const
1100 { return ntohs(((UINT16*)buffer)[OBJ_ID_OFFSET]);}
GetFecBlockId(UINT8 m)1101 NormBlockId GetFecBlockId(UINT8 m) const
1102 {
1103 NormPayloadId payloadId(GetFecId(), m, buffer + FEC_PAYLOAD_ID_OFFSET);
1104 return payloadId.GetFecBlockId();
1105 }
GetFecSymbolId(UINT8 m)1106 UINT16 GetFecSymbolId(UINT8 m) const
1107 {
1108 NormPayloadId payloadId(GetFecId(), m, buffer + FEC_PAYLOAD_ID_OFFSET);
1109 return payloadId.GetFecSymbolId();
1110 }
GetFecBlockLength()1111 UINT16 GetFecBlockLength() const
1112 {
1113 NormPayloadId payloadId(GetFecId(), 8, buffer + FEC_PAYLOAD_ID_OFFSET);
1114 return payloadId.GetFecBlockLength();
1115 }
1116
GetAckingNodeCount()1117 UINT16 GetAckingNodeCount() const
1118 {return ((length - header_length) >> 2);}
GetAckingNodeList()1119 const UINT32* GetAckingNodeList() const
1120 {return (buffer+(header_length/4));}
GetAckingNodeId(UINT16 index)1121 NormNodeId GetAckingNodeId(UINT16 index) const
1122 {return (ntohl(buffer[(header_length/4)+index]));}
1123
1124 private:
1125 enum
1126 {
1127 FEC_ID_OFFSET = FLAVOR_OFFSET + 1,
1128 OBJ_ID_OFFSET = (FEC_ID_OFFSET + 1)/2,
1129 FEC_PAYLOAD_ID_OFFSET = ((OBJ_ID_OFFSET+1)*2)/4
1130 };
1131 }; // end class NormCmdFlushMsg
1132
1133 class NormCmdEotMsg : public NormCmdMsg
1134 {
1135 public:
Init()1136 void Init()
1137 {
1138 SetType(CMD);
1139 SetFlavor(EOT);
1140 SetBaseHeaderLength(EOT_HEADER_LEN);
1141 memset(((char*)buffer)+RESERVED_OFFSET, 0, 3);
1142 }
1143 private:
1144 enum
1145 {
1146 RESERVED_OFFSET = FLAVOR_OFFSET + 1,
1147 EOT_HEADER_LEN = RESERVED_OFFSET + 3
1148 };
1149 }; // end class NormCmdEotMsg
1150
1151
1152 class NormCmdSquelchMsg : public NormCmdMsg
1153 {
1154 public:
1155 // Message building
Init(UINT8 fecId)1156 void Init(UINT8 fecId)
1157 {
1158 SetType(CMD);
1159 SetFlavor(SQUELCH);
1160 SetFecId(fecId); // default "fec_id"
1161 SetBaseHeaderLength(4*FEC_PAYLOAD_ID_OFFSET + NormPayloadId::GetLength(fecId));
1162 }
SetFecId(UINT8 fecId)1163 void SetFecId(UINT8 fecId)
1164 {((UINT8*)buffer)[FEC_ID_OFFSET] = fecId;}
SetObjectId(const NormObjectId & objectId)1165 void SetObjectId(const NormObjectId& objectId)
1166 {((UINT16*)buffer)[OBJ_ID_OFFSET] = htons((UINT16)objectId);}
SetFecPayloadId(UINT8 fecId,UINT32 blockId,UINT16 symbolId,UINT16 blockLen,UINT8 m)1167 void SetFecPayloadId(UINT8 fecId, UINT32 blockId, UINT16 symbolId, UINT16 blockLen, UINT8 m)
1168 {
1169 SetFecId(fecId);
1170 SetBaseHeaderLength(4*FEC_PAYLOAD_ID_OFFSET + NormPayloadId::GetLength(fecId));
1171 NormPayloadId payloadId(fecId, m, buffer + FEC_PAYLOAD_ID_OFFSET);
1172 payloadId.SetFecPayloadId(blockId, symbolId, blockLen);
1173 ResetInvalidObjectList();
1174 }
ResetInvalidObjectList()1175 void ResetInvalidObjectList()
1176 {length = header_length;}
1177
1178 // Note must apply any header extensions _before_ appending payload.
AppendInvalidObject(NormObjectId objectId,UINT16 segmentSize)1179 bool AppendInvalidObject(NormObjectId objectId, UINT16 segmentSize)
1180 {
1181 if ((length-header_length+2) > segmentSize) return false;
1182 ((UINT16*)buffer)[length/2] = htons((UINT16)objectId);
1183 length += 2;
1184 return true;
1185 }
1186
1187 // Message processing
GetFecId()1188 UINT8 GetFecId() const
1189 {return ((UINT8*)buffer)[FEC_ID_OFFSET];}
GetObjectId()1190 NormObjectId GetObjectId() const
1191 {return (ntohs(((UINT16*)buffer)[OBJ_ID_OFFSET]));}
GetFecBlockId(UINT8 m)1192 NormBlockId GetFecBlockId(UINT8 m) const
1193 {
1194 NormPayloadId payloadId(GetFecId(), m, buffer + FEC_PAYLOAD_ID_OFFSET);
1195 return payloadId.GetFecBlockId();
1196 }
GetFecSymbolId(UINT8 m)1197 UINT16 GetFecSymbolId(UINT8 m) const
1198 {
1199 NormPayloadId payloadId(GetFecId(), m, buffer + FEC_PAYLOAD_ID_OFFSET);
1200 return payloadId.GetFecSymbolId();
1201 }
GetFecBlockLength()1202 UINT16 GetFecBlockLength() const
1203 {
1204 NormPayloadId payloadId(GetFecId(), 8, buffer + FEC_PAYLOAD_ID_OFFSET);
1205 return payloadId.GetFecBlockLength();
1206 }
1207
1208 // Use these to parse invalid object list
GetInvalidObjectCount()1209 UINT16 GetInvalidObjectCount() const
1210 {return ((length - header_length) >> 1);}
GetInvalidObjectList()1211 UINT16* GetInvalidObjectList() const
1212 {return (UINT16*)(buffer+header_length);}
GetInvalidObjectId(UINT16 index)1213 NormObjectId GetInvalidObjectId(UINT16 index) const
1214 {return (ntohs(((UINT16*)buffer)[(header_length/2)+index]));}
1215
1216 private:
1217 enum
1218 {
1219 FEC_ID_OFFSET = FLAVOR_OFFSET + 1,
1220 OBJ_ID_OFFSET = (FEC_ID_OFFSET + 1)/2,
1221 FEC_PAYLOAD_ID_OFFSET = ((OBJ_ID_OFFSET+1)*2)/4
1222 };
1223 }; // end class NormCmdSquelchMsg
1224
1225
1226 // These flag values are used "cc_flags" field of NORM_CMD(CC) CC_NODE_LIST
1227 // items and NORM_NACK and NORM_ACK messages
1228 class NormCC
1229 {
1230 public:
1231 enum Flag
1232 {
1233 CLR = 0x01,
1234 PLR = 0x02,
1235 RTT = 0x04,
1236 START = 0x08,
1237 LEAVE = 0x10,
1238 LIMIT = 0x20 // experimental, non-RFC5740
1239 }; // (set when included rate is measured, not calculated)
1240 }; // end class NormCC
1241
1242 class NormCmdCCMsg : public NormCmdMsg
1243 {
1244 public:
Init()1245 void Init()
1246 {
1247 SetType(CMD);
1248 SetFlavor(CC);
1249 SetBaseHeaderLength(CC_HEADER_LEN);
1250 ((UINT8*)buffer)[RESERVED_OFFSET] = 0;
1251 }
1252
SetCCSequence(UINT16 ccSequence)1253 void SetCCSequence(UINT16 ccSequence)
1254 {
1255 ((UINT16*)buffer)[CC_SEQUENCE_OFFSET] = htons(ccSequence);
1256 }
SetSendTime(const struct timeval & sendTime)1257 void SetSendTime(const struct timeval& sendTime)
1258 {
1259 buffer[SEND_TIME_SEC_OFFSET] = htonl(sendTime.tv_sec);
1260 buffer[SEND_TIME_USEC_OFFSET] = htonl(sendTime.tv_usec);
1261 }
1262
GetCCSequence()1263 UINT16 GetCCSequence() const
1264 {return (ntohs(((UINT16*)buffer)[CC_SEQUENCE_OFFSET]));}
GetSendTime(struct timeval & sendTime)1265 void GetSendTime(struct timeval& sendTime) const
1266 {
1267 sendTime.tv_sec = ntohl(buffer[SEND_TIME_SEC_OFFSET]);
1268 sendTime.tv_usec = ntohl(buffer[SEND_TIME_USEC_OFFSET]);
1269 }
1270
AppendCCNode(UINT16 segMax,NormNodeId nodeId,UINT8 flags,UINT8 rtt,UINT16 rate)1271 bool AppendCCNode(UINT16 segMax, NormNodeId nodeId, UINT8 flags,
1272 UINT8 rtt, UINT16 rate)
1273 {
1274 if ((length-header_length+CC_ITEM_SIZE)> segMax) return false;
1275 UINT32* ptr = buffer + length/4;
1276 ptr[CC_NODE_ID_OFFSET] = htonl(nodeId);
1277 ((UINT8*)ptr)[CC_FLAGS_OFFSET] = flags;
1278 ((UINT8*)ptr)[CC_RTT_OFFSET] = rtt;
1279 ((UINT16*)ptr)[CC_RATE_OFFSET] = htons(rate);
1280 length += CC_ITEM_SIZE;
1281 return true;
1282 }
1283 bool GetCCNode(NormNodeId nodeId, UINT8& flags, UINT8& rtt, UINT16& rate) const;
1284
1285
1286 class Iterator;
1287 friend class Iterator;
1288
1289 class Iterator
1290 {
1291 public:
1292 Iterator(const NormCmdCCMsg& msg);
Reset()1293 void Reset() {offset = 0;}
1294 bool GetNextNode(NormNodeId& nodeId, UINT8& flags, UINT8& rtt, UINT16& rate);
1295
1296 private:
1297 const NormCmdCCMsg& cc_cmd;
1298 UINT16 offset;
1299 };
1300
1301
1302 private:
1303 enum
1304 {
1305 RESERVED_OFFSET = FLAVOR_OFFSET + 1,
1306 CC_SEQUENCE_OFFSET = (RESERVED_OFFSET + 1)/2,
1307 SEND_TIME_SEC_OFFSET = ((CC_SEQUENCE_OFFSET*2)+2)/4,
1308 SEND_TIME_USEC_OFFSET = ((SEND_TIME_SEC_OFFSET*4)+4)/4,
1309 CC_HEADER_LEN = (SEND_TIME_USEC_OFFSET*4)+4
1310 };
1311
1312 enum
1313 {
1314 CC_NODE_ID_OFFSET = 0,
1315 CC_FLAGS_OFFSET = CC_NODE_ID_OFFSET + 4,
1316 CC_RTT_OFFSET = CC_FLAGS_OFFSET + 1,
1317 CC_RATE_OFFSET = (CC_RTT_OFFSET + 1)/2,
1318 CC_ITEM_SIZE = (CC_RATE_OFFSET*2)+2
1319 };
1320
1321 }; // end class NormCmdCCMsg
1322
1323 class NormCCRateExtension : public NormHeaderExtension
1324 {
1325 public:
1326
Init(UINT32 * theBuffer)1327 virtual void Init(UINT32* theBuffer)
1328 {
1329 AttachBuffer(theBuffer);
1330 SetType(CC_RATE);
1331 ((UINT8*)buffer)[RESERVED_OFFSET] = 0;
1332 }
SetSendRate(UINT16 sendRate)1333 void SetSendRate(UINT16 sendRate)
1334 {((UINT16*)buffer)[SEND_RATE_OFFSET] = htons(sendRate);}
GetSendRate()1335 UINT16 GetSendRate()
1336 {return (ntohs(((UINT16*)buffer)[SEND_RATE_OFFSET]));}
1337
1338 private:
1339 enum
1340 {
1341 RESERVED_OFFSET = TYPE_OFFSET + 1,
1342 SEND_RATE_OFFSET = (RESERVED_OFFSET + 1)/2
1343 };
1344 }; // end class NormCCRateExtension
1345
1346 // This implementation currently assumes "fec_id"= 129
1347 class NormRepairRequest
1348 {
1349 public:
1350 class Iterator;
1351 friend class NormRepairRequest::Iterator;
1352 enum Form
1353 {
1354 INVALID = 0,
1355 ITEMS = 1,
1356 RANGES = 2,
1357 ERASURES = 3
1358 };
1359
1360 enum Flag
1361 {
1362 SEGMENT = 0x01,
1363 BLOCK = 0x02,
1364 INFO = 0x04,
1365 OBJECT = 0x08
1366 };
1367
1368 // Construction
1369 NormRepairRequest();
Init(UINT32 * bufferPtr,UINT16 bufferLen)1370 void Init(UINT32* bufferPtr, UINT16 bufferLen)
1371 {
1372 buffer = bufferPtr;
1373 buffer_len = bufferLen;
1374 length = 0;
1375 }
1376 // (TBD) these could be an enumeration for optimization
RepairItemLength(UINT8 fecId)1377 static UINT16 RepairItemLength(UINT8 fecId)
1378 {return (4 + NormPayloadId::GetLength(fecId));}
RepairRangeLength(UINT8 fecId)1379 static UINT16 RepairRangeLength(UINT8 fecId)
1380 {return (2 * RepairItemLength(fecId));}
ErasureItemLength(UINT8 fecId)1381 static UINT16 ErasureItemLength(UINT8 fecId)
1382 {return RepairItemLength(fecId);}
1383
1384 // Repair request building
SetForm(NormRepairRequest::Form theForm)1385 void SetForm(NormRepairRequest::Form theForm)
1386 {form = theForm;}
ResetFlags()1387 void ResetFlags()
1388 {flags = 0;}
SetFlag(NormRepairRequest::Flag theFlag)1389 void SetFlag(NormRepairRequest::Flag theFlag)
1390 {flags |= theFlag;}
ClearFlag(NormRepairRequest::Flag theFlag)1391 void ClearFlag(NormRepairRequest::Flag theFlag)
1392 {flags &= ~theFlag;}
1393
1394 // Returns length (each repair item requires 8 bytes of space)
1395 bool AppendRepairItem(UINT8 fecId,
1396 UINT8 fecM,
1397 const NormObjectId& objectId,
1398 const NormBlockId& blockId,
1399 UINT16 blockLen,
1400 UINT16 symbolId);
1401
1402 bool AppendRepairRange(UINT8 fecId,
1403 UINT8 fecM,
1404 const NormObjectId& startObjectId,
1405 const NormBlockId& startBlockId,
1406 UINT16 startBlockLen,
1407 UINT16 startSymbolId,
1408 const NormObjectId& endObjectId,
1409 const NormBlockId& endBlockId,
1410 UINT16 endBlockLen,
1411 UINT16 endSymbolId);
1412
1413 bool AppendErasureCount(UINT8 fecId,
1414 UINT8 fecM,
1415 const NormObjectId& objectId,
1416 const NormBlockId& blockId,
1417 UINT16 blockLen,
1418 UINT16 erasureCount);
1419
1420 UINT16 Pack();
1421
1422 // Repair request processing
1423 UINT16 Unpack(const UINT32* bufferPtr, UINT16 bufferLen);
GetForm()1424 NormRepairRequest::Form GetForm() const
1425 {return form;}
FlagIsSet(NormRepairRequest::Flag theFlag)1426 bool FlagIsSet(NormRepairRequest::Flag theFlag) const
1427 {return (0 != (theFlag & flags));}
GetLength()1428 UINT16 GetLength() const {return length;}
1429
1430 // Outputs textual representation of RepairRequest content
1431 void Log(UINT8 fecId, UINT8 fecM) const;
1432
1433 class Iterator
1434 {
1435 public:
1436 // Checks for matching fecId and assumes constant 'm' ?!?!
1437 Iterator(const NormRepairRequest& theRequest, UINT8 fecId, UINT8 fecM);
Reset()1438 void Reset() {offset = 0;}
1439 bool NextRepairItem(NormObjectId* objectId,
1440 NormBlockId* blockId,
1441 UINT16* blockLen,
1442 UINT16* symbolId);
1443 private:
1444 const NormRepairRequest& request;
1445 UINT8 fec_id;
1446 UINT8 fec_m;
1447 UINT16 offset;
1448 }; // end class NormRepairRequest::Iterator
1449
1450 private:
1451 UINT16 RetrieveRepairItem(UINT8 fecM,
1452 UINT16 offset,
1453 UINT8* fecId,
1454 NormObjectId* objectId,
1455 NormBlockId* blockId,
1456 UINT16* blockLen,
1457 UINT16* symbolId) const;
1458 enum
1459 {
1460 FORM_OFFSET = 0,
1461 FLAGS_OFFSET = FORM_OFFSET + 1,
1462 LENGTH_OFFSET = (FLAGS_OFFSET + 1)/2,
1463 ITEM_LIST_OFFSET = (LENGTH_OFFSET*2)+2
1464 };
1465
1466 // These are the offsets for "fec_id" = 129 NormRepairRequest items
1467 enum
1468 {
1469 FEC_ID_OFFSET = 0,
1470 RESERVED_OFFSET = FEC_ID_OFFSET + 1,
1471 OBJ_ID_OFFSET = (RESERVED_OFFSET + 1)/2,
1472 FEC_PAYLOAD_ID_OFFSET = ((OBJ_ID_OFFSET+1)*2)/4
1473 };
1474
1475 Form form;
1476 int flags;
1477 UINT16 length; // length of repair items
1478 UINT32* buffer;
1479 UINT16 buffer_len; // in bytes
1480
1481 }; // end class NormRepairRequest
1482
1483 class NormCmdRepairAdvMsg : public NormCmdMsg
1484 {
1485 public:
1486 enum Flag {NORM_REPAIR_ADV_FLAG_LIMIT = 0x01};
1487
Init()1488 void Init()
1489 {
1490 SetType(CMD);
1491 SetFlavor(REPAIR_ADV);
1492 SetBaseHeaderLength(REPAIR_ADV_HEADER_LEN);
1493 ResetFlags();
1494 ((UINT16*)buffer)[RESERVED_OFFSET] = 0;
1495 }
1496
1497 // Message building
ResetFlags()1498 void ResetFlags() {((UINT8*)buffer)[FLAGS_OFFSET] = 0;}
SetFlag(NormCmdRepairAdvMsg::Flag flag)1499 void SetFlag(NormCmdRepairAdvMsg::Flag flag)
1500 {((UINT8*)buffer)[FLAGS_OFFSET] |= (UINT8)flag;}
AttachRepairRequest(NormRepairRequest & request,UINT16 segmentMax)1501 void AttachRepairRequest(NormRepairRequest& request,
1502 UINT16 segmentMax)
1503 {
1504 int buflen = segmentMax - (length - header_length);
1505 buflen = (buflen>0) ? buflen : 0;
1506 request.Init(buffer+length/4, buflen);
1507 }
PackRepairRequest(NormRepairRequest & request)1508 UINT16 PackRepairRequest(NormRepairRequest& request)
1509 {
1510 UINT16 requestLength = request.Pack();
1511 length += requestLength;
1512 return requestLength;
1513 }
1514
1515 // Message processing
FlagIsSet(NormCmdRepairAdvMsg::Flag flag)1516 bool FlagIsSet(NormCmdRepairAdvMsg::Flag flag) const
1517 {return (0 != ((UINT8)flag | ((UINT8*)buffer)[FLAGS_OFFSET]));}
1518 //char* AccessRepairContent() {return (buffer + header_length);}
GetRepairContent()1519 const UINT32* GetRepairContent() const
1520 {return (buffer + header_length/4);}
GetRepairContentLength()1521 UINT16 GetRepairContentLength() const
1522 {return (length - header_length);}
1523
1524 private:
1525 enum
1526 {
1527 FLAGS_OFFSET = FLAVOR_OFFSET + 1,
1528 RESERVED_OFFSET = FLAGS_OFFSET + 1,
1529 REPAIR_ADV_HEADER_LEN = RESERVED_OFFSET + 2
1530 };
1531
1532 }; // end class NormCmdRepairAdvMsg
1533
1534 // TBD - define NormCCFeedbackExtension2 for larger loss encoding range
1535 // the current 16-bit range is too limited for large RTT*rate combos
1536 class NormCCFeedbackExtension : public NormHeaderExtension
1537 {
1538 public:
Init(UINT32 * theBuffer)1539 virtual void Init(UINT32* theBuffer)
1540 {
1541 AttachBuffer(theBuffer);
1542 SetType(CC_FEEDBACK);
1543 SetWords(3);
1544 ((UINT8*)buffer)[CC_FLAGS_OFFSET] = 0;
1545 //((UINT16*)buffer)[CC_RESERVED_OFFSET] = 0;
1546 }
SetCCSequence(UINT16 ccSequence)1547 void SetCCSequence(UINT16 ccSequence)
1548 {((UINT16*)buffer)[CC_SEQUENCE_OFFSET] = htons(ccSequence);}
ResetCCFlags()1549 void ResetCCFlags()
1550 {((UINT8*)buffer)[CC_FLAGS_OFFSET] = 0;}
SetCCFlag(NormCC::Flag flag)1551 void SetCCFlag(NormCC::Flag flag)
1552 {((UINT8*)buffer)[CC_FLAGS_OFFSET] |= (UINT8)flag;}
SetCCRtt(UINT8 ccRtt)1553 void SetCCRtt(UINT8 ccRtt)
1554 {((UINT8*)buffer)[CC_RTT_OFFSET] = ccRtt;}
1555 //void SetCCLoss(UINT16 ccLoss)
1556 // {((UINT16*)buffer)[CC_LOSS_OFFSET] = htons(ccLoss);}
SetCCRate(UINT16 ccRate)1557 void SetCCRate(UINT16 ccRate)
1558 {((UINT16*)buffer)[CC_RATE_OFFSET] = htons(ccRate);}
1559
SetCCLoss32(UINT32 ccLoss)1560 void SetCCLoss32(UINT32 ccLoss)
1561 {
1562 ccLoss = htonl(ccLoss);
1563 UINT16* ptr = (UINT16*)&ccLoss;
1564 ((UINT16*)buffer)[CC_LOSS_OFFSET] = ptr[0]; // msb
1565 ((UINT16*)buffer)[CC_LOSS_EX_OFFSET] = ptr[1]; // lsb
1566 }
1567
GetCCSequence()1568 UINT16 GetCCSequence() const
1569 {return (ntohs(((UINT16*)buffer)[CC_SEQUENCE_OFFSET]));}
GetCCFlags()1570 UINT8 GetCCFlags()
1571 {return ((UINT8*)buffer)[CC_FLAGS_OFFSET];}
CCFlagIsSet(NormCC::Flag flag)1572 bool CCFlagIsSet(NormCC::Flag flag) const
1573 {return (0 != ((UINT8)flag & ((UINT8*)buffer)[CC_FLAGS_OFFSET]));}
GetCCRtt()1574 UINT8 GetCCRtt() const
1575 {return ((UINT8*)buffer)[CC_RTT_OFFSET];}
1576 //UINT16 GetCCLoss() const
1577 // {return (ntohs(((UINT16*)buffer)[CC_LOSS_OFFSET]));}
GetCCRate()1578 UINT16 GetCCRate()const
1579 {return (ntohs(((UINT16*)buffer)[CC_RATE_OFFSET]));}
1580
GetCCLoss32()1581 UINT32 GetCCLoss32() const
1582 {
1583 UINT32 lossQuantized;
1584 UINT16* ptr = (UINT16*)&lossQuantized;
1585 ptr[0] = ((UINT16*)buffer)[CC_LOSS_OFFSET]; // msb
1586 ptr[1] = ((UINT16*)buffer)[CC_LOSS_EX_OFFSET]; // lsb
1587 return ntohl(lossQuantized); // return in host byte order
1588 }
1589
1590 private:
1591 enum
1592 {
1593 CC_SEQUENCE_OFFSET = (LENGTH_OFFSET+1)/2,
1594 CC_FLAGS_OFFSET = (CC_SEQUENCE_OFFSET*2)+2,
1595 CC_RTT_OFFSET = CC_FLAGS_OFFSET + 1,
1596 CC_LOSS_OFFSET = (CC_RTT_OFFSET + 1)/2,
1597 CC_RATE_OFFSET = ((CC_LOSS_OFFSET*2)+2)/2,
1598 //CC_RESERVED_OFFSET = ((CC_RATE_OFFSET*2)+2)/2
1599 CC_LOSS_EX_OFFSET = ((CC_RATE_OFFSET*2)+2)/2 // extended precision loss estimate (non-RFC5940 compliant, but compatible)
1600 };
1601
1602 }; // end class NormCCFeedbackExtension
1603
1604 // Note: Support for application-defined AckFlavors (32-255)
1605 // may be provided, but 0-31 are reserved values
1606 class NormAck
1607 {
1608 public:
1609 enum Type
1610 {
1611 INVALID = 0,
1612 CC = 1,
1613 FLUSH = 2,
1614 APP_BASE = 16
1615 };
1616 };
1617
1618 class NormCmdAckReqMsg : public NormCmdMsg
1619 {
1620 public:
1621
Init()1622 void Init()
1623 {
1624 SetType(CMD);
1625 SetFlavor(ACK_REQ);
1626 SetBaseHeaderLength(ACK_REQ_HEADER_LEN);
1627 ((UINT8*)buffer)[RESERVED_OFFSET] = 0;
1628 }
1629
1630 // Message building
SetAckType(NormAck::Type ackType)1631 void SetAckType(NormAck::Type ackType)
1632 {((UINT8*)buffer)[ACK_TYPE_OFFSET] = (UINT8)ackType;}
SetAckId(UINT8 ackId)1633 void SetAckId(UINT8 ackId)
1634 {((UINT8*)buffer)[ACK_ID_OFFSET] = ackId;}
ResetAckingNodeList()1635 void ResetAckingNodeList()
1636 {length = header_length;}
AppendAckingNode(NormNodeId nodeId,UINT16 segmentSize)1637 bool AppendAckingNode(NormNodeId nodeId, UINT16 segmentSize)
1638 {
1639 if ((length - header_length + 4) > segmentSize) return false;
1640 buffer[length/4] = htonl(nodeId);
1641 length += 4;
1642 return true;
1643 }
1644
1645 // Message processing
GetAckType()1646 NormAck::Type GetAckType() const
1647 {return (NormAck::Type)(((UINT8*)buffer)[ACK_TYPE_OFFSET]);}
GetAckId()1648 UINT8 GetAckId() const
1649 {return ((UINT8*)buffer)[ACK_ID_OFFSET];}
GetAckingNodeCount()1650 UINT16 GetAckingNodeCount() const
1651 {return ((length - header_length) >> 2);}
GetAckingNodeId(UINT16 index)1652 NormNodeId GetAckingNodeId(UINT16 index) const
1653 {return (ntohl(buffer[(header_length/4)+index]));}
1654
1655 private:
1656 enum
1657 {
1658 RESERVED_OFFSET = FLAVOR_OFFSET + 1,
1659 ACK_TYPE_OFFSET = RESERVED_OFFSET + 1,
1660 ACK_ID_OFFSET = ACK_TYPE_OFFSET + 1,
1661 ACK_REQ_HEADER_LEN = ACK_ID_OFFSET + 1
1662 };
1663 }; // end class NormCmdAckReqMsg
1664
1665
1666 class NormCmdAppMsg : public NormCmdMsg
1667 {
1668 public:
Init()1669 void Init()
1670 {
1671 SetType(CMD);
1672 SetFlavor(APPLICATION);
1673 SetBaseHeaderLength(APPLICATION_HEADER_LEN);
1674 memset(((UINT8*)buffer)+RESERVED_OFFSET, 0, 3);
1675 }
1676
SetContent(const char * content,UINT16 contentLen,UINT16 segmentSize)1677 bool SetContent(const char* content, UINT16 contentLen, UINT16 segmentSize)
1678 {
1679 UINT16 len = MIN(contentLen, segmentSize);
1680 memcpy(((char*)buffer)+header_length, content, len);
1681 length = header_length + len;
1682 return (contentLen <= segmentSize);
1683 }
1684
GetContentLength()1685 UINT16 GetContentLength() const
1686 {return (length - header_length);}
GetContent()1687 const char* GetContent() const
1688 {return (((char*)buffer)+header_length);}
1689
1690 private:
1691 enum
1692 {
1693 RESERVED_OFFSET = FLAVOR_OFFSET + 1,
1694 APPLICATION_HEADER_LEN = RESERVED_OFFSET + 3
1695 };
1696 }; // end class NormCmdAppMsg
1697
1698
1699 // Receiver Messages
1700
1701 class NormNackMsg : public NormMsg
1702 {
1703 public:
1704 enum {DEFAULT_LENGTH_MAX = 40};
Init()1705 void Init()
1706 {
1707 SetType(NACK);
1708 ((UINT16*)buffer)[RESERVED_OFFSET] = 0;
1709 SetBaseHeaderLength(NACK_HEADER_LEN);
1710 }
1711 // Message building
SetSenderId(NormNodeId senderId)1712 void SetSenderId(NormNodeId senderId)
1713 {buffer[SENDER_ID_OFFSET] = htonl(senderId);}
SetInstanceId(UINT16 instanceId)1714 void SetInstanceId(UINT16 instanceId)
1715 {((UINT16*)buffer)[INSTANCE_ID_OFFSET] = htons(instanceId);}
SetGrttResponse(const struct timeval & grttResponse)1716 void SetGrttResponse(const struct timeval& grttResponse)
1717 {
1718 buffer[GRTT_RESPONSE_SEC_OFFSET] = htonl(grttResponse.tv_sec);
1719 buffer[GRTT_RESPONSE_USEC_OFFSET] = htonl(grttResponse.tv_usec);
1720 }
AttachRepairRequest(NormRepairRequest & request,UINT16 segmentMax)1721 void AttachRepairRequest(NormRepairRequest& request,
1722 UINT16 segmentMax)
1723 {
1724 int buflen = segmentMax - (length - header_length);
1725 buflen = (buflen>0) ? buflen : 0;
1726 request.Init(buffer+length/4, buflen);
1727 }
PackRepairRequest(NormRepairRequest & request)1728 UINT16 PackRepairRequest(NormRepairRequest& request)
1729 {
1730 UINT16 requestLength = request.Pack();
1731 length += requestLength;
1732 return requestLength;
1733 }
1734
1735 // Message processing
GetSenderId()1736 NormNodeId GetSenderId() const
1737 {return (ntohl(buffer[SENDER_ID_OFFSET]));}
GetInstanceId()1738 UINT16 GetInstanceId() const
1739 {return (ntohs(((UINT16*)buffer)[INSTANCE_ID_OFFSET]));}
GetGrttResponse(struct timeval & grttResponse)1740 void GetGrttResponse(struct timeval& grttResponse) const
1741 {
1742 grttResponse.tv_sec = ntohl(buffer[GRTT_RESPONSE_SEC_OFFSET]);
1743 grttResponse.tv_usec = ntohl(buffer[GRTT_RESPONSE_USEC_OFFSET]);
1744 }
1745 //char* AccessRepairContent() {return (buffer + header_length);}
GetRepairContent()1746 const UINT32* GetRepairContent() const
1747 {return (buffer + header_length/4);}
GetRepairContentLength()1748 UINT16 GetRepairContentLength() const
1749 {return ((length > header_length) ? length - header_length : 0);}
UnpackRepairRequest(NormRepairRequest & request,UINT16 requestOffset)1750 UINT16 UnpackRepairRequest(NormRepairRequest& request,
1751 UINT16 requestOffset)
1752 {
1753 int buflen = length - header_length - requestOffset;
1754 buflen = (buflen > 0) ? buflen : 0;
1755 return request.Unpack(buffer+(header_length+requestOffset)/4, buflen);
1756 }
1757
1758 private:
1759 enum
1760 {
1761 SENDER_ID_OFFSET = MSG_OFFSET/4,
1762 INSTANCE_ID_OFFSET = ((SENDER_ID_OFFSET*4)+4)/2,
1763 RESERVED_OFFSET = ((INSTANCE_ID_OFFSET*2)+2)/2,
1764 GRTT_RESPONSE_SEC_OFFSET = ((RESERVED_OFFSET*2)+2)/4,
1765 GRTT_RESPONSE_USEC_OFFSET = ((GRTT_RESPONSE_SEC_OFFSET*4)+4)/4,
1766 NACK_HEADER_LEN = (GRTT_RESPONSE_USEC_OFFSET*4)+4
1767 };
1768 }; // end class NormNackMsg
1769
1770 class NormAckMsg : public NormMsg
1771 {
1772 public:
1773
1774 // Message building
Init()1775 void Init()
1776 {
1777 SetType(ACK);
1778 SetBaseHeaderLength(ACK_HEADER_LEN);
1779 SetAckType(NormAck::INVALID);
1780 }
SetSenderId(NormNodeId senderId)1781 void SetSenderId(NormNodeId senderId)
1782 {buffer[SENDER_ID_OFFSET] = htonl(senderId);}
SetInstanceId(UINT16 instanceId)1783 void SetInstanceId(UINT16 instanceId)
1784 {((UINT16*)buffer)[INSTANCE_ID_OFFSET] = htons(instanceId);}
SetAckType(NormAck::Type ackType)1785 void SetAckType(NormAck::Type ackType)
1786 {((UINT8*)buffer)[ACK_TYPE_OFFSET] = (UINT8)ackType;}
SetAckId(UINT8 ackId)1787 void SetAckId(UINT8 ackId)
1788 {((UINT8*)buffer)[ACK_ID_OFFSET] = ackId;}
SetGrttResponse(const struct timeval & grttResponse)1789 void SetGrttResponse(const struct timeval& grttResponse)
1790 {
1791 buffer[GRTT_RESPONSE_SEC_OFFSET] = htonl(grttResponse.tv_sec);
1792 buffer[GRTT_RESPONSE_USEC_OFFSET] = htonl(grttResponse.tv_usec);
1793 }
SetAckPayload(const char * payload,UINT16 payloadLen,UINT16 segmentSize)1794 bool SetAckPayload(const char* payload, UINT16 payloadLen, UINT16 segmentSize)
1795 {
1796 UINT16 len = MIN(payloadLen, segmentSize);
1797 memcpy(((char*)buffer)+header_length, payload, len);
1798 length += len;
1799 return (payloadLen <= segmentSize);
1800 }
1801
1802 // Message processing
GetSenderId()1803 NormNodeId GetSenderId() const
1804 {return (ntohl(buffer[SENDER_ID_OFFSET]));}
GetInstanceId()1805 UINT16 GetInstanceId() const
1806 {return (ntohs(((UINT16*)buffer)[INSTANCE_ID_OFFSET]));}
GetGrttResponse(struct timeval & grttResponse)1807 void GetGrttResponse(struct timeval& grttResponse) const
1808 {
1809 grttResponse.tv_sec = ntohl(buffer[GRTT_RESPONSE_SEC_OFFSET]);
1810 grttResponse.tv_usec = ntohl(buffer[GRTT_RESPONSE_USEC_OFFSET]);
1811 }
GetAckType()1812 NormAck::Type GetAckType() const
1813 {return (NormAck::Type)((UINT8*)buffer)[ACK_TYPE_OFFSET];}
GetAckId()1814 UINT8 GetAckId() const
1815 {return ((UINT8*)buffer)[ACK_ID_OFFSET];}
GetPayloadLength()1816 UINT16 GetPayloadLength() const
1817 {return (length - header_length);}
GetPayload()1818 const char* GetPayload() const
1819 {return (((char*)buffer) + header_length);}
1820
1821 protected:
1822 enum
1823 {
1824 SENDER_ID_OFFSET = MSG_OFFSET/4,
1825 INSTANCE_ID_OFFSET = ((SENDER_ID_OFFSET*4)+4)/2,
1826 ACK_TYPE_OFFSET = (INSTANCE_ID_OFFSET*2)+2,
1827 ACK_ID_OFFSET = ACK_TYPE_OFFSET + 1,
1828 GRTT_RESPONSE_SEC_OFFSET = (ACK_ID_OFFSET + 1)/4,
1829 GRTT_RESPONSE_USEC_OFFSET = ((GRTT_RESPONSE_SEC_OFFSET+1)*4)/4,
1830 ACK_HEADER_LEN = (GRTT_RESPONSE_USEC_OFFSET+1)*4
1831 };
1832 }; // end class NormAckMsg
1833
1834 class NormAckFlushMsg : public NormAckMsg
1835 {
1836 public:
Init()1837 void Init()
1838 {
1839 SetType(ACK);
1840 SetBaseHeaderLength(ACK_HEADER_LEN);
1841 SetAckType(NormAck::FLUSH);
1842 ((UINT8*)buffer)[RESERVED_OFFSET] = 0;
1843 }
1844
1845 // Note: must apply any header exts _before_ the payload is set
SetFecId(UINT8 fecId)1846 void SetFecId(UINT8 fecId)
1847 {((UINT8*)buffer)[header_length+FEC_ID_OFFSET] = fecId;}
SetObjectId(NormObjectId objectId)1848 void SetObjectId(NormObjectId objectId)
1849 {((UINT16*)buffer)[(header_length/2)+OBJ_ID_OFFSET] = htons((UINT16)objectId);}
SetFecPayloadId(UINT8 fecId,UINT32 blockId,UINT16 symbolId,UINT16 blockLen,UINT8 m)1850 void SetFecPayloadId(UINT8 fecId, UINT32 blockId, UINT16 symbolId, UINT16 blockLen, UINT8 m)
1851 {
1852 SetFecId(fecId);
1853 ((UINT8*)buffer)[header_length+RESERVED_OFFSET] = 0;
1854 NormPayloadId payloadId(fecId, m, buffer + header_length/4 + FEC_PAYLOAD_ID_OFFSET);
1855 payloadId.SetFecPayloadId(blockId, symbolId, blockLen);
1856 length = header_length + 4*FEC_PAYLOAD_ID_OFFSET + NormPayloadId::GetLength(fecId);
1857 }
1858
GetFecId()1859 UINT8 GetFecId() const
1860 {return ((UINT8*)buffer)[header_length+FEC_ID_OFFSET];}
1861
GetObjectId()1862 NormObjectId GetObjectId() const
1863 {return ntohs(((UINT16*)buffer)[(header_length/2)+OBJ_ID_OFFSET]);}
1864
GetFecBlockId(UINT8 m)1865 NormBlockId GetFecBlockId(UINT8 m) const
1866 {
1867 NormPayloadId payloadId(GetFecId(), m, buffer + header_length/4 + FEC_PAYLOAD_ID_OFFSET);
1868 return payloadId.GetFecBlockId();
1869 }
GetFecSymbolId(UINT8 m)1870 UINT16 GetFecSymbolId(UINT8 m) const
1871 {
1872 NormPayloadId payloadId(GetFecId(), m, buffer + header_length/4 + FEC_PAYLOAD_ID_OFFSET);
1873 return payloadId.GetFecSymbolId();
1874 }
GetFecBlockLength()1875 UINT16 GetFecBlockLength() const
1876 {
1877 NormPayloadId payloadId(GetFecId(), 8, buffer + header_length/4 + FEC_PAYLOAD_ID_OFFSET);
1878 return payloadId.GetFecBlockLength();
1879 }
1880
1881 private:
1882 // Note - These are the payload offsets for "fec_id" = 129
1883 // "fec_payload_id" field
1884 // IMPORTANT - These are _relative_ to the NORM_ACK header (incl. extensions)
1885 enum
1886 {
1887 FEC_ID_OFFSET = 0,
1888 RESERVED_OFFSET = FEC_ID_OFFSET + 1,
1889 OBJ_ID_OFFSET = (RESERVED_OFFSET+1)/2,
1890 FEC_PAYLOAD_ID_OFFSET = ((OBJ_ID_OFFSET*2)+2)/4
1891 };
1892
1893 }; // end class NormAckFlushMsg
1894
1895 class NormReportMsg : public NormMsg
1896 {
1897 // (TBD)
1898
1899 }; // end class NormReportMsg
1900
1901 // One we've defined our basic message types, we
1902 // do some unions so we can easily use these
1903 // via casting or dereferencing the union members
1904
1905 class NormMessageQueue
1906 {
1907 public:
1908 NormMessageQueue();
1909 ~NormMessageQueue();
1910 void Destroy();
1911 void Prepend(NormMsg* msg);
1912 void Append(NormMsg* msg);
1913 void Remove(NormMsg* msg);
1914 NormMsg* RemoveHead();
1915 NormMsg* RemoveTail();
GetHead()1916 NormMsg* GetHead() {return head;}
IsEmpty()1917 bool IsEmpty() {return ((NormMsg*)NULL == head);}
1918
1919 private:
1920 NormMsg* head;
1921 NormMsg* tail;
1922 }; // end class NormMessageQueue
1923
1924 // Helper function to output report on repair content (e.g. NormNack content) to debug log
1925 void LogRepairContent(const UINT32* buffer, UINT16 bufferLen, UINT8 fecId, UINT8 fecM);
1926
1927 #endif // _NORM_MESSAGE
1928