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