make tabs/spaces consistent; fix minor SetSilentReceiver logic bug; add missing bits to usage statements; copy 'ack auto' commandline option and logic from normCast/normStreamer into normMsgr

pull/18/head
Jeffery Weston 2020-09-14 15:58:09 -04:00
parent 0ff199fc3c
commit fe2e9d7f02
3 changed files with 283 additions and 253 deletions

View File

@ -121,16 +121,16 @@ class NormCaster
// Receiver methods // Receiver methods
void SetRxCacheDirectory(const char* path) void SetRxCacheDirectory(const char* path)
{ {
strncpy(rx_cache_path, path, PATH_MAX); strncpy(rx_cache_path, path, PATH_MAX);
unsigned int len = strlen(rx_cache_path); unsigned int len = strlen(rx_cache_path);
if (PROTO_PATH_DELIMITER != rx_cache_path[len - 1]) if (PROTO_PATH_DELIMITER != rx_cache_path[len - 1])
{ {
if (PATH_MAX == len) len--; if (PATH_MAX == len) len--;
rx_cache_path[len] = PROTO_PATH_DELIMITER; rx_cache_path[len] = PROTO_PATH_DELIMITER;
rx_cache_path[len + 1] = '\0'; rx_cache_path[len + 1] = '\0';
} }
} }
const char* GetRxCacheDirectory() const const char* GetRxCacheDirectory() const
{return rx_cache_path;} {return rx_cache_path;}
@ -143,7 +143,7 @@ class NormCaster
norm_acking = enable; norm_acking = enable;
} }
void SetSilentReceiver(bool state) void SetSilentReceiver(bool state)
{NormSetSilentReceiver(norm_session, true);} {NormSetSilentReceiver(norm_session, state);}
void SetProbeTOS(UINT8 value) void SetProbeTOS(UINT8 value)
{probe_tos = value;} {probe_tos = value;}
@ -348,7 +348,7 @@ bool NormCaster::TxReady() const
// NORM_TX_QUEUE_VACANCY notifications (tracked by the "norm_tx_vacancy" variable, // NORM_TX_QUEUE_VACANCY notifications (tracked by the "norm_tx_vacancy" variable,
// _and_ (if ack-based flow control is enabled) the norm_tx_queue_count or // _and_ (if ack-based flow control is enabled) the norm_tx_queue_count or
// norm_stream_buffer_count status. // norm_stream_buffer_count status.
if (norm_tx_vacancy) if (norm_tx_vacancy)
{ {
if (norm_tx_queue_count >= norm_tx_queue_max) if (norm_tx_queue_count >= norm_tx_queue_max)
return false; // still waiting for ACK return false; // still waiting for ACK
@ -639,7 +639,7 @@ void NormCaster::HandleNormEvent(const NormEvent& event)
if ('/' == fileName[i]) if ('/' == fileName[i])
fileName[i] = PROTO_PATH_DELIMITER; fileName[i] = PROTO_PATH_DELIMITER;
} }
if (!NormFileRename(event.object, fileName)) if (!NormFileRename(event.object, fileName))
perror("normCast: rx file rename error"); perror("normCast: rx file rename error");
break; break;
} }
@ -667,15 +667,17 @@ void NormCaster::HandleNormEvent(const NormEvent& event)
void Usage() void Usage()
{ {
fprintf(stderr, "Usage: normCast id <nodeId> {send <file/dir list> &| recv <rxCacheDir>}\n" fprintf(stderr, "Usage: normCast id <nodeIdInteger> {send <file/dir list> &| recv <rxCacheDir>}\n"
" [addr <addr>[/<port>]][interface <name>][ack <node1>[,<node2>,...]\n" " [addr <addr>[/<port>]] [interface <name>] [loopback]\n"
" [cc|cce|ccl|rate <bitsPerSecond>][ptos <value>]\n" " [ack auto|<node1>[,<node2>,...]]\n"
" [debug <level>][trace]\n"); " [cc|cce|ccl|rate <bitsPerSecond>] [ptos <value>]\n"
" [flush {none|passive|active}] [silent] [txloss <lossFraction>]\n"
" [debug <level>] [trace] [log <logfile>]\n");
} // end Usage() } // end Usage()
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
// REQUIRED parameters initiailization // REQUIRED parameters initiailization
NormNodeId nodeId = NORM_NODE_NONE; NormNodeId nodeId = NORM_NODE_NONE;
bool send = false; bool send = false;
bool recv = false; bool recv = false;
@ -967,20 +969,20 @@ int main(int argc, char* argv[])
return -1; return -1;
} }
// TBD - should provide more error checking of calls // TBD - should provide more error checking of calls
NormInstanceHandle normInstance = NormCreateInstance(); NormInstanceHandle normInstance = NormCreateInstance();
NormSetDebugLevel(debugLevel); NormSetDebugLevel(debugLevel);
if (NULL != debugLog) if (NULL != debugLog)
NormOpenDebugLog(normInstance, debugLog); NormOpenDebugLog(normInstance, debugLog);
// TBD - enhance NORM to support per-session or perhaps per-sender rx cache directories? // TBD - enhance NORM to support per-session or perhaps per-sender rx cache directories?
if (recv) if (recv)
NormSetCacheDirectory(normInstance, normCast.GetRxCacheDirectory()); NormSetCacheDirectory(normInstance, normCast.GetRxCacheDirectory());
normCast.SetLoopback(loopback); normCast.SetLoopback(loopback);
normCast.SetFlushing(flushing); normCast.SetFlushing(flushing);
if (!normCast.OpenNormSession(normInstance, sessionAddr, sessionPort, (NormNodeId)nodeId)) if (!normCast.OpenNormSession(normInstance, sessionAddr, sessionPort, (NormNodeId)nodeId))
{ {
fprintf(stderr, "normCast error: unable to open NORM session\n"); fprintf(stderr, "normCast error: unable to open NORM session\n");
NormDestroyInstance(normInstance); NormDestroyInstance(normInstance);
@ -1023,10 +1025,10 @@ int main(int argc, char* argv[])
if (trace) normCast.SetNormMessageTrace(true); if (trace) normCast.SetNormMessageTrace(true);
// TBD - set NORM session parameters // TBD - set NORM session parameters
normCast.Start(send, recv); normCast.Start(send, recv);
if (normCast.TxFilePending()) normCast.SendFiles(); if (normCast.TxFilePending()) normCast.SendFiles();
#ifdef WIN32 #ifdef WIN32
//Win32InputHandler inputHandler; //Win32InputHandler inputHandler;
@ -1050,7 +1052,7 @@ int main(int argc, char* argv[])
bool normEventPending = false; bool normEventPending = false;
bool inputEventPending = false; bool inputEventPending = false;
#ifdef WIN32 #ifdef WIN32
DWORD handleCount = inputNeeded ? 2 : 1; DWORD handleCount = inputNeeded ? 2 : 1;
DWORD waitStatus = DWORD waitStatus =
MsgWaitForMultipleObjectsEx(handleCount, // number of handles in array MsgWaitForMultipleObjectsEx(handleCount, // number of handles in array
handleArray, // object-handle array handleArray, // object-handle array

View File

@ -192,8 +192,14 @@ class NormMsgr
{omit_header = state;} {omit_header = state;}
// These can only be called post-OpenNormSession // These can only be called post-OpenNormSession
void SetAutoAck(bool enable)
{
NormTrackingStatus trackingMode = enable? NORM_TRACK_RECEIVERS : NORM_TRACK_NONE;
NormSetAutoAckingNodes(norm_session, trackingMode);
norm_acking = enable;
}
void SetSilentReceiver(bool state) void SetSilentReceiver(bool state)
{NormSetSilentReceiver(norm_session, true);} {NormSetSilentReceiver(norm_session, state);}
void SetTxLoss(double txloss) void SetTxLoss(double txloss)
{NormSetTxLoss(norm_session, txloss);} {NormSetTxLoss(norm_session, txloss);}
@ -773,9 +779,11 @@ void NormMsgr::HandleNormEvent(const NormEvent& event)
void Usage() void Usage()
{ {
fprintf(stderr, "Usage: normMsgr id <nodeId> {send &| recv} [addr <addr>[/<port>]][ack <node1>[,<node2>,...]\n" fprintf(stderr, "Usage: normMsgr id <nodeIdInteger> {send &| recv} [addr <addr>[/<port>]]\n"
" [cc|cce|ccl|rate <bitsPerSecond>][interface <name>][debug <level>][trace]\n" " [ack auto|<node1>[,<node2>,...]] [output <outFile>]\n"
" [flush {none|active}][omit][silent][txloss <lossFraction>]\n"); " [cc|cce|ccl|rate <bitsPerSecond>] [interface <name>] [loopback]\n"
" [debug <level>] [trace] [log <logfile>] [silent]\n"
" [flush {none|passive|active}] [omit] [txloss <lossFraction>]\n");
} }
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
@ -788,6 +796,7 @@ int main(int argc, char* argv[])
strcpy(sessionAddr, "224.1.2.3"); strcpy(sessionAddr, "224.1.2.3");
unsigned int sessionPort = 6003; unsigned int sessionPort = 6003;
bool autoAck = false;
NormNodeId ackingNodeList[256]; NormNodeId ackingNodeList[256];
unsigned int ackingNodeCount = 0; unsigned int ackingNodeCount = 0;
bool flushing = false; bool flushing = false;
@ -886,20 +895,28 @@ int main(int argc, char* argv[])
return -1; return -1;
} }
const char* alist = argv[i++]; const char* alist = argv[i++];
while ((NULL != alist) && (*alist != '\0')) if (0 == strcmp("auto", alist))
{ {
// TBD - Do we need to skip leading white space? autoAck = true;
int id; }
if (1 != sscanf(alist, "%d", &id)) else
{
autoAck = false;
while ((NULL != alist) && (*alist != '\0'))
{ {
fprintf(stderr, "nodeMsgr error: invalid acking node list!\n"); // TBD - Do we need to skip leading white space?
Usage(); int id;
return -1; if (1 != sscanf(alist, "%d", &id))
{
fprintf(stderr, "nodeMsgr error: invalid acking node list!\n");
Usage();
return -1;
}
ackingNodeList[ackingNodeCount] = NormNodeId(id);
ackingNodeCount++;
alist = strchr(alist, ',');
if (NULL != alist) alist++; // point past comma
} }
ackingNodeList[ackingNodeCount] = NormNodeId(id);
ackingNodeCount++;
alist = strchr(alist, ',');
if (NULL != alist) alist++; // point past comma
} }
} }
else if (0 == strncmp(cmd, "flush", len)) else if (0 == strncmp(cmd, "flush", len))
@ -1057,8 +1074,15 @@ int main(int argc, char* argv[])
if (silentReceiver) normMsgr.SetSilentReceiver(true); if (silentReceiver) normMsgr.SetSilentReceiver(true);
if (txloss > 0.0) normMsgr.SetTxLoss(txloss); if (txloss > 0.0) normMsgr.SetTxLoss(txloss);
for (unsigned int i = 0; i < ackingNodeCount; i++) if (autoAck)
normMsgr.AddAckingNode(ackingNodeList[i]); {
normMsgr.SetAutoAck(true);
}
else
{
for (unsigned int i = 0; i < ackingNodeCount; i++)
normMsgr.AddAckingNode(ackingNodeList[i]);
}
normMsgr.SetNormCongestionControl(ccMode); normMsgr.SetNormCongestionControl(ccMode);
if (NormMsgr::NORM_FIXED == ccMode) if (NormMsgr::NORM_FIXED == ccMode)

View File

@ -83,7 +83,7 @@ class NormStreamer
{ack_ex = state;} {ack_ex = state;}
bool EnableUdpRelay(const char* relayAddr, unsigned short relayPort); bool EnableUdpRelay(const char* relayAddr, unsigned short relayPort);
bool EnableUdpListener(unsigned short thePort, const char* groupAddr, const char * interfaceName); bool EnableUdpListener(unsigned short thePort, const char* groupAddr, const char * interfaceName);
bool UdpListenerEnabled() const bool UdpListenerEnabled() const
{return input_socket.IsOpen();} {return input_socket.IsOpen();}
bool UdpRelayEnabled() const bool UdpRelayEnabled() const
@ -253,7 +253,7 @@ class NormStreamer
// These can only be called post-OpenNormSession() // These can only be called post-OpenNormSession()
void SetSilentReceiver(bool state) void SetSilentReceiver(bool state)
{NormSetSilentReceiver(norm_session, true);} {NormSetSilentReceiver(norm_session, state);}
void SetTxLoss(double txloss) void SetTxLoss(double txloss)
{NormSetTxLoss(norm_session, txloss);} {NormSetTxLoss(norm_session, txloss);}
// Set the scheduler for running the app and norm threads. // Set the scheduler for running the app and norm threads.
@ -267,7 +267,7 @@ class NormStreamer
{num_parity = numParity;} {num_parity = numParity;}
void SetAutoParity(unsigned short autoParity) void SetAutoParity(unsigned short autoParity)
{auto_parity = autoParity;} {auto_parity = autoParity;}
void SetStreamBufferSize(unsigned int value) void SetStreamBufferSize(unsigned int value)
{stream_buffer_size = value;} {stream_buffer_size = value;}
void SetTxSocketBufferSize(unsigned int value) void SetTxSocketBufferSize(unsigned int value)
@ -284,12 +284,12 @@ class NormStreamer
{probe_tos = value;} {probe_tos = value;}
// Check that sequence numbers increase by one each time. // Check that sequence numbers increase by one each time.
// Assumes that sequence number is 8- or 4-byte network-order first 8 bytes of buffer. // Assumes that sequence number is 8- or 4-byte network-order first 8 bytes of buffer.
void CheckSequenceNumber(const char* buffer, const char* source); void CheckSequenceNumber(const char* buffer, const char* source);
void CheckSequenceNumber64(const char* buffer, const char* source); void CheckSequenceNumber64(const char* buffer, const char* source);
void CheckSequenceNumber32(const char* buffer, const char* source); void CheckSequenceNumber32(const char* buffer, const char* source);
void SetCheckSequence(unsigned int value) // 64 or 32 void SetCheckSequence(unsigned int value) // 64 or 32
{check_sequence = value;} {check_sequence = value;}
private: private:
NormSessionHandle norm_session; NormSessionHandle norm_session;
@ -391,22 +391,22 @@ NormStreamer::~NormStreamer()
bool NormStreamer::BoostPriority() bool NormStreamer::BoostPriority()
{ {
#ifdef LINUX #ifdef LINUX
pid_t this_process = getpid() ; pid_t this_process = getpid() ;
int policy = SCHED_FIFO ; int policy = SCHED_FIFO ;
int max_priority = sched_get_priority_max(policy) ; int max_priority = sched_get_priority_max(policy) ;
struct sched_param schedule_parameters ; struct sched_param schedule_parameters ;
memset((void*)&schedule_parameters, 0, sizeof(schedule_parameters)) ; memset((void*)&schedule_parameters, 0, sizeof(schedule_parameters)) ;
schedule_parameters.sched_priority = max_priority ; schedule_parameters.sched_priority = max_priority ;
int status = sched_setscheduler(this_process, policy, &schedule_parameters) ; int status = sched_setscheduler(this_process, policy, &schedule_parameters) ;
if (0 != status) if (0 != status)
{ {
fprintf(stderr, "%s:=>sched_setscheduler failed (%d), %s\n", __PRETTY_FUNCTION__, errno, strerror(errno) ) ; fprintf(stderr, "%s:=>sched_setscheduler failed (%d), %s\n", __PRETTY_FUNCTION__, errno, strerror(errno) ) ;
return false ; return false ;
} }
else else
{ {
fprintf(stderr, "%s:=>sched_setscheduler set priority to %d for process %u \n", __PRETTY_FUNCTION__, max_priority, this_process ) ; fprintf(stderr, "%s:=>sched_setscheduler set priority to %d for process %u \n", __PRETTY_FUNCTION__, max_priority, this_process ) ;
} }
#else #else
// (TBD) Do something differently if "pthread sched param"? // (TBD) Do something differently if "pthread sched param"?
if (0 != setpriority(PRIO_PROCESS, getpid(), -20)) if (0 != setpriority(PRIO_PROCESS, getpid(), -20))
@ -422,34 +422,34 @@ bool NormStreamer::BoostPriority()
//Convert net-order to host-order. //Convert net-order to host-order.
uint64_t ntohll(uint64_t value) uint64_t ntohll(uint64_t value)
{ {
static const int betest = 1 ; static const int betest = 1 ;
union MyUnion union MyUnion
{ {
uint64_t i64; uint64_t i64;
uint32_t i32[2]; uint32_t i32[2];
}; };
uint64_t rval = value; uint64_t rval = value;
bool host_is_little_endian = ( 1 == (int)(*(char*)&betest) ) ; bool host_is_little_endian = ( 1 == (int)(*(char*)&betest) ) ;
if ( host_is_little_endian ) if ( host_is_little_endian )
{ {
MyUnion u; MyUnion u;
u.i64 = value; u.i64 = value;
uint32_t temp = u.i32[0]; uint32_t temp = u.i32[0];
u.i32[0] = ntohl(u.i32[1]); u.i32[0] = ntohl(u.i32[1]);
u.i32[1] = ntohl(temp); u.i32[1] = ntohl(temp);
rval = u.i64; rval = u.i64;
} }
return rval ; return rval ;
} }
#endif // !nothll #endif // !nothll
void NormStreamer::CheckSequenceNumber64(const char* buffer, const char* source) void NormStreamer::CheckSequenceNumber64(const char* buffer, const char* source)
{ {
uint64_t temp; uint64_t temp;
memcpy((void*)&temp, (void*)buffer, sizeof(temp)); memcpy((void*)&temp, (void*)buffer, sizeof(temp));
uint64_t sequence = ntohll(temp); uint64_t sequence = ntohll(temp);
if (0 != sequence_prev) if (0 != sequence_prev)
{ {
int64_t delta = (int64_t)(sequence - sequence_prev); int64_t delta = (int64_t)(sequence - sequence_prev);
@ -460,14 +460,14 @@ void NormStreamer::CheckSequenceNumber64(const char* buffer, const char* source)
(unsigned long)sequence_prev); (unsigned long)sequence_prev);
} }
} }
sequence_prev = sequence; sequence_prev = sequence;
} // end NormStreamer::CheckSequenceNumber64() } // end NormStreamer::CheckSequenceNumber64()
void NormStreamer::CheckSequenceNumber32(const char* buffer, const char* source) void NormStreamer::CheckSequenceNumber32(const char* buffer, const char* source)
{ {
uint32_t temp; uint32_t temp;
memcpy((void*)&temp, (void*)buffer, sizeof(temp)); memcpy((void*)&temp, (void*)buffer, sizeof(temp));
uint32_t sequence = ntohll(temp); uint32_t sequence = ntohll(temp);
if (0 != sequence_prev) if (0 != sequence_prev)
{ {
int32_t delta = (int32_t)(sequence - sequence_prev); int32_t delta = (int32_t)(sequence - sequence_prev);
@ -478,7 +478,7 @@ void NormStreamer::CheckSequenceNumber32(const char* buffer, const char* source)
(unsigned long)sequence_prev); (unsigned long)sequence_prev);
} }
} }
sequence_prev = sequence; sequence_prev = sequence;
} // end NormStreamer::CheckSequenceNumber32() } // end NormStreamer::CheckSequenceNumber32()
void NormStreamer::CheckSequenceNumber(const char* buffer, const char* source) void NormStreamer::CheckSequenceNumber(const char* buffer, const char* source)
@ -505,7 +505,7 @@ bool NormStreamer::EnableUdpRelay(const char* relayAddr, unsigned short relayPor
} }
if (!output_socket.SetTxBufferSize(output_socket_buffer_size)) if (!output_socket.SetTxBufferSize(output_socket_buffer_size))
{ {
fprintf(stderr, "normStreamer warning: unable to set desired 'relay' socket buffer size (retrieved value:%u)\n", fprintf(stderr, "normStreamer warning: unable to set desired 'relay' socket buffer size (retrieved value:%u)\n",
output_socket.GetTxBufferSize()); output_socket.GetTxBufferSize());
} }
if (!relay_addr.ResolveFromString(relayAddr)) if (!relay_addr.ResolveFromString(relayAddr))
@ -523,12 +523,12 @@ bool NormStreamer::EnableUdpListener(unsigned short thePort, const char* groupAd
if (!input_socket.Open(thePort)) if (!input_socket.Open(thePort))
{ {
fprintf(stderr, "normStreamer error: unable to open 'listen' socket on port %hu\n", thePort); fprintf(stderr, "normStreamer error: unable to open 'listen' socket on port %hu\n", thePort);
return false; return false;
} }
if (!input_socket.SetRxBufferSize(input_socket_buffer_size)) if (!input_socket.SetRxBufferSize(input_socket_buffer_size))
{ {
fprintf(stderr, "normStreamer error: unable to set desired 'listen' socket buffer size\n"); fprintf(stderr, "normStreamer error: unable to set desired 'listen' socket buffer size\n");
return false; return false;
} }
if (NULL != groupAddr) if (NULL != groupAddr)
{ {
@ -537,15 +537,15 @@ bool NormStreamer::EnableUdpListener(unsigned short thePort, const char* groupAd
{ {
fprintf(stderr, "normStreamer error: invalid 'listen' group address\n"); fprintf(stderr, "normStreamer error: invalid 'listen' group address\n");
input_socket.Close(); input_socket.Close();
return false ; return false ;
} }
if (!input_socket.JoinGroup(addr, interfaceName)) if (!input_socket.JoinGroup(addr, interfaceName))
{ {
fprintf(stderr, "normStreamer error: unable to join 'listen' group address\n"); fprintf(stderr, "normStreamer error: unable to join 'listen' group address\n");
input_socket.Close(); input_socket.Close();
return false; return false;
} }
} }
return true; return true;
} // end NormStreamer::EnableUdpListener() } // end NormStreamer::EnableUdpListener()
@ -629,7 +629,7 @@ bool NormStreamer::Start(bool sender, bool receiver)
return false; return false;
} }
if (0 != mlockall(MCL_CURRENT | MCL_FUTURE)) if (0 != mlockall(MCL_CURRENT | MCL_FUTURE))
fprintf(stderr, "normStreamer error: failed to lock memory for receiver.\n"); fprintf(stderr, "normStreamer error: failed to lock memory for receiver.\n");
if (0 != rx_socket_buffer_size) if (0 != rx_socket_buffer_size)
NormSetRxSocketBuffer(norm_session, rx_socket_buffer_size); NormSetRxSocketBuffer(norm_session, rx_socket_buffer_size);
rx_needed = true; rx_needed = true;
@ -679,11 +679,11 @@ bool NormStreamer::Start(bool sender, bool receiver)
if (receiver) NormStopReceiver(norm_session); if (receiver) NormStopReceiver(norm_session);
return false; return false;
} }
else else
{ {
if (0 != mlockall(MCL_CURRENT|MCL_FUTURE)) if (0 != mlockall(MCL_CURRENT|MCL_FUTURE))
fprintf(stderr, "normStreamer warning: failed to lock memory for sender.\n"); fprintf(stderr, "normStreamer warning: failed to lock memory for sender.\n");
} }
tx_stream_buffer_max = NormGetStreamBufferSegmentCount(bufferSize, segment_size, block_size); tx_stream_buffer_max = NormGetStreamBufferSegmentCount(bufferSize, segment_size, block_size);
tx_stream_buffer_max -= block_size; // a little safety margin (perhaps not necessary) tx_stream_buffer_max -= block_size; // a little safety margin (perhaps not necessary)
tx_stream_buffer_threshold = tx_stream_buffer_max / 8; tx_stream_buffer_threshold = tx_stream_buffer_max / 8;
@ -1340,31 +1340,35 @@ void NormStreamer::HandleNormEvent(const NormEvent& event)
void Usage() void Usage()
{ {
fprintf(stderr, "Usage: normStreamer id <nodeId> {send|recv} [addr <addr>[/<port>]][interface <name>][loopback][info]\n" fprintf(stderr, "Usage: normStreamer id <nodeIdInteger> {send|recv} [addr <addr>[/<port>]]\n"
" [cc|cce|ccl|rate <bitsPerSecond>][ack <node1>[,<node2>,...][flush {none|passive|active}]\n" " [interface <name>] [loopback] [info] [ptos <value>] [ex]\n"
" [listen [<mcastAddr>/]<port>][linterface <name>]\n" " [cc|cce|ccl|rate <bitsPerSecond>]\n"
" [relay <dstAddr>/<port>][limit [<rate>/]<depth>][output <device>]\n" " [ack auto|<node1>[,<node2>,...]]\n"
" [boost][debug <level>][trace][log <logfile>]\n" " [flush {none|passive|active}]\n"
" [segment <bytes>][block <count>][parity <count>][auto <count>]\n" " [listen [<mcastAddr>/]<port>] [linterface <name>]\n"
" [insockbuffer <bytes>][outsockbuffer <bytes>]\n" " [relay <dstAddr>/<port>] [limit [<rate>/]<depth>]\n"
" [txsockbuffer <bytes>][rxsockbuffer <bytes>]\n" " [output <device>] [boost] [debug <level>] [trace]\n"
" [log <logfile>] [segment <bytes>] [block <count>]\n"
" [parity <count>] [auto <count>]\n"
" [insockbuffer <bytes>] [outsockbuffer <bytes>]\n"
" [txsockbuffer <bytes>] [rxsockbuffer <bytes>]\n"
" [streambuffer <bytes>]\n" " [streambuffer <bytes>]\n"
" [check64 | check32]\n"); " [check64 | check32]\n"
//" [omit][silent][txloss <lossFraction>]\n"); " [omit] [silent] [txloss <lossFraction>]\n");
} // end Usage() } // end Usage()
void PrintHelp() void PrintHelp()
{ {
fprintf(stderr, "\nHelp for normStreamer:\n\n") ; fprintf(stderr, "\nHelp for normStreamer:\n\n") ;
fprintf(stderr, fprintf(stderr,
"The 'normStreamer' application sends messages from STDIN (or a listening UDP socket) to one or more\n" "The 'normStreamer' application sends messages from STDIN (or a listening UDP socket) to one or more\n"
"receiving nodes using the NORM protocol. Received messages are output to STDOUT (or relayed to\n" "receiving nodes using the NORM protocol. Received messages are output to STDOUT (or relayed to\n"
"to a UDP destination address/port). Key command line options are:\n\n" "to a UDP destination address/port). Key command line options are:\n\n"
" id <nodeId> -- Specifies the node id for the local NORM instance (required)\n" " id <nodeId> -- Specifies the node id for the local NORM instance (required)\n"
" send | recv -- Specifies whether this node will be a sender and/or receiver (must choose at least one)\n" " send | recv -- Specifies whether this node will be a sender and/or receiver (must choose at least one)\n"
" addr <addr>[/<port>] -- specifies the network address over which to send/receive NORM protocol\n" " addr <addr>[/<port>] -- specifies the network address over which to send/receive NORM protocol\n"
" interface <name> -- Specifies the name of the network interface on which to conduct NORM protocol\n" " interface <name> -- Specifies the name of the network interface on which to conduct NORM protocol\n"
" (e.g., 'eth0')\n" " (e.g., 'eth0')\n"
" loopback -- Enables 'loopback' sessions on the same host machine. Required for multicast loopback.\n" " loopback -- Enables 'loopback' sessions on the same host machine. Required for multicast loopback.\n"
" ptos <value> -- Set special IP traffic class (TOS) for GRTT probing and acknowledgments\n" " ptos <value> -- Set special IP traffic class (TOS) for GRTT probing and acknowledgments\n"
" info -- Limits FTI header extension to NORM_INFO message only (reduced overhead)\n" " info -- Limits FTI header extension to NORM_INFO message only (reduced overhead)\n"
@ -1377,20 +1381,20 @@ void PrintHelp()
" any messages as soon as possible. If 'active', NORM stream will be flushed\n" " any messages as soon as possible. If 'active', NORM stream will be flushed\n"
" on a per-message basis as with 'passive' mode, but positive acknowledgment will\n" " on a per-message basis as with 'passive' mode, but positive acknowledgment will\n"
" _also_ be requested if a list of acking receiver node ids has beeen provided.\n" " _also_ be requested if a list of acking receiver node ids has beeen provided.\n"
" listen [<addr>/]<port> -- Specifies the port and optional multicast address which the sender uses to listen\n" " listen [<addr>/]<port> -- Specifies the port and optional multicast address which the sender uses to listen\n"
" for UDP packets to transmit to the receiver(s) via the NORM protocol\n" " for UDP packets to transmit to the receiver(s) via the NORM protocol\n"
" linterface <name> -- Specifies the name of the network interface on which to listen for UDP packet\n" " linterface <name> -- Specifies the name of the network interface on which to listen for UDP packet\n"
" payloads to send to the receiver(s) via NORM protocol\n" " payloads to send to the receiver(s) via NORM protocol\n"
" relay <dstAddr>/<port> -- Specifies the address/port for which to relay (as UDP datagrams) received messages\n" " relay <dstAddr>/<port> -- Specifies the address/port for which to relay (as UDP datagrams) received messages\n"
" limit [<rate>/]<depth> -- Token bucket rate/depth for optional receiver output limiter (smooths bursty output\n" " limit [<rate>/]<depth> -- Token bucket rate/depth for optional receiver output limiter (smooths bursty output\n"
" upon NORM loss recovery). When UDP 'relay' is used, this option is useful to avoid\n" " upon NORM loss recovery). When UDP 'relay' is used, this option is useful to avoid\n"
" overly bursty UDP output. The <rate> is in units of bits/second and the <depth> is\n" " overly bursty UDP output. The <rate> is in units of bits/second and the <depth> is\n"
" in units of bytes. If not specified here, the value set by 'rate' command is used\n" " in units of bytes. If not specified here, the value set by 'rate' command is used\n"
" as the token bucket rate.\n" " as the token bucket rate.\n"
" check64 | check32 -- Enables checking that packet sequence numbers in the first 4/8 bytes of received\n" " check64 | check32 -- Enables checking that packet sequence numbers in the first 4/8 bytes of received\n"
" packets increment properly (optional)\n" " packets increment properly (optional)\n"
" insockbuffer <bytes> -- Specifies the size of the 'listen' UDP socket buffer (optional).\n" " insockbuffer <bytes> -- Specifies the size of the 'listen' UDP socket buffer (optional).\n"
" outsockbuffer <bytes> -- Specifies the size of the 'relay' UDP socket buffer (optional).\n" " outsockbuffer <bytes> -- Specifies the size of the 'relay' UDP socket buffer (optional).\n"
" txsockbuffer <bytes> -- Specifies the size of the NORM/UDP transmit socket buffer (optional).\n" " txsockbuffer <bytes> -- Specifies the size of the NORM/UDP transmit socket buffer (optional).\n"
" rxsockbuffer <bytes> -- Specifies the size of the NORM/UDP receive socket buffer (optional).\n" " rxsockbuffer <bytes> -- Specifies the size of the NORM/UDP receive socket buffer (optional).\n"
" streambuffer <bytes> -- Specifies the size of the NORM stream buffer (optional).\n\n"); " streambuffer <bytes> -- Specifies the size of the NORM stream buffer (optional).\n\n");
@ -1710,59 +1714,59 @@ int main(int argc, char* argv[])
} }
mcastIface = argv[i++]; mcastIface = argv[i++];
} }
else if (0 == strncmp(cmd, "linterface", len)) else if (0 == strncmp(cmd, "linterface", len))
{ {
if (i >= argc) if (i >= argc)
{ {
fprintf(stderr, "normStreamer error: missing 'linterface' <name>!\n"); fprintf(stderr, "normStreamer error: missing 'linterface' <name>!\n");
Usage(); Usage();
return -1; return -1;
} }
listenIface = argv[i++]; listenIface = argv[i++];
} }
else if (0 == strncmp(cmd, "insockbuffer", len)) else if (0 == strncmp(cmd, "insockbuffer", len))
{ {
unsigned long value = 0 ; unsigned long value = 0 ;
if (i >= argc) if (i >= argc)
{ {
fprintf(stderr, "normStreamer error: missing 'insockbuffer' size!\n"); fprintf(stderr, "normStreamer error: missing 'insockbuffer' size!\n");
Usage(); Usage();
return -1; return -1;
} }
if (1 != sscanf(argv[i++], "%lu", &value)) if (1 != sscanf(argv[i++], "%lu", &value))
{ {
fprintf(stderr, "normStreamer error: invalid 'insockbuffer' size\n"); fprintf(stderr, "normStreamer error: invalid 'insockbuffer' size\n");
Usage(); Usage();
return -1; return -1;
} }
inputSocketBufferSize = value; inputSocketBufferSize = value;
} }
else if (0 == strncmp(cmd, "outsockbuffer", len)) else if (0 == strncmp(cmd, "outsockbuffer", len))
{ {
unsigned long value = 0 ; unsigned long value = 0 ;
if (i >= argc) if (i >= argc)
{ {
fprintf(stderr, "normStreamer error: missing 'outsockbuffer' size!\n"); fprintf(stderr, "normStreamer error: missing 'outsockbuffer' size!\n");
Usage(); Usage();
return -1; return -1;
} }
if (1 != sscanf(argv[i++], "%lu", &value)) if (1 != sscanf(argv[i++], "%lu", &value))
{ {
fprintf(stderr, "normStreamer error: invalid 'outsockbuffer' size!\n"); fprintf(stderr, "normStreamer error: invalid 'outsockbuffer' size!\n");
Usage(); Usage();
return -1; return -1;
} }
outputSocketBufferSize = value; outputSocketBufferSize = value;
} }
else if (0 == strncmp(cmd, "limit", len)) else if (0 == strncmp(cmd, "limit", len))
{ {
// format: limit [<rate>/<size>] with 'rate' in bps and 'size' in bytes // format: limit [<rate>/<size>] with 'rate' in bps and 'size' in bytes
if (i >= argc) if (i >= argc)
{ {
fprintf(stderr, "normStreamer error: missing 'limit' size!\n"); fprintf(stderr, "normStreamer error: missing 'limit' size!\n");
Usage(); Usage();
return -1; return -1;
} }
const char* ratePtr = argv[i++]; const char* ratePtr = argv[i++];
const char* sizePtr = strchr(ratePtr, '/'); const char* sizePtr = strchr(ratePtr, '/');
unsigned int rateLen = 0; unsigned int rateLen = 0;
@ -1775,8 +1779,8 @@ int main(int argc, char* argv[])
if (rateLen > 63) if (rateLen > 63)
{ {
fprintf(stderr, "normStreamer error: out-of-bounds 'limit' rate\n"); fprintf(stderr, "normStreamer error: out-of-bounds 'limit' rate\n");
Usage(); Usage();
return -1; return -1;
} }
char rateText[64]; char rateText[64];
strncpy(rateText, ratePtr, rateLen); strncpy(rateText, ratePtr, rateLen);
@ -1785,8 +1789,8 @@ int main(int argc, char* argv[])
if (1 != sscanf(rateText, "%lf", &value)) if (1 != sscanf(rateText, "%lf", &value))
{ {
fprintf(stderr, "normStreamer error: invalid 'limit' rate\n"); fprintf(stderr, "normStreamer error: invalid 'limit' rate\n");
Usage(); Usage();
return -1; return -1;
} }
normStreamer.SetOutputBucketRate(value); normStreamer.SetOutputBucketRate(value);
} }
@ -1794,142 +1798,142 @@ int main(int argc, char* argv[])
if (1 != sscanf(sizePtr, "%lu", &value)) if (1 != sscanf(sizePtr, "%lu", &value))
{ {
fprintf(stderr, "normStreamer error: invalid 'limit' size\n"); fprintf(stderr, "normStreamer error: invalid 'limit' size\n");
Usage(); Usage();
return -1; return -1;
} }
normStreamer.SetOutputBucketDepth(value); normStreamer.SetOutputBucketDepth(value);
} }
else if (0 == strncmp(cmd, "txsockbuffer", len)) else if (0 == strncmp(cmd, "txsockbuffer", len))
{ {
unsigned long value = 0 ; unsigned long value = 0 ;
if (i >= argc) if (i >= argc)
{ {
fprintf(stderr, "normStreamer error: missing 'txsockbuffer' size!\n"); fprintf(stderr, "normStreamer error: missing 'txsockbuffer' size!\n");
Usage(); Usage();
return -1; return -1;
} }
if (1 != sscanf(argv[i++], "%lu", &value)) if (1 != sscanf(argv[i++], "%lu", &value))
{ {
fprintf(stderr, "normStreamer error: invalid 'txsockbuffer' size!\n"); fprintf(stderr, "normStreamer error: invalid 'txsockbuffer' size!\n");
Usage(); Usage();
return -1; return -1;
} }
txSocketBufferSize = value; txSocketBufferSize = value;
} }
else if (0 == strncmp(cmd, "rxsockbuffer", len)) else if (0 == strncmp(cmd, "rxsockbuffer", len))
{ {
unsigned long value = 0 ; unsigned long value = 0 ;
if (i >= argc) if (i >= argc)
{ {
fprintf(stderr, "normStreamer error: missing 'rxsockbuffer' size!\n"); fprintf(stderr, "normStreamer error: missing 'rxsockbuffer' size!\n");
Usage(); Usage();
return -1; return -1;
} }
if (1 != sscanf(argv[i++], "%lu", &value)) if (1 != sscanf(argv[i++], "%lu", &value))
{ {
fprintf(stderr, "normStreamer error: invalid 'rxsockbuffer' size!\n"); fprintf(stderr, "normStreamer error: invalid 'rxsockbuffer' size!\n");
Usage(); Usage();
return -1; return -1;
} }
rxSocketBufferSize = value; rxSocketBufferSize = value;
} }
else if (0 == strncmp(cmd, "segment", len)) else if (0 == strncmp(cmd, "segment", len))
{ {
if (i >= argc) if (i >= argc)
{ {
fprintf(stderr, "normStreamer error: missing 'segment' size!\n"); fprintf(stderr, "normStreamer error: missing 'segment' size!\n");
Usage(); Usage();
return -1; return -1;
} }
unsigned short value; unsigned short value;
if (1 != sscanf(argv[i++], "%hu", &value)) if (1 != sscanf(argv[i++], "%hu", &value))
{ {
fprintf(stderr, "normStreamer error: invalid 'segment' size!\n"); fprintf(stderr, "normStreamer error: invalid 'segment' size!\n");
Usage(); Usage();
return -1; return -1;
} }
normStreamer.SetSegmentSize(value); normStreamer.SetSegmentSize(value);
} }
else if (0 == strncmp(cmd, "block", len)) else if (0 == strncmp(cmd, "block", len))
{ {
if (i >= argc) if (i >= argc)
{ {
fprintf(stderr, "normStreamer error: missing 'block' size!\n"); fprintf(stderr, "normStreamer error: missing 'block' size!\n");
Usage(); Usage();
return -1; return -1;
} }
unsigned short value; unsigned short value;
if (1 != sscanf(argv[i++], "%hu", &value)) if (1 != sscanf(argv[i++], "%hu", &value))
{ {
fprintf(stderr, "normStreamer error: invalid 'block' size!\n"); fprintf(stderr, "normStreamer error: invalid 'block' size!\n");
Usage(); Usage();
return -1; return -1;
} }
normStreamer.SetBlockSize(value); normStreamer.SetBlockSize(value);
} }
else if (0 == strncmp(cmd, "parity", len)) else if (0 == strncmp(cmd, "parity", len))
{ {
if (i >= argc) if (i >= argc)
{ {
fprintf(stderr, "normStreamer error: missing 'parity' count!\n"); fprintf(stderr, "normStreamer error: missing 'parity' count!\n");
Usage(); Usage();
return -1; return -1;
} }
unsigned short value; unsigned short value;
if (1 != sscanf(argv[i++], "%hu", &value)) if (1 != sscanf(argv[i++], "%hu", &value))
{ {
fprintf(stderr, "normStreamer error: invalid 'parity' count!\n"); fprintf(stderr, "normStreamer error: invalid 'parity' count!\n");
Usage(); Usage();
return -1; return -1;
} }
normStreamer.SetNumParity(value); normStreamer.SetNumParity(value);
} }
else if (0 == strncmp(cmd, "auto", len)) else if (0 == strncmp(cmd, "auto", len))
{ {
if (i >= argc) if (i >= argc)
{ {
fprintf(stderr, "normStreamer error: missing 'auto' parity count!\n"); fprintf(stderr, "normStreamer error: missing 'auto' parity count!\n");
Usage(); Usage();
return -1; return -1;
} }
unsigned short value; unsigned short value;
if (1 != sscanf(argv[i++], "%hu", &value)) if (1 != sscanf(argv[i++], "%hu", &value))
{ {
fprintf(stderr, "normStreamer error: invalid 'auto' parity count!\n"); fprintf(stderr, "normStreamer error: invalid 'auto' parity count!\n");
Usage(); Usage();
return -1; return -1;
} }
normStreamer.SetAutoParity(value); normStreamer.SetAutoParity(value);
} }
else if (0 == strncmp(cmd, "streambuffer", len)) else if (0 == strncmp(cmd, "streambuffer", len))
{ {
unsigned long value = 0 ; unsigned long value = 0 ;
if (i >= argc) if (i >= argc)
{ {
fprintf(stderr, "normStreamer error: missing 'streambuffer' size!\n"); fprintf(stderr, "normStreamer error: missing 'streambuffer' size!\n");
Usage(); Usage();
return -1; return -1;
} }
if (1 != sscanf(argv[i++], "%lu", &value)) if (1 != sscanf(argv[i++], "%lu", &value))
{ {
fprintf(stderr, "normStreamer error: invalid 'streambuffer' size!\n"); fprintf(stderr, "normStreamer error: invalid 'streambuffer' size!\n");
Usage(); Usage();
return -1; return -1;
} }
streamBufferSize = value; streamBufferSize = value;
} }
else if ( 0 == strncmp(cmd,"chkseq", len) ) else if ( 0 == strncmp(cmd,"chkseq", len) )
{ {
checkSequence = 64; // same as "check64" for "historical" reasons checkSequence = 64; // same as "check64" for "historical" reasons
} }
else if ( 0 == strncmp(cmd,"check64", len) ) else if ( 0 == strncmp(cmd,"check64", len) )
{ {
checkSequence = 64; checkSequence = 64;
} }
else if ( 0 == strncmp(cmd,"check32", len) ) else if ( 0 == strncmp(cmd,"check32", len) )
{ {
checkSequence = 32; checkSequence = 32;
} }
else if (0 == strncmp(cmd, "omit", len)) else if (0 == strncmp(cmd, "omit", len))
{ {
omitHeaderOnOutput = true; omitHeaderOnOutput = true;