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

View File

@ -35,9 +35,9 @@
namespace Norm
{
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];}

View File

@ -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(&currentTime);
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 readLength;
if (output_messaging)
{
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 < nBytes)
while (put < writeLength)
{
size_t result = fwrite(buffer, sizeof(char), nBytes, output);
fflush(output);
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);
if (input)
{
if (input_active)
{
dispatcher.RemoveGenericInput(fileno(input));
input_active = false;
}
if (stdin != input) fclose(input);
input = NULL;
if (output) fclose(output);
}
if (output)
{
if (stdout != output) fclose(output);
output = NULL;
}
} // end NormApp::OnShutdown()
@ -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;

View File

@ -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;

View File

@ -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_

View File

@ -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()

View File

@ -40,7 +40,7 @@ class NormEncoder
// Members
private:
int npar; // No. of parity packets (N-k)
int vecSize; // Size of biggest vector to encode
int vector_size; // Size of biggest vector to encode
unsigned char* genPoly; // Ptr to generator polynomial
unsigned char* scratch; // scratch space for encoding
@ -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();

View File

@ -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()

View File

@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -16,12 +16,13 @@ class NormNode
NormNode(class NormSession* theSession, NormNodeId nodeId);
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

View File

@ -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,
void HandleObjectMessage(const NormObjectMsg& msg,
NormMsg::Type msgType,
NormBlockId blockId,
NormSegmentId segmentId);
bool StreamUpdateStatus(NormBlockId blockId);
// 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
{

165
common/normPostProcess.cpp Normal file
View File

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

35
common/normPostProcess.h Normal file
View File

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

View File

@ -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()

View File

@ -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

View File

@ -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;

View File

@ -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",
"+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",
"+block",
"+parity",
"+auto",
"+gsize",
"+txbuffer",
"+rxbuffer",
"+start",
"-stop",
"+sendFile",
"+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,6 +572,23 @@ void NormSimAgent::Notify(NormController::Event event,
{
case TX_QUEUE_EMPTY:
// Can queue a new object or write to stream for transmission
if (object && (object == stream))
{
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
{
// Schedule or queue next "sim file" transmission
if (interval_timer.Interval() > 0.0)
{
InstallTimer(interval_timer);
@ -345,6 +597,7 @@ void NormSimAgent::Notify(NormController::Event event,
{
OnIntervalTimeout();
}
}
break;
case RX_OBJECT_NEW:
@ -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()

View File

@ -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

View File

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

View File

@ -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.

View File

@ -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
}

253
ns/normcc.tcl Normal file
View File

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

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

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

View File

@ -39,17 +39,18 @@ static class NsNormAgentClass : public TclClass
{
public:
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::Init(ProtoSimAgent::TimerInstaller,
: NormSimAgent(ProtoSimAgent::TimerInstaller,
static_cast<ProtoSimAgent*>(this),
ProtoSimAgent::SocketInstaller,
static_cast<ProtoSimAgent*>(this));
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()

View File

@ -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

View File

@ -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
}

View File

@ -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"

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,38 +1,15 @@
#
# MacOS X Protean Makefile definitions
# Protean MacOS X (Darwin) Makefile definitions
#
# TO BUILD THE TK GUI VERSION, EDIT THE FOLLOWING NUMBERED
# 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

View File

@ -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

View File

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

View File

@ -1,34 +1,13 @@
#
# MDPv2 IRIX Makefile
# IRIX Protean Makefile definitions
#
# TO BUILD THE TK GUI VERSION OF MDP EDIT THE FOLLOWING NUMBERED
# ITEMS AS NEEDED FOR YOUR SYSTEM
# (This has only been tested with TCL/TK 8.0 but it probably
# will work with Tcl7.x/Tk4.x with a little tweaking to
# the list of TCL_SCRIPTS (library scripts) given below)
# 1) Where to find the Tcl standard library scripts
# (e.g. init.tcl, ...)
TCL_SCRIPT_PATH = /usr/local/lib/tcl8.0
# 2) Where to find the Tk standard library scripts
# (e.g. button.tcl, entry.tcl, ...)
TK_SCRIPT_PATH = /usr/local/lib/tk8.0
# 3) Where to find Tcl/Tk header files
# (e.g. tcl.h, tk.h, ...)
TCL_INCL_PATH = -I/usr/local/include
# 4) Point to specific libtcl.a and libtk.a to use
TCL_LIB = /usr/local/lib/libtcl8.0.a
TK_LIB = /usr/local/lib/libtk8.0.a
# 5) System specific additional libraries, include paths, etc
# 1) System specific additional libraries, include paths, etc
# (Where to find X11 libraries, etc)
#
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

View File

@ -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

View File

@ -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