v0.1
commit
565afa5529
|
|
@ -0,0 +1,20 @@
|
|||
# protolib
|
||||
protolib/
|
||||
|
||||
# build executables
|
||||
build/
|
||||
lib/
|
||||
makefiles/norm
|
||||
makefiles/normMsgr
|
||||
makefiles/normStreamer
|
||||
makefiles/npc
|
||||
makefiles/raft
|
||||
|
||||
# OS generated files #
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*********************************************************************
|
||||
*
|
||||
* AUTHORIZATION TO USE AND DISTRIBUTE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that:
|
||||
*
|
||||
* (1) source code distributions retain this paragraph in its entirety,
|
||||
*
|
||||
* (2) distributions including binary code include this paragraph in
|
||||
* its entirety in the documentation or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* "This product includes software written and developed
|
||||
* by Code 5520 of the Naval Research Laboratory (NRL)."
|
||||
*
|
||||
* The name of NRL, the name(s) of NRL employee(s), or any entity
|
||||
* of the United States Government may not be used to endorse or
|
||||
* promote products derived from this software, nor does the
|
||||
* inclusion of the NRL written and developed software directly or
|
||||
* indirectly suggest NRL or United States Government endorsement
|
||||
* of this product.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
********************************************************************/
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
NORM PRELIMINARY CODE RELEASE
|
||||
|
||||
These directories contain source code for a very preliminary
|
||||
implementation of the Nack Oriented Reliable Multicast (NORM)
|
||||
protocol. Currently, a very dumb "norm" command-line application
|
||||
(which currently takes no command-line arguments) is
|
||||
created. This application creates a NormSession and acts
|
||||
both as a sender and receiver to the multicast group. It
|
||||
creates a "NORM_STREAM" object and writes repeated,
|
||||
continuous strings of "aaaaaaa ..." to the stream. As the
|
||||
stream is received, the client (receiver) portion of the
|
||||
"norm" app writes a notices of a successful Read()
|
||||
operation from the stream.
|
||||
|
||||
This currently uses a fixed transmission rate of 64 kbps
|
||||
and a Reed-Solomon FEC encoding block with 20 user data
|
||||
segments and calculates 8 parity segments per coding
|
||||
block. Four parity segments are sent at the end of each
|
||||
coding block as "auto parity". The current NORM code is
|
||||
currently automatically discarding segment 9 of the
|
||||
received data stream to test the FEC encoding/decoding and
|
||||
stream buffer routines.
|
||||
|
||||
The code does not currently generate any NACK messages,
|
||||
but the routines to perform checks for losses is in place
|
||||
and the routines for building NACK messages are in place,
|
||||
so the addition of the timer installation routines to
|
||||
schedule NACK back-off and subsequent transmission will be
|
||||
added very soon. Then, routines will be added for the
|
||||
server (sender) side to process received NACKs and
|
||||
subsequently provide repair messages. Then, client-side
|
||||
routines for NACK suppression will be added. After that,
|
||||
the final details of GRTT collection, unicast feedback
|
||||
suppression will be added and finally one or more
|
||||
congestion control schemes will be included.
|
||||
|
||||
The purpose of this release is to illustrate routines to
|
||||
build and parse the messages currently defined in the NORM
|
||||
Internet Draft.
|
||||
|
||||
The current code only has Makefiles for Unix platforms, but the
|
||||
code could be assembled as Win32 project under VC++.
|
||||
|
||||
The NORM code depends upon the current "Protolib" release.
|
||||
See <http://pf.itd.nrl.navy.mil> for that code.
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,44 @@
|
|||
/*********************************************************************
|
||||
*
|
||||
* AUTHORIZATION TO USE AND DISTRIBUTE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that:
|
||||
*
|
||||
* (1) source code distributions retain this paragraph in its entirety,
|
||||
*
|
||||
* (2) distributions including binary code include this paragraph in
|
||||
* its entirety in the documentation or other materials provided
|
||||
* with the distribution, and
|
||||
*
|
||||
* (3) all advertising materials mentioning features or use of this
|
||||
* software display the following acknowledgment:
|
||||
*
|
||||
* "This product includes software written and developed
|
||||
* by Brian Adamson and Joe Macker of the Naval Research
|
||||
* Laboratory (NRL)."
|
||||
*
|
||||
* The name of NRL, the name(s) of NRL employee(s), or any entity
|
||||
* of the United States Government may not be used to endorse or
|
||||
* promote products derived from this software, nor does the
|
||||
* inclusion of the NRL written and developed software directly or
|
||||
* indirectly suggest NRL or United States Government endorsement
|
||||
* of this product.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
********************************************************************/
|
||||
|
||||
#ifndef _GALOIS
|
||||
#define _GALOIS
|
||||
|
||||
extern const unsigned char GINV[256];
|
||||
extern const unsigned char GEXP[512];
|
||||
extern const unsigned char GMULT[256][256];
|
||||
|
||||
inline unsigned char gexp(unsigned int x) {return GEXP[x];}
|
||||
inline unsigned char gmult(unsigned int x, unsigned int y) {return GMULT[x][y];}
|
||||
inline unsigned char ginv(unsigned int x) {return GINV[x];}
|
||||
|
||||
#endif // _GALOIS
|
||||
|
|
@ -0,0 +1,250 @@
|
|||
|
||||
// norm.cpp - Command-line NORM application
|
||||
|
||||
#include "protoLib.h"
|
||||
#include "normSession.h"
|
||||
|
||||
#include <stdio.h> // for stdout/stderr printouts
|
||||
#include <signal.h> // for SIGTERM/SIGINT handling
|
||||
|
||||
class NormApp : public NormController
|
||||
{
|
||||
public:
|
||||
NormApp();
|
||||
virtual ~NormApp();
|
||||
bool OnStartup();
|
||||
int MainLoop() {return dispatcher.Run();}
|
||||
void Stop(int exitCode) {dispatcher.Stop(exitCode);}
|
||||
void OnShutdown();
|
||||
|
||||
private:
|
||||
|
||||
virtual void Notify(NormController::Event event,
|
||||
class NormSessionMgr* sessionMgr,
|
||||
class NormSession* session,
|
||||
class NormServerNode* server,
|
||||
class NormObject* object);
|
||||
|
||||
static void SignalHandler(int sigNum);
|
||||
|
||||
EventDispatcher dispatcher;
|
||||
NormSessionMgr session_mgr;
|
||||
NormSession* session;
|
||||
NormStreamObject* stream;
|
||||
|
||||
}; // end class NormApp
|
||||
|
||||
|
||||
void NormApp::Notify(NormController::Event event,
|
||||
class NormSessionMgr* sessionMgr,
|
||||
class NormSession* session,
|
||||
class NormServerNode* server,
|
||||
class NormObject* object)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case TX_QUEUE_EMPTY:
|
||||
//TRACE("NormApp::Notify(TX_QUEUE_EMPTY) ...\n");
|
||||
if (object == stream)
|
||||
{
|
||||
char text[256];
|
||||
memset(text, 'a', 256);
|
||||
stream->Write(text, 256);
|
||||
}
|
||||
break;
|
||||
|
||||
case RX_OBJECT_NEW:
|
||||
//TRACE("NormApp::Notify(RX_OBJECT_NEW) ...\n");
|
||||
{
|
||||
switch (object->GetType())
|
||||
{
|
||||
case NormObject::STREAM:
|
||||
{
|
||||
const NormObjectSize& size = object->Size();
|
||||
if (!((NormStreamObject*)object)->Accept(size.LSB()))
|
||||
{
|
||||
TRACE("stream object accept error!\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NormObject::FILE:
|
||||
case NormObject::DATA:
|
||||
TRACE("NormApp::Notify() FILE/DATA objects not supported...\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RX_OBJECT_UPDATE:
|
||||
//TRACE("NormApp::Notify(RX_OBJECT_UPDATE) ...\n");
|
||||
switch (object->GetType())
|
||||
{
|
||||
case NormObject::STREAM:
|
||||
{
|
||||
// Read the stream
|
||||
char buffer[2048];
|
||||
unsigned int nBytes;
|
||||
while ((nBytes = ((NormStreamObject*)object)->Read(buffer, 2048)))
|
||||
{
|
||||
for (unsigned int i =0; i < nBytes; i++)
|
||||
{
|
||||
if ('a' != buffer[i])
|
||||
{
|
||||
TRACE("NormApp::Notify() bad data received!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
buffer[32] = '\0';
|
||||
DMSG(0, "NormApp::Notify() stream read %u bytes: \"%s\"\n", nBytes, buffer);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case NormObject::FILE:
|
||||
case NormObject::DATA:
|
||||
TRACE("NormApp::Notify() FILE/DATA objects not supported...\n");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NormApp::NormApp()
|
||||
: session(NULL), stream(NULL)
|
||||
{
|
||||
// Init tx_timer for 1.0 second interval, infinite repeats
|
||||
session_mgr.Init(EventDispatcher::TimerInstaller, &dispatcher,
|
||||
EventDispatcher::SocketInstaller, &dispatcher,
|
||||
this);
|
||||
}
|
||||
|
||||
NormApp::~NormApp()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool NormApp::OnStartup()
|
||||
{
|
||||
#ifdef WIN32
|
||||
if (!dispatcher.Win32Init())
|
||||
{
|
||||
fprintf(stderr, "norm:: Win32Init() error!\n");
|
||||
return false;
|
||||
}
|
||||
#endif // WIN32
|
||||
|
||||
signal(SIGTERM, SignalHandler);
|
||||
signal(SIGINT, SignalHandler);
|
||||
|
||||
|
||||
session = session_mgr.NewSession("224.225.1.5", 5005);
|
||||
if (session)
|
||||
{
|
||||
if (!session->StartServer(1024*1024, 256, 20, 8))
|
||||
{
|
||||
DMSG(0, "NormApp::OnStartup() start server error!\n");
|
||||
session_mgr.Destroy();
|
||||
return false;
|
||||
}
|
||||
session->ServerSetAutoParity(4);
|
||||
//session->SetLoopback(true);
|
||||
|
||||
// Open a stream object to write to
|
||||
stream = session->QueueTxStream(10*1024);
|
||||
if (!stream)
|
||||
{
|
||||
DMSG(0, "NormApp::OnStartup() queue tx stream error!\n");
|
||||
session_mgr.Destroy();
|
||||
return false;
|
||||
}
|
||||
char text[256];
|
||||
memset(text, 'a', 256);
|
||||
stream->Write(text, 256);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} // end NormApp::OnStartup()
|
||||
|
||||
void NormApp::OnShutdown()
|
||||
{
|
||||
session_mgr.Destroy();
|
||||
} // end NormApp::OnShutdown()
|
||||
|
||||
|
||||
// Out application instance (global for SignalHandler)
|
||||
NormApp theApp;
|
||||
|
||||
// Use "main()" for UNIX and WIN32 console apps,
|
||||
// "WinMain()" for non-console WIN32
|
||||
// (VC++ uses the "_CONSOLE_ macro to indicate build type)
|
||||
|
||||
#if defined(WIN32) && !defined(_CONSOLE)
|
||||
int PASCAL WinMain(HINSTANCE instance, HINSTANCE prevInst, LPSTR cmdline, int cmdshow)
|
||||
#else
|
||||
int main(int argc, char* argv[])
|
||||
#endif
|
||||
{
|
||||
#ifdef WIN32
|
||||
// Hack to determine if Win32 console application was launched
|
||||
// independently or from a pre-existing console window
|
||||
bool pauseForUser = false;
|
||||
HANDLE hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (INVALID_HANDLE_VALUE != hConsoleOutput)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
GetConsoleScreenBufferInfo(hConsoleOutput, &csbi);
|
||||
pauseForUser = ((csbi.dwCursorPosition.X==0) && (csbi.dwCursorPosition.Y==0));
|
||||
if ((csbi.dwSize.X<=0) || (csbi.dwSize.Y <= 0)) pauseForUser = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We're not a "console" application, so create one
|
||||
// This could be commented out or made a command-line option
|
||||
OpenDebugWindow();
|
||||
pauseForUser = true;
|
||||
}
|
||||
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
int exitCode = 0;
|
||||
if (theApp.OnStartup())
|
||||
{
|
||||
exitCode = theApp.MainLoop();
|
||||
theApp.OnShutdown();
|
||||
fprintf(stderr, "norm: Done.\n");
|
||||
#ifdef WIN32
|
||||
// If Win32 console is going to disappear, pause for user before exiting
|
||||
if (pauseForUser)
|
||||
{
|
||||
printf ("Program Finished - Hit <Enter> to exit");
|
||||
getchar();
|
||||
}
|
||||
#endif // WIN32
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "norm: Error initializing application!\n");
|
||||
return -1;
|
||||
}
|
||||
return exitCode; // exitCode contains "signum" causing exit
|
||||
} // end main();
|
||||
|
||||
void NormApp::SignalHandler(int sigNum)
|
||||
{
|
||||
switch(sigNum)
|
||||
{
|
||||
case SIGTERM:
|
||||
case SIGINT:
|
||||
theApp.Stop(sigNum); // causes theApp's main loop to exit
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "norm: Unexpected signal: %d\n", sigNum);
|
||||
break;
|
||||
}
|
||||
} // end NormApp::SignalHandler()
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,184 @@
|
|||
#ifndef _NORM_BITMASK_
|
||||
#define _NORM_BITMASK_
|
||||
|
||||
#include "debug.h" // for PROTO_DEBUG stuff
|
||||
#include <string.h> // for memset()
|
||||
#include <stdio.h> // for fprintf()
|
||||
|
||||
|
||||
/***************************************************************
|
||||
* This class also provides space-efficient binary storage.
|
||||
* It's pretty much just a flat-indexed array of bits, but
|
||||
* keeps some state to be relatively efficient for various
|
||||
* operations.
|
||||
*/
|
||||
|
||||
class NormBitmask
|
||||
{
|
||||
// Methods
|
||||
public:
|
||||
NormBitmask();
|
||||
~NormBitmask();
|
||||
|
||||
bool Init(unsigned long numBits);
|
||||
void Destroy();
|
||||
unsigned long Size() {return num_bits;}
|
||||
void Clear() // set to all zero's
|
||||
{
|
||||
memset(mask, 0, mask_len);
|
||||
first_set = num_bits;
|
||||
};
|
||||
void Reset() // set to all one's
|
||||
{
|
||||
memset(mask, 0xff, (mask_len-1));
|
||||
mask[mask_len-1] = 0x00ff << ((8 - (num_bits & 0x07)) & 0x07);
|
||||
first_set = 0;
|
||||
}
|
||||
|
||||
bool IsSet() const {return (first_set < num_bits);}
|
||||
unsigned long FirstSet() const {return first_set;}
|
||||
unsigned long LastSet() const
|
||||
{
|
||||
return ((first_set < num_bits) ?
|
||||
PrevSet(num_bits - 1) : num_bits);
|
||||
}
|
||||
bool Test(unsigned long index) const
|
||||
{
|
||||
return ((index < num_bits) ?
|
||||
(0 != (mask[(index >> 3)] & (0x80 >> (index & 0x07)))) :
|
||||
false);
|
||||
}
|
||||
bool CanSet(unsigned long index) const
|
||||
{return (index < num_bits);}
|
||||
|
||||
bool Set(unsigned long index)
|
||||
{
|
||||
if (index < num_bits)
|
||||
{
|
||||
mask[(index >> 3)] |= (0x80 >> (index & 0x07));
|
||||
(index < first_set) ? (first_set = index) : 0;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool Unset(unsigned long index)
|
||||
{
|
||||
if (index < num_bits)
|
||||
{
|
||||
mask[(index >> 3)] &= ~(0x80 >> (index & 0x07));
|
||||
(index == first_set) ? first_set = NextSet(index) : 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Invert(unsigned long index)
|
||||
{return (Test(index) ? Unset(index) : Set(index));}
|
||||
|
||||
bool SetBits(unsigned long baseIndex, unsigned long count);
|
||||
bool UnsetBits(unsigned long baseIndex, unsigned long count);
|
||||
|
||||
unsigned long NextSet(unsigned long index) const;
|
||||
unsigned long PrevSet(unsigned long index) const;
|
||||
unsigned long NextUnset(unsigned long index) const;
|
||||
|
||||
bool Copy(const NormBitmask &b); // this = b
|
||||
bool Add(const NormBitmask & b); // this = this | b
|
||||
bool Subtract(const NormBitmask & b); // this = this & ~b
|
||||
bool XCopy(const NormBitmask & b); // this = ~this & b
|
||||
bool Multiply(const NormBitmask & b); // this = this & b
|
||||
bool Xor(const NormBitmask & b); // this = this ^ b
|
||||
|
||||
void Display(FILE* stream);
|
||||
|
||||
// Members
|
||||
private:
|
||||
unsigned char* mask;
|
||||
unsigned long mask_len;
|
||||
unsigned long num_bits;
|
||||
unsigned long first_set; // index of lowest _set_ bit
|
||||
}; // end class NormBitmask
|
||||
|
||||
|
||||
|
||||
/***************************************************************
|
||||
* This class also provides space-efficient binary storage.
|
||||
* More than just a flat-indexed array of bits, this
|
||||
* class can also automatically act as a sliding
|
||||
* window buffer as long as the range of set bit
|
||||
* indexes fall within the number of storage bits
|
||||
* for which the class initialized.
|
||||
*/
|
||||
|
||||
class NormSlidingMask
|
||||
{
|
||||
public:
|
||||
NormSlidingMask();
|
||||
~NormSlidingMask();
|
||||
|
||||
bool Init(long numBits);
|
||||
void Destroy();
|
||||
long Size() const {return num_bits;}
|
||||
void Clear()
|
||||
{
|
||||
memset(mask, 0, mask_len);
|
||||
start = end = num_bits;
|
||||
offset = 0;
|
||||
}
|
||||
void Reset(unsigned long index = 0)
|
||||
{
|
||||
memset(mask, 0xff, mask_len);
|
||||
mask[mask_len-1] = 0x00ff << ((8 - (num_bits & 0x07)) & 0x07);
|
||||
start = 0;
|
||||
end = num_bits - 1;
|
||||
offset = index;
|
||||
}
|
||||
bool IsSet() const {return (start < num_bits);}
|
||||
unsigned long FirstSet() const {return offset;}
|
||||
unsigned long LastSet() const
|
||||
{
|
||||
long n = end - start;
|
||||
n = (n < 0) ? (n + num_bits) : n;
|
||||
return (n + offset);
|
||||
}
|
||||
bool Test(unsigned long index) const;
|
||||
bool CanSet(unsigned long index) const;
|
||||
|
||||
bool Set(unsigned long index);
|
||||
bool Unset(unsigned long index);
|
||||
bool Invert(unsigned long index)
|
||||
{return (Test(index) ? Unset(index): Set(index));}
|
||||
|
||||
bool SetBits(unsigned long index, long count);
|
||||
bool UnsetBits(unsigned long index, long count);
|
||||
|
||||
|
||||
|
||||
// These return "FirstSet()+Size()" when finding nothing
|
||||
unsigned long NextSet(unsigned long index) const;
|
||||
unsigned long PrevSet(unsigned long index) const;
|
||||
|
||||
static unsigned long RawNextSet(const char* mask, long index, long start);
|
||||
static unsigned long RawPrevSet(const char* mask, long index, long end);
|
||||
|
||||
|
||||
bool Copy(const NormSlidingMask& b); // this = b
|
||||
bool Add(const NormSlidingMask & b); // this = this | b
|
||||
bool Subtract(const NormSlidingMask & b); // this = this & ~b
|
||||
bool XCopy(const NormSlidingMask & b); // this = ~this & b
|
||||
bool Multiply(const NormSlidingMask & b); // this = this & b
|
||||
bool Xor(const NormSlidingMask & b); // this = this ^ b
|
||||
|
||||
void Display(FILE* stream);
|
||||
|
||||
private:
|
||||
unsigned char* mask;
|
||||
unsigned long mask_len;
|
||||
long num_bits;
|
||||
long start;
|
||||
long end;
|
||||
unsigned long offset;
|
||||
}; // end class NormSlidingMask
|
||||
|
||||
#endif // _NORM_BITMASK_
|
||||
|
|
@ -0,0 +1,420 @@
|
|||
/*********************************************************************
|
||||
*
|
||||
* AUTHORIZATION TO USE AND DISTRIBUTE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that:
|
||||
*
|
||||
* (1) source code distributions retain this paragraph in its entirety,
|
||||
*
|
||||
* (2) distributions including binary code include this paragraph in
|
||||
* its entirety in the documentation or other materials provided
|
||||
* with the distribution, and
|
||||
*
|
||||
* (3) all advertising materials mentioning features or use of this
|
||||
* software display the following acknowledgment:
|
||||
*
|
||||
* "This product includes software written and developed
|
||||
* by Brian Adamson and Joe Macker of the Naval Research
|
||||
* Laboratory (NRL)."
|
||||
*
|
||||
* The name of NRL, the name(s) of NRL employee(s), or any entity
|
||||
* of the United States Government may not be used to endorse or
|
||||
* promote products derived from this software, nor does the
|
||||
* inclusion of the NRL written and developed software directly or
|
||||
* indirectly suggest NRL or United States Government endorsement
|
||||
* of this product.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
********************************************************************/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "normEncoder.h"
|
||||
#include "galois.h" // for Galois math routines
|
||||
#include "debug.h"
|
||||
|
||||
NormEncoder::NormEncoder()
|
||||
: npar(0), vecSize(0),
|
||||
genPoly(NULL), scratch(NULL)
|
||||
{
|
||||
|
||||
} // end NormEncoder::NormEncoder()
|
||||
|
||||
NormEncoder::~NormEncoder()
|
||||
{
|
||||
if (genPoly) Destroy();
|
||||
}
|
||||
|
||||
bool NormEncoder::Init(int numParity, int vecSizeMax)
|
||||
{
|
||||
// Debugging assertions
|
||||
ASSERT((numParity>=0)&&(numParity<129));
|
||||
ASSERT(vecSizeMax >= 0);
|
||||
if (genPoly) Destroy();
|
||||
npar = numParity;
|
||||
vecSize = vecSizeMax;
|
||||
// Create generator polynomial
|
||||
if(!CreateGeneratorPolynomial())
|
||||
{
|
||||
DMSG(0, "NormEncoder: Error creating generator polynomial!\n");
|
||||
return false;
|
||||
}
|
||||
// Allocate scratch space for encoding
|
||||
if(!(scratch = new unsigned char[vecSizeMax]))
|
||||
{
|
||||
DMSG(0, "NormEncoder: Error allocating memory for encoder scratch space: %s\n",
|
||||
strerror(errno));
|
||||
Destroy();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} // end NormEncoder::Init()
|
||||
|
||||
// Free memory allocated for encoder state (Encoder must be re-inited before use)
|
||||
void NormEncoder::Destroy()
|
||||
{
|
||||
if(scratch)
|
||||
{
|
||||
delete []scratch;
|
||||
scratch = NULL;
|
||||
}
|
||||
if (genPoly)
|
||||
{
|
||||
delete genPoly;
|
||||
genPoly = NULL;
|
||||
}
|
||||
} // end NormEncoder::Destroy()
|
||||
|
||||
|
||||
bool NormEncoder::CreateGeneratorPolynomial()
|
||||
{
|
||||
unsigned char *tp, *tp1, *tp2;
|
||||
int degree = 2*npar;
|
||||
if(genPoly) delete genPoly;
|
||||
|
||||
if(!(genPoly = new unsigned char[npar+1]))
|
||||
{
|
||||
DMSG(0, "NormEncoder: Error allocating memory for generator polynomial: %s\n",
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
/* Allocate memory for temporary polynomial arrays */
|
||||
if(!(tp = new unsigned char[2*degree]))
|
||||
{
|
||||
DMSG(0, "NormEncoder: Error allocating memory while computing genpoly: %s\n",
|
||||
strerror(errno));
|
||||
delete genPoly;
|
||||
return false;
|
||||
}
|
||||
if(!(tp1 = new unsigned char[2*degree]))
|
||||
{
|
||||
delete tp;
|
||||
delete genPoly;
|
||||
DMSG(0, "NormEncoder: Error allocating memory while computing genpoly: %s\n",
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
if(!(tp2 = new unsigned char[2*degree]))
|
||||
{
|
||||
delete tp1;
|
||||
delete tp;
|
||||
delete genPoly;
|
||||
DMSG(0, "NormEncoder: Error allocating memory while computing genpoly: %s\n",
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
// multiply (x + a^n) for n = 1 to npar
|
||||
memset(tp1, 0, degree*sizeof(unsigned char));
|
||||
tp1[0] = 1;
|
||||
for (int n = 1; n <= npar; n++)
|
||||
{
|
||||
memset(tp, 0, degree*sizeof(unsigned char));
|
||||
tp[0] = gexp(n); // set up x+a^n
|
||||
tp[1] = 1;
|
||||
// Polynomial multiplication
|
||||
memset(genPoly, 0, (npar+1)*sizeof(unsigned char));
|
||||
for (int i = 0; i < degree; i++)
|
||||
{
|
||||
memset(&tp2[degree], 0, degree*sizeof(unsigned char));
|
||||
// Scale tp2 by p1[i]
|
||||
for(int j=0; j<degree; j++) tp2[j]=gmult(tp1[j], tp[i]);
|
||||
// Mult(shift) tp2 right by i
|
||||
for (int j = (degree*2)-1; j >= i; j--) tp2[j] = tp2[j-i];
|
||||
memset(tp2, 0, i*sizeof(unsigned char));
|
||||
// Add into partial product
|
||||
for(int j=0; j < (npar+1); j++) genPoly[j] ^= tp2[j];
|
||||
}
|
||||
memcpy(tp1, genPoly, (npar+1)*sizeof(unsigned char));
|
||||
memset(&tp1[npar+1], 0, (2*degree)-(npar+1));
|
||||
}
|
||||
delete tp2;
|
||||
delete tp1;
|
||||
delete tp;
|
||||
return true;
|
||||
} // end NormEncoder::CreateGeneratorPolynomial()
|
||||
|
||||
|
||||
|
||||
// Encode data vectors one at a time. The user of this function
|
||||
// must keep track of when parity is ready for transmission
|
||||
// Parity data is written to list of parity vectors supplied by caller
|
||||
void NormEncoder::Encode(const char *data, char **pVec)
|
||||
{
|
||||
|
||||
#if defined(NS2) || defined(OPNET)
|
||||
return; // lobotomize FEC for faster simulations
|
||||
#endif
|
||||
|
||||
int i, j;
|
||||
unsigned char *userData, *LSFR1, *LSFR2, *pVec0;
|
||||
int npar_minus_one = npar - 1;
|
||||
unsigned char *gen_poly = &genPoly[npar_minus_one];
|
||||
ASSERT(scratch); // Make sure it's been init'd first
|
||||
// Assumes parity vectors are zero-filled at block start !!!
|
||||
// Copy pVec[0] for use in calculations
|
||||
memcpy(scratch, pVec[0], vecSize);
|
||||
if (npar > 1)
|
||||
{
|
||||
for(i = 0; i < npar_minus_one; i++)
|
||||
{
|
||||
pVec0 = scratch;
|
||||
userData = (unsigned char *) data;
|
||||
LSFR1 = (unsigned char *) pVec[i];
|
||||
LSFR2 = (unsigned char *) pVec[i+1];
|
||||
for(j = 0; j < vecSize; j++)
|
||||
*LSFR1++ = *LSFR2++ ^
|
||||
gmult(*gen_poly, (*userData++ ^ *pVec0++));
|
||||
gen_poly--;
|
||||
}
|
||||
}
|
||||
pVec0 = scratch;
|
||||
userData = (unsigned char *) data;
|
||||
LSFR1 = (unsigned char *) pVec[npar_minus_one];
|
||||
for(j = 0; j < vecSize; j++)
|
||||
*LSFR1++ = gmult(*gen_poly, (*userData++ ^ *pVec0++));
|
||||
} // end NormEncoder::Encode()
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* NormDecoder implementation routines
|
||||
*/
|
||||
|
||||
NormDecoder::NormDecoder()
|
||||
: npar(0), vector_size(0),
|
||||
Lambda(NULL), sVec(NULL), oVec(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
NormDecoder::~NormDecoder()
|
||||
{
|
||||
if (Lambda) Destroy();
|
||||
}
|
||||
|
||||
bool NormDecoder::Init(int numParity, int vecSizeMax)
|
||||
{
|
||||
// Debugging assertions
|
||||
ASSERT((numParity>=0)&&(numParity<=128));
|
||||
ASSERT(vecSizeMax >= 0);
|
||||
|
||||
if (Lambda) Destroy(); // Check if already inited ...
|
||||
|
||||
npar = numParity;
|
||||
vector_size = vecSizeMax;
|
||||
|
||||
if(!(Lambda = new unsigned char[2*npar]))
|
||||
{
|
||||
DMSG(0, "NormDecoder: Error allocating memory for Lambda: %s\n",
|
||||
strerror(errno));
|
||||
return(false);
|
||||
}
|
||||
|
||||
/* Allocate memory for sVec ptr and the syndrome vectors */
|
||||
if(!(sVec = new unsigned char*[npar]))
|
||||
{
|
||||
DMSG(0, "NormDecoder: Error allocating memory for sVec ptr: %s\n",
|
||||
strerror(errno));
|
||||
Destroy();
|
||||
return(false);
|
||||
}
|
||||
int i;
|
||||
for(i=0; i < npar; i++)
|
||||
{
|
||||
if(!(sVec[i] = new unsigned char[vecSizeMax]))
|
||||
{
|
||||
DMSG(0, "NormDecoder: Error allocating memory for new sVec: %s\n",
|
||||
strerror(errno));
|
||||
Destroy();
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate memory for the oVec ptr and the Omega vectors */
|
||||
if(!(oVec = new unsigned char*[npar]))
|
||||
{
|
||||
DMSG(0, "NormDecoder: Error allocating memory for new oVec ptr: %s\n",
|
||||
strerror(errno));
|
||||
Destroy();
|
||||
return(false);
|
||||
}
|
||||
|
||||
for(i=0; i < npar; i++)
|
||||
{
|
||||
if(!(oVec[i] = new unsigned char[vecSizeMax]))
|
||||
{
|
||||
DMSG(0, "NormDecoder: Error allocating memory for new oVec: %s",
|
||||
strerror(errno));
|
||||
Destroy();
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(scratch = new unsigned char[vecSizeMax]))
|
||||
{
|
||||
DMSG(0, "NormDecoder: Error allocating memory for scratch space: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
memset(scratch, 0, vecSizeMax*sizeof(unsigned char));
|
||||
return(true);
|
||||
} // end NormDecoder::Init()
|
||||
|
||||
|
||||
void NormDecoder::Destroy()
|
||||
{
|
||||
if (scratch)
|
||||
{
|
||||
delete scratch;
|
||||
scratch = NULL;
|
||||
}
|
||||
if(oVec)
|
||||
{
|
||||
for(int i=0; i<npar; i++)
|
||||
if (oVec[i]) delete oVec[i];
|
||||
delete oVec;
|
||||
oVec = NULL;
|
||||
}
|
||||
if(sVec)
|
||||
{
|
||||
for(int i = 0; i < npar; i++)
|
||||
if (sVec[i]) delete sVec[i];
|
||||
delete sVec;
|
||||
sVec = NULL;
|
||||
}
|
||||
if (Lambda)
|
||||
{
|
||||
|
||||
delete Lambda;
|
||||
Lambda = NULL;
|
||||
}
|
||||
} // end NormDecoder::Destroy()
|
||||
|
||||
|
||||
// This will crash & burn if (erasureCount > npar)
|
||||
int NormDecoder::Decode(char** dVec, int ndata, UINT16 erasureCount, UINT16* erasureLocs)
|
||||
{
|
||||
// Debugging assertions
|
||||
ASSERT(Lambda);
|
||||
ASSERT(erasureCount && (erasureCount<=npar));
|
||||
|
||||
#if defined(NS2) || defined (OPNET)
|
||||
return erasureCount; // lobotomize FEC for faster simulations
|
||||
#endif
|
||||
|
||||
// (A) Compute syndrome vectors
|
||||
|
||||
// First zero out erasure vectors (MDP provides zero-filled vecs)
|
||||
|
||||
// Then calculate syndrome (based on zero value erasures)
|
||||
int nvecs = npar + ndata;
|
||||
int vecSize = vector_size;
|
||||
for (int i = 0; i < npar; i++)
|
||||
{
|
||||
int X = gexp(i+1);
|
||||
unsigned char* synVec = sVec[i];
|
||||
memset(synVec, 0, vecSize*sizeof(char));
|
||||
for(int j = 0; j < nvecs; j++)
|
||||
{
|
||||
unsigned char* data = dVec[j] ? (unsigned char*)dVec[j] : scratch;
|
||||
unsigned char* S = synVec;
|
||||
for (int n = 0; n < vecSize; n++)
|
||||
{
|
||||
*S = *data++ ^ gmult(X, *S);
|
||||
S++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// (B) Init Lambda (the erasure locator polynomial)
|
||||
int degree = 2*npar;
|
||||
int nvecsMinusOne = nvecs - 1;
|
||||
memset(Lambda, 0, degree*sizeof(char));
|
||||
Lambda[0] = 1;
|
||||
for (int i = 0; i < erasureCount; i++)
|
||||
{
|
||||
int X = gexp(nvecsMinusOne - erasureLocs[i]);
|
||||
for(int j = (degree-1); j > 0; j--)
|
||||
Lambda[j] = Lambda[j] ^ gmult(X, Lambda[j-1]);
|
||||
}
|
||||
|
||||
// (C) Compute modified Omega using Lambda
|
||||
for(int i = 0; i < npar; i++)
|
||||
{
|
||||
int k = i;
|
||||
memset(oVec[i], 0, vecSize*sizeof(char));
|
||||
int m = i + 1;
|
||||
for(int j = 0; j < m; j++)
|
||||
{
|
||||
unsigned char* Omega = oVec[i];
|
||||
unsigned char* S = sVec[j];
|
||||
int Lk = Lambda[k--];
|
||||
for(int n = 0; n < vecSize; n++)
|
||||
*Omega++ ^= gmult(*S++, Lk);
|
||||
}
|
||||
}
|
||||
|
||||
// (D) Finally, fill in the erasures
|
||||
for (int i = 0; i < erasureCount; i++)
|
||||
{
|
||||
// Only fill _data_ erasures
|
||||
if (erasureLocs[i] >= ndata) return erasureCount;
|
||||
|
||||
// evaluate Lambda' (derivative) at alpha^(-i)
|
||||
// ( all odd powers disappear)
|
||||
int k = nvecsMinusOne - erasureLocs[i];
|
||||
int denom = 0;
|
||||
for (int j = 1; j < degree; j += 2)
|
||||
denom ^= gmult(Lambda[j], gexp(((255-k)*(j-1)) % 255));
|
||||
// Invert for use computing errror value below
|
||||
denom = ginv(denom);
|
||||
|
||||
// Now evaluate Omega at alpha^(-i) (numerator)
|
||||
unsigned char* eVec = (unsigned char*)dVec[erasureLocs[i]];
|
||||
for (int j = 0; j < npar; j++)
|
||||
{
|
||||
unsigned char* data = eVec;
|
||||
unsigned char* Omega = oVec[j];
|
||||
int X = gexp(((255-k)*j) % 255);
|
||||
for(int n = 0; n < vecSize; n++)
|
||||
*data++ ^= gmult(*Omega++, X);
|
||||
|
||||
}
|
||||
|
||||
// Scale numerator with denominator
|
||||
unsigned char* data = eVec;
|
||||
for(int n = 0; n < vecSize; n++)
|
||||
{
|
||||
*data = gmult(*data, denom);
|
||||
data++;
|
||||
}
|
||||
}
|
||||
return erasureCount;
|
||||
} // end NormDecoder::Decode()
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
/*********************************************************************
|
||||
*
|
||||
* AUTHORIZATION TO USE AND DISTRIBUTE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that:
|
||||
*
|
||||
* (1) source code distributions retain this paragraph in its entirety,
|
||||
*
|
||||
* (2) distributions including binary code include this paragraph in
|
||||
* its entirety in the documentation or other materials provided
|
||||
* with the distribution, and
|
||||
*
|
||||
* (3) all advertising materials mentioning features or use of this
|
||||
* software display the following acknowledgment:
|
||||
*
|
||||
* "This product includes software written and developed
|
||||
* by Brian Adamson and Joe Macker of the Naval Research
|
||||
* Laboratory (NRL)."
|
||||
*
|
||||
* The name of NRL, the name(s) of NRL employee(s), or any entity
|
||||
* of the United States Government may not be used to endorse or
|
||||
* promote products derived from this software, nor does the
|
||||
* inclusion of the NRL written and developed software directly or
|
||||
* indirectly suggest NRL or United States Government endorsement
|
||||
* of this product.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
********************************************************************/
|
||||
|
||||
#ifndef _NORM_ENCODER
|
||||
#define _NORM_ENCODER
|
||||
|
||||
#include "sysdefs.h" // protolib stuff
|
||||
|
||||
class NormEncoder
|
||||
{
|
||||
// Members
|
||||
private:
|
||||
int npar; // No. of parity packets (N-k)
|
||||
int vecSize; // Size of biggest vector to encode
|
||||
unsigned char* genPoly; // Ptr to generator polynomial
|
||||
unsigned char* scratch; // scratch space for encoding
|
||||
|
||||
// Methods
|
||||
public:
|
||||
NormEncoder();
|
||||
~NormEncoder();
|
||||
bool Init(int numParity, int vectorSize);
|
||||
void Destroy();
|
||||
bool IsReady(){return (bool)(genPoly != NULL);}
|
||||
void Encode(const char *dataVector, char **parityVectorList);
|
||||
int NumParity() {return npar;}
|
||||
int VectorSize() {return vecSize;}
|
||||
|
||||
private:
|
||||
bool CreateGeneratorPolynomial();
|
||||
};
|
||||
|
||||
|
||||
class NormDecoder
|
||||
{
|
||||
// Members
|
||||
private:
|
||||
int npar; // No. of parity packets (n-K)
|
||||
int vector_size; // Size of biggest vector to encode
|
||||
unsigned char* Lambda; // Erasure location polynomial ("2*npar" ints)
|
||||
unsigned char** sVec; // Syndrome vectors (pointers to "npar" vectors)
|
||||
unsigned char** oVec; // Omega vectors (pointers to "npar" vectors)
|
||||
unsigned char* scratch;
|
||||
// Methods
|
||||
public:
|
||||
NormDecoder();
|
||||
~NormDecoder();
|
||||
bool Init(int numParity, int vectorSize);
|
||||
int Decode(char **vectorList, int ndata, UINT16 erasureCount, UINT16* erasureLocs);
|
||||
int NumParity() {return npar;}
|
||||
int VectorSize() {return vector_size;}
|
||||
void Destroy();
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // _NORM_ENCODER
|
||||
|
|
@ -0,0 +1,453 @@
|
|||
#include "normMessage.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
NormRepairRequest::NormRepairRequest()
|
||||
: form(INVALID), flags(0), length(0), buffer(NULL), buffer_len(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool NormRepairRequest::AppendRepairItem(const NormObjectId& objectId,
|
||||
const NormBlockId& blockId,
|
||||
UINT16 symbolId)
|
||||
{
|
||||
if (buffer_len >= (CONTENT_OFFSET+length+RepairItemLength()))
|
||||
{
|
||||
UINT16 temp16 = htons((UINT16)objectId);
|
||||
memcpy(buffer+CONTENT_OFFSET+length, &temp16, 2);
|
||||
UINT32 temp32 =htonl((UINT32)blockId);
|
||||
memcpy(buffer+length+CONTENT_OFFSET+2, &temp32, 4);
|
||||
symbolId = htons(symbolId);
|
||||
memcpy(buffer+length+CONTENT_OFFSET+6, &symbolId, 2);
|
||||
length += RepairItemLength();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} // end NormRepairRequest::AppendRepairItem()
|
||||
|
||||
bool NormRepairRequest::AppendRepairRange(const NormObjectId& startObjectId,
|
||||
const NormBlockId& startBlockId,
|
||||
UINT16 startSymbolId,
|
||||
const NormObjectId& endObjectId,
|
||||
const NormBlockId& endBlockId,
|
||||
UINT16 endSymbolId)
|
||||
{
|
||||
if (buffer_len >= (CONTENT_OFFSET+length+RepairRangeLength()))
|
||||
{
|
||||
// range start
|
||||
UINT16 temp16;
|
||||
temp16 = htons((UINT16)startObjectId);
|
||||
memcpy(buffer+CONTENT_OFFSET+length, &temp16, 2);
|
||||
UINT32 temp32 =htonl((UINT32)startBlockId);
|
||||
memcpy(buffer+length+CONTENT_OFFSET+2, &temp32, 4);
|
||||
startSymbolId = htons(startSymbolId);
|
||||
memcpy(buffer+length+CONTENT_OFFSET+6, &startSymbolId, 2);
|
||||
// range end
|
||||
temp16 = htons((UINT16)endObjectId);
|
||||
memcpy(buffer+CONTENT_OFFSET+length+8, &temp16, 2);
|
||||
temp32 =htonl((UINT32)endBlockId);
|
||||
memcpy(buffer+length+CONTENT_OFFSET+10, &temp32, 4);
|
||||
endSymbolId = htons(endSymbolId);
|
||||
memcpy(buffer+length+CONTENT_OFFSET+14, &endSymbolId, 2);
|
||||
length += RepairRangeLength();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} // end NormRepairRequest::AppendErasureCount()
|
||||
|
||||
bool NormRepairRequest::AppendErasureCount(const NormObjectId& objectId,
|
||||
const NormBlockId& blockId,
|
||||
UINT16 erasureCount)
|
||||
{
|
||||
if (buffer_len >= (CONTENT_OFFSET+length+ErasureItemLength()))
|
||||
{
|
||||
UINT16 temp16 = htons((UINT16)objectId);
|
||||
memcpy(buffer+CONTENT_OFFSET+length, &temp16, 2);
|
||||
UINT32 temp32 =htonl((UINT32)blockId);
|
||||
memcpy(buffer+length+CONTENT_OFFSET+2, &temp32, 4);
|
||||
erasureCount = htons(erasureCount);
|
||||
memcpy(buffer+length+CONTENT_OFFSET+6, &erasureCount, 2);
|
||||
length += ErasureItemLength();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} // end NormRepairRequest::AppendErasureCount()
|
||||
|
||||
|
||||
UINT16 NormRepairRequest::Pack()
|
||||
{
|
||||
if (length)
|
||||
{
|
||||
buffer[FORM_OFFSET] = form;
|
||||
buffer[FLAGS_OFFSET] = (char)flags;
|
||||
UINT16 temp16 = htons(length);
|
||||
memcpy(buffer+LENGTH_OFFSET, &temp16, 2);
|
||||
return (CONTENT_OFFSET + length);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
} // end NormRepairRequest::Pack()
|
||||
|
||||
|
||||
UINT16 NormRepairRequest::Unpack()
|
||||
{
|
||||
// Make sure there's at least a header
|
||||
if (buffer_len >= CONTENT_OFFSET)
|
||||
{
|
||||
form = (Form)buffer[FORM_OFFSET];
|
||||
flags = (int)buffer[FLAGS_OFFSET];
|
||||
memcpy(&length, buffer+LENGTH_OFFSET, 2);
|
||||
length = ntohs(length);
|
||||
if (length > (buffer_len - CONTENT_OFFSET))
|
||||
{
|
||||
// Badly formed message
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (CONTENT_OFFSET+length);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
} // end NormRepairRequest::Unpack()
|
||||
|
||||
bool NormRepairRequest::RetrieveRepairItem(UINT16 offset,
|
||||
NormObjectId* objectId,
|
||||
NormBlockId* blockId,
|
||||
UINT16* symbolId) const
|
||||
{
|
||||
if (length >= (offset + RepairItemLength()))
|
||||
{
|
||||
UINT16 temp16;
|
||||
memcpy(&temp16, buffer+CONTENT_OFFSET+offset, 2);
|
||||
*objectId = ntohs(temp16);
|
||||
UINT32 temp32;
|
||||
memcpy(&temp32, buffer+CONTENT_OFFSET+offset+2, 4);
|
||||
*blockId = ntohl(temp32);
|
||||
memcpy(symbolId, buffer+CONTENT_OFFSET+offset+6, 2);
|
||||
*symbolId = ntohs(*symbolId);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} // end NormRepairRequest::RetrieveRepairItem()
|
||||
|
||||
NormRepairRequest::Iterator::Iterator(NormRepairRequest& theRequest)
|
||||
: request(theRequest), offset(0)
|
||||
{
|
||||
}
|
||||
|
||||
// For erasure requests, symbolId is loaded with erasureCount
|
||||
bool NormRepairRequest::Iterator::NextRepairItem(NormObjectId* objectId,
|
||||
NormBlockId* blockId,
|
||||
UINT16* symbolId)
|
||||
{
|
||||
if (request.RetrieveRepairItem(offset, objectId, blockId, symbolId))
|
||||
{
|
||||
offset += NormRepairRequest::RepairItemLength();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} // end NormRepairRequest::Iterator::NextRepairItem()
|
||||
|
||||
|
||||
NormMessageQueue::NormMessageQueue()
|
||||
: head(NULL), tail(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
NormMessageQueue::~NormMessageQueue()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void NormMessageQueue::Destroy()
|
||||
{
|
||||
NormMessage* next;
|
||||
while ((next = head))
|
||||
{
|
||||
head = next->next;
|
||||
delete next;
|
||||
}
|
||||
} // end NormMessageQueue::Destroy()
|
||||
|
||||
|
||||
void NormMessageQueue::Prepend(NormMessage* msg)
|
||||
{
|
||||
if ((msg->next = head))
|
||||
head->prev = msg;
|
||||
else
|
||||
tail = msg;
|
||||
msg->prev = NULL;
|
||||
head = msg;
|
||||
} // end NormMessageQueue::Prepend()
|
||||
|
||||
void NormMessageQueue::Append(NormMessage* msg)
|
||||
{
|
||||
if ((msg->prev = tail))
|
||||
tail->next = msg;
|
||||
else
|
||||
head = msg;
|
||||
msg->next = NULL;
|
||||
tail = msg;
|
||||
} // end NormMessageQueue::Append()
|
||||
|
||||
void NormMessageQueue::Remove(NormMessage* msg)
|
||||
{
|
||||
if (msg->prev)
|
||||
msg->prev->next = msg->next;
|
||||
else
|
||||
head = msg->next;
|
||||
if (msg->next)
|
||||
msg->next->prev = msg->prev;
|
||||
else
|
||||
tail = msg->prev;
|
||||
} // end NormMessageQueue::Remove()
|
||||
|
||||
NormMessage* NormMessageQueue::RemoveHead()
|
||||
{
|
||||
if (head)
|
||||
{
|
||||
NormMessage* msg = head;
|
||||
if ((head = msg->next))
|
||||
msg->next->prev = NULL;
|
||||
else
|
||||
tail = NULL;
|
||||
return msg;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
} // end NormMessageQueue::RemoveHead()
|
||||
|
||||
NormMessage* NormMessageQueue::RemoveTail()
|
||||
{
|
||||
if (tail)
|
||||
{
|
||||
NormMessage* msg = tail;
|
||||
if ((tail = msg->prev))
|
||||
msg->prev->next = NULL;
|
||||
else
|
||||
head = NULL;
|
||||
return msg;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
} // end NormMessageQueue::RemoveTail()
|
||||
|
||||
bool NormObjectSize::operator<(const NormObjectSize& size) const
|
||||
{
|
||||
UINT16 diff = msb - size.msb;
|
||||
if (0 == diff)
|
||||
return (lsb < size.lsb);
|
||||
else if ((diff > 0x8000) ||
|
||||
((0x8000 == diff) && (msb > size.msb)))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
} // end NormObjectSize::operator<(NormObjectSize size)
|
||||
|
||||
bool NormObjectSize::operator>(const NormObjectSize& size) const
|
||||
{
|
||||
UINT16 diff = size.msb - msb;
|
||||
if (0 == diff)
|
||||
return (lsb > size.lsb);
|
||||
else if ((diff > 0x8000) ||
|
||||
((0x8000 == diff) && (size.msb > msb)))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
} // end NormObjectSize::operator>(NormObjectSize id)
|
||||
|
||||
NormObjectSize NormObjectSize::operator+(const NormObjectSize& size) const
|
||||
{
|
||||
NormObjectSize total;
|
||||
total.msb = msb + size.msb;
|
||||
total.lsb = lsb + size.lsb;
|
||||
if ((total.lsb < lsb) || (total.lsb < size.lsb)) total.msb++;
|
||||
return total;
|
||||
} // end NormObjectSize::operator+(NormObjectSize id)
|
||||
|
||||
NormObjectSize NormObjectSize::operator-(const NormObjectSize& b) const
|
||||
{
|
||||
NormObjectSize result;
|
||||
result.lsb = lsb - b.lsb;
|
||||
result.msb = msb - b.msb;
|
||||
if (lsb < b.lsb) result.msb--;
|
||||
return result;
|
||||
} // end NormObjectSize::operator-(NormObjectSize id)
|
||||
|
||||
NormObjectSize NormObjectSize::operator*(const NormObjectSize& b) const
|
||||
{
|
||||
UINT32 ll = (lsb & 0x0000ffff) * (b.lsb & 0x0000ffff);
|
||||
UINT32 lm = (lsb & 0x0000ffff) * ((b.lsb >> 16) & 0x0000ffff);
|
||||
UINT32 ml = ((lsb >> 16) & 0x0000ffff) * (b.lsb & 0x0000ffff);
|
||||
UINT32 lu = (lsb & 0x0000ffff) * (UINT32)b.msb;
|
||||
UINT32 mm = ((lsb >> 16) & 0x0000ffff) *
|
||||
((b.lsb >> 16) & 0x0000ffff);
|
||||
NormObjectSize result;
|
||||
result.lsb = ll + (lm << 16) + (ml << 16);
|
||||
result.msb = lu + mm + ((lm >> 16) & 0x0000ffff) +
|
||||
((ml >> 16) & 0x0000ffff);
|
||||
return result;
|
||||
} // end NormObjectSize::operator*(NormObjectSize size)
|
||||
|
||||
NormObjectSize NormObjectSize::operator/(const NormObjectSize& b) const
|
||||
{
|
||||
// Zero dividend is special case
|
||||
if ((0 == lsb) && (0 == msb)) return NormObjectSize(0, 0);
|
||||
// Zero divisor is special case
|
||||
if ((0 == b.lsb) && (0 == b.msb)) return NormObjectSize(0xffff, 0xffffffff);
|
||||
// Dividend equals divisor is special case
|
||||
if (*this == b) return NormObjectSize(0,1);
|
||||
// Divisor > dividend is special case
|
||||
if ((b.lsb > lsb) && (b.msb > msb)) return NormObjectSize(0,1);
|
||||
// divisor
|
||||
UINT32 divisor[2];
|
||||
divisor[0] = (UINT32)b.msb;
|
||||
divisor[1] = b.lsb;
|
||||
// dividend
|
||||
UINT32 dividend[2];
|
||||
dividend[0] = msb;
|
||||
dividend[1] = (UINT32)lsb;
|
||||
// remainder
|
||||
UINT32 remainder[2];
|
||||
remainder[0] = remainder[1] = 0;
|
||||
unsigned int numBits = 64;
|
||||
UINT32 d[2];
|
||||
while (((divisor[1] > remainder[1]) && (divisor[0] == remainder[0])) ||
|
||||
(divisor[0] > remainder[0]))
|
||||
{
|
||||
remainder[0] <<= 1;
|
||||
remainder[0] |= (remainder[1] >> 31) & 0x00000001;
|
||||
remainder[1] <<= 1;
|
||||
remainder[1] |= (dividend[0] >> 31) & 0x00000001;
|
||||
d[0] = dividend[0];
|
||||
d[1] = dividend[1];
|
||||
dividend[0] <<= 1;
|
||||
dividend[0] |= (dividend[1] >> 31) & 0x00000001;
|
||||
dividend[1] <<= 1;
|
||||
numBits--;
|
||||
}
|
||||
|
||||
// Note: above loop goes one step too far
|
||||
// so we incr numBits, use old dividend (d)
|
||||
numBits++;
|
||||
UINT32 quotient[2];
|
||||
quotient[0] = quotient[1] = 0;
|
||||
bool extra = false;
|
||||
for (unsigned int i = 0; i < numBits; i++)
|
||||
{
|
||||
UINT32 t[2];
|
||||
t[0] = remainder[0] - divisor[0];
|
||||
t[1] = remainder[1] - divisor[1];
|
||||
if (remainder[1] < divisor[1]) t[0]--;
|
||||
UINT32 q = ((t[0] >> 31) & 0x00000001) ^ 0x00000001;
|
||||
d[0] <<= 1;
|
||||
d[0] |= (d[1] >> 31) & 0x00000001;
|
||||
d[1] <<= 1;
|
||||
quotient[0] <<= 1;
|
||||
quotient[1] = (quotient[1] << 1) | q;
|
||||
if (q)
|
||||
{
|
||||
remainder[0] = t[0];
|
||||
remainder[1] = t[1];
|
||||
}
|
||||
if (remainder[0] || remainder[1])
|
||||
extra = true;
|
||||
else
|
||||
extra = false;
|
||||
remainder[0] <<= 1;
|
||||
remainder[0] |= (remainder[1] >> 31) & 0x00000001;
|
||||
remainder[1] <<= 1;
|
||||
remainder[1] |= (d[0] >> 31) & 0x00000001;
|
||||
}
|
||||
NormObjectSize result((UINT16)quotient[0], quotient[1]);
|
||||
// If there was _any_ remainder, round up
|
||||
if (extra) result++;
|
||||
return result;
|
||||
} // end NormObjectSize::operator/(NormObjectSize b)
|
||||
|
||||
|
||||
bool NormObjectId::operator<(const NormObjectId& id) const
|
||||
{
|
||||
UINT16 diff = value - id.value;
|
||||
if ((diff > 0x8000) ||
|
||||
((0x8000 == diff) && (value > id.value)))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
} // end NormObjectId::operator<(NormObjectId id)
|
||||
|
||||
bool NormObjectId::operator>(const NormObjectId& id) const
|
||||
{
|
||||
UINT16 diff = id.value - value;;
|
||||
if ((diff > 0x8000) ||
|
||||
((0x8000 == diff) && (id.value > value)))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
} // end NormObjectId::operator>(NormObjectId id)
|
||||
|
||||
int NormObjectId::operator-(const NormObjectId& id) const
|
||||
{
|
||||
UINT16 diff = value - id.value;
|
||||
if ((diff > 0x8000) ||
|
||||
((0x8000 == diff) && (value > id.value)))
|
||||
return ((INT16)(value - id.value));
|
||||
else
|
||||
return (-(INT16)(id.value - value));
|
||||
} // end NormObjectId::operator-(NormObjectId id) const
|
||||
|
||||
|
||||
bool NormBlockId::operator<(const NormBlockId& id) const
|
||||
{
|
||||
UINT32 diff = value - id.value;
|
||||
if ((diff > 0x80000000) ||
|
||||
((0x80000000 == diff) && (value > id.value)))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
} // end NormBlockId::operator<(NormBlockId id)
|
||||
|
||||
bool NormBlockId::operator>(const NormBlockId& id) const
|
||||
{
|
||||
UINT32 diff = id.value - value;;
|
||||
if ((diff > 0x80000000) ||
|
||||
((0x80000000 == diff) && (id.value > value)))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
} // end NormBlockId::operator>(NormBlockId id)
|
||||
|
||||
long NormBlockId::operator-(const NormBlockId& id) const
|
||||
{
|
||||
UINT32 diff = value - id.value;
|
||||
if ((diff > 0x80000000) ||
|
||||
((0x80000000 == diff) && (value > id.value)))
|
||||
return ((INT32)(value - id.value));
|
||||
else
|
||||
return (-(INT32)(id.value - value));
|
||||
} // end NormBlockId::operator-(NormBlockId id) const
|
||||
|
|
@ -0,0 +1,975 @@
|
|||
#ifndef _NORM_MESSAGE
|
||||
#define _NORM_MESSAGE
|
||||
|
||||
// PROTOLIB includes
|
||||
#include <networkAddress.h> // for NetworkAddress class
|
||||
#include <sysdefs.h> // for UINT typedefs
|
||||
#include <debug.h>
|
||||
|
||||
// standard includes
|
||||
#include <string.h> // for memcpy(), etc
|
||||
|
||||
// (TBD) Alot of the "memcpy()" calls could be eliminated by
|
||||
// taking advantage of the alignment of NORM messsages
|
||||
|
||||
const UINT16 NORM_MSG_SIZE_MAX = 8192;
|
||||
const int NORM_ROBUST_FACTOR = 20; // default robust factor
|
||||
|
||||
// This class is used to describe object "size" and/or "offset"
|
||||
class NormObjectSize
|
||||
{
|
||||
public:
|
||||
NormObjectSize() : msb(0), lsb(0) {}
|
||||
NormObjectSize(UINT16 upper, UINT32 lower) : msb(upper), lsb(lower) {}
|
||||
NormObjectSize(UINT32 size) : msb(0), lsb(size) {}
|
||||
NormObjectSize(UINT16 size) : msb(0), lsb(size) {}
|
||||
NormObjectSize(const NormObjectSize& size) : msb(size.msb), lsb(size.lsb) {}
|
||||
|
||||
UINT16 MSB() const {return msb;}
|
||||
UINT32 LSB() const {return lsb;}
|
||||
|
||||
bool operator<(const NormObjectSize& size) const;
|
||||
bool operator>(const NormObjectSize& size) const;
|
||||
bool operator==(const NormObjectSize& size) const
|
||||
{return ((msb == size.msb) && (lsb == size.lsb));}
|
||||
bool operator!=(const NormObjectSize& size) const
|
||||
{return ((lsb != size.lsb) || (msb != size.msb));}
|
||||
NormObjectSize operator+(const NormObjectSize& size) const;
|
||||
NormObjectSize operator-(const NormObjectSize& size) const;
|
||||
void operator+=(UINT32 increment)
|
||||
{
|
||||
UINT32 temp32 = lsb + increment;
|
||||
if (temp32 < lsb) msb++;
|
||||
lsb = temp32;
|
||||
}
|
||||
NormObjectSize operator+(UINT32 increment) const
|
||||
{
|
||||
NormObjectSize total;
|
||||
total.msb = msb;
|
||||
total.lsb = lsb + increment;
|
||||
if (total.lsb < lsb) total.msb++;
|
||||
return total;
|
||||
}
|
||||
NormObjectSize& operator++(int)
|
||||
{
|
||||
lsb++;
|
||||
if (0 == lsb) msb++;
|
||||
return (*this);
|
||||
}
|
||||
NormObjectSize operator*(const NormObjectSize& b) const;
|
||||
NormObjectSize operator/(const NormObjectSize& b) const;
|
||||
|
||||
private:
|
||||
UINT16 msb;
|
||||
UINT32 lsb;
|
||||
}; // end class NormObjectSize
|
||||
|
||||
typedef UINT32 NormNodeId;
|
||||
|
||||
class NormObjectId
|
||||
{
|
||||
public:
|
||||
NormObjectId() {};
|
||||
NormObjectId(UINT16 id) {value = id;}
|
||||
NormObjectId(const NormObjectId& id) {value = id.value;}
|
||||
operator UINT16() const {return value;}
|
||||
bool operator<(const NormObjectId& id) const;
|
||||
bool operator>(const NormObjectId& id) const;
|
||||
bool operator==(const NormObjectId& id) const
|
||||
{return (value == id.value);}
|
||||
bool operator!=(const NormObjectId& id) const
|
||||
{return (value != id.value);}
|
||||
int operator-(const NormObjectId& id) const;
|
||||
NormObjectId& operator++(int ) {value++; return *this;}
|
||||
|
||||
private:
|
||||
UINT16 value;
|
||||
}; // end class NormObjectId
|
||||
|
||||
class NormBlockId
|
||||
{
|
||||
public:
|
||||
NormBlockId() {};
|
||||
NormBlockId(UINT32 id) {value = id;}
|
||||
NormBlockId(const NormObjectId& id) {value = (UINT32)id;}
|
||||
operator UINT32() const {return value;}
|
||||
bool operator<(const NormBlockId& id) const;
|
||||
bool operator>(const NormBlockId& id) const;
|
||||
bool operator==(const NormBlockId& id) const
|
||||
{return (value == (UINT32)id);}
|
||||
bool operator!=(const NormBlockId& id) const
|
||||
{return (value != (UINT32)id);}
|
||||
long operator-(const NormBlockId& id) const;
|
||||
NormBlockId& operator++(int ) {value++; return *this;}
|
||||
|
||||
private:
|
||||
UINT32 value;
|
||||
}; // end class NormObjectId
|
||||
|
||||
typedef UINT16 NormSymbolId;
|
||||
typedef NormSymbolId NormSegmentId;
|
||||
|
||||
const NormNodeId NORM_NODE_INVALID = 0x0;
|
||||
const NormNodeId NORM_NODE_ANY = 0xffffffff;
|
||||
|
||||
enum NormMsgType
|
||||
{
|
||||
NORM_MSG_INVALID,
|
||||
NORM_MSG_INFO,
|
||||
NORM_MSG_DATA,
|
||||
NORM_MSG_CMD,
|
||||
NORM_MSG_NACK,
|
||||
NORM_MSG_ACK,
|
||||
NORM_MSG_REPORT
|
||||
};
|
||||
|
||||
class NormMsg
|
||||
{
|
||||
public:
|
||||
// Message building routines
|
||||
void SetVersion(UINT8 version) {buffer[VERSION_OFFSET] = version;}
|
||||
void SetType(NormMsgType type) {buffer[TYPE_OFFSET] = type;}
|
||||
void SetSequence(UINT16 sequence)
|
||||
{
|
||||
UINT16 temp16 = htons(sequence);
|
||||
memcpy(buffer+SEQUENCE_OFFSET, &temp16, 2);
|
||||
}
|
||||
void SetSender(NormNodeId sender)
|
||||
{
|
||||
UINT32 temp32 = htonl(sender);
|
||||
memcpy(buffer+SENDER_OFFSET, &temp32, 4);
|
||||
}
|
||||
|
||||
void SetDestination(const NetworkAddress& dest)
|
||||
{addr = dest;}
|
||||
|
||||
// Message processing routines
|
||||
UINT8 GetVersion() const {return buffer[VERSION_OFFSET];}
|
||||
NormMsgType GetType() const {return (NormMsgType)buffer[TYPE_OFFSET];}
|
||||
UINT16 GetSequence() const
|
||||
{
|
||||
UINT16 temp16;
|
||||
memcpy(&temp16, buffer+SEQUENCE_OFFSET, 2);
|
||||
return (ntohs(temp16));
|
||||
}
|
||||
NormNodeId GetSender() const
|
||||
{
|
||||
UINT32 temp32;
|
||||
memcpy(&temp32, buffer+SENDER_OFFSET, 4);
|
||||
return (ntohl(temp32));
|
||||
}
|
||||
|
||||
// For message buffer transmission/reception and misc.
|
||||
NetworkAddress* Src() {return &addr;}
|
||||
NetworkAddress* Dest() {return &addr;}
|
||||
char* GetBuffer() {return buffer;}
|
||||
UINT16 GetLength() const {return length;}
|
||||
void SetLength(UINT16 len) {length = len;}
|
||||
|
||||
|
||||
protected:
|
||||
// Common message header offsets
|
||||
enum
|
||||
{
|
||||
VERSION_OFFSET = 0,
|
||||
TYPE_OFFSET = VERSION_OFFSET + 1,
|
||||
SEQUENCE_OFFSET = TYPE_OFFSET + 1,
|
||||
SENDER_OFFSET = SEQUENCE_OFFSET + 2,
|
||||
MSG_OFFSET = SENDER_OFFSET + 4
|
||||
};
|
||||
char buffer[NORM_MSG_SIZE_MAX];
|
||||
UINT16 length;
|
||||
NetworkAddress addr; // src/dst (default dst is session address)
|
||||
}; // end class NormMsg
|
||||
|
||||
// "NormObjectMsg" are comprised of NORM_INFO and NORM_DATA messages
|
||||
// (NormInfoMsg and NormDataMsg will derive from this type)
|
||||
|
||||
class NormObjectMsg : public NormMsg
|
||||
{
|
||||
public:
|
||||
enum Flag
|
||||
{
|
||||
FLAG_REPAIR = 0x01,
|
||||
FLAG_EXPLICIT = 0x02,
|
||||
FLAG_INFO = 0x04,
|
||||
FLAG_UNRELIABLE = 0x08,
|
||||
FLAG_FILE = 0x10,
|
||||
FLAG_STREAM = 0x20
|
||||
};
|
||||
bool FlagIsSet(NormObjectMsg::Flag flag) const
|
||||
{return (0 != (flag & buffer[FLAGS_OFFSET]));}
|
||||
UINT8 GetGrtt() const {return buffer[GRTT_OFFSET];}
|
||||
UINT8 GetGroupSize() const {return buffer[GSIZE_OFFSET];}
|
||||
UINT8 GetFecId() const {return buffer[FEC_ID_OFFSET];}
|
||||
UINT16 GetSegmentSize() const
|
||||
{
|
||||
UINT16 segmentSize;
|
||||
memcpy(&segmentSize, buffer+SEG_SIZE_OFFSET, 2);
|
||||
return (ntohs(segmentSize));
|
||||
}
|
||||
NormObjectSize GetObjectSize() const
|
||||
{
|
||||
UINT16 temp16;
|
||||
memcpy(&temp16, buffer+OBJ_SIZE_OFFSET, 2);
|
||||
UINT32 temp32;
|
||||
memcpy(&temp32, buffer+OBJ_SIZE_OFFSET+2, 4);
|
||||
return NormObjectSize(ntohs(temp16), ntohl(temp32));
|
||||
}
|
||||
UINT16 GetFecEncodingName() const
|
||||
{
|
||||
UINT16 encodingName;
|
||||
memcpy(&encodingName, buffer+FEC_NAME_OFFSET, 2);
|
||||
return (ntohs(encodingName));
|
||||
}
|
||||
UINT16 GetFecNumParity() const
|
||||
{
|
||||
UINT16 nparity;
|
||||
memcpy(&nparity, buffer+FEC_NPARITY_OFFSET, 2);
|
||||
return (ntohs(nparity));
|
||||
}
|
||||
UINT16 GetFecBlockLen() const
|
||||
{
|
||||
UINT16 nparity;
|
||||
memcpy(&nparity, buffer+FEC_NDATA_OFFSET, 2);
|
||||
return (ntohs(nparity));
|
||||
}
|
||||
NormObjectId GetObjectId() const
|
||||
{
|
||||
UINT16 temp16;
|
||||
memcpy(&temp16, buffer+OBJ_ID_OFFSET, 2);
|
||||
return (ntohs(temp16));
|
||||
}
|
||||
|
||||
// Message building routines
|
||||
|
||||
void SetFlag(NormObjectMsg::Flag flag)
|
||||
{buffer[FLAGS_OFFSET] |= flag;}
|
||||
void SetGrtt(UINT8 grtt) {buffer[GRTT_OFFSET] = grtt;}
|
||||
void SetGroupSize(UINT8 gsize) {buffer[GSIZE_OFFSET] = gsize;}
|
||||
void SetFecId(UINT8 fecId) {buffer[FEC_ID_OFFSET] = fecId;}
|
||||
void SetSegmentSize(UINT16 segmentSize)
|
||||
{
|
||||
segmentSize = htons(segmentSize);
|
||||
memcpy(buffer+SEG_SIZE_OFFSET, &segmentSize, 2);
|
||||
}
|
||||
void SetObjectSize(const NormObjectSize& objectSize)
|
||||
{
|
||||
UINT16 temp16 = htons(objectSize.MSB());
|
||||
memcpy(buffer+OBJ_SIZE_OFFSET, &temp16, 2);
|
||||
UINT32 temp32 = htonl(objectSize.LSB());
|
||||
memcpy(buffer+OBJ_SIZE_OFFSET+2, &temp32, 4);
|
||||
}
|
||||
void SetFecEncodingName(UINT16 encodingName)
|
||||
{
|
||||
encodingName = htons(encodingName);
|
||||
memcpy(buffer+FEC_NAME_OFFSET, &encodingName, 2);
|
||||
}
|
||||
void SetFecNumParity(UINT16 nparity)
|
||||
{
|
||||
nparity = htons(nparity);
|
||||
memcpy(buffer+FEC_NPARITY_OFFSET, &nparity, 2);
|
||||
}
|
||||
void SetFecBlockLen(UINT16 blockLen)
|
||||
{
|
||||
blockLen = htons(blockLen);
|
||||
memcpy(buffer+FEC_NDATA_OFFSET, &blockLen, 2);
|
||||
}
|
||||
void SetObjectId(const NormObjectId& objectId)
|
||||
{
|
||||
UINT16 temp16 = htons((UINT16)objectId);
|
||||
memcpy(buffer+OBJ_ID_OFFSET, &temp16, 2);
|
||||
}
|
||||
|
||||
protected:
|
||||
enum
|
||||
{
|
||||
FLAGS_OFFSET = MSG_OFFSET,
|
||||
GRTT_OFFSET = FLAGS_OFFSET + 1,
|
||||
GSIZE_OFFSET = GRTT_OFFSET + 1,
|
||||
FEC_ID_OFFSET = GSIZE_OFFSET + 1,
|
||||
SEG_SIZE_OFFSET = FEC_ID_OFFSET + 1,
|
||||
OBJ_SIZE_OFFSET = SEG_SIZE_OFFSET + 2,
|
||||
RESV_OFFSET = OBJ_SIZE_OFFSET + 6,
|
||||
FEC_NAME_OFFSET = RESV_OFFSET + 2,
|
||||
FEC_NPARITY_OFFSET = FEC_NAME_OFFSET + 2,
|
||||
FEC_NDATA_OFFSET = FEC_NPARITY_OFFSET + 2,
|
||||
OBJ_ID_OFFSET = FEC_NDATA_OFFSET + 2
|
||||
};
|
||||
}; // end class NormObjectMsg
|
||||
|
||||
class NormInfoMsg : public NormObjectMsg
|
||||
{
|
||||
public:
|
||||
UINT16 GetInfoLen() const {return (length - INFO_OFFSET);}
|
||||
const char* GetInfo() const {return (buffer + INFO_OFFSET);}
|
||||
void SetInfo(char* data, UINT16 len)
|
||||
{
|
||||
memcpy(buffer+INFO_OFFSET, data, len);
|
||||
length = len + INFO_OFFSET;
|
||||
}
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
INFO_OFFSET = OBJ_ID_OFFSET + 2
|
||||
};
|
||||
}; // end class NormInfoMsg
|
||||
|
||||
class NormDataMsg : public NormObjectMsg
|
||||
{
|
||||
public:
|
||||
// Message building methods
|
||||
void SetFecBlockId(const NormBlockId& blockId)
|
||||
{
|
||||
UINT32 temp32 = htonl((UINT32)blockId);
|
||||
memcpy(buffer+BLOCK_ID_OFFSET, &temp32, 4);
|
||||
}
|
||||
void SetFecSymbolId(UINT16 symbolId)
|
||||
{
|
||||
symbolId = htons(symbolId);
|
||||
memcpy(buffer+SYMBOL_ID_OFFSET, &symbolId, 2);
|
||||
}
|
||||
char* AccessData() {return (buffer+DATA_OFFSET);}
|
||||
void SetData(const NormObjectSize& offset, char* data, UINT16 len)
|
||||
{
|
||||
WriteLength(buffer+LENGTH_OFFSET, len);
|
||||
WriteOffset(buffer+LENGTH_OFFSET, offset);
|
||||
memcpy(buffer+DATA_OFFSET, data, len);
|
||||
length = DATA_OFFSET + len;
|
||||
}
|
||||
void SetDataOffset(const NormObjectSize& offset)
|
||||
{
|
||||
WriteOffset(buffer+LENGTH_OFFSET, offset);
|
||||
}
|
||||
void SetDataLength(UINT16 len)
|
||||
{
|
||||
WriteLength(buffer+LENGTH_OFFSET, len);
|
||||
length = DATA_OFFSET + len;
|
||||
}
|
||||
// (Note: "payload_len" and "offset" field spaces are in the FEC payload)
|
||||
char* AccessPayload() {return (buffer+PAYLOAD_OFFSET);}
|
||||
void SetPayload(const char* data, UINT16 len)
|
||||
{
|
||||
memcpy(buffer+PAYLOAD_OFFSET, data, len);
|
||||
length = PAYLOAD_OFFSET + len;
|
||||
}
|
||||
|
||||
// Message processing methods
|
||||
NormBlockId GetFecBlockId() const
|
||||
{
|
||||
UINT32 temp32;
|
||||
memcpy(&temp32, buffer+BLOCK_ID_OFFSET, 4);
|
||||
return (ntohl(temp32));
|
||||
}
|
||||
UINT16 GetFecSymbolId() const
|
||||
{
|
||||
UINT16 temp16;
|
||||
memcpy(&temp16, buffer+SYMBOL_ID_OFFSET, 2);
|
||||
return (ntohs(temp16));
|
||||
}
|
||||
bool IsData() const {return (GetFecSymbolId() < GetFecBlockLen());}
|
||||
const char* GetData() {return (buffer + DATA_OFFSET);}
|
||||
UINT16 GetDataLen() const {return (length - DATA_OFFSET);}
|
||||
|
||||
const char* GetPayload() {return (buffer+LENGTH_OFFSET);}
|
||||
UINT16 GetPayloadLen() const {return (length - LENGTH_OFFSET);}
|
||||
|
||||
bool IsParity() const {return (GetFecSymbolId() >= GetFecBlockLen());}
|
||||
// (Note: "payload_len" and "offset" field spaces are in the FEC payload)
|
||||
char* GetParity() {return buffer+LENGTH_OFFSET;}
|
||||
// (Note: This should be the same as "segment_size")
|
||||
UINT16 GetParityLen() const
|
||||
{return (length - LENGTH_OFFSET);}
|
||||
|
||||
// Some static helper routines for various purposes
|
||||
static UINT16 PayloadHeaderLen() {return (DATA_OFFSET - LENGTH_OFFSET);}
|
||||
static void WriteLength(char* payload, UINT16 len)
|
||||
{
|
||||
UINT16 temp16 = htons(len);
|
||||
memcpy(payload+LENGTH_OFFSET-LENGTH_OFFSET, &temp16, 2);
|
||||
}
|
||||
static void WriteOffset(char* payload, const NormObjectSize& offset)
|
||||
{
|
||||
UINT16 temp16 = htons(offset.MSB());
|
||||
memcpy(payload+OFFSET_OFFSET-LENGTH_OFFSET, &temp16, 2);
|
||||
UINT32 temp32 = htonl(offset.LSB());
|
||||
memcpy(payload+OFFSET_OFFSET-LENGTH_OFFSET+2, &temp32, 4);
|
||||
}
|
||||
static UINT16 ReadLength(const char* payload)
|
||||
{
|
||||
UINT16 temp16;
|
||||
memcpy(&temp16, payload+LENGTH_OFFSET-LENGTH_OFFSET, 2);
|
||||
return ntohs(temp16);
|
||||
}
|
||||
static NormObjectSize ReadOffset(const char* payload)
|
||||
{
|
||||
UINT16 temp16;
|
||||
memcpy(&temp16, payload+OFFSET_OFFSET-LENGTH_OFFSET, 2);
|
||||
UINT32 temp32;
|
||||
memcpy(&temp32, payload+OFFSET_OFFSET-LENGTH_OFFSET+2, 4);
|
||||
return NormObjectSize(ntohs(temp16), ntohl(temp32));
|
||||
}
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
BLOCK_ID_OFFSET = OBJ_ID_OFFSET + 2,
|
||||
SYMBOL_ID_OFFSET = BLOCK_ID_OFFSET + 4,
|
||||
PAYLOAD_OFFSET = SYMBOL_ID_OFFSET + 2,
|
||||
LENGTH_OFFSET = PAYLOAD_OFFSET,
|
||||
OFFSET_OFFSET = LENGTH_OFFSET + 2,
|
||||
DATA_OFFSET = OFFSET_OFFSET + 6
|
||||
};
|
||||
}; // end class NormDataMsg
|
||||
|
||||
|
||||
class NormCmdMsg : public NormMsg
|
||||
{
|
||||
public:
|
||||
enum Flavor
|
||||
{
|
||||
NORM_CMD_INVALID,
|
||||
NORM_CMD_FLUSH,
|
||||
NORM_CMD_SQUELCH,
|
||||
NORM_CMD_ACK_REQ,
|
||||
NORM_CMD_REPAIR_ADV,
|
||||
NORM_CMD_CC,
|
||||
NORM_CMD_APPLICATION
|
||||
};
|
||||
|
||||
// Message building
|
||||
void SetGrtt(UINT8 quantizedGrtt)
|
||||
{buffer[GRTT_OFFSET] = quantizedGrtt;}
|
||||
void SetGroupSize(UINT8 quantizedGroupSize)
|
||||
{buffer[GSIZE_OFFSET] = quantizedGroupSize;}
|
||||
void SetFlavor(NormCmdMsg::Flavor flavor)
|
||||
{buffer[FLAVOR_OFFSET] = flavor;}
|
||||
|
||||
// Message processing
|
||||
UINT8 GetGrtt() {return buffer[GRTT_OFFSET];}
|
||||
UINT8 GetGroupSize() {return buffer[GSIZE_OFFSET];}
|
||||
NormCmdMsg::Flavor GetFlavor() {return (Flavor)buffer[FLAVOR_OFFSET];}
|
||||
|
||||
protected:
|
||||
enum
|
||||
{
|
||||
GRTT_OFFSET = MSG_OFFSET,
|
||||
GSIZE_OFFSET = GRTT_OFFSET + 1,
|
||||
FLAVOR_OFFSET = GSIZE_OFFSET + 1
|
||||
};
|
||||
}; // end class NormCmdMsg
|
||||
|
||||
class NormCmdFlushMsg : public NormCmdMsg
|
||||
{
|
||||
public:
|
||||
enum Flag {NORM_FLUSH_FLAG_EOT = 0x01};
|
||||
|
||||
// Message building
|
||||
void SetFlag(NormCmdFlushMsg::Flag flag)
|
||||
{buffer[FLAGS_OFFSET] |= flag;}
|
||||
void UnsetFlag(NormCmdFlushMsg::Flag flag)
|
||||
{buffer[FLAGS_OFFSET] &= ~flag;}
|
||||
void SetObjectId(const NormObjectId& objectId)
|
||||
{
|
||||
UINT16 temp16 = htons((UINT16)objectId);
|
||||
memcpy(buffer+OBJECT_ID_OFFSET, &temp16, 2);
|
||||
}
|
||||
void SetFecBlockId(const NormBlockId& blockId)
|
||||
{
|
||||
UINT32 temp32 = htonl((UINT32)blockId);
|
||||
memcpy(buffer+BLOCK_ID_OFFSET, &temp32, 4);
|
||||
}
|
||||
void SetFecSymbolId(UINT16 symbolId)
|
||||
{
|
||||
symbolId = htons(symbolId);
|
||||
memcpy(buffer+SYMBOL_ID_OFFSET, &symbolId, 2);
|
||||
}
|
||||
|
||||
// Message processing
|
||||
bool FlagIsSet(NormCmdFlushMsg::Flag flag)
|
||||
{return (0 != (buffer[FLAGS_OFFSET] & flag));}
|
||||
NormObjectId GetObjectId()
|
||||
{
|
||||
UINT16 temp16;
|
||||
memcpy(&temp16, buffer+OBJECT_ID_OFFSET, 2);
|
||||
return (ntohs(temp16));
|
||||
}
|
||||
NormBlockId GetFecBlockId()
|
||||
{
|
||||
UINT32 temp32;
|
||||
memcpy(&temp32, buffer+BLOCK_ID_OFFSET, 4);
|
||||
return (ntohl(temp32));
|
||||
}
|
||||
UINT16 GetFecSymbolId()
|
||||
{
|
||||
UINT16 temp16;
|
||||
memcpy(&temp16, buffer+SYMBOL_ID_OFFSET, 2);
|
||||
return (ntohs(temp16));
|
||||
}
|
||||
// Flush messages are fixed length
|
||||
UINT16 GetLength() {return (SYMBOL_ID_OFFSET + 2);}
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
FLAGS_OFFSET = FLAVOR_OFFSET + 1,
|
||||
OBJECT_ID_OFFSET = FLAGS_OFFSET + 1,
|
||||
BLOCK_ID_OFFSET = OBJECT_ID_OFFSET + 2,
|
||||
SYMBOL_ID_OFFSET = BLOCK_ID_OFFSET + 4
|
||||
};
|
||||
}; // end class NormCmdFlushMsg
|
||||
|
||||
|
||||
class NormCmdSquelchMsg : public NormCmdMsg
|
||||
{
|
||||
public:
|
||||
// Message building
|
||||
void SetObjectId(NormObjectId objectId)
|
||||
{
|
||||
UINT16 temp16 = htons((UINT16)objectId);
|
||||
memcpy(buffer+OBJECT_ID_OFFSET, &temp16, 2);
|
||||
}
|
||||
void SetFecBlockId(NormBlockId blockId)
|
||||
{
|
||||
UINT32 temp32 = htonl((UINT32)blockId);
|
||||
memcpy(buffer+BLOCK_ID_OFFSET, &temp32, 4);
|
||||
}
|
||||
void SetFecSymbolId(UINT16 symbolId)
|
||||
{
|
||||
symbolId = htons(symbolId);
|
||||
memcpy(buffer+SYMBOL_ID_OFFSET, &symbolId, 2);
|
||||
}
|
||||
|
||||
void ResetInvalidObjectList() {length = OBJECT_LIST_OFFSET;}
|
||||
UINT16 AppendInvalidObject(NormObjectId objectId)
|
||||
{
|
||||
UINT16 temp16 = htons((UINT16)objectId);
|
||||
memcpy(buffer+length, &temp16, 2);
|
||||
length += 2;
|
||||
return length;
|
||||
}
|
||||
|
||||
// Message processing
|
||||
NormObjectId GetObjectId()
|
||||
{
|
||||
UINT16 temp16;
|
||||
memcpy(&temp16, buffer+OBJECT_ID_OFFSET, 2);
|
||||
return (ntohs(temp16));
|
||||
}
|
||||
NormBlockId GetFecBlockId()
|
||||
{
|
||||
UINT32 temp32;
|
||||
memcpy(&temp32, buffer+BLOCK_ID_OFFSET, 4);
|
||||
return (NormBlockId(ntohl(temp32)));
|
||||
}
|
||||
UINT16 GetFecSymbolId()
|
||||
{
|
||||
UINT16 temp16;
|
||||
memcpy(&temp16, buffer+SYMBOL_ID_OFFSET, 2);
|
||||
return (ntohs(temp16));
|
||||
}
|
||||
|
||||
// Use these to parse invalid object list
|
||||
UINT16 GetInvalidObjectCount()
|
||||
{return ((length - OBJECT_LIST_OFFSET) / 2);}
|
||||
NormObjectId GetInvalidObjectId(UINT16 index)
|
||||
{
|
||||
UINT16 temp16;
|
||||
memcpy(&temp16, buffer + (2*index+OBJECT_LIST_OFFSET), 2);
|
||||
return (ntohs(temp16));
|
||||
}
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
RESERVED_OFFSET = FLAVOR_OFFSET + 1,
|
||||
OBJECT_ID_OFFSET = RESERVED_OFFSET + 1,
|
||||
BLOCK_ID_OFFSET = OBJECT_ID_OFFSET + 2,
|
||||
SYMBOL_ID_OFFSET = BLOCK_ID_OFFSET + 4,
|
||||
OBJECT_LIST_OFFSET = SYMBOL_ID_OFFSET + 2,
|
||||
};
|
||||
}; // end class NormCmdSquelchMsg
|
||||
|
||||
class NormCmdAckReqMsg : public NormCmdMsg
|
||||
{
|
||||
public:
|
||||
// Note: Support for application-defined AckFlavors (32-255)
|
||||
// may be provided, but 0-31 are reserved values
|
||||
enum AckFlavor
|
||||
{
|
||||
INVALID = 0,
|
||||
WATERMARK = 1,
|
||||
RTT = 2,
|
||||
APP_BASE = 32
|
||||
};
|
||||
|
||||
// Message building
|
||||
void SetAckFlavor(UINT8 ackFlavor)
|
||||
{buffer[ACK_FLAVOR_OFFSET] = ackFlavor;}
|
||||
// For setting generic content
|
||||
void SetAckContent(char content[64])
|
||||
{memcpy(buffer+CONTENT_OFFSET, content, 64);}
|
||||
|
||||
void ResetAckingNodeList()
|
||||
{length = NODE_LIST_OFFSET;}
|
||||
UINT16 AppendAckingNode(NormNodeId nodeId)
|
||||
{
|
||||
nodeId = htonl(nodeId);
|
||||
memcpy(buffer+length, &nodeId, 4);
|
||||
return length;
|
||||
}
|
||||
|
||||
void SetWatermark(NormObjectId objectId,
|
||||
NormBlockId fecBlockId,
|
||||
UINT16 fecSymbolId)
|
||||
{
|
||||
UINT16 temp16 = htons((UINT16)objectId);
|
||||
memcpy(buffer+OBJECT_ID_OFFSET, &temp16, 2);
|
||||
UINT32 temp32 = htonl((UINT32)fecBlockId);
|
||||
memcpy(buffer+BLOCK_ID_OFFSET, &temp32, 4);
|
||||
fecSymbolId = htons(fecSymbolId);
|
||||
memcpy(buffer+SYMBOL_ID_OFFSET, &fecSymbolId, 2);
|
||||
}
|
||||
|
||||
void SetRttSendTime(const struct timeval& sendTime)
|
||||
{
|
||||
UINT32 temp32 = htonl(sendTime.tv_sec);
|
||||
memcpy(buffer+SEND_TIME_OFFSET, &temp32, 4);
|
||||
temp32 = htonl(sendTime.tv_usec);
|
||||
memcpy(buffer+SEND_TIME_OFFSET+4, &temp32, 4);
|
||||
}
|
||||
|
||||
// Message processing
|
||||
NormCmdAckReqMsg::AckFlavor GetAckFlavor()
|
||||
{return (AckFlavor)buffer[ACK_FLAVOR_OFFSET];}
|
||||
char* GetAckContent() {return (buffer+CONTENT_OFFSET);}
|
||||
UINT16 GetAckingNodeCount()
|
||||
{return ((length - NODE_LIST_OFFSET) / 4);}
|
||||
NormNodeId GetAckingNodeId(UINT16 index)
|
||||
{
|
||||
UINT32 temp32;
|
||||
memcpy(&temp32, buffer+NODE_LIST_OFFSET+(4*index), 4);
|
||||
return (ntohl(temp32));
|
||||
}
|
||||
|
||||
void GetWatermark(NormObjectId& objectId,
|
||||
NormBlockId& fecBlockId,
|
||||
UINT16 fecSymbolId)
|
||||
{
|
||||
UINT16 temp16;
|
||||
memcpy(&temp16, buffer+OBJECT_ID_OFFSET, 2);
|
||||
objectId = ntohs(temp16);
|
||||
UINT32 temp32;
|
||||
memcpy(&temp32, buffer+BLOCK_ID_OFFSET, 4);
|
||||
fecBlockId = ntohl(temp32);
|
||||
memcpy(&fecSymbolId, buffer+SYMBOL_ID_OFFSET, 2);
|
||||
fecSymbolId = ntohs(fecSymbolId);
|
||||
}
|
||||
|
||||
void GetRttSendTime(struct timeval& sendTime)
|
||||
{
|
||||
memcpy(&sendTime.tv_sec, buffer+SEND_TIME_OFFSET, 4);
|
||||
sendTime.tv_sec = ntohl(sendTime.tv_sec);
|
||||
memcpy(&sendTime.tv_usec, buffer+SEND_TIME_OFFSET+4, 4);
|
||||
sendTime.tv_usec = ntohl(sendTime.tv_usec);
|
||||
}
|
||||
|
||||
private:
|
||||
enum GenericOffsets
|
||||
{
|
||||
ACK_FLAVOR_OFFSET = FLAVOR_OFFSET + 1,
|
||||
CONTENT_OFFSET = ACK_FLAVOR_OFFSET + 1,
|
||||
NODE_LIST_OFFSET = CONTENT_OFFSET + 8
|
||||
};
|
||||
enum WatermarkOffsets
|
||||
{
|
||||
OBJECT_ID_OFFSET = CONTENT_OFFSET,
|
||||
BLOCK_ID_OFFSET = OBJECT_ID_OFFSET + 2,
|
||||
SYMBOL_ID_OFFSET = BLOCK_ID_OFFSET + 4
|
||||
};
|
||||
enum RttOffsets
|
||||
{
|
||||
SEND_TIME_OFFSET = CONTENT_OFFSET
|
||||
};
|
||||
}; // end class NormCmdAckReqMsg
|
||||
|
||||
|
||||
class NormCmdRepairAdvMsg : public NormCmdMsg
|
||||
{
|
||||
public:
|
||||
enum Flag {NORM_REPAIR_ADV_FLAG_LIMIT = 0x01};
|
||||
// TBD (Uses NormNack format)
|
||||
}; // end class NormCmdRepairAdvMsg
|
||||
|
||||
|
||||
class NormCmdCCMsg : public NormCmdMsg
|
||||
{
|
||||
// (TBD) Congestion control command message
|
||||
}; // end class NormCmdCCMsg
|
||||
|
||||
class NormCmdApplicationMsg : public NormCmdMsg
|
||||
{
|
||||
// (TBD) Application-defined command (non-acked)
|
||||
}; // end class NormCmdApplicationMsg
|
||||
|
||||
|
||||
class NormRepairRequest
|
||||
{
|
||||
friend class NormRepairRequest::Iterator;
|
||||
public:
|
||||
enum Form
|
||||
{
|
||||
INVALID,
|
||||
ITEMS,
|
||||
RANGES,
|
||||
ERASURES
|
||||
};
|
||||
|
||||
enum Flag
|
||||
{
|
||||
SEGMENT = 0x01,
|
||||
BLOCK = 0x02,
|
||||
INFO = 0x04,
|
||||
OBJECT = 0x08
|
||||
};
|
||||
|
||||
// Construction
|
||||
NormRepairRequest();
|
||||
void SetBuffer(char* bufferPtr, UINT16 bufferLen)
|
||||
{
|
||||
buffer = bufferPtr;
|
||||
buffer_len = bufferLen;
|
||||
length = 0;
|
||||
}
|
||||
static UINT16 RepairItemLength() {return 8;}
|
||||
static UINT16 RepairRangeLength() {return 16;}
|
||||
static UINT16 ErasureItemLength() {return 8;}
|
||||
|
||||
// Repair request building
|
||||
void SetForm(NormRepairRequest::Form theForm) {form = theForm;}
|
||||
void SetFlag(NormRepairRequest::Flag theFlag) {flags |= theFlag;}
|
||||
void SetFlags(int theFlags) {flags |= theFlags;}
|
||||
void UnsetFlag(NormRepairRequest::Flag theFlag) {flags &= ~theFlag;}
|
||||
|
||||
|
||||
|
||||
// Returns length (each repair item requires 8 bytes of space)
|
||||
bool AppendRepairItem(const NormObjectId& objectId,
|
||||
const NormBlockId& blockId,
|
||||
UINT16 symbolId);
|
||||
|
||||
bool AppendRepairRange(const NormObjectId& startObjectId,
|
||||
const NormBlockId& startBlockId,
|
||||
UINT16 startSymbolId,
|
||||
const NormObjectId& endObjectId,
|
||||
const NormBlockId& endBlockId,
|
||||
UINT16 endSymbolId);
|
||||
|
||||
bool AppendErasureCount(const NormObjectId& objectId,
|
||||
const NormBlockId& blockId,
|
||||
UINT16 erasureCount);
|
||||
|
||||
UINT16 Pack();
|
||||
|
||||
// Repair request processing
|
||||
UINT16 Unpack();
|
||||
NormRepairRequest::Form GetForm() const {return form;}
|
||||
bool FlagIsSet(NormRepairRequest::Flag theFlag) const
|
||||
{return (0 != (theFlag & flags));}
|
||||
UINT16 GetLength() const {return length;}
|
||||
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
Iterator(NormRepairRequest& theRequest);
|
||||
void Reset() {offset = 0;}
|
||||
bool NextRepairItem(NormObjectId* objectId,
|
||||
NormBlockId* blockId,
|
||||
UINT16* symbolId);
|
||||
private:
|
||||
NormRepairRequest& request;
|
||||
UINT16 offset;
|
||||
}; // end class NormRepairRequest::Iterator
|
||||
|
||||
private:
|
||||
bool RetrieveRepairItem(UINT16 offset,
|
||||
NormObjectId* objectId,
|
||||
NormBlockId* blockId,
|
||||
UINT16* erasureCount) const;
|
||||
enum
|
||||
{
|
||||
FORM_OFFSET = 0,
|
||||
FLAGS_OFFSET = FORM_OFFSET + 1,
|
||||
LENGTH_OFFSET = FLAGS_OFFSET + 1,
|
||||
CONTENT_OFFSET = LENGTH_OFFSET + 2
|
||||
};
|
||||
Form form;
|
||||
int flags;
|
||||
UINT16 length;
|
||||
char* buffer;
|
||||
UINT16 buffer_len;
|
||||
|
||||
}; // end class NormRepairRequest
|
||||
|
||||
|
||||
class NormNackMsg : public NormMsg
|
||||
{
|
||||
public:
|
||||
// Message building
|
||||
void SetServerId(NormNodeId serverId)
|
||||
{
|
||||
serverId = htonl(serverId);
|
||||
memcpy(buffer+SERVER_ID_OFFSET, &serverId, 4);
|
||||
}
|
||||
void SetGrttResponse(const struct timeval& grttResponse)
|
||||
{
|
||||
UINT32 temp32 = htonl(grttResponse.tv_sec);
|
||||
memcpy(buffer+GRTT_RESPONSE_OFFSET, &temp32, 4);
|
||||
temp32 = htonl(grttResponse.tv_usec);
|
||||
memcpy(buffer+GRTT_RESPONSE_OFFSET+4, &temp32, 4);
|
||||
}
|
||||
void SetLossEstimate(UINT16 lossEstimate)
|
||||
{
|
||||
lossEstimate = htons(lossEstimate);
|
||||
memcpy(buffer+LOSS_OFFSET, &lossEstimate, 2);
|
||||
}
|
||||
void SetGrttSequence(UINT16 sequence)
|
||||
{
|
||||
sequence = htons(sequence);
|
||||
memcpy(buffer+GRTT_SEQUENCE_OFFSET, &sequence, 2);
|
||||
}
|
||||
|
||||
void ResetNackContent() {length = CONTENT_OFFSET;}
|
||||
void AttachRepairRequest(NormRepairRequest& request,
|
||||
UINT16 segmentMax)
|
||||
{
|
||||
int buflen = segmentMax - (length - CONTENT_OFFSET);
|
||||
buflen = (buflen>0) ? buflen : 0;
|
||||
request.SetBuffer(buffer+length, buflen);
|
||||
}
|
||||
UINT16 PackRepairRequest(NormRepairRequest& request)
|
||||
{
|
||||
UINT16 requestLength = request.Pack();
|
||||
length += request.Pack();
|
||||
return requestLength;
|
||||
}
|
||||
|
||||
// Message processing
|
||||
NormNodeId GetServerId()
|
||||
{
|
||||
UINT32 temp32;
|
||||
memcpy(&temp32, buffer+SERVER_ID_OFFSET, 4);
|
||||
return (ntohl(temp32));
|
||||
}
|
||||
void GetGrttResponse(struct timeval& grttResponse)
|
||||
{
|
||||
memcpy(&grttResponse.tv_sec, buffer+GRTT_RESPONSE_OFFSET, 4);
|
||||
grttResponse.tv_sec = ntohl(grttResponse.tv_sec);
|
||||
memcpy(&grttResponse.tv_usec, buffer+GRTT_RESPONSE_OFFSET+4, 4);
|
||||
grttResponse.tv_usec = ntohl(grttResponse.tv_usec);
|
||||
}
|
||||
UINT16 GetLossEstimate()
|
||||
{
|
||||
UINT16 temp16;
|
||||
memcpy(&temp16, buffer+LOSS_OFFSET, 2);
|
||||
return (ntohs(temp16));
|
||||
}
|
||||
UINT16 GetGrttSequence()
|
||||
{
|
||||
UINT16 temp16;
|
||||
memcpy(&temp16, buffer+GRTT_SEQUENCE_OFFSET, 2);
|
||||
return (ntohs(temp16));
|
||||
}
|
||||
|
||||
UINT16 UnpackRepairRequest(NormRepairRequest& request,
|
||||
UINT16 requestOffset)
|
||||
{
|
||||
int buflen = length - CONTENT_OFFSET - requestOffset;
|
||||
buflen = (buflen > 0) ? buflen : 0;
|
||||
request.SetBuffer(buffer + CONTENT_OFFSET + requestOffset,
|
||||
buflen);
|
||||
return request.Unpack();
|
||||
}
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
SERVER_ID_OFFSET = MSG_OFFSET,
|
||||
GRTT_RESPONSE_OFFSET = SERVER_ID_OFFSET + 4,
|
||||
LOSS_OFFSET = GRTT_RESPONSE_OFFSET + 8,
|
||||
GRTT_SEQUENCE_OFFSET = LOSS_OFFSET + 2,
|
||||
CONTENT_OFFSET = GRTT_SEQUENCE_OFFSET + 2
|
||||
};
|
||||
}; // end class NormNackMsg
|
||||
|
||||
class NormAckMsg : public NormMsg
|
||||
{
|
||||
// (TBD)
|
||||
}; // end class NormAckMsg
|
||||
|
||||
class NormReportMsg : public NormMsg
|
||||
{
|
||||
// (TBD)
|
||||
}; // end class NormReportMsg
|
||||
|
||||
// One we've defined our basic message types, we
|
||||
// do some unions so we can easily use these
|
||||
// via casting or dereferencing the union members
|
||||
|
||||
class NormCommandMessage
|
||||
{
|
||||
public:
|
||||
union
|
||||
{
|
||||
NormCmdMsg generic;
|
||||
NormCmdFlushMsg flush;
|
||||
NormCmdSquelchMsg squelch;
|
||||
NormCmdAckReqMsg ack_req;
|
||||
NormCmdRepairAdvMsg repair_adv;
|
||||
NormCmdCCMsg cc;
|
||||
NormCmdApplicationMsg app;
|
||||
};
|
||||
}; // end class NormCommandMessage
|
||||
|
||||
class NormMessage
|
||||
{
|
||||
friend class NormMessageQueue;
|
||||
public:
|
||||
union
|
||||
{
|
||||
NormMsg generic;
|
||||
NormObjectMsg object;
|
||||
NormInfoMsg info;
|
||||
NormDataMsg data;
|
||||
NormCommandMessage cmd;
|
||||
NormNackMsg nack;
|
||||
NormAckMsg ack;
|
||||
NormReportMsg report;
|
||||
};
|
||||
|
||||
private:
|
||||
NormMessage* prev;
|
||||
NormMessage* next;
|
||||
}; // end class NormMessage
|
||||
|
||||
|
||||
class NormMessageQueue
|
||||
{
|
||||
public:
|
||||
NormMessageQueue();
|
||||
~NormMessageQueue();
|
||||
void Destroy();
|
||||
void Prepend(NormMessage* msg);
|
||||
void Append(NormMessage* msg);
|
||||
void Remove(NormMessage* msg);
|
||||
NormMessage* RemoveHead();
|
||||
NormMessage* RemoveTail();
|
||||
bool IsEmpty() {return ((NormMessage*)NULL == head);}
|
||||
|
||||
private:
|
||||
NormMessage* head;
|
||||
NormMessage* tail;
|
||||
}; // end class NormMessageQueue
|
||||
|
||||
#endif // _NORM_MESSAGE
|
||||
|
|
@ -0,0 +1,843 @@
|
|||
|
||||
#include "normNode.h"
|
||||
#include "normSession.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
NormNode::NormNode(class NormSession* theSession, NormNodeId nodeId)
|
||||
: session(theSession), id(nodeId),
|
||||
parent(NULL), right(NULL), left(NULL),
|
||||
prev(NULL), next(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
NormNode::~NormNode()
|
||||
{
|
||||
}
|
||||
|
||||
const NormNodeId& NormNode::LocalNodeId() {return session->LocalNodeId();}
|
||||
|
||||
|
||||
NormServerNode::NormServerNode(class NormSession* theSession, NormNodeId nodeId)
|
||||
: NormNode(theSession, nodeId), synchronized(false),
|
||||
is_open(false), segment_size(0), ndata(0), nparity(0), erasure_loc(NULL)
|
||||
{
|
||||
repair_timer.Init(0.0, -1, (ProtocolTimerOwner*)this,
|
||||
(ProtocolTimeoutFunc)&NormServerNode::OnRepairTimeout);
|
||||
}
|
||||
|
||||
NormServerNode::~NormServerNode()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
bool NormServerNode::Open(UINT16 segmentSize, UINT16 numData, UINT16 numParity)
|
||||
{
|
||||
if (!rx_table.Init(256))
|
||||
{
|
||||
DMSG(0, "NormServerNode::Open() rx_table init error\n");
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
if (!rx_pending_mask.Init(256))
|
||||
{
|
||||
DMSG(0, "NormServerNode::Open() rx_pending_mask init error\n");
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
if (!rx_repair_mask.Init(256))
|
||||
{
|
||||
DMSG(0, "NormServerNode::Open() rx_repair_mask init error\n");
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
// Calculate how much memory each buffered block will require
|
||||
UINT16 blockSize = numData + numParity;
|
||||
unsigned long maskSize = blockSize >> 3;
|
||||
if (0 != (blockSize & 0x07)) maskSize++;
|
||||
unsigned long blockSpace = sizeof(NormBlock) +
|
||||
blockSize * sizeof(char*) +
|
||||
2*maskSize +
|
||||
numData * (segmentSize + NormDataMsg::PayloadHeaderLen());
|
||||
unsigned long bufferSpace = session->RemoteServerBufferSize();
|
||||
unsigned long numBlocks = bufferSpace / blockSpace;
|
||||
if (bufferSpace > (numBlocks*blockSpace)) numBlocks++;
|
||||
if (numBlocks < 2) numBlocks = 2;
|
||||
unsigned long numSegments = numBlocks * numData;
|
||||
|
||||
if (!block_pool.Init(numBlocks, blockSize))
|
||||
{
|
||||
DMSG(0, "NormServerNode::Open() block_pool init error\n");
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!segment_pool.Init(numSegments, segmentSize+NormDataMsg::PayloadHeaderLen()))
|
||||
{
|
||||
DMSG(0, "NormServerNode::Open() segment_pool init error\n");
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!decoder.Init(numParity, segmentSize+NormDataMsg::PayloadHeaderLen()))
|
||||
{
|
||||
DMSG(0, "NormServerNode::Open() decoder init error: %s\n",
|
||||
strerror(errno));
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
if (!(erasure_loc = new UINT16[numParity]))
|
||||
{
|
||||
DMSG(0, "NormServerNode::Open() erasure_loc allocation error: %s\n",
|
||||
strerror(errno));
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
segment_size = segmentSize;
|
||||
ndata = numData;
|
||||
nparity = numParity;
|
||||
is_open= true;
|
||||
return true;
|
||||
} // end NormServerNode::Open()
|
||||
|
||||
void NormServerNode::Close()
|
||||
{
|
||||
decoder.Destroy();
|
||||
if (erasure_loc)
|
||||
{
|
||||
delete []erasure_loc;
|
||||
erasure_loc = NULL;
|
||||
}
|
||||
NormObjectTable::Iterator iterator(rx_table);
|
||||
NormObject* obj;
|
||||
while ((obj = iterator.GetNextObject()))
|
||||
{
|
||||
// (TBD) Notify app of object closing
|
||||
obj->Close();
|
||||
delete obj;
|
||||
}
|
||||
rx_repair_mask.Destroy();
|
||||
rx_pending_mask.Destroy();
|
||||
rx_table.Destroy();
|
||||
segment_size = ndata = nparity = 0;
|
||||
is_open = false;
|
||||
} // end NormServerNode::Close()
|
||||
|
||||
void NormServerNode::HandleObjectMessage(NormMessage& msg)
|
||||
{
|
||||
if (IsOpen())
|
||||
{
|
||||
// (TBD - also verify encoder name ...)
|
||||
if ((msg.object.GetSegmentSize() != segment_size) &&
|
||||
(ndata != msg.object.GetFecBlockLen()) &&
|
||||
(nparity != msg.object.GetFecNumParity()))
|
||||
{
|
||||
DMSG(0, "NormServerNode::HandleObjectMessage() node:%lu remote server:%lu parameter change.\n",
|
||||
LocalNodeId(), Id());
|
||||
Close();
|
||||
if (!Open(msg.object.GetSegmentSize(), msg.object.GetFecBlockLen(),
|
||||
msg.object.GetFecNumParity()))
|
||||
{
|
||||
DMSG(0, "NormServerNode::HandleObjectMessage() node:%lu remote server:%lu open error\n",
|
||||
LocalNodeId(), Id());
|
||||
// (TBD) notify app of error ??
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Open(msg.object.GetSegmentSize(),
|
||||
msg.object.GetFecBlockLen(),
|
||||
msg.object.GetFecNumParity()))
|
||||
{
|
||||
DMSG(0, "NormServerNode::HandleObjectMessage() node:%lu remote server:%lu open error\n",
|
||||
LocalNodeId(), Id());
|
||||
// (TBD) notify app of error ??
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NormObjectId objectId = msg.object.GetObjectId();
|
||||
ObjectStatus objectStatus = GetObjectStatus(objectId);
|
||||
if (synchronized)
|
||||
{
|
||||
if (OBJ_INVALID == objectStatus)
|
||||
{
|
||||
// (TBD) We may want to control re-sync policy options
|
||||
// or at least revert to fresh sync if sync is totally lost.
|
||||
DMSG(0, "NormServerNode::HandleObjectMessage() re-syncing ...\n");
|
||||
Sync(objectId);
|
||||
objectStatus = OBJ_NEW;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Does this object message meet our sync policy?
|
||||
if (SyncTest(msg))
|
||||
{
|
||||
Sync(objectId);
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormServerNode::HandleObjectMessage() waiting to sync ...\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
NormObject* obj = NULL;
|
||||
switch (objectStatus)
|
||||
{
|
||||
case OBJ_NEW:
|
||||
SetPending(objectId);
|
||||
break;
|
||||
|
||||
case OBJ_PENDING:
|
||||
obj = rx_table.Find(objectId);
|
||||
break;
|
||||
|
||||
case OBJ_COMPLETE:
|
||||
return;
|
||||
}
|
||||
if (!obj)
|
||||
{
|
||||
if (msg.object.FlagIsSet(NormObjectMsg::FLAG_STREAM))
|
||||
{
|
||||
if (!(obj = new NormStreamObject(session, this, objectId)))
|
||||
{
|
||||
DMSG(0, "NormServerNode::HandleObjectMessage() new NORM_OBJECT_STREAM error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
else if (msg.object.FlagIsSet(NormObjectMsg::FLAG_FILE))
|
||||
{
|
||||
DMSG(0, "NormServerNode::HandleObjectMessage() NORM_OBJECT_FILE not yet supported!\n");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormServerNode::HandleObjectMessage() NORM_OBJECT_DATA not yet supported!\n");
|
||||
return;
|
||||
}
|
||||
// Open receive object and notify app for accept.
|
||||
NormObjectSize objectSize = msg.object.GetObjectSize();
|
||||
if (!obj->Open(objectSize, msg.object.FlagIsSet(NormObjectMsg::FLAG_INFO)))
|
||||
{
|
||||
DMSG(0, "NormServerNode::HandleObjectMessage() node:%lu server:%lu "
|
||||
"obj:%hu was not opened.\n", LocalNodeId(), Id(), (UINT16)objectId);
|
||||
delete obj;
|
||||
rx_pending_mask.Unset(objectId);
|
||||
return;
|
||||
}
|
||||
|
||||
session->Notify(NormController::RX_OBJECT_NEW, this, obj);
|
||||
|
||||
if (!obj->Accepted())
|
||||
{
|
||||
delete obj;
|
||||
rx_pending_mask.Unset(objectId);
|
||||
return;
|
||||
}
|
||||
|
||||
rx_table.Insert(obj);
|
||||
DMSG(0, "NormServerNode::HandleObjectMessage() node:%lu server:%lu new obj:%hu\n",
|
||||
LocalNodeId(), Id(), (UINT16)objectId);
|
||||
}
|
||||
obj->HandleObjectMessage(msg);
|
||||
} // end NormServerNode::HandleObjectMessage()
|
||||
|
||||
void NormServerNode::SetPending(NormObjectId objectId)
|
||||
{
|
||||
ASSERT(synchronized);
|
||||
ASSERT(OBJ_NEW == GetObjectStatus(objectId));
|
||||
if (objectId < next_id)
|
||||
{
|
||||
rx_pending_mask.Set(objectId);
|
||||
}
|
||||
else
|
||||
{
|
||||
rx_pending_mask.SetBits(next_id, next_id - objectId + 1);
|
||||
next_id = objectId + 1;
|
||||
}
|
||||
} // end NormServerNode::SetPending()
|
||||
|
||||
|
||||
void NormServerNode::Sync(NormObjectId objectId)
|
||||
{
|
||||
if (synchronized)
|
||||
{
|
||||
// Dump pending objects < objectId
|
||||
if (rx_pending_mask.IsSet() && (objectId > sync_id))
|
||||
{
|
||||
NormObjectTable::Iterator iterator(rx_table);
|
||||
NormObject* obj = iterator.GetNextObject();
|
||||
while (obj && (obj->Id() < objectId))
|
||||
{
|
||||
DeleteObject(obj);
|
||||
obj = iterator.GetNextObject();
|
||||
}
|
||||
rx_pending_mask.UnsetBits(sync_id, (objectId - sync_id));
|
||||
}
|
||||
sync_id = objectId;
|
||||
if (objectId > next_id) next_id = objectId;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(!rx_pending_mask.IsSet());
|
||||
sync_id = next_id = objectId;
|
||||
synchronized = true;
|
||||
}
|
||||
} // end NormServerNode::Sync()
|
||||
|
||||
|
||||
bool NormServerNode::SyncTest(const NormMessage& msg) const
|
||||
{
|
||||
// (TBD) Additional sync policies
|
||||
|
||||
// Sync if non-repair and (INFO or block zero message)
|
||||
bool result = !msg.object.FlagIsSet(NormObjectMsg::FLAG_REPAIR) &&
|
||||
(NORM_MSG_INFO == msg.generic.GetType()) ?
|
||||
true : (0 == msg.data.GetFecBlockId());
|
||||
return result;
|
||||
|
||||
} // end NormServerNode::SyncTest()
|
||||
|
||||
void NormServerNode::DeleteObject(NormObject* obj)
|
||||
{
|
||||
rx_table.Remove(obj);
|
||||
delete obj;
|
||||
} // end NormServerNode::DeleteObject()
|
||||
|
||||
NormBlock* NormServerNode::GetFreeBlock(NormObjectId objectId, NormBlockId blockId)
|
||||
{
|
||||
NormBlock* b = block_pool.Get();
|
||||
if (!b)
|
||||
{
|
||||
// reverse iteration to find newest object with resources
|
||||
NormObjectTable::Iterator iterator(rx_table);
|
||||
NormObject* obj;
|
||||
while ((obj = iterator.GetPrevObject()))
|
||||
{
|
||||
if (obj->Id() < objectId)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (obj->Id() > objectId)
|
||||
b = obj->StealNewestBlock(false);
|
||||
else
|
||||
b = obj->StealNewestBlock(true, blockId);
|
||||
if (b)
|
||||
{
|
||||
b->EmptyToPool(segment_pool);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return b;
|
||||
} // end NormServerNode::GetFreeBlock()
|
||||
|
||||
char* NormServerNode::GetFreeSegment(NormObjectId objectId, NormBlockId blockId)
|
||||
{
|
||||
char* ptr = segment_pool.Get();
|
||||
while (!ptr)
|
||||
{
|
||||
NormBlock* b = GetFreeBlock(objectId, blockId);
|
||||
if (b)
|
||||
ptr = segment_pool.Get();
|
||||
else
|
||||
break;
|
||||
}
|
||||
return ptr;
|
||||
} // end NormServerNode::GetFreeSegment()
|
||||
|
||||
NormServerNode::ObjectStatus NormServerNode::GetObjectStatus(NormObjectId objectId) const
|
||||
{
|
||||
if (synchronized)
|
||||
{
|
||||
if (objectId < sync_id)
|
||||
{
|
||||
return OBJ_INVALID;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (objectId < next_id)
|
||||
{
|
||||
if (rx_pending_mask.Test(objectId))
|
||||
return OBJ_PENDING;
|
||||
else
|
||||
return OBJ_COMPLETE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rx_pending_mask.IsSet())
|
||||
{
|
||||
if (rx_pending_mask.CanSet(objectId))
|
||||
return OBJ_NEW;
|
||||
else
|
||||
return OBJ_INVALID;
|
||||
}
|
||||
else
|
||||
{
|
||||
NormObjectId delta = objectId - next_id + 1;
|
||||
if (delta > NormObjectId(rx_pending_mask.Size()))
|
||||
return OBJ_INVALID;
|
||||
else
|
||||
return OBJ_NEW;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return OBJ_NEW;
|
||||
}
|
||||
} // end NormServerNode::ObjectStatus()
|
||||
|
||||
// (TBD) mod repair check to do full server flush?
|
||||
void NormServerNode::RepairCheck(NormObject::CheckLevel checkLevel,
|
||||
NormObjectId objectId,
|
||||
NormBlockId blockId,
|
||||
NormSegmentId segmentId)
|
||||
{
|
||||
ASSERT(synchronized);
|
||||
if (!repair_timer.IsActive())
|
||||
{
|
||||
bool startTimer = false;
|
||||
if (rx_pending_mask.IsSet())
|
||||
{
|
||||
if (rx_repair_mask.IsSet()) rx_repair_mask.Clear();
|
||||
NormObjectId nextId = rx_pending_mask.FirstSet();
|
||||
NormObjectId lastId = rx_pending_mask.LastSet();
|
||||
if (objectId < lastId) lastId = objectId;
|
||||
while (nextId <= lastId)
|
||||
{
|
||||
NormObject* obj = rx_table.Find(nextId);
|
||||
if (obj)
|
||||
{
|
||||
NormObject::CheckLevel level =
|
||||
(nextId == lastId) ? checkLevel : NormObject::THRU_OBJECT;
|
||||
startTimer |=
|
||||
obj->ClientRepairCheck(level, blockId, segmentId, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
startTimer = true;
|
||||
}
|
||||
nextId++;
|
||||
nextId = rx_pending_mask.NextSet(nextId);
|
||||
}
|
||||
current_object_id = objectId;
|
||||
if (startTimer)
|
||||
{
|
||||
DMSG(0, "NormServerNode::RepairCheck() starting NACK back-off ...\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No repairs needed
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (repair_timer.RepeatCount())
|
||||
{
|
||||
// Repair timer in back-off phase
|
||||
// Trim server current transmit position reference
|
||||
if (objectId < current_object_id)
|
||||
current_object_id = objectId;
|
||||
}
|
||||
} // end NormServerNode::RepairCheck()
|
||||
|
||||
// When repair timer fires, possibly build a NACK
|
||||
// and queue for transmission to this server node
|
||||
bool NormServerNode::OnRepairTimeout()
|
||||
{
|
||||
DMSG(0, "NormServerNode::OnRepairTimeout() ...\n");
|
||||
switch(repair_timer.RepeatCount())
|
||||
{
|
||||
case 0: // hold-off time complete
|
||||
break;
|
||||
|
||||
case 1: // back-off timeout complete
|
||||
{
|
||||
// 1) Were we suppressed?
|
||||
if (rx_pending_mask.IsSet())
|
||||
{
|
||||
bool repair_pending = false;
|
||||
NormObjectId nextId = rx_pending_mask.FirstSet();
|
||||
NormObjectId lastId = rx_pending_mask.LastSet();
|
||||
if (current_object_id < lastId) lastId = current_object_id;
|
||||
while (nextId <= lastId)
|
||||
{
|
||||
if (!rx_repair_mask.Test(nextId))
|
||||
{
|
||||
NormObject* obj = rx_table.Find(nextId);
|
||||
if (!obj || obj->IsRepairPending(nextId != current_object_id))
|
||||
{
|
||||
repair_pending = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
nextId++;
|
||||
nextId = rx_pending_mask.NextSet(nextId);
|
||||
} // end while (nextId <= current_block_id)
|
||||
if (repair_pending)
|
||||
{
|
||||
// Build NACK
|
||||
NormMessage msg;
|
||||
NormNackMsg& nack = msg.nack;
|
||||
nack.ResetNackContent();
|
||||
NormRepairRequest req;
|
||||
NormObjectId prevId;
|
||||
UINT16 reqCount = 0;
|
||||
NormRepairRequest::Form prevForm = NormRepairRequest::INVALID;
|
||||
nextId = rx_pending_mask.FirstSet();
|
||||
lastId = rx_pending_mask.LastSet();
|
||||
if (current_object_id < lastId) lastId = current_object_id;
|
||||
lastId++; // force loop to fully flush nack building.
|
||||
while (nextId <= lastId)
|
||||
{
|
||||
NormObject* obj = NULL;
|
||||
if (nextId == lastId)
|
||||
nextId++; // force break of possible ending consecutive series
|
||||
else
|
||||
obj = rx_table.Find(nextId);
|
||||
if (obj)
|
||||
{
|
||||
if (obj->IsPending(nextId != current_object_id))
|
||||
{
|
||||
if (NormRepairRequest::INVALID != prevForm)
|
||||
{
|
||||
nack.PackRepairRequest(req);
|
||||
prevForm = NormRepairRequest::INVALID;
|
||||
}
|
||||
obj->AppendRepairRequest(nack); // (TBD) error check
|
||||
reqCount = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (reqCount && (reqCount == (nextId - prevId)))
|
||||
{
|
||||
// Consecutive series of missing objects continues
|
||||
reqCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
NormRepairRequest::Form nextForm;
|
||||
switch (reqCount)
|
||||
{
|
||||
case 0:
|
||||
nextForm = NormRepairRequest::INVALID;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
nextForm = NormRepairRequest::ITEMS;
|
||||
break;
|
||||
default:
|
||||
nextForm = NormRepairRequest::RANGES;
|
||||
break;
|
||||
}
|
||||
if (prevForm != nextForm)
|
||||
{
|
||||
if (NormRepairRequest::INVALID != prevForm)
|
||||
nack.PackRepairRequest(req); // (TBD) error check
|
||||
if (NormRepairRequest::INVALID != nextForm)
|
||||
{
|
||||
nack.AttachRepairRequest(req, segment_size); // (TBD) error check
|
||||
req.SetForm(nextForm);
|
||||
req.SetFlag(NormRepairRequest::OBJECT);
|
||||
}
|
||||
prevForm = nextForm;
|
||||
}
|
||||
switch (nextForm)
|
||||
{
|
||||
case NormRepairRequest::ITEMS:
|
||||
req.AppendRepairItem(prevId, 0, 0);
|
||||
if (2 == reqCount)
|
||||
req.AppendRepairItem(prevId+1, 0, 0);
|
||||
break;
|
||||
case NormRepairRequest::RANGES:
|
||||
req.AppendRepairItem(prevId, 0, 0);
|
||||
req.AppendRepairItem(prevId+reqCount-1, 0, 0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
prevId = nextId;
|
||||
reqCount = 1;
|
||||
}
|
||||
}
|
||||
nextId++;
|
||||
if (nextId <= lastId)
|
||||
nextId = rx_pending_mask.NextSet(nextId);
|
||||
} // end while (nextId <= lastId)
|
||||
|
||||
// (TBD) Queue NACK for transmission
|
||||
DMSG(0, "NormServerNode::OnRepairTimeout() NACK TRANSMITTED ...\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormServerNode::OnRepairTimeout() NACK SUPPRESSED ...\n");
|
||||
// (TBD) repair_timer.SetInterval(HOLD_OFF_INTERVAL)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormServerNode::OnRepairTimeout() nothing pending ...\n");
|
||||
// (TBD) cancel hold-off timeout ???
|
||||
} // end if/else (repair_pending)
|
||||
}
|
||||
break;
|
||||
|
||||
default: // should never occur
|
||||
ASSERT(0);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
} // end NormServerNode::OnRepairTimeout()
|
||||
|
||||
|
||||
|
||||
|
||||
NormNodeTree::NormNodeTree()
|
||||
: root(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
NormNodeTree::~NormNodeTree()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
||||
NormNode *NormNodeTree::FindNodeById(unsigned long nodeId) const
|
||||
{
|
||||
NormNode* x = root;
|
||||
while(x && (x->id != nodeId))
|
||||
{
|
||||
if (nodeId < x->id)
|
||||
x = x->left;
|
||||
else
|
||||
x = x->right;
|
||||
}
|
||||
return x;
|
||||
} // end NormNodeTree::FindNodeById()
|
||||
|
||||
|
||||
|
||||
void NormNodeTree::AttachNode(NormNode *node)
|
||||
{
|
||||
ASSERT(node);
|
||||
node->left = NULL;
|
||||
node->right = NULL;
|
||||
NormNode *x = root;
|
||||
while (x)
|
||||
{
|
||||
if (node->id < x->id)
|
||||
{
|
||||
if (!x->left)
|
||||
{
|
||||
x->left = node;
|
||||
node->parent = x;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = x->left;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!x->right)
|
||||
{
|
||||
x->right = node;
|
||||
node->parent = x;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = x->right;
|
||||
}
|
||||
}
|
||||
}
|
||||
root = node; // root _was_ NULL
|
||||
} // end NormNodeTree::AddNode()
|
||||
|
||||
|
||||
void NormNodeTree::DetachNode(NormNode* node)
|
||||
{
|
||||
ASSERT(node);
|
||||
NormNode* x;
|
||||
NormNode* y;
|
||||
if (!node->left || !node->right)
|
||||
{
|
||||
y = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node->right)
|
||||
{
|
||||
y = node->right;
|
||||
while (y->left) y = y->left;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = node;
|
||||
y = node->parent;
|
||||
while(y && (y->right == x))
|
||||
{
|
||||
x = y;
|
||||
y = y->parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (y->left)
|
||||
x = y->left;
|
||||
else
|
||||
x = y->right;
|
||||
if (x) x->parent = y->parent;
|
||||
if (!y->parent)
|
||||
root = x;
|
||||
else if (y == y->parent->left)
|
||||
y->parent->left = x;
|
||||
else
|
||||
y->parent->right = x;
|
||||
|
||||
if (node != y)
|
||||
{
|
||||
if ((y->parent = node->parent))
|
||||
{
|
||||
if (y->id < y->parent->id)
|
||||
y->parent->left = y;
|
||||
else
|
||||
y->parent->right = y;
|
||||
}
|
||||
else
|
||||
{
|
||||
root = y;
|
||||
}
|
||||
if ((y->left = node->left)) y->left->parent = y;
|
||||
if ((y->right = node->right)) y->right->parent = y;
|
||||
}
|
||||
} // end NormNodeTree::DetachNode()
|
||||
|
||||
|
||||
void NormNodeTree::Destroy()
|
||||
{
|
||||
NormNode* n;
|
||||
while ((n = root))
|
||||
{
|
||||
DetachNode(n);
|
||||
delete n;
|
||||
}
|
||||
} // end NormNodeTree::Destroy()
|
||||
|
||||
NormNodeTreeIterator::NormNodeTreeIterator(const NormNodeTree& t)
|
||||
: tree(t)
|
||||
{
|
||||
NormNode* x = t.root;
|
||||
if (x)
|
||||
{
|
||||
while (x->left) x = x->left;
|
||||
next = x;
|
||||
}
|
||||
}
|
||||
|
||||
void NormNodeTreeIterator::Reset()
|
||||
{
|
||||
NormNode* x = tree.root;
|
||||
if (x)
|
||||
{
|
||||
while (x->left) x = x->left;
|
||||
next = x;
|
||||
}
|
||||
} // end NormNodeTreeIterator::Reset()
|
||||
|
||||
NormNode* NormNodeTreeIterator::GetNextNode()
|
||||
{
|
||||
NormNode* n = next;
|
||||
if (n)
|
||||
{
|
||||
if (next->right)
|
||||
{
|
||||
NormNode* y = n->right;
|
||||
while (y->left) y = y->left;
|
||||
next = y;
|
||||
}
|
||||
else
|
||||
{
|
||||
NormNode* x = n;
|
||||
NormNode* y = n->parent;
|
||||
while(y && (y->right == x))
|
||||
{
|
||||
x = y;
|
||||
y = y->parent;
|
||||
}
|
||||
next = y;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
} // end NormNodeTreeIterator::GetNextNode()
|
||||
|
||||
NormNodeList::NormNodeList()
|
||||
: head(NULL), tail(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
NormNodeList::~NormNodeList()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
NormNode* NormNodeList::FindNodeById(NormNodeId nodeId) const
|
||||
{
|
||||
NormNode *next = head;
|
||||
while (next)
|
||||
{
|
||||
if (nodeId == next->id)
|
||||
return next;
|
||||
else
|
||||
next = next->right;
|
||||
}
|
||||
return NULL;
|
||||
} // NormNodeList::Find()
|
||||
|
||||
void NormNodeList::Append(NormNode *theNode)
|
||||
{
|
||||
ASSERT(theNode);
|
||||
theNode->left = tail;
|
||||
if (tail)
|
||||
tail->right = theNode;
|
||||
else
|
||||
head = theNode;
|
||||
tail = theNode;
|
||||
theNode->right = NULL;
|
||||
} // end NormNodeList::Append()
|
||||
|
||||
void NormNodeList::Remove(NormNode *theNode)
|
||||
{
|
||||
ASSERT(theNode);
|
||||
if (theNode->right)
|
||||
theNode->right->left = theNode->left;
|
||||
else
|
||||
tail = theNode->left;
|
||||
if (theNode->left)
|
||||
theNode->left->right = theNode->right;
|
||||
else
|
||||
head = theNode->right;
|
||||
} // end NormNodeList::Remove()
|
||||
|
||||
void NormNodeList::Destroy()
|
||||
{
|
||||
NormNode* n;
|
||||
while ((n = head))
|
||||
{
|
||||
Remove(n);
|
||||
delete n;
|
||||
}
|
||||
} // end NormNodeList::Destroy()
|
||||
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
#ifndef _NORM_NODE
|
||||
#define _NORM_NODE
|
||||
|
||||
#include "normMessage.h"
|
||||
#include "normObject.h"
|
||||
#include "normEncoder.h"
|
||||
#include "protocolTimer.h"
|
||||
class NormNode
|
||||
{
|
||||
friend class NormNodeTree;
|
||||
friend class NormNodeTreeIterator;
|
||||
friend class NormNodeList;
|
||||
friend class NormNodeListIterator;
|
||||
|
||||
public:
|
||||
NormNode(class NormSession* theSession, NormNodeId nodeId);
|
||||
virtual ~NormNode();
|
||||
|
||||
void SetAddress(const NetworkAddress& address)
|
||||
{addr = address;}
|
||||
const NetworkAddress Address() const {return addr;}
|
||||
|
||||
const NormNodeId& Id() {return id;}
|
||||
inline const NormNodeId& LocalNodeId();
|
||||
|
||||
protected:
|
||||
class NormSession* session;
|
||||
|
||||
private:
|
||||
NormNodeId id;
|
||||
NetworkAddress addr;
|
||||
|
||||
NormNode* parent;
|
||||
NormNode* right;
|
||||
NormNode* left;
|
||||
NormNode* prev;
|
||||
NormNode* next;
|
||||
|
||||
}; // end class NormNode
|
||||
|
||||
class NormServerNode : public NormNode
|
||||
{
|
||||
public:
|
||||
enum ObjectStatus {OBJ_INVALID, OBJ_NEW, OBJ_PENDING, OBJ_COMPLETE};
|
||||
|
||||
NormServerNode(class NormSession* theSession, NormNodeId nodeId);
|
||||
~NormServerNode();
|
||||
|
||||
void HandleObjectMessage(NormMessage& msg);
|
||||
|
||||
bool Open(UINT16 segmentSize, UINT16 numData, UINT16 numParity);
|
||||
void Close();
|
||||
bool IsOpen() const {return is_open;}
|
||||
|
||||
bool SyncTest(const NormMessage& msg) const;
|
||||
void Sync(NormObjectId objectId);
|
||||
ObjectStatus GetObjectStatus(NormObjectId objectId) const;
|
||||
void SetPending(NormObjectId objectId);
|
||||
|
||||
void DeleteObject(NormObject* obj);
|
||||
|
||||
UINT16 SegmentSize() {return segment_size;}
|
||||
UINT16 BlockSize() {return ndata;}
|
||||
UINT16 NumParity() {return nparity;}
|
||||
//NormBlockPool* BlockPool() {return &block_pool;}
|
||||
//NormSegmentPool* SegmentPool() {return &segment_pool;}
|
||||
|
||||
NormBlock* GetFreeBlock(NormObjectId objectId, NormBlockId blockId);
|
||||
void PutFreeBlock(NormBlock* block)
|
||||
{
|
||||
block->EmptyToPool(segment_pool);
|
||||
block_pool.Put(block);
|
||||
}
|
||||
char* GetFreeSegment(NormObjectId objectId, NormBlockId blockId);
|
||||
void PutFreeSegment(char* segment)
|
||||
{segment_pool.Put(segment);}
|
||||
|
||||
void SetErasureLoc(UINT16 index, UINT16 value)
|
||||
{
|
||||
ASSERT(index < (nparity));
|
||||
erasure_loc[index] = value;
|
||||
}
|
||||
UINT16 GetErasureLoc(UINT16 index)
|
||||
{return erasure_loc[index];}
|
||||
UINT16 Decode(char** segmentList, UINT16 numData, UINT16 erasureCount)
|
||||
{
|
||||
return decoder.Decode(segmentList, numData, erasureCount, erasure_loc);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
void RepairCheck(NormObject::CheckLevel checkLevel,
|
||||
NormObjectId objectId,
|
||||
NormBlockId blockId,
|
||||
NormSegmentId segmentId);
|
||||
|
||||
bool OnRepairTimeout();
|
||||
|
||||
|
||||
bool synchronized;
|
||||
NormObjectId sync_id; // only valid if(synchronized)
|
||||
NormObjectId next_id; // only valid if(synchronized)
|
||||
|
||||
bool is_open;
|
||||
UINT16 segment_size;
|
||||
UINT16 ndata;
|
||||
UINT16 nparity;
|
||||
|
||||
NormObjectTable rx_table;
|
||||
NormSlidingMask rx_pending_mask;
|
||||
NormSlidingMask rx_repair_mask;
|
||||
NormBlockPool block_pool;
|
||||
NormSegmentPool segment_pool;
|
||||
NormDecoder decoder;
|
||||
UINT16* erasure_loc;
|
||||
|
||||
ProtocolTimer repair_timer;
|
||||
NormObjectId current_object_id; // index for repair
|
||||
|
||||
}; // end class NodeServerNode
|
||||
|
||||
|
||||
// Used for binary trees of NormNodes
|
||||
class NormNodeTree
|
||||
{
|
||||
friend class NormNodeTreeIterator;
|
||||
|
||||
public:
|
||||
// Methods
|
||||
NormNodeTree();
|
||||
~NormNodeTree();
|
||||
NormNode* FindNodeById(NormNodeId nodeId) const;
|
||||
void DeleteNode(NormNode *theNode)
|
||||
{
|
||||
ASSERT(theNode);
|
||||
DetachNode(theNode);
|
||||
delete theNode;
|
||||
}
|
||||
void AttachNode(NormNode *theNode);
|
||||
void DetachNode(NormNode *theNode);
|
||||
void Destroy(); // delete all nodes in tree
|
||||
|
||||
|
||||
|
||||
private:
|
||||
// Members
|
||||
NormNode* root;
|
||||
}; // end class NormNodeTree
|
||||
|
||||
class NormNodeTreeIterator
|
||||
{
|
||||
public:
|
||||
NormNodeTreeIterator(const NormNodeTree& nodeTree);
|
||||
void Reset();
|
||||
NormNode* GetNextNode();
|
||||
|
||||
|
||||
private:
|
||||
const NormNodeTree& tree;
|
||||
NormNode* next;
|
||||
}; // end class NormNodeTreeIterator
|
||||
|
||||
class NormNodeList
|
||||
{
|
||||
friend class NormNodeListIterator;
|
||||
|
||||
public:
|
||||
// Construction
|
||||
NormNodeList();
|
||||
~NormNodeList();
|
||||
NormNode* FindNodeById(NormNodeId nodeId) const;
|
||||
void Append(NormNode* theNode);
|
||||
void Remove(NormNode* theNode);
|
||||
void DeleteNode(NormNode* theNode)
|
||||
{
|
||||
ASSERT(theNode);
|
||||
Remove(theNode);
|
||||
delete theNode;
|
||||
}
|
||||
void Destroy(); // delete all nodes in list
|
||||
|
||||
|
||||
|
||||
// Members
|
||||
private:
|
||||
NormNode* head;
|
||||
NormNode* tail;
|
||||
}; // end class NormNodeList
|
||||
|
||||
class NormNodeListIterator
|
||||
{
|
||||
public:
|
||||
NormNodeListIterator(const NormNodeList& nodeList)
|
||||
: list(nodeList), next(nodeList.head) {}
|
||||
void Reset() {next = list.head;}
|
||||
NormNode* GetNextNode()
|
||||
{
|
||||
NormNode* n = next;
|
||||
next = n ? n->next : NULL;
|
||||
return n;
|
||||
}
|
||||
private:
|
||||
const NormNodeList& list;
|
||||
NormNode* next;
|
||||
}; // end class NormNodeListIterator
|
||||
#endif // NORM_NODE
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,218 @@
|
|||
#ifndef _NORM_OBJECT
|
||||
#define _NORM_OBJECT
|
||||
|
||||
#include "normSegment.h" // NORM segmentation classes
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
class NormObject
|
||||
{
|
||||
friend class NormObjectTable;
|
||||
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
DATA,
|
||||
FILE,
|
||||
STREAM
|
||||
};
|
||||
|
||||
enum CheckLevel
|
||||
{
|
||||
THRU_INFO,
|
||||
TO_BLOCK,
|
||||
THRU_SEGMENT,
|
||||
THRU_BLOCK,
|
||||
THRU_OBJECT
|
||||
};
|
||||
|
||||
|
||||
virtual ~NormObject();
|
||||
NormObject::Type GetType() const {return type;}
|
||||
const NormObjectId& Id() const {return id;}
|
||||
const NormObjectSize& Size() {return object_size;}
|
||||
|
||||
bool IsStream() {return (STREAM == type);}
|
||||
NormNodeId LocalNodeId() const;
|
||||
|
||||
// Opens (inits) object for tx operation
|
||||
bool Open(const NormObjectSize& objectSize,
|
||||
const char* infoPtr,
|
||||
UINT16 infoLen);
|
||||
// Opens (inits) object for rx operation
|
||||
bool Open(const NormObjectSize& objectSize, bool hasInfo)
|
||||
{return Open(objectSize, NULL, hasInfo ? 1 : 0);}
|
||||
void Close();
|
||||
|
||||
virtual bool WriteSegment(NormBlockId blockId,
|
||||
NormSegmentId segmentId,
|
||||
const char* buffer) = 0;
|
||||
|
||||
virtual UINT16 ReadSegment(NormBlockId blockId, NormSegmentId segmentId,
|
||||
NormObjectSize* offset, char* buffer, UINT16 maxlen) = 0;
|
||||
|
||||
// These are only valid after object is open
|
||||
NormBlockId LastBlockId();
|
||||
NormSegmentId LastSegmentId();
|
||||
NormSegmentId LastSegmentId(NormBlockId blockId);
|
||||
|
||||
// (TBD) re-write to use current_block_id/next_segment_id when
|
||||
// flush == false !!!
|
||||
bool IsPending(bool flush = true)
|
||||
{return (pending_info || pending_mask.IsSet());}
|
||||
|
||||
// Methods available to server for transmission
|
||||
bool NextServerMsg(NormMessage* msg);
|
||||
|
||||
// Used by session server for resource management scheme
|
||||
NormBlock* StealOldestBlock(bool excludeBlock, NormBlockId excludeId = 0);
|
||||
|
||||
|
||||
// Methods available to client for reception
|
||||
bool Accepted() {return accepted;}
|
||||
void HandleObjectMessage(NormMessage& msg);
|
||||
bool StreamUpdateStatus(NormBlockId blockId);
|
||||
|
||||
// Used by remote server node for resource management scheme
|
||||
NormBlock* StealNewestBlock(bool excludeBlock, NormBlockId excludeId = 0);
|
||||
|
||||
|
||||
bool ClientRepairCheck(CheckLevel level,
|
||||
NormBlockId blockId,
|
||||
NormSegmentId segmentId,
|
||||
bool timerActive);
|
||||
bool IsRepairPending(bool flush);
|
||||
bool AppendRepairRequest(NormNackMsg& nack) {return true;}
|
||||
|
||||
protected:
|
||||
NormObject(NormObject::Type theType,
|
||||
class NormSession* theSession,
|
||||
class NormServerNode* theServer,
|
||||
const NormObjectId& objectId);
|
||||
|
||||
void Accept() {accepted = true;}
|
||||
|
||||
NormObject::Type type;
|
||||
class NormSession* session;
|
||||
class NormServerNode* server; // NULL value indicates local (tx) object
|
||||
NormObjectId id;
|
||||
|
||||
NormObjectSize object_size;
|
||||
UINT16 segment_size;
|
||||
UINT16 ndata;
|
||||
UINT16 nparity;
|
||||
NormBlockBuffer block_buffer;
|
||||
bool pending_info;
|
||||
NormSlidingMask pending_mask;
|
||||
bool repair_info;
|
||||
NormSlidingMask repair_mask;
|
||||
NormBlockId current_block_id;
|
||||
NormSegmentId next_segment_id;
|
||||
NormBlockId last_block_id;
|
||||
NormSegmentId last_segment_id;
|
||||
|
||||
char* info;
|
||||
UINT16 info_len;
|
||||
|
||||
bool accepted;
|
||||
|
||||
// Extra state for STREAM objects
|
||||
bool stream_sync;
|
||||
NormBlockId stream_sync_id;
|
||||
NormBlockId stream_next_id;
|
||||
|
||||
NormObject* next;
|
||||
}; // end class NormObject
|
||||
|
||||
|
||||
|
||||
class NormStreamObject : public NormObject
|
||||
{
|
||||
public:
|
||||
NormStreamObject(class NormSession* theSession,
|
||||
class NormServerNode* theServer,
|
||||
const NormObjectId& objectId);
|
||||
~NormStreamObject();
|
||||
|
||||
bool Open(unsigned long bufferSize,
|
||||
const char* infoPtr = NULL,
|
||||
UINT16 infoLen = 0);
|
||||
void Close();
|
||||
|
||||
bool Accept(unsigned long bufferSize);
|
||||
|
||||
virtual bool WriteSegment(NormBlockId blockId,
|
||||
NormSegmentId segmentId,
|
||||
const char* buffer);
|
||||
|
||||
virtual UINT16 ReadSegment(NormBlockId blockId, NormSegmentId segmentId,
|
||||
NormObjectSize* offset, char* buffer, UINT16 maxlen);
|
||||
unsigned long Read(char* buffer, unsigned long len);
|
||||
unsigned long Write(char* buffer, unsigned long len, bool flush = false);
|
||||
|
||||
// For receive stream, we can rewind to earliest buffered offset
|
||||
void Rewind();
|
||||
|
||||
private:
|
||||
class Index
|
||||
{
|
||||
public:
|
||||
NormBlockId block;
|
||||
NormSegmentId segment;
|
||||
};
|
||||
NormBlockPool block_pool;
|
||||
NormSegmentPool segment_pool;
|
||||
NormBlockBuffer stream_buffer;
|
||||
Index write_index;
|
||||
NormObjectSize write_offset;
|
||||
Index read_index;
|
||||
NormObjectSize read_offset;
|
||||
}; // end class NormStreamObject
|
||||
|
||||
class NormObjectTable
|
||||
{
|
||||
friend class NormObjectTable::Iterator;
|
||||
|
||||
public:
|
||||
NormObjectTable();
|
||||
~NormObjectTable();
|
||||
bool Init(UINT16 rangeMax, UINT16 tableSize = 256);
|
||||
void Destroy();
|
||||
|
||||
bool IsInited() {return (NULL != table);}
|
||||
|
||||
bool Insert(NormObject* theObject);
|
||||
bool Remove(const NormObject* theObject);
|
||||
NormObject* Find(const NormObjectId& objectId) const;
|
||||
|
||||
NormObjectId RangeLo() {return range_lo;}
|
||||
NormObjectId RangeHi() {return range_hi;}
|
||||
bool IsEmpty() {return (0 == range);}
|
||||
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
Iterator(const NormObjectTable& objectTable);
|
||||
NormObject* GetNextObject();
|
||||
NormObject* GetPrevObject();
|
||||
void Reset() {reset = true;}
|
||||
|
||||
private:
|
||||
const NormObjectTable& table;
|
||||
bool reset;
|
||||
NormObjectId index;
|
||||
bool backwards;
|
||||
};
|
||||
|
||||
private:
|
||||
NormObject* Next(NormObject* o) const {return o->next;}
|
||||
|
||||
NormObject** table;
|
||||
unsigned long hash_mask;
|
||||
unsigned long range_max; // max range of objects that can be kept
|
||||
unsigned long range; // zero if "object table" is empty
|
||||
NormObjectId range_lo;
|
||||
NormObjectId range_hi;
|
||||
}; // end class NormObjectTable
|
||||
|
||||
#endif // _NORM_OBJECT
|
||||
|
|
@ -0,0 +1,551 @@
|
|||
#include "normSegment.h"
|
||||
|
||||
#include <errno.h> // for strerror()
|
||||
|
||||
NormSegmentPool::NormSegmentPool()
|
||||
: seg_size(0), seg_count(0), seg_total(0), seg_list(NULL),
|
||||
peak_usage(0), overruns(0), overrun_flag(false)
|
||||
{
|
||||
}
|
||||
|
||||
NormSegmentPool::~NormSegmentPool()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NormSegmentPool::Init(unsigned int count, unsigned int size)
|
||||
{
|
||||
if (seg_list) Destroy();
|
||||
peak_usage = 0;
|
||||
overruns = 0;
|
||||
// This makes sure we get appropriate alignment
|
||||
unsigned int alloc_size = size / sizeof(char*);
|
||||
if ((alloc_size*sizeof(char*)) < size) alloc_size++;
|
||||
seg_size = alloc_size * sizeof(char*);
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
char** ptr = new char*[alloc_size];
|
||||
if (ptr)
|
||||
{
|
||||
*ptr = seg_list;
|
||||
seg_list = (char*)ptr;
|
||||
seg_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormSegmentPool::Init() memory allocation error: %s\n",
|
||||
strerror(errno));
|
||||
seg_total = seg_count;
|
||||
Destroy();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
seg_total = seg_count;
|
||||
return true;
|
||||
} // end NormSegmentPool::Init()
|
||||
|
||||
void NormSegmentPool::Destroy()
|
||||
{
|
||||
ASSERT(seg_count == seg_total);
|
||||
char** ptr = (char**)seg_list;
|
||||
while (ptr)
|
||||
{
|
||||
char* next = *ptr;
|
||||
delete ptr;
|
||||
ptr = (char**)next;
|
||||
}
|
||||
seg_list = NULL;
|
||||
seg_count = 0;
|
||||
seg_total = 0;
|
||||
seg_size = 0;
|
||||
} // end NormSegmentPool::Destroy()
|
||||
|
||||
char* NormSegmentPool::Get()
|
||||
{
|
||||
char** ptr = (char**)seg_list;
|
||||
if (ptr)
|
||||
{
|
||||
seg_list = *ptr;
|
||||
seg_count--;
|
||||
#ifdef NORM_DEBUG
|
||||
overrun_flag = false;
|
||||
unsigned int usage = seg_total - seg_count;
|
||||
if (usage > peak_usage) peak_usage = usage;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!overrun_flag)
|
||||
{
|
||||
overruns++;
|
||||
overrun_flag = true;
|
||||
}
|
||||
#endif // NORM_DEBUG
|
||||
}
|
||||
return ((char*)ptr);
|
||||
} // end NormSegmentPool::GetSegment()
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// NormBlock Implementation
|
||||
|
||||
NormBlock::NormBlock()
|
||||
: size(0), segment_table(NULL), erasure_count(0), parity_count(0)
|
||||
{
|
||||
}
|
||||
|
||||
NormBlock::~NormBlock()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NormBlock::Init(UINT16 blockSize)
|
||||
{
|
||||
if (segment_table) Destroy();
|
||||
if (!(segment_table = new char*[blockSize]))
|
||||
{
|
||||
DMSG(0, "NormBlock::Init() segment_table allocation error: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
memset(segment_table, 0, blockSize*sizeof(char*));
|
||||
if (!pending_mask.Init(blockSize))
|
||||
{
|
||||
DMSG(0, "NormBlock::Init() pending_mask allocation error: %s\n", strerror(errno));
|
||||
Destroy();
|
||||
return false;
|
||||
}
|
||||
if (!repair_mask.Init(blockSize))
|
||||
{
|
||||
DMSG(0, "NormBlock::Init() repair_mask allocation error: %s\n", strerror(errno));
|
||||
Destroy();
|
||||
return false;
|
||||
}
|
||||
size = blockSize;
|
||||
erasure_count = 0;
|
||||
parity_count = 0;
|
||||
return true;
|
||||
} // end NormBlock::Init()
|
||||
|
||||
void NormBlock::Destroy()
|
||||
{
|
||||
repair_mask.Destroy();
|
||||
pending_mask.Destroy();
|
||||
// (TBD) Option to return segments to pool from which they came
|
||||
if (segment_table)
|
||||
{
|
||||
for (unsigned int i = 0; i < size; i++)
|
||||
if (segment_table[i]) delete []segment_table[i];
|
||||
delete []segment_table;
|
||||
segment_table = (char**)NULL;
|
||||
}
|
||||
erasure_count = parity_count = size = 0;
|
||||
} // end NormBlock::Destroy()
|
||||
|
||||
void NormBlock::EmptyToPool(NormSegmentPool& segmentPool)
|
||||
{
|
||||
ASSERT(segment_table);
|
||||
for (unsigned int i = 0; i < size; i++)
|
||||
{
|
||||
if (segment_table[i])
|
||||
{
|
||||
segmentPool.Put(segment_table[i]);
|
||||
segment_table[i] = (char*)NULL;
|
||||
}
|
||||
}
|
||||
} // end NormBlock::EmptyToPool()
|
||||
|
||||
bool NormBlock::IsEmpty()
|
||||
{
|
||||
ASSERT(segment_table);
|
||||
for (unsigned int i = 0; i < size; i++)
|
||||
if (segment_table[i]) return false;
|
||||
return true;
|
||||
} // end NormBlock::EmptyToPool()
|
||||
|
||||
bool NormBlock::IsRepairPending(NormSegmentId end)
|
||||
{
|
||||
ASSERT(end <= repair_mask.Size());
|
||||
repair_mask.SetBits(end, repair_mask.Size() - end);
|
||||
repair_mask.XCopy(pending_mask);
|
||||
return (repair_mask.IsSet() ? (repair_mask.FirstSet() < end) : false);
|
||||
} // end NormBlock::IsRepairPending()
|
||||
|
||||
|
||||
NormBlockPool::NormBlockPool()
|
||||
: head((NormBlock*)NULL)
|
||||
{
|
||||
}
|
||||
|
||||
NormBlockPool::~NormBlockPool()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NormBlockPool::Init(UINT32 numBlocks, UINT16 blockSize)
|
||||
{
|
||||
if (head) Destroy();
|
||||
for (UINT32 i = 0; i < numBlocks; i++)
|
||||
{
|
||||
NormBlock* b = new NormBlock();
|
||||
if (b)
|
||||
{
|
||||
if (!b->Init(blockSize))
|
||||
{
|
||||
DMSG(0, "NormBlockPool::Init() block init error\n");
|
||||
delete b;
|
||||
Destroy();
|
||||
return false;
|
||||
}
|
||||
b->next = head;
|
||||
head = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormBlockPool::Init() new block error\n");
|
||||
Destroy();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} // end NormBlockPool::Init()
|
||||
|
||||
void NormBlockPool::Destroy()
|
||||
{
|
||||
NormBlock* next;
|
||||
while ((next = head))
|
||||
{
|
||||
head = next->next;
|
||||
delete next;
|
||||
}
|
||||
} // end NormBlockPool::Destroy()
|
||||
|
||||
NormBlockBuffer::NormBlockBuffer()
|
||||
: table((NormBlock**)NULL), range_max(0), range(0)
|
||||
{
|
||||
}
|
||||
|
||||
NormBlockBuffer::~NormBlockBuffer()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NormBlockBuffer::Init(unsigned long rangeMax, unsigned long tableSize)
|
||||
{
|
||||
if (table) Destroy();
|
||||
// Make sure tableSize is greater than 0 and 2^n
|
||||
if (!rangeMax || !tableSize)
|
||||
{
|
||||
DMSG(0, "NormBlockBuffer::Init() bad range(%lu) or tableSize(%lu)\n",
|
||||
rangeMax, tableSize);
|
||||
return false;
|
||||
}
|
||||
if (0 != (tableSize & 0x07)) tableSize = (tableSize >> 3) + 1;
|
||||
if (!(table = new NormBlock*[tableSize]))
|
||||
{
|
||||
DMSG(0, "NormBlockBuffer::Init() buffer allocation error: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
memset(table, 0, tableSize*sizeof(char*));
|
||||
hash_mask = tableSize - 1;
|
||||
range_max = rangeMax;
|
||||
range = 0;
|
||||
return true;
|
||||
} // end NormBlockBuffer::Init()
|
||||
|
||||
void NormBlockBuffer::Destroy()
|
||||
{
|
||||
range_max = range = 0;
|
||||
if (table)
|
||||
{
|
||||
NormBlock* block;
|
||||
while((block = Find(range_lo)))
|
||||
{
|
||||
DMSG(0, "NormBlockBuffer::Destroy() buffer not empty!?\n");
|
||||
Remove(block);
|
||||
delete block;
|
||||
}
|
||||
delete []table;
|
||||
table = (NormBlock**)NULL;
|
||||
range_max = 0;
|
||||
}
|
||||
} // end NormBlockBuffer::Destroy()
|
||||
|
||||
NormBlock* NormBlockBuffer::Find(const NormBlockId& blockId) const
|
||||
{
|
||||
if (range)
|
||||
{
|
||||
if ((blockId < range_lo) || (blockId > range_hi)) return (NormBlock*)NULL;
|
||||
NormBlock* theBlock = table[((UINT32)blockId) & hash_mask];
|
||||
//printf("NormBlockBuffer::Find() table[%lu] = %p\n", ((UINT32)blockId) & hash_mask, theBlock);
|
||||
while (theBlock && (blockId != theBlock->Id())) theBlock = theBlock->next;
|
||||
return theBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (NormBlock*)NULL;
|
||||
}
|
||||
} // end NormBlockBuffer::Find()
|
||||
|
||||
|
||||
bool NormBlockBuffer::CanInsert(NormBlockId blockId) const
|
||||
{
|
||||
if (0 != range)
|
||||
{
|
||||
if (blockId < range_lo)
|
||||
{
|
||||
if ((range_lo - blockId + range) > range_max)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
else if (blockId > range_hi)
|
||||
{
|
||||
if ((blockId - range_hi + range) > range_max)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
} // end NormBlockBuffer::CanInsert()
|
||||
|
||||
|
||||
bool NormBlockBuffer::Insert(NormBlock* theBlock)
|
||||
{
|
||||
if (range < range_max)
|
||||
{
|
||||
const NormBlockId& blockId = theBlock->Id();
|
||||
if (!range)
|
||||
{
|
||||
range_lo = range_hi = blockId;
|
||||
range = 1;
|
||||
}
|
||||
if (blockId < range_lo)
|
||||
{
|
||||
UINT32 newRange = range_lo - blockId + range;
|
||||
if (newRange > range_max) return false;
|
||||
range_lo = blockId;
|
||||
range = newRange;
|
||||
}
|
||||
else if (blockId > range_hi)
|
||||
{
|
||||
UINT32 newRange = blockId - range_hi + range;
|
||||
if (newRange > range_max) return false;
|
||||
range_hi = blockId;
|
||||
range = newRange;
|
||||
}
|
||||
UINT32 index = ((UINT32)blockId) & hash_mask;
|
||||
NormBlock* prev = NULL;
|
||||
NormBlock* entry = table[index];
|
||||
while (entry && (entry->Id() < blockId))
|
||||
{
|
||||
prev = entry;
|
||||
entry = entry->next;
|
||||
}
|
||||
if (prev)
|
||||
prev->next = theBlock;
|
||||
else
|
||||
table[index] = theBlock;
|
||||
ASSERT((entry ? (blockId != entry->Id()) : true));
|
||||
theBlock->next = entry;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} // end NormBlockBuffer::Insert()
|
||||
|
||||
bool NormBlockBuffer::Remove(const NormBlock* theBlock)
|
||||
{
|
||||
ASSERT(theBlock);
|
||||
const NormBlockId& blockId = theBlock->Id();
|
||||
if (range)
|
||||
{
|
||||
if ((blockId < range_lo) || (blockId > range_hi)) return false;
|
||||
UINT32 index = ((UINT32)blockId) & hash_mask;
|
||||
NormBlock* prev = NULL;
|
||||
NormBlock* entry = table[index];
|
||||
while (entry && (entry->Id() != blockId))
|
||||
{
|
||||
prev = entry;
|
||||
entry = entry->next;
|
||||
}
|
||||
if (entry != theBlock) return false;
|
||||
if (prev)
|
||||
prev->next = entry->next;
|
||||
else
|
||||
table[index] = (NormBlock*)NULL;
|
||||
if (range > 1)
|
||||
{
|
||||
if (blockId == range_lo)
|
||||
{
|
||||
// Find next entry for range_lo
|
||||
UINT32 i = index;
|
||||
UINT32 endex;
|
||||
if (range <= hash_mask)
|
||||
endex = (index + range) & hash_mask;
|
||||
else
|
||||
endex = index;
|
||||
entry = NULL;
|
||||
UINT32 offset = 0;
|
||||
NormBlockId nextId = range_hi;
|
||||
do
|
||||
{
|
||||
++i &= hash_mask;
|
||||
offset++;
|
||||
if ((entry = table[i]))
|
||||
{
|
||||
NormBlockId id = (UINT32)index + offset;
|
||||
while(entry && (entry->Id() != id))
|
||||
{
|
||||
if ((entry->Id() > blockId) && (entry->Id() < nextId))
|
||||
nextId = entry->Id();
|
||||
entry = entry->next;
|
||||
|
||||
}
|
||||
if (entry) break;
|
||||
}
|
||||
} while (i != endex);
|
||||
if (entry)
|
||||
{
|
||||
range_lo = entry->Id();
|
||||
range = range_hi - range_lo + 1;
|
||||
}
|
||||
else if (nextId != range_hi)
|
||||
{
|
||||
range_lo = nextId;
|
||||
range = range_hi - range_lo + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
range = 0;
|
||||
}
|
||||
}
|
||||
else if (blockId == range_hi)
|
||||
{
|
||||
// Find prev entry for range_hi
|
||||
UINT32 i = index;
|
||||
UINT32 endex;
|
||||
if (range <= hash_mask)
|
||||
endex = (index - range) & hash_mask;
|
||||
else
|
||||
endex = index;
|
||||
entry = NULL;
|
||||
UINT32 offset = 0;
|
||||
//printf("preving i:%lu endex:%lu lo:%lu hi:%lu\n", i, endex, (UINT32)range_lo, (UINT32) range_hi);
|
||||
NormBlockId prevId = range_lo;
|
||||
do
|
||||
{
|
||||
--i &= hash_mask;
|
||||
offset++;
|
||||
if ((entry = table[i]))
|
||||
{
|
||||
NormBlockId id = (UINT32)index - offset;
|
||||
//printf("Looking for id:%lu at index:%lu\n", (UINT32)id, i);
|
||||
while(entry && (entry->Id() != id))
|
||||
{
|
||||
if ((entry->Id() < blockId) && (entry->Id() > prevId))
|
||||
prevId = entry->Id();
|
||||
entry = entry->next;
|
||||
}
|
||||
if (entry) break;
|
||||
}
|
||||
} while (i != endex);
|
||||
if (entry)
|
||||
{
|
||||
range_hi = entry->Id();
|
||||
|
||||
}
|
||||
else if (prevId != range_lo)
|
||||
{
|
||||
range_hi = prevId;
|
||||
range = range_hi - range_lo + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
range = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
range = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} // end NormBlockBuffer::Remove()
|
||||
|
||||
NormBlockBuffer::Iterator::Iterator(const NormBlockBuffer& blockBuffer)
|
||||
: buffer(blockBuffer), reset(true)
|
||||
{
|
||||
}
|
||||
|
||||
NormBlock* NormBlockBuffer::Iterator::GetNextBlock()
|
||||
{
|
||||
if (reset)
|
||||
{
|
||||
if (buffer.range)
|
||||
{
|
||||
reset = false;
|
||||
index = buffer.range_lo;
|
||||
return buffer.Find(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (NormBlock*)NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (buffer.range &&
|
||||
(index < buffer.range_hi) &&
|
||||
!(index < buffer.range_lo))
|
||||
{
|
||||
// Find next entry _after_ current "index"
|
||||
UINT32 i = index;
|
||||
UINT32 endex = buffer.range_hi - index;
|
||||
if (endex <= buffer.hash_mask)
|
||||
endex = (index + endex) & buffer.hash_mask;
|
||||
else
|
||||
endex = index;
|
||||
UINT32 offset = 0;
|
||||
NormBlockId nextId = buffer.range_hi;
|
||||
do
|
||||
{
|
||||
++i &= buffer.hash_mask;
|
||||
offset++;
|
||||
NormBlockId id = (UINT32)index + offset;
|
||||
NormBlock* entry = buffer.table[i];
|
||||
while ((NULL != entry )& (entry->Id() != id))
|
||||
{
|
||||
if ((entry->Id() > index) && (entry->Id() < nextId))
|
||||
nextId = entry->Id();
|
||||
entry = NormBlockBuffer::Next(entry);
|
||||
}
|
||||
if (entry)
|
||||
{
|
||||
index = entry->Id();
|
||||
return entry;
|
||||
}
|
||||
} while (i != endex);
|
||||
// If we get here, use nextId value
|
||||
index = nextId;
|
||||
return buffer.Find(nextId);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (NormBlock*)NULL;
|
||||
}
|
||||
}
|
||||
} // end NormBlockBuffer::Iterator::GetNextBlock()
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
#ifndef _NORM_SEGMENT
|
||||
#define _NORM_SEGMENT
|
||||
|
||||
#include "normMessage.h"
|
||||
#include "normBitmask.h"
|
||||
|
||||
// Norm uses preallocated (or dynamically allocated) pools of
|
||||
// segments (vectors) for different buffering purposes
|
||||
|
||||
class NormSegmentPool
|
||||
{
|
||||
public:
|
||||
NormSegmentPool();
|
||||
~NormSegmentPool();
|
||||
|
||||
bool Init(unsigned int count, unsigned int size);
|
||||
void Destroy();
|
||||
char* Get();
|
||||
void Put(char* segment)
|
||||
{
|
||||
ASSERT(seg_count < seg_total);
|
||||
char** ptr = (char**)segment;
|
||||
*ptr = seg_list;
|
||||
seg_list = segment;
|
||||
seg_count++;
|
||||
}
|
||||
bool IsEmpty() {return (NULL == seg_list);}
|
||||
|
||||
private:
|
||||
unsigned int seg_size;
|
||||
unsigned int seg_count;
|
||||
unsigned int seg_total;
|
||||
char* seg_list;
|
||||
|
||||
unsigned int peak_usage;
|
||||
unsigned int overruns;
|
||||
bool overrun_flag;
|
||||
}; // end class NormSegmentPool
|
||||
|
||||
class NormBlock
|
||||
{
|
||||
friend class NormBlockPool;
|
||||
friend class NormBlockBuffer;
|
||||
|
||||
public:
|
||||
enum Flag
|
||||
{
|
||||
PARITY_READY = 0x01,
|
||||
IN_REPAIR = 0x02
|
||||
};
|
||||
|
||||
NormBlock();
|
||||
~NormBlock();
|
||||
const NormBlockId& Id() const {return id;}
|
||||
void SetId(NormBlockId& x) {id = x;}
|
||||
bool Init(UINT16 blockSize);
|
||||
void Destroy();
|
||||
|
||||
void SetFlag(NormBlock::Flag flag) {flags |= flag;}
|
||||
bool ParityReady() {return (0 != (flags & PARITY_READY));}
|
||||
bool InRepair() {return (0 != (flags & IN_REPAIR));}
|
||||
|
||||
char** SegmentList(UINT16 index = 0) {return &segment_table[index];}
|
||||
char* Segment(NormSegmentId sid)
|
||||
{
|
||||
ASSERT(sid < size);
|
||||
return segment_table[sid];
|
||||
}
|
||||
void AttachSegment(NormSegmentId sid, char* segment)
|
||||
{
|
||||
ASSERT(sid < size);
|
||||
ASSERT(!segment_table[sid]);
|
||||
segment_table[sid] = segment;
|
||||
erasure_count--;
|
||||
}
|
||||
char* DetachSegment(NormSegmentId sid)
|
||||
{
|
||||
ASSERT(sid < size);
|
||||
char* segment = segment_table[sid];
|
||||
segment_table[sid] = (char*)NULL;
|
||||
return segment;
|
||||
}
|
||||
void SetSegment(NormSegmentId sid, char* segment)
|
||||
{
|
||||
ASSERT(sid < size);
|
||||
ASSERT(!segment_table[sid]);
|
||||
segment_table[sid] = segment;
|
||||
}
|
||||
|
||||
void TxInit(NormBlockId& blockId, UINT16 ndata, UINT16 autoParity)
|
||||
{
|
||||
id = blockId;
|
||||
pending_mask.Clear();
|
||||
pending_mask.SetBits(0, ndata+autoParity);
|
||||
repair_mask.Clear();
|
||||
erasure_count = size - ndata;
|
||||
parity_count = 0;
|
||||
flags = 0;
|
||||
}
|
||||
void RxInit(NormBlockId& blockId, UINT16 ndata)
|
||||
{
|
||||
id = blockId;
|
||||
pending_mask.Reset();
|
||||
repair_mask.Clear();
|
||||
erasure_count = size;
|
||||
parity_count = 0;
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
NormSymbolId FirstPending() const
|
||||
{return pending_mask.FirstSet();}
|
||||
NormSymbolId FirstRepair() const
|
||||
{return repair_mask.FirstSet();}
|
||||
bool SetPending(NormSymbolId s)
|
||||
{return pending_mask.Set(s);}
|
||||
void UnsetPending(NormSymbolId s)
|
||||
{pending_mask.Unset(s);}
|
||||
void ClearPending()
|
||||
{pending_mask.Clear();}
|
||||
bool SetRepair(NormSymbolId s)
|
||||
{return repair_mask.Set(s);}
|
||||
void UnsetRepair(NormSymbolId s)
|
||||
{repair_mask.Unset(s);}
|
||||
void ClearRepairs()
|
||||
{repair_mask.Clear();}
|
||||
bool IsPending(NormSymbolId s) const
|
||||
{return pending_mask.Test(s);}
|
||||
bool IsPending() const
|
||||
{return pending_mask.IsSet();}
|
||||
bool IsRepairPending(NormSegmentId end);
|
||||
|
||||
NormSymbolId NextPending(NormSymbolId index) const
|
||||
{return pending_mask.NextSet(index);}
|
||||
UINT16 ErasureCount() const {return erasure_count;}
|
||||
//void DisplayPendingMask(FILE* f) {pending_mask.Display(f);}
|
||||
|
||||
bool IsEmpty();
|
||||
void EmptyToPool(NormSegmentPool& segmentPool);
|
||||
|
||||
private:
|
||||
NormBlockId id;
|
||||
UINT16 size;
|
||||
char** segment_table;
|
||||
|
||||
int flags;
|
||||
UINT16 erasure_count;
|
||||
UINT16 parity_count;
|
||||
|
||||
NormBitmask pending_mask;
|
||||
NormBitmask repair_mask;
|
||||
|
||||
NormBlock* next;
|
||||
}; // end class NormBlock
|
||||
|
||||
class NormBlockPool
|
||||
{
|
||||
public:
|
||||
NormBlockPool();
|
||||
~NormBlockPool();
|
||||
bool Init(UINT32 numBlocks, UINT16 blockSize);
|
||||
void Destroy();
|
||||
bool IsEmpty() {return (NULL == head);}
|
||||
NormBlock* Get()
|
||||
{
|
||||
NormBlock* b = head;
|
||||
head = b ? b->next : NULL;
|
||||
return b;
|
||||
}
|
||||
void Put(NormBlock* b)
|
||||
{
|
||||
b->next = head;
|
||||
head = b;
|
||||
}
|
||||
|
||||
private:
|
||||
NormBlock* head;
|
||||
}; // end class NormBlockPool
|
||||
|
||||
class NormBlockBuffer
|
||||
{
|
||||
friend class NormBlockBuffer::Iterator;
|
||||
|
||||
public:
|
||||
NormBlockBuffer();
|
||||
~NormBlockBuffer();
|
||||
bool Init(unsigned long rangeMax, unsigned long tableSize = 256);
|
||||
void Destroy();
|
||||
|
||||
bool Insert(NormBlock* theBlock);
|
||||
bool Remove(const NormBlock* theBlock);
|
||||
NormBlock* Find(const NormBlockId& blockId) const;
|
||||
|
||||
NormBlockId RangeLo() {return range_lo;}
|
||||
NormBlockId RangeHi() {return range_hi;}
|
||||
bool IsEmpty() {return (0 == range);}
|
||||
bool CanInsert(NormBlockId blockId) const;
|
||||
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
Iterator(const NormBlockBuffer& blockBuffer);
|
||||
NormBlock* GetNextBlock();
|
||||
void Reset() {reset = true;}
|
||||
|
||||
private:
|
||||
const NormBlockBuffer& buffer;
|
||||
bool reset;
|
||||
NormBlockId index;
|
||||
};
|
||||
|
||||
private:
|
||||
static NormBlock* Next(NormBlock* b) {return b->next;}
|
||||
|
||||
NormBlock** table;
|
||||
unsigned long hash_mask;
|
||||
unsigned long range_max; // max range of blocks that can be buffered
|
||||
unsigned long range; // zero if "block buffer" is empty
|
||||
NormBlockId range_lo;
|
||||
NormBlockId range_hi;
|
||||
}; // end class NormBlockBuffer
|
||||
|
||||
|
||||
|
||||
#endif // _NORM_SEGMENT
|
||||
|
|
@ -0,0 +1,547 @@
|
|||
#include "normSession.h"
|
||||
#include <errno.h>
|
||||
|
||||
NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
|
||||
: session_mgr(sessionMgr), local_node_id(localNodeId),
|
||||
tx_rate(DEFAULT_TRANSMIT_RATE),
|
||||
is_server(false), flush_count(NORM_ROBUST_FACTOR),
|
||||
posted_tx_queue_empty(false),
|
||||
is_client(false),
|
||||
next(NULL)
|
||||
{
|
||||
tx_socket.Init((UdpSocketOwner*) this,
|
||||
(UdpSocketRecvHandler)&NormSession::TxSocketRecvHandler,
|
||||
sessionMgr.SocketInstaller(),
|
||||
sessionMgr.SocketInstallData());
|
||||
rx_socket.Init((UdpSocketOwner*) this,
|
||||
(UdpSocketRecvHandler)&NormSession::RxSocketRecvHandler,
|
||||
sessionMgr.SocketInstaller(),
|
||||
sessionMgr.SocketInstallData());
|
||||
|
||||
tx_timer.Init(0.0, -1,
|
||||
(ProtocolTimerOwner *)this,
|
||||
(ProtocolTimeoutFunc)&NormSession::OnTxTimeout);
|
||||
}
|
||||
|
||||
NormSession::~NormSession()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
const double NormSession::DEFAULT_TRANSMIT_RATE = 8000.0;
|
||||
|
||||
|
||||
bool NormSession::Open()
|
||||
{
|
||||
ASSERT(address.IsValid());
|
||||
if (!tx_socket.IsOpen())
|
||||
{
|
||||
if (UDP_SOCKET_ERROR_NONE != tx_socket.Open())
|
||||
{
|
||||
DMSG(0, "NormSession::Open() tx_socket open error\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!rx_socket.IsOpen())
|
||||
{
|
||||
if (UDP_SOCKET_ERROR_NONE != rx_socket.Open(address.Port()))
|
||||
{
|
||||
DMSG(0, "NormSession::Open() rx_socket open error\n");
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
if (address.IsMulticast())
|
||||
{
|
||||
if (UDP_SOCKET_ERROR_NONE != rx_socket.JoinGroup(&address, ttl))
|
||||
{
|
||||
DMSG(0, "NormSession::Open() rx_socket join group error\n");
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < DEFAULT_MESSAGE_POOL_DEPTH; i++)
|
||||
{
|
||||
NormMessage* msg = new NormMessage();
|
||||
if (msg)
|
||||
{
|
||||
message_pool.Append(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormSession::Open() new message error: %s\n", strerror(errno));
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} // end NormSession::Open()
|
||||
|
||||
void NormSession::Close()
|
||||
{
|
||||
if (is_server) StopServer();
|
||||
if (is_client) StopClient();
|
||||
if (tx_timer.IsActive()) tx_timer.Deactivate();
|
||||
message_queue.Destroy();
|
||||
message_pool.Destroy();
|
||||
if (tx_socket.IsOpen()) tx_socket.Close();
|
||||
if (rx_socket.IsOpen()) rx_socket.Close();
|
||||
} // end NormSession::Close()
|
||||
|
||||
|
||||
bool NormSession::StartServer(unsigned long bufferSpace,
|
||||
UINT16 segmentSize,
|
||||
UINT16 numData,
|
||||
UINT16 numParity)
|
||||
{
|
||||
if (!IsOpen())
|
||||
{
|
||||
if (!Open()) return false;
|
||||
}
|
||||
// (TBD) parameterize the object history depth
|
||||
if (!tx_table.Init(256))
|
||||
{
|
||||
DMSG(0, "NormSession::StartServer() tx_table.Init() error!\n");
|
||||
StopServer();
|
||||
return false;
|
||||
}
|
||||
if (!tx_pending_mask.Init(256))
|
||||
{
|
||||
DMSG(0, "NormSession::StartServer() tx_pending_mask.Init() error!\n");
|
||||
StopServer();
|
||||
return false;
|
||||
}
|
||||
if (!tx_repair_mask.Init(256))
|
||||
{
|
||||
DMSG(0, "NormSession::StartServer() tx_repair_mask.Init() error!\n");
|
||||
StopServer();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate how much memory each buffered block will require
|
||||
UINT16 blockSize = numData + numParity;
|
||||
unsigned long maskSize = blockSize >> 3;
|
||||
if (0 != (blockSize & 0x07)) maskSize++;
|
||||
unsigned long blockSpace = sizeof(NormBlock) +
|
||||
blockSize * sizeof(char*) +
|
||||
2*maskSize +
|
||||
numParity * (segmentSize + NormDataMsg::PayloadHeaderLen());
|
||||
|
||||
unsigned long numBlocks = bufferSpace / blockSpace;
|
||||
if (bufferSpace > (numBlocks*blockSpace)) numBlocks++;
|
||||
if (numBlocks < 2) numBlocks = 2;
|
||||
unsigned long numSegments = numBlocks * numParity;
|
||||
|
||||
if (!block_pool.Init(numBlocks, blockSize))
|
||||
{
|
||||
DMSG(0, "NormSession::StartServer() block_pool init error\n");
|
||||
StopServer();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!segment_pool.Init(numSegments, segmentSize + NormDataMsg::PayloadHeaderLen()))
|
||||
{
|
||||
DMSG(0, "NormSession::StartServer() segment_pool init error\n");
|
||||
StopServer();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (numParity)
|
||||
{
|
||||
if (!encoder.Init(numParity, segmentSize + NormDataMsg::PayloadHeaderLen()))
|
||||
{
|
||||
DMSG(0, "NormSession::StartServer() encoder init error\n");
|
||||
StopServer();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
segment_size = segmentSize;
|
||||
ndata = numData;
|
||||
nparity = numParity;
|
||||
is_server = true;
|
||||
flush_count = NORM_ROBUST_FACTOR; // (TBD) parameterize robust_factor
|
||||
return true;
|
||||
} // end NormSession::StartServer()
|
||||
|
||||
void NormSession::StopServer()
|
||||
{
|
||||
encoder.Destroy();
|
||||
tx_table.Destroy();
|
||||
block_pool.Destroy();
|
||||
segment_pool.Destroy();
|
||||
tx_repair_mask.Destroy();
|
||||
tx_pending_mask.Destroy();
|
||||
tx_table.Destroy();
|
||||
is_server = false;
|
||||
if (!IsClient()) Close();
|
||||
} // end NormSession::StopServer()
|
||||
|
||||
bool NormSession::StartClient(unsigned long bufferSize)
|
||||
{
|
||||
is_client = true;
|
||||
remote_server_buffer_size = bufferSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
void NormSession::StopClient()
|
||||
{
|
||||
server_tree.Destroy();
|
||||
is_client = false;
|
||||
if (!is_server) Close();
|
||||
}
|
||||
|
||||
void NormSession::Serve()
|
||||
{
|
||||
if (tx_timer.IsActive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NormObject* obj = NULL;
|
||||
// Queue next server message
|
||||
if (tx_pending_mask.IsSet())
|
||||
{
|
||||
NormObjectId objectId(tx_pending_mask.FirstSet());
|
||||
obj = tx_table.Find(objectId);
|
||||
ASSERT(obj);
|
||||
flush_count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!posted_tx_queue_empty)
|
||||
{
|
||||
posted_tx_queue_empty = true;
|
||||
Notify(NormController::TX_QUEUE_EMPTY,
|
||||
(NormServerNode*)NULL,
|
||||
(NormObject*)NULL);
|
||||
// (TBD) Was session deleted?
|
||||
Serve();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (obj)
|
||||
{
|
||||
NormMessage* msg = message_pool.RemoveHead();
|
||||
if (msg)
|
||||
{
|
||||
if (obj->NextServerMsg(msg))
|
||||
{
|
||||
msg->generic.SetDestination(address);
|
||||
QueueMessage(msg);
|
||||
if (!obj->IsPending())
|
||||
tx_pending_mask.Unset(obj->Id());
|
||||
}
|
||||
else
|
||||
{
|
||||
message_pool.Append(msg);
|
||||
if (obj->IsStream())
|
||||
{
|
||||
if (!posted_tx_queue_empty)
|
||||
{
|
||||
posted_tx_queue_empty = true;
|
||||
Notify(NormController::TX_QUEUE_EMPTY,
|
||||
(NormServerNode*)NULL, obj);
|
||||
// (TBD) Was session deleted?
|
||||
Serve();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormSession::Serve() pending obj, no message?.\n");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormSession::Serve() Warning! message_pool empty.\n");
|
||||
}
|
||||
}
|
||||
else if (flush_count < NORM_ROBUST_FACTOR)
|
||||
{
|
||||
// Queue flush message
|
||||
flush_count++;
|
||||
}
|
||||
} // end NormSession::Serve()
|
||||
|
||||
void NormSession::QueueMessage(NormMessage* msg)
|
||||
{
|
||||
if (message_queue.IsEmpty())
|
||||
{
|
||||
tx_timer.SetInterval(0.0);
|
||||
InstallTimer(&tx_timer);
|
||||
}
|
||||
message_queue.Append(msg);
|
||||
} // end NormSesssion::QueueMessage(NormMessage& msg)
|
||||
|
||||
NormStreamObject* NormSession::QueueTxStream(UINT32 bufferSize,
|
||||
const char* infoPtr,
|
||||
UINT16 infoLen)
|
||||
{
|
||||
if (!IsServer())
|
||||
{
|
||||
DMSG(0, "NormSession::QueueTxStream() non-server session!\n");
|
||||
return NULL;
|
||||
}
|
||||
NormStreamObject* stream = new NormStreamObject(this, NULL, current_tx_object_id);
|
||||
if (!stream)
|
||||
{
|
||||
DMSG(0, "NormSession::QueueTxStream() new stream error!\n");
|
||||
return NULL;
|
||||
}
|
||||
if (!stream->Open(bufferSize, infoPtr, infoLen))
|
||||
{
|
||||
DMSG(0, "NormSession::QueueTxStream() stream open error!\n");
|
||||
delete stream;
|
||||
return NULL;
|
||||
}
|
||||
if (QueueTxObject(stream, false))
|
||||
{
|
||||
// (???: stream has nothing pending until user writes to it???)
|
||||
//stream->Reset();
|
||||
return stream;
|
||||
}
|
||||
else
|
||||
{
|
||||
stream->Close();
|
||||
delete stream;
|
||||
return NULL;
|
||||
}
|
||||
} // end NormSession::QueueTxStream()
|
||||
|
||||
|
||||
bool NormSession::QueueTxObject(NormObject* obj, bool touchServer)
|
||||
{
|
||||
if (!IsServer())
|
||||
{
|
||||
DMSG(0, "NormSession::QueueTxObject() non-server session!\n");
|
||||
return false;
|
||||
}
|
||||
// Attempt to queue the object
|
||||
if (!tx_table.Insert(obj))
|
||||
{
|
||||
// (TBD) steal an old non-pending object
|
||||
DMSG(0, "NormSession::QueueTxObject() tx_table insert error\n");
|
||||
return false;
|
||||
}
|
||||
tx_pending_mask.Set(obj->Id());
|
||||
ASSERT(tx_pending_mask.Test(obj->Id()));
|
||||
current_tx_object_id++;
|
||||
if (touchServer) TouchServer();
|
||||
return true;
|
||||
} // end NormSession::QueueTxObject()
|
||||
|
||||
NormBlock* NormSession::ServerGetFreeBlock(NormObjectId objectId,
|
||||
NormBlockId blockId)
|
||||
{
|
||||
// First, try to get one from our block pool
|
||||
NormBlock* b = block_pool.Get();
|
||||
if (!b)
|
||||
{
|
||||
NormObjectTable::Iterator iterator(tx_table);
|
||||
NormObject* obj;
|
||||
while ((obj = iterator.GetNextObject()))
|
||||
{
|
||||
if (obj->Id() > objectId)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (obj->Id() < objectId)
|
||||
b = obj->StealOldestBlock(false);
|
||||
else
|
||||
b = obj->StealOldestBlock(true, blockId);
|
||||
if (b)
|
||||
{
|
||||
b->EmptyToPool(segment_pool);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return b;
|
||||
} // end NormSession::ServerGetFreeBlock()
|
||||
|
||||
char* NormSession::ServerGetFreeSegment(NormObjectId objectId,
|
||||
NormBlockId blockId)
|
||||
{
|
||||
while (segment_pool.IsEmpty() &&
|
||||
ServerGetFreeBlock(objectId, blockId));
|
||||
return segment_pool.Get();
|
||||
} // end NormSession::ServerGetFreeSegment()
|
||||
|
||||
bool NormSession::TxSocketRecvHandler(UdpSocket* /*theSocket*/)
|
||||
{
|
||||
NormMessage msg;
|
||||
unsigned int buflen = NORM_MSG_SIZE_MAX;
|
||||
if (UDP_SOCKET_ERROR_NONE == tx_socket.RecvFrom(msg.generic.GetBuffer(), &buflen, msg.generic.Src()))
|
||||
{
|
||||
msg.generic.SetLength(buflen);
|
||||
HandleReceiveMessage(msg, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormSession::TxSocketRecvHandler() recv from error");
|
||||
}
|
||||
return true;
|
||||
} // end NormSession::TxSocketRecvHandler()
|
||||
|
||||
bool NormSession::RxSocketRecvHandler(UdpSocket* /*theSocket*/)
|
||||
{
|
||||
NormMessage msg;
|
||||
unsigned int buflen = NORM_MSG_SIZE_MAX;
|
||||
if (UDP_SOCKET_ERROR_NONE == rx_socket.RecvFrom(msg.generic.GetBuffer(), &buflen, msg.generic.Src()))
|
||||
{
|
||||
msg.generic.SetLength(buflen);
|
||||
HandleReceiveMessage(msg, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormSession::RxSocketRecvHandler() recv from error");
|
||||
}
|
||||
return true;
|
||||
} // end NormSession::RxSocketRecvHandler()
|
||||
|
||||
void NormSession::HandleReceiveMessage(NormMessage& msg, bool wasUnicast)
|
||||
{
|
||||
switch (msg.generic.GetType())
|
||||
{
|
||||
case NORM_MSG_INFO:
|
||||
DMSG(0, "NormSession::HandleReceiveMessage(NORM_MSG_INFO)\n");
|
||||
break;
|
||||
case NORM_MSG_DATA:
|
||||
//DMSG(0, "NormSession::HandleReceiveMessage(NORM_MSG_DATA)\n");
|
||||
ClientHandleObjectMessage(msg);
|
||||
break;
|
||||
case NORM_MSG_CMD:
|
||||
case NORM_MSG_NACK:
|
||||
case NORM_MSG_ACK:
|
||||
case NORM_MSG_REPORT:
|
||||
case NORM_MSG_INVALID:
|
||||
DMSG(0, "NormSession::HandleReceiveMessage(NORM_MSG_INVALID)\n");
|
||||
break;
|
||||
}
|
||||
} // end NormSession::HandleReceiveMessage()
|
||||
|
||||
void NormSession::ClientHandleObjectMessage(NormMessage& msg)
|
||||
{
|
||||
NormNodeId serverId = msg.generic.GetSender();
|
||||
NormServerNode* theServer = (NormServerNode*)server_tree.FindNodeById(serverId);
|
||||
if (!theServer)
|
||||
{
|
||||
if ((theServer = new NormServerNode(this, serverId)))
|
||||
{
|
||||
server_tree.AttachNode(theServer);
|
||||
DMSG(0, "NormSession::ClientHandleObjectMessage() new remote server:%lu ...\n",
|
||||
serverId);
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormSession::ClientHandleObjectMessage() new server node error\n");
|
||||
// (TBD) notify application of error
|
||||
return;
|
||||
}
|
||||
}
|
||||
theServer->SetAddress(*msg.generic.Src());
|
||||
theServer->HandleObjectMessage(msg);
|
||||
|
||||
} // end NormSession::ClientHandleObjectMessage()
|
||||
|
||||
bool NormSession::OnTxTimeout()
|
||||
{
|
||||
NormMessage* msg = message_queue.RemoveHead();
|
||||
if (msg)
|
||||
{
|
||||
// Fill in common message fields
|
||||
msg->generic.SetVersion(1);
|
||||
msg->generic.SetSequence(tx_sequence++);
|
||||
msg->generic.SetSender(local_node_id);
|
||||
NetworkAddress* dest = msg->generic.Dest();
|
||||
// Use session address by default
|
||||
if (!dest) dest = &address;
|
||||
UINT16 len = msg->generic.GetLength();
|
||||
if (UDP_SOCKET_ERROR_NONE != tx_socket.SendTo(dest, msg->generic.GetBuffer(), len))
|
||||
{
|
||||
DMSG(0, "NormSession::OnTxTimeout() sendto() error\n");
|
||||
}
|
||||
tx_timer.SetInterval(((double)len) / tx_rate);
|
||||
message_pool.Append(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
tx_timer.Deactivate();
|
||||
if (IsServer()) Serve();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} // end NormSession::OnTxTimeout()
|
||||
|
||||
NormSessionMgr::NormSessionMgr()
|
||||
: socket_installer(NULL), socket_install_data(NULL),
|
||||
controller(NULL), top_session(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
NormSessionMgr::~NormSessionMgr()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void NormSessionMgr::Destroy()
|
||||
{
|
||||
NormSession* next;
|
||||
while ((next = top_session))
|
||||
{
|
||||
top_session = next->next;
|
||||
delete next;
|
||||
}
|
||||
} // end NormSessionMgr::Destroy()
|
||||
|
||||
NormSession* NormSessionMgr::NewSession(const char* sessionAddress,
|
||||
UINT16 sessionPort,
|
||||
NormNodeId localNodeId)
|
||||
{
|
||||
if (NORM_NODE_ANY == localNodeId)
|
||||
{
|
||||
// Use local ip address to assign default localNodeId
|
||||
NetworkAddress localAddr;
|
||||
if (!localAddr.LookupLocalHostAddress())
|
||||
{
|
||||
DMSG(0, "NormSessionMgr::NewSession() local address lookup error\n");
|
||||
return ((NormSession*)NULL);
|
||||
}
|
||||
// (TBD) test IPv6 "EndIdentifier" ???
|
||||
localNodeId = localAddr.EndIdentifier();
|
||||
}
|
||||
|
||||
|
||||
NetworkAddress a;
|
||||
if (!a.LookupHostAddress(sessionAddress))
|
||||
{
|
||||
DMSG(0, "NormSessionMgr::NewSession() session address lookup error!\n");
|
||||
return ((NormSession*)NULL);
|
||||
}
|
||||
a.SetPort(sessionPort);
|
||||
|
||||
NormSession* s = new NormSession(*this, localNodeId);
|
||||
|
||||
if (!s)
|
||||
{
|
||||
DMSG(0, "NormSessionMgr::NewSession() new session error: %s\n",
|
||||
strerror(errno));
|
||||
return ((NormSession*)NULL);
|
||||
}
|
||||
|
||||
s->SetAddress(a);
|
||||
|
||||
// Add new session to our session list
|
||||
s->next = top_session;
|
||||
top_session = s;
|
||||
return s;
|
||||
} // end NormSessionMgr::NewSession();
|
||||
|
||||
|
|
@ -0,0 +1,208 @@
|
|||
#ifndef _NORM_SESSION
|
||||
#define _NORM_SESSION
|
||||
|
||||
#include "normMessage.h"
|
||||
#include "normObject.h"
|
||||
#include "normNode.h"
|
||||
#include "normEncoder.h"
|
||||
|
||||
#include "protocolTimer.h"
|
||||
#include "udpSocket.h"
|
||||
|
||||
|
||||
class NormController
|
||||
{
|
||||
public:
|
||||
enum Event
|
||||
{
|
||||
TX_QUEUE_EMPTY,
|
||||
RX_OBJECT_NEW,
|
||||
RX_OBJECT_UPDATE
|
||||
};
|
||||
|
||||
virtual void Notify(NormController::Event event,
|
||||
class NormSessionMgr* sessionMgr,
|
||||
class NormSession* session,
|
||||
class NormServerNode* server,
|
||||
class NormObject* object) = 0;
|
||||
|
||||
}; // end class NormController
|
||||
|
||||
class NormSessionMgr
|
||||
{
|
||||
friend class NormSession;
|
||||
public:
|
||||
NormSessionMgr();
|
||||
~NormSessionMgr();
|
||||
void Init(ProtocolTimerInstallFunc* timerInstaller,
|
||||
const void* timerInstallData,
|
||||
UdpSocketInstallFunc* socketInstaller,
|
||||
void* socketInstallData,
|
||||
NormController* theController)
|
||||
{
|
||||
timer_mgr.SetInstaller(timerInstaller, timerInstallData);
|
||||
socket_installer = socketInstaller;
|
||||
socket_install_data = socketInstallData;
|
||||
controller = theController;
|
||||
}
|
||||
void Destroy();
|
||||
|
||||
class NormSession* NewSession(const char* sessionAddress,
|
||||
UINT16 sessionPort,
|
||||
NormNodeId localNodeId =
|
||||
NORM_NODE_ANY);
|
||||
|
||||
UdpSocketInstallFunc* SocketInstaller() {return socket_installer;}
|
||||
const void* SocketInstallData() {return socket_install_data;}
|
||||
|
||||
void Notify(NormController::Event event,
|
||||
class NormSession* session,
|
||||
class NormServerNode* server,
|
||||
class NormObject* object)
|
||||
{
|
||||
if (controller)
|
||||
controller->Notify(event, this, session, server, object);
|
||||
}
|
||||
|
||||
private:
|
||||
void InstallTimer(ProtocolTimer* timer)
|
||||
{timer_mgr.InstallTimer(timer);}
|
||||
|
||||
ProtocolTimerMgr timer_mgr;
|
||||
UdpSocketInstallFunc* socket_installer;
|
||||
const void* socket_install_data;
|
||||
NormController* controller;
|
||||
|
||||
class NormSession* top_session;
|
||||
|
||||
}; // end class NormSessionMgr
|
||||
|
||||
|
||||
class NormSession
|
||||
{
|
||||
friend class NormSessionMgr;
|
||||
|
||||
public:
|
||||
enum {DEFAULT_MESSAGE_POOL_DEPTH = 16};
|
||||
static const double DEFAULT_TRANSMIT_RATE; // in bytes per second
|
||||
|
||||
NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId);
|
||||
~NormSession();
|
||||
|
||||
// General methods
|
||||
const NormNodeId& LocalNodeId() {return local_node_id;}
|
||||
bool Open();
|
||||
void Close();
|
||||
bool IsOpen() {return (rx_socket.IsOpen() || tx_socket.IsOpen());}
|
||||
|
||||
void SetAddress(const NetworkAddress& addr) {address = addr;}
|
||||
void SetLoopback(bool state)
|
||||
{rx_socket.SetLoopback(state);
|
||||
tx_socket.SetLoopback(state);}
|
||||
void Notify(NormController::Event event,
|
||||
class NormServerNode* server,
|
||||
class NormObject* object)
|
||||
{
|
||||
session_mgr.Notify(event, this, server, object);
|
||||
}
|
||||
|
||||
// Server methods
|
||||
bool StartServer(unsigned long bufferSpace,
|
||||
UINT16 segmentSize,
|
||||
UINT16 numData,
|
||||
UINT16 numParity);
|
||||
void StopServer();
|
||||
bool IsServer() {return is_server;}
|
||||
UINT16 ServerSegmentSize() {return segment_size;}
|
||||
UINT16 ServerBlockSize() {return ndata;}
|
||||
UINT16 ServerNumParity() {return nparity;}
|
||||
UINT16 ServerAutoParity() {return auto_parity;}
|
||||
void ServerSetAutoParity(UINT16 autoParity)
|
||||
{ASSERT(autoParity <= nparity); auto_parity = autoParity;}
|
||||
|
||||
void ServerEncode(const char* segment, char** parityVectorList)
|
||||
{encoder.Encode(segment, parityVectorList);}
|
||||
|
||||
NormStreamObject* QueueTxStream(UINT32 bufferSize,
|
||||
const char* infoPtr = NULL,
|
||||
UINT16 infoLen = 0);
|
||||
NormBlock* ServerGetFreeBlock(NormObjectId objectId, NormBlockId blockId);
|
||||
char* ServerGetFreeSegment(NormObjectId objectId, NormBlockId blockId);
|
||||
void ServerPutFreeBlock(NormBlock* block)
|
||||
{
|
||||
block->EmptyToPool(segment_pool);
|
||||
block_pool.Put(block);
|
||||
}
|
||||
void TouchServer()
|
||||
{
|
||||
posted_tx_queue_empty = false;
|
||||
Serve();
|
||||
}
|
||||
|
||||
// Client methods
|
||||
bool StartClient(unsigned long bufferSpace);
|
||||
void StopClient();
|
||||
bool IsClient() {return is_client;}
|
||||
unsigned long RemoteServerBufferSize()
|
||||
{return remote_server_buffer_size;}
|
||||
|
||||
private:
|
||||
void QueueMessage(NormMessage* msg);
|
||||
void Serve();
|
||||
bool QueueTxObject(NormObject* obj, bool touchServer = true);
|
||||
|
||||
void InstallTimer(ProtocolTimer* timer)
|
||||
{session_mgr.InstallTimer(timer);}
|
||||
|
||||
bool OnTxTimeout();
|
||||
|
||||
bool TxSocketRecvHandler(UdpSocket* theSocket);
|
||||
bool RxSocketRecvHandler(UdpSocket* theSocket);
|
||||
void HandleReceiveMessage(NormMessage& msg, bool wasUnicast);
|
||||
|
||||
void ClientHandleObjectMessage(NormMessage& msg);
|
||||
|
||||
NormSessionMgr& session_mgr;
|
||||
ProtocolTimer tx_timer;
|
||||
UdpSocket tx_socket;
|
||||
UdpSocket rx_socket;
|
||||
NormMessageQueue message_queue;
|
||||
NormMessageQueue message_pool;
|
||||
|
||||
// General session parameters
|
||||
NormNodeId local_node_id;
|
||||
NetworkAddress address; // session destination address
|
||||
UINT8 ttl; // session multicast ttl
|
||||
|
||||
UINT16 tx_sequence;
|
||||
double tx_rate; // bytes per second
|
||||
|
||||
// Server parameters
|
||||
bool is_server;
|
||||
UINT16 segment_size;
|
||||
UINT16 ndata;
|
||||
UINT16 nparity;
|
||||
UINT16 auto_parity;
|
||||
|
||||
NormObjectTable tx_table;
|
||||
NormSlidingMask tx_pending_mask;
|
||||
NormSlidingMask tx_repair_mask;
|
||||
NormBlockPool block_pool;
|
||||
NormSegmentPool segment_pool;
|
||||
NormEncoder encoder;
|
||||
|
||||
NormObjectId current_tx_object_id;
|
||||
int flush_count;
|
||||
bool posted_tx_queue_empty;
|
||||
|
||||
// Client parameters
|
||||
bool is_client;
|
||||
NormNodeTree server_tree;
|
||||
unsigned long remote_server_buffer_size;
|
||||
|
||||
// Misc
|
||||
NormSession* next;
|
||||
}; // end class NormSession
|
||||
|
||||
|
||||
#endif // _NORM_SESSION
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
NORM Rules
|
||||
|
||||
This file contains descriptions of rules used in the NRL
|
||||
NORM implementation for various aspects of protocol
|
||||
operation. These rules are related to the nature of the
|
||||
NORM protocol and how this particular implementation
|
||||
maintains protocol state.
|
||||
|
||||
Norm Receive Object Status Rules
|
||||
====================================
|
||||
|
||||
When a message for a transport object is received from a
|
||||
remote NORM server node, the "status" (based on the object's
|
||||
transport identifier - NormObjectId)of the object is
|
||||
determined so that appropriate actions may be taken by the
|
||||
receiver. The possible status types include:
|
||||
|
||||
INVALID - the NormObjectId is out-of-range with respect
|
||||
to the current state for the sender. Out-of-
|
||||
range is defined as an objectId which is
|
||||
excessively ordinally less than the range of
|
||||
currently pending objects (or last object
|
||||
successfully complete if none are pending)
|
||||
Note that if the object is the _first_ object
|
||||
received for the sender, it is always considered
|
||||
"valid", thus establishing an initial
|
||||
synchronization point for the sender (sync_id):
|
||||
|
||||
sender->Synchronized AND
|
||||
|
||||
objectId < sync_id OR
|
||||
objectId > first_pending + bufferRange
|
||||
(first_pending = sender->IsPending ?
|
||||
first_pending : next_pending)
|
||||
|
||||
NEW - The objectId is greater than the range of
|
||||
currently pending objects (but not too
|
||||
much greater) and acceptable for reception.
|
||||
Note that is the object is the _first_
|
||||
received from the sender, this status
|
||||
always results:
|
||||
|
||||
!sender->Synchronized OR
|
||||
|
||||
objectId >= next_pending AND
|
||||
object_id - first_pending < bufferRange
|
||||
(first_pending = sender->IsPending ?
|
||||
first_pending : next_pending)
|
||||
|
||||
PENDING - The objectId corresponds to an object _within_
|
||||
the range of currently pending objects for
|
||||
the sender and has is marked as still pending:
|
||||
|
||||
sender->Synchronized AND
|
||||
sender->IsPending() AND
|
||||
first_pending <= objectId < next_pending AND
|
||||
sender->IsPending(objectId)
|
||||
|
||||
COMPLETE - The objectId is within range of objects which
|
||||
have been detected and is not marked as pending:
|
||||
|
||||
sender->Synchronized AND
|
||||
sync_id <= objectId < next_pending AND
|
||||
!sender->IsPending(objectId)
|
||||
|
||||
Note since the sequence of objectId's received from a sender
|
||||
is circular, the "sync_id" will eventually need to be
|
||||
updated as the sequence of objects progresses. Also note
|
||||
that the "sync_id" might be adjusted depending upon the
|
||||
receiver synchronisation policy. For example, if the
|
||||
synchronization policy is strict, the "sync_id" will be
|
||||
fixed to no less than the first object the receiver accepts
|
||||
for reception (according to policies) But for a looser
|
||||
policy the receiver might permit the sync_id to be
|
||||
decremented to fit within the current "bufferRange". An
|
||||
even looser policy would be to allow the receiver's buffer
|
||||
range to grow as needed. However, for some applications,
|
||||
the sender has a finite range of objects for which it
|
||||
will maintain repair state.
|
||||
|
||||
The "bufferRange" is the range (sequential count) of objects
|
||||
for which the receiver is maintaining state. That range may
|
||||
be application specific and senders/receivers are anticipated
|
||||
to use relatively compatible buffer ranges/sizes based on
|
||||
application needs.
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
#########################################################################
|
||||
# COMMON MDP MAKEFILE STUFF
|
||||
#
|
||||
|
||||
SHELL=/bin/sh
|
||||
|
||||
.SUFFIXES: .cpp $(.SUFFIXES)
|
||||
|
||||
PROTOLIB = ../protolib
|
||||
COMMON = ../common
|
||||
UNIX = ./
|
||||
NS = ../ns
|
||||
|
||||
INCLUDES = $(TCL_INCL_PATH) $(SYSTEM_INCLUDES) -I$(UNIX) -I$(COMMON) -I$(PROTOLIB)/common
|
||||
|
||||
CFLAGS = -g -DPROTO_DEBUG -DUNIX -Wall -O -fPIC $(SYSTEM_HAVES) $(INCLUDES)
|
||||
|
||||
LDFLAGS = $(SYSTEM_LDFLAGS)
|
||||
|
||||
# Note: Even command line app needs X11 for Netscape post-processing
|
||||
LIBS = $(SYSTEM_LIBS) -lm
|
||||
XLIBS = -lXmu -lXt -lX11
|
||||
|
||||
#NOTE: TK_LIB must come before TCL_LIB for some reason
|
||||
TKLIBS = $(TK_LIB) $(TCL_LIB)
|
||||
|
||||
TCL_SCRIPTS = ${TCL_SCRIPT_PATH}/init.tcl \
|
||||
${TK_SCRIPT_PATH}/tk.tcl \
|
||||
${TK_SCRIPT_PATH}/bgerror.tcl \
|
||||
${TK_SCRIPT_PATH}/button.tcl \
|
||||
${TK_SCRIPT_PATH}/dialog.tcl \
|
||||
${TK_SCRIPT_PATH}/entry.tcl \
|
||||
${TK_SCRIPT_PATH}/focus.tcl \
|
||||
${TK_SCRIPT_PATH}/listbox.tcl \
|
||||
${TK_SCRIPT_PATH}/menu.tcl \
|
||||
${TK_SCRIPT_PATH}/palette.tcl \
|
||||
${TK_SCRIPT_PATH}/scale.tcl \
|
||||
${TK_SCRIPT_PATH}/scrlbar.tcl \
|
||||
${TK_SCRIPT_PATH}/tearoff.tcl \
|
||||
${TK_SCRIPT_PATH}/text.tcl \
|
||||
${TK_SCRIPT_PATH}/optMenu.tcl
|
||||
|
||||
TARGETS = mdp tkMdp
|
||||
|
||||
# Rule for C++ .cpp extension
|
||||
.cpp.o:
|
||||
$(CC) -c $(CFLAGS) -o $*.o $*.cpp
|
||||
|
||||
# MDP depends upon the NRL Protean Group's development library
|
||||
LIBPROTO = $(PROTOLIB)/unix/libProto.a
|
||||
$(PROTOLIB)/unix/libProto.a:
|
||||
make -C $(PROTOLIB)/unix -f Makefile.common libProto.a
|
||||
|
||||
NORM_SRC = $(COMMON)/normMessage.cpp $(COMMON)/normSession.cpp \
|
||||
$(COMMON)/normNode.cpp $(COMMON)/normObject.cpp \
|
||||
$(COMMON)/normSegment.cpp $(COMMON)/normBitmask.cpp \
|
||||
$(COMMON)/normEncoder.cpp $(COMMON)/galois.cpp
|
||||
|
||||
NORM_OBJ = $(NORM_SRC:.cpp=.o)
|
||||
|
||||
LIB_SRC = $(NORM_SRC)
|
||||
LIB_OBJ = $(LIB_SRC:.cpp=.o)
|
||||
|
||||
libNorm.a: $(LIB_OBJ)
|
||||
ar rcv $@ $(LIB_OBJ)
|
||||
ranlib $@
|
||||
|
||||
# (mdp) command-line file broadcaster/receiver
|
||||
APP_SRC = $(COMMON)/normApp.cpp
|
||||
APP_OBJ = $(APP_SRC:.cpp=.o)
|
||||
|
||||
norm: $(APP_OBJ) libNorm.a $(LIBPROTO)
|
||||
$(CC) $(CFLAGS) -o $@ $(APP_OBJ) $(LDFLAGS) $(LIBS) libNorm.a $(LIBPROTO)
|
||||
|
||||
clean:
|
||||
rm -f $(COMMON)/*.o $(UNIX)/*.o $(UNIX)/libNorm.a $(UNIX)/norm;
|
||||
make -C $(PROTOLIB)/unix -f Makefile.common clean
|
||||
|
||||
# DO NOT DELETE THIS LINE -- mkdep uses it.
|
||||
# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
|
||||
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
#
|
||||
# FreeBSD Protean Makefile definitions
|
||||
#
|
||||
|
||||
# TO BUILD THE TK GUI VERSION, EDIT THE FOLLOWING NUMBERED
|
||||
# ITEMS AS NEEDED FOR YOUR SYSTEM
|
||||
# (This has only been tested with TCL/TK 8.0 but it probably
|
||||
# will work with Tcl7.x/Tk4.x with a little tweaking to
|
||||
# the list of TCL_SCRIPTS (library scripts) given below)
|
||||
|
||||
# 1) Where to find the Tcl standard library scripts
|
||||
# (e.g. init.tcl, ...)
|
||||
TCL_SCRIPT_PATH = /usr/local/lib/tcl8.0
|
||||
|
||||
# 2) Where to find the Tk standard library scripts
|
||||
# (e.g. button.tcl, entry.tcl, ...)
|
||||
TK_SCRIPT_PATH = /usr/local/lib/tk8.0
|
||||
|
||||
# 3) Where to find Tcl/Tk header files
|
||||
# (e.g. tcl.h, tk.h, ...)
|
||||
TCL_INCL_PATH = -I/usr/local/include/tcl8.0 -I/usr/local/include/tk8.0
|
||||
|
||||
# 4) Point to specific libtcl.a and libtk.a to use
|
||||
TCL_LIB = /usr/local/lib/libtcl80.a
|
||||
TK_LIB = /usr/local/lib/libtk80.a
|
||||
|
||||
|
||||
# 5) System specific additional libraries, include paths, etc
|
||||
# (Where to find X11 libraries, etc)
|
||||
#
|
||||
SYSTEM_INCLUDES = -I/usr/X11R6/include
|
||||
SYSTEM_LDFLAGS = -L/usr/X11R6/lib
|
||||
SYSTEM_LIBS =
|
||||
|
||||
# 6) System specific capabilities
|
||||
# Must choose appropriate for the following:
|
||||
#
|
||||
# A) -DHAVE_CUSERID (preferred) or -DHAVE_GETLOGIN for cuserid() or getlogin()
|
||||
# functions to obtain user's login name (We may change this to getpwd()
|
||||
# if that is better across different platforms and login environments)
|
||||
#
|
||||
# B) -DHAVE_LOCKF (preferred) or -D_LOCKF for lockf() or flock() file locking
|
||||
# functions to attempt exclusive lock on writing to files
|
||||
#
|
||||
# C) Specify -DHAVE_DIRFD if you system provides the "dirfd()" function
|
||||
# (Most don't have it defined ... but some do)
|
||||
#
|
||||
# D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT()
|
||||
# routine.
|
||||
#
|
||||
# E) The MDP code's use of offset pointers requires special treatment
|
||||
# for some different compilers. Set -DUSE_INHERITANCE for some
|
||||
# to keep some compilers (gcc 2.7.2) happy.
|
||||
#
|
||||
# F) Some systems (SOLARIS/SUNOS) have a few gotchas which require
|
||||
# some #ifdefs to avoid compiler warnings ... so you might need
|
||||
# to specify -DSOLARIS or -DSUNOS depending on your OS.
|
||||
#
|
||||
# G) Uncomment this if you have the NRL IPv6+IPsec software
|
||||
#DNETSEC = -DNETSEC -I/usr/inet6/include
|
||||
#
|
||||
# (We export these for other Makefiles as needed)
|
||||
#
|
||||
|
||||
export SYSTEM_HAVES = -DHAVE_GETLOGIN -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC)
|
||||
|
||||
export CC = gcc
|
||||
|
||||
include Makefile.common
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
#
|
||||
# HPUX Protean Makefile definitions
|
||||
#
|
||||
|
||||
# TO BUILD THE TK GUI VERSION OF MDP EDIT THE FOLLOWING NUMBERED
|
||||
# ITEMS AS NEEDED FOR YOUR SYSTEM
|
||||
# (This has only been tested with TCL/TK 8.0 but it probably
|
||||
# will work with Tcl7.x/Tk4.x with a little tweaking to
|
||||
# the list of TCL_SCRIPTS (library scripts) given below)
|
||||
|
||||
# 1) Where to find the Tcl standard library scripts
|
||||
# (e.g. init.tcl, ...)
|
||||
TCL_SCRIPT_PATH = /opt/tcl-8.0/lib
|
||||
|
||||
# 2) Where to find the Tk standard library scripts
|
||||
# (e.g. button.tcl, entry.tcl, ...)
|
||||
TK_SCRIPT_PATH = /opt/tk-8.0/lib/X11
|
||||
|
||||
# 3) Where to find Tcl/Tk header files
|
||||
# (e.g. tcl.h, tk.h, ...)
|
||||
TCL_INCL_PATH = -I/opt/tcl-8.0/include -I/opt/tk-8.0/include/X11
|
||||
|
||||
# 4) Point to specific libtcl.a and libtk.a to use
|
||||
TCL_LIB = ./hpux-libtcl8.0.a
|
||||
TK_LIB = ./hpux-libtk8.0.a
|
||||
|
||||
# 5) System specific additional libraries, include paths, etc
|
||||
# (Where to find X11 libraries, etc)
|
||||
#
|
||||
SYSTEM_INCLUDES =
|
||||
SYSTEM_LDFLAGS = -Xlinker +b -Xlinker /usr/lib/X11R5:/usr/lib/X11R6:/usr/local/X11R5/lib:/usr/local/X11R6/lib:/usr/lib:/usr/lib/X11R4\
|
||||
-Xlinker +s -L/home/macker/mdp/X11R5/lib
|
||||
SYTSTEM_LIBS =
|
||||
|
||||
# 6) System specific capabilities
|
||||
# Must choose appropriate for the following:
|
||||
#
|
||||
# A) -DHAVE_CUSERID (preferred) or -DHAVE_GETLOGIN for cuserid() or getlogin()
|
||||
# functions to obtain user's login name (We may change this to getpwd()
|
||||
# if that is better across different platforms and login environments)
|
||||
#
|
||||
# B) -DHAVE_LOCKF (preferred) or -D_LOCKF for lockf() or flock() file locking
|
||||
# functions to attempt exclusive lock on writing to files
|
||||
#
|
||||
# C) Specify -DHAVE_DIRFD if you system provides the "dirfd()" function
|
||||
# (Most don't have it defined ... but some do)
|
||||
#
|
||||
# D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT()
|
||||
# routine.
|
||||
#
|
||||
# E) The MDP code's use of offset pointers requires special treatment
|
||||
# for some different compilers. Set -DUSE_INHERITANCE for some
|
||||
# to keep some compilers (gcc 2.7.2) happy.
|
||||
#
|
||||
# F) Some systems (SOLARIS/SUNOS) have a few gotchas which require
|
||||
# some #ifdefs to avoid compiler warnings ... so you might need
|
||||
# to specify -DSOLARIS or -DSUNOS depending on your OS.
|
||||
#
|
||||
# G) Uncomment this if you have the NRL IPv6+IPsec software
|
||||
#DNETSEC = -DNETSEC -I/usr/inet6/include
|
||||
#
|
||||
# (We export these for other Makefiles as needed)
|
||||
#
|
||||
|
||||
export SYSTEM_HAVES = -DHAVE_CUSERID -DHAVE_LOCKF
|
||||
|
||||
export CC = gcc
|
||||
|
||||
include Makefile.common
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
#
|
||||
# Linux Protean Makefile definitions
|
||||
#
|
||||
|
||||
# TO BUILD THE TK GUI VERSION OF MDP EDIT THE FOLLOWING NUMBERED
|
||||
# ITEMS AS NEEDED FOR YOUR SYSTEM
|
||||
# (This has only been tested with TCL/TK 8.0 but it probably
|
||||
# will work with Tcl7.x/Tk4.x with a little tweaking to
|
||||
# the list of TCL_SCRIPTS (library scripts) given below)
|
||||
|
||||
# 1) Where to find the Tcl standard library scripts
|
||||
# (e.g. init.tcl, ...)
|
||||
TCL_SCRIPT_PATH = /usr/local/lib/tcl8.0
|
||||
|
||||
# 2) Where to find the Tk standard library scripts
|
||||
# (e.g. button.tcl, entry.tcl, ...)
|
||||
TK_SCRIPT_PATH = /usr/local/lib/tk8.0
|
||||
|
||||
# 3) Where to find Tcl/Tk header files
|
||||
# (e.g. tcl.h, tk.h, ...)
|
||||
TCL_INCL_PATH = -I/usr/local/include
|
||||
|
||||
# 4) Point to specific libtcl.a and libtk.a to use
|
||||
TCL_LIB = /usr/local/lib/libtcl8.0.a
|
||||
TK_LIB = /usr/local/lib/libtk8.0.a
|
||||
|
||||
|
||||
# 5) System specific additional libraries, include paths, etc
|
||||
# (Where to find X11 libraries, etc)
|
||||
#
|
||||
SYSTEM_INCLUDES = -I/usr/X11R6/include
|
||||
SYSTEM_LDFLAGS = -L/usr/X11R6/lib
|
||||
SYSTEM_LIBS = -ldl
|
||||
|
||||
# 6) System specific capabilities
|
||||
# Must choose appropriate for the following:
|
||||
#
|
||||
# A) -DHAVE_CUSERID (preferred) or -DHAVE_GETLOGIN for cuserid() or getlogin()
|
||||
# functions to obtain user's login name (We may change this to getpwd()
|
||||
# if that is better across different platforms and login environments)
|
||||
#
|
||||
# B) -DHAVE_LOCKF (preferred) or -DHAVE_FLOCK for lockf() or flock() file locking
|
||||
# functions to attempt exclusive lock on writing to files
|
||||
#
|
||||
# C) Specify -DHAVE_DIRFD if your system provides the "dirfd()" function
|
||||
# (Most don't have it defined ... but some do)
|
||||
#
|
||||
# D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT()
|
||||
# routine.
|
||||
#
|
||||
# E) The MDP code's use of offset pointers requires special treatment
|
||||
# for some different compilers. Set -DUSE_INHERITANCE for some
|
||||
# to keep some compilers (gcc 2.7.2) happy.
|
||||
#
|
||||
# F) Some systems (SOLARIS/SUNOS) have a few gotchas which require
|
||||
# some #ifdefs to avoid compiler warnings ... so you might need
|
||||
# to specify -DSOLARIS or -DSUNOS depending on your OS.
|
||||
#
|
||||
# G) Uncomment this if you have the NRL IPv6+IPsec software
|
||||
#DNETSEC = -DNETSEC -I/usr/inet6/include
|
||||
#
|
||||
# (We export these for other Makefiles as needed)
|
||||
#
|
||||
|
||||
export SYSTEM_HAVES = -DLINUX -DHAVE_IPV6 -DHAVE_GETLOGIN -DHAVE_LOCKF \
|
||||
-DHAVE_OLD_SIGNALHANDLER -DHAVE_DIRFD -DHAVE_ASSERT $(NETSEC)
|
||||
|
||||
export CC = gcc
|
||||
|
||||
include Makefile.common
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
#
|
||||
# MacOS X Protean Makefile definitions
|
||||
#
|
||||
|
||||
# TO BUILD THE TK GUI VERSION, EDIT THE FOLLOWING NUMBERED
|
||||
# ITEMS AS NEEDED FOR YOUR SYSTEM
|
||||
# (This has only been tested with TCL/TK 8.0 but it probably
|
||||
# will work with Tcl7.x/Tk4.x with a little tweaking to
|
||||
# the list of TCL_SCRIPTS (library scripts) given below)
|
||||
|
||||
# 1) Where to find the Tcl standard library scripts
|
||||
# (e.g. init.tcl, ...)
|
||||
TCL_SCRIPT_PATH = /usr/local/lib/tcl8.0
|
||||
|
||||
# 2) Where to find the Tk standard library scripts
|
||||
# (e.g. button.tcl, entry.tcl, ...)
|
||||
TK_SCRIPT_PATH = /usr/local/lib/tk8.0
|
||||
|
||||
# 3) Where to find Tcl/Tk header files
|
||||
# (e.g. tcl.h, tk.h, ...)
|
||||
TCL_INCL_PATH = -I/usr/local/include/tcl8.0 -I/usr/local/include/tk8.0
|
||||
|
||||
# 4) Point to specific libtcl.a and libtk.a to use
|
||||
TCL_LIB = /usr/local/lib/libtcl80.a
|
||||
TK_LIB = /usr/local/lib/libtk80.a
|
||||
|
||||
|
||||
# 5) System specific additional libraries, include paths, etc
|
||||
# (Where to find X11 libraries, etc)
|
||||
#
|
||||
SYSTEM_INCLUDES = -I/usr/X11R6/include
|
||||
SYSTEM_LDFLAGS = -L/usr/X11R6/lib
|
||||
SYSTEM_LIBS =
|
||||
|
||||
# 6) System specific capabilities
|
||||
# Must choose appropriate for the following:
|
||||
#
|
||||
# A) -DHAVE_CUSERID (preferred) or -DHAVE_GETLOGIN for cuserid() or getlogin()
|
||||
# functions to obtain user's login name (We may change this to getpwd()
|
||||
# if that is better across different platforms and login environments)
|
||||
#
|
||||
# B) -DHAVE_LOCKF (preferred) or -D_LOCKF for lockf() or flock() file locking
|
||||
# functions to attempt exclusive lock on writing to files
|
||||
#
|
||||
# C) Specify -DHAVE_DIRFD if you system provides the "dirfd()" function
|
||||
# (Most don't have it defined ... but some do)
|
||||
#
|
||||
# D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT()
|
||||
# routine.
|
||||
#
|
||||
# E) The MDP code's use of offset pointers requires special treatment
|
||||
# for some different compilers. Set -DUSE_INHERITANCE for some
|
||||
# to keep some compilers (gcc 2.7.2) happy.
|
||||
#
|
||||
# F) Some systems (SOLARIS/SUNOS) have a few gotchas which require
|
||||
# some #ifdefs to avoid compiler warnings ... so you might need
|
||||
# to specify -DSOLARIS or -DSUNOS depending on your OS.
|
||||
#
|
||||
# G) Uncomment this if you have the NRL IPv6+IPsec software
|
||||
#DNETSEC = -DNETSEC -I/usr/inet6/include
|
||||
#
|
||||
# (We export these for other Makefiles as needed)
|
||||
#
|
||||
|
||||
export SYSTEM_HAVES = -DHAVE_ASSERT -DHAVE_GETLOGIN -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC)
|
||||
|
||||
export CC = cc
|
||||
|
||||
include Makefile.common
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
#
|
||||
# MDPv2 NetBSD Makefile
|
||||
#
|
||||
|
||||
# TO BUILD THE TK GUI VERSION OF MDP EDIT THE FOLLOWING NUMBERED
|
||||
# ITEMS AS NEEDED FOR YOUR SYSTEM
|
||||
# (This has only been tested with TCL/TK 8.0 but it probably
|
||||
# will work with Tcl7.x/Tk4.x with a little tweaking to
|
||||
# the list of TCL_SCRIPTS (library scripts) given below)
|
||||
|
||||
# 1) Where to find the Tcl standard library scripts
|
||||
# (e.g. init.tcl, ...)
|
||||
TCL_SCRIPT_PATH = /usr/local/lib/tcl8.0
|
||||
|
||||
# 2) Where to find the Tk standard library scripts
|
||||
# (e.g. button.tcl, entry.tcl, ...)
|
||||
TK_SCRIPT_PATH = /usr/local/lib/tk8.0
|
||||
|
||||
# 3) Where to find Tcl/Tk header files
|
||||
# (e.g. tcl.h, tk.h, ...)
|
||||
TCL_INCL_PATH = -I/usr/local/include
|
||||
|
||||
# 4) Point to specific libtcl.a and libtk.a to use
|
||||
TCL_LIB = /usr/local/lib/libtcl8.0.a
|
||||
TK_LIB = /usr/local/lib/libtk8.0.a
|
||||
|
||||
|
||||
# 5) System specific additional libraries, include paths, etc
|
||||
# (Where to find X11 libraries, etc)
|
||||
#
|
||||
SYSTEM_INCLUDES = -I/usr/X11R6/include
|
||||
|
||||
SYSTEM_LDFLAGS = -L/usr/X11R6/lib
|
||||
SYSTEM_LIBS = -ldl
|
||||
|
||||
# 6) System specific capabilities
|
||||
# Must choose appropriate for the following:
|
||||
#
|
||||
# A) -DHAVE_CUSERID (preferred) or -DHAVE_GETLOGIN for cuserid() or getlogin()
|
||||
# functions to obtain user's login name (We may change this to getpwd()
|
||||
# if that is better across different platforms and login environments)
|
||||
#
|
||||
# B) -DHAVE_LOCKF (preferred) or -D_LOCKF for lockf() or flock() file locking
|
||||
# functions to attempt exclusive lock on writing to files
|
||||
#
|
||||
# C) Specify -DHAVE_DIRFD if you system provides the "dirfd()" function
|
||||
# (Most don't have it defined ... but some do)
|
||||
#
|
||||
# D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT()
|
||||
# routine.
|
||||
#
|
||||
# E) The MDP code's use of offset pointers requires special treatment
|
||||
# for some different compilers. Set -DUSE_INHERITANCE for some
|
||||
# to keep some compilers (gcc 2.7.2) happy.
|
||||
#
|
||||
# F) Some systems (SOLARIS/SUNOS) have a few gotchas which require
|
||||
# some #ifdefs to avoid compiler warnings ... so you might need
|
||||
# to specify -DSOLARIS or -DSUNOS depending on your OS.
|
||||
#
|
||||
# G) Uncomment this if you have the NRL IPv6+IPsec software
|
||||
#DNETSEC = -DNETSEC -I/usr/inet6/include
|
||||
#
|
||||
# (We export these for other Makefiles as needed)
|
||||
#
|
||||
|
||||
export SYSTEM_HAVES = -DHAVE_CUSERID -DHAVE_LOCKF -DHAVE_DIRFD $(NETSEC)
|
||||
|
||||
export CC = gcc
|
||||
|
||||
include Makefile.common
|
||||
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
#
|
||||
# MDPv2 NetBSD Makefile
|
||||
#
|
||||
|
||||
# TO BUILD THE TK GUI VERSION OF MDP EDIT THE FOLLOWING NUMBERED
|
||||
# ITEMS AS NEEDED FOR YOUR SYSTEM
|
||||
# (This has only been tested with TCL/TK 8.0 but it probably
|
||||
# will work with Tcl7.x/Tk4.x with a little tweaking to
|
||||
# the list of TCL_SCRIPTS (library scripts) given below)
|
||||
|
||||
# 1) Where to find the Tcl standard library scripts
|
||||
# (e.g. init.tcl, ...)
|
||||
TCL_SCRIPT_PATH = /usr/local/lib/tcl8.0
|
||||
|
||||
# 2) Where to find the Tk standard library scripts
|
||||
# (e.g. button.tcl, entry.tcl, ...)
|
||||
TK_SCRIPT_PATH = /usr/local/lib/tk8.0
|
||||
|
||||
# 3) Where to find Tcl/Tk header files
|
||||
# (e.g. tcl.h, tk.h, ...)
|
||||
TCL_INCL_PATH = -I/usr/local/include
|
||||
|
||||
# 4) Point to specific libtcl.a and libtk.a to use
|
||||
TCL_LIB = /usr/local/lib/libtcl80.a
|
||||
TK_LIB = /usr/local/lib/libtk80.a
|
||||
|
||||
|
||||
# 5) System specific additional libraries, include paths, etc
|
||||
# (Where to find X11 libraries, etc)
|
||||
#
|
||||
SYSTEM_INCLUDES = -I/usr/X11R6/include
|
||||
SYSTEM_LDFLAGS = -L/usr/X11R6/lib
|
||||
SYSTEM_LIBS =
|
||||
|
||||
# 6) System specific capabilities
|
||||
# Must choose appropriate for the following:
|
||||
#
|
||||
# A) -DHAVE_CUSERID (preferred) or -DHAVE_GETLOGIN for cuserid() or getlogin()
|
||||
# functions to obtain user's login name (We may change this to getpwd()
|
||||
# if that is better across different platforms and login environments)
|
||||
#
|
||||
# B) -DHAVE_LOCKF (preferred) or -D_LOCKF for lockf() or flock() file locking
|
||||
# functions to attempt exclusive lock on writing to files
|
||||
#
|
||||
# C) Specify -DHAVE_DIRFD if you system provides the "dirfd()" function
|
||||
# (Most don't have it defined ... but some do)
|
||||
#
|
||||
# D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT()
|
||||
# routine.
|
||||
#
|
||||
# E) The MDP code's use of offset pointers requires special treatment
|
||||
# for some different compilers. Set -DUSE_INHERITANCE for some
|
||||
# to keep some compilers (gcc 2.7.2) happy.
|
||||
#
|
||||
# F) Some systems (SOLARIS/SUNOS) have a few gotchas which require
|
||||
# some #ifdefs to avoid compiler warnings ... so you might need
|
||||
# to specify -DSOLARIS or -DSUNOS depending on your OS.
|
||||
#
|
||||
# G) Uncomment this if you have the NRL IPv6+IPsec software
|
||||
#DNETSEC = -DNETSEC -I/usr/inet6/include
|
||||
#
|
||||
# (We export these for other Makefiles as needed)
|
||||
#
|
||||
|
||||
export SYSTEM_HAVES = -DHAVE_GETLOGIN -DHAVE_ASSERT -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC)
|
||||
|
||||
export CC = gcc
|
||||
|
||||
include Makefile.common
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
#
|
||||
# MDPv2 IRIX Makefile
|
||||
#
|
||||
|
||||
# TO BUILD THE TK GUI VERSION OF MDP EDIT THE FOLLOWING NUMBERED
|
||||
# ITEMS AS NEEDED FOR YOUR SYSTEM
|
||||
# (This has only been tested with TCL/TK 8.0 but it probably
|
||||
# will work with Tcl7.x/Tk4.x with a little tweaking to
|
||||
# the list of TCL_SCRIPTS (library scripts) given below)
|
||||
|
||||
# 1) Where to find the Tcl standard library scripts
|
||||
# (e.g. init.tcl, ...)
|
||||
TCL_SCRIPT_PATH = /usr/local/lib/tcl8.0
|
||||
|
||||
# 2) Where to find the Tk standard library scripts
|
||||
# (e.g. button.tcl, entry.tcl, ...)
|
||||
TK_SCRIPT_PATH = /usr/local/lib/tk8.0
|
||||
|
||||
# 3) Where to find Tcl/Tk header files
|
||||
# (e.g. tcl.h, tk.h, ...)
|
||||
TCL_INCL_PATH = -I/usr/local/include
|
||||
|
||||
# 4) Point to specific libtcl.a and libtk.a to use
|
||||
TCL_LIB = /usr/local/lib/libtcl8.0.a
|
||||
TK_LIB = /usr/local/lib/libtk8.0.a
|
||||
|
||||
|
||||
# 5) System specific additional libraries, include paths, etc
|
||||
# (Where to find X11 libraries, etc)
|
||||
#
|
||||
SYSTEM_INCLUDES =
|
||||
SYSTEM_LDFLAGS =
|
||||
SYSTEM_LIBS =
|
||||
|
||||
# 6) System specific capabilities
|
||||
# Must choose appropriate for the following:
|
||||
#
|
||||
# A) -DHAVE_CUSERID (preferred) or -DHAVE_GETLOGIN for cuserid() or getlogin()
|
||||
# functions to obtain user's login name (We may change this to getpwd()
|
||||
# if that is better across different platforms and login environments)
|
||||
#
|
||||
# B) -DHAVE_LOCKF (preferred) or -D_LOCKF for lockf() or flock() file locking
|
||||
# functions to attempt exclusive lock on writing to files
|
||||
#
|
||||
# C) Specify -DHAVE_DIRFD if you system provides the "dirfd()" function
|
||||
# (Most don't have it defined ... but some do)
|
||||
#
|
||||
# D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT()
|
||||
# routine.
|
||||
#
|
||||
# E) The MDP code's use of offset pointers requires special treatment
|
||||
# for some different compilers. Set -DUSE_INHERITANCE for some
|
||||
# to keep some compilers (gcc 2.7.2) happy.
|
||||
#
|
||||
# F) Some systems (SOLARIS/SUNOS) have a few gotchas which require
|
||||
# some #ifdefs to avoid compiler warnings ... so you might need
|
||||
# to specify -DSOLARIS or -DSUNOS depending on your OS.
|
||||
#
|
||||
# G) Uncomment this if you have the NRL IPv6+IPsec software
|
||||
#DNETSEC = -DNETSEC -I/usr/inet6/include
|
||||
#
|
||||
# (We export these for other Makefiles as needed)
|
||||
#
|
||||
|
||||
export SYSTEM_HAVES = -DUSE_INHERITANCE -DHAVE_CUSERID -DHAVE_LOCKF $(NETSEC)
|
||||
|
||||
export CC = gcc
|
||||
|
||||
include Makefile.common
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
#
|
||||
# MDPv2 Solaris Makefile
|
||||
#
|
||||
# TO BUILD THE TK GUI VERSION OF MDP EDIT THE FOLLOWING NUMBERED
|
||||
# ITEMS AS NEEDED FOR YOUR SYSTEM
|
||||
# (This has only been tested with TCL/TK 8.0 but it probably
|
||||
# will work with Tcl7.x/Tk4.x with a little tweaking to
|
||||
# the list of TCL_SCRIPTS (library scripts) given below)
|
||||
|
||||
# 1) Where to find the Tcl standard library scripts
|
||||
# (e.g. init.tcl, ...)
|
||||
TCL_SCRIPT_PATH = /usr/local/lib/tcl8.0
|
||||
|
||||
# 2) Where to find the Tk standard library scripts
|
||||
# (e.g. button.tcl, entry.tcl, ...)
|
||||
TK_SCRIPT_PATH = /usr/local/lib/tk8.0
|
||||
|
||||
# 3) Where to find Tcl/Tk header files
|
||||
# (e.g. tcl.h, tk.h, ...)
|
||||
TCL_INCL_PATH = -I/usr/local/include
|
||||
|
||||
# 4) Point to specific libtcl.a and libtk.a to use
|
||||
TCL_LIB = /usr/local/lib/libtcl8.0.a
|
||||
TK_LIB = /usr/local/lib/libtk8.0.a
|
||||
|
||||
# 5) System specific additional libraries, include paths, etc
|
||||
# (Where to find X11 libraries, etc)
|
||||
#
|
||||
SYSTEM_INCLUDES = -I/usr/openwin/include
|
||||
SYSTEM_LDFLAGS = -L/usr/openwin/lib -R/usr/openwin/lib
|
||||
SYSTEM_LIBS = -ldl -lnsl -lsocket
|
||||
|
||||
# 6) System specific capabilities
|
||||
# Must choose appropriate for the following:
|
||||
#
|
||||
# A) -DHAVE_CUSERID (preferred) or -DHAVE_GETLOGIN for cuserid() or getlogin()
|
||||
# functions to obtain user's login name (We may change this to getpwd()
|
||||
# if that is better across different platforms and login environments)
|
||||
#
|
||||
# B) -DHAVE_LOCKF (preferred) or -D_LOCKF for lockf() or flock() file locking
|
||||
# functions to attempt exclusive lock on writing to files
|
||||
#
|
||||
# C) Specify -DHAVE_DIRFD if you system provides the "dirfd()" function
|
||||
# (Most don't have it defined ... but some do)
|
||||
#
|
||||
# D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT()
|
||||
# routine.
|
||||
#
|
||||
# E) The MDP code's use of offset pointers requires special treatment
|
||||
# for some different compilers. Set -DUSE_INHERITANCE for some
|
||||
# to keep some compilers (gcc 2.7.2) happy.
|
||||
#
|
||||
# F) Some systems (SOLARIS/SUNOS) have a few gotchas which require
|
||||
# some #ifdefs to avoid compiler warnings ... so you might need
|
||||
# to specify -DSOLARIS or -DSUNOS depending on your OS.
|
||||
#
|
||||
# G) Uncomment this if you have the NRL IPv6+IPsec software
|
||||
#DNETSEC = -DNETSEC -I/usr/inet6/include
|
||||
#
|
||||
# (We export these for other Makefiles as needed)
|
||||
#
|
||||
|
||||
export SYSTEM_HAVES = -DHAVE_ASSERT -DHAVE_CUSERID -DHAVE_LOCKF $(NETSEC) -DSOLARIS
|
||||
|
||||
export CC = gcc
|
||||
|
||||
include Makefile.common
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
#
|
||||
# MDPv2 Solaris x86 (Solaris Version 2.7) Makefile
|
||||
#
|
||||
# TO BUILD THE TK GUI VERSION OF MDP EDIT THE FOLLOWING NUMBERED
|
||||
# ITEMS AS NEEDED FOR YOUR SYSTEM
|
||||
# (This has only been tested with TCL/TK 8.0 but it probably
|
||||
# will work with Tcl7.x/Tk4.x with a little tweaking to
|
||||
# the list of TCL_SCRIPTS (library scripts) given below)
|
||||
|
||||
# 1) Where to find the Tcl standard library scripts
|
||||
# (e.g. init.tcl, ...)
|
||||
TCL_SCRIPT_PATH = /usr/local/lib/tcl8.0
|
||||
|
||||
# 2) Where to find the Tk standard library scripts
|
||||
# (e.g. button.tcl, entry.tcl, ...)
|
||||
TK_SCRIPT_PATH = /usr/local/lib/tk8.0
|
||||
|
||||
# 3) Where to find Tcl/Tk header files
|
||||
# (e.g. tcl.h, tk.h, ...)
|
||||
TCL_INCL_PATH = -I/usr/local/include
|
||||
|
||||
# 4) Point to specific libtcl.a and libtk.a to use
|
||||
TCL_LIB = /usr/local/lib/libtcl8.0.a
|
||||
TK_LIB = /usr/local/lib/libtk8.0.a
|
||||
|
||||
# 5) System specific additional libraries, include paths, etc
|
||||
# (Where to find X11 libraries, etc)
|
||||
#
|
||||
SYSTEM_INCLUDES = -I/usr/openwin/include
|
||||
SYSTEM_LDFLAGS = -L/usr/openwin/lib -R/usr/openwin/lib
|
||||
SYSTEM_LIBS = -ldl -lnsl -lsocket
|
||||
|
||||
# 6) System specific capabilities
|
||||
# Must choose appropriate for the following:
|
||||
#
|
||||
# A) -DHAVE_CUSERID (preferred) or -DHAVE_GETLOGIN for cuserid() or getlogin()
|
||||
# functions to obtain user's login name (We may change this to getpwd()
|
||||
# if that is better across different platforms and login environments)
|
||||
#
|
||||
# B) -DHAVE_LOCKF (preferred) or -D_LOCKF for lockf() or flock() file locking
|
||||
# functions to attempt exclusive lock on writing to files
|
||||
#
|
||||
# C) Specify -DHAVE_DIRFD if you system provides the "dirfd()" function
|
||||
# (Most don't have it defined ... but some do)
|
||||
#
|
||||
# D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT()
|
||||
# routine.
|
||||
#
|
||||
# E) The MDP code's use of offset pointers requires special treatment
|
||||
# for some different compilers. Set -DUSE_INHERITANCE for some
|
||||
# to keep some compilers (gcc 2.7.2) happy.
|
||||
#
|
||||
# F) Some systems (SOLARIS/SUNOS) have a few gotchas which require
|
||||
# some #ifdefs to avoid compiler warnings ... so you might need
|
||||
# to specify -DSOLARIS or -DSUNOS depending on your OS.
|
||||
#
|
||||
# G) Uncomment this if you have the NRL IPv6+IPsec software
|
||||
#DNETSEC = -DNETSEC -I/usr/inet6/include
|
||||
#
|
||||
# (We export these for other Makefiles as needed)
|
||||
#
|
||||
|
||||
export SYSTEM_HAVES = -DHAVE_ASSERT -DHAVE_CUSERID -DHAVE_LOCKF $(NETSEC) -DSOLARIS
|
||||
|
||||
export CC = gcc
|
||||
|
||||
include Makefile.common
|
||||
|
||||
Loading…
Reference in New Issue