pull/2/head
Jeff Weston 2019-09-11 11:25:00 -04:00
parent 3456db14f2
commit d0417b042a
40 changed files with 6936 additions and 1996 deletions

View File

@ -35,9 +35,9 @@
namespace Norm namespace Norm
{ {
extern const unsigned char GINV[256]; extern const unsigned char GINV[256];
extern const unsigned char GEXP[512]; extern const unsigned char GEXP[512];
extern const unsigned char GMULT[256][256]; extern const unsigned char GMULT[256][256];
} }
inline unsigned char gexp(unsigned int x) {return Norm::GEXP[x];} inline unsigned char gexp(unsigned int x) {return Norm::GEXP[x];}
inline unsigned char gmult(unsigned int x, unsigned int y) {return Norm::GMULT[x][y];} inline unsigned char gmult(unsigned int x, unsigned int y) {return Norm::GMULT[x][y];}

View File

@ -3,12 +3,12 @@
#include "protoLib.h" #include "protoLib.h"
#include "normSession.h" #include "normSession.h"
#include "normPostProcess.h"
#include <stdio.h> // for stdout/stderr printouts #include <stdio.h> // for stdout/stderr printouts
#include <signal.h> // for SIGTERM/SIGINT handling #include <signal.h> // for SIGTERM/SIGINT handling
#include <errno.h> #include <errno.h>
// Command-line application using Protolib EventDispatcher // Command-line application using Protolib EventDispatcher
class NormApp : public NormController class NormApp : public NormController
{ {
@ -23,7 +23,13 @@ class NormApp : public NormController
bool ProcessCommand(const char* cmd, const char* val); bool ProcessCommand(const char* cmd, const char* val);
bool ParseCommandLine(int argc, char* argv[]); bool ParseCommandLine(int argc, char* argv[]);
static void DoInputReady(EventDispatcher::Descriptor descriptor,
EventDispatcher::EventType theEvent,
const void* userData);
private: private:
void OnInputReady();
enum CmdType {CMD_INVALID, CMD_NOARG, CMD_ARG}; enum CmdType {CMD_INVALID, CMD_NOARG, CMD_ARG};
CmdType CommandType(const char* cmd); CmdType CommandType(const char* cmd);
@ -40,41 +46,62 @@ class NormApp : public NormController
static const char* const cmd_list[]; static const char* const cmd_list[];
static void SignalHandler(int sigNum); static void SignalHandler(int sigNum);
bool IsPostProcessing() {return post_processor.IsActive();}
void HandleSIGCHLD() {post_processor.HandleSIGCHLD();}
EventDispatcher dispatcher; EventDispatcher dispatcher;
NormSessionMgr session_mgr; NormSessionMgr session_mgr;
NormSession* session; NormSession* session;
NormStreamObject* stream; NormStreamObject* tx_stream;
NormStreamObject* rx_stream;
// application parameters // application parameters
FILE* input; // input stream FILE* input; // input stream
FILE* output; // output stream FILE* output; // output stream
char input_buffer[512]; char input_buffer[1250];
unsigned int input_index; unsigned int input_index;
unsigned int input_length; unsigned int input_length;
bool input_active;
bool push_stream;
bool input_messaging; // stream input mode
UINT16 input_msg_length;
UINT16 input_msg_index;
char output_buffer[65536];
UINT16 output_index;
bool output_messaging;
UINT16 output_msg_length;
bool output_msg_sync;
// NormSession parameters // NormSession common parameters
char* address; // session address char* address; // session address
UINT16 port; // session port number UINT16 port; // session port number
UINT8 ttl; UINT8 ttl;
double tx_rate; // bits/sec double tx_rate; // bits/sec
bool cc_enable;
// NormSession server-only parameters
UINT16 segment_size; UINT16 segment_size;
UINT8 ndata; UINT8 ndata;
UINT8 nparity; UINT8 nparity;
UINT8 auto_parity; UINT8 auto_parity;
UINT8 extra_parity;
double backoff_factor;
unsigned long tx_buffer_size; // bytes unsigned long tx_buffer_size; // bytes
unsigned long rx_buffer_size; // bytes
NormFileList tx_file_list; NormFileList tx_file_list;
double tx_object_interval; double tx_object_interval;
int tx_repeat_count; int tx_repeat_count;
double tx_repeat_interval; double tx_repeat_interval;
ProtocolTimer interval_timer;
// NormSession client-only parameters
unsigned long rx_buffer_size; // bytes
NormFileList rx_file_cache; NormFileList rx_file_cache;
char* rx_cache_path; char* rx_cache_path;
NormPostProcessor post_processor;
bool unicast_nacks;
bool silent_client;
ProtocolTimer interval_timer; // Debug parameters
// protocol debug parameters
bool tracing; bool tracing;
double tx_loss; double tx_loss;
double rx_loss; double rx_loss;
@ -82,13 +109,16 @@ class NormApp : public NormController
}; // end class NormApp }; // end class NormApp
NormApp::NormApp() NormApp::NormApp()
: session(NULL), stream(NULL), input(NULL), output(NULL), : session(NULL), tx_stream(NULL), rx_stream(NULL), input(NULL), output(NULL),
input_index(0), input_length(0), input_index(0), input_length(0), input_active(false),
address(NULL), port(0), ttl(3), tx_rate(64000.0), push_stream(false), input_messaging(false), input_msg_length(0), input_msg_index(0),
segment_size(1024), ndata(32), nparity(16), auto_parity(0), output_index(0), output_messaging(false), output_msg_length(0), output_msg_sync(false),
tx_buffer_size(1024*1024), rx_buffer_size(1024*1024), address(NULL), port(0), ttl(3), tx_rate(64000.0), cc_enable(false),
segment_size(1024), ndata(32), nparity(16), auto_parity(0), extra_parity(0),
backoff_factor(NormSession::DEFAULT_BACKOFF_FACTOR),
tx_buffer_size(1024*1024),
tx_object_interval(0.0), tx_repeat_count(0), tx_repeat_interval(0.0), tx_object_interval(0.0), tx_repeat_count(0), tx_repeat_interval(0.0),
rx_cache_path(NULL), rx_buffer_size(1024*1024), rx_cache_path(NULL), unicast_nacks(false), silent_client(false),
tracing(false), tx_loss(0.0), rx_loss(0.0) tracing(false), tx_loss(0.0), rx_loss(0.0)
{ {
// Init tx_timer for 1.0 second interval, infinite repeats // Init tx_timer for 1.0 second interval, infinite repeats
@ -97,6 +127,10 @@ NormApp::NormApp()
this); this);
interval_timer.Init(0.0, 0, (ProtocolTimerOwner*)this, interval_timer.Init(0.0, 0, (ProtocolTimerOwner*)this,
(ProtocolTimeoutFunc)&NormApp::OnIntervalTimeout); (ProtocolTimeoutFunc)&NormApp::OnIntervalTimeout);
struct timeval currentTime;
GetSystemTime(&currentTime);
srand(currentTime.tv_usec);
} }
NormApp::~NormApp() NormApp::~NormApp()
@ -108,27 +142,36 @@ NormApp::~NormApp()
const char* const NormApp::cmd_list[] = const char* const NormApp::cmd_list[] =
{ {
"+debug", "+debug", // debug level
"+log", "+log", // log file name
"-trace", "-trace", // message tracing on
"+txloss", "+txloss", // tx packet loss percent (for testing)
"+rxloss", "+rxloss", // rx packet loss percent (for testing)
"+address", "+address", // session destination address
"+ttl", "+ttl", // multicast hop count scope
"+rate", "+cc", // congestion control on/off
"+input", "+rate", // tx date rate (bps)
"+output", "-push", // push stream writes for real-time messaging
"+sendfile", "+input", // send stream input
"+interval", "+output", // recv stream output
"+repeatcount", "+minput", // send message stream input
"+rinterval", // repeat interval "+moutput", // recv message stream output
"+rxcachedir", "+sendfile", // file/directory list to transmit
"+segment", "+interval", // delay time (sec) between files (0.0 sec default)
"+block", "+repeatcount", // How many times to repeat the file/directory list
"+parity", "+rinterval", // Interval (sec) between file/directory list repeats
"+auto", "+rxcachedir", // recv file cache directory
"+txbuffer", "+segment", // payload segment size (bytes)
"+rxbuffer", "+block", // User data packets per FEC coding block (blockSize)
"+parity", // FEC packets calculated per coding block (nparity)
"+auto", // Number of FEC packets to proactively send (<= nparity)
"+extra", // Number of extra FEC packets sent in response to repair requests
"+backoff", // Backoff factor to use
"+txbuffer", // Size of sender's buffer
"+rxbuffer", // Size receiver allocates for buffering each sender
"-unicastNacks", // unicast instead of multicast feedback messages
"-silentClient", // "silent" (non-nacking) client (EMCON mode)
"+processor", // receive file post processing command
NULL NULL
}; };
@ -236,23 +279,90 @@ bool NormApp::ProcessCommand(const char* cmd, const char* val)
tx_rate = txRate; tx_rate = txRate;
if (session) session->SetTxRate(txRate); if (session) session->SetTxRate(txRate);
} }
else if (!strncmp("cc", cmd, len))
{
if (!strcmp("on", val))
{
cc_enable = true;
}
else if (!strcmp("off", val))
{
cc_enable = false;
}
else
{
DMSG(0, "NormApp::ProcessCommand(cc) invalid option!\n");
return false;
}
if (session) session->SetCongestionControl(cc_enable);
}
else if (!strncmp("input", cmd, len)) else if (!strncmp("input", cmd, len))
{ {
if (!(input = fopen(val, "rb"))) if (!strcmp(val, "STDIN"))
{
input = stdin;
}
else if (!(input = fopen(val, "rb")))
{ {
DMSG(0, "NormApp::ProcessCommand(input) fopen() error: %s\n", DMSG(0, "NormApp::ProcessCommand(input) fopen() error: %s\n",
strerror(errno)); strerror(errno));
return false; return false;
} }
input_index = input_length = 0;
input_messaging = false;
// Set input non-blocking
if(-1 == fcntl(fileno(input), F_SETFL, fcntl(fileno(input), F_GETFL, 0) | O_NONBLOCK))
perror("NormApp::ProcessCommand(input) fcntl(F_SETFL(O_NONBLOCK)) error");
} }
else if (!strncmp("output", cmd, len)) else if (!strncmp("output", cmd, len))
{ {
if (!(output = fopen(val, "wb"))) if (!strcmp(val, "STDOUT"))
{
output = stdout;
}
else if (!(output = fopen(val, "wb")))
{ {
DMSG(0, "NormApp::ProcessCommand(output) fopen() error: %s\n", DMSG(0, "NormApp::ProcessCommand(output) fopen() error: %s\n",
strerror(errno)); strerror(errno));
return false; return false;
} }
output_messaging = false;
output_index = 0;
output_msg_sync = true;
}
else if (!strncmp("minput", cmd, len))
{
if (!strcmp(val, "STDIN"))
{
input = stdin;
}
else if (!(input = fopen(val, "rb")))
{
DMSG(0, "NormApp::ProcessCommand(input) fopen() error: %s\n",
strerror(errno));
return false;
}
input_index = input_length = 0;
input_messaging = true;
// Set input non-blocking
if(-1 == fcntl(fileno(input), F_SETFL, fcntl(fileno(input), F_GETFL, 0) | O_NONBLOCK))
perror("NormApp::ProcessCommand(input) fcntl(F_SETFL(O_NONBLOCK)) error");
}
else if (!strncmp("moutput", cmd, len))
{
if (!strcmp(val, "STDOUT"))
{
output = stdout;
}
else if (!(output = fopen(val, "wb")))
{
DMSG(0, "NormApp::ProcessCommand(output) fopen() error: %s\n",
strerror(errno));
return false;
}
output_messaging = true;
output_msg_length = output_index = 0;
output_msg_sync = false;
} }
else if (!strncmp("sendfile", cmd, len)) else if (!strncmp("sendfile", cmd, len))
{ {
@ -350,6 +460,28 @@ bool NormApp::ProcessCommand(const char* cmd, const char* val)
auto_parity = autoParity; auto_parity = autoParity;
if (session) session->ServerSetAutoParity(autoParity); if (session) session->ServerSetAutoParity(autoParity);
} }
else if (!strncmp("extra", cmd, len))
{
int extraParity = atoi(val);
if ((extraParity < 0) || (extraParity > 254))
{
DMSG(0, "NormApp::ProcessCommand(extra) invalid value!\n");
return false;
}
extra_parity = extraParity;
if (session) session->ServerSetExtraParity(extraParity);
}
else if (!strncmp("backoff", cmd, len))
{
double backoffFactor = atof(val);
if (backoffFactor < 0)
{
DMSG(0, "NormSimAgent::ProcessCommand(backoff) invalid txRate!\n");
return false;
}
backoff_factor = backoffFactor;
if (session) session->SetBackoffFactor(backoffFactor);
}
else if (!strncmp("txbuffer", cmd, len)) else if (!strncmp("txbuffer", cmd, len))
{ {
if (1 != sscanf(val, "%lu", &tx_buffer_size)) if (1 != sscanf(val, "%lu", &tx_buffer_size))
@ -366,6 +498,28 @@ bool NormApp::ProcessCommand(const char* cmd, const char* val)
return false; return false;
} }
} }
else if (!strncmp("unicastNacks", cmd, len))
{
unicast_nacks = true;
if (session) session->SetUnicastNacks(true);
}
else if (!strncmp("silentClient", cmd, len))
{
silent_client = true;
if (session) session->ClientSetSilent(true);
}
else if (!strncmp("push", cmd, len))
{
push_stream = true;
}
else if (!strncmp("processor", cmd, len))
{
if (!post_processor.SetCommand(val))
{
DMSG(0, "NormApp::ProcessCommand(processor) error!\n");
return false;
}
}
return true; return true;
} // end NormApp::ProcessCommand() } // end NormApp::ProcessCommand()
@ -436,6 +590,159 @@ bool NormApp::ParseCommandLine(int argc, char* argv[])
return true; return true;
} // end NormApp::ParseCommandLine() } // end NormApp::ParseCommandLine()
void NormApp::DoInputReady(EventDispatcher::Descriptor /*descriptor*/,
EventDispatcher::EventType /*theEvent*/,
const void* userData)
{
((NormApp*)userData)->OnInputReady();
} // end NormApp::DoDataReady()
void NormApp::OnInputReady()
{
//TRACE("NormApp::OnInputReady() ...\n");
bool flush = false;
// write to the stream while input is available _and_
// the stream has buffer space for input
while (input)
{
if (0 == input_length)
{
// We need input ...
UINT16 readLength;
if (input_messaging)
{
if (input_msg_length)
{
UINT16 bufferSpace = 1024 - input_index;
UINT16 msgRemainder = input_msg_length - input_msg_index;
readLength = MIN(bufferSpace, msgRemainder);
}
else if (input_index < 2)
{
readLength = 2 - input_index;
}
else
{
input_msg_length = ntohs(*((UINT16*)input_buffer));
ASSERT(input_msg_length >= 2);
UINT16 bufferSpace = 1024 - input_index;
UINT16 msgRemainder = input_msg_length - 2;
readLength = MIN(bufferSpace, msgRemainder);
}
}
else
{
readLength = 1024;
}
// Read from "input" into our "input_buffer"
size_t result = fread(input_buffer+input_index, sizeof(char), readLength, input);
if (result > 0)
{
if (input_messaging)
{
if (input_msg_length)
{
input_length = input_index + result;
input_index = 0;
}
else
{
input_length = 0;
input_index += result;
}
}
else
{
input_length = input_index + result;
input_index = 0;
}
}
else
{
if (feof(input))
{
DMSG(0, "norm: input end-of-file.\n");
if (input_active)
{
dispatcher.RemoveGenericInput(fileno(input));
input_active = false;
}
if (stdin != input) fclose(input);
input = NULL;
flush = true;
}
else if (ferror(input))
{
switch (errno)
{
case EINTR:
case EAGAIN:
// Input not ready, will get notification when ready
break;
default:
DMSG(0, "norm: input error:%s\n", strerror(errno));
break;
}
clearerr(input);
}
}
} // end if (0 == input_length)
unsigned int writeLength = input_length;// ? input_length - input_index : 0;
if (writeLength || flush)
{
unsigned int wroteLength = tx_stream->Write(input_buffer+input_index, writeLength, flush, false, push_stream);
input_length -= wroteLength;
if (0 == input_length)
input_index = 0;
else
input_index += wroteLength;
if (input_messaging)
{
input_msg_index += wroteLength;
if (input_msg_index == input_msg_length)
{
input_msg_index = 0;
input_msg_length = 0;
// Mark EOM
tx_stream->Write(NULL, 0, false, true, false);
}
}
if (wroteLength < writeLength)
{
// Stream buffer full, temporarily deactive "input" and
// wait for next TX_QUEUE_EMPTY notification
//TRACE("stream buffer full ...\n");
if (input_active)
{
dispatcher.RemoveGenericInput(fileno(input));
input_active = false;
}
break;
}
}
else
{
// Input not ready, wait for "input" to be ready
// (Activate/reactivate "input" as necessary
//TRACE("input starved ...\n");
if (!input_active)
{
if (dispatcher.AddGenericInput(fileno(input), NormApp::DoInputReady, this))
input_active = true;
else
DMSG(0, "NormApp::Notify(TX_QUEUE_EMPTY) error adding input notification!\n");
}
break;
}
} // end while (1)
} // NormApp::OnInputReady()
void NormApp::Notify(NormController::Event event, void NormApp::Notify(NormController::Event event,
class NormSessionMgr* sessionMgr, class NormSessionMgr* sessionMgr,
class NormSession* session, class NormSession* session,
@ -447,45 +754,14 @@ void NormApp::Notify(NormController::Event event,
case TX_QUEUE_EMPTY: case TX_QUEUE_EMPTY:
// Write to stream as needed // Write to stream as needed
//DMSG(0, "NormApp::Notify(TX_QUEUE_EMPTY) ...\n"); //DMSG(0, "NormApp::Notify(TX_QUEUE_EMPTY) ...\n");
if (object && (object == stream)) if (object && (object == tx_stream))
{ {
bool flush = false; if (input) OnInputReady();
if (input)
{
if (input_index >= input_length)
{
size_t result = fread(input_buffer, sizeof(char), 512, input);
if (result)
{
input_index = 0;
input_length = result;
}
else
{
input_length = input_index = 0;
if (feof(input))
{
DMSG(0, "norm: input end-of-file.\n");
fclose(input);
input = NULL;
flush = true;
}
else if (ferror(input))
{
DMSG(0, "norm: input error:%s\n", strerror(errno));
clearerr(input);
break;
}
}
}
input_index += stream->Write(input_buffer+input_index,
input_length-input_index,
flush);
} // end if (input)
} }
else else
{ {
// Can queue a new object for transmission // Can queue a new object for transmission
if (interval_timer.IsActive()) interval_timer.Deactivate();
if (interval_timer.Interval() > 0.0) if (interval_timer.Interval() > 0.0)
{ {
InstallTimer(&interval_timer); InstallTimer(&interval_timer);
@ -505,8 +781,23 @@ void NormApp::Notify(NormController::Event event,
{ {
case NormObject::STREAM: case NormObject::STREAM:
{ {
const NormObjectSize& size = object->Size(); // Only have one rx_stream at a time for now.
if (!((NormStreamObject*)object)->Accept(size.LSB())) // Reset stream i/o mgmt
output_msg_length = output_index = 0;
if (output_messaging) output_msg_sync = false;
// object Size() has recommended buffering size
NormObjectSize size;
if (silent_client)
size = NormObjectSize(rx_buffer_size);
else
size = object->Size();
if (((NormStreamObject*)object)->Accept(size.LSB()))
{
rx_stream = (NormStreamObject*)object;
}
else
{ {
DMSG(0, "NormApp::Notify(RX_OBJECT_NEW) stream object accept error!\n"); DMSG(0, "NormApp::Notify(RX_OBJECT_NEW) stream object accept error!\n");
} }
@ -544,7 +835,7 @@ void NormApp::Notify(NormController::Event event,
else else
{ {
DMSG(0, "NormApp::Notify(RX_OBJECT_NEW) no rx cache for file\n"); DMSG(0, "NormApp::Notify(RX_OBJECT_NEW) no rx cache for file\n");
} }
} }
break; break;
case NormObject::DATA: case NormObject::DATA:
@ -599,22 +890,95 @@ void NormApp::Notify(NormController::Event event,
switch (object->GetType()) switch (object->GetType())
{ {
case NormObject::FILE: case NormObject::FILE:
// (TBD) update progress // (TBD) update reception progress display when applicable
break; break;
case NormObject::STREAM: case NormObject::STREAM:
{ {
if (object != rx_stream)
{
DMSG(0, "NormApp::Notify(RX_OBJECT_UPDATE) update for invalid stream\n");
break;
}
// Read the stream when it's updated // Read the stream when it's updated
ASSERT(output); ASSERT(output);
char buffer[256]; bool reading = true;
unsigned int nBytes; bool findMsgSync;
while ((nBytes = ((NormStreamObject*)object)->Read(buffer, 256))) while (reading)
{ {
unsigned int put = 0; unsigned int readLength;
while (put < nBytes) if (output_messaging)
{ {
size_t result = fwrite(buffer, sizeof(char), nBytes, output); if (output_msg_length)
fflush(output); {
readLength = output_msg_length - output_index;
}
else if (output_index < 2)
{
readLength = 2 - output_index;
}
else
{
output_msg_length = ntohs(*((UINT16*)output_buffer));
ASSERT(output_msg_length >= 2);
readLength = output_msg_length - output_index;
}
findMsgSync = output_msg_sync ? false : true;
}
else
{
output_index = 0;
readLength = 512;
findMsgSync = false;
}
if(!((NormStreamObject*)object)->Read(output_buffer+output_index,
&readLength, findMsgSync))
{
// The stream broke
if (output_messaging)
{
if (output_msg_sync)
DMSG(0, "NormApp::Notify() detected broken stream ...\n");
output_msg_length = output_index = 0;
output_msg_sync = false;
continue;
}
}
else
{
output_msg_sync = true;
}
if (readLength)
output_index += readLength;
else
reading = false;
unsigned int writeLength;
if (output_messaging)
{
if (output_msg_length && (output_index >= output_msg_length))
{
writeLength = output_msg_length;
output_msg_length = 0;
output_index = 0;
}
else
{
writeLength = 0;
}
}
else
{
writeLength = readLength;
output_index = 0;
}
unsigned int put = 0;
while (put < writeLength)
{
size_t result = fwrite(output_buffer+put, sizeof(char), writeLength-put, output);
if (result) if (result)
{ {
put += result; put += result;
@ -637,22 +1001,35 @@ void NormApp::Notify(NormController::Event event,
} }
} }
} // end while(put < nBytes) } // end while(put < nBytes)
} if (writeLength) memset(output_buffer, 0, writeLength);
} // end while (reading)
fflush(output);
break; break;
} }
case NormObject::DATA: case NormObject::DATA:
DMSG(0, "NormApp::Notify() FILE/DATA objects not _yet_ supported...\n"); DMSG(0, "NormApp::Notify() DATA objects not _yet_ supported...\n");
break; break;
} // end switch (object->GetType()) } // end switch (object->GetType())
break; break;
case RX_OBJECT_COMPLETE: case RX_OBJECT_COMPLETE:
{ {
switch(object->GetType()) switch(object->GetType())
{ {
case NormObject::FILE: case NormObject::FILE:
DMSG(0, "norm: Completed rx file: %s\n", ((NormFileObject*)object)->Path()); {
const char* filePath = ((NormFileObject*)object)->Path();
//DMSG(0, "norm: Completed rx file: %s\n", filePath);
if (post_processor.IsEnabled())
{
if (!post_processor.ProcessFile(filePath))
{
DMSG(0, "norm: post processing error\n");
}
}
break; break;
}
case NormObject::STREAM: case NormObject::STREAM:
ASSERT(0); ASSERT(0);
@ -694,12 +1071,15 @@ bool NormApp::OnIntervalTimeout()
temp[len] = '\0'; temp[len] = '\0';
if (!session->QueueTxFile(fileName, fileNameInfo, len)) if (!session->QueueTxFile(fileName, fileNameInfo, len))
{ {
DMSG(0, "NormApp::OnIntervalTimeout() Error opening tx file: %s\n", DMSG(0, "NormApp::OnIntervalTimeout() Error queuing tx file: %s\n",
fileName); fileName);
// Try the next file in the list // Wait a second, then try the next file in the list
return OnIntervalTimeout(); if (interval_timer.IsActive()) interval_timer.Deactivate();
interval_timer.SetInterval(1.0);
InstallTimer(&interval_timer);
return false;
} }
DMSG(0, "norm: File \"%s\" queued for transmission.\n", fileName); //DMSG(0, "norm: File \"%s\" queued for transmission.\n", fileName);
interval_timer.SetInterval(tx_object_interval); interval_timer.SetInterval(tx_object_interval);
} }
else if (tx_repeat_count) else if (tx_repeat_count)
@ -738,17 +1118,18 @@ bool NormApp::OnStartup()
signal(SIGTERM, SignalHandler); signal(SIGTERM, SignalHandler);
signal(SIGINT, SignalHandler); signal(SIGINT, SignalHandler);
signal(SIGCHLD, SignalHandler);
// Validate our application settings // Validate our application settings
if (!address) if (!address)
{ {
DMSG(0, "NormApp::OnStartup() Error! no session address given."); DMSG(0, "NormApp::OnStartup() Error! no session address given.\n");
return false; return false;
} }
if (!input && !output && tx_file_list.IsEmpty() && !rx_cache_path) if (!input && !output && tx_file_list.IsEmpty() && !rx_cache_path)
{ {
DMSG(0, "NormApp::OnStartup() Error! no \"input\", \"output\", " DMSG(0, "NormApp::OnStartup() Error! no \"input\", \"output\", "
"\"sendfile\", or \"rxcache\" given."); "\"sendfile\", or \"rxcache\" given.\n");
return false; return false;
} }
@ -761,10 +1142,14 @@ bool NormApp::OnStartup()
session->SetTrace(tracing); session->SetTrace(tracing);
session->SetTxLoss(tx_loss); session->SetTxLoss(tx_loss);
session->SetRxLoss(rx_loss); session->SetRxLoss(rx_loss);
session->SetBackoffFactor(backoff_factor);
if (input || !tx_file_list.IsEmpty()) if (input || !tx_file_list.IsEmpty())
{ {
// StartServer(bufferMax, segmentSize, fec_ndata, fec_nparity) NormObjectId baseId = (unsigned short)(rand() * (65535.0/ (double)RAND_MAX));
session->ServerSetBaseObjectId(baseId);
session->SetCongestionControl(cc_enable);
if (!session->StartServer(tx_buffer_size, segment_size, ndata, nparity)) if (!session->StartServer(tx_buffer_size, segment_size, ndata, nparity))
{ {
DMSG(0, "NormApp::OnStartup() start server error!\n"); DMSG(0, "NormApp::OnStartup() start server error!\n");
@ -772,12 +1157,12 @@ bool NormApp::OnStartup()
return false; return false;
} }
session->ServerSetAutoParity(auto_parity); session->ServerSetAutoParity(auto_parity);
session->ServerSetExtraParity(extra_parity);
if (input) if (input)
{ {
// Open a stream object to write to (QueueTxStream(stream bufferSize)) // Open a stream object to write to (QueueTxStream(stream bufferSize))
stream = session->QueueTxStream(tx_buffer_size); tx_stream = session->QueueTxStream(tx_buffer_size);
if (!stream) if (!tx_stream)
{ {
DMSG(0, "NormApp::OnStartup() queue tx stream error!\n"); DMSG(0, "NormApp::OnStartup() queue tx stream error!\n");
session_mgr.Destroy(); session_mgr.Destroy();
@ -788,8 +1173,9 @@ bool NormApp::OnStartup()
if (output || rx_cache_path) if (output || rx_cache_path)
{ {
TRACE("starting client ...\n");
// StartClient(bufferMax (per-sender)) // StartClient(bufferMax (per-sender))
session->SetUnicastNacks(unicast_nacks);
session->ClientSetSilent(silent_client);
if (!session->StartClient(rx_buffer_size)) if (!session->StartClient(rx_buffer_size))
{ {
DMSG(0, "NormApp::OnStartup() start client error!\n"); DMSG(0, "NormApp::OnStartup() start client error!\n");
@ -808,11 +1194,23 @@ bool NormApp::OnStartup()
void NormApp::OnShutdown() void NormApp::OnShutdown()
{ {
//TRACE("NormApp::OnShutdown() ...\n");
session_mgr.Destroy(); session_mgr.Destroy();
if (input) fclose(input); if (input)
input = NULL; {
if (output) fclose(output); if (input_active)
output = NULL; {
dispatcher.RemoveGenericInput(fileno(input));
input_active = false;
}
if (stdin != input) fclose(input);
input = NULL;
}
if (output)
{
if (stdout != output) fclose(output);
output = NULL;
}
} // end NormApp::OnShutdown() } // end NormApp::OnShutdown()
@ -859,7 +1257,7 @@ int main(int argc, char* argv[])
{ {
if (theApp.OnStartup()) if (theApp.OnStartup())
{ {
exitCode = theApp.MainLoop(); exitCode = theApp.MainLoop();
theApp.OnShutdown(); theApp.OnShutdown();
fprintf(stderr, "norm: Done.\n"); fprintf(stderr, "norm: Done.\n");
} }
@ -886,6 +1284,8 @@ int main(int argc, char* argv[])
return exitCode; // exitCode contains "signum" causing exit return exitCode; // exitCode contains "signum" causing exit
} // end main(); } // end main();
void NormApp::SignalHandler(int sigNum) void NormApp::SignalHandler(int sigNum)
{ {
switch(sigNum) switch(sigNum)
@ -895,6 +1295,11 @@ void NormApp::SignalHandler(int sigNum)
theApp.Stop(sigNum); // causes theApp's main loop to exit theApp.Stop(sigNum); // causes theApp's main loop to exit
break; break;
case SIGCHLD:
if (theApp.IsPostProcessing()) theApp.HandleSIGCHLD();
signal(SIGCHLD, SignalHandler);
break;
default: default:
fprintf(stderr, "norm: Unexpected signal: %d\n", sigNum); fprintf(stderr, "norm: Unexpected signal: %d\n", sigNum);
break; break;

View File

@ -3,6 +3,7 @@
#include "debug.h" #include "debug.h"
#include "sysdefs.h" #include "sysdefs.h"
// Hamming weights for given one-byte bit masks // Hamming weights for given one-byte bit masks
static unsigned char WEIGHT[256] = static unsigned char WEIGHT[256] =
{ {
@ -191,7 +192,7 @@ void NormBitmask::Destroy()
{ {
if (mask) if (mask)
{ {
delete []mask; delete[] mask;
mask = (unsigned char*)NULL; mask = (unsigned char*)NULL;
num_bits = first_set = 0; num_bits = first_set = 0;
} }
@ -425,7 +426,7 @@ void NormBitmask::Display(FILE* stream)
if (0x07 == (i & 0x07)) fprintf(stream, " "); if (0x07 == (i & 0x07)) fprintf(stream, " ");
if (0x3f == (i & 0x3f)) fprintf(stream, "\n"); if (0x3f == (i & 0x3f)) fprintf(stream, "\n");
} }
} // end NormSlidingMask::NormBitmask() } // end NormBitmask::Display()
@ -433,7 +434,7 @@ void NormBitmask::Display(FILE* stream)
NormSlidingMask::NormSlidingMask() NormSlidingMask::NormSlidingMask()
: mask((unsigned char*)0), mask_len(0), num_bits(0), : mask((unsigned char*)NULL), mask_len(0), num_bits(0),
start(0), end(0), offset(0) start(0), end(0), offset(0)
{ {
} }
@ -446,6 +447,7 @@ NormSlidingMask::~NormSlidingMask()
bool NormSlidingMask::Init(long numBits) bool NormSlidingMask::Init(long numBits)
{ {
if (mask) Destroy(); if (mask) Destroy();
if (numBits <= 0) return false; if (numBits <= 0) return false;
unsigned long len = (numBits + 7) >> 3; unsigned long len = (numBits + 7) >> 3;
@ -519,6 +521,7 @@ bool NormSlidingMask::CanSet(unsigned long index) const
bool NormSlidingMask::Set(unsigned long index) bool NormSlidingMask::Set(unsigned long index)
{ {
ASSERT(CanSet(index));
if (IsSet()) if (IsSet())
{ {
// Determine position with respect to current start // Determine position with respect to current start
@ -571,6 +574,8 @@ bool NormSlidingMask::Set(unsigned long index)
if ((pos > end) || (pos < start)) end = pos; if ((pos > end) || (pos < start)) end = pos;
} }
} }
ASSERT((pos >> 3) >= 0);
ASSERT((pos >> 3) < (long)mask_len);
mask[(pos >> 3)] |= (0x80 >> (pos & 0x07)); mask[(pos >> 3)] |= (0x80 >> (pos & 0x07));
} }
else else
@ -584,6 +589,7 @@ bool NormSlidingMask::Set(unsigned long index)
bool NormSlidingMask::Unset(unsigned long index) bool NormSlidingMask::Unset(unsigned long index)
{ {
//ASSERT(CanSet(index));
if (IsSet()) if (IsSet())
{ {
long pos = index - offset; long pos = index - offset;
@ -602,6 +608,8 @@ bool NormSlidingMask::Unset(unsigned long index)
if ((pos < start) || (pos > end)) return true; if ((pos < start) || (pos > end)) return true;
} }
// Unset the corresponding bit // Unset the corresponding bit
ASSERT((pos >> 3) >= 0);
ASSERT((pos >> 3) < (long)mask_len);
mask[(pos >> 3)] &= ~(0x80 >> (pos & 0x07)); mask[(pos >> 3)] &= ~(0x80 >> (pos & 0x07));
if (start == end) if (start == end)
{ {
@ -640,6 +648,8 @@ bool NormSlidingMask::Unset(unsigned long index)
bool NormSlidingMask::SetBits(unsigned long index, long count) bool NormSlidingMask::SetBits(unsigned long index, long count)
{ {
ASSERT(CanSet(index));
ASSERT(CanSet(index+count-1));
if (count < 0) return false; if (count < 0) return false;
if (0 == count) return true; if (0 == count) return true;
long firstPos, lastPos; long firstPos, lastPos;
@ -691,19 +701,28 @@ bool NormSlidingMask::SetBits(unsigned long index, long count)
long maskIndex = firstPos >> 3; long maskIndex = firstPos >> 3;
int bitIndex = firstPos & 0x07; int bitIndex = firstPos & 0x07;
int bitRemainder = 8 - bitIndex; int bitRemainder = 8 - bitIndex;
ASSERT(maskIndex >= 0);
if (count <= bitRemainder) if (count <= bitRemainder)
{ {
ASSERT(maskIndex < (long)mask_len);
mask[maskIndex] |= (0x00ff >> bitIndex) & mask[maskIndex] |= (0x00ff >> bitIndex) &
(0x00ff << (bitRemainder - count)); (0x00ff << (bitRemainder - count));
} }
else else
{ {
ASSERT(maskIndex < (long)mask_len);
mask[maskIndex] |= 0x00ff >> bitIndex; mask[maskIndex] |= 0x00ff >> bitIndex;
count -= bitRemainder; count -= bitRemainder;
unsigned long nbytes = count >> 3; long nbytes = count >> 3;
ASSERT((maskIndex+1+nbytes) <= (long)mask_len);
memset(&mask[++maskIndex], 0xff, nbytes); memset(&mask[++maskIndex], 0xff, nbytes);
count &= 0x07; count &= 0x07;
if (count) mask[maskIndex+nbytes] |= 0xff << (8-count); if (count)
{
ASSERT((maskIndex+nbytes) >= 0);
ASSERT((maskIndex+nbytes) < (long)mask_len);
mask[maskIndex+nbytes] |= 0xff << (8-count);
}
} }
firstPos = 0; firstPos = 0;
} }
@ -720,25 +739,36 @@ bool NormSlidingMask::SetBits(unsigned long index, long count)
long maskIndex = firstPos >> 3; long maskIndex = firstPos >> 3;
int bitIndex = firstPos & 0x07; int bitIndex = firstPos & 0x07;
int bitRemainder = 8 - bitIndex; int bitRemainder = 8 - bitIndex;
ASSERT(maskIndex >= 0);
if (count <= bitRemainder) if (count <= bitRemainder)
{ {
ASSERT(maskIndex < (long)mask_len);
mask[maskIndex] |= (0x00ff >> bitIndex) & mask[maskIndex] |= (0x00ff >> bitIndex) &
(0x00ff << (bitRemainder - count)); (0x00ff << (bitRemainder - count));
} }
else else
{ {
ASSERT(maskIndex < (long)mask_len);
mask[maskIndex] |= 0x00ff >> bitIndex; mask[maskIndex] |= 0x00ff >> bitIndex;
count -= bitRemainder; count -= bitRemainder;
unsigned long nbytes = count >> 3; long nbytes = count >> 3;
ASSERT((maskIndex+1+nbytes) <= (long)mask_len);
memset(&mask[++maskIndex], 0xff, nbytes); memset(&mask[++maskIndex], 0xff, nbytes);
count &= 0x07; count &= 0x07;
if (count) mask[maskIndex+nbytes] |= 0xff << (8-count); if (count)
{
ASSERT((maskIndex+nbytes) >= 0);
ASSERT((maskIndex+nbytes) < (long)mask_len);
mask[maskIndex+nbytes] |= 0xff << (8-count);
}
} }
return true; return true;
} // end NormSlidingMask::SetBits() } // end NormSlidingMask::SetBits()
bool NormSlidingMask::UnsetBits(unsigned long index, long count) bool NormSlidingMask::UnsetBits(unsigned long index, long count)
{ {
//ASSERT(CanSet(index));
//ASSERT(CanSet(index+count-1));
if (IsSet()) if (IsSet())
{ {
// Trim to fit as needed. // Trim to fit as needed.
@ -782,17 +812,24 @@ bool NormSlidingMask::UnsetBits(unsigned long index, long count)
int bitRemainder = 8 - bitIndex; int bitRemainder = 8 - bitIndex;
if (count <= bitRemainder) if (count <= bitRemainder)
{ {
ASSERT(maskIndex < (long)mask_len);
mask[maskIndex] &= (0x00ff << bitRemainder) | mask[maskIndex] &= (0x00ff << bitRemainder) |
(0x00ff >> (bitIndex + count)); (0x00ff >> (bitIndex + count));
} }
else else
{ {
ASSERT(maskIndex < (long)mask_len);
mask[maskIndex] &= 0x00ff << bitRemainder; mask[maskIndex] &= 0x00ff << bitRemainder;
count -= bitRemainder; count -= bitRemainder;
unsigned long nbytes = count >> 3; unsigned long nbytes = count >> 3;
ASSERT((maskIndex+1+nbytes) <= mask_len);
memset(&mask[++maskIndex], 0, nbytes); memset(&mask[++maskIndex], 0, nbytes);
count &= 0x07; count &= 0x07;
if (count) mask[maskIndex+nbytes] &= 0xff >> count; if (count)
{
ASSERT((maskIndex+nbytes) < mask_len);
mask[maskIndex+nbytes] &= 0xff >> count;
}
} }
startPos = 0; startPos = 0;
} }
@ -807,17 +844,24 @@ bool NormSlidingMask::UnsetBits(unsigned long index, long count)
int bitRemainder = 8 - bitIndex; int bitRemainder = 8 - bitIndex;
if (count <= bitRemainder) if (count <= bitRemainder)
{ {
ASSERT(maskIndex < (long)mask_len);
mask[maskIndex] &= (0x00ff << bitRemainder) | mask[maskIndex] &= (0x00ff << bitRemainder) |
(0x00ff >> (bitIndex + count)); (0x00ff >> (bitIndex + count));
} }
else else
{ {
ASSERT(maskIndex < (long)mask_len);
mask[maskIndex] &= 0x00ff << bitRemainder; mask[maskIndex] &= 0x00ff << bitRemainder;
count -= bitRemainder; count -= bitRemainder;
unsigned long nbytes = count >> 3; unsigned long nbytes = count >> 3;
ASSERT((maskIndex+1+nbytes) <= mask_len);
memset(&mask[++maskIndex], 0, nbytes); memset(&mask[++maskIndex], 0, nbytes);
count &= 0x07; count &= 0x07;
if (count) mask[maskIndex+nbytes] &= 0xff >> count; if (count)
{
ASSERT((maskIndex+nbytes) < mask_len);
mask[maskIndex+nbytes] &= 0xff >> count;
}
} }
// Calling these will update the start/end state // Calling these will update the start/end state
if (start == firstPos) if (start == firstPos)
@ -1078,8 +1122,11 @@ bool NormSlidingMask::Copy(const NormSlidingMask& b)
long endIndex = b.end >> 3; long endIndex = b.end >> 3;
if (b.end < b.start) if (b.end < b.start)
{ {
ASSERT((b.mask_len - startIndex) <= mask_len);
memcpy(mask, b.mask+startIndex, b.mask_len - startIndex); memcpy(mask, b.mask+startIndex, b.mask_len - startIndex);
memcpy(mask+b.mask_len-startIndex, b.mask, endIndex+1); ASSERT((b.mask_len - startIndex + endIndex) <= mask_len);
//memcpy(mask+b.mask_len-startIndex, b.mask, endIndex+1); // old
memcpy(mask+b.mask_len-startIndex, b.mask, endIndex); // new
// Clear any possible start/end overlap // Clear any possible start/end overlap
if (mask_len > b.mask_len) if (mask_len > b.mask_len)
{ {
@ -1087,11 +1134,15 @@ bool NormSlidingMask::Copy(const NormSlidingMask& b)
if (remainder) mask[0] &= 0xff >> remainder; if (remainder) mask[0] &= 0xff >> remainder;
remainder = end & 0x7; remainder = end & 0x7;
if (remainder) if (remainder)
{
ASSERT((startIndex+endIndex) < (long)mask_len);
mask[startIndex+endIndex] &= 0xff << (8 - remainder); mask[startIndex+endIndex] &= 0xff << (8 - remainder);
}
} }
} }
else else
{ {
ASSERT((endIndex-startIndex+1) <= (long)mask_len);
memcpy(mask, b.mask+startIndex, endIndex-startIndex+1); memcpy(mask, b.mask+startIndex, endIndex-startIndex+1);
} }
return true; return true;

View File

@ -117,6 +117,8 @@ class NormSlidingMask
NormSlidingMask(); NormSlidingMask();
~NormSlidingMask(); ~NormSlidingMask();
const char* GetMask() const {return (const char*)mask;}
bool Init(long numBits); bool Init(long numBits);
void Destroy(); void Destroy();
long Size() const {return num_bits;} long Size() const {return num_bits;}
@ -181,6 +183,7 @@ class NormSlidingMask
long start; long start;
long end; long end;
unsigned long offset; unsigned long offset;
unsigned char* mask2;
}; // end class NormSlidingMask }; // end class NormSlidingMask
#endif // _NORM_BITMASK_ #endif // _NORM_BITMASK_

View File

@ -39,8 +39,12 @@
#include "galois.h" // for Galois math routines #include "galois.h" // for Galois math routines
#include "debug.h" #include "debug.h"
#ifdef SIMULATE
#include "normMessage.h"
#endif // SIMULATE
NormEncoder::NormEncoder() NormEncoder::NormEncoder()
: npar(0), vecSize(0), : npar(0), vector_size(0),
genPoly(NULL), scratch(NULL) genPoly(NULL), scratch(NULL)
{ {
@ -58,7 +62,7 @@ bool NormEncoder::Init(int numParity, int vecSizeMax)
ASSERT(vecSizeMax >= 0); ASSERT(vecSizeMax >= 0);
if (genPoly) Destroy(); if (genPoly) Destroy();
npar = numParity; npar = numParity;
vecSize = vecSizeMax; vector_size = vecSizeMax;
// Create generator polynomial // Create generator polynomial
if(!CreateGeneratorPolynomial()) if(!CreateGeneratorPolynomial())
{ {
@ -166,11 +170,6 @@ bool NormEncoder::CreateGeneratorPolynomial()
// Parity data is written to list of parity vectors supplied by caller // Parity data is written to list of parity vectors supplied by caller
void NormEncoder::Encode(const char *data, char **pVec) void NormEncoder::Encode(const char *data, char **pVec)
{ {
#if defined(NS2) || defined(OPNET)
return; // lobotomize FEC for faster simulations
#endif
int i, j; int i, j;
unsigned char *userData, *LSFR1, *LSFR2, *pVec0; unsigned char *userData, *LSFR1, *LSFR2, *pVec0;
int npar_minus_one = npar - 1; int npar_minus_one = npar - 1;
@ -178,6 +177,14 @@ void NormEncoder::Encode(const char *data, char **pVec)
ASSERT(scratch); // Make sure it's been init'd first ASSERT(scratch); // Make sure it's been init'd first
// Assumes parity vectors are zero-filled at block start !!! // Assumes parity vectors are zero-filled at block start !!!
// Copy pVec[0] for use in calculations // Copy pVec[0] for use in calculations
#ifdef SIMULATE
UINT16 vecSize = MIN(SIM_PAYLOAD_MAX, vector_size);
vecSize = MAX(vecSize, NormDataMsg::PayloadHeaderLength());
#else
UINT16 vecSize = vector_size;
#endif // if/else SIMULATE
memcpy(scratch, pVec[0], vecSize); memcpy(scratch, pVec[0], vecSize);
if (npar > 1) if (npar > 1)
{ {
@ -322,17 +329,20 @@ int NormDecoder::Decode(char** dVec, int ndata, UINT16 erasureCount, UINT16* era
ASSERT(Lambda); ASSERT(Lambda);
ASSERT(erasureCount && (erasureCount<=npar)); ASSERT(erasureCount && (erasureCount<=npar));
#if defined(NS2) || defined (OPNET)
return erasureCount; // lobotomize FEC for faster simulations
#endif
// (A) Compute syndrome vectors // (A) Compute syndrome vectors
// First zero out erasure vectors (MDP provides zero-filled vecs) // First zero out erasure vectors (MDP provides zero-filled vecs)
// Then calculate syndrome (based on zero value erasures) // Then calculate syndrome (based on zero value erasures)
int nvecs = npar + ndata; int nvecs = npar + ndata;
#ifdef SIMULATE
int vecSize = MIN(SIM_PAYLOAD_MAX, vector_size);
vecSize = MAX(NormDataMsg::PayloadHeaderLength(), vecSize);
#else
int vecSize = vector_size; int vecSize = vector_size;
#endif // if/else SIMUATE
for (int i = 0; i < npar; i++) for (int i = 0; i < npar; i++)
{ {
int X = gexp(i+1); int X = gexp(i+1);
@ -382,7 +392,7 @@ int NormDecoder::Decode(char** dVec, int ndata, UINT16 erasureCount, UINT16* era
for (int i = 0; i < erasureCount; i++) for (int i = 0; i < erasureCount; i++)
{ {
// Only fill _data_ erasures // Only fill _data_ erasures
if (erasureLocs[i] >= ndata) return erasureCount; if (erasureLocs[i] >= ndata) break;//return erasureCount;
// evaluate Lambda' (derivative) at alpha^(-i) // evaluate Lambda' (derivative) at alpha^(-i)
// ( all odd powers disappear) // ( all odd powers disappear)
@ -413,6 +423,7 @@ int NormDecoder::Decode(char** dVec, int ndata, UINT16 erasureCount, UINT16* era
data++; data++;
} }
} }
return erasureCount; return erasureCount;
} // end NormDecoder::Decode() } // end NormDecoder::Decode()

View File

@ -39,10 +39,10 @@ class NormEncoder
{ {
// Members // Members
private: private:
int npar; // No. of parity packets (N-k) int npar; // No. of parity packets (N-k)
int vecSize; // Size of biggest vector to encode int vector_size; // Size of biggest vector to encode
unsigned char* genPoly; // Ptr to generator polynomial unsigned char* genPoly; // Ptr to generator polynomial
unsigned char* scratch; // scratch space for encoding unsigned char* scratch; // scratch space for encoding
// Methods // Methods
public: public:
@ -53,7 +53,7 @@ class NormEncoder
bool IsReady(){return (bool)(genPoly != NULL);} bool IsReady(){return (bool)(genPoly != NULL);}
void Encode(const char *dataVector, char **parityVectorList); void Encode(const char *dataVector, char **parityVectorList);
int NumParity() {return npar;} int NumParity() {return npar;}
int VectorSize() {return vecSize;} int VectorSize() {return vector_size;}
private: private:
bool CreateGeneratorPolynomial(); bool CreateGeneratorPolynomial();

View File

@ -121,15 +121,18 @@ bool NormFile::Lock()
{ {
#ifndef WIN32 // WIN32 files are automatically locked #ifndef WIN32 // WIN32 files are automatically locked
fchmod(fd, 0640 | S_ISGID); fchmod(fd, 0640 | S_ISGID);
#ifdef HAVE_FLOCK #ifdef HAVE_FLOCK
if (flock(fd, LOCK_EX | LOCK_NB)) if (flock(fd, LOCK_EX | LOCK_NB))
#else
//#ifdef HAVE_LOCKF
if (lockf(fd, F_LOCK, 0)) // assume lockf if not flock
//#endif // HAVE_LOCKF
#endif // if/else HAVE_FLOCK
return false; return false;
else else
#else
#ifdef HAVE_LOCKF
if (lockf(fd, F_LOCK, 0)) // assume lockf if not flock
return false;
else
#endif // HAVE_LOCKF
#endif // if/else HAVE_FLOCK
#endif // !WIN32 #endif // !WIN32
return true; return true;
} // end NormFile::Lock() } // end NormFile::Lock()
@ -143,7 +146,7 @@ void NormFile::Unlock()
#ifdef HAVE_LOCKF #ifdef HAVE_LOCKF
lockf(fd, F_ULOCK, 0); lockf(fd, F_ULOCK, 0);
#endif // HAVE_LOCKF #endif // HAVE_LOCKF
#endif // HAVE_FLOCK #endif // if/elseHAVE_FLOCK
fchmod(fd, 0640); fchmod(fd, 0640);
#endif // !WIN32 #endif // !WIN32
} // end NormFile::UnLock() } // end NormFile::UnLock()

View File

@ -1,5 +1,136 @@
#include "normMessage.h" #include "normMessage.h"
NormHeaderExtension::NormHeaderExtension()
: buffer(NULL)
{
}
NormMsg::NormMsg()
: length(8), header_length(8), header_length_base(8)
{
SetType(INVALID);
SetVersion(NORM_PROTOCOL_VERSION);
}
bool NormMsg::InitFromBuffer(UINT16 msgLength)
{
header_length = GetHeaderLength();
// "header_length_base" is type dependent
switch (GetType())
{
// for INFO, DATA, and
case INFO:
header_length_base = 16;
break;
case DATA:
// (TBD) look at "fec_id" to determine "fec_payload_id" size
// (we _assume_ "fec_id" == 129 here
if ((unsigned char)buffer[NormDataMsg::FEC_ID_OFFSET] == 129)
{
header_length_base = 24;
}
else
{
DMSG(0, "NormMsg::InitFromBuffer(DATA) unknown fec_id value: %u\n",
buffer[NormDataMsg::FEC_ID_OFFSET]);
return false;
}
break;
case CMD:
switch (buffer[NormCmdMsg::FLAVOR_OFFSET])
{
case NormCmdMsg::FLUSH:
case NormCmdMsg::SQUELCH:
// (TBD) look at "fec_id" to determine "fec_payload_id" size
// (we _assume_ "fec_id" == 129 here
if ((unsigned char)buffer[NormCmdFlushMsg::FEC_ID_OFFSET] == 129)
{
header_length_base = 24;
}
else
{
DMSG(0, "NormMsg::InitFromBuffer(FLUSH|SQUELCH) unknown fec_id value: %u\n",
buffer[NormDataMsg::FEC_ID_OFFSET]);
return false;
}
break;
case NormCmdMsg::EOT:
case NormCmdMsg::REPAIR_ADV:
case NormCmdMsg::ACK_REQ:
case NormCmdMsg::APPLICATION:
header_length_base = 16;
break;
case NormCmdMsg::CC:
header_length_base = 24;
break;
}
break;
case NACK:
case ACK:
header_length_base= 24;
break;
case REPORT:
header_length_base= 8;
break;
default:
DMSG(0, "NormMsg::InitFromBuffer() invalid message type!\n");
return false;
}
ASSERT(msgLength >= header_length);
length = msgLength;
return true;
} // end NormMsg::InitFromBuffer()
bool NormCmdCCMsg::GetCCNode(NormNodeId nodeId,
UINT8& flags,
UINT8& rtt,
UINT16& rate) const
{
UINT16 cmdLength = length;
UINT16 offset = header_length;
nodeId = htonl(nodeId);
while (offset < cmdLength)
{
if (nodeId == *((UINT32*)(buffer+offset)))
{
const char* ptr = buffer+offset;
flags = ptr[CC_FLAGS_OFFSET];
rtt = ptr[CC_RTT_OFFSET];
rate = ntohs(*((UINT16*)(ptr+CC_RATE_OFFSET)));
return true;
}
offset += CC_ITEM_SIZE;
}
return false;
} // end NormCmdCCMsg::GetCCNode()
NormCmdCCMsg::Iterator::Iterator(const NormCmdCCMsg& msg)
: cc_cmd(msg), offset(0)
{
}
bool NormCmdCCMsg::Iterator::GetNextNode(NormNodeId& nodeId,
UINT8& flags,
UINT8& rtt,
UINT16& rate)
{
if ((offset+CC_ITEM_SIZE) > cc_cmd.GetLength()) return false;
const char* ptr = cc_cmd.buffer + cc_cmd.header_length;
nodeId = ntohl(*((UINT32*)(ptr+offset)));
flags = ptr[offset+CC_FLAGS_OFFSET];
rtt = ptr[offset+CC_RTT_OFFSET];
rate = ntohs(*((UINT16*)(ptr+CC_RATE_OFFSET)));
offset += CC_ITEM_SIZE;
return true;
} // end NormCmdCCMsg::Iterator::GetNextNode()
NormRepairRequest::NormRepairRequest() NormRepairRequest::NormRepairRequest()
: form(INVALID), flags(0), length(0), buffer(NULL), buffer_len(0) : form(INVALID), flags(0), length(0), buffer(NULL), buffer_len(0)
{ {
@ -7,22 +138,24 @@ NormRepairRequest::NormRepairRequest()
bool NormRepairRequest::AppendRepairItem(const NormObjectId& objectId, bool NormRepairRequest::AppendRepairItem(const NormObjectId& objectId,
const NormBlockId& blockId, const NormBlockId& blockId,
UINT16 blockLen,
UINT16 symbolId) UINT16 symbolId)
{ {
if (RANGES == form) if (RANGES == form)
DMSG(4, "NormRepairRequest::AppendRepairRange(obj>%hu blk>%lu seg>%hu) ...\n", DMSG(4, "NormRepairRequest::AppendRepairItem-Range(obj>%hu blk>%lu seg>%hu) ...\n",
(UINT16)objectId, (UINT32)blockId, (UINT32)symbolId); (UINT16)objectId, (UINT32)blockId, (UINT32)symbolId);
else else
DMSG(4, "NormRepairRequest::AppendRepairItem(obj>%hu blk>%lu seg>%hu) ...\n", DMSG(4, "NormRepairRequest::AppendRepairItem(obj>%hu blk>%lu seg>%hu) ...\n",
(UINT16)objectId, (UINT32)blockId, (UINT32)symbolId); (UINT16)objectId, (UINT32)blockId, (UINT32)symbolId);
if (buffer_len >= (length+CONTENT_OFFSET+RepairItemLength())) if (buffer_len >= (length+ITEM_LIST_OFFSET+RepairItemLength()))
{ {
UINT16 temp16 = htons((UINT16)objectId); char* ptr = buffer + length + ITEM_LIST_OFFSET;
memcpy(buffer+CONTENT_OFFSET+length, &temp16, 2); ptr[FEC_ID_OFFSET] = 129;
UINT32 temp32 =htonl((UINT32)blockId); ptr[RESERVED_OFFSET] = 0;
memcpy(buffer+length+CONTENT_OFFSET+2, &temp32, 4); *((UINT16*)(ptr+OBJ_ID_OFFSET)) = htons((UINT16)objectId);
symbolId = htons(symbolId); *((UINT32*)(ptr+BLOCK_ID_OFFSET)) = htonl((UINT32)blockId);
memcpy(buffer+length+CONTENT_OFFSET+6, &symbolId, 2); *((UINT16*)(ptr+BLOCK_LEN_OFFSET)) = htons((UINT16)blockLen);
*((UINT16*)(ptr+SYMBOL_ID_OFFSET)) = htons((UINT16)symbolId);
length += RepairItemLength(); length += RepairItemLength();
return true; return true;
} }
@ -34,31 +167,34 @@ bool NormRepairRequest::AppendRepairItem(const NormObjectId& objectId,
bool NormRepairRequest::AppendRepairRange(const NormObjectId& startObjectId, bool NormRepairRequest::AppendRepairRange(const NormObjectId& startObjectId,
const NormBlockId& startBlockId, const NormBlockId& startBlockId,
UINT16 startBlockLen,
UINT16 startSymbolId, UINT16 startSymbolId,
const NormObjectId& endObjectId, const NormObjectId& endObjectId,
const NormBlockId& endBlockId, const NormBlockId& endBlockId,
UINT16 endBlockLen,
UINT16 endSymbolId) UINT16 endSymbolId)
{ {
DMSG(4, "NormRepairRequest::AppendRepairRange(%hu:%lu:%hu->%hu:%lu:%hu) ...\n", DMSG(4, "NormRepairRequest::AppendRepairRange(%hu:%lu:%hu->%hu:%lu:%hu) ...\n",
(UINT16)startObjectId, (UINT32)startBlockId, (UINT32)startSymbolId, (UINT16)startObjectId, (UINT32)startBlockId, (UINT32)startSymbolId,
(UINT16)endObjectId, (UINT32)endBlockId, (UINT32)endSymbolId); (UINT16)endObjectId, (UINT32)endBlockId, (UINT32)endSymbolId);
if (buffer_len >= (length+CONTENT_OFFSET+RepairRangeLength())) if (buffer_len >= (length+ITEM_LIST_OFFSET+RepairRangeLength()))
{ {
// range start // range start
UINT16 temp16; char* ptr = buffer + length + ITEM_LIST_OFFSET;
temp16 = htons((UINT16)startObjectId); ptr[FEC_ID_OFFSET] = 129;
memcpy(buffer+CONTENT_OFFSET+length, &temp16, 2); ptr[RESERVED_OFFSET] = 0;
UINT32 temp32 =htonl((UINT32)startBlockId); *((UINT16*)(ptr+OBJ_ID_OFFSET)) = htons((UINT16)startObjectId);
memcpy(buffer+length+CONTENT_OFFSET+2, &temp32, 4); *((UINT32*)(ptr+BLOCK_ID_OFFSET)) = htonl((UINT32)startBlockId);
startSymbolId = htons(startSymbolId); *((UINT16*)(ptr+BLOCK_LEN_OFFSET)) = htons((UINT16)startBlockLen);
memcpy(buffer+length+CONTENT_OFFSET+6, &startSymbolId, 2); *((UINT16*)(ptr+SYMBOL_ID_OFFSET)) = htons((UINT16)startSymbolId);
ptr += RepairItemLength();
// range end // range end
temp16 = htons((UINT16)endObjectId); ptr[FEC_ID_OFFSET] = 129;
memcpy(buffer+CONTENT_OFFSET+length+8, &temp16, 2); ptr[RESERVED_OFFSET] = 0;
temp32 =htonl((UINT32)endBlockId); *((UINT16*)(ptr+OBJ_ID_OFFSET)) = htons((UINT16)endObjectId);
memcpy(buffer+length+CONTENT_OFFSET+10, &temp32, 4); *((UINT32*)(ptr+BLOCK_ID_OFFSET)) = htonl((UINT32)endBlockId);
endSymbolId = htons(endSymbolId); *((UINT16*)(ptr+BLOCK_LEN_OFFSET)) = htons((UINT16)endBlockLen);
memcpy(buffer+length+CONTENT_OFFSET+14, &endSymbolId, 2); *((UINT16*)(ptr+SYMBOL_ID_OFFSET)) = htons((UINT16)endSymbolId);
length += RepairRangeLength(); length += RepairRangeLength();
return true; return true;
} }
@ -66,20 +202,22 @@ bool NormRepairRequest::AppendRepairRange(const NormObjectId& startObjectId,
{ {
return false; return false;
} }
} // end NormRepairRequest::AppendErasureCount() } // end NormRepairRequest::AppendRepairRange()
bool NormRepairRequest::AppendErasureCount(const NormObjectId& objectId, bool NormRepairRequest::AppendErasureCount(const NormObjectId& objectId,
const NormBlockId& blockId, const NormBlockId& blockId,
UINT16 blockLen,
UINT16 erasureCount) UINT16 erasureCount)
{ {
if (buffer_len >= (CONTENT_OFFSET+length+ErasureItemLength())) if (buffer_len >= (ITEM_LIST_OFFSET+length+ErasureItemLength()))
{ {
UINT16 temp16 = htons((UINT16)objectId); char* ptr = buffer + length + ITEM_LIST_OFFSET;
memcpy(buffer+CONTENT_OFFSET+length, &temp16, 2); ptr[FEC_ID_OFFSET] = 129;
UINT32 temp32 =htonl((UINT32)blockId); ptr[RESERVED_OFFSET] = 0;
memcpy(buffer+length+CONTENT_OFFSET+2, &temp32, 4); *((UINT16*)(ptr+OBJ_ID_OFFSET)) = htons((UINT16)objectId);
erasureCount = htons(erasureCount); *((UINT32*)(ptr+BLOCK_ID_OFFSET)) = htonl((UINT32)blockId);
memcpy(buffer+length+CONTENT_OFFSET+6, &erasureCount, 2); *((UINT16*)(ptr+BLOCK_LEN_OFFSET)) = htons((UINT16)blockLen);
*((UINT16*)(ptr+SYMBOL_ID_OFFSET)) = htons((UINT16)erasureCount);
length += ErasureItemLength(); length += ErasureItemLength();
return true; return true;
} }
@ -96,9 +234,8 @@ UINT16 NormRepairRequest::Pack()
{ {
buffer[FORM_OFFSET] = form; buffer[FORM_OFFSET] = form;
buffer[FLAGS_OFFSET] = (char)flags; buffer[FLAGS_OFFSET] = (char)flags;
UINT16 temp16 = htons(length); *((UINT16*)(buffer+LENGTH_OFFSET)) = htons(length);
memcpy(buffer+LENGTH_OFFSET, &temp16, 2); return (ITEM_LIST_OFFSET + length);
return (CONTENT_OFFSET + length);
} }
else else
{ {
@ -107,23 +244,26 @@ UINT16 NormRepairRequest::Pack()
} // end NormRepairRequest::Pack() } // end NormRepairRequest::Pack()
UINT16 NormRepairRequest::Unpack() UINT16 NormRepairRequest::Unpack(const char* bufferPtr, UINT16 bufferLen)
{ {
buffer = (char*)bufferPtr;
buffer_len = bufferLen;
length = 0;
// Make sure there's at least a header // Make sure there's at least a header
if (buffer_len >= CONTENT_OFFSET) if (buffer_len >= ITEM_LIST_OFFSET)
{ {
form = (Form)buffer[FORM_OFFSET]; form = (Form)buffer[FORM_OFFSET];
flags = (int)buffer[FLAGS_OFFSET]; flags = (int)buffer[FLAGS_OFFSET];
memcpy(&length, buffer+LENGTH_OFFSET, 2); length = ntohs(*((UINT16*)(buffer+LENGTH_OFFSET)));
length = ntohs(length); if (length > (buffer_len - ITEM_LIST_OFFSET))
if (length > (buffer_len - CONTENT_OFFSET))
{ {
// Badly formed message // Badly formed message
return 0; return 0;
} }
else else
{ {
return (CONTENT_OFFSET+length); return (ITEM_LIST_OFFSET+length);
} }
} }
else else
@ -135,18 +275,16 @@ UINT16 NormRepairRequest::Unpack()
bool NormRepairRequest::RetrieveRepairItem(UINT16 offset, bool NormRepairRequest::RetrieveRepairItem(UINT16 offset,
NormObjectId* objectId, NormObjectId* objectId,
NormBlockId* blockId, NormBlockId* blockId,
UINT16* blockLen,
UINT16* symbolId) const UINT16* symbolId) const
{ {
if (length >= (offset + RepairItemLength())) if (length >= (offset + RepairItemLength()))
{ {
UINT16 temp16; const char* ptr = buffer+ITEM_LIST_OFFSET+offset;
memcpy(&temp16, buffer+CONTENT_OFFSET+offset, 2); *objectId = ntohs(*((UINT16*)(ptr+OBJ_ID_OFFSET)));
*objectId = ntohs(temp16); *blockId = ntohl(*((UINT32*)(ptr+BLOCK_ID_OFFSET)));
UINT32 temp32; *blockLen = ntohs(*((UINT16*)(ptr+BLOCK_LEN_OFFSET)));
memcpy(&temp32, buffer+CONTENT_OFFSET+offset+2, 4); *symbolId = ntohs(*((UINT16*)(ptr+SYMBOL_ID_OFFSET)));
*blockId = ntohl(temp32);
memcpy(symbolId, buffer+CONTENT_OFFSET+offset+6, 2);
*symbolId = ntohs(*symbolId);
return true; return true;
} }
else else
@ -163,9 +301,10 @@ NormRepairRequest::Iterator::Iterator(NormRepairRequest& theRequest)
// For erasure requests, symbolId is loaded with erasureCount // For erasure requests, symbolId is loaded with erasureCount
bool NormRepairRequest::Iterator::NextRepairItem(NormObjectId* objectId, bool NormRepairRequest::Iterator::NextRepairItem(NormObjectId* objectId,
NormBlockId* blockId, NormBlockId* blockId,
UINT16* blockLen,
UINT16* symbolId) UINT16* symbolId)
{ {
if (request.RetrieveRepairItem(offset, objectId, blockId, symbolId)) if (request.RetrieveRepairItem(offset, objectId, blockId, blockLen, symbolId))
{ {
offset += NormRepairRequest::RepairItemLength(); offset += NormRepairRequest::RepairItemLength();
return true; return true;
@ -177,6 +316,8 @@ bool NormRepairRequest::Iterator::NextRepairItem(NormObjectId* objectId,
} // end NormRepairRequest::Iterator::NextRepairItem() } // end NormRepairRequest::Iterator::NextRepairItem()
NormMessageQueue::NormMessageQueue() NormMessageQueue::NormMessageQueue()
: head(NULL), tail(NULL) : head(NULL), tail(NULL)
{ {
@ -189,7 +330,7 @@ NormMessageQueue::~NormMessageQueue()
void NormMessageQueue::Destroy() void NormMessageQueue::Destroy()
{ {
NormMessage* next; NormMsg* next;
while ((next = head)) while ((next = head))
{ {
head = next->next; head = next->next;
@ -198,7 +339,7 @@ void NormMessageQueue::Destroy()
} // end NormMessageQueue::Destroy() } // end NormMessageQueue::Destroy()
void NormMessageQueue::Prepend(NormMessage* msg) void NormMessageQueue::Prepend(NormMsg* msg)
{ {
if ((msg->next = head)) if ((msg->next = head))
head->prev = msg; head->prev = msg;
@ -208,7 +349,7 @@ void NormMessageQueue::Prepend(NormMessage* msg)
head = msg; head = msg;
} // end NormMessageQueue::Prepend() } // end NormMessageQueue::Prepend()
void NormMessageQueue::Append(NormMessage* msg) void NormMessageQueue::Append(NormMsg* msg)
{ {
if ((msg->prev = tail)) if ((msg->prev = tail))
tail->next = msg; tail->next = msg;
@ -218,7 +359,7 @@ void NormMessageQueue::Append(NormMessage* msg)
tail = msg; tail = msg;
} // end NormMessageQueue::Append() } // end NormMessageQueue::Append()
void NormMessageQueue::Remove(NormMessage* msg) void NormMessageQueue::Remove(NormMsg* msg)
{ {
if (msg->prev) if (msg->prev)
msg->prev->next = msg->next; msg->prev->next = msg->next;
@ -230,11 +371,11 @@ void NormMessageQueue::Remove(NormMessage* msg)
tail = msg->prev; tail = msg->prev;
} // end NormMessageQueue::Remove() } // end NormMessageQueue::Remove()
NormMessage* NormMessageQueue::RemoveHead() NormMsg* NormMessageQueue::RemoveHead()
{ {
if (head) if (head)
{ {
NormMessage* msg = head; NormMsg* msg = head;
if ((head = msg->next)) if ((head = msg->next))
msg->next->prev = NULL; msg->next->prev = NULL;
else else
@ -247,11 +388,11 @@ NormMessage* NormMessageQueue::RemoveHead()
} }
} // end NormMessageQueue::RemoveHead() } // end NormMessageQueue::RemoveHead()
NormMessage* NormMessageQueue::RemoveTail() NormMsg* NormMessageQueue::RemoveTail()
{ {
if (tail) if (tail)
{ {
NormMessage* msg = tail; NormMsg* msg = tail;
if ((tail = msg->prev)) if ((tail = msg->prev))
msg->prev->next = NULL; msg->prev->next = NULL;
else else

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -16,12 +16,13 @@ class NormNode
NormNode(class NormSession* theSession, NormNodeId nodeId); NormNode(class NormSession* theSession, NormNodeId nodeId);
virtual ~NormNode(); virtual ~NormNode();
void SetAddress(const NetworkAddress& address) void SetAddress(const NetworkAddress& address) {addr = address;}
{addr = address;} const NetworkAddress& GetAddress() const {return addr;}
const NetworkAddress Address() const {return addr;}
const NormNodeId& Id() {return id;} const NormNodeId& Id() const {return id;}
inline const NormNodeId& LocalNodeId(); inline const NormNodeId& LocalNodeId() const;
void SetId(const NormNodeId& nodeId) {id = nodeId;}
protected: protected:
class NormSession* session; class NormSession* session;
@ -33,11 +34,154 @@ class NormNode
NormNode* parent; NormNode* parent;
NormNode* right; NormNode* right;
NormNode* left; NormNode* left;
NormNode* prev;
NormNode* next; //NormNode* prev;
//NormNode* next;
}; // end class NormNode }; // end class NormNode
// Weighted-history loss event estimator
class NormLossEstimator
{
public:
NormLossEstimator();
double LossFraction();
bool Update(const struct timeval& currentTime,
unsigned short seqNumber,
bool ecn = false);
void SetLossEventWindow(double lossWindow) {event_window = lossWindow;}
void SetInitialLoss(double lossFraction)
{
memset(history, 0, (DEPTH+1)*sizeof(unsigned int));
history[1] = (unsigned int)((1.0 / lossFraction) + 0.5);
}
unsigned int LastLossInterval() {return history[1];}
private:
enum {DEPTH = 8};
enum {MAX_OUTAGE = 100};
void Sync(unsigned short seq)
{
index_seq = seq;
synchronized = true;
}
int SequenceDelta(unsigned short a, unsigned short b);
static const double weight[8];
bool synchronized;
unsigned short index_seq;
bool seeking_loss_event;
double event_window;
struct timeval event_time;
unsigned int history[DEPTH+1];
}; // end class NormLossEstimator
class NormLossEstimator2
{
public:
NormLossEstimator2();
void SetEventWindow(unsigned short windowDepth)
{event_window = windowDepth;}
void SetLossEventWindow(double theTime)
{event_window_time = theTime;}
bool Update(const struct timeval& currentTime,
unsigned short seqNumber,
bool ecn = false);
double LossFraction();
double MdpLossFraction()
{return ((loss_interval > 0.0) ? (1.0/loss_interval) : 0.0);}
double TfrcLossFraction();
bool NoLoss() {return no_loss;}
void SetInitialLoss(double lossFraction)
{
memset(history, 0, (DEPTH+1)*sizeof(unsigned int));
history[1] = (unsigned int)((1.0 / lossFraction) + 0.5);
}
unsigned long CurrentLossInterval() {return history[0];}
unsigned int LastLossInterval() {return history[1];}
private:
enum {DEPTH = 8};
// Members
bool init;
unsigned long lag_mask;
unsigned int lag_depth;
unsigned long lag_test_bit;
unsigned short lag_index;
unsigned short event_window;
unsigned short event_index;
double event_window_time;
double event_index_time;
bool seeking_loss_event;
bool no_loss;
double initial_loss;
double loss_interval; // EWMA of loss event interval
unsigned long history[9]; // loss interval history
double discount[9];
double current_discount;
static const double weight[8];
void Init(unsigned short theSequence)
{init = true; Sync(theSequence);}
void Sync(unsigned short theSequence)
{lag_index = theSequence;}
void ChangeLagDepth(unsigned int theDepth)
{
theDepth = (theDepth > 20) ? 20 : theDepth;
lag_depth = theDepth;
lag_test_bit = 0x01 << theDepth;
}
int SequenceDelta(unsigned short a, unsigned short b);
}; // end class NormLossEstimator2
class NormCCNode : public NormNode
{
public:
NormCCNode(class NormSession* theSession, NormNodeId nodeId);
~NormCCNode();
bool IsClr() const {return is_clr;}
bool IsActive() const {return is_active;}
bool HasRtt() const {return rtt_confirmed;}
double GetRtt() const {return rtt;}
double GetLoss() const {return loss;}
double GetRate() const {return rate;}
UINT8 GetCCSequence() const {return cc_sequence;}
void SetActive(bool state) {is_active = state;}
void SetClrStatus(bool state) {is_clr = state;}
void SetRttStatus(bool state) {rtt_confirmed = state;}
void SetRtt(double value) {rtt = value;}
double UpdateRtt(double value)
{
rtt = 0.9*rtt + 0.1 * value;
return rtt;
}
void SetLoss(double value) {loss = value;}
void SetRate(double value) {rate = value;}
void SetCCSequence(UINT8 value) {cc_sequence = value;}
private:
bool is_clr; // true if worst path representative
bool is_plr; // true if worst path candidate
bool is_active;
bool rtt_confirmed;
double rtt; // in seconds
double loss; // loss fraction
double rate; // in bytes per second
UINT8 cc_sequence;
}; // end class NormCCNode
class NormServerNode : public NormNode class NormServerNode : public NormNode
{ {
public: public:
@ -46,15 +190,28 @@ class NormServerNode : public NormNode
NormServerNode(class NormSession* theSession, NormNodeId nodeId); NormServerNode(class NormSession* theSession, NormNodeId nodeId);
~NormServerNode(); ~NormServerNode();
void HandleCommand(NormCommandMsg& cmd); bool UpdateLossEstimate(const struct timeval& currentTime,
void HandleObjectMessage(NormMessage& msg); unsigned short theSequence,
void HandleNackMessage(NormNackMsg& nack); bool ecnStatus = false);
double LossEstimate() {return loss_estimator.LossFraction();}
bool Open(UINT16 segmentSize, UINT16 numData, UINT16 numParity);
void UpdateRecvRate(const struct timeval& currentTime,
unsigned short msgSize);
void HandleCommand(const struct timeval& currentTime,
const NormCmdMsg& cmd);
void HandleObjectMessage(const NormObjectMsg& msg);
void HandleCCFeedback(UINT8 ccFlags, double ccRate);
void HandleNackMessage(const NormNackMsg& nack);
void HandleAckMessage(const NormAckMsg& ack);
bool Open(UINT16 sessionId, UINT16 segmentSize, UINT16 numData, UINT16 numParity);
void Activate();
void Close(); void Close();
bool IsOpen() const {return is_open;} bool IsOpen() const {return is_open;}
bool SyncTest(const NormMessage& msg) const; bool SyncTest(const NormObjectMsg& msg) const;
void Sync(NormObjectId objectId); void Sync(NormObjectId objectId);
ObjectStatus UpdateSyncStatus(const NormObjectId& objectId); ObjectStatus UpdateSyncStatus(const NormObjectId& objectId);
void SetPending(NormObjectId objectId); void SetPending(NormObjectId objectId);
@ -65,8 +222,6 @@ class NormServerNode : public NormNode
UINT16 SegmentSize() {return segment_size;} UINT16 SegmentSize() {return segment_size;}
UINT16 BlockSize() {return ndata;} UINT16 BlockSize() {return ndata;}
UINT16 NumParity() {return nparity;} UINT16 NumParity() {return nparity;}
//NormBlockPool* BlockPool() {return &block_pool;}
//NormSegmentPool* SegmentPool() {return &segment_pool;}
NormBlock* GetFreeBlock(NormObjectId objectId, NormBlockId blockId); NormBlock* GetFreeBlock(NormObjectId objectId, NormBlockId blockId);
void PutFreeBlock(NormBlock* block) void PutFreeBlock(NormBlock* block)
@ -90,27 +245,29 @@ class NormServerNode : public NormNode
return decoder.Decode(segmentList, numData, erasureCount, erasure_loc); return decoder.Decode(segmentList, numData, erasureCount, erasure_loc);
} }
void CalculateGrttResponse(struct timeval& grttResponse); void CalculateGrttResponse(const struct timeval& currentTime,
struct timeval& grttResponse) const;
unsigned long CurrentBufferUsage() // Statistics kept on server
unsigned long CurrentBufferUsage() const
{return (segment_size * segment_pool.CurrentUsage());} {return (segment_size * segment_pool.CurrentUsage());}
unsigned long PeakBufferUsage() unsigned long PeakBufferUsage() const
{return (segment_size * segment_pool.PeakUsage());} {return (segment_size * segment_pool.PeakUsage());}
unsigned long BufferOverunCount() unsigned long BufferOverunCount() const
{return segment_pool.OverunCount() + block_pool.OverrunCount();} {return segment_pool.OverunCount() + block_pool.OverrunCount();}
unsigned long RecvTotal() const {return recv_total;}
unsigned long RecvTotal() {return recv_total;} unsigned long RecvGoodput() const {return recv_goodput;}
unsigned long RecvGoodput() {return recv_goodput;}
void IncrementRecvTotal(unsigned long count) {recv_total += count;} void IncrementRecvTotal(unsigned long count) {recv_total += count;}
void IncrementRecvGoodput(unsigned long count) {recv_goodput += count;} void IncrementRecvGoodput(unsigned long count) {recv_goodput += count;}
void ResetRecvStats() {recv_total = recv_goodput = 0;} void ResetRecvStats() {recv_total = recv_goodput = 0;}
void IncrementResyncCount() {resync_count++;} void IncrementResyncCount() {resync_count++;}
unsigned long ResyncCount() {return resync_count;} unsigned long ResyncCount() const {return resync_count;}
unsigned long NackCount() {return nack_count;} unsigned long NackCount() const {return nack_count;}
unsigned long SuppressCount() {return suppress_count;} unsigned long SuppressCount() const {return suppress_count;}
unsigned long CompletionCount() {return completion_count;} unsigned long CompletionCount() const {return completion_count;}
unsigned long PendingCount() {return rx_table.Count();} unsigned long PendingCount() const {return rx_table.Count();}
unsigned long FailureCount() {return failure_count;} unsigned long FailureCount() const {return failure_count;}
private: private:
void RepairCheck(NormObject::CheckLevel checkLevel, void RepairCheck(NormObject::CheckLevel checkLevel,
@ -118,9 +275,12 @@ class NormServerNode : public NormNode
NormBlockId blockId, NormBlockId blockId,
NormSegmentId segmentId); NormSegmentId segmentId);
bool OnActivityTimeout();
bool OnRepairTimeout(); bool OnRepairTimeout();
bool OnCCTimeout();
void HandleRepairContent(const char* buffer, UINT16 bufferLen);
UINT16 session_id;
bool synchronized; bool synchronized;
NormObjectId sync_id; // only valid if(synchronized) NormObjectId sync_id; // only valid if(synchronized)
NormObjectId next_id; // only valid if(synchronized) NormObjectId next_id; // only valid if(synchronized)
@ -138,8 +298,10 @@ class NormServerNode : public NormNode
NormDecoder decoder; NormDecoder decoder;
UINT16* erasure_loc; UINT16* erasure_loc;
ProtocolTimer activity_timer;
ProtocolTimer repair_timer; ProtocolTimer repair_timer;
NormObjectId current_object_id; // index for repair NormObjectId current_object_id; // index for suppression
NormObjectId max_pending_object; // index for NACK construction
double grtt_estimate; double grtt_estimate;
UINT8 grtt_quantized; UINT8 grtt_quantized;
@ -148,6 +310,25 @@ class NormServerNode : public NormNode
double gsize_estimate; double gsize_estimate;
UINT8 gsize_quantized; UINT8 gsize_quantized;
// Congestion control state
NormLossEstimator2 loss_estimator;
//NormLossEstimator loss_estimator;
UINT8 cc_sequence;
bool cc_enable;
double cc_rate; // ccRate at start of cc_timer
ProtocolTimer cc_timer;
double rtt_estimate;
UINT8 rtt_quantized;
bool rtt_confirmed;
bool is_clr;
bool is_plr;
bool slow_start;
double send_rate; // sender advertised rate
double recv_rate; // measured recv rate
struct timeval prev_update_time; // for recv_rate measurement
unsigned long recv_accumulator; // for recv_rate measurement
double nominal_packet_size;
// For statistics tracking // For statistics tracking
unsigned long recv_total; // total recvd accumulator unsigned long recv_total; // total recvd accumulator
unsigned long recv_goodput; // goodput recvd accumulator unsigned long recv_goodput; // goodput recvd accumulator
@ -157,7 +338,7 @@ class NormServerNode : public NormNode
unsigned long completion_count; unsigned long completion_count;
unsigned long failure_count; // due to re-syncs unsigned long failure_count; // due to re-syncs
}; // end class NodeServerNode }; // end class NormServerNode
// Used for binary trees of NormNodes // Used for binary trees of NormNodes
@ -179,9 +360,7 @@ class NormNodeTree
void AttachNode(NormNode *theNode); void AttachNode(NormNode *theNode);
void DetachNode(NormNode *theNode); void DetachNode(NormNode *theNode);
void Destroy(); // delete all nodes in tree void Destroy(); // delete all nodes in tree
private: private:
// Members // Members
NormNode* root; NormNode* root;
@ -208,6 +387,7 @@ class NormNodeList
// Construction // Construction
NormNodeList(); NormNodeList();
~NormNodeList(); ~NormNodeList();
unsigned int GetCount() {return count;}
NormNode* FindNodeById(NormNodeId nodeId) const; NormNode* FindNodeById(NormNodeId nodeId) const;
void Append(NormNode* theNode); void Append(NormNode* theNode);
void Remove(NormNode* theNode); void Remove(NormNode* theNode);
@ -218,13 +398,14 @@ class NormNodeList
delete theNode; delete theNode;
} }
void Destroy(); // delete all nodes in list void Destroy(); // delete all nodes in list
const NormNode* Head() {return head;}
// Members // Members
private: private:
NormNode* head; NormNode* head;
NormNode* tail; NormNode* tail;
unsigned int count;
}; // end class NormNodeList }; // end class NormNodeList
class NormNodeListIterator class NormNodeListIterator
@ -236,7 +417,7 @@ class NormNodeListIterator
NormNode* GetNextNode() NormNode* GetNextNode()
{ {
NormNode* n = next; NormNode* n = next;
next = n ? n->next : NULL; next = n ? n->right : NULL;
return n; return n;
} }
private: private:

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,7 @@ class NormObject
THRU_OBJECT THRU_OBJECT
}; };
void Verify() const;
virtual ~NormObject(); virtual ~NormObject();
NormObject::Type GetType() const {return type;} NormObject::Type GetType() const {return type;}
@ -39,14 +40,16 @@ class NormObject
bool IsStream() const {return (STREAM == type);} bool IsStream() const {return (STREAM == type);}
NormNodeId LocalNodeId() const; NormNodeId LocalNodeId() const;
class NormServerNode* GetServer() {return server;}
bool IsOpen() {return (0 != segment_size);}
// Opens (inits) object for tx operation // Opens (inits) object for tx operation
bool Open(const NormObjectSize& objectSize, bool Open(const NormObjectSize& objectSize,
const char* infoPtr, const char* infoPtr,
UINT16 infoLen); UINT16 infoLen);
// Opens (inits) object for rx operation // Opens (inits) object for rx operation
bool Open(const NormObjectSize& objectSize, bool hasInfo) bool Open(const NormObjectSize& objectSize, bool hasInfo)
{return Open(objectSize, NULL, hasInfo ? 1 : 0);} {return Open(objectSize, (char*)NULL, hasInfo ? 1 : 0);}
void Close(); void Close();
virtual bool WriteSegment(NormBlockId blockId, virtual bool WriteSegment(NormBlockId blockId,
@ -68,7 +71,7 @@ class NormObject
NormBlockId FirstPending() {return pending_mask.FirstSet();} NormBlockId FirstPending() {return pending_mask.FirstSet();}
// Methods available to server for transmission // Methods available to server for transmission
bool NextServerMsg(NormMessage* msg); bool NextServerMsg(NormObjectMsg* msg);
NormBlock* ServerRecoverBlock(NormBlockId blockId); NormBlock* ServerRecoverBlock(NormBlockId blockId);
bool CalculateBlockParity(NormBlock* block); bool CalculateBlockParity(NormBlock* block);
@ -82,25 +85,18 @@ class NormObject
NormBlockId blockId = theBlock->Id(); NormBlockId blockId = theBlock->Id();
bool result = theBlock->TxUpdate(firstSegmentId, lastSegmentId, bool result = theBlock->TxUpdate(firstSegmentId, lastSegmentId,
BlockSize(blockId), nparity, BlockSize(blockId), nparity,
segment_size, numErasures); numErasures);
if (result) ASSERT(result ? pending_mask.Set(blockId) : true);
{ result = result ? pending_mask.Set(blockId) : false;
result = pending_mask.Set(blockId);
ASSERT(result);
}
return result; return result;
} // end NormObject::TxUpdateBlock() } // end NormObject::TxUpdateBlock()
bool HandleInfoRequest(); bool HandleInfoRequest();
bool HandleBlockRequest(NormBlockId nextId, NormBlockId lastId); bool HandleBlockRequest(NormBlockId nextId, NormBlockId lastId);
bool SetPending(NormBlockId blockId) bool SetPending(NormBlockId blockId) {return pending_mask.Set(blockId);}
{return pending_mask.Set(blockId);} NormBlock* FindBlock(NormBlockId blockId) {return block_buffer.Find(blockId);}
NormBlock* FindBlock(NormBlockId blockId)
{
return block_buffer.Find(blockId);
}
bool ActivateRepairs(); bool ActivateRepairs();
bool IsRepairSet(NormBlockId blockId) bool IsRepairSet(NormBlockId blockId) {return repair_mask.Test(blockId);}
{return repair_mask.Test(blockId);} bool AppendRepairAdv(NormCmdRepairAdvMsg& cmd);
// Used by session server for resource management scheme // Used by session server for resource management scheme
NormBlock* StealNonPendingBlock(bool excludeBlock, NormBlockId excludeId = 0); NormBlock* StealNonPendingBlock(bool excludeBlock, NormBlockId excludeId = 0);
@ -108,29 +104,28 @@ class NormObject
// Methods available to client for reception // Methods available to client for reception
bool Accepted() {return accepted;} bool Accepted() {return accepted;}
void HandleObjectMessage(NormMessage& msg, void HandleObjectMessage(const NormObjectMsg& msg,
NormMsgType msgType, NormMsg::Type msgType,
NormBlockId blockId, NormBlockId blockId,
NormSegmentId segmentId); NormSegmentId segmentId);
bool StreamUpdateStatus(NormBlockId blockId);
// Used by remote server node for resource management scheme // Used by remote server node for resource management scheme
NormBlock* StealNewestBlock(bool excludeBlock, NormBlockId excludeId = 0); NormBlock* StealNewestBlock(bool excludeBlock, NormBlockId excludeId = 0);
NormBlock* StealOldestBlock(bool excludeBlock, NormBlockId excludeId = 0);
bool ClientRepairCheck(CheckLevel level, bool ClientRepairCheck(CheckLevel level,
NormBlockId blockId, NormBlockId blockId,
NormSegmentId segmentId, NormSegmentId segmentId,
bool timerActive); bool timerActive,
bool holdoffPhase = false);
bool IsRepairPending(bool flush); bool IsRepairPending(bool flush);
bool AppendRepairRequest(NormNackMsg& nack, bool flush); bool AppendRepairRequest(NormNackMsg& nack, bool flush);
void SetRepairInfo() {repair_info = true;} void SetRepairInfo() {repair_info = true;}
bool SetRepairs(NormBlockId first, NormBlockId last) bool SetRepairs(NormBlockId first, NormBlockId last)
{ {
if (first == last) return (first == last) ? repair_mask.Set(first) :
return repair_mask.Set(first); repair_mask.SetBits(first, last-first+1);
else
return repair_mask.SetBits(first, last-first+1);
} }
protected: protected:
@ -155,8 +150,10 @@ class NormObject
NormSlidingMask pending_mask; NormSlidingMask pending_mask;
bool repair_info; bool repair_info;
NormSlidingMask repair_mask; NormSlidingMask repair_mask;
NormBlockId current_block_id; NormBlockId current_block_id; // for suppression
NormSegmentId next_segment_id; NormSegmentId next_segment_id; // for suppression
NormBlockId max_pending_block; // for NACK construction
NormSegmentId max_pending_segment; // for NACK construction
NormBlockId last_block_id; NormBlockId last_block_id;
NormSegmentId last_block_size; NormSegmentId last_block_size;
UINT16 last_segment_size; UINT16 last_segment_size;
@ -166,10 +163,7 @@ class NormObject
bool accepted; bool accepted;
// Extra state for STREAM objects
bool stream_sync;
NormBlockId stream_sync_id;
NormBlockId stream_next_id;
NormObject* next; NormObject* next;
}; // end class NormObject }; // end class NormObject
@ -191,15 +185,9 @@ class NormFileObject : public NormObject
const char* Path() {return path;} const char* Path() {return path;}
bool Rename(const char* newPath) bool Rename(const char* newPath)
{ {
if (file.Rename(path, newPath)) bool result = file.Rename(path, newPath);
{ result ? strncpy(path, newPath, PATH_MAX) : NULL;
strncpy(path, newPath, PATH_MAX); return result;
return true;
}
else
{
return false;
}
} }
virtual bool WriteSegment(NormBlockId blockId, virtual bool WriteSegment(NormBlockId blockId,
@ -231,7 +219,11 @@ class NormStreamObject : public NormObject
void Close(); void Close();
bool Accept(unsigned long bufferSize); bool Accept(unsigned long bufferSize);
bool StreamUpdateStatus(NormBlockId blockId);
void StreamResync(NormBlockId nextBlockId)
{stream_next_id = nextBlockId;}
void StreamAdvance();
virtual bool WriteSegment(NormBlockId blockId, virtual bool WriteSegment(NormBlockId blockId,
NormSegmentId segmentId, NormSegmentId segmentId,
const char* buffer); const char* buffer);
@ -239,8 +231,8 @@ class NormStreamObject : public NormObject
NormSegmentId segmentId, NormSegmentId segmentId,
char* buffer); char* buffer);
unsigned long Read(char* buffer, unsigned long len); bool Read(char* buffer, unsigned int* buflen, bool findMsgStart = false);
unsigned long Write(char* buffer, unsigned long len, bool flush = false); unsigned long Write(const char* buffer, unsigned long len, bool flush, bool eom, bool push);
// For receive stream, we can rewind to earliest buffered offset // For receive stream, we can rewind to earliest buffered offset
void Rewind(); void Rewind();
@ -266,6 +258,11 @@ class NormStreamObject : public NormObject
NormBlockId block; NormBlockId block;
NormSegmentId segment; NormSegmentId segment;
}; };
// Extra state for STREAM objects
bool stream_sync;
NormBlockId stream_sync_id;
NormBlockId stream_next_id;
NormBlockPool block_pool; NormBlockPool block_pool;
NormSegmentPool segment_pool; NormSegmentPool segment_pool;
NormBlockBuffer stream_buffer; NormBlockBuffer stream_buffer;
@ -274,6 +271,7 @@ class NormStreamObject : public NormObject
Index read_index; Index read_index;
NormObjectSize read_offset; NormObjectSize read_offset;
bool flush_pending; bool flush_pending;
bool msg_start;
}; // end class NormStreamObject }; // end class NormStreamObject
#ifdef SIMULATE #ifdef SIMULATE
@ -317,17 +315,17 @@ class NormObjectTable
bool Init(UINT16 rangeMax, UINT16 tableSize = 256); bool Init(UINT16 rangeMax, UINT16 tableSize = 256);
void Destroy(); void Destroy();
bool IsInited() {return (NULL != table);} bool IsInited() const {return (NULL != table);}
bool CanInsert(NormObjectId objectId) const; bool CanInsert(NormObjectId objectId) const;
bool Insert(NormObject* theObject); bool Insert(NormObject* theObject);
bool Remove(const NormObject* theObject); bool Remove(const NormObject* theObject);
NormObject* Find(const NormObjectId& objectId) const; NormObject* Find(const NormObjectId& objectId) const;
NormObjectId RangeLo() {return range_lo;} NormObjectId RangeLo() const {return range_lo;}
NormObjectId RangeHi() {return range_hi;} NormObjectId RangeHi() const {return range_hi;}
bool IsEmpty() {return (0 == range);} bool IsEmpty() const {return (0 == range);}
unsigned long Count() {return count;} unsigned long Count() const {return count;}
const NormObjectSize& Size() {return size;} const NormObjectSize& Size() const {return size;}
class Iterator class Iterator
{ {

165
common/normPostProcess.cpp Normal file
View File

@ -0,0 +1,165 @@
#include "normPostProcess.h"
#include "protoLib.h"
#include <errno.h>
#include <signal.h>
#include <ctype.h>
#ifdef UNIX
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#endif // UNIX
typedef void (*sighandler_t)(int);
NormPostProcessor::NormPostProcessor()
: process_argv(NULL)
#ifdef UNIX
,process_id(0)
#endif // UNIX
{
}
NormPostProcessor::~NormPostProcessor()
{
if (IsActive()) Kill();
SetCommand(NULL);
}
bool NormPostProcessor::SetCommand(const char* cmd)
{
// 1) Delete old command resources
if (process_argv)
{
const char** arg = process_argv;
while (*arg)
{
delete *arg;
arg++;
}
delete process_argv;
process_argv = NULL;
process_argc = 0;
}
// 2) Count the number of tokens
if (!cmd) return true; // post processing disabled
if (!strcmp(cmd, "none")) return SetCommand(NULL);
const char* ptr = cmd;
unsigned int argCount = 0;
while (isspace(*ptr) && ('\0' != *ptr)) ptr++;
while ('\0' != *ptr)
{
argCount++;
while (!isspace(*ptr) && ('\0' != *ptr)) ptr++;
}
if (!argCount) return true; // post processing disabled
// 3) Allocate new process_argv array (2 extra slots, one for "target",
// and one for terminating NULL pointer.
if (!(process_argv = new const char*[argCount+2]))
{
DMSG(0, "NormPostProcessor::SetCommand new(process_argv) error: %s\n",
strerror(errno));
return false;
}
memset((void*)process_argv, 0, (argCount+2)*sizeof(char**));
process_argc = argCount;
// 4) Fill in process_argv[] array with individual args
ptr = cmd;
while (isspace(*ptr) && ('\0' != *ptr)) ptr++;
unsigned int index = 0;
while ('\0' != *ptr)
{
const char* argStart = ptr;
while (!isspace(*ptr) && ('\0' != *ptr)) ptr++;
unsigned int argLength = ptr - argStart;
char* arg;
if (!(arg = new char[argLength+1]))
{
SetCommand(NULL);
DMSG(0, "NormPostProcessor::SetCommand new(process_arg) error: %s\n",
strerror(errno));
return false;
}
strncpy(arg, argStart, argLength);
arg[argLength] = '\0';
process_argv[index] = arg;
}
return true;
} // end NormPostProcessor::SetCommand()
bool NormPostProcessor::ProcessFile(const char* path)
{
if (IsActive()) Kill();
#ifdef UNIX
// 1) temporarily disable signal handling
sighandler_t sigtermHandler = signal(SIGTERM, SIG_DFL);
sighandler_t sigintHandler = signal(SIGINT, SIG_DFL);
sighandler_t sigchldHandler = signal(SIGCHLD, SIG_DFL);
process_argv[process_argc] = path;
switch((process_id = fork()))
{
case -1: // error
DMSG(0, "NormPostProcessor::ProcessFile fork() error: %s\n", strerror(errno));
process_id = 0;
process_argv[process_argc] = NULL;
return false;
case 0: // child
if (execvp((char*)process_argv[0], (char**)process_argv) < 0)
{
DMSG(0, "NormPostProcessor::ProcessFile execvp() error: %s\n", strerror(errno));
exit(-1);
}
break;
default: // parent
process_argv[process_argc] = NULL;
// Restore signal handlers for parent
signal(SIGTERM, sigtermHandler);
signal(SIGINT, sigintHandler);
signal(SIGCHLD, sigchldHandler);
break;
}
#endif // UNIX
return true;
} // end NormPostProcessor::ProcessFile()
void NormPostProcessor::Kill()
{
if (!IsActive()) return;
#ifdef UNIX
int count = 0;
while((kill(process_id, SIGTERM) != 0) && count < 10)
{
if (errno == ESRCH) break;
count++;
DMSG(0, "NormPostProcessor::Kill kill() error: %s\n", strerror(errno));
}
count = 0;
int status;
while((waitpid(process_id, &status, 0) != process_id) && count < 10)
{
if (errno == ECHILD) break;
count++;
DMSG(0, "NormPostProcessor::Kill waitpid() error: %s\n", strerror(errno));
}
process_id = 0;
#endif // UNIX
} // end NormPostProcessor::Kill()
void NormPostProcessor::HandleSIGCHLD()
{
// See if processor exited itself
int status;
if (wait(&status) == process_id) process_id = 0;
} // end NormPostProcessor::HandleSIGCHLD()

35
common/normPostProcess.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef _NORM_POST_PROCESS
#define _NORM_POST_PROCESS
class NormPostProcessor
{
public:
NormPostProcessor();
~NormPostProcessor();
bool IsEnabled() {return (0 != process_argv);}
bool SetCommand(const char* cmd);
bool ProcessFile(const char* path);
void Kill();
bool IsActive()
{
#ifdef UNIX
return (0 != process_id);
#endif // UNIX
}
void HandleSIGCHLD();
private:
const char** process_argv;
unsigned int process_argc;
#ifdef UNIX
int process_id;
#endif
#ifdef WIN32
HANDLE process_handle;
#endif
}; // end class NormPostProcessor
#endif // _NORM_POST_PROCESS

View File

@ -5,9 +5,10 @@
NormSegmentPool::NormSegmentPool() NormSegmentPool::NormSegmentPool()
: seg_size(0), seg_count(0), seg_total(0), seg_list(NULL), : seg_size(0), seg_count(0), seg_total(0), seg_list(NULL),
peak_usage(0), overruns(0), overrun_flag(false) peak_usage(0), overruns(0), overrun_flag(false)
{ {
} }
NormSegmentPool::~NormSegmentPool() NormSegmentPool::~NormSegmentPool()
{ {
Destroy(); Destroy();
@ -18,6 +19,12 @@ bool NormSegmentPool::Init(unsigned int count, unsigned int size)
if (seg_list) Destroy(); if (seg_list) Destroy();
peak_usage = 0; peak_usage = 0;
overruns = 0; overruns = 0;
#ifdef SIMULATE
// In simulations, don't really need big vectors for data
// since we don't actually read/write real data
size = MIN(size, (SIM_PAYLOAD_MAX+NormDataMsg::PayloadHeaderLength()+1));
#endif // SIMULATE
// This makes sure we get appropriate alignment // This makes sure we get appropriate alignment
unsigned int alloc_size = size / sizeof(char*); unsigned int alloc_size = size / sizeof(char*);
if ((alloc_size*sizeof(char*)) < size) alloc_size++; if ((alloc_size*sizeof(char*)) < size) alloc_size++;
@ -157,7 +164,7 @@ void NormBlock::EmptyToPool(NormSegmentPool& segmentPool)
} }
} // end NormBlock::EmptyToPool() } // end NormBlock::EmptyToPool()
bool NormBlock::IsEmpty() bool NormBlock::IsEmpty() const
{ {
ASSERT(segment_table); ASSERT(segment_table);
for (unsigned int i = 0; i < size; i++) for (unsigned int i = 0; i < size; i++)
@ -166,7 +173,7 @@ bool NormBlock::IsEmpty()
} // end NormBlock::EmptyToPool() } // end NormBlock::EmptyToPool()
// Used by client side to determine if NACK should be sent // Used by client side to determine if NACK should be sent
// Note: This clears the block's "repair_mask" state // Note: This invalidates the block's "repair_mask" state
bool NormBlock::IsRepairPending(UINT16 ndata, UINT16 nparity) bool NormBlock::IsRepairPending(UINT16 ndata, UINT16 nparity)
{ {
// Clients ask for a block of parity to fulfill their // Clients ask for a block of parity to fulfill their
@ -250,9 +257,10 @@ bool NormBlock::ActivateRepairs(UINT16 nparity)
} // end NormBlock::ActivateRepairs() } // end NormBlock::ActivateRepairs()
// For NACKs arriving during server repair_timer "holdoff" time // For NACKs arriving during server repair_timer "holdoff" time
// (we directly update the "pending_mask" for blocks/segments
// greater than our current transmit index)
bool NormBlock::TxUpdate(NormSegmentId nextId, NormSegmentId lastId, bool NormBlock::TxUpdate(NormSegmentId nextId, NormSegmentId lastId,
UINT16 ndata, UINT16 nparity, UINT16 ndata, UINT16 nparity, UINT16 erasureCount)
UINT16 segmentSize, UINT16 erasureCount)
{ {
bool increasedRepair = false; bool increasedRepair = false;
@ -314,7 +322,7 @@ bool NormBlock::TxUpdate(NormSegmentId nextId, NormSegmentId lastId,
bool NormBlock::HandleSegmentRequest(NormSegmentId nextId, NormSegmentId lastId, bool NormBlock::HandleSegmentRequest(NormSegmentId nextId, NormSegmentId lastId,
UINT16 ndata, UINT16 nparity, UINT16 erasureCount) UINT16 ndata, UINT16 nparity, UINT16 erasureCount)
{ {
DMSG(4, "NormBlock::HandleSegmentRequest() blk>%lu seg>%hu:%hu erasures:%hu\n", DMSG(6, "NormBlock::HandleSegmentRequest() blk>%lu seg>%hu:%hu erasures:%hu\n",
(UINT32)id, (UINT16)nextId, (UINT16)lastId, erasureCount); (UINT32)id, (UINT16)nextId, (UINT16)lastId, erasureCount);
bool increasedRepair = false; bool increasedRepair = false;
if (nextId < ndata) if (nextId < ndata)
@ -373,6 +381,78 @@ bool NormBlock::HandleSegmentRequest(NormSegmentId nextId, NormSegmentId lastId,
} // end NormBlock::HandleSegmentRequest() } // end NormBlock::HandleSegmentRequest()
bool NormBlock::AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
NormObjectId objectId,
bool repairInfo,
UINT16 ndata,
UINT16 segmentSize)
{
NormRepairRequest req;
req.SetFlag(NormRepairRequest::SEGMENT);
if (repairInfo) req.SetFlag(NormRepairRequest::INFO);
UINT16 nextId = repair_mask.FirstSet();
UINT16 blockSize = size;
NormRepairRequest::Form prevForm = NormRepairRequest::INVALID;
UINT16 segmentCount = 0;
UINT16 firstId = 0;
while (nextId < blockSize)
{
UINT16 currentId = nextId;
nextId = repair_mask.NextSet(++nextId);
if (!segmentCount) firstId = currentId;
segmentCount++;
// Check for break in consecutive series or end
if (((nextId - currentId) > 1) || (nextId >= blockSize))
{
NormRepairRequest::Form form;
switch (segmentCount)
{
case 0:
form = NormRepairRequest::INVALID;
break;
case 1:
case 2:
form = NormRepairRequest::ITEMS;
break;
default:
form = NormRepairRequest::RANGES;
break;
}
if (form != prevForm)
{
if (NormRepairRequest::INVALID != prevForm)
cmd.PackRepairRequest(req); // (TBD) error check
req.SetForm(form);
cmd.AttachRepairRequest(req, segmentSize); // (TBD) error check
prevForm = form;
}
switch(form)
{
case NormRepairRequest::INVALID:
ASSERT(0); // can't happen
break;
case NormRepairRequest::ITEMS:
req.AppendRepairItem(objectId, id, ndata, firstId);
if (2 == segmentCount)
req.AppendRepairItem(objectId, id, ndata, currentId);
break;
case NormRepairRequest::RANGES:
req.AppendRepairRange(objectId, id, ndata, firstId,
objectId, id, ndata, currentId);
break;
case NormRepairRequest::ERASURES:
// erasure counts not used
break;
}
segmentCount = 0;
}
} // end while (nextId < blockSize)
if (NormRepairRequest::INVALID != prevForm)
cmd.PackRepairRequest(req); // (TBD) error check
return true;
} // end NormBlock::AppendRepairAdv()
// Called by client // Called by client
bool NormBlock::AppendRepairRequest(NormNackMsg& nack, bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
UINT16 ndata, UINT16 ndata,
@ -382,11 +462,7 @@ bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
UINT16 segmentSize) UINT16 segmentSize)
{ {
ASSERT(pending_mask.FirstSet() < ndata); ASSERT(pending_mask.FirstSet() < ndata);
NormRepairRequest req; NormSegmentId nextId, endId;
nack.AttachRepairRequest(req, segmentSize);
req.SetFlag(NormRepairRequest::SEGMENT);
if (pendingInfo) req.SetFlag(NormRepairRequest::INFO);
NormSegmentId nextId, lastId;
if (erasure_count > nparity) if (erasure_count > nparity)
{ {
@ -397,30 +473,92 @@ bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
while (i--) while (i--)
{ {
nextId++; nextId++;
nextId = pending_mask.NextSet(nextId); endId = pending_mask.NextSet(nextId);
} }
lastId = ndata + nparity; endId = ndata + nparity;
} }
else else
{ {
nextId = pending_mask.NextSet(ndata); nextId = pending_mask.NextSet(ndata);
lastId = ndata + erasure_count; endId = ndata + erasure_count;
} }
NormRepairRequest req;
req.SetFlag(NormRepairRequest::SEGMENT);
if (pendingInfo) req.SetFlag(NormRepairRequest::INFO);
NormRepairRequest::Form prevForm = NormRepairRequest::INVALID; NormRepairRequest::Form prevForm = NormRepairRequest::INVALID;
UINT16 reqCount = 0; UINT16 segmentCount = 0;
// new code begins here
UINT16 firstId = 0;
while (nextId < endId)
{
UINT16 currentId = nextId;
nextId = pending_mask.NextSet(++nextId);
if (0 == segmentCount) firstId = currentId;
segmentCount++;
// Check for break in consecutive series or end
if (((nextId - currentId) > 1) || (nextId >= endId))
{
NormRepairRequest::Form form;
switch (segmentCount)
{
case 0:
form = NormRepairRequest::INVALID;
break;
case 1:
case 2:
form = NormRepairRequest::ITEMS;
break;
default:
form = NormRepairRequest::RANGES;
break;
}
if (form != prevForm)
{
if (NormRepairRequest::INVALID != prevForm)
nack.PackRepairRequest(req); // (TBD) error check
nack.AttachRepairRequest(req, segmentSize); // (TBD) error check
req.SetForm(form);
prevForm = form;
}
switch (form)
{
case NormRepairRequest::INVALID:
ASSERT(0);
break;
case NormRepairRequest::ITEMS:
req.AppendRepairItem(objectId, id, ndata, firstId); // (TBD) error check
if (2 == segmentCount)
req.AppendRepairItem(objectId, id, ndata, currentId); // (TBD) error check
break;
case NormRepairRequest::RANGES:
req.AppendRepairRange(objectId, id, ndata, firstId, // (TBD) error check
objectId, id, ndata, currentId); // (TBD) error check
break;
case NormRepairRequest::ERASURES:
// erasure counts not used
break;
} // end switch(form)
segmentCount = 0;
}
} // end while (nextId < lastId)
if (NormRepairRequest::INVALID != prevForm)
nack.PackRepairRequest(req); // (TBD) error check
/*
// old code begins here
NormSegmentId prevId = nextId; NormSegmentId prevId = nextId;
while ((nextId <= lastId) || (reqCount > 0)) while ((nextId <= lastId) || (segmentCount > 0))
{ {
// force break of possible ending consec. series // force break of possible ending consec. series
if (nextId == lastId) nextId++; if (nextId == lastId) nextId++;
if (reqCount && (reqCount == (nextId - prevId))) if (segmentCount && (segmentCount == (nextId - prevId)))
{ {
reqCount++; // consecutive series continues segmentCount++; // consecutive series continues
} }
else else
{ {
NormRepairRequest::Form nextForm; NormRepairRequest::Form nextForm;
switch(reqCount) switch(segmentCount)
{ {
case 0: case 0:
nextForm = NormRepairRequest::INVALID; nextForm = NormRepairRequest::INVALID;
@ -464,15 +602,16 @@ bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
} // end switch(nextForm) } // end switch(nextForm)
prevId = nextId; prevId = nextId;
if (nextId < lastId) if (nextId < lastId)
reqCount = 1; segmentCount = 1;
else else
reqCount = 0; segmentCount = 0;
} // end if/else (reqCount && (reqCount == (nextId - prevId))) } // end if/else (reqCount && (reqCount == (nextId - prevId)))
nextId++; nextId++;
if (nextId <= lastId) nextId = pending_mask.NextSet(nextId); if (nextId <= lastId) nextId = pending_mask.NextSet(nextId);
} // end while(nextId <= lastId) } // end while(nextId <= lastId)
if (NormRepairRequest::INVALID != prevForm) if (NormRepairRequest::INVALID != prevForm)
nack.PackRepairRequest(req); // (TBD) error check nack.PackRepairRequest(req); // (TBD) error check
*/
return true; return true;
} // end NormBlock::AppendRepairRequest() } // end NormBlock::AppendRepairRequest()

View File

@ -24,11 +24,13 @@ class NormSegmentPool
seg_list = segment; seg_list = segment;
seg_count++; seg_count++;
} }
bool IsEmpty() {return (NULL == seg_list);} bool IsEmpty() const {return (NULL == seg_list);}
unsigned long CurrentUsage() {return (seg_total - seg_count);} unsigned long CurrentUsage() const {return (seg_total - seg_count);}
unsigned long PeakUsage() {return peak_usage;} unsigned long PeakUsage() const {return peak_usage;}
unsigned long OverunCount() {return overruns;} unsigned long OverunCount() const {return overruns;}
unsigned int GetSegmentSize() {return seg_size;}
private: private:
unsigned int seg_size; unsigned int seg_size;
@ -117,8 +119,7 @@ class NormBlock
bool TxReset(UINT16 ndata, UINT16 nparity, UINT16 autoParity, bool TxReset(UINT16 ndata, UINT16 nparity, UINT16 autoParity,
UINT16 segmentSize); UINT16 segmentSize);
bool TxUpdate(NormSegmentId nextId, NormSegmentId lastId, bool TxUpdate(NormSegmentId nextId, NormSegmentId lastId,
UINT16 ndata, UINT16 nparity, UINT16 ndata, UINT16 nparity, UINT16 erasureCount);
UINT16 segmentSize, UINT16 erasureCount);
bool HandleSegmentRequest(NormSegmentId nextId, NormSegmentId lastId, bool HandleSegmentRequest(NormSegmentId nextId, NormSegmentId lastId,
UINT16 ndata, UINT16 nparity, UINT16 ndata, UINT16 nparity,
@ -130,6 +131,11 @@ class NormBlock
parity_offset = MIN(parity_offset, nparity); parity_offset = MIN(parity_offset, nparity);
parity_count = 0; parity_count = 0;
} }
bool AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
NormObjectId objectId,
bool repairInfo,
UINT16 ndata,
UINT16 segmentSize);
// Client routines // Client routines
void RxInit(NormBlockId& blockId, UINT16 ndata, UINT16 nparity) void RxInit(NormBlockId& blockId, UINT16 ndata, UINT16 nparity)
@ -143,11 +149,12 @@ class NormBlock
parity_offset = 0; parity_offset = 0;
flags = 0; flags = 0;
} }
// Note: This invalidates the repair_mask state.
bool IsRepairPending(UINT16 ndata, UINT16 nparity); bool IsRepairPending(UINT16 ndata, UINT16 nparity);
void DecrementErasureCount() {erasure_count--;} void DecrementErasureCount() {erasure_count--;}
UINT16 ErasureCount() const {return erasure_count;} UINT16 ErasureCount() const {return erasure_count;}
void IncrementParityCount() {parity_count++;} void IncrementParityCount() {parity_count++;}
UINT16 ParityCount() {return parity_count;} UINT16 ParityCount() const {return parity_count;}
NormSymbolId FirstPending() const NormSymbolId FirstPending() const
{return pending_mask.FirstSet();} {return pending_mask.FirstSet();}
@ -196,7 +203,7 @@ class NormBlock
UINT16 segmentSize); UINT16 segmentSize);
//void DisplayPendingMask(FILE* f) {pending_mask.Display(f);} //void DisplayPendingMask(FILE* f) {pending_mask.Display(f);}
bool IsEmpty(); bool IsEmpty() const;
void EmptyToPool(NormSegmentPool& segmentPool); void EmptyToPool(NormSegmentPool& segmentPool);
private: private:
@ -222,7 +229,7 @@ class NormBlockPool
~NormBlockPool(); ~NormBlockPool();
bool Init(UINT32 numBlocks, UINT16 blockSize); bool Init(UINT32 numBlocks, UINT16 blockSize);
void Destroy(); void Destroy();
bool IsEmpty() {return (NULL == head);} bool IsEmpty() const {return (NULL == head);}
NormBlock* Get() NormBlock* Get()
{ {
NormBlock* b = head; NormBlock* b = head;
@ -243,7 +250,7 @@ class NormBlockPool
b->next = head; b->next = head;
head = b; head = b;
} }
unsigned long OverrunCount() {return overruns;} unsigned long OverrunCount() const {return overruns;}
private: private:
NormBlock* head; NormBlock* head;
@ -266,9 +273,9 @@ class NormBlockBuffer
bool Remove(const NormBlock* theBlock); bool Remove(const NormBlock* theBlock);
NormBlock* Find(const NormBlockId& blockId) const; NormBlock* Find(const NormBlockId& blockId) const;
NormBlockId RangeLo() {return range_lo;} NormBlockId RangeLo() const {return range_lo;}
NormBlockId RangeHi() {return range_hi;} NormBlockId RangeHi() const {return range_hi;}
bool IsEmpty() {return (0 == range);} bool IsEmpty() const {return (0 == range);}
bool CanInsert(NormBlockId blockId) const; bool CanInsert(NormBlockId blockId) const;
class Iterator class Iterator

File diff suppressed because it is too large Load Diff

View File

@ -87,14 +87,17 @@ class NormSession
public: public:
enum {DEFAULT_MESSAGE_POOL_DEPTH = 16}; enum {DEFAULT_MESSAGE_POOL_DEPTH = 16};
static const UINT8 DEFAULT_TTL;
static const double DEFAULT_TRANSMIT_RATE; // in bytes per second static const double DEFAULT_TRANSMIT_RATE; // in bytes per second
static const double DEFAULT_PROBE_MIN; static const double DEFAULT_GRTT_INTERVAL_MIN;
static const double DEFAULT_PROBE_MAX; static const double DEFAULT_GRTT_INTERVAL_MAX;
static const double DEFAULT_GRTT_ESTIMATE; static const double DEFAULT_GRTT_ESTIMATE;
static const double DEFAULT_GRTT_MAX; static const double DEFAULT_GRTT_MAX;
static const unsigned int DEFAULT_GRTT_DECREASE_DELAY; static const unsigned int DEFAULT_GRTT_DECREASE_DELAY;
static const double DEFAULT_BACKOFF_FACTOR; // times GRTT = backoff max static const double DEFAULT_BACKOFF_FACTOR; // times GRTT = backoff max
static const double DEFAULT_GSIZE_ESTIMATE; static const double DEFAULT_GSIZE_ESTIMATE;
static const UINT16 DEFAULT_NDATA;
static const UINT16 DEFAULT_NPARITY;
// General methods // General methods
const NormNodeId& LocalNodeId() {return local_node_id;} const NormNodeId& LocalNodeId() {return local_node_id;}
@ -103,20 +106,22 @@ class NormSession
bool IsOpen() {return (rx_socket.IsOpen() || tx_socket.IsOpen());} bool IsOpen() {return (rx_socket.IsOpen() || tx_socket.IsOpen());}
const NetworkAddress& Address() {return address;} const NetworkAddress& Address() {return address;}
void SetAddress(const NetworkAddress& addr) {address = addr;} void SetAddress(const NetworkAddress& addr) {address = addr;}
static double CalculateRate(double size, double rtt, double loss);
// Session parameters // Session parameters
double TxRate() {return (tx_rate * 8.0);} double TxRate() {return (tx_rate * 8.0);}
// (TBD) watch timer scheduling and min/max bounds
void SetTxRate(double txRate) {tx_rate = txRate / 8.0;} void SetTxRate(double txRate) {tx_rate = txRate / 8.0;}
double BackoffFactor() {return backoff_factor;} double BackoffFactor() {return backoff_factor;}
void SetBackoffFactor(double value) {backoff_factor = value;} void SetBackoffFactor(double value) {backoff_factor = value;}
void SetUnicastNacks(bool state) {unicast_nacks = state;}
bool UnicastNacks() {return unicast_nacks;}
void SetLoopback(bool state) void SetLoopback(bool state)
{ {
rx_socket.SetLoopback(state); rx_socket.SetLoopback(state);
tx_socket.SetLoopback(state); tx_socket.SetLoopback(state);
} }
bool CongestionControl() {return cc_enable;}
void SetCongestionControl(bool state) {cc_enable = state;}
void Notify(NormController::Event event, void Notify(NormController::Event event,
class NormServerNode* server, class NormServerNode* server,
@ -127,11 +132,19 @@ class NormSession
notify_pending = false; notify_pending = false;
} }
NormMessage* GetMessageFromPool() {return message_pool.RemoveHead();} NormMsg* GetMessageFromPool() {return message_pool.RemoveHead();}
void ReturnMessageToPool(NormMessage* msg) {message_pool.Append(msg);} void ReturnMessageToPool(NormMsg* msg) {message_pool.Append(msg);}
void QueueMessage(NormMessage* msg); void QueueMessage(NormMsg* msg);
void SendMessage(NormMsg& msg);
void InstallTimer(ProtocolTimer* timer)
{session_mgr.InstallTimer(timer);}
// Server methods // Server methods
void ServerSetBaseObjectId(NormObjectId baseId)
{
next_tx_object_id = IsServer() ? next_tx_object_id : baseId;
session_id = IsServer() ? session_id : (UINT16)baseId;
}
bool StartServer(unsigned long bufferSpace, bool StartServer(unsigned long bufferSpace,
UINT16 segmentSize, UINT16 segmentSize,
UINT16 numData, UINT16 numData,
@ -151,6 +164,9 @@ class NormSession
UINT16 ServerAutoParity() {return auto_parity;} UINT16 ServerAutoParity() {return auto_parity;}
void ServerSetAutoParity(UINT16 autoParity) void ServerSetAutoParity(UINT16 autoParity)
{ASSERT(autoParity <= nparity); auto_parity = autoParity;} {ASSERT(autoParity <= nparity); auto_parity = autoParity;}
UINT16 ServerExtraParity() {return extra_parity;}
void ServerSetExtraParity(UINT16 extraParity)
{extra_parity = extraParity;}
double ServerGroupSize() {return gsize_measured;} double ServerGroupSize() {return gsize_measured;}
void ServerSetGroupSize(double gsize) void ServerSetGroupSize(double gsize)
@ -172,10 +188,23 @@ class NormSession
} }
char* ServerGetFreeSegment(NormObjectId objectId, NormBlockId blockId); char* ServerGetFreeSegment(NormObjectId objectId, NormBlockId blockId);
void ServerPutFreeSegment(char* segment) {segment_pool.Put(segment);} void ServerPutFreeSegment(char* segment) {segment_pool.Put(segment);}
void PromptServer()
{
if (!tx_timer.IsActive())
{
tx_timer.SetInterval(0.0);
InstallTimer(&tx_timer);
}
}
void TouchServer() void TouchServer()
{ {
posted_tx_queue_empty = false; posted_tx_queue_empty = false;
if (!notify_pending) Serve(); PromptServer();
//if (!notify_pending) Serve();
} }
// Client methods // Client methods
@ -184,8 +213,10 @@ class NormSession
bool IsClient() {return is_client;} bool IsClient() {return is_client;}
unsigned long RemoteServerBufferSize() unsigned long RemoteServerBufferSize()
{return remote_server_buffer_size;} {return remote_server_buffer_size;}
void InstallTimer(ProtocolTimer* timer) void SetUnicastNacks(bool state) {unicast_nacks = state;}
{session_mgr.InstallTimer(timer);} bool UnicastNacks() {return unicast_nacks;}
void ClientSetSilent(bool state) {client_silent = state;}
bool ClientIsSilent() {return client_silent;}
// Debug settings // Debug settings
void SetTrace(bool state) {trace = state;} void SetTrace(bool state) {trace = state;}
@ -210,24 +241,45 @@ class NormSession
bool OnTxTimeout(); bool OnTxTimeout();
bool OnRepairTimeout(); bool OnRepairTimeout();
bool OnCommandTimeout(); bool OnFlushTimeout();
bool OnWatermarkTimeout();
bool OnProbeTimeout(); bool OnProbeTimeout();
bool OnReportTimeout(); bool OnReportTimeout();
bool TxSocketRecvHandler(UdpSocket* theSocket); bool TxSocketRecvHandler(UdpSocket* theSocket);
bool RxSocketRecvHandler(UdpSocket* theSocket); bool RxSocketRecvHandler(UdpSocket* theSocket);
void HandleReceiveMessage(NormMsg& msg, bool wasUnicast);
void HandleReceiveMessage(NormMessage& msg, bool wasUnicast); // Server message handling routines
void ServerHandleNackMessage(const struct timeval& currentTime,
void ServerHandleNackMessage(NormNackMsg& nack); NormNackMsg& nack);
void ServerUpdateGrttEstimate(const struct timeval& grttResponse); void ServerHandleAckMessage(const struct timeval& currentTime,
const NormAckMsg& ack,
bool wasUnicast);
void ServerUpdateGrttEstimate(double clientRtt);
double CalculateRtt(const struct timeval& currentTime,
const struct timeval& grttResponse);
void ServerHandleCCFeedback(NormNodeId nodeId,
UINT8 ccFlags,
double ccRtt,
double ccLoss,
double ccRate,
UINT8 ccSequence);
void AdjustRate(bool onResponse);
bool ServerQueueSquelch(NormObjectId objectId); bool ServerQueueSquelch(NormObjectId objectId);
void ServerQueueFlush(); void ServerQueueFlush();
bool ServerBuildRepairAdv(NormCmdRepairAdvMsg& cmd);
void ServerUpdateGroupSize(); void ServerUpdateGroupSize();
void ClientHandleObjectMessage(NormMessage& msg); // Client message handling routines
void ClientHandleCommand(NormMessage& msg); void ClientHandleObjectMessage(const struct timeval& currentTime,
void ClientHandleNackMessage(NormNackMsg& nack); const NormObjectMsg& msg,
NormServerNode* theServer);
void ClientHandleCommand(const struct timeval& currentTime,
const NormCmdMsg& msg,
NormServerNode* theServer);
void ClientHandleNackMessage(const NormNackMsg& nack);
void ClientHandleAckMessage(const NormAckMsg& ack);
NormSessionMgr& session_mgr; NormSessionMgr& session_mgr;
bool notify_pending; bool notify_pending;
@ -248,10 +300,12 @@ class NormSession
// Server parameters and state // Server parameters and state
bool is_server; bool is_server;
UINT16 session_id;
UINT16 segment_size; UINT16 segment_size;
UINT16 ndata; UINT16 ndata;
UINT16 nparity; UINT16 nparity;
UINT16 auto_parity; UINT16 auto_parity;
UINT16 extra_parity;
NormObjectTable tx_table; NormObjectTable tx_table;
NormSlidingMask tx_pending_mask; NormSlidingMask tx_pending_mask;
@ -268,32 +322,51 @@ class NormSession
ProtocolTimer flush_timer; ProtocolTimer flush_timer;
int flush_count; int flush_count;
bool posted_tx_queue_empty; bool posted_tx_queue_empty;
ProtocolTimer watermark_timer;
int watermark_count;
// (TBD) watermark_object_id, watermark_block_id, watermark_symbol_id
// for unicast nack/cc feedback suppression
bool advertise_repairs;
bool suppress_nonconfirmed;
double suppress_rate;
double suppress_rtt;
ProtocolTimer probe_timer; // GRTT/congestion control probes ProtocolTimer probe_timer; // GRTT/congestion control probes
double probe_interval; bool probe_proactive;
double probe_interval_min;
double probe_interval_max; double grtt_interval; // current GRTT update interval
double grtt_interval_min; // minimum GRTT update interval
double grtt_interval_max; // maximum GRTT update interval
double grtt_max; double grtt_max;
unsigned int grtt_decrease_delay_count; unsigned int grtt_decrease_delay_count;
bool grtt_response; bool grtt_response;
double grtt_current_peak; double grtt_current_peak;
double grtt_measured; double grtt_measured;
double grtt_age;
double grtt_advertised; double grtt_advertised;
UINT8 grtt_quantized; UINT8 grtt_quantized;
double gsize_measured; double gsize_measured;
double gsize_advertised; double gsize_advertised;
UINT8 gsize_quantized; UINT8 gsize_quantized;
unsigned int gsize_nack_count;
double gsize_nack_ave; // Server congestion control parameters
double gsize_correction_factor; bool cc_enable;
double gsize_nack_delta; UINT8 cc_sequence;
NormNodeList cc_node_list;
bool cc_slow_start;
double sent_rate; // measured sent rate
struct timeval prev_update_time; // for sent_rate measurement
unsigned long sent_accumulator; // for sent_rate measurement
double nominal_packet_size;
// Client parameters // Client parameters
bool is_client; bool is_client;
NormNodeTree server_tree; NormNodeTree server_tree;
unsigned long remote_server_buffer_size; unsigned long remote_server_buffer_size;
bool unicast_nacks; bool unicast_nacks;
bool client_silent;
// Protocol test/debug parameters // Protocol test/debug parameters
bool trace; bool trace;

View File

@ -2,25 +2,36 @@
#include <errno.h> #include <errno.h>
NormSimAgent::NormSimAgent() // This NORM simulation agent includes support for providing transport
: session(NULL), stream(NULL), // of a message stream from the MGEN simulation agent with restrictions. The
// current restriction is the MGEN simulation agent
NormSimAgent::NormSimAgent(ProtocolTimerInstallFunc* timerInstaller,
const void* timerInstallData,
UdpSocketInstallFunc* socketInstaller,
void* socketInstallData)
: session(NULL),
address(NULL), port(0), ttl(3), address(NULL), port(0), ttl(3),
tx_rate(NormSession::DEFAULT_TRANSMIT_RATE), tx_rate(NormSession::DEFAULT_TRANSMIT_RATE),
cc_enable(false), unicast_nacks(false), silent_client(false),
backoff_factor(NormSession::DEFAULT_BACKOFF_FACTOR), backoff_factor(NormSession::DEFAULT_BACKOFF_FACTOR),
segment_size(1024), ndata(32), nparity(16), auto_parity(0), segment_size(1024), ndata(32), nparity(16), auto_parity(0), extra_parity(0),
group_size(NormSession::DEFAULT_GSIZE_ESTIMATE), group_size(NormSession::DEFAULT_GSIZE_ESTIMATE),
tx_buffer_size(1024*1024), rx_buffer_size(1024*1024), tx_buffer_size(1024*1024), rx_buffer_size(1024*1024),
tx_object_size(0), tx_object_interval(0.0), tx_object_size(0), tx_object_interval(0.0),
tx_repeat_count(0), tx_repeat_interval(0.0), tx_repeat_count(0), tx_repeat_interval(0.0),
stream(NULL), auto_stream(false), push_stream(false),
mgen(NULL), msg_sync(false), mgen_bytes(0), mgen_pending_bytes(0),
tracing(false), tx_loss(0.0), rx_loss(0.0) tracing(false), tx_loss(0.0), rx_loss(0.0)
{ {
// Bind NormSessionMgr to this agent and simulation environment // Bind NormSessionMgr to this agent and simulation environment
session_mgr.Init(ProtoSimAgent::TimerInstaller, this, session_mgr.Init(timerInstaller, timerInstallData,
ProtoSimAgent::SocketInstaller, this, socketInstaller, socketInstallData,
static_cast<NormController*>(this)); static_cast<NormController*>(this));
interval_timer.Init(0.0, 0, (ProtocolTimerOwner*)this, interval_timer.Init(0.0, 0, (ProtocolTimerOwner*)this,
(ProtocolTimeoutFunc)&NormSimAgent::OnIntervalTimeout); (ProtocolTimeoutFunc)&NormSimAgent::OnIntervalTimeout);
memset(mgen_buffer, 0, 64);
} }
NormSimAgent::~NormSimAgent() NormSimAgent::~NormSimAgent()
@ -31,30 +42,38 @@ NormSimAgent::~NormSimAgent()
const char* const NormSimAgent::cmd_list[] = const char* const NormSimAgent::cmd_list[] =
{ {
"+debug", "+debug", // debug level
"+log", "+log", // log file name
"-trace", "-trace", // message tracing
"+txloss", "+txloss", // tx packet loss percent
"+rxloss", "+rxloss", // rx packet loss percent
"+address", "+address", // session dest addres
"+ttl", "+ttl", // multicast ttl
"+rate", "+rate", // tx rate
"+backoff", "+cc", // congestion control on/off
"+input", "+backoff", // backoff factor 'k' (maxBackoff = k * GRTT)
"+output", "+input", // stream input
"+interval", "+output", // stream output
"+repeat", "+interval", // delay between tx objects
"+rinterval", // repeat interval "+repeat", // number of times to repeat tx object set
"+segment", "+rinterval", // repeat interval
"+block", "+segment", // server segment size
"+parity", "+block", // server blocking size
"+auto", "+parity", // server parity segments calculated per block
"+gsize", "+auto", // server auto parity count
"+txbuffer", "+extra", // server extra parity count
"+rxbuffer", "+gsize", // group size estimate
"+start", "+txbuffer", // tx buffer size (bytes)
"-stop", "+rxbuffer", // rx buffer size (bytes)
"+sendFile", "+start", // open session and beging activity
"-stop", // cease activity and close session
"+sendFile", // queue a "sim" file for transmission
"+sendStream", // send a simulated NORM stream
"+openStream", // open a stream object for messaging
"+push", // "on" means real-time push stream advancement (non-blocking)
"-flushStream", // flush output stream
"+unicastNacks", // clients will unicast feedback
"+silentClient", // clients will not transmit
NULL NULL
}; };
@ -162,6 +181,22 @@ bool NormSimAgent::ProcessCommand(const char* cmd, const char* val)
tx_rate = txRate; tx_rate = txRate;
if (session) session->SetTxRate(txRate); if (session) session->SetTxRate(txRate);
} }
else if (!strncmp("cc", cmd, len))
{
bool ccEnable;
if (!strcmp(val, "on"))
ccEnable = true;
else if (!strcmp(val, "off"))
ccEnable = false;
else
{
DMSG(0, "NormSimAgent::ProcessCommand(cc) invalid argument!\n");
return false;
}
cc_enable = ccEnable;
if (session) session->SetCongestionControl(ccEnable);
return true;
}
else if (!strncmp("backoff", cmd, len)) else if (!strncmp("backoff", cmd, len))
{ {
double backoffFactor = atof(val); double backoffFactor = atof(val);
@ -171,7 +206,7 @@ bool NormSimAgent::ProcessCommand(const char* cmd, const char* val)
return false; return false;
} }
backoff_factor = backoffFactor; backoff_factor = backoffFactor;
if (session) session->SetTxRate(backoffFactor); if (session) session->SetBackoffFactor(backoffFactor);
} }
else if (!strncmp("interval", cmd, len)) else if (!strncmp("interval", cmd, len))
{ {
@ -230,6 +265,17 @@ bool NormSimAgent::ProcessCommand(const char* cmd, const char* val)
auto_parity = autoParity; auto_parity = autoParity;
if (session) session->ServerSetAutoParity(autoParity); if (session) session->ServerSetAutoParity(autoParity);
} }
else if (!strncmp("extra", cmd, len))
{
int extraParity = atoi(val);
if ((extraParity < 0) || (extraParity > 254))
{
DMSG(0, "NormSimAgent::ProcessCommand(extra) invalid value!\n");
return false;
}
extra_parity = extraParity;
if (session) session->ServerSetExtraParity(extraParity);
}
else if (!strncmp("gsize", cmd, len)) else if (!strncmp("gsize", cmd, len))
{ {
if (1 != sscanf(val, "%lf", &group_size)) if (1 != sscanf(val, "%lf", &group_size))
@ -291,6 +337,120 @@ bool NormSimAgent::ProcessCommand(const char* cmd, const char* val)
DMSG(0, "NormSimAgent::ProcessCommand(sendFile) no session started!\n"); DMSG(0, "NormSimAgent::ProcessCommand(sendFile) no session started!\n");
return false; return false;
} }
}
else if (!strncmp("sendStream", cmd, len))
{
if (session)
{
if (stream)
{
DMSG(0, "NormSimAgent::ProcessCommand(sendStream) stream already open!\n");
return false;
}
if (1 != sscanf(val, "%lu", &tx_object_size))
{
DMSG(0, "NormSimAgent::ProcessCommand(sendStream) invalid buffer size!\n");
return false;
}
if (!(stream = session->QueueTxStream(tx_object_size)))
{
DMSG(0, "NormSimAgent::ProcessCommand(sendStream) error opening stream!\n");
return false;
}
auto_stream = true;
}
else
{
DMSG(0, "NormSimAgent::ProcessCommand(sendStream) session not started!\n");
return false;
}
}
else if (!strncmp("openStream", cmd, len))
{
if (session)
{
if (stream)
{
DMSG(0, "NormSimAgent::ProcessCommand(openStream) stream already open!\n");
return false;
}
if (1 != sscanf(val, "%lu", &tx_object_size))
{
DMSG(0, "NormSimAgent::ProcessCommand(openStream) invalid buffer size!\n");
return false;
}
if(!(tx_msg_buffer = new char[65536]))
{
DMSG(0, "NormSimAgent::ProcessCommand(openStream) error allocating tx_msg_buffer: %s\n",
strerror(errno));
return false;
}
if (!(stream = session->QueueTxStream(tx_object_size)))
{
DMSG(0, "NormSimAgent::ProcessCommand(openStream) error opening stream!\n");
return false;
}
auto_stream = false;
tx_msg_len = tx_msg_index = 0;
}
else
{
DMSG(0, "NormSimAgent::ProcessCommand(openStream) session not started!\n");
return false;
}
}
else if (!strncmp("flushStream", cmd, len))
{
if (session)
{
return FlushStream();
}
else
{
DMSG(0, "NormSimAgent::ProcessCommand(flushStream) session not started!\n");
return false;
}
}
else if (!strncmp("push", cmd, len))
{
if (!strcmp(val, "on"))
push_stream = true;
else if (!strcmp(val, "off"))
push_stream = false;
else
{
DMSG(0, "NormSimAgent::ProcessCommand(push) invalid argument!\n");
return false;
}
return true;
}
else if (!strncmp("unicastNacks", cmd, len))
{
if (!strcmp(val, "on"))
unicast_nacks = true;
else if (!strcmp(val, "off"))
unicast_nacks = false;
else
{
DMSG(0, "NormSimAgent::ProcessCommand(unicastNacks) invalid argument!\n");
return false;
}
if (session) session->SetUnicastNacks(unicast_nacks);
return true;
}
else if (!strncmp("silentClient", cmd, len))
{
if (!strcmp(val, "on"))
silent_client = true;
else if (!strcmp(val, "off"))
silent_client = false;
else
{
DMSG(0, "NormSimAgent::ProcessCommand(silentClient) invalid argument!\n");
return false;
}
if (session) session->ClientSetSilent(silent_client);
return true;
} }
return true; return true;
} // end NormSimAgent::ProcessCommand() } // end NormSimAgent::ProcessCommand()
@ -326,6 +486,81 @@ NormSimAgent::CmdType NormSimAgent::CommandType(const char* cmd)
return type; return type;
} // end NormSimAgent::CommandType() } // end NormSimAgent::CommandType()
bool NormSimAgent::SendMessage(unsigned int len, const char* txBuffer)
{
if (session)
{
if (!stream)
{
if(!(tx_msg_buffer = new char[65536]))
{
DMSG(0, "NormSimAgent::SendMessage() error allocating tx_msg_buffer: %s\n",
strerror(errno));
return false;
}
if (!(stream = session->QueueTxStream(tx_object_size)))
{
DMSG(0, "NormSimAgent::SendMessage() error opening stream!\n");
return false;
}
auto_stream = false;
tx_msg_len = tx_msg_index = 0;
}
if (0 == tx_msg_len)
{
memcpy(tx_msg_buffer, txBuffer, len);
tx_msg_len = len;
OnInputReady();
return true;
}
else
{
// Message still pending, can't send yet
DMSG(0, "NormSimAgent::SendMessage() input overflow!\n");
ASSERT(0);
return false;
}
}
else
{
DMSG(0, "NormSimAgent::SendMessage() session not started!\n");
return false;
}
} // end NormSimAgent::SendMessage()
void NormSimAgent::OnInputReady()
{
//TRACE("NormSimAgent::OnInputReady() index:%lu len:%lu\n",
// tx_msg_index, tx_msg_len);
if (tx_msg_index < tx_msg_len)
{
unsigned int bytesWrote = stream->Write(tx_msg_buffer+tx_msg_index,
tx_msg_len - tx_msg_index,
false, false, push_stream);
tx_msg_index += bytesWrote;
if (tx_msg_index == tx_msg_len)
{
// Provide EOM indication to norm stream
stream->Write(NULL, 0, false, true, false);
tx_msg_index = tx_msg_len = 0;
}
}
} // end NormSimAgent::InputReady()
bool NormSimAgent::FlushStream()
{
if (stream && session && session->IsServer())
{
stream->Write(NULL, 0, true, false, false);
return true;
}
else
{
DMSG(0, "NormSimAgent::FlushStream() no output stream to flush\n");
}
} // end NormSimAgent::FlushStream()
void NormSimAgent::Notify(NormController::Event event, void NormSimAgent::Notify(NormController::Event event,
class NormSessionMgr* sessionMgr, class NormSessionMgr* sessionMgr,
@ -337,13 +572,31 @@ void NormSimAgent::Notify(NormController::Event event,
{ {
case TX_QUEUE_EMPTY: case TX_QUEUE_EMPTY:
// Can queue a new object or write to stream for transmission // Can queue a new object or write to stream for transmission
if (interval_timer.Interval() > 0.0) if (object && (object == stream))
{ {
InstallTimer(interval_timer); if (auto_stream)
{
// sending a dummy byte stream
char buffer[NormMsg::MAX_SIZE];
unsigned int count = stream->Write(buffer, segment_size, false, false, false);
}
else
{
// Stream starved, ask for input from "source" ?
OnInputReady();
}
} }
else else
{ {
OnIntervalTimeout(); // Schedule or queue next "sim file" transmission
if (interval_timer.Interval() > 0.0)
{
InstallTimer(interval_timer);
}
else
{
OnIntervalTimeout();
}
} }
break; break;
@ -355,11 +608,19 @@ void NormSimAgent::Notify(NormController::Event event,
{ {
case NormObject::STREAM: case NormObject::STREAM:
{ {
const NormObjectSize& size = object->Size(); NormObjectSize size;
if (silent_client)
size = NormObjectSize(rx_buffer_size);
else
size = object->Size();
if (!((NormStreamObject*)object)->Accept(size.LSB())) if (!((NormStreamObject*)object)->Accept(size.LSB()))
{ {
DMSG(0, "NormSimAgent::Notify(RX_OBJECT_NEW) stream object accept error!\n"); DMSG(0, "NormSimAgent::Notify(RX_OBJECT_NEW) stream object accept error!\n");
} }
if (!stream)
stream = (NormStreamObject*)object;
else
DMSG(0, "NormSimAgent::Notify(RX_OBJECT_NEW) warning! one stream already accepted.\n");
} }
break; break;
case NormObject::FILE: case NormObject::FILE:
@ -399,11 +660,106 @@ void NormSimAgent::Notify(NormController::Event event,
case NormObject::STREAM: case NormObject::STREAM:
{ {
// Read the stream when it's updated // Read the stream when it's updated
char buffer[256]; if (mgen)
unsigned int nBytes; {
while ((nBytes = ((NormStreamObject*)object)->Read(buffer, 256))) bool dataReady = true;
while (dataReady)
{
if (!mgen_pending_bytes)
{
// Read 2 byte MGEN msg len header
unsigned int want = 2 - mgen_bytes;
unsigned int got = want;
bool findMsgSync = msg_sync ? false : true;
if (((NormStreamObject*)object)->Read(mgen_buffer + mgen_bytes,
&got, findMsgSync))
{
mgen_bytes += got;
msg_sync = true;
if (got != want) dataReady = false;
}
else
{
DMSG(0, "NormSimAgent::Notify(1) detected stream break\n");
mgen_bytes = mgen_pending_bytes = 0;
msg_sync = false;
continue;
}
if (2 == mgen_bytes)
{
UINT16 msgSize;
memcpy(&msgSize, mgen_buffer, sizeof(UINT16));
mgen_pending_bytes = ntohs(msgSize) - 2;
}
}
if (mgen_pending_bytes)
{
// Save the first part for MGEN logging
if (mgen_bytes < 64)
{
unsigned int want = MIN(mgen_pending_bytes, 62);
unsigned int got = want;
if (((NormStreamObject*)object)->Read(mgen_buffer+mgen_bytes,
&got))
{
mgen_pending_bytes -= got;
mgen_bytes += got;
if (got != want) dataReady = false;
}
else
{
DMSG(0, "NormSimAgent::Notify(2) detected stream break\n");
mgen_bytes = mgen_pending_bytes = 0;
msg_sync = false;
continue;
}
}
while (dataReady && mgen_pending_bytes)
{
char buffer[256];
unsigned int want = MIN(256, mgen_pending_bytes);
unsigned int got = want;
if (((NormStreamObject*)object)->Read(buffer, &got))
{
mgen_pending_bytes -= got;
mgen_bytes += got;
if (got != want) dataReady = false;
}
else
{
DMSG(0, "NormSimAgent::Notify(3) detected stream break\n");
mgen_bytes = mgen_pending_bytes = 0;
msg_sync = false;
break;
}
}
if (msg_sync && (0 == mgen_pending_bytes))
{
const NetworkAddress& srcAddr = server->GetAddress();
mgen->HandleMgenMessage(mgen_buffer, mgen_bytes, srcAddr);
mgen_bytes = 0;
}
} // end if (mgen_pending_bytes)
} // end while(dataReady)
}
else
{ {
char buffer[1024];
unsigned int want = 1024;
unsigned int got = want;
while (1)
{
if (((NormStreamObject*)object)->Read(buffer, &got))
{
// Break when data is no longer available
if (got != want) break;
}
else
{
DMSG(0, "NormSimAgent::Notify() detected stream break\n");
}
got = want = 1024;
}
} }
break; break;
} }
@ -440,7 +796,7 @@ bool NormSimAgent::OnIntervalTimeout()
{ {
if (stream) if (stream)
{ {
// (TBD)
} }
else else
{ {
@ -457,7 +813,7 @@ bool NormSimAgent::OnIntervalTimeout()
else else
{ {
// Done // Done
interval_timer.Deactivate(); if (interval_timer.IsActive()) interval_timer.Deactivate();
return false; return false;
} }
@ -484,20 +840,21 @@ bool NormSimAgent::StartServer()
{ {
// Common session parameters // Common session parameters
session->SetTxRate(tx_rate); session->SetTxRate(tx_rate);
session->SetCongestionControl(cc_enable);
session->SetBackoffFactor(backoff_factor); session->SetBackoffFactor(backoff_factor);
session->SetTrace(tracing); session->SetTrace(tracing);
session->SetTxLoss(tx_loss); session->SetTxLoss(tx_loss);
session->SetRxLoss(rx_loss); session->SetRxLoss(rx_loss);
session->ServerSetGroupSize(group_size);
// StartServer(bufferMax, segmentSize, fec_ndata, fec_nparity) // StartServer(bufferMax, segmentSize, fec_ndata, fec_nparity)
if (!session->StartServer(tx_buffer_size, segment_size, ndata, nparity)) if (!session->StartServer(tx_buffer_size, segment_size, ndata, nparity))
{ {
DMSG(0, "NormSimAgent::OnStartup() start server error!\n"); DMSG(0, "NormSimAgent::OnStartup() start server error!\n");
session_mgr.Destroy(); session_mgr.Destroy();
return false; return false;
} }
session->ServerSetAutoParity(auto_parity); session->ServerSetAutoParity(auto_parity);
session->ServerSetGroupSize(group_size); session->ServerSetExtraParity(extra_parity);
return true; return true;
} }
else else
@ -534,6 +891,9 @@ bool NormSimAgent::StartClient()
session->SetTxLoss(tx_loss); session->SetTxLoss(tx_loss);
session->SetRxLoss(rx_loss); session->SetRxLoss(rx_loss);
session->SetUnicastNacks(unicast_nacks);
session->ClientSetSilent(silent_client);
// StartClient(bufferSize) // StartClient(bufferSize)
if (!session->StartClient(rx_buffer_size)) if (!session->StartClient(rx_buffer_size))
{ {
@ -558,6 +918,7 @@ void NormSimAgent::Stop()
if (session->IsClient()) session->StopClient(); if (session->IsClient()) session->StopClient();
session_mgr.DeleteSession(session); session_mgr.DeleteSession(session);
session = NULL; session = NULL;
stream = NULL;
} }
} // end NormSimAgent::StopServer() } // end NormSimAgent::StopServer()

View File

@ -2,38 +2,40 @@
// normSimAgent.h - Generic (base class) NORM simulation agent // normSimAgent.h - Generic (base class) NORM simulation agent
#include "protoLib.h" #include "protoLib.h"
#include "protoSim.h"
#include "normSession.h" #include "normSession.h"
#include "mgen.h" // for MGEN instance attachment
// Base class for Norm simulation agents (e.g. ns-2, OPNET, etc) // Base class for Norm simulation agents (e.g. ns-2, OPNET, etc)
class NormSimAgent : public NormController class NormSimAgent : public NormController
{ {
public: public:
NormSimAgent();
virtual ~NormSimAgent(); virtual ~NormSimAgent();
void Init(ProtocolTimerInstallFunc* timerInstaller,
const void* timerInstallData,
UdpSocketInstallFunc* socketInstaller,
void* socketInstallData)
{
session_mgr.Init(timerInstaller, timerInstallData,
socketInstaller, socketInstallData,
this);
}
bool ProcessCommand(const char* cmd, const char* val); bool ProcessCommand(const char* cmd, const char* val);
// Note: don't allow client _and_ server operation at same time // Note: don't allow client _and_ server operation at same time
bool StartServer(); bool StartServer();
bool StartClient(); bool StartClient();
bool IsActive() {return (NULL != session);}
void Stop(); void Stop();
bool SendMessage(unsigned int len, const char* txBuffer);
void AttachMgen(Mgen* mgenInstance) {mgen = mgenInstance;}
protected: protected:
NormSimAgent(ProtocolTimerInstallFunc* timerInstaller,
const void* timerInstallData,
UdpSocketInstallFunc* socketInstaller,
void* socketInstallData);
enum CmdType {CMD_INVALID, CMD_NOARG, CMD_ARG}; enum CmdType {CMD_INVALID, CMD_NOARG, CMD_ARG};
CmdType CommandType(const char* cmd); CmdType CommandType(const char* cmd);
virtual unsigned long GetAgentId() = 0; virtual unsigned long GetAgentId() = 0;
private: private:
void OnInputReady();
bool FlushStream();
virtual void Notify(NormController::Event event, virtual void Notify(NormController::Event event,
class NormSessionMgr* sessionMgr, class NormSessionMgr* sessionMgr,
class NormSession* session, class NormSession* session,
@ -49,18 +51,21 @@ class NormSimAgent : public NormController
NormSessionMgr session_mgr; NormSessionMgr session_mgr;
NormSession* session; NormSession* session;
NormStreamObject* stream;
// session parameters // session parameters
char* address; // session address char* address; // session address
UINT16 port; // session port number UINT16 port; // session port number
UINT8 ttl; UINT8 ttl;
double tx_rate; // bits/sec double tx_rate; // bits/sec
bool cc_enable;
bool unicast_nacks;
bool silent_client;
double backoff_factor; double backoff_factor;
UINT16 segment_size; UINT16 segment_size;
UINT8 ndata; UINT8 ndata;
UINT8 nparity; UINT8 nparity;
UINT8 auto_parity; UINT8 auto_parity;
UINT8 extra_parity;
double group_size; double group_size;
unsigned long tx_buffer_size; // bytes unsigned long tx_buffer_size; // bytes
unsigned long rx_buffer_size; // bytes unsigned long rx_buffer_size; // bytes
@ -70,6 +75,18 @@ class NormSimAgent : public NormController
double tx_object_interval; double tx_object_interval;
int tx_repeat_count; int tx_repeat_count;
double tx_repeat_interval; double tx_repeat_interval;
NormStreamObject* stream;
bool auto_stream;
bool push_stream;
char* tx_msg_buffer;
unsigned int tx_msg_len;
unsigned int tx_msg_index;
Mgen* mgen;
char mgen_buffer[64];
bool msg_sync;
unsigned int mgen_bytes;
unsigned int mgen_pending_bytes;
ProtocolTimer interval_timer; ProtocolTimer interval_timer;

View File

@ -32,6 +32,6 @@
#ifndef _NORM_VERSION #ifndef _NORM_VERSION
#define _NORM_VERSION #define _NORM_VERSION
#define VERSION "1.0x1" #define VERSION "1.0b2"
#endif // _NORM_VERSION #endif // _NORM_VERSION

View File

@ -25,9 +25,12 @@ suppress.tcl - Executable TCL script which iteratively
invokes "ns" with the "simplenorm.tcl" invokes "ns" with the "simplenorm.tcl"
script and "nc" (nackCount) to evaluate script and "nc" (nackCount) to evaluate
NORM NACK suppression performance. NORM NACK suppression performance.
ns-2.1b9-Makefile.in - Patched version of ns-2.1b9 Makefile.in
with NORM, MDP & PROTOLIB stuff included.
(MDP stuff can be removed if desired)
ns-2.1b7a-Makefile.in - Patched version of ns-2.1b7a Makefile.in ns-2.1b7a-Makefile.in - Patched version of ns-2.1b7a Makefile.in
with NORM & PROTOLIB stuff included. with NORM & PROTOLIB stuff included.

View File

@ -33,7 +33,7 @@ for {set i 1} {$i <= $numNodes} {incr i} {
puts "Creating topology ..." puts "Creating topology ..."
for {set i 1} {$i <= $numNodes} {incr i} { for {set i 1} {$i <= $numNodes} {incr i} {
$ns_ duplex-link $n(0) $n($i) 64kb 100ms DropTail $ns_ duplex-link $n(0) $n($i) 1Mb 1ms DropTail
$ns_ queue-limit $n(0) $n($i) 100 $ns_ queue-limit $n(0) $n($i) 100
#$ns_ duplex-link-op $n(0) $n($i) orient right #$ns_ duplex-link-op $n(0) $n($i) orient right
$ns_ duplex-link-op $n(0) $n($i) queuePos 0.5 $ns_ duplex-link-op $n(0) $n($i) queuePos 0.5
@ -53,7 +53,7 @@ puts "Configuring NORM agents ..."
# 5) Configure global NORM agent parameters (debugging/logging is global) # 5) Configure global NORM agent parameters (debugging/logging is global)
# (Uncomment the "log" command to direct NORM debug output to a file) # (Uncomment the "log" command to direct NORM debug output to a file)
$norm(1) debug 2 $norm(1) debug 1
#$norm(1) log normLog.txt #$norm(1) log normLog.txt
# 6) Configure NORM server agent at node 1 # 6) Configure NORM server agent at node 1
@ -63,7 +63,7 @@ $norm(1) block 1
$norm(1) parity 0 $norm(1) parity 0
$norm(1) repeat -1 $norm(1) repeat -1
$norm(1) interval 0.0 $norm(1) interval 0.0
$norm(1) txloss 10.0 $norm(1) txloss 0.0
# Enabl NORM message tracing at the server # Enabl NORM message tracing at the server
#$norm(1) trace #$norm(1) trace
@ -71,7 +71,7 @@ $norm(1) txloss 10.0
for {set i 2} {$i <= $numNodes} {incr i} { for {set i 2} {$i <= $numNodes} {incr i} {
$norm($i) address $group/5000 $norm($i) address $group/5000
$norm($i) rxbuffer 100000 $norm($i) rxbuffer 100000
$norm($i) txloss 10.0 $norm($i) rxloss 0.0
#$norm($i) trace #$norm($i) trace
} }

253
ns/normcc.tcl Normal file
View File

@ -0,0 +1,253 @@
# This script exercises NORM-CC versus TCP flows over
# a single bottleneck topology. There is one NORM flow
# and possibly multiple TCP flows. The number of receivers
# in the NORM "group" can vary (default gsize:10)
proc normcc {optionList} {
# normcc usage
set usage {Usage: ns normcc.tcl [brate <bottleneckRate>][tcp <numTcp>][gsize <count>]}
append usage {[rate <sendRate>][duration <sec>][backoff <k>][trace]}
#Some default parameters for NORM
set groupSize "10"
set backoffFactor "4.0"
set sendRate "32kb"
set bottleneckRate "1Mb"
set duration "240.0"
set nsTracing 1
set numTcp 1
set queueType "DropTail"
set queueSize 100
#Parse optionList for parameters
set state flag
foreach option $optionList {
switch -- $state {
"flag" {
switch -glob -- $option {
"gsize" {set state "gsize"}
"rate" {set state "rate"}
"brate" {set state "brate"}
"backoff" {set state "backoff"}
"duration" {set state "duration"}
"tcp" {set state "tcp"}
"red" {set queueType "RED"}
"trace" {set nsTracing 1}
default {
puts "normcc: Bad option $option"
puts "$usage"
exit
}
}
}
"gsize" {
set groupSize $option
set state "flag"
}
"backoff" {
set backoffFactor $option
set state "flag"
}
"brate" {
set bottleneckRate $option
set state "flag"
}
"rate" {
set sendRate $option
set state "flag"
}
"duration" {
set duration $option
set state "flag"
}
"tcp" {
set numTcp $option
set state "flag"
}
default {
error "normcc: Bad option parse state!"
}
}
}
# 1) An ns-2 simulator instance is created an configured
# for multicast operation with a dense mode (DM) multicast
# routing protocol:
set ns_ [new Simulator -multicast on]
$ns_ multicast
# 2) Trace files are opened and ns and nam
# tracing is enabled:
if {$nsTracing} {
set f [open normcc.tr w]
$ns_ trace-all $f
set nf [open normcc.nam w]
$ns_ namtrace-all $nf
} else {
set f 0
set nf 0
}
# 3) Create a single bottleneck
# Link 0 <-> 1 is our bottleneck
set n(0) [$ns_ node]
set n(1) [$ns_ node]
puts "normcc: Creating bottleneck link ..."
$ns_ duplex-link $n(0) $n(1) $bottleneckRate 10ms $queueType
$ns_ queue-limit $n(0) $n(1) $queueSize
$ns_ duplex-link-op $n(0) $n(1) queuePos 0.5
if {"RED" == $queueType} {
set redq [[$ns_ link $n(0) $n(1)] queue]
$redq set thresh_ [expr int($queueSize/10 + 0.9)]
$redq set maxthresh_ [expr int($queueSize/2 +0.9)]
$redq set linterm_ 10
}
# Non-bottleneck link rate is 10 * bottleneckRate
set linkRate [expr 10 * [bw_parse $bottleneckRate]]
# 4) Create a single NORM server and link to bottleneck
puts "normcc: Creating NORM server ..."
set n(2) [$ns_ node]
set norm_server [new Agent/NORM]
$ns_ attach-agent $n(2) $norm_server
# Link from NORM server to bottleneck
$ns_ duplex-link $n(2) $n(0) $linkRate 1ms DropTail
$ns_ queue-limit $n(2) $n(0) 100
$ns_ duplex-link-op $n(2) $n(0) queuePos 0.5
# 5) Create nodes with TCP sources and links to bottleneck
if {$numTcp > 0} {
puts "normcc: Creating TCP sources ..."
}
for {set i 0} {$i < $numTcp} {incr i} {
set k [expr $i + 3]
set n($k) [$ns_ node]
set tcp_src($i) [new Agent/TCP/FullTcp]
$ns_ attach-agent $n($k) $tcp_src($i)
$tcp_src($i) set window_ 100
$tcp_src($i) set packetSize_ 512
# Links from TCP sources to bottleneck
$ns_ duplex-link $n($k) $n(0) $linkRate 1ms DropTail
$ns_ queue-limit $n($k) $n(0) 100
$ns_ duplex-link-op $n($k) $n(0) queuePos 0.5
# Attach FTP app to tcp sources
set ftp($i) [new Application/FTP]
$ftp($i) attach-agent $tcp_src($i)
}
# 6) Create nodes with NORM clients and links to bottleneck
puts "normcc: Creating NORM clients ..."
for {set i 0} {$i < $groupSize} {incr i} {
set k [expr $i + 3 + $numTcp]
set n($k) [$ns_ node]
set norm_client($i) [new Agent/NORM]
$ns_ attach-agent $n($k) $norm_client($i)
# Links from bottleneck to NORM clients
$ns_ duplex-link $n(1) $n($k) $linkRate 1ms DropTail
$ns_ queue-limit $n(1) $n($k) 100
$ns_ duplex-link-op $n(1) $n($k) queuePos 0.5
}
# 7) Create nodes with TCP sinks and links to bottleneck
puts "normcc: Creating TCP sinks..."
for {set i 0} {$i < $numTcp} {incr i} {
set k [expr $i + 4 + $numTcp + $groupSize]
set n($k) [$ns_ node]
set tcp_sink($i) [new Agent/TCP/FullTcp]
$ns_ attach-agent $n($k) $tcp_sink($i)
# Links from bottleneck to TCP sinks
$ns_ duplex-link $n(1) $n($k) $linkRate 1ms DropTail
$ns_ queue-limit $n(1) $n($k) 100
$ns_ duplex-link-op $n(1) $n($k) queuePos 0.5
# Connect tcp sources->sinks
$ns_ connect $tcp_src($i) $tcp_sink($i)
$tcp_sink($i) listen
}
# 8) Configure multicast routing for topology
set mproto DM
set mrthandle [$ns_ mrtproto $mproto {}]
if {$mrthandle != ""} {
$mrthandle set_c_rp [list $n(1)]
}
# 9) Allocate a multicast address to use
set group [Node allocaddr]
puts "normcc: Configuring NORM agents ..."
# 10) Configure global NORM agent commands (using norm_server)
$norm_server debug 2
#$norm_server log normLog.txt
# 11) Configure NORM server parameters
$norm_server address $group/5000
$norm_server rate [bw_parse $sendRate]
$norm_server cc on
$norm_server backoff $backoffFactor
$norm_server segment 532
$norm_server block 64
$norm_server parity 32
$norm_server repeat -1
$norm_server interval 0.0
$norm_server txloss 0.0
$norm_server gsize $groupSize
#$norm_server trace
# 12) Configure NORM client parameters
for {set i 0} {$i < $groupSize} {incr i} {
$norm_client($i) address $group/5000
$norm_client($i) backoff $backoffFactor
$norm_client($i) rxbuffer 1000000
$norm_client($i) txloss 0.0
$norm_client($i) gsize $groupSize
#$norm_client($i) trace
}
# 13) Start NORM server and clients
$ns_ at 0.0 "$norm_server start server"
for {set i 0} {$i < $groupSize} {incr i} {
$ns_ at 0.0 "$norm_client($i) start client"
}
$ns_ at 0.0 "$norm_server sendStream 1000000"
# 14) Start tcp flows
for {set i 0} {$i < $numTcp} {incr i} {
$ns_ at 0.0 "$ftp($i) start"
}
# 15) Schedule finish time
$ns_ at $duration "finish $ns_ $f $nf $nsTracing"
puts "normcc: Running simulation (tcp:$numTcp gsize:$groupSize rate:$sendRate backoff $backoffFactor duration:$duration) ..."
$ns_ run
}
proc finish {ns_ f nf nsTracing} {
puts "normcc: Done."
$ns_ flush-trace
if {$nsTracing} {
close $f
close $nf
}
$ns_ halt
delete $ns_
}
# Run a set of trials with optional command-line parameters
puts "Running normcc: $argv"
normcc $argv

536
ns/ns-2.1b9-Makefile.in Normal file
View File

@ -0,0 +1,536 @@
# Copyright (c) 1994, 1995, 1996
# The Regents of the University of California. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that: (1) source code distributions
# retain the above copyright notice and this paragraph in its entirety, (2)
# distributions including binary code include the above copyright notice and
# 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 acknowledgement:
# ``This product includes software developed by the University of California,
# Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
# the University nor the names of its contributors may be used to endorse
# or promote products derived from this software without specific prior
# written permission.
# 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.
#
# @(#) $Header: /cvsroot/norm/norm/ns/ns-2.1b9-Makefile.in,v 1.1 2002/11/18 16:14:07 adamson Exp $ (LBL)
#
# Various configurable paths (remember to edit Makefile.in, not Makefile)
#
# Top level hierarchy
prefix = @prefix@
# Pathname of directory to install the binary
BINDEST = @prefix@/bin
# Pathname of directory to install the man page
MANDEST = @prefix@/man
BLANK = # make a blank space. DO NOT add anything to this line
# The following will be redefined under Windows (see WIN32 lable below)
CC = @CC@
CPP = @CXX@
LINK = $(CPP)
MKDEP = ./conf/mkdep
TCLSH = @V_TCLSH@
TCL2C = @V_TCL2CPP@
AR = ar rc $(BLANK)
RANLIB = @V_RANLIB@
INSTALL = @INSTALL@
LN = ln
TEST = test
RM = rm -f
MV = mv
PERL = @PERL@
# for diffusion
#DIFF_INCLUDES = "./diffusion3/main ./diffusion3/lib ./diffusion3/nr ./diffusion3/ns"
CCOPT = @V_CCOPT@
STATIC = @V_STATIC@
LDFLAGS = $(STATIC)
LDOUT = -o $(BLANK)
DEFINE = -DTCP_DELAY_BIND_ALL -DNO_TK -DNIXVECTOR @V_DEFINE@ @V_DEFINES@ @DEFS@ -DPGM -DPGM_DEBUG -DNS_DIFFUSION
PROTOLIB_INCLUDES = -Iprotolib/common -Iprotolib/ns
MDP_INCLUDES = -Imdp/common -Imdp/ns -Imdp/unix
NORM_INCLUDES = -Inorm/common -Inorm/ns
INCLUDES = \
-I. @V_INCLUDE_X11@ \
@V_INCLUDES@ \
-I./tcp -I./common -I./link -I./queue \
-I./adc -I./apps -I./mac -I./mobile -I./trace \
-I./routing -I./tools -I./classifier -I./mcast \
-I./diffusion3/main -I./diffusion3/lib \
-I./diffusion3/nr -I./diffusion3/ns -I./asim/ \
$(PROTOLIB_INCLUDES) $(MDP_INCLUDES) $(NORM_INCLUDES)
LIB = \
@V_LIBS@ \
@V_LIB_X11@ \
@V_LIB@ \
-lm @LIBS@
# -L@libdir@ \
# These flags work on Linux
PROTOLIB_CFLAGS = -g -DUNIX -DNS2 -DPROTO_DEBUG -DSIMULATE -DHAVE_ASSERT -DHAVE_DIRFD
CFLAGS = $(CCOPT) $(DEFINE) $(PROTOLIB_CFLAGS)
# Explicitly define compilation rules since SunOS 4's make doesn't like gcc.
# Also, gcc does not remove the .o before forking 'as', which can be a
# problem if you don't own the file but can write to the directory.
# PROTOLIB/MDP/NORM code uses .cpp files so we added a suffix and rule
.SUFFIXES: .cc .cpp # $(.SUFFIXES)
.cc.o:
@rm -f $@
$(CPP) -c $(CFLAGS) $(INCLUDES) -o $@ $*.cc
.c.o:
@rm -f $@
$(CC) -c $(CFLAGS) $(INCLUDES) -o $@ $*.c
.cpp.o:
@rm -f $@
$(CC) -c $(CFLAGS) $(INCLUDES) -o $@ $*.cpp
GEN_DIR = gen/
LIB_DIR = lib/
NS = ns
NSX = nsx
NSE = nse
# To allow conf/makefile.win overwrite this macro
# We will set these two macros to empty in conf/makefile.win since VC6.0
# does not seem to support the STL in gcc 2.8 and up.
OBJ_STL = linkstate/ls.o linkstate/rtProtoLS.o \
pgm/classifier-pgm.o pgm/pgm-agent.o pgm/pgm-sender.o \
pgm/pgm-receiver.o pgm/rcvbuf.o \
diffusion3/nr/nr.o diffusion3/lib/dr.o \
diffusion3/ns/diffagent.o diffusion3/ns/diffrtg.o \
diffusion3/ns/difftimer.o diffusion3/main/diffusion.o \
diffusion3/main/attrs.o diffusion3/main/iodev.o \
diffusion3/main/events.o diffusion3/main/message.o \
diffusion3/main/hashutils.o diffusion3/main/stats.o \
diffusion3/main/tools.o diffusion3/main/drivers/rpc_stats.o \
diffusion3/apps/sysapps/gradient.o \
diffusion3/apps/sysapps/log.o \
diffusion3/lib/diffapp.o \
diffusion3/apps/agents/ping_sender.o \
diffusion3/apps/agents/ping_receiver.o \
diffusion3/apps/agents/ping_common.o \
diffusion3/apps/gear/geo-attr.o \
diffusion3/apps/gear/geo-routing.o \
diffusion3/apps/gear/geo-tools.o
NS_TCL_LIB_STL = tcl/rtglib/ns-rtProtoLS.tcl \
tcl/lib/ns-diffusion.tcl
# WIN32: uncomment the following line to include specific make for VC++
# !include <conf/makefile.win>
OBJ_CC = \
tools/random.o tools/rng.o tools/ranvar.o common/misc.o common/timer-handler.o \
common/scheduler.o common/object.o common/packet.o \
common/ip.o routing/route.o common/connector.o common/ttl.o \
trace/trace.o trace/trace-ip.o \
classifier/classifier.o classifier/classifier-addr.o \
classifier/classifier-hash.o \
classifier/classifier-virtual.o \
classifier/classifier-mcast.o \
classifier/classifier-bst.o \
classifier/classifier-mpath.o mcast/replicator.o \
classifier/classifier-mac.o \
classifier/classifier-port.o src_rtg/classifier-sr.o \
src_rtg/sragent.o src_rtg/hdr_src.o adc/ump.o \
apps/app.o apps/telnet.o tcp/tcplib-telnet.o \
tools/trafgen.o trace/traffictrace.o tools/pareto.o \
tools/expoo.o tools/cbr_traffic.o \
adc/tbf.o adc/resv.o adc/sa.o tcp/saack.o \
tools/measuremod.o adc/estimator.o adc/adc.o adc/ms-adc.o \
adc/timewindow-est.o adc/acto-adc.o \
adc/pointsample-est.o adc/salink.o adc/actp-adc.o \
adc/hb-adc.o adc/expavg-est.o\
adc/param-adc.o adc/null-estimator.o \
adc/adaptive-receiver.o apps/vatrcvr.o adc/consrcvr.o \
common/agent.o common/message.o apps/udp.o \
common/session-rtp.o apps/rtp.o tcp/rtcp.o \
common/ivs.o \
tcp/tcp.o tcp/tcp-sink.o tcp/tcp-reno.o \
tcp/tcp-newreno.o \
tcp/tcp-vegas.o tcp/tcp-rbp.o tcp/tcp-full.o tcp/rq.o \
baytcp/tcp-full-bay.o baytcp/ftpc.o baytcp/ftps.o \
tcp/scoreboard.o tcp/tcp-sack1.o tcp/tcp-fack.o \
tcp/tcp-asym.o tcp/tcp-asym-sink.o tcp/tcp-fs.o \
tcp/tcp-asym-fs.o \
tcp/tcp-int.o tcp/chost.o tcp/tcp-session.o \
tcp/nilist.o \
tools/integrator.o tools/queue-monitor.o \
tools/flowmon.o tools/loss-monitor.o \
queue/queue.o queue/drop-tail.o \
adc/simple-intserv-sched.o queue/red.o \
queue/semantic-packetqueue.o queue/semantic-red.o \
tcp/ack-recons.o \
queue/sfq.o queue/fq.o queue/drr.o queue/srr.o queue/cbq.o \
link/hackloss.o queue/errmodel.o queue/fec.o\
link/delay.o tcp/snoop.o \
gaf/gaf.o \
link/dynalink.o routing/rtProtoDV.o common/net-interface.o \
mcast/ctrMcast.o mcast/mcast_ctrl.o mcast/srm.o \
common/sessionhelper.o queue/delaymodel.o \
mcast/srm-ssm.o mcast/srm-topo.o \
apps/mftp.o apps/mftp_snd.o apps/mftp_rcv.o \
apps/codeword.o \
routing/alloc-address.o routing/address.o \
$(LIB_DIR)int.Vec.o $(LIB_DIR)int.RVec.o \
$(LIB_DIR)dmalloc_support.o \
webcache/http.o webcache/tcp-simple.o webcache/pagepool.o \
webcache/inval-agent.o webcache/tcpapp.o webcache/http-aux.o \
webcache/mcache.o webcache/webtraf.o \
empweb/empweb.o \
empweb/empftp.o \
realaudio/realaudio.o \
mac/lanRouter.o classifier/filter.o \
common/pkt-counter.o \
common/Decapsulator.o common/Encapsulator.o \
common/encap.o \
mac/channel.o mac/mac.o mac/ll.o mac/mac-802_11.o \
mac/mac-802_3.o mac/mac-tdma.o \
mobile/mip.o mobile/mip-reg.o mobile/gridkeeper.o \
mobile/propagation.o mobile/tworayground.o \
mobile/antenna.o mobile/omni-antenna.o \
mobile/shadowing.o mobile/shadowing-vis.o \
common/bi-connector.o common/node.o \
common/mobilenode.o \
mac/arp.o mobile/god.o mobile/dem.o \
mobile/topography.o mobile/modulation.o \
queue/priqueue.o \
mac/phy.o mac/wired-phy.o mac/wireless-phy.o \
mac/mac-timers.o trace/cmu-trace.o mac/varp.o \
dsdv/dsdv.o dsdv/rtable.o queue/rtqueue.o \
routing/rttable.o \
imep/imep.o imep/dest_queue.o imep/imep_api.o \
imep/imep_rt.o imep/rxmit_queue.o imep/imep_timers.o \
imep/imep_util.o imep/imep_io.o \
tora/tora.o tora/tora_api.o tora/tora_dest.o \
tora/tora_io.o tora/tora_logs.o tora/tora_neighbor.o \
dsr/dsragent.o dsr/hdr_sr.o dsr/mobicache.o dsr/path.o \
dsr/requesttable.o dsr/routecache.o dsr/add_sr.o \
dsr/dsr_proto.o dsr/flowstruct.o dsr/linkcache.o \
dsr/simplecache.o dsr/sr_forwarder.o \
aodv/aodv_logs.o aodv/aodv.o \
aodv/aodv_rtable.o aodv/aodv_rqueue.o \
common/ns-process.o \
satellite/satgeometry.o satellite/sathandoff.o \
satellite/satlink.o satellite/satnode.o \
satellite/satposition.o satellite/satroute.o \
satellite/sattrace.o \
rap/raplist.o rap/rap.o rap/media-app.o rap/utilities.o \
common/fsm.o tcp/tcp-abs.o \
diffusion/diffusion.o diffusion/diff_rate.o diffusion/diff_prob.o \
diffusion/diff_sink.o diffusion/flooding.o diffusion/omni_mcast.o \
diffusion/hash_table.o diffusion/routing_table.o diffusion/iflist.o \
tcp/tfrc.o tcp/tfrc-sink.o mobile/energy-model.o apps/ping.o tcp/tcp-rfc793edu.o \
queue/rio.o queue/semantic-rio.o tcp/tcp-sack-rh.o tcp/scoreboard-rh.o \
plm/loss-monitor-plm.o plm/cbr-traffic-PP.o \
linkstate/hdr-ls.o \
mpls/classifier-addr-mpls.o mpls/ldp.o mpls/mpls-module.o \
routing/rtmodule.o classifier/classifier-hier.o \
routing/addr-params.o \
nix/hdr_nv.o nix/classifier-nix.o \
nix/nixnode.o \
routealgo/rnode.o \
routealgo/bfs.o \
routealgo/rbitmap.o \
routealgo/rlookup.o \
routealgo/routealgo.o \
nix/nixvec.o \
nix/nixroute.o \
diffserv/dsred.o diffserv/dsredq.o \
diffserv/dsEdge.o diffserv/dsCore.o \
diffserv/dsPolicy.o diffserv/ew.o\
queue/red-pd.o queue/pi.o queue/vq.o queue/rem.o \
queue/gk.o \
pushback/rate-limit.o pushback/rate-limit-strategy.o \
pushback/ident-tree.o pushback/agg-spec.o \
pushback/logging-data-struct.o \
pushback/rate-estimator.o \
pushback/pushback-queue.o pushback/pushback.o \
common/parentnode.o trace/basetrace.o \
common/simulator.o asim/asim.o \
@V_STLOBJ@
# don't allow comments to follow continuation lines
# mac-csma.o mac-multihop.o\
# sensor-nets/landmark.o mac-simple-wireless.o \
# sensor-nets/tags.o sensor-nets/sensor-query.o \
# sensor-nets/flood-agent.o \
# what was here before is now in emulate/
OBJ_C =
OBJ_COMPAT = $(OBJ_GETOPT) common/win32.o
#XXX compat/win32x.o compat/tkConsole.o
OBJ_EMULATE_CC = \
emulate/net-ip.o \
emulate/net.o \
emulate/tap.o \
emulate/ether.o \
emulate/internet.o \
emulate/ping_responder.o \
emulate/arp.o \
emulate/icmp.o \
emulate/net-pcap.o \
emulate/nat.o \
emulate/iptap.o \
emulate/tcptap.o
OBJ_EMULATE_C = \
emulate/inet.o
OBJ_GEN = $(GEN_DIR)version.o $(GEN_DIR)ns_tcl.o $(GEN_DIR)ptypes.o
OBJ_PROTOLIB_CPP = \
protolib/ns/nsProtoAgent.o protolib/common/protoSim.o \
protolib/common/networkAddress.o protolib/common/protocolTimer.o \
protolib/common/debug.o
OBJ_MDP_CPP = \
mdp/ns/nsMdpAgent.o mdp/common/mdpSimAgent.o \
mdp/common/mdpBitMask.o mdp/common/mdpMessage.o \
mdp/common/mdpEncoder.o mdp/common/galois.o \
mdp/common/mdpSession.o mdp/common/mdpMsgHandler.o \
mdp/common/mdpNode.o mdp/common/mdpObject.o \
mdp/unix/mdpFile.o
OBJ_NORM_CPP = \
norm/ns/nsNormAgent.o norm/common/normSimAgent.o \
norm/common/normMessage.o norm/common/normSession.o \
norm/common/normNode.o norm/common/normObject.o \
norm/common/normSegment.o norm/common/normBitmask.o \
norm/common/normEncoder.o norm/common/galois.o \
norm/common/normFile.o
OBJ_CPP = $(OBJ_PROTOLIB_CPP) $(OBJ_MDP_CPP) $(OBJ_NORM_CPP)
SRC = $(OBJ_C:.o=.c) $(OBJ_CC:.o=.cc) $(OBJ_CPP:.o=.cpp) \
$(OBJ_EMULATE_C:.o=.c) $(OBJ_EMULATE_CC:.o=.cc) \
common/tclAppInit.cc common/tkAppInit.cc
OBJ = $(OBJ_C) $(OBJ_CC) $(OBJ_GEN) $(OBJ_COMPAT) $(OBJ_CPP)
CLEANFILES = ns nse nsx ns.dyn $(OBJ) $(OBJ_EMULATE_CC) \
$(OBJ_EMULATE_C) common/tclAppInit.o \
$(GEN_DIR)* $(NS).core core core.$(NS) core.$(NSX) core.$(NSE) \
common/ptypes2tcl common/ptypes2tcl.o
SUBDIRS=\
indep-utils/cmu-scen-gen/setdest \
indep-utils/webtrace-conv/dec \
indep-utils/webtrace-conv/epa \
indep-utils/webtrace-conv/nlanr \
indep-utils/webtrace-conv/ucb
BUILD_NSE = @build_nse@
all: $(NS) $(BUILD_NSE) all-recursive
all-recursive:
for i in $(SUBDIRS); do ( cd $$i; $(MAKE) all; ) done
$(NS): $(OBJ) common/tclAppInit.o Makefile
$(LINK) $(LDFLAGS) $(LDOUT)$@ \
common/tclAppInit.o $(OBJ) $(LIB)
Makefile: Makefile.in
@echo "Makefile.in is newer than Makefile."
@echo "You need to re-run configure."
false
$(NSE): $(OBJ) common/tclAppInit.o $(OBJ_EMULATE_CC) $(OBJ_EMULATE_C)
$(LINK) $(LDFLAGS) $(LDOUT)$@ \
common/tclAppInit.o $(OBJ) \
$(OBJ_EMULATE_CC) $(OBJ_EMULATE_C) $(LIB)
ns.dyn: $(OBJ) common/tclAppInit.o
$(LINK) $(LDFLAGS) -o $@ \
common/tclAppInit.o $(OBJ) $(LIB)
PURIFY = purify -cache-dir=/tmp
ns-pure: $(OBJ) common/tclAppInit.o
$(PURIFY) $(LINK) $(LDFLAGS) -o $@ \
common/tclAppInit.o $(OBJ) $(LIB)
NS_TCL_LIB = \
tcl/lib/ns-compat.tcl \
tcl/lib/ns-default.tcl \
tcl/lib/ns-errmodel.tcl \
tcl/lib/ns-lib.tcl \
tcl/lib/ns-link.tcl \
tcl/lib/ns-mobilenode.tcl \
tcl/lib/ns-sat.tcl \
tcl/lib/ns-cmutrace.tcl \
tcl/lib/ns-node.tcl \
tcl/lib/ns-rtmodule.tcl \
tcl/lib/ns-hiernode.tcl \
tcl/lib/ns-packet.tcl \
tcl/lib/ns-queue.tcl \
tcl/lib/ns-source.tcl \
tcl/lib/ns-nam.tcl \
tcl/lib/ns-trace.tcl \
tcl/lib/ns-agent.tcl \
tcl/lib/ns-random.tcl \
tcl/lib/ns-namsupp.tcl \
tcl/lib/ns-address.tcl \
tcl/lib/ns-intserv.tcl \
tcl/lib/ns-autoconf.tcl \
tcl/rtp/session-rtp.tcl \
tcl/lib/ns-mip.tcl \
tcl/rtglib/dynamics.tcl \
tcl/rtglib/route-proto.tcl \
tcl/rtglib/algo-route-proto.tcl \
tcl/rtglib/ns-rtProtoLS.tcl \
tcl/interface/ns-iface.tcl \
tcl/mcast/BST.tcl \
tcl/mcast/ns-mcast.tcl \
tcl/mcast/McastProto.tcl \
tcl/mcast/DM.tcl \
tcl/mcast/srm.tcl \
tcl/mcast/srm-adaptive.tcl \
tcl/mcast/srm-ssm.tcl \
tcl/mcast/timer.tcl \
tcl/mcast/McastMonitor.tcl \
tcl/mcast/mftp_snd.tcl \
tcl/mcast/mftp_rcv.tcl \
tcl/mcast/mftp_rcv_stat.tcl \
tcl/mobility/dsdv.tcl \
tcl/mobility/dsr.tcl \
tcl/ctr-mcast/CtrMcast.tcl \
tcl/ctr-mcast/CtrMcastComp.tcl \
tcl/ctr-mcast/CtrRPComp.tcl \
tcl/rlm/rlm.tcl \
tcl/rlm/rlm-ns.tcl \
tcl/session/session.tcl \
tcl/lib/ns-route.tcl \
tcl/emulate/ns-emulate.tcl \
tcl/lan/vlan.tcl \
tcl/lan/abslan.tcl \
tcl/lan/ns-ll.tcl \
tcl/lan/ns-mac.tcl \
tcl/webcache/http-agent.tcl \
tcl/webcache/http-server.tcl \
tcl/webcache/http-cache.tcl \
tcl/webcache/http-mcache.tcl \
tcl/webcache/webtraf.tcl \
tcl/webcache/empweb.tcl \
tcl/webcache/empftp.tcl \
tcl/plm/plm.tcl \
tcl/plm/plm-ns.tcl \
tcl/plm/plm-topo.tcl \
tcl/mpls/ns-mpls-classifier.tcl \
tcl/mpls/ns-mpls-ldpagent.tcl \
tcl/mpls/ns-mpls-node.tcl \
tcl/mpls/ns-mpls-simulator.tcl \
tcl/lib/ns-pushback.tcl \
tcl/lib/ns-srcrt.tcl \
@V_NS_TCL_LIB_STL@
$(GEN_DIR)ns_tcl.cc: $(NS_TCL_LIB)
$(TCLSH) bin/tcl-expand.tcl tcl/lib/ns-lib.tcl @V_NS_TCL_LIB_STL@ | $(TCL2C) et_ns_lib > $@
$(GEN_DIR)version.c: VERSION
$(RM) $@
$(TCLSH) bin/string2c.tcl version_string < VERSION > $@
$(GEN_DIR)ptypes.cc: common/ptypes2tcl common/packet.h
./common/ptypes2tcl > $@
common/ptypes2tcl: common/ptypes2tcl.o
$(LINK) $(LDFLAGS) $(LDOUT)$@ common/ptypes2tcl.o
common/ptypes2tcl.o: common/ptypes2tcl.cc common/packet.h
install: force install-ns install-man install-recursive
install-ns: force
$(INSTALL) -m 555 -o bin -g bin ns $(DESTDIR)$(BINDEST)
install-man: force
$(INSTALL) -m 444 -o bin -g bin ns.1 $(DESTDIR)$(MANDEST)/man1
install-recursive: force
for i in $(SUBDIRS); do ( cd $$i; $(MAKE) install; ) done
clean:
$(RM) $(CLEANFILES)
AUTOCONF_GEN = tcl/lib/ns-autoconf.tcl
distclean:
$(RM) $(CLEANFILES) Makefile config.cache config.log config.status \
gnuc.h os-proto.h $(AUTOCONF_GEN); \
$(MV) .configure .configure- ;\
echo "Moved .configure to .configure-"
tags: force
ctags -wtd *.cc *.h webcache/*.cc webcache/*.h dsdv/*.cc dsdv/*.h \
dsr/*.cc dsr/*.h webcache/*.cc webcache/*.h lib/*.cc lib/*.h \
../Tcl/*.cc ../Tcl/*.h
TAGS: force
etags *.cc *.h webcache/*.cc webcache/*.h dsdv/*.cc dsdv/*.h \
dsr/*.cc dsr/*.h webcache/*.cc webcache/*.h lib/*.cc lib/*.h \
../Tcl/*.cc ../Tcl/*.h
tcl/lib/TAGS: force
( \
cd tcl/lib; \
$(TCLSH) ../../bin/tcl-expand.tcl ns-lib.tcl | grep '^### tcl-expand.tcl: begin' | awk '{print $$5}' >.tcl_files; \
etags --lang=none -r '/^[ \t]*proc[ \t]+\([^ \t]+\)/\1/' `cat .tcl_files`; \
etags --append --lang=none -r '/^\([A-Z][^ \t]+\)[ \t]+\(instproc\|proc\)[ \t]+\([^ \t]+\)[ \t]+/\1::\3/' `cat .tcl_files`; \
)
depend: $(SRC)
$(MKDEP) $(CFLAGS) $(INCLUDES) $(SRC)
srctar:
@cwd=`pwd` ; dir=`basename $$cwd` ; \
name=ns-`cat VERSION | tr A-Z a-z` ; \
tar=ns-src-`cat VERSION`.tar.gz ; \
list="" ; \
for i in `cat FILES` ; do list="$$list $$name/$$i" ; done; \
echo \
"(rm -f $$tar; cd .. ; ln -s $$dir $$name)" ; \
(rm -f $$tar; cd .. ; ln -s $$dir $$name) ; \
echo \
"(cd .. ; tar cfh $$tar [lots of files])" ; \
(cd .. ; tar cfh - $$list) | gzip -c > $$tar ; \
echo \
"rm ../$$name; chmod 444 $$tar" ; \
rm ../$$name; chmod 444 $$tar
force:
test: force
./validate
# Create makefile.vc for Win32 development by replacing:
# "# !include ..." -> "!include ..."
makefile.vc: Makefile.in
$(PERL) bin/gen-vcmake.pl < Makefile.in > makefile.vc
# $(PERL) -pe 's/^# (\!include)/\!include/o' < Makefile.in > makefile.vc

View File

@ -39,17 +39,18 @@ static class NsNormAgentClass : public TclClass
{ {
public: public:
NsNormAgentClass() : TclClass("Agent/NORM") {} NsNormAgentClass() : TclClass("Agent/NORM") {}
TclObject *create(int argc, const char*const* argv) TclObject* create(int argc, const char*const* argv)
{return (new NsNormAgent());} {return (new NsNormAgent());}
} class_norm_agent; } class_norm_agent;
NsNormAgent::NsNormAgent() NsNormAgent::NsNormAgent()
: NormSimAgent(ProtoSimAgent::TimerInstaller,
static_cast<ProtoSimAgent*>(this),
ProtoSimAgent::SocketInstaller,
static_cast<ProtoSimAgent*>(this))
{ {
NormSimAgent::Init(ProtoSimAgent::TimerInstaller,
static_cast<ProtoSimAgent*>(this),
ProtoSimAgent::SocketInstaller,
static_cast<ProtoSimAgent*>(this));
} }
NsNormAgent::~NsNormAgent() NsNormAgent::~NsNormAgent()
@ -62,6 +63,42 @@ int NsNormAgent::command(int argc, const char*const* argv)
int i = 1; int i = 1;
while (i < argc) while (i < argc)
{ {
// Intercept ns-specific commands
if (!strcmp(argv[i], "attach-mgen"))
{
// (TBD) this could be done as a generic NormSimAgent command
// Attach Agent/MGEN to this NormSimAgent
if (++i >= argc)
{
DMSG(0, "NsNormAgent::command() ProcessCommand(attach-mgen) error: insufficent arguments\n");
return TCL_ERROR;
}
Tcl& tcl = Tcl::instance();
NsMgenAgent* mgenAgent = dynamic_cast<NsMgenAgent*> (tcl.lookup(argv[i]));
if (mgenAgent)
{
AttachMgen(mgenAgent->GetMgenInstance());
i++;
continue;
}
else
{
DMSG(0, "NsNormAgent::command() ProcessCommand(attach-mgen) error: invalid mgen agent\n");
return TCL_ERROR;
}
}
else if (!strcmp(argv[i], "active"))
{
// query agent's current state of activity
Tcl& tcl = Tcl::instance();
if (IsActive())
sprintf(tcl.result(), "on");
else
sprintf(tcl.result(), "off");
i++;
continue;
}
// Other commands are interpreted by the NormSimAgent base class
NormSimAgent::CmdType cmdType = CommandType(argv[i]); NormSimAgent::CmdType cmdType = CommandType(argv[i]);
switch (cmdType) switch (cmdType)
{ {
@ -92,6 +129,13 @@ int NsNormAgent::command(int argc, const char*const* argv)
return TCL_OK; return TCL_OK;
} // end NsNormAgent::command() } // end NsNormAgent::command()
bool NsNormAgent::SendMgenMessage(const NetworkAddress* dstAddr,
const char* txBuffer,
unsigned int len)
{
return SendMessage(len, txBuffer);
} // end NsNormAgent::SendMgenMessage()

View File

@ -36,21 +36,28 @@
#include "nsProtoAgent.h" // from ProtoLib #include "nsProtoAgent.h" // from ProtoLib
#include "normSimAgent.h" #include "normSimAgent.h"
// The "NsNormAgent" is based on the ns agent class. #include "nsMgenAgent.h"
// The "NsProtoAgent" is based on the ns Agent class.
// This lets us have a send/recv attachment to the NS // This lets us have a send/recv attachment to the NS
// simulation environment // simulation environment
// IMPORTANT NOTE! NsProtoAgent must be listed _first_ here // IMPORTANT NOTE! NsProtoAgent must be listed _first_ here
// (because we can't dynamic_cast install_data void* pointers) // (because we can't dynamic_cast install_data void* pointers)
class NsNormAgent : public NormSimAgent, public NsProtoAgent class NsNormAgent : public NsProtoAgent, public NormSimAgent, public MgenSink
{ {
public: public:
NsNormAgent(); NsNormAgent();
~NsNormAgent(); ~NsNormAgent();
// NsProtoAgent base class overrides // NsProtoAgent base class override
int command(int argc, const char*const* argv); int command(int argc, const char*const* argv);
unsigned long GetAgentId() {return (unsigned long)addr();} // NormSimAgent override
unsigned long GetAgentId() {return (unsigned long)addr();}
// MgenSink override
bool SendMgenMessage(const NetworkAddress* dstAddr,
const char* txBuffer,
unsigned int len);
}; // end class NsNormAgent }; // end class NsNormAgent

View File

@ -10,46 +10,47 @@ set backoffFactor "4.0"
set sendRate "64kb" set sendRate "64kb"
set duration "120.0" set duration "120.0"
set nsTracing 0 set nsTracing 0
set unicastNacks "off"
set cc "off"
#Parse optionList for parameters #Parse optionList for parameters
set state flag set state "flag"
foreach option $optionList { foreach option $optionList {
if {"flag" != $state} {
set reset true
} else {
set reset false
}
switch -- $state { switch -- $state {
"flag" { "flag" {
switch -glob -- $option { switch -glob -- $option {
"gsize" {set state "gsize"} "unicast" {set unicastNacks "on"}
"rate" {set state "rate"} "cc" {set cc "on"}
"backoff" {set state "backoff"}
"duration" {set state "duration"}
"trace" {set nsTracing 1} "trace" {set nsTracing 1}
default {error "simplenorm: Bad option argument $option"} default {set state $option}
} }
} }
"gsize" { "gsize" {
set groupSize $option set groupSize $option
set state "flag"
} }
"backoff" { "backoff" {
set backoffFactor $option set backoffFactor $option
set state "flag"
} }
"rate" { "rate" {
set sendRate $option set sendRate $option
set state "flag"
} }
"duration" { "duration" {
set duration $option set duration $option
set state "flag"
} }
default { default {
error "simplenorm: Bad option parse state!" error "simplenorm: bad option: $state"
} }
} }
if {$reset == "true"} {set state "flag"}
} }
# 1) An ns-2 simulator instance is created an configured # 1) An ns-2 simulator instance is created an configured
# for multicast operation with a dense mode (DM) multicast # for multicast operation with a dense mode (DM) multicast
# routing protocol: # routing protocol:
@ -87,6 +88,7 @@ for {set i 1} {$i <= $numNodes} {incr i} {
puts "simplenorm: Creating spoke links ..." puts "simplenorm: Creating spoke links ..."
set linkRate [expr $groupSize * [bw_parse $sendRate]] set linkRate [expr $groupSize * [bw_parse $sendRate]]
puts "simplenorm: linkRate = [expr $linkRate / 1000.0] kbps"
for {set i 1} {$i <= $numNodes} {incr i} { for {set i 1} {$i <= $numNodes} {incr i} {
$ns_ duplex-link $n(0) $n($i) $linkRate 100ms DropTail $ns_ duplex-link $n(0) $n($i) $linkRate 100ms DropTail
$ns_ queue-limit $n(0) $n($i) 100 $ns_ queue-limit $n(0) $n($i) 100
@ -108,26 +110,28 @@ puts "simplenorm: Configuring NORM agents ..."
# 6) Configure global NORM agent commands (using norm(1)) # 6) Configure global NORM agent commands (using norm(1))
$norm(1) debug 2 $norm(1) debug 2
$norm(1) log normLog.txt #$norm(1) log normLog.txt
# 7) Configure NORM server agent at node 1 # 7) Configure NORM server agent at node 1
$norm(1) address $group/5000 $norm(1) address $group/5000
$norm(1) rate [bw_parse $sendRate] $norm(1) rate [bw_parse $sendRate]
$norm(1) backoff $backoffFactor $norm(1) backoff $backoffFactor
$norm(1) parity 0 $norm(1) parity 0
$norm(1) repeat -1 $norm(1) repeat 50
$norm(1) interval 0.0 $norm(1) interval 0.0
$norm(1) txloss 10.0 $norm(1) txloss 10.0
$norm(1) gsize $groupSize $norm(1) gsize $groupSize
#$norm(1) trace $norm(1) cc off
#$norm(1) trace on
# 8) Configure NORM client agents at other nodes # 8) Configure NORM client agents at other nodes
for {set i 2} {$i <= $numNodes} {incr i} { for {set i 2} {$i <= $numNodes} {incr i} {
$norm($i) address $group/5000 $norm($i) address $group/5000
$norm($i) backoff $backoffFactor $norm($i) backoff $backoffFactor
$norm($i) rxbuffer 100000 $norm($i) rxbuffer 1000000
$norm($i) txloss 10.0 #$norm($i) txloss 10.0
$norm($i) gsize $groupSize $norm($i) gsize $groupSize
$norm($i) unicastNacks $unicastNacks
#$norm($i) trace #$norm($i) trace
} }

View File

@ -8,7 +8,7 @@ set rate 32kb
set duration 120.0 set duration 120.0
set backoff 4.0 set backoff 4.0
set fileName "results.gp" set fileName "supress.gp"
exec rm -f $fileName exec rm -f $fileName
@ -20,8 +20,12 @@ puts $outFile "set xlabel 'Number of Receivers'"
puts $outFile "set ylabel 'NACK Transmission Fraction'" puts $outFile "set ylabel 'NACK Transmission Fraction'"
puts $outFile "plot \\" puts $outFile "plot \\"
puts $outFile "'-' using 1:2 \\" puts $outFile "'-' using 1:2 \\"
puts $outFile "'Receivers:%lf alpha:%lf' t 'Theoretical Multicast Nacking', \\" puts $outFile "'Receivers:%lf alpha:%lf' t 'Theoretical Unicast Nacking', \\"
puts $outFile "'-' using 1:2 \\" puts $outFile "'-' using 1:2 \\"
puts $outFile "'Receivers:%lf alpha:%lf' t 'Theoretical Multicast Nacking', \\"
puts $outFile "'-' using 1:4 \\"
puts $outFile "'Receivers:%lf Sent:%lf Suppressed:%lf alpha:%lf' t 'Measured Unicast Nacking', \\"
puts $outFile "'-' using 1:4 \\"
puts $outFile "'Receivers:%lf Sent:%lf Suppressed:%lf alpha:%lf' t 'Measured Multicast Nacking'\n" puts $outFile "'Receivers:%lf Sent:%lf Suppressed:%lf alpha:%lf' t 'Measured Multicast Nacking'\n"
close $outFile close $outFile
@ -29,7 +33,19 @@ puts "Computing theoretical results ..."
# T = number of GRTT for NACK backoff timers ... # T = number of GRTT for NACK backoff timers ...
set T $backoff set T $backoff
# Theoretical Multicast NACK results # Theoretical Unicast NACK suppression results
set outFile [open $fileName "a"]
puts $outFile "#Theoretical Unicast NACK Transmission Fraction"
foreach groupSize $sizeList {
set lambda [expr log($groupSize) + 1.0]
set N [expr exp((1.2/($T)) * ($lambda))]
set alpha [expr $N / $groupSize]
puts $outFile "Receivers:$groupSize alpha:$alpha"
}
puts $outFile "e\n"
close $outFile
# Theoretical Multicast NACK suppression results
set outFile [open $fileName "a"] set outFile [open $fileName "a"]
puts $outFile "#Theoretical Multicast NACK Transmission Fraction" puts $outFile "#Theoretical Multicast NACK Transmission Fraction"
foreach groupSize $sizeList { foreach groupSize $sizeList {
@ -41,6 +57,19 @@ foreach groupSize $sizeList {
puts $outFile "e\n" puts $outFile "e\n"
close $outFile close $outFile
# Measured Unicast NACK results
set outFile [open $fileName "a"]
puts $outFile "#Measured Unicast NACK Transmission Fraction"
close $outFile
foreach groupSize $sizeList {
puts "Starting simulation run for groupSize:$groupSize ..."
puts " ns simplenorm.tcl unicast gsize $groupSize backoff $backoff rate $rate duration $duration"
catch {eval exec ns simplenorm.tcl unicast gsize $groupSize backoff $backoff rate $rate duration $duration}
puts " cat normLog.txt | nc >> $fileName"
catch {eval exec cat normLog.txt | nc >> $fileName}
}
puts $outFile "e\n"
# Measured Multicast NACK results # Measured Multicast NACK results
set outFile [open $fileName "a"] set outFile [open $fileName "a"]
puts $outFile "#Measured Multicast NACK Transmission Fraction" puts $outFile "#Measured Multicast NACK Transmission Fraction"

View File

@ -13,7 +13,7 @@ NS = ../ns
INCLUDES = $(TCL_INCL_PATH) $(SYSTEM_INCLUDES) -I$(UNIX) -I$(COMMON) -I$(PROTOLIB)/common INCLUDES = $(TCL_INCL_PATH) $(SYSTEM_INCLUDES) -I$(UNIX) -I$(COMMON) -I$(PROTOLIB)/common
CFLAGS = -g -DPROTO_DEBUG -DUNIX -Wall -O -fPIC $(SYSTEM_HAVES) $(INCLUDES) CFLAGS = -g -DPROTO_DEBUG -DUNIX -O -fPIC $(SYSTEM_HAVES) $(INCLUDES)
LDFLAGS = $(SYSTEM_LDFLAGS) LDFLAGS = $(SYSTEM_LDFLAGS)
@ -49,7 +49,7 @@ TARGETS = mdp tkMdp
# MDP depends upon the NRL Protean Group's development library # MDP depends upon the NRL Protean Group's development library
LIBPROTO = $(PROTOLIB)/unix/libProto.a LIBPROTO = $(PROTOLIB)/unix/libProto.a
$(PROTOLIB)/unix/libProto.a: $(PROTOLIB)/unix/libProto.a:
make -C $(PROTOLIB)/unix -f Makefile.common libProto.a cd $(PROTOLIB)/unix; $(MAKE) -f Makefile.$(SYSTEM) libProto.a
NORM_SRC = $(COMMON)/normMessage.cpp $(COMMON)/normSession.cpp \ NORM_SRC = $(COMMON)/normMessage.cpp $(COMMON)/normSession.cpp \
$(COMMON)/normNode.cpp $(COMMON)/normObject.cpp \ $(COMMON)/normNode.cpp $(COMMON)/normObject.cpp \
@ -63,8 +63,8 @@ LIB_SRC = $(NORM_SRC)
LIB_OBJ = $(LIB_SRC:.cpp=.o) LIB_OBJ = $(LIB_SRC:.cpp=.o)
libnorm.a: $(LIB_OBJ) libnorm.a: $(LIB_OBJ)
ar rcv $@ $(LIB_OBJ) $(AR) rcv $@ $(LIB_OBJ)
ranlib $@ $(RANLIB) $@
.cpp-sim.o: .cpp-sim.o:
$(CC) -c $(CFLAGS) -DSIMULATE -o $*-sim.o $*.cpp $(CC) -c $(CFLAGS) -DSIMULATE -o $*-sim.o $*.cpp
@ -77,15 +77,15 @@ libnormSim.a: $(SIM_OBJ)
ranlib $@ ranlib $@
# (mdp) command-line file broadcaster/receiver # (mdp) command-line file broadcaster/receiver
APP_SRC = $(COMMON)/normApp.cpp APP_SRC = $(COMMON)/normApp.cpp $(COMMON)/normPostProcess.cpp
APP_OBJ = $(APP_SRC:.cpp=.o) APP_OBJ = $(APP_SRC:.cpp=.o)
norm: $(APP_OBJ) libnorm.a $(LIBPROTO) norm: $(APP_OBJ) libnorm.a $(LIBPROTO)
$(CC) $(CFLAGS) -o $@ $(APP_OBJ) $(LDFLAGS) $(LIBS) libnorm.a $(LIBPROTO) $(CC) $(CFLAGS) -o $@ $(APP_OBJ) $(LDFLAGS) libnorm.a $(LIBPROTO) $(LIBS)
clean: clean:
rm -f $(COMMON)/*.o $(UNIX)/*.o $(UNIX)/libnorm.a $(UNIX)/norm $(NS)/*.o; rm -f $(COMMON)/*.o $(UNIX)/*.o $(UNIX)/libnorm.a $(UNIX)/norm $(NS)/*.o;
make -C $(PROTOLIB)/unix -f Makefile.common clean cd $(PROTOLIB)/unix; $(MAKE) -f Makefile.$(SYSTEM) clean
# DO NOT DELETE THIS LINE -- mkdep uses it. # DO NOT DELETE THIS LINE -- mkdep uses it.
# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. # DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.

View File

@ -65,5 +65,7 @@ SYSTEM_LIBS =
export SYSTEM_HAVES = -DHAVE_GETLOGIN -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC) export SYSTEM_HAVES = -DHAVE_GETLOGIN -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC)
export CC = gcc export CC = gcc
export RANLIB = ranlib
export AR = ar
include Makefile.common include Makefile.common

View File

@ -65,5 +65,7 @@ SYTSTEM_LIBS =
export SYSTEM_HAVES = -DHAVE_CUSERID -DHAVE_LOCKF export SYSTEM_HAVES = -DHAVE_CUSERID -DHAVE_LOCKF
export CC = gcc export CC = gcc
export RANLIB = touch
export AR = ar
include Makefile.common include Makefile.common

View File

@ -10,19 +10,19 @@
# 1) Where to find the Tcl standard library scripts # 1) Where to find the Tcl standard library scripts
# (e.g. init.tcl, ...) # (e.g. init.tcl, ...)
TCL_SCRIPT_PATH = /usr/local/lib/tcl8.0 TCL_SCRIPT_PATH = /usr/lib/tcl
# 2) Where to find the Tk standard library scripts # 2) Where to find the Tk standard library scripts
# (e.g. button.tcl, entry.tcl, ...) # (e.g. button.tcl, entry.tcl, ...)
TK_SCRIPT_PATH = /usr/local/lib/tk8.0 TK_SCRIPT_PATH = /usr/lib/tk
# 3) Where to find Tcl/Tk header files # 3) Where to find Tcl/Tk header files
# (e.g. tcl.h, tk.h, ...) # (e.g. tcl.h, tk.h, ...)
TCL_INCL_PATH = -I/usr/local/include TCL_INCL_PATH = -I/usr/local/include
# 4) Point to specific libtcl.a and libtk.a to use # 4) Point to specific libtcl.a and libtk.a to use
TCL_LIB = /usr/local/lib/libtcl8.0.a TCL_LIB = -ltcl #/usr/local/lib/libtcl8.0.a
TK_LIB = /usr/local/lib/libtk8.0.a TK_LIB = -ltk #/usr/local/lib/libtk8.0.a
# 5) System specific additional libraries, include paths, etc # 5) System specific additional libraries, include paths, etc
@ -66,5 +66,7 @@ export SYSTEM_HAVES = -DLINUX -DHAVE_IPV6 -DHAVE_GETLOGIN -DHAVE_LOCKF \
-DHAVE_OLD_SIGNALHANDLER -DHAVE_DIRFD -DHAVE_ASSERT $(NETSEC) -DHAVE_OLD_SIGNALHANDLER -DHAVE_DIRFD -DHAVE_ASSERT $(NETSEC)
export CC = gcc export CC = gcc
export RANLIB = ranlib
export AR = ar
include Makefile.common include Makefile.common

View File

@ -1,38 +1,15 @@
# #
# MacOS X Protean Makefile definitions # Protean MacOS X (Darwin) Makefile definitions
# #
# TO BUILD THE TK GUI VERSION, EDIT THE FOLLOWING NUMBERED # 1) System specific additional libraries, include paths, etc
# 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) # (Where to find X11 libraries, etc)
# #
SYSTEM_INCLUDES = -I/usr/X11R6/include SYSTEM_INCLUDES = -I/usr/X11R6/include
SYSTEM_LDFLAGS = -L/usr/X11R6/lib SYSTEM_LDFLAGS = -L/usr/X11R6/lib
SYSTEM_LIBS = SYSTEM_LIBS =
# 6) System specific capabilities # 2) System specific capabilities
# Must choose appropriate for the following: # Must choose appropriate for the following:
# #
# A) -DHAVE_CUSERID (preferred) or -DHAVE_GETLOGIN for cuserid() or getlogin() # A) -DHAVE_CUSERID (preferred) or -DHAVE_GETLOGIN for cuserid() or getlogin()
@ -48,22 +25,20 @@ SYSTEM_LIBS =
# D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT() # D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT()
# routine. # routine.
# #
# E) The MDP code's use of offset pointers requires special treatment # E) Some systems (SOLARIS/SUNOS) have a few gotchas which require
# 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 # some #ifdefs to avoid compiler warnings ... so you might need
# to specify -DSOLARIS or -DSUNOS depending on your OS. # to specify -DSOLARIS or -DSUNOS depending on your OS.
# #
# G) Uncomment this if you have the NRL IPv6+IPsec software # F) Uncomment this if you have the NRL IPv6+IPsec software
#DNETSEC = -DNETSEC -I/usr/inet6/include #DNETSEC = -DNETSEC -I/usr/inet6/include
# #
# (We export these for other Makefiles as needed) # (We export these for other Makefiles as needed)
# #
export SYSTEM_HAVES = -DHAVE_ASSERT -DHAVE_GETLOGIN -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC) export SYSTEM_HAVES = -DHAVE_ASSERT -DHAVE_GETLOGIN -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC) -DSOCKLEN_T=int
export CC = cc export CC = g++
export RANLIB = ranlib
export AR = ar
include Makefile.common include Makefile.common

View File

@ -66,6 +66,8 @@ SYSTEM_LIBS = -ldl
export SYSTEM_HAVES = -DHAVE_CUSERID -DHAVE_LOCKF -DHAVE_DIRFD $(NETSEC) export SYSTEM_HAVES = -DHAVE_CUSERID -DHAVE_LOCKF -DHAVE_DIRFD $(NETSEC)
export CC = gcc export CC = gcc
export RANLIB = ranlib
export AR = ar
include Makefile.common include Makefile.common

View File

@ -62,8 +62,10 @@ SYSTEM_LIBS =
# (We export these for other Makefiles as needed) # (We export these for other Makefiles as needed)
# #
export SYSTEM_HAVES = -DHAVE_GETLOGIN -DHAVE_ASSERT -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC) export SYSTEM_HAVES = -DHAVE_GETLOGIN -DHAVE_ASSERT -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC)
export CC = gcc export CC = gcc
export RANLIB = ranlib
export AR = ar
include Makefile.common include Makefile.common

View File

@ -1,34 +1,13 @@
# #
# MDPv2 IRIX Makefile # IRIX 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 # 1) System specific additional libraries, include paths, etc
# (Where to find X11 libraries, etc) # (Where to find X11 libraries, etc)
# #
SYSTEM_INCLUDES = SYSTEM_INCLUDES = -DIRIX -n32 -woff 3333 -cfront
SYSTEM_LDFLAGS = SYSTEM_LDFLAGS =
SYSTEM_LIBS = SYSTEM_LIBS =
@ -59,11 +38,17 @@ SYSTEM_LIBS =
# G) Uncomment this if you have the NRL IPv6+IPsec software # G) Uncomment this if you have the NRL IPv6+IPsec software
#DNETSEC = -DNETSEC -I/usr/inet6/include #DNETSEC = -DNETSEC -I/usr/inet6/include
# #
# (We export these for other Makefiles as needed)
# #
export SYSTEM_HAVES = -DUSE_INHERITANCE -DHAVE_CUSERID -DHAVE_LOCKF $(NETSEC) SYSTEM_HAVES = -DHAVE_IPV6 -DHAVE_GETLOGIN -DHAVE_LOCKF \
-DHAVE_DIRFD -DHAVE_ASSERT $(NETSEC)
export CC = gcc SYSTEM_SRC =
SYSTEM = sgi
CC = CC
RANLIB = touch
AR = ar
include Makefile.common include Makefile.common

View File

@ -63,5 +63,7 @@ SYSTEM_LIBS = -ldl -lnsl -lsocket
export SYSTEM_HAVES = -DHAVE_ASSERT -DHAVE_CUSERID -DHAVE_LOCKF $(NETSEC) -DSOLARIS export SYSTEM_HAVES = -DHAVE_ASSERT -DHAVE_CUSERID -DHAVE_LOCKF $(NETSEC) -DSOLARIS
export CC = gcc export CC = gcc
export RANLIB = touch
export AR = ar
include Makefile.common include Makefile.common

View File

@ -63,6 +63,8 @@ SYSTEM_LIBS = -ldl -lnsl -lsocket
export SYSTEM_HAVES = -DHAVE_ASSERT -DHAVE_CUSERID -DHAVE_LOCKF $(NETSEC) -DSOLARIS export SYSTEM_HAVES = -DHAVE_ASSERT -DHAVE_CUSERID -DHAVE_LOCKF $(NETSEC) -DSOLARIS
export CC = gcc export CC = gcc
export RANLIB = touch
export AR = ar
include Makefile.common include Makefile.common