v1.0b2
parent
3456db14f2
commit
d0417b042a
|
|
@ -35,9 +35,9 @@
|
|||
|
||||
namespace Norm
|
||||
{
|
||||
extern const unsigned char GINV[256];
|
||||
extern const unsigned char GEXP[512];
|
||||
extern const unsigned char GMULT[256][256];
|
||||
extern const unsigned char GINV[256];
|
||||
extern const unsigned char GEXP[512];
|
||||
extern const unsigned char GMULT[256][256];
|
||||
}
|
||||
inline unsigned char gexp(unsigned int x) {return Norm::GEXP[x];}
|
||||
inline unsigned char gmult(unsigned int x, unsigned int y) {return Norm::GMULT[x][y];}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@
|
|||
|
||||
#include "protoLib.h"
|
||||
#include "normSession.h"
|
||||
#include "normPostProcess.h"
|
||||
|
||||
#include <stdio.h> // for stdout/stderr printouts
|
||||
#include <signal.h> // for SIGTERM/SIGINT handling
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
// Command-line application using Protolib EventDispatcher
|
||||
class NormApp : public NormController
|
||||
{
|
||||
|
|
@ -23,7 +23,13 @@ class NormApp : public NormController
|
|||
bool ProcessCommand(const char* cmd, const char* val);
|
||||
bool ParseCommandLine(int argc, char* argv[]);
|
||||
|
||||
static void DoInputReady(EventDispatcher::Descriptor descriptor,
|
||||
EventDispatcher::EventType theEvent,
|
||||
const void* userData);
|
||||
|
||||
private:
|
||||
void OnInputReady();
|
||||
|
||||
enum CmdType {CMD_INVALID, CMD_NOARG, CMD_ARG};
|
||||
CmdType CommandType(const char* cmd);
|
||||
|
||||
|
|
@ -40,41 +46,62 @@ class NormApp : public NormController
|
|||
static const char* const cmd_list[];
|
||||
|
||||
static void SignalHandler(int sigNum);
|
||||
bool IsPostProcessing() {return post_processor.IsActive();}
|
||||
void HandleSIGCHLD() {post_processor.HandleSIGCHLD();}
|
||||
|
||||
EventDispatcher dispatcher;
|
||||
NormSessionMgr session_mgr;
|
||||
NormSession* session;
|
||||
NormStreamObject* stream;
|
||||
NormStreamObject* tx_stream;
|
||||
NormStreamObject* rx_stream;
|
||||
|
||||
// application parameters
|
||||
FILE* input; // input stream
|
||||
FILE* output; // output stream
|
||||
char input_buffer[512];
|
||||
char input_buffer[1250];
|
||||
unsigned int input_index;
|
||||
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
|
||||
UINT16 port; // session port number
|
||||
UINT8 ttl;
|
||||
double tx_rate; // bits/sec
|
||||
bool cc_enable;
|
||||
|
||||
// NormSession server-only parameters
|
||||
UINT16 segment_size;
|
||||
UINT8 ndata;
|
||||
UINT8 nparity;
|
||||
UINT8 auto_parity;
|
||||
UINT8 extra_parity;
|
||||
double backoff_factor;
|
||||
unsigned long tx_buffer_size; // bytes
|
||||
unsigned long rx_buffer_size; // bytes
|
||||
|
||||
NormFileList tx_file_list;
|
||||
double tx_object_interval;
|
||||
int tx_repeat_count;
|
||||
double tx_repeat_interval;
|
||||
NormFileList rx_file_cache;
|
||||
char* rx_cache_path;
|
||||
|
||||
ProtocolTimer interval_timer;
|
||||
|
||||
// protocol debug parameters
|
||||
// NormSession client-only parameters
|
||||
unsigned long rx_buffer_size; // bytes
|
||||
NormFileList rx_file_cache;
|
||||
char* rx_cache_path;
|
||||
NormPostProcessor post_processor;
|
||||
bool unicast_nacks;
|
||||
bool silent_client;
|
||||
|
||||
// Debug parameters
|
||||
bool tracing;
|
||||
double tx_loss;
|
||||
double rx_loss;
|
||||
|
|
@ -82,13 +109,16 @@ class NormApp : public NormController
|
|||
}; // end class NormApp
|
||||
|
||||
NormApp::NormApp()
|
||||
: session(NULL), stream(NULL), input(NULL), output(NULL),
|
||||
input_index(0), input_length(0),
|
||||
address(NULL), port(0), ttl(3), tx_rate(64000.0),
|
||||
segment_size(1024), ndata(32), nparity(16), auto_parity(0),
|
||||
tx_buffer_size(1024*1024), rx_buffer_size(1024*1024),
|
||||
: session(NULL), tx_stream(NULL), rx_stream(NULL), input(NULL), output(NULL),
|
||||
input_index(0), input_length(0), input_active(false),
|
||||
push_stream(false), input_messaging(false), input_msg_length(0), input_msg_index(0),
|
||||
output_index(0), output_messaging(false), output_msg_length(0), output_msg_sync(false),
|
||||
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),
|
||||
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)
|
||||
{
|
||||
// Init tx_timer for 1.0 second interval, infinite repeats
|
||||
|
|
@ -97,6 +127,10 @@ NormApp::NormApp()
|
|||
this);
|
||||
interval_timer.Init(0.0, 0, (ProtocolTimerOwner*)this,
|
||||
(ProtocolTimeoutFunc)&NormApp::OnIntervalTimeout);
|
||||
|
||||
struct timeval currentTime;
|
||||
GetSystemTime(¤tTime);
|
||||
srand(currentTime.tv_usec);
|
||||
}
|
||||
|
||||
NormApp::~NormApp()
|
||||
|
|
@ -108,27 +142,36 @@ NormApp::~NormApp()
|
|||
|
||||
const char* const NormApp::cmd_list[] =
|
||||
{
|
||||
"+debug",
|
||||
"+log",
|
||||
"-trace",
|
||||
"+txloss",
|
||||
"+rxloss",
|
||||
"+address",
|
||||
"+ttl",
|
||||
"+rate",
|
||||
"+input",
|
||||
"+output",
|
||||
"+sendfile",
|
||||
"+interval",
|
||||
"+repeatcount",
|
||||
"+rinterval", // repeat interval
|
||||
"+rxcachedir",
|
||||
"+segment",
|
||||
"+block",
|
||||
"+parity",
|
||||
"+auto",
|
||||
"+txbuffer",
|
||||
"+rxbuffer",
|
||||
"+debug", // debug level
|
||||
"+log", // log file name
|
||||
"-trace", // message tracing on
|
||||
"+txloss", // tx packet loss percent (for testing)
|
||||
"+rxloss", // rx packet loss percent (for testing)
|
||||
"+address", // session destination address
|
||||
"+ttl", // multicast hop count scope
|
||||
"+cc", // congestion control on/off
|
||||
"+rate", // tx date rate (bps)
|
||||
"-push", // push stream writes for real-time messaging
|
||||
"+input", // send stream input
|
||||
"+output", // recv stream output
|
||||
"+minput", // send message stream input
|
||||
"+moutput", // recv message stream output
|
||||
"+sendfile", // file/directory list to transmit
|
||||
"+interval", // delay time (sec) between files (0.0 sec default)
|
||||
"+repeatcount", // How many times to repeat the file/directory list
|
||||
"+rinterval", // Interval (sec) between file/directory list repeats
|
||||
"+rxcachedir", // recv file cache directory
|
||||
"+segment", // payload segment size (bytes)
|
||||
"+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
|
||||
};
|
||||
|
||||
|
|
@ -236,23 +279,90 @@ bool NormApp::ProcessCommand(const char* cmd, const char* val)
|
|||
tx_rate = 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))
|
||||
{
|
||||
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",
|
||||
strerror(errno));
|
||||
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))
|
||||
{
|
||||
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",
|
||||
strerror(errno));
|
||||
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))
|
||||
{
|
||||
|
|
@ -350,6 +460,28 @@ bool NormApp::ProcessCommand(const char* cmd, const char* val)
|
|||
auto_parity = 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))
|
||||
{
|
||||
if (1 != sscanf(val, "%lu", &tx_buffer_size))
|
||||
|
|
@ -366,6 +498,28 @@ bool NormApp::ProcessCommand(const char* cmd, const char* val)
|
|||
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;
|
||||
} // end NormApp::ProcessCommand()
|
||||
|
||||
|
|
@ -436,6 +590,159 @@ bool NormApp::ParseCommandLine(int argc, char* argv[])
|
|||
return true;
|
||||
} // 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,
|
||||
class NormSessionMgr* sessionMgr,
|
||||
class NormSession* session,
|
||||
|
|
@ -447,45 +754,14 @@ void NormApp::Notify(NormController::Event event,
|
|||
case TX_QUEUE_EMPTY:
|
||||
// Write to stream as needed
|
||||
//DMSG(0, "NormApp::Notify(TX_QUEUE_EMPTY) ...\n");
|
||||
if (object && (object == stream))
|
||||
if (object && (object == tx_stream))
|
||||
{
|
||||
bool flush = false;
|
||||
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)
|
||||
if (input) OnInputReady();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Can queue a new object for transmission
|
||||
if (interval_timer.IsActive()) interval_timer.Deactivate();
|
||||
if (interval_timer.Interval() > 0.0)
|
||||
{
|
||||
InstallTimer(&interval_timer);
|
||||
|
|
@ -505,8 +781,23 @@ void NormApp::Notify(NormController::Event event,
|
|||
{
|
||||
case NormObject::STREAM:
|
||||
{
|
||||
const NormObjectSize& size = object->Size();
|
||||
if (!((NormStreamObject*)object)->Accept(size.LSB()))
|
||||
// Only have one rx_stream at a time for now.
|
||||
// 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");
|
||||
}
|
||||
|
|
@ -599,22 +890,95 @@ void NormApp::Notify(NormController::Event event,
|
|||
switch (object->GetType())
|
||||
{
|
||||
case NormObject::FILE:
|
||||
// (TBD) update progress
|
||||
// (TBD) update reception progress display when applicable
|
||||
break;
|
||||
|
||||
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
|
||||
ASSERT(output);
|
||||
char buffer[256];
|
||||
unsigned int nBytes;
|
||||
while ((nBytes = ((NormStreamObject*)object)->Read(buffer, 256)))
|
||||
bool reading = true;
|
||||
bool findMsgSync;
|
||||
while (reading)
|
||||
{
|
||||
unsigned int put = 0;
|
||||
while (put < nBytes)
|
||||
unsigned int readLength;
|
||||
if (output_messaging)
|
||||
{
|
||||
size_t result = fwrite(buffer, sizeof(char), nBytes, output);
|
||||
fflush(output);
|
||||
if (output_msg_length)
|
||||
{
|
||||
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)
|
||||
{
|
||||
put += result;
|
||||
|
|
@ -637,22 +1001,35 @@ void NormApp::Notify(NormController::Event event,
|
|||
}
|
||||
}
|
||||
} // end while(put < nBytes)
|
||||
}
|
||||
if (writeLength) memset(output_buffer, 0, writeLength);
|
||||
} // end while (reading)
|
||||
fflush(output);
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
} // end switch (object->GetType())
|
||||
break;
|
||||
|
||||
case RX_OBJECT_COMPLETE:
|
||||
{
|
||||
switch(object->GetType())
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
case NormObject::STREAM:
|
||||
ASSERT(0);
|
||||
|
|
@ -694,12 +1071,15 @@ bool NormApp::OnIntervalTimeout()
|
|||
temp[len] = '\0';
|
||||
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);
|
||||
// Try the next file in the list
|
||||
return OnIntervalTimeout();
|
||||
// Wait a second, then try the next file in the list
|
||||
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);
|
||||
}
|
||||
else if (tx_repeat_count)
|
||||
|
|
@ -738,17 +1118,18 @@ bool NormApp::OnStartup()
|
|||
|
||||
signal(SIGTERM, SignalHandler);
|
||||
signal(SIGINT, SignalHandler);
|
||||
signal(SIGCHLD, SignalHandler);
|
||||
|
||||
// Validate our application settings
|
||||
if (!address)
|
||||
{
|
||||
DMSG(0, "NormApp::OnStartup() Error! no session address given.");
|
||||
DMSG(0, "NormApp::OnStartup() Error! no session address given.\n");
|
||||
return false;
|
||||
}
|
||||
if (!input && !output && tx_file_list.IsEmpty() && !rx_cache_path)
|
||||
{
|
||||
DMSG(0, "NormApp::OnStartup() Error! no \"input\", \"output\", "
|
||||
"\"sendfile\", or \"rxcache\" given.");
|
||||
"\"sendfile\", or \"rxcache\" given.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -761,10 +1142,14 @@ bool NormApp::OnStartup()
|
|||
session->SetTrace(tracing);
|
||||
session->SetTxLoss(tx_loss);
|
||||
session->SetRxLoss(rx_loss);
|
||||
session->SetBackoffFactor(backoff_factor);
|
||||
|
||||
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))
|
||||
{
|
||||
DMSG(0, "NormApp::OnStartup() start server error!\n");
|
||||
|
|
@ -772,12 +1157,12 @@ bool NormApp::OnStartup()
|
|||
return false;
|
||||
}
|
||||
session->ServerSetAutoParity(auto_parity);
|
||||
|
||||
session->ServerSetExtraParity(extra_parity);
|
||||
if (input)
|
||||
{
|
||||
// Open a stream object to write to (QueueTxStream(stream bufferSize))
|
||||
stream = session->QueueTxStream(tx_buffer_size);
|
||||
if (!stream)
|
||||
tx_stream = session->QueueTxStream(tx_buffer_size);
|
||||
if (!tx_stream)
|
||||
{
|
||||
DMSG(0, "NormApp::OnStartup() queue tx stream error!\n");
|
||||
session_mgr.Destroy();
|
||||
|
|
@ -788,8 +1173,9 @@ bool NormApp::OnStartup()
|
|||
|
||||
if (output || rx_cache_path)
|
||||
{
|
||||
TRACE("starting client ...\n");
|
||||
// StartClient(bufferMax (per-sender))
|
||||
session->SetUnicastNacks(unicast_nacks);
|
||||
session->ClientSetSilent(silent_client);
|
||||
if (!session->StartClient(rx_buffer_size))
|
||||
{
|
||||
DMSG(0, "NormApp::OnStartup() start client error!\n");
|
||||
|
|
@ -808,11 +1194,23 @@ bool NormApp::OnStartup()
|
|||
|
||||
void NormApp::OnShutdown()
|
||||
{
|
||||
//TRACE("NormApp::OnShutdown() ...\n");
|
||||
session_mgr.Destroy();
|
||||
if (input) fclose(input);
|
||||
input = NULL;
|
||||
if (output) fclose(output);
|
||||
output = NULL;
|
||||
if (input)
|
||||
{
|
||||
if (input_active)
|
||||
{
|
||||
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()
|
||||
|
||||
|
||||
|
|
@ -859,7 +1257,7 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
if (theApp.OnStartup())
|
||||
{
|
||||
exitCode = theApp.MainLoop();
|
||||
exitCode = theApp.MainLoop();
|
||||
theApp.OnShutdown();
|
||||
fprintf(stderr, "norm: Done.\n");
|
||||
}
|
||||
|
|
@ -886,6 +1284,8 @@ int main(int argc, char* argv[])
|
|||
return exitCode; // exitCode contains "signum" causing exit
|
||||
} // end main();
|
||||
|
||||
|
||||
|
||||
void NormApp::SignalHandler(int sigNum)
|
||||
{
|
||||
switch(sigNum)
|
||||
|
|
@ -895,6 +1295,11 @@ void NormApp::SignalHandler(int sigNum)
|
|||
theApp.Stop(sigNum); // causes theApp's main loop to exit
|
||||
break;
|
||||
|
||||
case SIGCHLD:
|
||||
if (theApp.IsPostProcessing()) theApp.HandleSIGCHLD();
|
||||
signal(SIGCHLD, SignalHandler);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "norm: Unexpected signal: %d\n", sigNum);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "debug.h"
|
||||
#include "sysdefs.h"
|
||||
|
||||
|
||||
// Hamming weights for given one-byte bit masks
|
||||
static unsigned char WEIGHT[256] =
|
||||
{
|
||||
|
|
@ -191,7 +192,7 @@ void NormBitmask::Destroy()
|
|||
{
|
||||
if (mask)
|
||||
{
|
||||
delete []mask;
|
||||
delete[] mask;
|
||||
mask = (unsigned char*)NULL;
|
||||
num_bits = first_set = 0;
|
||||
}
|
||||
|
|
@ -425,7 +426,7 @@ void NormBitmask::Display(FILE* stream)
|
|||
if (0x07 == (i & 0x07)) fprintf(stream, " ");
|
||||
if (0x3f == (i & 0x3f)) fprintf(stream, "\n");
|
||||
}
|
||||
} // end NormSlidingMask::NormBitmask()
|
||||
} // end NormBitmask::Display()
|
||||
|
||||
|
||||
|
||||
|
|
@ -433,7 +434,7 @@ void NormBitmask::Display(FILE* stream)
|
|||
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
|
@ -446,6 +447,7 @@ NormSlidingMask::~NormSlidingMask()
|
|||
|
||||
bool NormSlidingMask::Init(long numBits)
|
||||
{
|
||||
|
||||
if (mask) Destroy();
|
||||
if (numBits <= 0) return false;
|
||||
unsigned long len = (numBits + 7) >> 3;
|
||||
|
|
@ -519,6 +521,7 @@ bool NormSlidingMask::CanSet(unsigned long index) const
|
|||
|
||||
bool NormSlidingMask::Set(unsigned long index)
|
||||
{
|
||||
ASSERT(CanSet(index));
|
||||
if (IsSet())
|
||||
{
|
||||
// Determine position with respect to current start
|
||||
|
|
@ -571,6 +574,8 @@ bool NormSlidingMask::Set(unsigned long index)
|
|||
if ((pos > end) || (pos < start)) end = pos;
|
||||
}
|
||||
}
|
||||
ASSERT((pos >> 3) >= 0);
|
||||
ASSERT((pos >> 3) < (long)mask_len);
|
||||
mask[(pos >> 3)] |= (0x80 >> (pos & 0x07));
|
||||
}
|
||||
else
|
||||
|
|
@ -584,6 +589,7 @@ bool NormSlidingMask::Set(unsigned long index)
|
|||
|
||||
bool NormSlidingMask::Unset(unsigned long index)
|
||||
{
|
||||
//ASSERT(CanSet(index));
|
||||
if (IsSet())
|
||||
{
|
||||
long pos = index - offset;
|
||||
|
|
@ -602,6 +608,8 @@ bool NormSlidingMask::Unset(unsigned long index)
|
|||
if ((pos < start) || (pos > end)) return true;
|
||||
}
|
||||
// Unset the corresponding bit
|
||||
ASSERT((pos >> 3) >= 0);
|
||||
ASSERT((pos >> 3) < (long)mask_len);
|
||||
mask[(pos >> 3)] &= ~(0x80 >> (pos & 0x07));
|
||||
if (start == end)
|
||||
{
|
||||
|
|
@ -640,6 +648,8 @@ bool NormSlidingMask::Unset(unsigned long index)
|
|||
|
||||
bool NormSlidingMask::SetBits(unsigned long index, long count)
|
||||
{
|
||||
ASSERT(CanSet(index));
|
||||
ASSERT(CanSet(index+count-1));
|
||||
if (count < 0) return false;
|
||||
if (0 == count) return true;
|
||||
long firstPos, lastPos;
|
||||
|
|
@ -691,19 +701,28 @@ bool NormSlidingMask::SetBits(unsigned long index, long count)
|
|||
long maskIndex = firstPos >> 3;
|
||||
int bitIndex = firstPos & 0x07;
|
||||
int bitRemainder = 8 - bitIndex;
|
||||
ASSERT(maskIndex >= 0);
|
||||
if (count <= bitRemainder)
|
||||
{
|
||||
ASSERT(maskIndex < (long)mask_len);
|
||||
mask[maskIndex] |= (0x00ff >> bitIndex) &
|
||||
(0x00ff << (bitRemainder - count));
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(maskIndex < (long)mask_len);
|
||||
mask[maskIndex] |= 0x00ff >> bitIndex;
|
||||
count -= bitRemainder;
|
||||
unsigned long nbytes = count >> 3;
|
||||
long nbytes = count >> 3;
|
||||
ASSERT((maskIndex+1+nbytes) <= (long)mask_len);
|
||||
memset(&mask[++maskIndex], 0xff, nbytes);
|
||||
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;
|
||||
}
|
||||
|
|
@ -720,25 +739,36 @@ bool NormSlidingMask::SetBits(unsigned long index, long count)
|
|||
long maskIndex = firstPos >> 3;
|
||||
int bitIndex = firstPos & 0x07;
|
||||
int bitRemainder = 8 - bitIndex;
|
||||
ASSERT(maskIndex >= 0);
|
||||
if (count <= bitRemainder)
|
||||
{
|
||||
ASSERT(maskIndex < (long)mask_len);
|
||||
mask[maskIndex] |= (0x00ff >> bitIndex) &
|
||||
(0x00ff << (bitRemainder - count));
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(maskIndex < (long)mask_len);
|
||||
mask[maskIndex] |= 0x00ff >> bitIndex;
|
||||
count -= bitRemainder;
|
||||
unsigned long nbytes = count >> 3;
|
||||
long nbytes = count >> 3;
|
||||
ASSERT((maskIndex+1+nbytes) <= (long)mask_len);
|
||||
memset(&mask[++maskIndex], 0xff, nbytes);
|
||||
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;
|
||||
} // end NormSlidingMask::SetBits()
|
||||
|
||||
bool NormSlidingMask::UnsetBits(unsigned long index, long count)
|
||||
{
|
||||
//ASSERT(CanSet(index));
|
||||
//ASSERT(CanSet(index+count-1));
|
||||
if (IsSet())
|
||||
{
|
||||
// Trim to fit as needed.
|
||||
|
|
@ -782,17 +812,24 @@ bool NormSlidingMask::UnsetBits(unsigned long index, long count)
|
|||
int bitRemainder = 8 - bitIndex;
|
||||
if (count <= bitRemainder)
|
||||
{
|
||||
ASSERT(maskIndex < (long)mask_len);
|
||||
mask[maskIndex] &= (0x00ff << bitRemainder) |
|
||||
(0x00ff >> (bitIndex + count));
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(maskIndex < (long)mask_len);
|
||||
mask[maskIndex] &= 0x00ff << bitRemainder;
|
||||
count -= bitRemainder;
|
||||
unsigned long nbytes = count >> 3;
|
||||
ASSERT((maskIndex+1+nbytes) <= mask_len);
|
||||
memset(&mask[++maskIndex], 0, nbytes);
|
||||
count &= 0x07;
|
||||
if (count) mask[maskIndex+nbytes] &= 0xff >> count;
|
||||
if (count)
|
||||
{
|
||||
ASSERT((maskIndex+nbytes) < mask_len);
|
||||
mask[maskIndex+nbytes] &= 0xff >> count;
|
||||
}
|
||||
}
|
||||
startPos = 0;
|
||||
}
|
||||
|
|
@ -807,17 +844,24 @@ bool NormSlidingMask::UnsetBits(unsigned long index, long count)
|
|||
int bitRemainder = 8 - bitIndex;
|
||||
if (count <= bitRemainder)
|
||||
{
|
||||
ASSERT(maskIndex < (long)mask_len);
|
||||
mask[maskIndex] &= (0x00ff << bitRemainder) |
|
||||
(0x00ff >> (bitIndex + count));
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(maskIndex < (long)mask_len);
|
||||
mask[maskIndex] &= 0x00ff << bitRemainder;
|
||||
count -= bitRemainder;
|
||||
unsigned long nbytes = count >> 3;
|
||||
ASSERT((maskIndex+1+nbytes) <= mask_len);
|
||||
memset(&mask[++maskIndex], 0, nbytes);
|
||||
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
|
||||
if (start == firstPos)
|
||||
|
|
@ -1078,8 +1122,11 @@ bool NormSlidingMask::Copy(const NormSlidingMask& b)
|
|||
long endIndex = b.end >> 3;
|
||||
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_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
|
||||
if (mask_len > b.mask_len)
|
||||
{
|
||||
|
|
@ -1087,11 +1134,15 @@ bool NormSlidingMask::Copy(const NormSlidingMask& b)
|
|||
if (remainder) mask[0] &= 0xff >> remainder;
|
||||
remainder = end & 0x7;
|
||||
if (remainder)
|
||||
{
|
||||
ASSERT((startIndex+endIndex) < (long)mask_len);
|
||||
mask[startIndex+endIndex] &= 0xff << (8 - remainder);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT((endIndex-startIndex+1) <= (long)mask_len);
|
||||
memcpy(mask, b.mask+startIndex, endIndex-startIndex+1);
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -117,6 +117,8 @@ class NormSlidingMask
|
|||
NormSlidingMask();
|
||||
~NormSlidingMask();
|
||||
|
||||
const char* GetMask() const {return (const char*)mask;}
|
||||
|
||||
bool Init(long numBits);
|
||||
void Destroy();
|
||||
long Size() const {return num_bits;}
|
||||
|
|
@ -181,6 +183,7 @@ class NormSlidingMask
|
|||
long start;
|
||||
long end;
|
||||
unsigned long offset;
|
||||
unsigned char* mask2;
|
||||
}; // end class NormSlidingMask
|
||||
|
||||
#endif // _NORM_BITMASK_
|
||||
|
|
|
|||
|
|
@ -39,8 +39,12 @@
|
|||
#include "galois.h" // for Galois math routines
|
||||
#include "debug.h"
|
||||
|
||||
#ifdef SIMULATE
|
||||
#include "normMessage.h"
|
||||
#endif // SIMULATE
|
||||
|
||||
NormEncoder::NormEncoder()
|
||||
: npar(0), vecSize(0),
|
||||
: npar(0), vector_size(0),
|
||||
genPoly(NULL), scratch(NULL)
|
||||
{
|
||||
|
||||
|
|
@ -58,7 +62,7 @@ bool NormEncoder::Init(int numParity, int vecSizeMax)
|
|||
ASSERT(vecSizeMax >= 0);
|
||||
if (genPoly) Destroy();
|
||||
npar = numParity;
|
||||
vecSize = vecSizeMax;
|
||||
vector_size = vecSizeMax;
|
||||
// Create generator polynomial
|
||||
if(!CreateGeneratorPolynomial())
|
||||
{
|
||||
|
|
@ -166,11 +170,6 @@ bool NormEncoder::CreateGeneratorPolynomial()
|
|||
// Parity data is written to list of parity vectors supplied by caller
|
||||
void NormEncoder::Encode(const char *data, char **pVec)
|
||||
{
|
||||
|
||||
#if defined(NS2) || defined(OPNET)
|
||||
return; // lobotomize FEC for faster simulations
|
||||
#endif
|
||||
|
||||
int i, j;
|
||||
unsigned char *userData, *LSFR1, *LSFR2, *pVec0;
|
||||
int npar_minus_one = npar - 1;
|
||||
|
|
@ -178,6 +177,14 @@ void NormEncoder::Encode(const char *data, char **pVec)
|
|||
ASSERT(scratch); // Make sure it's been init'd first
|
||||
// Assumes parity vectors are zero-filled at block start !!!
|
||||
// Copy pVec[0] for use in calculations
|
||||
|
||||
#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);
|
||||
if (npar > 1)
|
||||
{
|
||||
|
|
@ -322,9 +329,6 @@ int NormDecoder::Decode(char** dVec, int ndata, UINT16 erasureCount, UINT16* era
|
|||
ASSERT(Lambda);
|
||||
ASSERT(erasureCount && (erasureCount<=npar));
|
||||
|
||||
#if defined(NS2) || defined (OPNET)
|
||||
return erasureCount; // lobotomize FEC for faster simulations
|
||||
#endif
|
||||
|
||||
// (A) Compute syndrome vectors
|
||||
|
||||
|
|
@ -332,7 +336,13 @@ int NormDecoder::Decode(char** dVec, int ndata, UINT16 erasureCount, UINT16* era
|
|||
|
||||
// Then calculate syndrome (based on zero value erasures)
|
||||
int nvecs = npar + ndata;
|
||||
#ifdef SIMULATE
|
||||
int vecSize = MIN(SIM_PAYLOAD_MAX, vector_size);
|
||||
vecSize = MAX(NormDataMsg::PayloadHeaderLength(), vecSize);
|
||||
#else
|
||||
int vecSize = vector_size;
|
||||
#endif // if/else SIMUATE
|
||||
|
||||
for (int i = 0; i < npar; i++)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
// Only fill _data_ erasures
|
||||
if (erasureLocs[i] >= ndata) return erasureCount;
|
||||
if (erasureLocs[i] >= ndata) break;//return erasureCount;
|
||||
|
||||
// evaluate Lambda' (derivative) at alpha^(-i)
|
||||
// ( all odd powers disappear)
|
||||
|
|
@ -413,6 +423,7 @@ int NormDecoder::Decode(char** dVec, int ndata, UINT16 erasureCount, UINT16* era
|
|||
data++;
|
||||
}
|
||||
}
|
||||
|
||||
return erasureCount;
|
||||
} // end NormDecoder::Decode()
|
||||
|
||||
|
|
|
|||
|
|
@ -39,10 +39,10 @@ class NormEncoder
|
|||
{
|
||||
// Members
|
||||
private:
|
||||
int npar; // No. of parity packets (N-k)
|
||||
int vecSize; // Size of biggest vector to encode
|
||||
unsigned char* genPoly; // Ptr to generator polynomial
|
||||
unsigned char* scratch; // scratch space for encoding
|
||||
int npar; // No. of parity packets (N-k)
|
||||
int vector_size; // Size of biggest vector to encode
|
||||
unsigned char* genPoly; // Ptr to generator polynomial
|
||||
unsigned char* scratch; // scratch space for encoding
|
||||
|
||||
// Methods
|
||||
public:
|
||||
|
|
@ -53,7 +53,7 @@ class NormEncoder
|
|||
bool IsReady(){return (bool)(genPoly != NULL);}
|
||||
void Encode(const char *dataVector, char **parityVectorList);
|
||||
int NumParity() {return npar;}
|
||||
int VectorSize() {return vecSize;}
|
||||
int VectorSize() {return vector_size;}
|
||||
|
||||
private:
|
||||
bool CreateGeneratorPolynomial();
|
||||
|
|
|
|||
|
|
@ -121,15 +121,18 @@ bool NormFile::Lock()
|
|||
{
|
||||
#ifndef WIN32 // WIN32 files are automatically locked
|
||||
fchmod(fd, 0640 | S_ISGID);
|
||||
|
||||
#ifdef HAVE_FLOCK
|
||||
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;
|
||||
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
|
||||
return true;
|
||||
} // end NormFile::Lock()
|
||||
|
|
@ -143,7 +146,7 @@ void NormFile::Unlock()
|
|||
#ifdef HAVE_LOCKF
|
||||
lockf(fd, F_ULOCK, 0);
|
||||
#endif // HAVE_LOCKF
|
||||
#endif // HAVE_FLOCK
|
||||
#endif // if/elseHAVE_FLOCK
|
||||
fchmod(fd, 0640);
|
||||
#endif // !WIN32
|
||||
} // end NormFile::UnLock()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,136 @@
|
|||
#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()
|
||||
: form(INVALID), flags(0), length(0), buffer(NULL), buffer_len(0)
|
||||
{
|
||||
|
|
@ -7,22 +138,24 @@ NormRepairRequest::NormRepairRequest()
|
|||
|
||||
bool NormRepairRequest::AppendRepairItem(const NormObjectId& objectId,
|
||||
const NormBlockId& blockId,
|
||||
UINT16 blockLen,
|
||||
UINT16 symbolId)
|
||||
{
|
||||
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);
|
||||
else
|
||||
DMSG(4, "NormRepairRequest::AppendRepairItem(obj>%hu blk>%lu seg>%hu) ...\n",
|
||||
(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);
|
||||
memcpy(buffer+CONTENT_OFFSET+length, &temp16, 2);
|
||||
UINT32 temp32 =htonl((UINT32)blockId);
|
||||
memcpy(buffer+length+CONTENT_OFFSET+2, &temp32, 4);
|
||||
symbolId = htons(symbolId);
|
||||
memcpy(buffer+length+CONTENT_OFFSET+6, &symbolId, 2);
|
||||
char* ptr = buffer + length + ITEM_LIST_OFFSET;
|
||||
ptr[FEC_ID_OFFSET] = 129;
|
||||
ptr[RESERVED_OFFSET] = 0;
|
||||
*((UINT16*)(ptr+OBJ_ID_OFFSET)) = htons((UINT16)objectId);
|
||||
*((UINT32*)(ptr+BLOCK_ID_OFFSET)) = htonl((UINT32)blockId);
|
||||
*((UINT16*)(ptr+BLOCK_LEN_OFFSET)) = htons((UINT16)blockLen);
|
||||
*((UINT16*)(ptr+SYMBOL_ID_OFFSET)) = htons((UINT16)symbolId);
|
||||
length += RepairItemLength();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -34,31 +167,34 @@ bool NormRepairRequest::AppendRepairItem(const NormObjectId& objectId,
|
|||
|
||||
bool NormRepairRequest::AppendRepairRange(const NormObjectId& startObjectId,
|
||||
const NormBlockId& startBlockId,
|
||||
UINT16 startBlockLen,
|
||||
UINT16 startSymbolId,
|
||||
const NormObjectId& endObjectId,
|
||||
const NormBlockId& endBlockId,
|
||||
UINT16 endBlockLen,
|
||||
UINT16 endSymbolId)
|
||||
{
|
||||
DMSG(4, "NormRepairRequest::AppendRepairRange(%hu:%lu:%hu->%hu:%lu:%hu) ...\n",
|
||||
(UINT16)startObjectId, (UINT32)startBlockId, (UINT32)startSymbolId,
|
||||
(UINT16)endObjectId, (UINT32)endBlockId, (UINT32)endSymbolId);
|
||||
if (buffer_len >= (length+CONTENT_OFFSET+RepairRangeLength()))
|
||||
if (buffer_len >= (length+ITEM_LIST_OFFSET+RepairRangeLength()))
|
||||
{
|
||||
// range start
|
||||
UINT16 temp16;
|
||||
temp16 = htons((UINT16)startObjectId);
|
||||
memcpy(buffer+CONTENT_OFFSET+length, &temp16, 2);
|
||||
UINT32 temp32 =htonl((UINT32)startBlockId);
|
||||
memcpy(buffer+length+CONTENT_OFFSET+2, &temp32, 4);
|
||||
startSymbolId = htons(startSymbolId);
|
||||
memcpy(buffer+length+CONTENT_OFFSET+6, &startSymbolId, 2);
|
||||
char* ptr = buffer + length + ITEM_LIST_OFFSET;
|
||||
ptr[FEC_ID_OFFSET] = 129;
|
||||
ptr[RESERVED_OFFSET] = 0;
|
||||
*((UINT16*)(ptr+OBJ_ID_OFFSET)) = htons((UINT16)startObjectId);
|
||||
*((UINT32*)(ptr+BLOCK_ID_OFFSET)) = htonl((UINT32)startBlockId);
|
||||
*((UINT16*)(ptr+BLOCK_LEN_OFFSET)) = htons((UINT16)startBlockLen);
|
||||
*((UINT16*)(ptr+SYMBOL_ID_OFFSET)) = htons((UINT16)startSymbolId);
|
||||
ptr += RepairItemLength();
|
||||
// range end
|
||||
temp16 = htons((UINT16)endObjectId);
|
||||
memcpy(buffer+CONTENT_OFFSET+length+8, &temp16, 2);
|
||||
temp32 =htonl((UINT32)endBlockId);
|
||||
memcpy(buffer+length+CONTENT_OFFSET+10, &temp32, 4);
|
||||
endSymbolId = htons(endSymbolId);
|
||||
memcpy(buffer+length+CONTENT_OFFSET+14, &endSymbolId, 2);
|
||||
ptr[FEC_ID_OFFSET] = 129;
|
||||
ptr[RESERVED_OFFSET] = 0;
|
||||
*((UINT16*)(ptr+OBJ_ID_OFFSET)) = htons((UINT16)endObjectId);
|
||||
*((UINT32*)(ptr+BLOCK_ID_OFFSET)) = htonl((UINT32)endBlockId);
|
||||
*((UINT16*)(ptr+BLOCK_LEN_OFFSET)) = htons((UINT16)endBlockLen);
|
||||
*((UINT16*)(ptr+SYMBOL_ID_OFFSET)) = htons((UINT16)endSymbolId);
|
||||
length += RepairRangeLength();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -66,20 +202,22 @@ bool NormRepairRequest::AppendRepairRange(const NormObjectId& startObjectId,
|
|||
{
|
||||
return false;
|
||||
}
|
||||
} // end NormRepairRequest::AppendErasureCount()
|
||||
} // end NormRepairRequest::AppendRepairRange()
|
||||
|
||||
bool NormRepairRequest::AppendErasureCount(const NormObjectId& objectId,
|
||||
const NormBlockId& blockId,
|
||||
UINT16 blockLen,
|
||||
UINT16 erasureCount)
|
||||
{
|
||||
if (buffer_len >= (CONTENT_OFFSET+length+ErasureItemLength()))
|
||||
if (buffer_len >= (ITEM_LIST_OFFSET+length+ErasureItemLength()))
|
||||
{
|
||||
UINT16 temp16 = htons((UINT16)objectId);
|
||||
memcpy(buffer+CONTENT_OFFSET+length, &temp16, 2);
|
||||
UINT32 temp32 =htonl((UINT32)blockId);
|
||||
memcpy(buffer+length+CONTENT_OFFSET+2, &temp32, 4);
|
||||
erasureCount = htons(erasureCount);
|
||||
memcpy(buffer+length+CONTENT_OFFSET+6, &erasureCount, 2);
|
||||
char* ptr = buffer + length + ITEM_LIST_OFFSET;
|
||||
ptr[FEC_ID_OFFSET] = 129;
|
||||
ptr[RESERVED_OFFSET] = 0;
|
||||
*((UINT16*)(ptr+OBJ_ID_OFFSET)) = htons((UINT16)objectId);
|
||||
*((UINT32*)(ptr+BLOCK_ID_OFFSET)) = htonl((UINT32)blockId);
|
||||
*((UINT16*)(ptr+BLOCK_LEN_OFFSET)) = htons((UINT16)blockLen);
|
||||
*((UINT16*)(ptr+SYMBOL_ID_OFFSET)) = htons((UINT16)erasureCount);
|
||||
length += ErasureItemLength();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -96,9 +234,8 @@ UINT16 NormRepairRequest::Pack()
|
|||
{
|
||||
buffer[FORM_OFFSET] = form;
|
||||
buffer[FLAGS_OFFSET] = (char)flags;
|
||||
UINT16 temp16 = htons(length);
|
||||
memcpy(buffer+LENGTH_OFFSET, &temp16, 2);
|
||||
return (CONTENT_OFFSET + length);
|
||||
*((UINT16*)(buffer+LENGTH_OFFSET)) = htons(length);
|
||||
return (ITEM_LIST_OFFSET + length);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -107,23 +244,26 @@ UINT16 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
|
||||
if (buffer_len >= CONTENT_OFFSET)
|
||||
if (buffer_len >= ITEM_LIST_OFFSET)
|
||||
{
|
||||
form = (Form)buffer[FORM_OFFSET];
|
||||
flags = (int)buffer[FLAGS_OFFSET];
|
||||
memcpy(&length, buffer+LENGTH_OFFSET, 2);
|
||||
length = ntohs(length);
|
||||
if (length > (buffer_len - CONTENT_OFFSET))
|
||||
length = ntohs(*((UINT16*)(buffer+LENGTH_OFFSET)));
|
||||
if (length > (buffer_len - ITEM_LIST_OFFSET))
|
||||
{
|
||||
// Badly formed message
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (CONTENT_OFFSET+length);
|
||||
return (ITEM_LIST_OFFSET+length);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -135,18 +275,16 @@ UINT16 NormRepairRequest::Unpack()
|
|||
bool NormRepairRequest::RetrieveRepairItem(UINT16 offset,
|
||||
NormObjectId* objectId,
|
||||
NormBlockId* blockId,
|
||||
UINT16* blockLen,
|
||||
UINT16* symbolId) const
|
||||
{
|
||||
if (length >= (offset + RepairItemLength()))
|
||||
{
|
||||
UINT16 temp16;
|
||||
memcpy(&temp16, buffer+CONTENT_OFFSET+offset, 2);
|
||||
*objectId = ntohs(temp16);
|
||||
UINT32 temp32;
|
||||
memcpy(&temp32, buffer+CONTENT_OFFSET+offset+2, 4);
|
||||
*blockId = ntohl(temp32);
|
||||
memcpy(symbolId, buffer+CONTENT_OFFSET+offset+6, 2);
|
||||
*symbolId = ntohs(*symbolId);
|
||||
const char* ptr = buffer+ITEM_LIST_OFFSET+offset;
|
||||
*objectId = ntohs(*((UINT16*)(ptr+OBJ_ID_OFFSET)));
|
||||
*blockId = ntohl(*((UINT32*)(ptr+BLOCK_ID_OFFSET)));
|
||||
*blockLen = ntohs(*((UINT16*)(ptr+BLOCK_LEN_OFFSET)));
|
||||
*symbolId = ntohs(*((UINT16*)(ptr+SYMBOL_ID_OFFSET)));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
|
@ -163,9 +301,10 @@ NormRepairRequest::Iterator::Iterator(NormRepairRequest& theRequest)
|
|||
// For erasure requests, symbolId is loaded with erasureCount
|
||||
bool NormRepairRequest::Iterator::NextRepairItem(NormObjectId* objectId,
|
||||
NormBlockId* blockId,
|
||||
UINT16* blockLen,
|
||||
UINT16* symbolId)
|
||||
{
|
||||
if (request.RetrieveRepairItem(offset, objectId, blockId, symbolId))
|
||||
if (request.RetrieveRepairItem(offset, objectId, blockId, blockLen, symbolId))
|
||||
{
|
||||
offset += NormRepairRequest::RepairItemLength();
|
||||
return true;
|
||||
|
|
@ -177,6 +316,8 @@ bool NormRepairRequest::Iterator::NextRepairItem(NormObjectId* objectId,
|
|||
} // end NormRepairRequest::Iterator::NextRepairItem()
|
||||
|
||||
|
||||
|
||||
|
||||
NormMessageQueue::NormMessageQueue()
|
||||
: head(NULL), tail(NULL)
|
||||
{
|
||||
|
|
@ -189,7 +330,7 @@ NormMessageQueue::~NormMessageQueue()
|
|||
|
||||
void NormMessageQueue::Destroy()
|
||||
{
|
||||
NormMessage* next;
|
||||
NormMsg* next;
|
||||
while ((next = head))
|
||||
{
|
||||
head = next->next;
|
||||
|
|
@ -198,7 +339,7 @@ void NormMessageQueue::Destroy()
|
|||
} // end NormMessageQueue::Destroy()
|
||||
|
||||
|
||||
void NormMessageQueue::Prepend(NormMessage* msg)
|
||||
void NormMessageQueue::Prepend(NormMsg* msg)
|
||||
{
|
||||
if ((msg->next = head))
|
||||
head->prev = msg;
|
||||
|
|
@ -208,7 +349,7 @@ void NormMessageQueue::Prepend(NormMessage* msg)
|
|||
head = msg;
|
||||
} // end NormMessageQueue::Prepend()
|
||||
|
||||
void NormMessageQueue::Append(NormMessage* msg)
|
||||
void NormMessageQueue::Append(NormMsg* msg)
|
||||
{
|
||||
if ((msg->prev = tail))
|
||||
tail->next = msg;
|
||||
|
|
@ -218,7 +359,7 @@ void NormMessageQueue::Append(NormMessage* msg)
|
|||
tail = msg;
|
||||
} // end NormMessageQueue::Append()
|
||||
|
||||
void NormMessageQueue::Remove(NormMessage* msg)
|
||||
void NormMessageQueue::Remove(NormMsg* msg)
|
||||
{
|
||||
if (msg->prev)
|
||||
msg->prev->next = msg->next;
|
||||
|
|
@ -230,11 +371,11 @@ void NormMessageQueue::Remove(NormMessage* msg)
|
|||
tail = msg->prev;
|
||||
} // end NormMessageQueue::Remove()
|
||||
|
||||
NormMessage* NormMessageQueue::RemoveHead()
|
||||
NormMsg* NormMessageQueue::RemoveHead()
|
||||
{
|
||||
if (head)
|
||||
{
|
||||
NormMessage* msg = head;
|
||||
NormMsg* msg = head;
|
||||
if ((head = msg->next))
|
||||
msg->next->prev = NULL;
|
||||
else
|
||||
|
|
@ -247,11 +388,11 @@ NormMessage* NormMessageQueue::RemoveHead()
|
|||
}
|
||||
} // end NormMessageQueue::RemoveHead()
|
||||
|
||||
NormMessage* NormMessageQueue::RemoveTail()
|
||||
NormMsg* NormMessageQueue::RemoveTail()
|
||||
{
|
||||
if (tail)
|
||||
{
|
||||
NormMessage* msg = tail;
|
||||
NormMsg* msg = tail;
|
||||
if ((tail = msg->prev))
|
||||
msg->prev->next = NULL;
|
||||
else
|
||||
|
|
|
|||
1415
common/normMessage.h
1415
common/normMessage.h
File diff suppressed because it is too large
Load Diff
1450
common/normNode.cpp
1450
common/normNode.cpp
File diff suppressed because it is too large
Load Diff
|
|
@ -16,12 +16,13 @@ class NormNode
|
|||
NormNode(class NormSession* theSession, NormNodeId nodeId);
|
||||
virtual ~NormNode();
|
||||
|
||||
void SetAddress(const NetworkAddress& address)
|
||||
{addr = address;}
|
||||
const NetworkAddress Address() const {return addr;}
|
||||
void SetAddress(const NetworkAddress& address) {addr = address;}
|
||||
const NetworkAddress& GetAddress() const {return addr;}
|
||||
|
||||
const NormNodeId& Id() {return id;}
|
||||
inline const NormNodeId& LocalNodeId();
|
||||
const NormNodeId& Id() const {return id;}
|
||||
inline const NormNodeId& LocalNodeId() const;
|
||||
|
||||
void SetId(const NormNodeId& nodeId) {id = nodeId;}
|
||||
|
||||
protected:
|
||||
class NormSession* session;
|
||||
|
|
@ -33,11 +34,154 @@ class NormNode
|
|||
NormNode* parent;
|
||||
NormNode* right;
|
||||
NormNode* left;
|
||||
NormNode* prev;
|
||||
NormNode* next;
|
||||
|
||||
//NormNode* prev;
|
||||
//NormNode* next;
|
||||
|
||||
}; // 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
|
||||
{
|
||||
public:
|
||||
|
|
@ -46,15 +190,28 @@ class NormServerNode : public NormNode
|
|||
NormServerNode(class NormSession* theSession, NormNodeId nodeId);
|
||||
~NormServerNode();
|
||||
|
||||
void HandleCommand(NormCommandMsg& cmd);
|
||||
void HandleObjectMessage(NormMessage& msg);
|
||||
void HandleNackMessage(NormNackMsg& nack);
|
||||
bool UpdateLossEstimate(const struct timeval& currentTime,
|
||||
unsigned short theSequence,
|
||||
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();
|
||||
bool IsOpen() const {return is_open;}
|
||||
|
||||
bool SyncTest(const NormMessage& msg) const;
|
||||
bool SyncTest(const NormObjectMsg& msg) const;
|
||||
void Sync(NormObjectId objectId);
|
||||
ObjectStatus UpdateSyncStatus(const NormObjectId& objectId);
|
||||
void SetPending(NormObjectId objectId);
|
||||
|
|
@ -65,8 +222,6 @@ class NormServerNode : public NormNode
|
|||
UINT16 SegmentSize() {return segment_size;}
|
||||
UINT16 BlockSize() {return ndata;}
|
||||
UINT16 NumParity() {return nparity;}
|
||||
//NormBlockPool* BlockPool() {return &block_pool;}
|
||||
//NormSegmentPool* SegmentPool() {return &segment_pool;}
|
||||
|
||||
NormBlock* GetFreeBlock(NormObjectId objectId, NormBlockId blockId);
|
||||
void PutFreeBlock(NormBlock* block)
|
||||
|
|
@ -90,27 +245,29 @@ class NormServerNode : public NormNode
|
|||
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());}
|
||||
unsigned long PeakBufferUsage()
|
||||
unsigned long PeakBufferUsage() const
|
||||
{return (segment_size * segment_pool.PeakUsage());}
|
||||
unsigned long BufferOverunCount()
|
||||
unsigned long BufferOverunCount() const
|
||||
{return segment_pool.OverunCount() + block_pool.OverrunCount();}
|
||||
|
||||
unsigned long RecvTotal() {return recv_total;}
|
||||
unsigned long RecvGoodput() {return recv_goodput;}
|
||||
unsigned long RecvTotal() const {return recv_total;}
|
||||
unsigned long RecvGoodput() const {return recv_goodput;}
|
||||
void IncrementRecvTotal(unsigned long count) {recv_total += count;}
|
||||
void IncrementRecvGoodput(unsigned long count) {recv_goodput += count;}
|
||||
void ResetRecvStats() {recv_total = recv_goodput = 0;}
|
||||
void IncrementResyncCount() {resync_count++;}
|
||||
unsigned long ResyncCount() {return resync_count;}
|
||||
unsigned long NackCount() {return nack_count;}
|
||||
unsigned long SuppressCount() {return suppress_count;}
|
||||
unsigned long CompletionCount() {return completion_count;}
|
||||
unsigned long PendingCount() {return rx_table.Count();}
|
||||
unsigned long FailureCount() {return failure_count;}
|
||||
unsigned long ResyncCount() const {return resync_count;}
|
||||
unsigned long NackCount() const {return nack_count;}
|
||||
unsigned long SuppressCount() const {return suppress_count;}
|
||||
unsigned long CompletionCount() const {return completion_count;}
|
||||
unsigned long PendingCount() const {return rx_table.Count();}
|
||||
unsigned long FailureCount() const {return failure_count;}
|
||||
|
||||
|
||||
private:
|
||||
void RepairCheck(NormObject::CheckLevel checkLevel,
|
||||
|
|
@ -118,9 +275,12 @@ class NormServerNode : public NormNode
|
|||
NormBlockId blockId,
|
||||
NormSegmentId segmentId);
|
||||
|
||||
bool OnActivityTimeout();
|
||||
bool OnRepairTimeout();
|
||||
bool OnCCTimeout();
|
||||
void HandleRepairContent(const char* buffer, UINT16 bufferLen);
|
||||
|
||||
|
||||
UINT16 session_id;
|
||||
bool synchronized;
|
||||
NormObjectId sync_id; // only valid if(synchronized)
|
||||
NormObjectId next_id; // only valid if(synchronized)
|
||||
|
|
@ -138,8 +298,10 @@ class NormServerNode : public NormNode
|
|||
NormDecoder decoder;
|
||||
UINT16* erasure_loc;
|
||||
|
||||
ProtocolTimer activity_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;
|
||||
UINT8 grtt_quantized;
|
||||
|
|
@ -148,6 +310,25 @@ class NormServerNode : public NormNode
|
|||
double gsize_estimate;
|
||||
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
|
||||
unsigned long recv_total; // total recvd accumulator
|
||||
unsigned long recv_goodput; // goodput recvd accumulator
|
||||
|
|
@ -157,7 +338,7 @@ class NormServerNode : public NormNode
|
|||
unsigned long completion_count;
|
||||
unsigned long failure_count; // due to re-syncs
|
||||
|
||||
}; // end class NodeServerNode
|
||||
}; // end class NormServerNode
|
||||
|
||||
|
||||
// Used for binary trees of NormNodes
|
||||
|
|
@ -180,8 +361,6 @@ class NormNodeTree
|
|||
void DetachNode(NormNode *theNode);
|
||||
void Destroy(); // delete all nodes in tree
|
||||
|
||||
|
||||
|
||||
private:
|
||||
// Members
|
||||
NormNode* root;
|
||||
|
|
@ -208,6 +387,7 @@ class NormNodeList
|
|||
// Construction
|
||||
NormNodeList();
|
||||
~NormNodeList();
|
||||
unsigned int GetCount() {return count;}
|
||||
NormNode* FindNodeById(NormNodeId nodeId) const;
|
||||
void Append(NormNode* theNode);
|
||||
void Remove(NormNode* theNode);
|
||||
|
|
@ -218,13 +398,14 @@ class NormNodeList
|
|||
delete theNode;
|
||||
}
|
||||
void Destroy(); // delete all nodes in list
|
||||
|
||||
const NormNode* Head() {return head;}
|
||||
|
||||
|
||||
// Members
|
||||
private:
|
||||
NormNode* head;
|
||||
NormNode* tail;
|
||||
unsigned int count;
|
||||
}; // end class NormNodeList
|
||||
|
||||
class NormNodeListIterator
|
||||
|
|
@ -236,7 +417,7 @@ class NormNodeListIterator
|
|||
NormNode* GetNextNode()
|
||||
{
|
||||
NormNode* n = next;
|
||||
next = n ? n->next : NULL;
|
||||
next = n ? n->right : NULL;
|
||||
return n;
|
||||
}
|
||||
private:
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -28,6 +28,7 @@ class NormObject
|
|||
THRU_OBJECT
|
||||
};
|
||||
|
||||
void Verify() const;
|
||||
|
||||
virtual ~NormObject();
|
||||
NormObject::Type GetType() const {return type;}
|
||||
|
|
@ -39,14 +40,16 @@ class NormObject
|
|||
bool IsStream() const {return (STREAM == type);}
|
||||
|
||||
NormNodeId LocalNodeId() const;
|
||||
class NormServerNode* GetServer() {return server;}
|
||||
|
||||
bool IsOpen() {return (0 != segment_size);}
|
||||
// Opens (inits) object for tx operation
|
||||
bool Open(const NormObjectSize& objectSize,
|
||||
const char* infoPtr,
|
||||
UINT16 infoLen);
|
||||
// Opens (inits) object for rx operation
|
||||
bool Open(const NormObjectSize& objectSize, bool hasInfo)
|
||||
{return Open(objectSize, NULL, hasInfo ? 1 : 0);}
|
||||
{return Open(objectSize, (char*)NULL, hasInfo ? 1 : 0);}
|
||||
void Close();
|
||||
|
||||
virtual bool WriteSegment(NormBlockId blockId,
|
||||
|
|
@ -68,7 +71,7 @@ class NormObject
|
|||
NormBlockId FirstPending() {return pending_mask.FirstSet();}
|
||||
|
||||
// Methods available to server for transmission
|
||||
bool NextServerMsg(NormMessage* msg);
|
||||
bool NextServerMsg(NormObjectMsg* msg);
|
||||
NormBlock* ServerRecoverBlock(NormBlockId blockId);
|
||||
bool CalculateBlockParity(NormBlock* block);
|
||||
|
||||
|
|
@ -82,25 +85,18 @@ class NormObject
|
|||
NormBlockId blockId = theBlock->Id();
|
||||
bool result = theBlock->TxUpdate(firstSegmentId, lastSegmentId,
|
||||
BlockSize(blockId), nparity,
|
||||
segment_size, numErasures);
|
||||
if (result)
|
||||
{
|
||||
result = pending_mask.Set(blockId);
|
||||
ASSERT(result);
|
||||
}
|
||||
numErasures);
|
||||
ASSERT(result ? pending_mask.Set(blockId) : true);
|
||||
result = result ? pending_mask.Set(blockId) : false;
|
||||
return result;
|
||||
} // end NormObject::TxUpdateBlock()
|
||||
bool HandleInfoRequest();
|
||||
bool HandleBlockRequest(NormBlockId nextId, NormBlockId lastId);
|
||||
bool SetPending(NormBlockId blockId)
|
||||
{return pending_mask.Set(blockId);}
|
||||
NormBlock* FindBlock(NormBlockId blockId)
|
||||
{
|
||||
return block_buffer.Find(blockId);
|
||||
}
|
||||
bool SetPending(NormBlockId blockId) {return pending_mask.Set(blockId);}
|
||||
NormBlock* FindBlock(NormBlockId blockId) {return block_buffer.Find(blockId);}
|
||||
bool ActivateRepairs();
|
||||
bool IsRepairSet(NormBlockId blockId)
|
||||
{return repair_mask.Test(blockId);}
|
||||
bool IsRepairSet(NormBlockId blockId) {return repair_mask.Test(blockId);}
|
||||
bool AppendRepairAdv(NormCmdRepairAdvMsg& cmd);
|
||||
|
||||
// Used by session server for resource management scheme
|
||||
NormBlock* StealNonPendingBlock(bool excludeBlock, NormBlockId excludeId = 0);
|
||||
|
|
@ -108,29 +104,28 @@ class NormObject
|
|||
|
||||
// Methods available to client for reception
|
||||
bool Accepted() {return accepted;}
|
||||
void HandleObjectMessage(NormMessage& msg,
|
||||
NormMsgType msgType,
|
||||
NormBlockId blockId,
|
||||
NormSegmentId segmentId);
|
||||
bool StreamUpdateStatus(NormBlockId blockId);
|
||||
void HandleObjectMessage(const NormObjectMsg& msg,
|
||||
NormMsg::Type msgType,
|
||||
NormBlockId blockId,
|
||||
NormSegmentId segmentId);
|
||||
|
||||
|
||||
// Used by remote server node for resource management scheme
|
||||
NormBlock* StealNewestBlock(bool excludeBlock, NormBlockId excludeId = 0);
|
||||
|
||||
NormBlock* StealOldestBlock(bool excludeBlock, NormBlockId excludeId = 0);
|
||||
|
||||
bool ClientRepairCheck(CheckLevel level,
|
||||
NormBlockId blockId,
|
||||
NormSegmentId segmentId,
|
||||
bool timerActive);
|
||||
bool timerActive,
|
||||
bool holdoffPhase = false);
|
||||
bool IsRepairPending(bool flush);
|
||||
bool AppendRepairRequest(NormNackMsg& nack, bool flush);
|
||||
void SetRepairInfo() {repair_info = true;}
|
||||
bool SetRepairs(NormBlockId first, NormBlockId last)
|
||||
{
|
||||
if (first == last)
|
||||
return repair_mask.Set(first);
|
||||
else
|
||||
return repair_mask.SetBits(first, last-first+1);
|
||||
return (first == last) ? repair_mask.Set(first) :
|
||||
repair_mask.SetBits(first, last-first+1);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
@ -155,8 +150,10 @@ class NormObject
|
|||
NormSlidingMask pending_mask;
|
||||
bool repair_info;
|
||||
NormSlidingMask repair_mask;
|
||||
NormBlockId current_block_id;
|
||||
NormSegmentId next_segment_id;
|
||||
NormBlockId current_block_id; // for suppression
|
||||
NormSegmentId next_segment_id; // for suppression
|
||||
NormBlockId max_pending_block; // for NACK construction
|
||||
NormSegmentId max_pending_segment; // for NACK construction
|
||||
NormBlockId last_block_id;
|
||||
NormSegmentId last_block_size;
|
||||
UINT16 last_segment_size;
|
||||
|
|
@ -166,10 +163,7 @@ class NormObject
|
|||
|
||||
bool accepted;
|
||||
|
||||
// Extra state for STREAM objects
|
||||
bool stream_sync;
|
||||
NormBlockId stream_sync_id;
|
||||
NormBlockId stream_next_id;
|
||||
|
||||
|
||||
NormObject* next;
|
||||
}; // end class NormObject
|
||||
|
|
@ -191,15 +185,9 @@ class NormFileObject : public NormObject
|
|||
const char* Path() {return path;}
|
||||
bool Rename(const char* newPath)
|
||||
{
|
||||
if (file.Rename(path, newPath))
|
||||
{
|
||||
strncpy(path, newPath, PATH_MAX);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool result = file.Rename(path, newPath);
|
||||
result ? strncpy(path, newPath, PATH_MAX) : NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual bool WriteSegment(NormBlockId blockId,
|
||||
|
|
@ -231,6 +219,10 @@ class NormStreamObject : public NormObject
|
|||
void Close();
|
||||
|
||||
bool Accept(unsigned long bufferSize);
|
||||
bool StreamUpdateStatus(NormBlockId blockId);
|
||||
void StreamResync(NormBlockId nextBlockId)
|
||||
{stream_next_id = nextBlockId;}
|
||||
void StreamAdvance();
|
||||
|
||||
virtual bool WriteSegment(NormBlockId blockId,
|
||||
NormSegmentId segmentId,
|
||||
|
|
@ -239,8 +231,8 @@ class NormStreamObject : public NormObject
|
|||
NormSegmentId segmentId,
|
||||
char* buffer);
|
||||
|
||||
unsigned long Read(char* buffer, unsigned long len);
|
||||
unsigned long Write(char* buffer, unsigned long len, bool flush = false);
|
||||
bool Read(char* buffer, unsigned int* buflen, bool findMsgStart = 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
|
||||
void Rewind();
|
||||
|
|
@ -266,6 +258,11 @@ class NormStreamObject : public NormObject
|
|||
NormBlockId block;
|
||||
NormSegmentId segment;
|
||||
};
|
||||
// Extra state for STREAM objects
|
||||
bool stream_sync;
|
||||
NormBlockId stream_sync_id;
|
||||
NormBlockId stream_next_id;
|
||||
|
||||
NormBlockPool block_pool;
|
||||
NormSegmentPool segment_pool;
|
||||
NormBlockBuffer stream_buffer;
|
||||
|
|
@ -274,6 +271,7 @@ class NormStreamObject : public NormObject
|
|||
Index read_index;
|
||||
NormObjectSize read_offset;
|
||||
bool flush_pending;
|
||||
bool msg_start;
|
||||
}; // end class NormStreamObject
|
||||
|
||||
#ifdef SIMULATE
|
||||
|
|
@ -317,17 +315,17 @@ class NormObjectTable
|
|||
bool Init(UINT16 rangeMax, UINT16 tableSize = 256);
|
||||
void Destroy();
|
||||
|
||||
bool IsInited() {return (NULL != table);}
|
||||
bool IsInited() const {return (NULL != table);}
|
||||
bool CanInsert(NormObjectId objectId) const;
|
||||
bool Insert(NormObject* theObject);
|
||||
bool Remove(const NormObject* theObject);
|
||||
NormObject* Find(const NormObjectId& objectId) const;
|
||||
|
||||
NormObjectId RangeLo() {return range_lo;}
|
||||
NormObjectId RangeHi() {return range_hi;}
|
||||
bool IsEmpty() {return (0 == range);}
|
||||
unsigned long Count() {return count;}
|
||||
const NormObjectSize& Size() {return size;}
|
||||
NormObjectId RangeLo() const {return range_lo;}
|
||||
NormObjectId RangeHi() const {return range_hi;}
|
||||
bool IsEmpty() const {return (0 == range);}
|
||||
unsigned long Count() const {return count;}
|
||||
const NormObjectSize& Size() const {return size;}
|
||||
|
||||
class Iterator
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -8,6 +8,7 @@ NormSegmentPool::NormSegmentPool()
|
|||
{
|
||||
}
|
||||
|
||||
|
||||
NormSegmentPool::~NormSegmentPool()
|
||||
{
|
||||
Destroy();
|
||||
|
|
@ -18,6 +19,12 @@ bool NormSegmentPool::Init(unsigned int count, unsigned int size)
|
|||
if (seg_list) Destroy();
|
||||
peak_usage = 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
|
||||
unsigned int alloc_size = size / sizeof(char*);
|
||||
if ((alloc_size*sizeof(char*)) < size) alloc_size++;
|
||||
|
|
@ -157,7 +164,7 @@ void NormBlock::EmptyToPool(NormSegmentPool& segmentPool)
|
|||
}
|
||||
} // end NormBlock::EmptyToPool()
|
||||
|
||||
bool NormBlock::IsEmpty()
|
||||
bool NormBlock::IsEmpty() const
|
||||
{
|
||||
ASSERT(segment_table);
|
||||
for (unsigned int i = 0; i < size; i++)
|
||||
|
|
@ -166,7 +173,7 @@ bool NormBlock::IsEmpty()
|
|||
} // end NormBlock::EmptyToPool()
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Clients ask for a block of parity to fulfill their
|
||||
|
|
@ -250,9 +257,10 @@ bool NormBlock::ActivateRepairs(UINT16 nparity)
|
|||
} // end NormBlock::ActivateRepairs()
|
||||
|
||||
// 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,
|
||||
UINT16 ndata, UINT16 nparity,
|
||||
UINT16 segmentSize, UINT16 erasureCount)
|
||||
UINT16 ndata, UINT16 nparity, UINT16 erasureCount)
|
||||
{
|
||||
bool increasedRepair = false;
|
||||
|
||||
|
|
@ -314,7 +322,7 @@ bool NormBlock::TxUpdate(NormSegmentId nextId, NormSegmentId lastId,
|
|||
bool NormBlock::HandleSegmentRequest(NormSegmentId nextId, NormSegmentId lastId,
|
||||
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);
|
||||
bool increasedRepair = false;
|
||||
if (nextId < ndata)
|
||||
|
|
@ -373,6 +381,78 @@ bool NormBlock::HandleSegmentRequest(NormSegmentId nextId, NormSegmentId lastId,
|
|||
} // 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
|
||||
bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
|
||||
UINT16 ndata,
|
||||
|
|
@ -382,11 +462,7 @@ bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
|
|||
UINT16 segmentSize)
|
||||
{
|
||||
ASSERT(pending_mask.FirstSet() < ndata);
|
||||
NormRepairRequest req;
|
||||
nack.AttachRepairRequest(req, segmentSize);
|
||||
req.SetFlag(NormRepairRequest::SEGMENT);
|
||||
if (pendingInfo) req.SetFlag(NormRepairRequest::INFO);
|
||||
NormSegmentId nextId, lastId;
|
||||
NormSegmentId nextId, endId;
|
||||
|
||||
if (erasure_count > nparity)
|
||||
{
|
||||
|
|
@ -397,30 +473,92 @@ bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
|
|||
while (i--)
|
||||
{
|
||||
nextId++;
|
||||
nextId = pending_mask.NextSet(nextId);
|
||||
endId = pending_mask.NextSet(nextId);
|
||||
}
|
||||
lastId = ndata + nparity;
|
||||
endId = ndata + nparity;
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
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;
|
||||
while ((nextId <= lastId) || (reqCount > 0))
|
||||
while ((nextId <= lastId) || (segmentCount > 0))
|
||||
{
|
||||
// force break of possible ending consec. series
|
||||
if (nextId == lastId) nextId++;
|
||||
if (reqCount && (reqCount == (nextId - prevId)))
|
||||
if (segmentCount && (segmentCount == (nextId - prevId)))
|
||||
{
|
||||
reqCount++; // consecutive series continues
|
||||
segmentCount++; // consecutive series continues
|
||||
}
|
||||
else
|
||||
{
|
||||
NormRepairRequest::Form nextForm;
|
||||
switch(reqCount)
|
||||
switch(segmentCount)
|
||||
{
|
||||
case 0:
|
||||
nextForm = NormRepairRequest::INVALID;
|
||||
|
|
@ -464,15 +602,16 @@ bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
|
|||
} // end switch(nextForm)
|
||||
prevId = nextId;
|
||||
if (nextId < lastId)
|
||||
reqCount = 1;
|
||||
segmentCount = 1;
|
||||
else
|
||||
reqCount = 0;
|
||||
segmentCount = 0;
|
||||
} // end if/else (reqCount && (reqCount == (nextId - prevId)))
|
||||
nextId++;
|
||||
if (nextId <= lastId) nextId = pending_mask.NextSet(nextId);
|
||||
} // end while(nextId <= lastId)
|
||||
if (NormRepairRequest::INVALID != prevForm)
|
||||
nack.PackRepairRequest(req); // (TBD) error check
|
||||
*/
|
||||
return true;
|
||||
} // end NormBlock::AppendRepairRequest()
|
||||
|
||||
|
|
|
|||
|
|
@ -24,11 +24,13 @@ class NormSegmentPool
|
|||
seg_list = segment;
|
||||
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 PeakUsage() {return peak_usage;}
|
||||
unsigned long OverunCount() {return overruns;}
|
||||
unsigned long CurrentUsage() const {return (seg_total - seg_count);}
|
||||
unsigned long PeakUsage() const {return peak_usage;}
|
||||
unsigned long OverunCount() const {return overruns;}
|
||||
|
||||
unsigned int GetSegmentSize() {return seg_size;}
|
||||
|
||||
private:
|
||||
unsigned int seg_size;
|
||||
|
|
@ -117,8 +119,7 @@ class NormBlock
|
|||
bool TxReset(UINT16 ndata, UINT16 nparity, UINT16 autoParity,
|
||||
UINT16 segmentSize);
|
||||
bool TxUpdate(NormSegmentId nextId, NormSegmentId lastId,
|
||||
UINT16 ndata, UINT16 nparity,
|
||||
UINT16 segmentSize, UINT16 erasureCount);
|
||||
UINT16 ndata, UINT16 nparity, UINT16 erasureCount);
|
||||
|
||||
bool HandleSegmentRequest(NormSegmentId nextId, NormSegmentId lastId,
|
||||
UINT16 ndata, UINT16 nparity,
|
||||
|
|
@ -130,6 +131,11 @@ class NormBlock
|
|||
parity_offset = MIN(parity_offset, nparity);
|
||||
parity_count = 0;
|
||||
}
|
||||
bool AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
|
||||
NormObjectId objectId,
|
||||
bool repairInfo,
|
||||
UINT16 ndata,
|
||||
UINT16 segmentSize);
|
||||
|
||||
// Client routines
|
||||
void RxInit(NormBlockId& blockId, UINT16 ndata, UINT16 nparity)
|
||||
|
|
@ -143,11 +149,12 @@ class NormBlock
|
|||
parity_offset = 0;
|
||||
flags = 0;
|
||||
}
|
||||
// Note: This invalidates the repair_mask state.
|
||||
bool IsRepairPending(UINT16 ndata, UINT16 nparity);
|
||||
void DecrementErasureCount() {erasure_count--;}
|
||||
UINT16 ErasureCount() const {return erasure_count;}
|
||||
void IncrementParityCount() {parity_count++;}
|
||||
UINT16 ParityCount() {return parity_count;}
|
||||
UINT16 ParityCount() const {return parity_count;}
|
||||
|
||||
NormSymbolId FirstPending() const
|
||||
{return pending_mask.FirstSet();}
|
||||
|
|
@ -196,7 +203,7 @@ class NormBlock
|
|||
UINT16 segmentSize);
|
||||
//void DisplayPendingMask(FILE* f) {pending_mask.Display(f);}
|
||||
|
||||
bool IsEmpty();
|
||||
bool IsEmpty() const;
|
||||
void EmptyToPool(NormSegmentPool& segmentPool);
|
||||
|
||||
private:
|
||||
|
|
@ -222,7 +229,7 @@ class NormBlockPool
|
|||
~NormBlockPool();
|
||||
bool Init(UINT32 numBlocks, UINT16 blockSize);
|
||||
void Destroy();
|
||||
bool IsEmpty() {return (NULL == head);}
|
||||
bool IsEmpty() const {return (NULL == head);}
|
||||
NormBlock* Get()
|
||||
{
|
||||
NormBlock* b = head;
|
||||
|
|
@ -243,7 +250,7 @@ class NormBlockPool
|
|||
b->next = head;
|
||||
head = b;
|
||||
}
|
||||
unsigned long OverrunCount() {return overruns;}
|
||||
unsigned long OverrunCount() const {return overruns;}
|
||||
|
||||
private:
|
||||
NormBlock* head;
|
||||
|
|
@ -266,9 +273,9 @@ class NormBlockBuffer
|
|||
bool Remove(const NormBlock* theBlock);
|
||||
NormBlock* Find(const NormBlockId& blockId) const;
|
||||
|
||||
NormBlockId RangeLo() {return range_lo;}
|
||||
NormBlockId RangeHi() {return range_hi;}
|
||||
bool IsEmpty() {return (0 == range);}
|
||||
NormBlockId RangeLo() const {return range_lo;}
|
||||
NormBlockId RangeHi() const {return range_hi;}
|
||||
bool IsEmpty() const {return (0 == range);}
|
||||
bool CanInsert(NormBlockId blockId) const;
|
||||
|
||||
class Iterator
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -87,14 +87,17 @@ class NormSession
|
|||
|
||||
public:
|
||||
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_PROBE_MIN;
|
||||
static const double DEFAULT_PROBE_MAX;
|
||||
static const double DEFAULT_GRTT_INTERVAL_MIN;
|
||||
static const double DEFAULT_GRTT_INTERVAL_MAX;
|
||||
static const double DEFAULT_GRTT_ESTIMATE;
|
||||
static const double DEFAULT_GRTT_MAX;
|
||||
static const unsigned int DEFAULT_GRTT_DECREASE_DELAY;
|
||||
static const double DEFAULT_BACKOFF_FACTOR; // times GRTT = backoff max
|
||||
static const double DEFAULT_GSIZE_ESTIMATE;
|
||||
static const UINT16 DEFAULT_NDATA;
|
||||
static const UINT16 DEFAULT_NPARITY;
|
||||
|
||||
// General methods
|
||||
const NormNodeId& LocalNodeId() {return local_node_id;}
|
||||
|
|
@ -103,20 +106,22 @@ class NormSession
|
|||
bool IsOpen() {return (rx_socket.IsOpen() || tx_socket.IsOpen());}
|
||||
const NetworkAddress& Address() {return address;}
|
||||
void SetAddress(const NetworkAddress& addr) {address = addr;}
|
||||
static double CalculateRate(double size, double rtt, double loss);
|
||||
|
||||
|
||||
// Session parameters
|
||||
double TxRate() {return (tx_rate * 8.0);}
|
||||
// (TBD) watch timer scheduling and min/max bounds
|
||||
void SetTxRate(double txRate) {tx_rate = txRate / 8.0;}
|
||||
double BackoffFactor() {return backoff_factor;}
|
||||
void SetBackoffFactor(double value) {backoff_factor = value;}
|
||||
void SetUnicastNacks(bool state) {unicast_nacks = state;}
|
||||
bool UnicastNacks() {return unicast_nacks;}
|
||||
void SetLoopback(bool state)
|
||||
{
|
||||
rx_socket.SetLoopback(state);
|
||||
tx_socket.SetLoopback(state);
|
||||
}
|
||||
bool CongestionControl() {return cc_enable;}
|
||||
void SetCongestionControl(bool state) {cc_enable = state;}
|
||||
|
||||
void Notify(NormController::Event event,
|
||||
class NormServerNode* server,
|
||||
|
|
@ -127,11 +132,19 @@ class NormSession
|
|||
notify_pending = false;
|
||||
}
|
||||
|
||||
NormMessage* GetMessageFromPool() {return message_pool.RemoveHead();}
|
||||
void ReturnMessageToPool(NormMessage* msg) {message_pool.Append(msg);}
|
||||
void QueueMessage(NormMessage* msg);
|
||||
NormMsg* GetMessageFromPool() {return message_pool.RemoveHead();}
|
||||
void ReturnMessageToPool(NormMsg* msg) {message_pool.Append(msg);}
|
||||
void QueueMessage(NormMsg* msg);
|
||||
void SendMessage(NormMsg& msg);
|
||||
void InstallTimer(ProtocolTimer* timer)
|
||||
{session_mgr.InstallTimer(timer);}
|
||||
|
||||
// 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,
|
||||
UINT16 segmentSize,
|
||||
UINT16 numData,
|
||||
|
|
@ -151,6 +164,9 @@ class NormSession
|
|||
UINT16 ServerAutoParity() {return auto_parity;}
|
||||
void ServerSetAutoParity(UINT16 autoParity)
|
||||
{ASSERT(autoParity <= nparity); auto_parity = autoParity;}
|
||||
UINT16 ServerExtraParity() {return extra_parity;}
|
||||
void ServerSetExtraParity(UINT16 extraParity)
|
||||
{extra_parity = extraParity;}
|
||||
|
||||
double ServerGroupSize() {return gsize_measured;}
|
||||
void ServerSetGroupSize(double gsize)
|
||||
|
|
@ -172,10 +188,23 @@ class NormSession
|
|||
}
|
||||
char* ServerGetFreeSegment(NormObjectId objectId, NormBlockId blockId);
|
||||
void ServerPutFreeSegment(char* segment) {segment_pool.Put(segment);}
|
||||
|
||||
|
||||
void PromptServer()
|
||||
{
|
||||
if (!tx_timer.IsActive())
|
||||
{
|
||||
tx_timer.SetInterval(0.0);
|
||||
InstallTimer(&tx_timer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TouchServer()
|
||||
{
|
||||
posted_tx_queue_empty = false;
|
||||
if (!notify_pending) Serve();
|
||||
PromptServer();
|
||||
//if (!notify_pending) Serve();
|
||||
}
|
||||
|
||||
// Client methods
|
||||
|
|
@ -184,8 +213,10 @@ class NormSession
|
|||
bool IsClient() {return is_client;}
|
||||
unsigned long RemoteServerBufferSize()
|
||||
{return remote_server_buffer_size;}
|
||||
void InstallTimer(ProtocolTimer* timer)
|
||||
{session_mgr.InstallTimer(timer);}
|
||||
void SetUnicastNacks(bool state) {unicast_nacks = state;}
|
||||
bool UnicastNacks() {return unicast_nacks;}
|
||||
void ClientSetSilent(bool state) {client_silent = state;}
|
||||
bool ClientIsSilent() {return client_silent;}
|
||||
|
||||
// Debug settings
|
||||
void SetTrace(bool state) {trace = state;}
|
||||
|
|
@ -210,24 +241,45 @@ class NormSession
|
|||
|
||||
bool OnTxTimeout();
|
||||
bool OnRepairTimeout();
|
||||
bool OnCommandTimeout();
|
||||
bool OnFlushTimeout();
|
||||
bool OnWatermarkTimeout();
|
||||
bool OnProbeTimeout();
|
||||
bool OnReportTimeout();
|
||||
|
||||
bool TxSocketRecvHandler(UdpSocket* theSocket);
|
||||
bool RxSocketRecvHandler(UdpSocket* theSocket);
|
||||
void HandleReceiveMessage(NormMsg& msg, bool wasUnicast);
|
||||
|
||||
void HandleReceiveMessage(NormMessage& msg, bool wasUnicast);
|
||||
|
||||
void ServerHandleNackMessage(NormNackMsg& nack);
|
||||
void ServerUpdateGrttEstimate(const struct timeval& grttResponse);
|
||||
// Server message handling routines
|
||||
void ServerHandleNackMessage(const struct timeval& currentTime,
|
||||
NormNackMsg& nack);
|
||||
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);
|
||||
void ServerQueueFlush();
|
||||
bool ServerBuildRepairAdv(NormCmdRepairAdvMsg& cmd);
|
||||
void ServerUpdateGroupSize();
|
||||
|
||||
void ClientHandleObjectMessage(NormMessage& msg);
|
||||
void ClientHandleCommand(NormMessage& msg);
|
||||
void ClientHandleNackMessage(NormNackMsg& nack);
|
||||
// Client message handling routines
|
||||
void ClientHandleObjectMessage(const struct timeval& currentTime,
|
||||
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;
|
||||
bool notify_pending;
|
||||
|
|
@ -248,10 +300,12 @@ class NormSession
|
|||
|
||||
// Server parameters and state
|
||||
bool is_server;
|
||||
UINT16 session_id;
|
||||
UINT16 segment_size;
|
||||
UINT16 ndata;
|
||||
UINT16 nparity;
|
||||
UINT16 auto_parity;
|
||||
UINT16 extra_parity;
|
||||
|
||||
NormObjectTable tx_table;
|
||||
NormSlidingMask tx_pending_mask;
|
||||
|
|
@ -268,32 +322,51 @@ class NormSession
|
|||
ProtocolTimer flush_timer;
|
||||
int flush_count;
|
||||
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
|
||||
double probe_interval;
|
||||
double probe_interval_min;
|
||||
double probe_interval_max;
|
||||
bool probe_proactive;
|
||||
|
||||
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;
|
||||
unsigned int grtt_decrease_delay_count;
|
||||
bool grtt_response;
|
||||
double grtt_current_peak;
|
||||
double grtt_measured;
|
||||
double grtt_age;
|
||||
double grtt_advertised;
|
||||
UINT8 grtt_quantized;
|
||||
double gsize_measured;
|
||||
double gsize_advertised;
|
||||
UINT8 gsize_quantized;
|
||||
unsigned int gsize_nack_count;
|
||||
double gsize_nack_ave;
|
||||
double gsize_correction_factor;
|
||||
double gsize_nack_delta;
|
||||
|
||||
// Server congestion control parameters
|
||||
bool cc_enable;
|
||||
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
|
||||
bool is_client;
|
||||
NormNodeTree server_tree;
|
||||
unsigned long remote_server_buffer_size;
|
||||
bool unicast_nacks;
|
||||
bool client_silent;
|
||||
|
||||
// Protocol test/debug parameters
|
||||
bool trace;
|
||||
|
|
|
|||
|
|
@ -2,25 +2,36 @@
|
|||
|
||||
#include <errno.h>
|
||||
|
||||
NormSimAgent::NormSimAgent()
|
||||
: session(NULL), stream(NULL),
|
||||
// This NORM simulation agent includes support for providing transport
|
||||
// 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),
|
||||
tx_rate(NormSession::DEFAULT_TRANSMIT_RATE),
|
||||
cc_enable(false), unicast_nacks(false), silent_client(false),
|
||||
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),
|
||||
tx_buffer_size(1024*1024), rx_buffer_size(1024*1024),
|
||||
tx_object_size(0), tx_object_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)
|
||||
{
|
||||
// Bind NormSessionMgr to this agent and simulation environment
|
||||
session_mgr.Init(ProtoSimAgent::TimerInstaller, this,
|
||||
ProtoSimAgent::SocketInstaller, this,
|
||||
session_mgr.Init(timerInstaller, timerInstallData,
|
||||
socketInstaller, socketInstallData,
|
||||
static_cast<NormController*>(this));
|
||||
|
||||
interval_timer.Init(0.0, 0, (ProtocolTimerOwner*)this,
|
||||
(ProtocolTimeoutFunc)&NormSimAgent::OnIntervalTimeout);
|
||||
memset(mgen_buffer, 0, 64);
|
||||
}
|
||||
|
||||
NormSimAgent::~NormSimAgent()
|
||||
|
|
@ -31,30 +42,38 @@ NormSimAgent::~NormSimAgent()
|
|||
|
||||
const char* const NormSimAgent::cmd_list[] =
|
||||
{
|
||||
"+debug",
|
||||
"+log",
|
||||
"-trace",
|
||||
"+txloss",
|
||||
"+rxloss",
|
||||
"+address",
|
||||
"+ttl",
|
||||
"+rate",
|
||||
"+backoff",
|
||||
"+input",
|
||||
"+output",
|
||||
"+interval",
|
||||
"+repeat",
|
||||
"+rinterval", // repeat interval
|
||||
"+segment",
|
||||
"+block",
|
||||
"+parity",
|
||||
"+auto",
|
||||
"+gsize",
|
||||
"+txbuffer",
|
||||
"+rxbuffer",
|
||||
"+start",
|
||||
"-stop",
|
||||
"+sendFile",
|
||||
"+debug", // debug level
|
||||
"+log", // log file name
|
||||
"-trace", // message tracing
|
||||
"+txloss", // tx packet loss percent
|
||||
"+rxloss", // rx packet loss percent
|
||||
"+address", // session dest addres
|
||||
"+ttl", // multicast ttl
|
||||
"+rate", // tx rate
|
||||
"+cc", // congestion control on/off
|
||||
"+backoff", // backoff factor 'k' (maxBackoff = k * GRTT)
|
||||
"+input", // stream input
|
||||
"+output", // stream output
|
||||
"+interval", // delay between tx objects
|
||||
"+repeat", // number of times to repeat tx object set
|
||||
"+rinterval", // repeat interval
|
||||
"+segment", // server segment size
|
||||
"+block", // server blocking size
|
||||
"+parity", // server parity segments calculated per block
|
||||
"+auto", // server auto parity count
|
||||
"+extra", // server extra parity count
|
||||
"+gsize", // group size estimate
|
||||
"+txbuffer", // tx buffer size (bytes)
|
||||
"+rxbuffer", // rx buffer size (bytes)
|
||||
"+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
|
||||
};
|
||||
|
||||
|
|
@ -162,6 +181,22 @@ bool NormSimAgent::ProcessCommand(const char* cmd, const char* val)
|
|||
tx_rate = 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))
|
||||
{
|
||||
double backoffFactor = atof(val);
|
||||
|
|
@ -171,7 +206,7 @@ bool NormSimAgent::ProcessCommand(const char* cmd, const char* val)
|
|||
return false;
|
||||
}
|
||||
backoff_factor = backoffFactor;
|
||||
if (session) session->SetTxRate(backoffFactor);
|
||||
if (session) session->SetBackoffFactor(backoffFactor);
|
||||
}
|
||||
else if (!strncmp("interval", cmd, len))
|
||||
{
|
||||
|
|
@ -230,6 +265,17 @@ bool NormSimAgent::ProcessCommand(const char* cmd, const char* val)
|
|||
auto_parity = 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))
|
||||
{
|
||||
if (1 != sscanf(val, "%lf", &group_size))
|
||||
|
|
@ -292,6 +338,120 @@ bool NormSimAgent::ProcessCommand(const char* cmd, const char* val)
|
|||
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;
|
||||
} // end NormSimAgent::ProcessCommand()
|
||||
|
||||
|
|
@ -326,6 +486,81 @@ NormSimAgent::CmdType NormSimAgent::CommandType(const char* cmd)
|
|||
return type;
|
||||
} // 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,
|
||||
class NormSessionMgr* sessionMgr,
|
||||
|
|
@ -337,13 +572,31 @@ void NormSimAgent::Notify(NormController::Event event,
|
|||
{
|
||||
case TX_QUEUE_EMPTY:
|
||||
// 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
|
||||
{
|
||||
OnIntervalTimeout();
|
||||
// Schedule or queue next "sim file" transmission
|
||||
if (interval_timer.Interval() > 0.0)
|
||||
{
|
||||
InstallTimer(interval_timer);
|
||||
}
|
||||
else
|
||||
{
|
||||
OnIntervalTimeout();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -355,11 +608,19 @@ void NormSimAgent::Notify(NormController::Event event,
|
|||
{
|
||||
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()))
|
||||
{
|
||||
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;
|
||||
case NormObject::FILE:
|
||||
|
|
@ -399,11 +660,106 @@ void NormSimAgent::Notify(NormController::Event event,
|
|||
case NormObject::STREAM:
|
||||
{
|
||||
// Read the stream when it's updated
|
||||
char buffer[256];
|
||||
unsigned int nBytes;
|
||||
while ((nBytes = ((NormStreamObject*)object)->Read(buffer, 256)))
|
||||
if (mgen)
|
||||
{
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -440,7 +796,7 @@ bool NormSimAgent::OnIntervalTimeout()
|
|||
{
|
||||
if (stream)
|
||||
{
|
||||
|
||||
// (TBD)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -457,7 +813,7 @@ bool NormSimAgent::OnIntervalTimeout()
|
|||
else
|
||||
{
|
||||
// Done
|
||||
interval_timer.Deactivate();
|
||||
if (interval_timer.IsActive()) interval_timer.Deactivate();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -484,11 +840,12 @@ bool NormSimAgent::StartServer()
|
|||
{
|
||||
// Common session parameters
|
||||
session->SetTxRate(tx_rate);
|
||||
session->SetCongestionControl(cc_enable);
|
||||
session->SetBackoffFactor(backoff_factor);
|
||||
session->SetTrace(tracing);
|
||||
session->SetTxLoss(tx_loss);
|
||||
session->SetRxLoss(rx_loss);
|
||||
|
||||
session->ServerSetGroupSize(group_size);
|
||||
// StartServer(bufferMax, segmentSize, fec_ndata, fec_nparity)
|
||||
if (!session->StartServer(tx_buffer_size, segment_size, ndata, nparity))
|
||||
{
|
||||
|
|
@ -497,7 +854,7 @@ bool NormSimAgent::StartServer()
|
|||
return false;
|
||||
}
|
||||
session->ServerSetAutoParity(auto_parity);
|
||||
session->ServerSetGroupSize(group_size);
|
||||
session->ServerSetExtraParity(extra_parity);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
|
@ -534,6 +891,9 @@ bool NormSimAgent::StartClient()
|
|||
session->SetTxLoss(tx_loss);
|
||||
session->SetRxLoss(rx_loss);
|
||||
|
||||
session->SetUnicastNacks(unicast_nacks);
|
||||
session->ClientSetSilent(silent_client);
|
||||
|
||||
// StartClient(bufferSize)
|
||||
if (!session->StartClient(rx_buffer_size))
|
||||
{
|
||||
|
|
@ -558,6 +918,7 @@ void NormSimAgent::Stop()
|
|||
if (session->IsClient()) session->StopClient();
|
||||
session_mgr.DeleteSession(session);
|
||||
session = NULL;
|
||||
stream = NULL;
|
||||
}
|
||||
} // end NormSimAgent::StopServer()
|
||||
|
||||
|
|
|
|||
|
|
@ -2,38 +2,40 @@
|
|||
// normSimAgent.h - Generic (base class) NORM simulation agent
|
||||
|
||||
#include "protoLib.h"
|
||||
#include "protoSim.h"
|
||||
#include "normSession.h"
|
||||
|
||||
#include "mgen.h" // for MGEN instance attachment
|
||||
|
||||
// Base class for Norm simulation agents (e.g. ns-2, OPNET, etc)
|
||||
class NormSimAgent : public NormController
|
||||
{
|
||||
public:
|
||||
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);
|
||||
|
||||
// Note: don't allow client _and_ server operation at same time
|
||||
bool StartServer();
|
||||
bool StartClient();
|
||||
bool IsActive() {return (NULL != session);}
|
||||
void Stop();
|
||||
|
||||
bool SendMessage(unsigned int len, const char* txBuffer);
|
||||
void AttachMgen(Mgen* mgenInstance) {mgen = mgenInstance;}
|
||||
|
||||
protected:
|
||||
NormSimAgent(ProtocolTimerInstallFunc* timerInstaller,
|
||||
const void* timerInstallData,
|
||||
UdpSocketInstallFunc* socketInstaller,
|
||||
void* socketInstallData);
|
||||
enum CmdType {CMD_INVALID, CMD_NOARG, CMD_ARG};
|
||||
CmdType CommandType(const char* cmd);
|
||||
virtual unsigned long GetAgentId() = 0;
|
||||
|
||||
private:
|
||||
void OnInputReady();
|
||||
bool FlushStream();
|
||||
virtual void Notify(NormController::Event event,
|
||||
class NormSessionMgr* sessionMgr,
|
||||
class NormSession* session,
|
||||
|
|
@ -49,18 +51,21 @@ class NormSimAgent : public NormController
|
|||
|
||||
NormSessionMgr session_mgr;
|
||||
NormSession* session;
|
||||
NormStreamObject* stream;
|
||||
|
||||
// session parameters
|
||||
char* address; // session address
|
||||
UINT16 port; // session port number
|
||||
UINT8 ttl;
|
||||
double tx_rate; // bits/sec
|
||||
bool cc_enable;
|
||||
bool unicast_nacks;
|
||||
bool silent_client;
|
||||
double backoff_factor;
|
||||
UINT16 segment_size;
|
||||
UINT8 ndata;
|
||||
UINT8 nparity;
|
||||
UINT8 auto_parity;
|
||||
UINT8 extra_parity;
|
||||
double group_size;
|
||||
unsigned long tx_buffer_size; // bytes
|
||||
unsigned long rx_buffer_size; // bytes
|
||||
|
|
@ -71,6 +76,18 @@ class NormSimAgent : public NormController
|
|||
int tx_repeat_count;
|
||||
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;
|
||||
|
||||
// protocol debug parameters
|
||||
|
|
|
|||
|
|
@ -32,6 +32,6 @@
|
|||
|
||||
#ifndef _NORM_VERSION
|
||||
#define _NORM_VERSION
|
||||
#define VERSION "1.0x1"
|
||||
#define VERSION "1.0b2"
|
||||
#endif // _NORM_VERSION
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ suppress.tcl - Executable TCL script which iteratively
|
|||
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
|
||||
with NORM & PROTOLIB stuff included.
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ for {set i 1} {$i <= $numNodes} {incr i} {
|
|||
|
||||
puts "Creating topology ..."
|
||||
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_ duplex-link-op $n(0) $n($i) orient right
|
||||
$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)
|
||||
# (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
|
||||
|
||||
# 6) Configure NORM server agent at node 1
|
||||
|
|
@ -63,7 +63,7 @@ $norm(1) block 1
|
|||
$norm(1) parity 0
|
||||
$norm(1) repeat -1
|
||||
$norm(1) interval 0.0
|
||||
$norm(1) txloss 10.0
|
||||
$norm(1) txloss 0.0
|
||||
# Enabl NORM message tracing at the server
|
||||
#$norm(1) trace
|
||||
|
||||
|
|
@ -71,7 +71,7 @@ $norm(1) txloss 10.0
|
|||
for {set i 2} {$i <= $numNodes} {incr i} {
|
||||
$norm($i) address $group/5000
|
||||
$norm($i) rxbuffer 100000
|
||||
$norm($i) txloss 10.0
|
||||
$norm($i) rxloss 0.0
|
||||
#$norm($i) trace
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -39,17 +39,18 @@ static class NsNormAgentClass : public TclClass
|
|||
{
|
||||
public:
|
||||
NsNormAgentClass() : TclClass("Agent/NORM") {}
|
||||
TclObject *create(int argc, const char*const* argv)
|
||||
TclObject* create(int argc, const char*const* argv)
|
||||
{return (new NsNormAgent());}
|
||||
} class_norm_agent;
|
||||
|
||||
|
||||
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()
|
||||
|
|
@ -62,6 +63,42 @@ int NsNormAgent::command(int argc, const char*const* argv)
|
|||
int i = 1;
|
||||
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]);
|
||||
switch (cmdType)
|
||||
{
|
||||
|
|
@ -92,6 +129,13 @@ int NsNormAgent::command(int argc, const char*const* argv)
|
|||
return TCL_OK;
|
||||
} // end NsNormAgent::command()
|
||||
|
||||
bool NsNormAgent::SendMgenMessage(const NetworkAddress* dstAddr,
|
||||
const char* txBuffer,
|
||||
unsigned int len)
|
||||
{
|
||||
return SendMessage(len, txBuffer);
|
||||
} // end NsNormAgent::SendMgenMessage()
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -36,21 +36,28 @@
|
|||
#include "nsProtoAgent.h" // from ProtoLib
|
||||
#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
|
||||
// simulation environment
|
||||
|
||||
// IMPORTANT NOTE! NsProtoAgent must be listed _first_ here
|
||||
// (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:
|
||||
NsNormAgent();
|
||||
~NsNormAgent();
|
||||
|
||||
// NsProtoAgent base class overrides
|
||||
// NsProtoAgent base class override
|
||||
int command(int argc, const char*const* argv);
|
||||
// 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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -10,46 +10,47 @@ set backoffFactor "4.0"
|
|||
set sendRate "64kb"
|
||||
set duration "120.0"
|
||||
set nsTracing 0
|
||||
set unicastNacks "off"
|
||||
set cc "off"
|
||||
|
||||
#Parse optionList for parameters
|
||||
set state flag
|
||||
set state "flag"
|
||||
foreach option $optionList {
|
||||
if {"flag" != $state} {
|
||||
set reset true
|
||||
} else {
|
||||
set reset false
|
||||
}
|
||||
switch -- $state {
|
||||
"flag" {
|
||||
switch -glob -- $option {
|
||||
"gsize" {set state "gsize"}
|
||||
"rate" {set state "rate"}
|
||||
"backoff" {set state "backoff"}
|
||||
"duration" {set state "duration"}
|
||||
"unicast" {set unicastNacks "on"}
|
||||
"cc" {set cc "on"}
|
||||
"trace" {set nsTracing 1}
|
||||
default {error "simplenorm: Bad option argument $option"}
|
||||
default {set state $option}
|
||||
}
|
||||
|
||||
}
|
||||
"gsize" {
|
||||
set groupSize $option
|
||||
set state "flag"
|
||||
}
|
||||
"backoff" {
|
||||
set backoffFactor $option
|
||||
set state "flag"
|
||||
}
|
||||
"rate" {
|
||||
set sendRate $option
|
||||
set state "flag"
|
||||
}
|
||||
"duration" {
|
||||
set duration $option
|
||||
set state "flag"
|
||||
}
|
||||
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
|
||||
# for multicast operation with a dense mode (DM) multicast
|
||||
# routing protocol:
|
||||
|
|
@ -87,6 +88,7 @@ for {set i 1} {$i <= $numNodes} {incr i} {
|
|||
|
||||
puts "simplenorm: Creating spoke links ..."
|
||||
set linkRate [expr $groupSize * [bw_parse $sendRate]]
|
||||
puts "simplenorm: linkRate = [expr $linkRate / 1000.0] kbps"
|
||||
for {set i 1} {$i <= $numNodes} {incr i} {
|
||||
$ns_ duplex-link $n(0) $n($i) $linkRate 100ms DropTail
|
||||
$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))
|
||||
$norm(1) debug 2
|
||||
$norm(1) log normLog.txt
|
||||
#$norm(1) log normLog.txt
|
||||
|
||||
# 7) Configure NORM server agent at node 1
|
||||
$norm(1) address $group/5000
|
||||
$norm(1) rate [bw_parse $sendRate]
|
||||
$norm(1) backoff $backoffFactor
|
||||
$norm(1) parity 0
|
||||
$norm(1) repeat -1
|
||||
$norm(1) repeat 50
|
||||
$norm(1) interval 0.0
|
||||
$norm(1) txloss 10.0
|
||||
$norm(1) gsize $groupSize
|
||||
#$norm(1) trace
|
||||
$norm(1) cc off
|
||||
#$norm(1) trace on
|
||||
|
||||
# 8) Configure NORM client agents at other nodes
|
||||
for {set i 2} {$i <= $numNodes} {incr i} {
|
||||
$norm($i) address $group/5000
|
||||
$norm($i) backoff $backoffFactor
|
||||
$norm($i) rxbuffer 100000
|
||||
$norm($i) txloss 10.0
|
||||
$norm($i) rxbuffer 1000000
|
||||
#$norm($i) txloss 10.0
|
||||
$norm($i) gsize $groupSize
|
||||
$norm($i) unicastNacks $unicastNacks
|
||||
#$norm($i) trace
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ set rate 32kb
|
|||
set duration 120.0
|
||||
set backoff 4.0
|
||||
|
||||
set fileName "results.gp"
|
||||
set fileName "supress.gp"
|
||||
|
||||
exec rm -f $fileName
|
||||
|
||||
|
|
@ -20,8 +20,12 @@ puts $outFile "set xlabel 'Number of Receivers'"
|
|||
puts $outFile "set ylabel 'NACK Transmission Fraction'"
|
||||
puts $outFile "plot \\"
|
||||
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 "'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"
|
||||
close $outFile
|
||||
|
||||
|
|
@ -29,7 +33,19 @@ puts "Computing theoretical results ..."
|
|||
# T = number of GRTT for NACK backoff timers ...
|
||||
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"]
|
||||
puts $outFile "#Theoretical Multicast NACK Transmission Fraction"
|
||||
foreach groupSize $sizeList {
|
||||
|
|
@ -41,6 +57,19 @@ foreach groupSize $sizeList {
|
|||
puts $outFile "e\n"
|
||||
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
|
||||
set outFile [open $fileName "a"]
|
||||
puts $outFile "#Measured Multicast NACK Transmission Fraction"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ NS = ../ns
|
|||
|
||||
INCLUDES = $(TCL_INCL_PATH) $(SYSTEM_INCLUDES) -I$(UNIX) -I$(COMMON) -I$(PROTOLIB)/common
|
||||
|
||||
CFLAGS = -g -DPROTO_DEBUG -DUNIX -Wall -O -fPIC $(SYSTEM_HAVES) $(INCLUDES)
|
||||
CFLAGS = -g -DPROTO_DEBUG -DUNIX -O -fPIC $(SYSTEM_HAVES) $(INCLUDES)
|
||||
|
||||
LDFLAGS = $(SYSTEM_LDFLAGS)
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ TARGETS = mdp tkMdp
|
|||
# MDP depends upon the NRL Protean Group's development library
|
||||
LIBPROTO = $(PROTOLIB)/unix/libProto.a
|
||||
$(PROTOLIB)/unix/libProto.a:
|
||||
make -C $(PROTOLIB)/unix -f Makefile.common libProto.a
|
||||
cd $(PROTOLIB)/unix; $(MAKE) -f Makefile.$(SYSTEM) libProto.a
|
||||
|
||||
NORM_SRC = $(COMMON)/normMessage.cpp $(COMMON)/normSession.cpp \
|
||||
$(COMMON)/normNode.cpp $(COMMON)/normObject.cpp \
|
||||
|
|
@ -63,8 +63,8 @@ LIB_SRC = $(NORM_SRC)
|
|||
LIB_OBJ = $(LIB_SRC:.cpp=.o)
|
||||
|
||||
libnorm.a: $(LIB_OBJ)
|
||||
ar rcv $@ $(LIB_OBJ)
|
||||
ranlib $@
|
||||
$(AR) rcv $@ $(LIB_OBJ)
|
||||
$(RANLIB) $@
|
||||
|
||||
.cpp-sim.o:
|
||||
$(CC) -c $(CFLAGS) -DSIMULATE -o $*-sim.o $*.cpp
|
||||
|
|
@ -77,15 +77,15 @@ libnormSim.a: $(SIM_OBJ)
|
|||
ranlib $@
|
||||
|
||||
# (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)
|
||||
|
||||
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:
|
||||
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 PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
|
||||
|
|
|
|||
|
|
@ -65,5 +65,7 @@ SYSTEM_LIBS =
|
|||
export SYSTEM_HAVES = -DHAVE_GETLOGIN -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC)
|
||||
|
||||
export CC = gcc
|
||||
export RANLIB = ranlib
|
||||
export AR = ar
|
||||
|
||||
include Makefile.common
|
||||
|
|
|
|||
|
|
@ -65,5 +65,7 @@ SYTSTEM_LIBS =
|
|||
export SYSTEM_HAVES = -DHAVE_CUSERID -DHAVE_LOCKF
|
||||
|
||||
export CC = gcc
|
||||
export RANLIB = touch
|
||||
export AR = ar
|
||||
|
||||
include Makefile.common
|
||||
|
|
|
|||
|
|
@ -10,19 +10,19 @@
|
|||
|
||||
# 1) Where to find the Tcl standard library scripts
|
||||
# (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
|
||||
# (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
|
||||
# (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
|
||||
TCL_LIB = -ltcl #/usr/local/lib/libtcl8.0.a
|
||||
TK_LIB = -ltk #/usr/local/lib/libtk8.0.a
|
||||
|
||||
|
||||
# 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)
|
||||
|
||||
export CC = gcc
|
||||
export RANLIB = ranlib
|
||||
export AR = ar
|
||||
|
||||
include Makefile.common
|
||||
|
|
|
|||
|
|
@ -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
|
||||
# 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
|
||||
# 1) System specific additional libraries, include paths, etc
|
||||
# (Where to find X11 libraries, etc)
|
||||
#
|
||||
SYSTEM_INCLUDES = -I/usr/X11R6/include
|
||||
SYSTEM_LDFLAGS = -L/usr/X11R6/lib
|
||||
SYSTEM_LIBS =
|
||||
|
||||
# 6) System specific capabilities
|
||||
# 2) System specific capabilities
|
||||
# Must choose appropriate for the following:
|
||||
#
|
||||
# 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()
|
||||
# routine.
|
||||
#
|
||||
# E) The MDP code's use of offset pointers requires special treatment
|
||||
# for some different compilers. Set -DUSE_INHERITANCE for some
|
||||
# to keep some compilers (gcc 2.7.2) happy.
|
||||
#
|
||||
# F) Some systems (SOLARIS/SUNOS) have a few gotchas which require
|
||||
# E) Some systems (SOLARIS/SUNOS) have a few gotchas which require
|
||||
# some #ifdefs to avoid compiler warnings ... so you might need
|
||||
# to specify -DSOLARIS or -DSUNOS depending on your OS.
|
||||
#
|
||||
# G) Uncomment this if you have the NRL IPv6+IPsec software
|
||||
# F) Uncomment this if you have the NRL IPv6+IPsec software
|
||||
#DNETSEC = -DNETSEC -I/usr/inet6/include
|
||||
#
|
||||
# (We export these for other Makefiles as needed)
|
||||
#
|
||||
|
||||
export SYSTEM_HAVES = -DHAVE_ASSERT -DHAVE_GETLOGIN -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC)
|
||||
export 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
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ SYSTEM_LIBS = -ldl
|
|||
export SYSTEM_HAVES = -DHAVE_CUSERID -DHAVE_LOCKF -DHAVE_DIRFD $(NETSEC)
|
||||
|
||||
export CC = gcc
|
||||
export RANLIB = ranlib
|
||||
export AR = ar
|
||||
|
||||
include Makefile.common
|
||||
|
||||
|
|
|
|||
|
|
@ -62,8 +62,10 @@ SYSTEM_LIBS =
|
|||
# (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 RANLIB = ranlib
|
||||
export AR = ar
|
||||
|
||||
include Makefile.common
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
#
|
||||
SYSTEM_INCLUDES =
|
||||
SYSTEM_INCLUDES = -DIRIX -n32 -woff 3333 -cfront
|
||||
SYSTEM_LDFLAGS =
|
||||
SYSTEM_LIBS =
|
||||
|
||||
|
|
@ -59,11 +38,17 @@ SYSTEM_LIBS =
|
|||
# G) Uncomment this if you have the NRL IPv6+IPsec software
|
||||
#DNETSEC = -DNETSEC -I/usr/inet6/include
|
||||
#
|
||||
# (We export these for other Makefiles as needed)
|
||||
#
|
||||
|
||||
export SYSTEM_HAVES = -DUSE_INHERITANCE -DHAVE_CUSERID -DHAVE_LOCKF $(NETSEC)
|
||||
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
|
||||
|
|
|
|||
|
|
@ -63,5 +63,7 @@ SYSTEM_LIBS = -ldl -lnsl -lsocket
|
|||
export SYSTEM_HAVES = -DHAVE_ASSERT -DHAVE_CUSERID -DHAVE_LOCKF $(NETSEC) -DSOLARIS
|
||||
|
||||
export CC = gcc
|
||||
export RANLIB = touch
|
||||
export AR = ar
|
||||
|
||||
include Makefile.common
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ SYSTEM_LIBS = -ldl -lnsl -lsocket
|
|||
export SYSTEM_HAVES = -DHAVE_ASSERT -DHAVE_CUSERID -DHAVE_LOCKF $(NETSEC) -DSOLARIS
|
||||
|
||||
export CC = gcc
|
||||
export RANLIB = touch
|
||||
export AR = ar
|
||||
|
||||
include Makefile.common
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue