v1.2b2
parent
718455beb5
commit
7fdb889444
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,258 @@
|
|||
#ifndef _NORM_API
|
||||
#define _NORM_API
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#endif // WIN32
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// IMPORTANT NOTICE
|
||||
// The NORM API is _very_ much in a developmental phase
|
||||
// right now. So, although this code is available in
|
||||
// source code distribution, it is very much subject
|
||||
// to change in future revisions. The goal of the NORM
|
||||
// API _will_ be to provide a stable base of function calls
|
||||
// for applications to use, even as the underlying NORM
|
||||
// C++ code continues to evolve. But, until this notice
|
||||
// is removed, the API shouldn't be considered final.
|
||||
|
||||
|
||||
typedef const void* NormInstanceHandle;
|
||||
extern const NormInstanceHandle NORM_INSTANCE_INVALID;
|
||||
|
||||
NormInstanceHandle NormCreateInstance();
|
||||
void NormDestroyInstance(NormInstanceHandle instanceHandle);
|
||||
|
||||
// NORM session creation and control
|
||||
typedef const void* NormSessionHandle;
|
||||
extern const NormSessionHandle NORM_SESSION_INVALID;
|
||||
typedef unsigned long NormNodeId;
|
||||
extern const NormNodeId NORM_NODE_NONE;
|
||||
extern const NormNodeId NORM_NODE_ANY;
|
||||
|
||||
NormSessionHandle NormCreateSession(NormInstanceHandle instanceHandle,
|
||||
const char* sessionAddress,
|
||||
unsigned short sessionPort,
|
||||
NormNodeId localNodeId);
|
||||
|
||||
void NormDestroySession(NormSessionHandle sessionHandle);
|
||||
|
||||
// Session management and parameters
|
||||
|
||||
void NormSetTransmitRate(NormSessionHandle sessionHandle,
|
||||
double bitsPerSecond);
|
||||
|
||||
void NormSetGrttEstimate(NormSessionHandle sessionHandle,
|
||||
double grttEstimate);
|
||||
|
||||
NormNodeId NormGetLocalNodeId(NormSessionHandle sessionHandle);
|
||||
|
||||
bool NormSetLoopback(NormSessionHandle sessionHandle, bool state);
|
||||
|
||||
// Debug parameters
|
||||
void NormSetMessageTrace(NormSessionHandle sessionHandle, bool state);
|
||||
void NormSetTxLoss(NormSessionHandle sessionHandle, double percent);
|
||||
void NormSetRxLoss(NormSessionHandle sessionHandle, double percent);
|
||||
|
||||
// Sender control & parameters
|
||||
bool NormStartSender(NormSessionHandle sessionHandle,
|
||||
unsigned long bufferSpace,
|
||||
unsigned short segmentSize,
|
||||
unsigned char numData,
|
||||
unsigned char numParity);
|
||||
|
||||
void NormStopSender(NormSessionHandle sessionHandle);
|
||||
|
||||
bool NormAddAckingNode(NormSessionHandle sessionHandle,
|
||||
NormNodeId nodeId);
|
||||
|
||||
void NormRemoveAckingNode(NormSessionHandle sessionHandle,
|
||||
NormNodeId nodeId);
|
||||
|
||||
|
||||
// Receiver control & parameters
|
||||
bool NormStartReceiver(NormSessionHandle sessionHandle,
|
||||
unsigned long bufferSpace);
|
||||
|
||||
void NormStopReceiver(NormSessionHandle sessionHandle);
|
||||
|
||||
void NormSetDefaultUnicastNack(NormSessionHandle sessionHandle,
|
||||
bool state);
|
||||
|
||||
typedef const void* NormNodeHandle;
|
||||
extern const NormNodeHandle NORM_NODE_INVALID;
|
||||
typedef const void* NormObjectHandle;
|
||||
extern const NormObjectHandle NORM_OBJECT_INVALID;
|
||||
typedef unsigned short NormObjectTransportId;
|
||||
|
||||
enum NormNackingMode
|
||||
{
|
||||
NORM_NACK_NONE,
|
||||
NORM_NACK_INFO_ONLY,
|
||||
NORM_NACK_NORMAL
|
||||
};
|
||||
|
||||
enum NormRepairBoundary
|
||||
{
|
||||
NORM_BOUNDARY_BLOCK,
|
||||
NORM_BOUNDARY_OBJECT
|
||||
};
|
||||
|
||||
|
||||
NormNodeId NormGetNodeId(NormNodeHandle nodeHandle);
|
||||
|
||||
NormRepairBoundary NormGetNodeRepairBoundary(NormNodeHandle nodeHandle);
|
||||
|
||||
void NormSetNodeRepairBoundary(NormNodeHandle nodeHandle,
|
||||
NormRepairBoundary repairBoundary);
|
||||
|
||||
void NormSetDefaultRepairBoundary(NormSessionHandle sessionHandle,
|
||||
NormRepairBoundary repairBoundary);
|
||||
|
||||
// General NormObject functions
|
||||
|
||||
enum NormObjectType
|
||||
{
|
||||
NORM_OBJECT_NONE,
|
||||
NORM_OBJECT_DATA,
|
||||
NORM_OBJECT_FILE,
|
||||
NORM_OBJECT_STREAM
|
||||
};
|
||||
|
||||
|
||||
NormObjectType NormGetObjectType(NormObjectHandle objectHandle);
|
||||
|
||||
|
||||
bool NormGetObjectInfo(NormObjectHandle objectHandle,
|
||||
char* infoBuffer,
|
||||
unsigned short* infoLen);
|
||||
|
||||
NormObjectTransportId NormGetObjectTransportId(NormObjectHandle objectHandle);
|
||||
|
||||
void NormCancelObject(NormObjectHandle objectHandle);
|
||||
|
||||
|
||||
void NormRetainObject(NormObjectHandle objectHandle);
|
||||
void NormReleaseObject(NormObjectHandle objectHandle);
|
||||
|
||||
|
||||
// Receiver-only NormObject functions
|
||||
NormNackingMode NormGetObjectNackingMode(NormObjectHandle objectHandle);
|
||||
|
||||
void NormSetObjectNackingMode(NormObjectHandle objectHandle,
|
||||
NormNackingMode nackingMode);
|
||||
|
||||
void NormSetNodeNackingMode(NormNodeHandle nodeHandle,
|
||||
NormNackingMode nackingMode);
|
||||
|
||||
void NormSetDefaultNackingMode(NormSessionHandle sessionHandle,
|
||||
NormNackingMode nackingMode);
|
||||
|
||||
// Sender-only NormObject functions
|
||||
bool NormSetWatermark(NormSessionHandle sessionHandle,
|
||||
NormObjectHandle objectHandle);
|
||||
|
||||
|
||||
// NormStreamObject functions
|
||||
|
||||
NormObjectHandle NormOpenStream(NormSessionHandle sessionHandle,
|
||||
unsigned long bufferSize);
|
||||
|
||||
void NormCloseStream(NormObjectHandle streamHandle);
|
||||
|
||||
enum NormFlushMode
|
||||
{
|
||||
NORM_FLUSH_NONE,
|
||||
NORM_FLUSH_PASSIVE,
|
||||
NORM_FLUSH_ACTIVE
|
||||
};
|
||||
|
||||
void NormSetStreamFlushMode(NormObjectHandle streamHandle,
|
||||
NormFlushMode flushMode);
|
||||
|
||||
void NormSetStreamPushMode(NormObjectHandle streamHandle,
|
||||
bool state);
|
||||
|
||||
unsigned int NormWriteStream(NormObjectHandle streamHandle,
|
||||
const char* buffer,
|
||||
unsigned int numBytes);
|
||||
|
||||
void NormFlushStream(NormObjectHandle streamHandle);
|
||||
|
||||
void NormMarkStreamEom(NormObjectHandle streamHandle);
|
||||
|
||||
bool NormReadStream(NormObjectHandle streamHandle,
|
||||
char* buffer,
|
||||
unsigned int* numBytes);
|
||||
|
||||
// NormFileObject Functions
|
||||
NormObjectHandle NormQueueFile(NormSessionHandle sessionHandle,
|
||||
const char* fileName,
|
||||
const char* infoPtr = (const char*)0,
|
||||
unsigned int infoLen = 0);
|
||||
|
||||
bool NormSetCacheDirectory(NormInstanceHandle instanceHandle,
|
||||
const char* cachePath);
|
||||
|
||||
bool NormGetFileName(NormObjectHandle fileHandle,
|
||||
char* nameBuffer,
|
||||
unsigned int bufferLen);
|
||||
|
||||
bool NormSetFileName(NormObjectHandle fileHandle,
|
||||
const char* fileName);
|
||||
|
||||
// NormDataObject Functions
|
||||
bool NormQueueData(const char* dataPtr,
|
||||
unsigned long dataLen,
|
||||
const char* infoPtr = (const char*)0,
|
||||
unsigned int infoLen = 0);
|
||||
|
||||
// NORM Event Notification Routines
|
||||
|
||||
enum NormEventType
|
||||
{
|
||||
NORM_EVENT_INVALID = 0,
|
||||
NORM_TX_QUEUE_VACANCY,
|
||||
NORM_TX_QUEUE_EMPTY,
|
||||
NORM_TX_OBJECT_SENT,
|
||||
NORM_TX_OBJECT_PURGED,
|
||||
NORM_LOCAL_SERVER_CLOSED,
|
||||
NORM_REMOTE_SERVER_NEW,
|
||||
NORM_REMOTE_SERVER_INACTIVE,
|
||||
NORM_REMOTE_SERVER_ACTIVE,
|
||||
NORM_RX_OBJECT_NEW,
|
||||
NORM_RX_OBJECT_INFO,
|
||||
NORM_RX_OBJECT_UPDATE,
|
||||
NORM_RX_OBJECT_COMPLETED,
|
||||
NORM_RX_OBJECT_ABORTED
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
NormEventType type;
|
||||
NormSessionHandle session;
|
||||
NormNodeHandle sender;
|
||||
NormObjectHandle object;
|
||||
} NormEvent;
|
||||
|
||||
|
||||
// This call blocks until the next NormEvent is ready unless asynchronous
|
||||
// notification is used (see below)
|
||||
bool NormGetNextEvent(NormInstanceHandle instanceHandle, NormEvent* theEvent);
|
||||
|
||||
// The "NormGetDescriptor()" function returns a HANDLE (WIN32) or
|
||||
// a file descriptor (UNIX) which can be used for async notification
|
||||
// of pending NORM events. On WIN32, the returned HANDLE can be used
|
||||
// with system calls like "WaitForSingleEvent()", and on Unix the
|
||||
// returned descriptor can be used in a "select()" call. If this type
|
||||
// of asynchronous notification is used, calls to "NormGetNextEvent()" will
|
||||
// not block.
|
||||
|
||||
#ifdef WIN32
|
||||
HANDLE NormGetDescriptor(NormInstanceHandle instanceHandle);
|
||||
#else
|
||||
int NormGetDescriptor(NormInstanceHandle instanceHandle);
|
||||
#endif // if/else WIN32/UNIX
|
||||
|
||||
#endif // _NORM_API
|
||||
|
|
@ -11,6 +11,11 @@
|
|||
#include <stdlib.h>
|
||||
#include <ctype.h> // for "isspace()"
|
||||
|
||||
#ifdef UNIX
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h> // for "waitpid()"
|
||||
#endif // UNIX
|
||||
|
||||
// Command-line application using Protolib EventDispatcher
|
||||
class NormApp : public NormController, public ProtoApp
|
||||
{
|
||||
|
|
@ -64,8 +69,8 @@ class NormApp : public NormController, public ProtoApp
|
|||
unsigned int input_index;
|
||||
unsigned int input_length;
|
||||
bool input_active;
|
||||
bool push_stream;
|
||||
NormStreamObject::FlushType msg_flush_mode;
|
||||
bool push_mode;
|
||||
NormStreamObject::FlushMode msg_flush_mode;
|
||||
bool input_messaging; // stream input mode
|
||||
UINT16 input_msg_length;
|
||||
UINT16 input_msg_index;
|
||||
|
|
@ -79,6 +84,7 @@ class NormApp : public NormController, public ProtoApp
|
|||
char* address; // session address
|
||||
UINT16 port; // session port number
|
||||
UINT8 ttl;
|
||||
bool loopback;
|
||||
char* interface_name; // for multi-home hosts
|
||||
double tx_rate; // bits/sec
|
||||
bool cc_enable;
|
||||
|
|
@ -90,6 +96,8 @@ class NormApp : public NormController, public ProtoApp
|
|||
UINT8 auto_parity;
|
||||
UINT8 extra_parity;
|
||||
double backoff_factor;
|
||||
double grtt_estimate; // initial grtt estimate
|
||||
double group_size;
|
||||
unsigned long tx_buffer_size; // bytes
|
||||
NormFileList tx_file_list;
|
||||
double tx_object_interval;
|
||||
|
|
@ -118,13 +126,15 @@ NormApp::NormApp()
|
|||
session_mgr(GetTimerMgr(), GetSocketNotifier()),
|
||||
session(NULL), tx_stream(NULL), rx_stream(NULL), input(NULL), output(NULL),
|
||||
input_index(0), input_length(0), input_active(false),
|
||||
push_stream(false), msg_flush_mode(NormStreamObject::FLUSH_PASSIVE),
|
||||
push_mode(false), msg_flush_mode(NormStreamObject::FLUSH_PASSIVE),
|
||||
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), interface_name(NULL),
|
||||
address(NULL), port(0), ttl(3), loopback(false), interface_name(NULL),
|
||||
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),
|
||||
grtt_estimate(NormSession::DEFAULT_GRTT_ESTIMATE),
|
||||
group_size(NormSession::DEFAULT_GSIZE_ESTIMATE),
|
||||
tx_buffer_size(1024*1024),
|
||||
tx_object_interval(0.0), tx_repeat_count(0), tx_repeat_interval(2.0), tx_repeat_clear(true),
|
||||
rx_buffer_size(1024*1024), rx_cache_path(NULL), unicast_nacks(false), silent_client(false),
|
||||
|
|
@ -153,16 +163,33 @@ NormApp::~NormApp()
|
|||
if (post_processor) delete post_processor;
|
||||
}
|
||||
|
||||
// NOTE on message flushing mode:
|
||||
//
|
||||
// "none" - messages are aggregated to make NORM_DATA
|
||||
// payloads a full "segmentSize"
|
||||
//
|
||||
// "passive" - At the end-of-message, short NORM_DATA
|
||||
// payloads are sent as needed so that
|
||||
// the message is immediately sent
|
||||
// (i.e. not held for aggregation)
|
||||
// "active" - Same as "passive", plus NORM_CMD(FLUSH)
|
||||
// messages are generated until new
|
||||
// message is written to stream
|
||||
// (This helps keep receivers in sync
|
||||
// with sender when intermittent message
|
||||
// traffic is sent)
|
||||
|
||||
|
||||
const char* const NormApp::cmd_list[] =
|
||||
{
|
||||
"+debug", // debug level
|
||||
"+log", // log file name
|
||||
"-trace", // message tracing on
|
||||
"+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
|
||||
"+loopback", // "off" or "on" to recv our own packets
|
||||
"+interface", // multicast interface name to use
|
||||
"+cc", // congestion control on/off
|
||||
"+rate", // tx date rate (bps)
|
||||
|
|
@ -184,18 +211,19 @@ const char* const NormApp::cmd_list[] =
|
|||
"+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
|
||||
"+grtt", // Set sender's initial GRTT estimate
|
||||
"+gsize", // Set sender's group size estimate
|
||||
"+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
|
||||
"+instance", // specify norm instance name for commands
|
||||
"+instance", // specify norm instance name for remote control commands
|
||||
NULL
|
||||
};
|
||||
|
||||
void NormApp::OnControlEvent(ProtoSocket& /*theSocket*/, ProtoSocket::Event theEvent)
|
||||
{
|
||||
TRACE("NormApp::OnControlEvent() ...\n");
|
||||
switch (theEvent)
|
||||
{
|
||||
case ProtoSocket::RECV:
|
||||
|
|
@ -205,7 +233,7 @@ void NormApp::OnControlEvent(ProtoSocket& /*theSocket*/, ProtoSocket::Event theE
|
|||
if (control_pipe.Recv(buffer, len))
|
||||
{
|
||||
buffer[len] = '\0';
|
||||
TRACE("norm: received command \"%s\"\n", buffer);
|
||||
DMSG(0, "norm: received command \"%s\"\n", buffer);
|
||||
char* cmd = buffer;
|
||||
char* val = NULL;
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
|
|
@ -214,6 +242,7 @@ void NormApp::OnControlEvent(ProtoSocket& /*theSocket*/, ProtoSocket::Event theE
|
|||
{
|
||||
buffer[i++] = '\0';
|
||||
val = buffer + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!OnCommand(cmd, val))
|
||||
|
|
@ -288,8 +317,16 @@ bool NormApp::OnCommand(const char* cmd, const char* val)
|
|||
}
|
||||
else if (!strncmp("trace", cmd, len))
|
||||
{
|
||||
if (!strcmp("on", val))
|
||||
tracing = true;
|
||||
if (session) session->SetTrace(true);
|
||||
else if (!strcmp("off", val))
|
||||
tracing = false;
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormApp::OnCommand(trace) invalid argument!\n");
|
||||
return false;
|
||||
}
|
||||
if (session) session->SetTrace(tracing);
|
||||
}
|
||||
else if (!strncmp("txloss", cmd, len))
|
||||
{
|
||||
|
|
@ -346,12 +383,38 @@ bool NormApp::OnCommand(const char* cmd, const char* val)
|
|||
else if (!strncmp("ttl", cmd, len))
|
||||
{
|
||||
int ttlTemp = atoi(val);
|
||||
if ((ttlTemp < 1) || (ttlTemp > 255))
|
||||
if ((ttlTemp < 0) || (ttlTemp > 255))
|
||||
{
|
||||
DMSG(0, "NormApp::OnCommand(ttl) invalid value!\n");
|
||||
return false;
|
||||
}
|
||||
ttl = ttlTemp;
|
||||
bool result = session ? session->SetTTL((UINT8)ttlTemp) : true;
|
||||
ttl = result ? ttlTemp : ttl;
|
||||
if (!result)
|
||||
{
|
||||
DMSG(0, "NormApp::OnCommand(ttl) error setting socket ttl!\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!strncmp("loopback", cmd, len))
|
||||
{
|
||||
bool loopTemp = loopback;
|
||||
if (!strcmp("on", val))
|
||||
loopTemp = true;
|
||||
else if (!strcmp("off", val))
|
||||
loopTemp = false;
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormApp::OnCommand(loopback) invalid argument!\n");
|
||||
return false;
|
||||
}
|
||||
bool result = session ? session->SetLoopback(loopTemp) : true;
|
||||
loopback = result ? loopTemp : loopback;
|
||||
if (!result)
|
||||
{
|
||||
DMSG(0, "NormApp::OnCommand(loopback) error setting socket loopback!\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!strncmp("interface", cmd, len))
|
||||
{
|
||||
|
|
@ -580,12 +643,34 @@ bool NormApp::OnCommand(const char* cmd, const char* val)
|
|||
double backoffFactor = atof(val);
|
||||
if (backoffFactor < 0)
|
||||
{
|
||||
DMSG(0, "NormSimAgent::OnCommand(backoff) invalid txRate!\n");
|
||||
DMSG(0, "NormApp::OnCommand(backoff) invalid value!\n");
|
||||
return false;
|
||||
}
|
||||
backoff_factor = backoffFactor;
|
||||
if (session) session->SetBackoffFactor(backoffFactor);
|
||||
}
|
||||
else if (!strncmp("grtt", cmd, len))
|
||||
{
|
||||
double grttEstimate = atof(val);
|
||||
if (grttEstimate < 0)
|
||||
{
|
||||
DMSG(0, "NormApp::OnCommand(grtt) invalid value!\n");
|
||||
return false;
|
||||
}
|
||||
grtt_estimate = grttEstimate;
|
||||
if (session) session->ServerSetGrtt(grttEstimate);
|
||||
}
|
||||
else if (!strncmp("gsize", cmd, len))
|
||||
{
|
||||
double groupSize = atof(val);
|
||||
if (groupSize < 0)
|
||||
{
|
||||
DMSG(0, "NormApp::OnCommand(gsize) invalid value!\n");
|
||||
return false;
|
||||
}
|
||||
group_size = groupSize;
|
||||
if (session) session->ServerSetGroupSize(groupSize);
|
||||
}
|
||||
else if (!strncmp("txbuffer", cmd, len))
|
||||
{
|
||||
if (1 != sscanf(val, "%lu", &tx_buffer_size))
|
||||
|
|
@ -614,7 +699,8 @@ bool NormApp::OnCommand(const char* cmd, const char* val)
|
|||
}
|
||||
else if (!strncmp("push", cmd, len))
|
||||
{
|
||||
push_stream = true;
|
||||
push_mode = true;
|
||||
if (tx_stream) tx_stream->SetPushMode(push_mode);
|
||||
}
|
||||
else if (!strncmp("flush", cmd, len))
|
||||
{
|
||||
|
|
@ -630,6 +716,7 @@ bool NormApp::OnCommand(const char* cmd, const char* val)
|
|||
DMSG(0, "NormApp::OnCommand(flush) invalid msg flush mode!\n");
|
||||
return false;
|
||||
}
|
||||
if (tx_stream) tx_stream->SetFlushMode(msg_flush_mode);
|
||||
}
|
||||
else if (!strncmp("processor", cmd, len))
|
||||
{
|
||||
|
|
@ -644,12 +731,10 @@ bool NormApp::OnCommand(const char* cmd, const char* val)
|
|||
// First, try to connect to see if instance is already running
|
||||
if (control_pipe.Connect(val))
|
||||
{
|
||||
TRACE("connected to \"%s\"\n", val);
|
||||
control_remote = true;
|
||||
}
|
||||
else if (control_pipe.Listen(val))
|
||||
{
|
||||
TRACE("listening as \"%s\"\n", val);
|
||||
control_remote = false;
|
||||
}
|
||||
else
|
||||
|
|
@ -740,7 +825,7 @@ void NormApp::OnInputReady()
|
|||
{
|
||||
|
||||
//DMSG(0, "NormApp::OnInputReady() ...\n");
|
||||
NormStreamObject::FlushType flushType = NormStreamObject::FLUSH_NONE;
|
||||
bool endOfStream = false;
|
||||
// write to the stream while input is available _and_
|
||||
// the stream has buffer space for input
|
||||
while (input)
|
||||
|
|
@ -816,7 +901,8 @@ void NormApp::OnInputReady()
|
|||
}
|
||||
if (stdin != input) fclose(input);
|
||||
input = NULL;
|
||||
flushType = NormStreamObject::FLUSH_ACTIVE;
|
||||
endOfStream = true;
|
||||
tx_stream->SetFlushMode(NormStreamObject::FLUSH_ACTIVE);
|
||||
}
|
||||
else if (ferror(input))
|
||||
{
|
||||
|
|
@ -839,11 +925,10 @@ void NormApp::OnInputReady()
|
|||
|
||||
unsigned int writeLength = input_length;// ? input_length - input_index : 0;
|
||||
|
||||
if (writeLength || (NormStreamObject::FLUSH_NONE != flushType))
|
||||
if (writeLength || endOfStream)
|
||||
{
|
||||
unsigned int wroteLength = tx_stream->Write(input_buffer+input_index,
|
||||
writeLength, flushType, false,
|
||||
push_stream);
|
||||
writeLength, false);
|
||||
input_length -= wroteLength;
|
||||
if (0 == input_length)
|
||||
input_index = 0;
|
||||
|
|
@ -857,7 +942,9 @@ void NormApp::OnInputReady()
|
|||
input_msg_index = 0;
|
||||
input_msg_length = 0;
|
||||
// Mark EOM _and_ flush
|
||||
tx_stream->Write(NULL, 0, msg_flush_mode, true, false);
|
||||
tx_stream->Write(NULL, 0, true);
|
||||
// No need to explicitly flush with "flush mode" set.
|
||||
//tx_stream->Flush();
|
||||
}
|
||||
}
|
||||
if (wroteLength < writeLength)
|
||||
|
|
@ -890,7 +977,7 @@ void NormApp::OnInputReady()
|
|||
#endif // if/else WIN32/UNIX
|
||||
input_active = true;
|
||||
else
|
||||
DMSG(0, "NormApp::Notify(TX_QUEUE_EMPTY) error adding input notification!\n");
|
||||
DMSG(0, "NormApp::OnInputReady() error adding input notification!\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -992,6 +1079,9 @@ void NormApp::Notify(NormController::Event event,
|
|||
case NormObject::DATA:
|
||||
DMSG(0, "NormApp::Notify() FILE/DATA objects not _yet_ supported...\n");
|
||||
break;
|
||||
|
||||
case NormObject::NONE:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -1032,6 +1122,7 @@ void NormApp::Notify(NormController::Event event,
|
|||
}
|
||||
case NormObject::DATA:
|
||||
case NormObject::STREAM:
|
||||
case NormObject::NONE:
|
||||
break;
|
||||
} // end switch(object->GetType())
|
||||
break;
|
||||
|
|
@ -1042,6 +1133,8 @@ void NormApp::Notify(NormController::Event event,
|
|||
{
|
||||
case NormObject::FILE:
|
||||
// (TBD) update reception progress display when applicable
|
||||
// Call object->SetNotifyOnUpdate(true) here to keep
|
||||
// the update notifications coming. Otherwise they stop!
|
||||
break;
|
||||
|
||||
case NormObject::STREAM:
|
||||
|
|
@ -1161,17 +1254,22 @@ void NormApp::Notify(NormController::Event event,
|
|||
case NormObject::DATA:
|
||||
DMSG(0, "NormApp::Notify() DATA objects not _yet_ supported...\n");
|
||||
break;
|
||||
case NormObject::NONE:
|
||||
break;
|
||||
} // end switch (object->GetType())
|
||||
break;
|
||||
|
||||
case RX_OBJECT_COMPLETE:
|
||||
case RX_OBJECT_COMPLETED:
|
||||
{
|
||||
// (TBD) if we're not archiving files we should
|
||||
// manage our cache, deleting the cache
|
||||
// on shutdown ...
|
||||
//DMSG(0, "NormApp::Notify(RX_OBJECT_COMPLETE) ...\n");
|
||||
switch(object->GetType())
|
||||
{
|
||||
case NormObject::FILE:
|
||||
{
|
||||
const char* filePath = ((NormFileObject*)object)->Path();
|
||||
const char* filePath = ((NormFileObject*)object)->GetPath();
|
||||
//DMSG(0, "norm: Completed rx file: %s\n", filePath);
|
||||
if (post_processor->IsEnabled())
|
||||
{
|
||||
|
|
@ -1189,9 +1287,15 @@ void NormApp::Notify(NormController::Event event,
|
|||
case NormObject::DATA:
|
||||
ASSERT(0);
|
||||
break;
|
||||
case NormObject::NONE:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
DMSG(4, "NormApp::Notify() unhandled event: %d\n", event);
|
||||
}
|
||||
} // end switch(event)
|
||||
} // end NormApp::Notify()
|
||||
|
||||
|
|
@ -1315,14 +1419,17 @@ bool NormApp::OnStartup(int argc, const char*const* argv)
|
|||
session->SetTrace(tracing);
|
||||
session->SetTxLoss(tx_loss);
|
||||
session->SetRxLoss(rx_loss);
|
||||
session->SetBackoffFactor(backoff_factor);
|
||||
session->SetTTL(ttl);
|
||||
session->SetLoopback(loopback);
|
||||
|
||||
if (input || !tx_file_list.IsEmpty())
|
||||
{
|
||||
NormObjectId baseId = (unsigned short)(rand() * (65535.0/ (double)RAND_MAX));
|
||||
session->ServerSetBaseObjectId(baseId);
|
||||
|
||||
session->SetCongestionControl(cc_enable);
|
||||
session->SetBackoffFactor(backoff_factor);
|
||||
session->ServerSetGrtt(grtt_estimate);
|
||||
session->ServerSetGroupSize(group_size);
|
||||
if (!session->StartServer(tx_buffer_size, segment_size, ndata, nparity, interface_name))
|
||||
{
|
||||
DMSG(0, "NormApp::OnStartup() start server error!\n");
|
||||
|
|
@ -1341,6 +1448,8 @@ bool NormApp::OnStartup(int argc, const char*const* argv)
|
|||
session_mgr.Destroy();
|
||||
return false;
|
||||
}
|
||||
tx_stream->SetFlushMode(msg_flush_mode);
|
||||
tx_stream->SetPushMode(push_mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1407,6 +1516,10 @@ void NormApp::SignalHandler(int sigNum)
|
|||
{
|
||||
NormApp* app = static_cast<NormApp*>(ProtoApp::GetApp());
|
||||
if (app->post_processor) app->post_processor->OnDeath();
|
||||
// The use of "waitpid()" here is a work-around for
|
||||
// an IRIX SIGCHLD issue
|
||||
int status;
|
||||
while (waitpid(-1, &status, WNOHANG) > 0);
|
||||
signal(SIGCHLD, SignalHandler);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -378,7 +378,9 @@ bool NormBitmask::Add(const NormBitmask& b)
|
|||
if (b.num_bits > num_bits) return false;
|
||||
for(unsigned int i = 0; i < b.mask_len; i++)
|
||||
mask[i] |= b.mask[i];
|
||||
if (b.first_set < first_set) first_set = b.first_set;
|
||||
if ((b.first_set < first_set) &&
|
||||
(b.first_set < b.num_bits))
|
||||
first_set = b.first_set;
|
||||
return true;
|
||||
} // end NormBitmask::Add()
|
||||
|
||||
|
|
@ -406,13 +408,14 @@ bool NormBitmask::XCopy(const NormBitmask& b)
|
|||
for (unsigned int i = begin; i < len; i++)
|
||||
mask[i] = b.mask[i] & ~mask[i];
|
||||
if (len < mask_len) memset(&mask[len], 0, mask_len - len);
|
||||
if (b.first_set < first_set)
|
||||
UINT32 theFirst = (b.first_set < b.num_bits) ? b.first_set : num_bits;
|
||||
if (theFirst < first_set)
|
||||
{
|
||||
first_set = b.first_set;
|
||||
}
|
||||
else
|
||||
{
|
||||
first_set = b.first_set;
|
||||
first_set = theFirst;
|
||||
if (!GetNextSet(first_set)) first_set = num_bits;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -425,6 +428,7 @@ bool NormBitmask::Multiply(const NormBitmask& b)
|
|||
for(unsigned int i = 0; i < len; i++)
|
||||
mask[i] |= b.mask[i];
|
||||
if (len < mask_len) memset(&mask[len], 0, mask_len - len);
|
||||
|
||||
if (b.first_set > first_set)
|
||||
{
|
||||
first_set = b.first_set;
|
||||
|
|
@ -557,7 +561,7 @@ bool NormSlidingMask::CanSet(UINT32 index) const
|
|||
|
||||
bool NormSlidingMask::Set(UINT32 index)
|
||||
{
|
||||
ASSERT(CanSet(index));
|
||||
//ASSERT(CanSet(index));
|
||||
if (IsSet())
|
||||
{
|
||||
// Determine position with respect to current start
|
||||
|
|
|
|||
|
|
@ -218,8 +218,8 @@ void NormEncoder::Encode(const char *data, char **pVec)
|
|||
*/
|
||||
|
||||
NormDecoder::NormDecoder()
|
||||
: npar(0), vector_size(0),
|
||||
Lambda(NULL), sVec(NULL), oVec(NULL)
|
||||
: npar(0), vector_size(0), Lambda(NULL),
|
||||
sVec(NULL), oVec(NULL), scratch(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
#include "normFile.h"
|
||||
|
||||
#include <string.h> // for strerror()
|
||||
|
|
@ -63,7 +62,7 @@ bool NormFile::Open(const char* thePath, int theFlags)
|
|||
if (mkdir(tempPath, 0755))
|
||||
#endif // if/else WIN32/UNIX
|
||||
{
|
||||
DMSG(0, "NormFile::Rename() mkdir(%s) error: %s\n",
|
||||
DMSG(0, "NormFile::Open() mkdir(%s) error: %s\n",
|
||||
tempPath, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
|
@ -159,10 +158,21 @@ bool NormFile::Rename(const char* oldName, const char* newName)
|
|||
if (!strcmp(oldName, newName)) return true; // no change required
|
||||
// Make sure the new file name isn't an existing "busy" file
|
||||
// (This also builds sub-directories as needed)
|
||||
if (NormFile::IsLocked(newName)) return false;
|
||||
if (NormFile::IsLocked(newName))
|
||||
{
|
||||
DMSG(0, "NormFile::Rename() error: file is locked\n");
|
||||
return false;
|
||||
}
|
||||
#ifdef WIN32
|
||||
// In Win32, the new file can't already exist
|
||||
if (NormFile::Exists(newName)) _unlink(newName);
|
||||
if (NormFile::Exists(newName))
|
||||
{
|
||||
if (0 != _unlink(newName))
|
||||
{
|
||||
DMSG(0, "NormFile::Rename() _unlink() error: %s\n", GetErrorString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// In Win32, the old file can't be open
|
||||
int oldFlags = 0;
|
||||
if (IsOpen())
|
||||
|
|
@ -171,7 +181,7 @@ bool NormFile::Rename(const char* oldName, const char* newName)
|
|||
oldFlags &= ~(O_CREAT | O_TRUNC); // unset these
|
||||
Close();
|
||||
}
|
||||
#else
|
||||
#endif // WIN32
|
||||
// Create sub-directories as needed.
|
||||
char tempPath[PATH_MAX];
|
||||
strncpy(tempPath, newName, PATH_MAX);
|
||||
|
|
@ -198,29 +208,44 @@ bool NormFile::Rename(const char* oldName, const char* newName)
|
|||
{
|
||||
ptr = strchr(ptr, PROTO_PATH_DELIMITER);
|
||||
if (ptr) *ptr = '\0';
|
||||
#ifdef WIN32
|
||||
if (0 != _mkdir(tempPath))
|
||||
#else
|
||||
if (mkdir(tempPath, 0755))
|
||||
#endif // if/else WIN32/UNIX
|
||||
{
|
||||
DMSG(0, "NormFile::Rename() mkdir(%s) error: %s\n",
|
||||
tempPath, strerror(errno));
|
||||
tempPath, GetErrorString());
|
||||
return false;
|
||||
}
|
||||
if (ptr) *ptr++ = PROTO_PATH_DELIMITER;
|
||||
}
|
||||
#endif // if/else WIN32
|
||||
|
||||
if (rename(oldName, newName))
|
||||
{
|
||||
DMSG(0, "NormFile::Rename() rename() error: %s\n", strerror(errno));
|
||||
#ifdef WIN32
|
||||
//if (oldFlags) Open(oldName, oldFlags);
|
||||
if (oldFlags)
|
||||
{
|
||||
if (Open(oldName, oldFlags))
|
||||
offset = 0;
|
||||
else
|
||||
DMSG(0, "NormFile::Rename() error re-opening file w/ old name\n");
|
||||
}
|
||||
#endif // WIN32
|
||||
return false;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef WIN32
|
||||
// (TBD) Is the file offset OK doing this???
|
||||
//if (oldFlags) Open(newName, oldFlags);
|
||||
if (oldFlags)
|
||||
{
|
||||
if (Open(newName, oldFlags))
|
||||
offset = 0;
|
||||
else
|
||||
DMSG(0, "NormFile::Rename() error opening file w/ new name\n");
|
||||
}
|
||||
#endif // WIN32
|
||||
return true;
|
||||
}
|
||||
|
|
@ -234,7 +259,7 @@ int NormFile::Read(char* buffer, int len)
|
|||
#else
|
||||
int result = read(fd, buffer, len);
|
||||
#endif // if/else WIN32
|
||||
if (result > 0) offset += result;
|
||||
if (result > 0) offset += (off_t)result;
|
||||
return result;
|
||||
} // end NormFile::Read()
|
||||
|
||||
|
|
@ -246,7 +271,7 @@ int NormFile::Write(const char* buffer, int len)
|
|||
#else
|
||||
int result = write(fd, buffer, len);
|
||||
#endif // if/else WIN32
|
||||
if (result > 0) offset += result;
|
||||
if (result > 0) offset += (off_t)result;
|
||||
return result;
|
||||
} // end NormFile::Write()
|
||||
|
||||
|
|
|
|||
|
|
@ -29,14 +29,14 @@ bool NormMsg::InitFromBuffer(UINT16 msgLength)
|
|||
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)
|
||||
if ((unsigned char)buffer[NormObjectMsg::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]);
|
||||
buffer[NormObjectMsg::FEC_ID_OFFSET]);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
|
@ -54,7 +54,7 @@ bool NormMsg::InitFromBuffer(UINT16 msgLength)
|
|||
else
|
||||
{
|
||||
DMSG(0, "NormMsg::InitFromBuffer(FLUSH|SQUELCH) unknown fec_id value: %u\n",
|
||||
buffer[NormDataMsg::FEC_ID_OFFSET]);
|
||||
buffer[NormCmdFlushMsg::FEC_ID_OFFSET]);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
|
@ -420,7 +420,7 @@ unsigned char NormQuantizeRtt(double rtt)
|
|||
else if (rtt < NORM_RTT_MIN)
|
||||
rtt = NORM_RTT_MIN;
|
||||
if (rtt < 3.3e-05)
|
||||
return ((unsigned char)ceil((rtt*NORM_RTT_MIN)) - 1);
|
||||
return ((unsigned char)((rtt/NORM_RTT_MIN)) - 1);
|
||||
else
|
||||
return ((unsigned char)(ceil(255.0 - (13.0*log(NORM_RTT_MAX/rtt)))));
|
||||
} // end NormQuantizeRtt()
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ const UINT8 NORM_PROTOCOL_VERSION = 1;
|
|||
|
||||
const int NORM_ROBUST_FACTOR = 20; // default robust factor
|
||||
|
||||
|
||||
// Pick a random number from 0..max
|
||||
inline double UniformRand(double max)
|
||||
{
|
||||
|
|
@ -46,7 +45,7 @@ const double NORM_RTT_MAX = 1000.0;
|
|||
inline double NormUnquantizeRtt(unsigned char qrtt)
|
||||
{
|
||||
return ((qrtt < 31) ?
|
||||
(((double)(qrtt+1))/(double)NORM_RTT_MIN) :
|
||||
(((double)(qrtt+1))*(double)NORM_RTT_MIN) :
|
||||
(NORM_RTT_MAX/exp(((double)(255-qrtt))/(double)13.0)));
|
||||
}
|
||||
unsigned char NormQuantizeRtt(double rtt);
|
||||
|
|
@ -95,6 +94,7 @@ inline double NormUnquantizeRate(unsigned short rate)
|
|||
}
|
||||
|
||||
// This class is used to describe object "size" and/or "offset"
|
||||
// (TBD) This hokey implementation should use "off_t"
|
||||
class NormObjectSize
|
||||
{
|
||||
public:
|
||||
|
|
@ -103,6 +103,13 @@ class NormObjectSize
|
|||
NormObjectSize(UINT32 size) : msb(0), lsb(size) {}
|
||||
NormObjectSize(UINT16 size) : msb(0), lsb(size) {}
|
||||
NormObjectSize(const NormObjectSize& size) : msb(size.msb), lsb(size.lsb) {}
|
||||
NormObjectSize(off_t size)
|
||||
{
|
||||
lsb = size & 0x00000000ffffffff;
|
||||
size >>= 32;
|
||||
ASSERT(0 == (size & 0xffff0000));
|
||||
msb = size & 0x0000ffff;
|
||||
}
|
||||
|
||||
UINT16 MSB() const {return msb;}
|
||||
UINT32 LSB() const {return lsb;}
|
||||
|
|
@ -150,15 +157,24 @@ class NormObjectSize
|
|||
}
|
||||
NormObjectSize operator*(const NormObjectSize& b) const;
|
||||
NormObjectSize operator/(const NormObjectSize& b) const;
|
||||
off_t GetOffset() const
|
||||
{
|
||||
off_t offset = msb;
|
||||
offset <<= 32;
|
||||
offset += lsb;
|
||||
return offset;
|
||||
}
|
||||
|
||||
private:
|
||||
UINT16 msb;
|
||||
UINT32 lsb;
|
||||
}; // end class NormObjectSize
|
||||
|
||||
typedef UINT32 NormNodeId;
|
||||
const NormNodeId NORM_NODE_INVALID = 0x00000000;
|
||||
#ifndef _NORM_API
|
||||
typedef unsigned long NormNodeId;
|
||||
const NormNodeId NORM_NODE_NONE = 0x00000000;
|
||||
const NormNodeId NORM_NODE_ANY = 0xffffffff;
|
||||
#endif // !_NORM_API
|
||||
|
||||
class NormObjectId
|
||||
{
|
||||
|
|
@ -167,18 +183,12 @@ class NormObjectId
|
|||
NormObjectId(UINT16 id) {value = id;}
|
||||
NormObjectId(const NormObjectId& id) {value = id.value;}
|
||||
operator UINT16() const {return value;}
|
||||
int operator-(const NormObjectId& id) const
|
||||
{
|
||||
int result = value - id.value;
|
||||
return ((0 == (result & 0x00008000)) ?
|
||||
(result & 0x0000ffff) :
|
||||
(((result != 0x00008000) || (value < id.value)) ?
|
||||
result | 0xffff0000 : result));
|
||||
}
|
||||
INT16 operator-(const NormObjectId& id) const
|
||||
{return ((INT16)(value - id.value));}
|
||||
bool operator<(const NormObjectId& id) const
|
||||
{return ((*this - id) < 0);}
|
||||
{return (((short)(value - id.value)) < 0);}
|
||||
bool operator>(const NormObjectId& id) const
|
||||
{return ((*this - id) > 0);}
|
||||
{return (((INT16)(value - id.value)) > 0);}
|
||||
bool operator<=(const NormObjectId& id) const
|
||||
{return ((value == id.value) || (*this<id));}
|
||||
bool operator>=(const NormObjectId& id) const
|
||||
|
|
@ -187,7 +197,7 @@ class NormObjectId
|
|||
{return (value == id.value);}
|
||||
bool operator!=(const NormObjectId& id) const
|
||||
{return (value != id.value);}
|
||||
NormObjectId& operator++(int ) {value++; return *this;}
|
||||
NormObjectId& operator++(int) {value++; return *this;}
|
||||
|
||||
private:
|
||||
UINT16 value;
|
||||
|
|
@ -204,17 +214,17 @@ class NormBlockId
|
|||
{return (value == (UINT32)id);}
|
||||
bool operator!=(const NormBlockId& id) const
|
||||
{return (value != (UINT32)id);}
|
||||
long operator-(const NormBlockId& id) const
|
||||
{return ((long)value - id.value);}
|
||||
INT32 operator-(const NormBlockId& id) const
|
||||
{return ((INT32)value - id.value);}
|
||||
bool operator<(const NormBlockId& id) const
|
||||
{return ((*this - id) < 0);}
|
||||
{return (((INT32)(value-id.value)) < 0);}
|
||||
bool operator>(const NormBlockId& id) const
|
||||
{return ((*this - id) > 0);}
|
||||
{return (((INT32)(value-id.value)) > 0);}
|
||||
NormBlockId& operator++(int ) {value++; return *this;}
|
||||
|
||||
private:
|
||||
UINT32 value;
|
||||
}; // end class NormObjectId
|
||||
}; // end class NormBlockId
|
||||
|
||||
typedef UINT16 NormSymbolId;
|
||||
typedef NormSymbolId NormSegmentId;
|
||||
|
|
@ -361,7 +371,7 @@ class NormMsg
|
|||
void ExtendHeaderLength(UINT16 len)
|
||||
{
|
||||
header_length += len;
|
||||
length = header_length;
|
||||
length += len;
|
||||
buffer[HDR_LEN_OFFSET] = header_length >> 2;
|
||||
}
|
||||
|
||||
|
|
@ -624,6 +634,7 @@ class NormDataMsg : public NormObjectMsg
|
|||
return (length - dataIndex);
|
||||
}
|
||||
|
||||
|
||||
// These routines are only applicable to messages containing NORM_OBJECT_STREAM content
|
||||
// Some static helper routines for reading/writing embedded payload length/offsets
|
||||
static UINT16 GetStreamPayloadHeaderLength() {return (PAYLOAD_DATA_OFFSET);}
|
||||
|
|
@ -1049,7 +1060,7 @@ class NormRepairRequest
|
|||
void SetForm(NormRepairRequest::Form theForm) {form = theForm;}
|
||||
void ResetFlags() {flags = 0;}
|
||||
void SetFlag(NormRepairRequest::Flag theFlag) {flags |= theFlag;}
|
||||
void UnsetFlag(NormRepairRequest::Flag theFlag) {flags &= ~theFlag;}
|
||||
void ClearFlag(NormRepairRequest::Flag theFlag) {flags &= ~theFlag;}
|
||||
|
||||
// Returns length (each repair item requires 8 bytes of space)
|
||||
bool AppendRepairItem(const NormObjectId& objectId,
|
||||
|
|
@ -1417,6 +1428,7 @@ class NormAckMsg : public NormMsg
|
|||
{
|
||||
UINT16 len = MIN(payloadLen, segmentSize);
|
||||
memcpy(buffer+header_length, payload, len);
|
||||
length += len;
|
||||
return (payloadLen <= segmentSize);
|
||||
}
|
||||
|
||||
|
|
@ -1439,7 +1451,7 @@ class NormAckMsg : public NormMsg
|
|||
UINT16 GetPayloadLength() const {return (length - header_length);}
|
||||
const char* GetPayload() const {return (buffer + header_length);}
|
||||
|
||||
private:
|
||||
protected:
|
||||
enum
|
||||
{
|
||||
SERVER_ID_OFFSET = MSG_OFFSET,
|
||||
|
|
@ -1451,6 +1463,75 @@ class NormAckMsg : public NormMsg
|
|||
};
|
||||
}; // end class NormAckMsg
|
||||
|
||||
class NormAckFlushMsg : public NormAckMsg
|
||||
{
|
||||
public:
|
||||
void Init()
|
||||
{
|
||||
SetType(ACK);
|
||||
SetBaseHeaderLength(ACK_HEADER_LEN);
|
||||
SetAckType(NormAck::FLUSH);
|
||||
SetFecId(129); // only one supported for the moment
|
||||
buffer[RESERVED_OFFSET] = 0;
|
||||
length = ACK_HEADER_LEN+PAYLOAD_LENGTH;
|
||||
}
|
||||
|
||||
// Note: must apply any header exts _before_ the payload is set
|
||||
void SetFecId(UINT8 fecId)
|
||||
{buffer[header_length+FEC_ID_OFFSET] = fecId;}
|
||||
void SetObjectId(NormObjectId objectId)
|
||||
{*((UINT16*)(buffer+header_length+OBJ_ID_OFFSET)) = htons((UINT16)objectId);}
|
||||
void SetFecBlockId(const NormBlockId& blockId)
|
||||
{
|
||||
UINT32 temp32 = htonl((UINT32)blockId);
|
||||
memcpy(buffer+header_length+BLOCK_ID_OFFSET, &temp32, 4);
|
||||
}
|
||||
void SetFecBlockLen(UINT16 blockLen)
|
||||
{
|
||||
blockLen = htons(blockLen);
|
||||
memcpy(buffer+header_length+BLOCK_LEN_OFFSET, &blockLen, 2);
|
||||
}
|
||||
void SetFecSymbolId(UINT16 symbolId)
|
||||
{
|
||||
symbolId = htons(symbolId);
|
||||
memcpy(buffer+header_length+SYMBOL_ID_OFFSET, &symbolId, 2);
|
||||
}
|
||||
|
||||
// Message processing
|
||||
UINT8 GetFecId() {return buffer[header_length+FEC_ID_OFFSET];}
|
||||
NormObjectId GetObjectId() const
|
||||
{
|
||||
return (ntohs(*((UINT16*)(buffer+header_length+OBJ_ID_OFFSET))));
|
||||
}
|
||||
NormBlockId GetFecBlockId() const
|
||||
{
|
||||
return (ntohl(*((UINT32*)(buffer+header_length+BLOCK_ID_OFFSET))));
|
||||
}
|
||||
UINT16 GetFecBlockLen() const
|
||||
{
|
||||
return (ntohs(*((UINT16*)(buffer+header_length+BLOCK_LEN_OFFSET))));
|
||||
}
|
||||
UINT16 GetFecSymbolId() const
|
||||
{
|
||||
return (ntohs(*((UINT16*)(buffer+header_length+SYMBOL_ID_OFFSET))));
|
||||
}
|
||||
|
||||
private:
|
||||
// These are the payload offsets for "fec_id" = 129
|
||||
// "fec_payload_id" field
|
||||
enum
|
||||
{
|
||||
FEC_ID_OFFSET = 0,
|
||||
RESERVED_OFFSET = FEC_ID_OFFSET + 1,
|
||||
OBJ_ID_OFFSET = RESERVED_OFFSET + 1,
|
||||
BLOCK_ID_OFFSET = OBJ_ID_OFFSET + 2,
|
||||
BLOCK_LEN_OFFSET = BLOCK_ID_OFFSET + 4,
|
||||
SYMBOL_ID_OFFSET = BLOCK_LEN_OFFSET + 2,
|
||||
PAYLOAD_LENGTH = SYMBOL_ID_OFFSET + 2
|
||||
};
|
||||
|
||||
}; // end class NormAckFlushMsg
|
||||
|
||||
class NormReportMsg : public NormMsg
|
||||
{
|
||||
// (TBD)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -14,8 +14,10 @@ class NormNode
|
|||
friend class NormNodeListIterator;
|
||||
|
||||
public:
|
||||
NormNode(class NormSession* theSession, NormNodeId nodeId);
|
||||
NormNode(class NormSession& theSession, NormNodeId nodeId);
|
||||
virtual ~NormNode();
|
||||
void Retain();
|
||||
void Release();
|
||||
|
||||
const ProtoAddress& GetAddress() const {return addr;}
|
||||
void SetAddress(const ProtoAddress& address) {addr = address;}
|
||||
|
|
@ -24,12 +26,13 @@ class NormNode
|
|||
inline const NormNodeId& LocalNodeId() const;
|
||||
|
||||
protected:
|
||||
class NormSession* session;
|
||||
class NormSession& session;
|
||||
|
||||
private:
|
||||
NormNodeId id;
|
||||
ProtoAddress addr;
|
||||
// We keep NormNodes in a binary tree
|
||||
unsigned int reference_count;
|
||||
// We keep NormNodes in a binary tree (TBD) make this a ProtoTree
|
||||
NormNode* parent;
|
||||
NormNode* right;
|
||||
NormNode* left;
|
||||
|
|
@ -137,11 +140,33 @@ class NormLossEstimator2
|
|||
|
||||
}; // end class NormLossEstimator2
|
||||
|
||||
class NormAckingNode : public NormNode
|
||||
{
|
||||
public:
|
||||
NormAckingNode(class NormSession& theSession, NormNodeId nodeId);
|
||||
~NormAckingNode();
|
||||
bool IsPending() const
|
||||
{return (!ack_received &&( req_count > 0));}
|
||||
void Reset(unsigned int maxAttempts = NORM_ROBUST_FACTOR)
|
||||
{
|
||||
ack_received = false;
|
||||
req_count = maxAttempts;
|
||||
}
|
||||
void DecrementReqCount() {if (req_count > 0) req_count--;}
|
||||
unsigned int GetReqCount() const {return req_count;}
|
||||
bool AckReceived() const {return ack_received;}
|
||||
void MarkAckReceived() {ack_received = true;}
|
||||
|
||||
private:
|
||||
bool ack_received; // was ack received?
|
||||
unsigned int req_count; // remaining request attempts
|
||||
|
||||
}; // end NormAckingNode
|
||||
|
||||
class NormCCNode : public NormNode
|
||||
{
|
||||
public:
|
||||
NormCCNode(class NormSession* theSession, NormNodeId nodeId);
|
||||
NormCCNode(class NormSession& theSession, NormNodeId nodeId);
|
||||
~NormCCNode();
|
||||
|
||||
bool IsClr() const {return is_clr;}
|
||||
|
|
@ -182,9 +207,26 @@ class NormServerNode : public NormNode
|
|||
public:
|
||||
enum ObjectStatus {OBJ_INVALID, OBJ_NEW, OBJ_PENDING, OBJ_COMPLETE};
|
||||
|
||||
NormServerNode(class NormSession* theSession, NormNodeId nodeId);
|
||||
enum RepairBoundary {BLOCK_BOUNDARY, OBJECT_BOUNDARY};
|
||||
|
||||
NormServerNode(class NormSession& theSession, NormNodeId nodeId);
|
||||
~NormServerNode();
|
||||
|
||||
// Parameters
|
||||
NormObject::NackingMode GetDefaultNackingMode() const
|
||||
{return default_nacking_mode;}
|
||||
void SetDefaultNackingMode(NormObject::NackingMode nackingMode)
|
||||
{default_nacking_mode = nackingMode;}
|
||||
|
||||
NormServerNode::RepairBoundary GetRepairBoundary() const
|
||||
{return repair_boundary;}
|
||||
// (TBD) force an appropriate RepairCheck on boundary change???
|
||||
void SetRepairBoundary(RepairBoundary repairBoundary)
|
||||
{repair_boundary = repairBoundary;}
|
||||
|
||||
bool UnicastNacks() {return unicast_nacks;}
|
||||
void SetUnicastNacks(bool state) {unicast_nacks = state;}
|
||||
|
||||
bool UpdateLossEstimate(const struct timeval& currentTime,
|
||||
unsigned short theSequence,
|
||||
bool ecnStatus = false);
|
||||
|
|
@ -201,10 +243,15 @@ class NormServerNode : public NormNode
|
|||
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 Open(UINT16 sessionId);
|
||||
UINT16 GetSessionId() {return session_id;}
|
||||
bool IsOpen() const {return is_open;}
|
||||
void Close();
|
||||
bool AllocateBuffers(UINT16 segmentSize, UINT16 numData, UINT16 numParity);
|
||||
bool BuffersAllocated() {return (0 != segment_size);}
|
||||
void FreeBuffers();
|
||||
void Activate();
|
||||
|
||||
|
||||
bool SyncTest(const NormObjectMsg& msg) const;
|
||||
void Sync(NormObjectId objectId);
|
||||
|
|
@ -234,7 +281,7 @@ class NormServerNode : public NormNode
|
|||
}
|
||||
void SetPending(NormObjectId objectId);
|
||||
|
||||
void DeleteObject(NormObject* obj);
|
||||
void DeleteObject(NormObject* obj, int which);
|
||||
|
||||
UINT16 SegmentSize() {return segment_size;}
|
||||
UINT16 BlockSize() {return ndata;}
|
||||
|
|
@ -287,6 +334,9 @@ class NormServerNode : public NormNode
|
|||
|
||||
|
||||
private:
|
||||
bool PassiveRepairCheck(NormObjectId objectId,
|
||||
NormBlockId blockId,
|
||||
NormSegmentId segmentId);
|
||||
void RepairCheck(NormObject::CheckLevel checkLevel,
|
||||
NormObjectId objectId,
|
||||
NormBlockId blockId,
|
||||
|
|
@ -295,12 +345,18 @@ class NormServerNode : public NormNode
|
|||
bool OnActivityTimeout(ProtoTimer& theTimer);
|
||||
bool OnRepairTimeout(ProtoTimer& theTimer);
|
||||
bool OnCCTimeout(ProtoTimer& theTimer);
|
||||
bool OnAckTimeout(ProtoTimer& theTimer);
|
||||
|
||||
void AttachCCFeedback(NormAckMsg& ack);
|
||||
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)
|
||||
NormObjectId max_pending_object; // index for NACK construction
|
||||
NormObjectId current_object_id; // index for suppression
|
||||
UINT16 max_pending_range; // max range of pending objs allowed
|
||||
|
||||
bool is_open;
|
||||
UINT16 segment_size;
|
||||
|
|
@ -310,15 +366,23 @@ class NormServerNode : public NormNode
|
|||
NormObjectTable rx_table;
|
||||
NormSlidingMask rx_pending_mask;
|
||||
NormSlidingMask rx_repair_mask;
|
||||
RepairBoundary repair_boundary;
|
||||
NormObject::NackingMode default_nacking_mode;
|
||||
bool unicast_nacks;
|
||||
NormBlockPool block_pool;
|
||||
NormSegmentPool segment_pool;
|
||||
NormDecoder decoder;
|
||||
UINT16* erasure_loc;
|
||||
|
||||
bool server_active;
|
||||
ProtoTimer activity_timer;
|
||||
ProtoTimer repair_timer;
|
||||
NormObjectId current_object_id; // index for suppression
|
||||
NormObjectId max_pending_object; // index for NACK construction
|
||||
|
||||
// Watermark acknowledgement
|
||||
ProtoTimer ack_timer;
|
||||
NormObjectId watermark_object_id;
|
||||
NormBlockId watermark_block_id;
|
||||
NormSegmentId watermark_segment_id;
|
||||
|
||||
// Remote server grtt measurement state
|
||||
double grtt_estimate;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -14,6 +14,7 @@ class NormObject
|
|||
public:
|
||||
enum Type
|
||||
{
|
||||
NONE,
|
||||
DATA,
|
||||
FILE,
|
||||
STREAM
|
||||
|
|
@ -21,6 +22,7 @@ class NormObject
|
|||
|
||||
enum CheckLevel
|
||||
{
|
||||
TO_OBJECT,
|
||||
THRU_INFO,
|
||||
TO_BLOCK,
|
||||
THRU_SEGMENT,
|
||||
|
|
@ -28,7 +30,21 @@ class NormObject
|
|||
THRU_OBJECT
|
||||
};
|
||||
|
||||
enum NackingMode
|
||||
{
|
||||
NACK_NONE,
|
||||
NACK_INFO_ONLY,
|
||||
NACK_NORMAL
|
||||
};
|
||||
|
||||
virtual ~NormObject();
|
||||
void Retain();
|
||||
void Release();
|
||||
unsigned int GetReferenceCount() {return reference_count;}
|
||||
|
||||
// This must be reset after each update
|
||||
void SetNotifyOnUpdate(bool state)
|
||||
{notify_on_update = state;}
|
||||
|
||||
// Object information
|
||||
NormObject::Type GetType() const {return type;}
|
||||
|
|
@ -39,19 +55,33 @@ class NormObject
|
|||
UINT16 GetInfoLength() const {return info_len;}
|
||||
bool IsStream() const {return (STREAM == type);}
|
||||
|
||||
class NormSession& GetSession() const {return session;}
|
||||
NormNodeId LocalNodeId() const;
|
||||
class NormServerNode* GetServer() {return server;}
|
||||
class NormServerNode* GetServer() const {return server;}
|
||||
NormNodeId GetServerNodeId() const;
|
||||
|
||||
bool IsOpen() {return (0 != segment_size);}
|
||||
// Opens (inits) object for tx operation
|
||||
bool Open(const NormObjectSize& objectSize,
|
||||
const char* infoPtr,
|
||||
UINT16 infoLen);
|
||||
UINT16 infoLen,
|
||||
UINT16 segmentSize,
|
||||
UINT16 numData,
|
||||
UINT16 numParity);
|
||||
// Opens (inits) object for rx operation
|
||||
bool Open(const NormObjectSize& objectSize, bool hasInfo)
|
||||
{return Open(objectSize, (char*)NULL, hasInfo ? 1 : 0);}
|
||||
bool Open(const NormObjectSize& objectSize,
|
||||
bool hasInfo,
|
||||
UINT16 segmentSize,
|
||||
UINT16 numData,
|
||||
UINT16 numParity)
|
||||
{
|
||||
return Open(objectSize, (char*)NULL, hasInfo ? 1 : 0,
|
||||
segmentSize, numData, numParity);
|
||||
}
|
||||
void Close();
|
||||
|
||||
|
||||
|
||||
virtual bool WriteSegment(NormBlockId blockId,
|
||||
NormSegmentId segmentId,
|
||||
const char* buffer) = 0;
|
||||
|
|
@ -59,9 +89,17 @@ class NormObject
|
|||
NormSegmentId segmentId,
|
||||
char* buffer) = 0;
|
||||
|
||||
NackingMode GetNackingMode() const {return nacking_mode;}
|
||||
void SetNackingMode(NackingMode nackingMode)
|
||||
{
|
||||
nacking_mode = nackingMode;
|
||||
// (TBD) initiate an appropriate NormServerNode::RepairCheck
|
||||
// to prompt repair process if needed
|
||||
}
|
||||
|
||||
// These are only valid after object is open
|
||||
NormBlockId GetFinalBlockId() const {return final_block_id;}
|
||||
UINT32 GetBlockSize(NormBlockId blockId)
|
||||
UINT32 GetBlockSize(NormBlockId blockId) const
|
||||
{
|
||||
return (((UINT32)blockId < large_block_count) ? large_block_size :
|
||||
small_block_size);
|
||||
|
|
@ -114,6 +152,7 @@ class NormObject
|
|||
return result;
|
||||
}
|
||||
|
||||
bool FindRepairIndex(NormBlockId& blockId, NormSegmentId& segmentId) const;
|
||||
|
||||
// Methods available to server for transmission
|
||||
bool NextServerMsg(NormObjectMsg* msg);
|
||||
|
|
@ -141,6 +180,7 @@ class NormObject
|
|||
NormBlock* FindBlock(NormBlockId blockId) {return block_buffer.Find(blockId);}
|
||||
bool ActivateRepairs();
|
||||
bool IsRepairSet(NormBlockId blockId) {return repair_mask.Test(blockId);}
|
||||
bool IsPendingSet(NormBlockId blockId) {return pending_mask.Test(blockId);}
|
||||
bool AppendRepairAdv(NormCmdRepairAdvMsg& cmd);
|
||||
|
||||
NormBlockId GetMaxPendingBlockId() const {return max_pending_block;}
|
||||
|
|
@ -161,7 +201,8 @@ class NormObject
|
|||
// Used by receiver for resource management scheme
|
||||
NormBlock* StealNewestBlock(bool excludeBlock, NormBlockId excludeId = 0);
|
||||
NormBlock* StealOldestBlock(bool excludeBlock, NormBlockId excludeId = 0);
|
||||
|
||||
bool PassiveRepairCheck(NormBlockId blockId,
|
||||
NormSegmentId segmentId);
|
||||
bool ClientRepairCheck(CheckLevel level,
|
||||
NormBlockId blockId,
|
||||
NormSegmentId segmentId,
|
||||
|
|
@ -178,15 +219,16 @@ class NormObject
|
|||
|
||||
protected:
|
||||
NormObject(Type theType,
|
||||
class NormSession* theSession,
|
||||
class NormSession& theSession,
|
||||
class NormServerNode* theServer,
|
||||
const NormObjectId& objectId);
|
||||
|
||||
void Accept() {accepted = true;}
|
||||
|
||||
NormObject::Type type;
|
||||
class NormSession* session;
|
||||
class NormSession& session;
|
||||
class NormServerNode* server; // NULL value indicates local (tx) object
|
||||
unsigned int reference_count;
|
||||
NormObjectId transport_id;
|
||||
|
||||
NormObjectSize object_size;
|
||||
|
|
@ -194,9 +236,9 @@ class NormObject
|
|||
UINT16 ndata;
|
||||
UINT16 nparity;
|
||||
NormBlockBuffer block_buffer;
|
||||
bool pending_info;
|
||||
bool pending_info; // set when we need to send or recv info
|
||||
NormSlidingMask pending_mask;
|
||||
bool repair_info;
|
||||
bool repair_info; // client: set when
|
||||
NormSlidingMask repair_mask;
|
||||
NormBlockId current_block_id; // for suppression
|
||||
NormSegmentId next_segment_id; // for suppression
|
||||
|
|
@ -208,11 +250,14 @@ class NormObject
|
|||
UINT32 small_block_size;
|
||||
NormBlockId final_block_id;
|
||||
UINT16 final_segment_size;
|
||||
|
||||
NackingMode nacking_mode;
|
||||
char* info;
|
||||
UINT16 info_len;
|
||||
|
||||
// Here are some members used to let us know
|
||||
// our status with respect to the rest of the world
|
||||
bool accepted;
|
||||
bool notify_on_update;
|
||||
|
||||
NormObject* next;
|
||||
}; // end class NormObject
|
||||
|
|
@ -221,7 +266,7 @@ class NormObject
|
|||
class NormFileObject : public NormObject
|
||||
{
|
||||
public:
|
||||
NormFileObject(class NormSession* theSession,
|
||||
NormFileObject(class NormSession& theSession,
|
||||
class NormServerNode* theServer,
|
||||
const NormObjectId& objectId);
|
||||
~NormFileObject();
|
||||
|
|
@ -231,7 +276,8 @@ class NormFileObject : public NormObject
|
|||
UINT16 infoLen = 0);
|
||||
bool Accept(const char* thePath);
|
||||
void Close();
|
||||
const char* Path() {return path;}
|
||||
|
||||
const char* GetPath() {return path;}
|
||||
bool Rename(const char* newPath)
|
||||
{
|
||||
bool result = file.Rename(path, newPath);
|
||||
|
|
@ -254,11 +300,44 @@ class NormFileObject : public NormObject
|
|||
NormObjectSize small_block_length;
|
||||
}; // end class NormFileObject
|
||||
|
||||
class NormDataObject : public NormObject
|
||||
{
|
||||
// (TBD) allow support of greater than 4GB size data objects
|
||||
public:
|
||||
NormDataObject(class NormSession& theSession,
|
||||
class NormServerNode* theServer,
|
||||
const NormObjectId& objectId);
|
||||
~NormDataObject();
|
||||
|
||||
bool Open(char* dataPtr,
|
||||
UINT32 dataLen,
|
||||
const char* infoPtr = NULL,
|
||||
UINT16 infoLen = 0);
|
||||
bool Accept(char* dataPtr, UINT32 dataMax);
|
||||
void Close();
|
||||
|
||||
const char* GetData() {return data_ptr;}
|
||||
|
||||
virtual bool WriteSegment(NormBlockId blockId,
|
||||
NormSegmentId segmentId,
|
||||
const char* buffer);
|
||||
|
||||
virtual UINT16 ReadSegment(NormBlockId blockId,
|
||||
NormSegmentId segmentId,
|
||||
char* buffer);
|
||||
|
||||
private:
|
||||
NormObjectSize large_block_length;
|
||||
NormObjectSize small_block_length;
|
||||
char* data_ptr;
|
||||
UINT32 data_max;
|
||||
}; // end class NormDataObject
|
||||
|
||||
|
||||
class NormStreamObject : public NormObject
|
||||
{
|
||||
public:
|
||||
NormStreamObject(class NormSession* theSession,
|
||||
NormStreamObject(class NormSession& theSession,
|
||||
class NormServerNode* theServer,
|
||||
const NormObjectId& objectId);
|
||||
~NormStreamObject();
|
||||
|
|
@ -269,19 +348,35 @@ class NormStreamObject : public NormObject
|
|||
void Close();
|
||||
bool Accept(UINT32 bufferSize);
|
||||
|
||||
enum FlushType
|
||||
enum FlushMode
|
||||
{
|
||||
FLUSH_NONE, // no flush action taken
|
||||
FLUSH_PASSIVE, // pending queued data is transmitted, but no CMD(FLUSH) sent
|
||||
FLUSH_ACTIVE // pending queued data is transmitted, _and_ active CMD(FLUSH)
|
||||
};
|
||||
bool Read(char* buffer, unsigned int* buflen, bool findMsgStart = false);
|
||||
UINT32 Write(const char* buffer, UINT32 len, FlushType flushType, bool eom, bool push);
|
||||
|
||||
void SetFlushMode(FlushMode flushMode) {flush_mode = flushMode;}
|
||||
void Flush(bool eom = false)
|
||||
{
|
||||
FlushMode oldFlushMode = flush_mode;
|
||||
SetFlushMode(FLUSH_ACTIVE);
|
||||
Write(NULL, 0, eom);
|
||||
SetFlushMode(oldFlushMode);
|
||||
}
|
||||
void SetPushMode(bool state) {push_mode = state;}
|
||||
|
||||
bool Read(char* buffer, unsigned int* buflen, bool findMsgStart = false);
|
||||
UINT32 Write(const char* buffer, UINT32 len, bool eom = false);
|
||||
|
||||
bool SyncOffsetIsValid() {return sync_offset_valid;}
|
||||
UINT32 GetSyncOffset() {return sync_offset;}
|
||||
UINT32 GetCurrentReadOffset() {return read_offset;}
|
||||
|
||||
bool StreamUpdateStatus(NormBlockId blockId);
|
||||
void StreamResync(NormBlockId nextBlockId)
|
||||
{stream_next_id = nextBlockId;}
|
||||
{
|
||||
stream_next_id = nextBlockId;
|
||||
}
|
||||
void StreamAdvance();
|
||||
|
||||
virtual bool WriteSegment(NormBlockId blockId,
|
||||
|
|
@ -309,6 +404,10 @@ class NormStreamObject : public NormObject
|
|||
{return (write_index.segment ? (write_index.segment-1) :
|
||||
(ndata-1));}
|
||||
|
||||
NormBlockId GetNextBlockId() const
|
||||
{return (server ? read_index.block : write_index.block);}
|
||||
NormSegmentId GetNextSegmentId() const
|
||||
{return (server ? read_index.segment : write_index.segment);}
|
||||
private:
|
||||
class Index
|
||||
{
|
||||
|
|
@ -320,6 +419,8 @@ class NormStreamObject : public NormObject
|
|||
bool stream_sync;
|
||||
NormBlockId stream_sync_id;
|
||||
NormBlockId stream_next_id;
|
||||
UINT32 sync_offset;
|
||||
bool sync_offset_valid;
|
||||
|
||||
NormBlockPool block_pool;
|
||||
NormSegmentPool segment_pool;
|
||||
|
|
@ -330,6 +431,8 @@ class NormStreamObject : public NormObject
|
|||
UINT32 read_offset;
|
||||
bool flush_pending;
|
||||
bool msg_start;
|
||||
FlushMode flush_mode;
|
||||
bool push_mode;
|
||||
}; // end class NormStreamObject
|
||||
|
||||
#ifdef SIMULATE
|
||||
|
|
@ -338,7 +441,7 @@ class NormStreamObject : public NormObject
|
|||
class NormSimObject : public NormObject
|
||||
{
|
||||
public:
|
||||
NormSimObject(class NormSession* theSession,
|
||||
NormSimObject(class NormSession& theSession,
|
||||
class NormServerNode* theServer,
|
||||
const NormObjectId& objectId);
|
||||
~NormSimObject();
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ void NormPostProcessor::GetCommand(char* buffer, unsigned int buflen)
|
|||
|
||||
bool NormPostProcessor::SetCommand(const char* cmd)
|
||||
{
|
||||
|
||||
// 1) Delete old command resources
|
||||
if (process_argv)
|
||||
{
|
||||
|
|
@ -81,10 +80,10 @@ bool NormPostProcessor::SetCommand(const char* cmd)
|
|||
{
|
||||
argCount++;
|
||||
while (!isspace(*ptr) && ('\0' != *ptr)) ptr++;
|
||||
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 char*[argCount+2]))
|
||||
|
|
@ -115,7 +114,8 @@ bool NormPostProcessor::SetCommand(const char* cmd)
|
|||
}
|
||||
strncpy(arg, argStart, argLength);
|
||||
arg[argLength] = '\0';
|
||||
process_argv[index] = arg;
|
||||
process_argv[index++] = arg;
|
||||
while (isspace(*ptr) && ('\0' != *ptr)) ptr++;
|
||||
}
|
||||
return true;
|
||||
} // end NormPostProcessor::SetCommand()
|
||||
|
|
|
|||
|
|
@ -257,6 +257,7 @@ bool NormBlock::ActivateRepairs(UINT16 numParity)
|
|||
if (repair_mask.IsSet())
|
||||
{
|
||||
pending_mask.Add(repair_mask);
|
||||
ASSERT(pending_mask.IsSet());
|
||||
repair_mask.Clear();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -390,7 +391,7 @@ bool NormBlock::HandleSegmentRequest(NormSegmentId nextId, NormSegmentId lastId,
|
|||
return increasedRepair;
|
||||
} // end NormBlock::HandleSegmentRequest()
|
||||
|
||||
|
||||
// (TBD) this should return true is something is appending, false otherwise
|
||||
bool NormBlock::AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
|
||||
NormObjectId objectId,
|
||||
bool repairInfo,
|
||||
|
|
@ -433,7 +434,13 @@ bool NormBlock::AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
|
|||
if (form != prevForm)
|
||||
{
|
||||
if (NormRepairRequest::INVALID != prevForm)
|
||||
cmd.PackRepairRequest(req); // (TBD) error check
|
||||
{
|
||||
if (0 == cmd.PackRepairRequest(req))
|
||||
{
|
||||
DMSG(0, "NormBlock::AppendRepairAdv() warning: full msg\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
req.SetForm(form);
|
||||
cmd.AttachRepairRequest(req, segmentSize); // (TBD) error check
|
||||
prevForm = form;
|
||||
|
|
@ -460,12 +467,16 @@ bool NormBlock::AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
|
|||
}
|
||||
} // end while (nextId < totalSize)
|
||||
if (NormRepairRequest::INVALID != prevForm)
|
||||
cmd.PackRepairRequest(req); // (TBD) error check
|
||||
{
|
||||
if (0 == cmd.PackRepairRequest(req))
|
||||
DMSG(0, "NormBlock::AppendRepairAdv() warning: full msg\n");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} // end NormBlock::AppendRepairAdv()
|
||||
|
||||
// Called by client
|
||||
// (TBD) this should return true iff something appended, false otherwise
|
||||
bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
|
||||
UINT16 numData,
|
||||
UINT16 numParity,
|
||||
|
|
@ -527,7 +538,13 @@ bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
|
|||
if (form != prevForm)
|
||||
{
|
||||
if (NormRepairRequest::INVALID != prevForm)
|
||||
nack.PackRepairRequest(req); // (TBD) error check
|
||||
{
|
||||
if (0 == nack.PackRepairRequest(req))
|
||||
{
|
||||
DMSG(0, "NormBlock::AppendRepairRequest() warning: full NACK msg\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
nack.AttachRepairRequest(req, segmentSize); // (TBD) error check
|
||||
req.SetForm(form);
|
||||
prevForm = form;
|
||||
|
|
@ -554,76 +571,10 @@ bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
|
|||
}
|
||||
} // end while (nextId < lastId)
|
||||
if (NormRepairRequest::INVALID != prevForm)
|
||||
nack.PackRepairRequest(req); // (TBD) error check
|
||||
|
||||
/*
|
||||
// old code begins here
|
||||
NormSegmentId prevId = nextId;
|
||||
while ((nextId <= lastId) || (segmentCount > 0))
|
||||
{
|
||||
// force break of possible ending consec. series
|
||||
if (nextId == lastId) nextId++;
|
||||
if (segmentCount && (segmentCount == (nextId - prevId)))
|
||||
{
|
||||
segmentCount++; // consecutive series continues
|
||||
if (0 == nack.PackRepairRequest(req))
|
||||
DMSG(0, "NormBlock::AppendRepairRequest() warning: full NACK msg\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
NormRepairRequest::Form nextForm;
|
||||
switch(segmentCount)
|
||||
{
|
||||
case 0:
|
||||
nextForm = NormRepairRequest::INVALID;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
nextForm = NormRepairRequest::ITEMS;
|
||||
break;
|
||||
default:
|
||||
nextForm = NormRepairRequest::RANGES;
|
||||
break;
|
||||
} // end switch(reqCount)
|
||||
if (prevForm != nextForm)
|
||||
{
|
||||
if (NormRepairRequest::INVALID != prevForm)
|
||||
nack.PackRepairRequest(req); // (TBD) error check
|
||||
if (NormRepairRequest::INVALID != nextForm)
|
||||
{
|
||||
nack.AttachRepairRequest(req, segmentSize);
|
||||
req.SetForm(nextForm);
|
||||
req.SetFlag(NormRepairRequest::SEGMENT);
|
||||
if (pendingInfo) req.SetFlag(NormRepairRequest::INFO);
|
||||
}
|
||||
prevForm = nextForm;
|
||||
}
|
||||
if (NormRepairRequest::INVALID != nextForm)
|
||||
DMSG(6, "NormBlock::AppendRepairRequest() SEGMENT request\n");
|
||||
switch (nextForm)
|
||||
{
|
||||
case NormRepairRequest::ITEMS:
|
||||
req.AppendRepairItem(objectId, id, prevId); // (TBD) error check
|
||||
if (2 == reqCount)
|
||||
req.AppendRepairItem(objectId, id, prevId+1); // (TBD) error check
|
||||
break;
|
||||
case NormRepairRequest::RANGES:
|
||||
req.AppendRepairItem(objectId, id, prevId); // (TBD) error check
|
||||
req.AppendRepairItem(objectId, id, prevId+reqCount-1); // (TBD) error check
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
} // end switch(nextForm)
|
||||
prevId = nextId;
|
||||
if (nextId < lastId)
|
||||
segmentCount = 1;
|
||||
else
|
||||
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()
|
||||
|
||||
|
|
|
|||
|
|
@ -19,13 +19,15 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
|
|||
: session_mgr(sessionMgr), notify_pending(false),
|
||||
tx_socket(ProtoSocket::UDP), rx_socket(ProtoSocket::UDP),
|
||||
local_node_id(localNodeId),
|
||||
ttl(DEFAULT_TTL), tx_rate(DEFAULT_TRANSMIT_RATE/8.0),
|
||||
ttl(DEFAULT_TTL), loopback(false),
|
||||
tx_rate(DEFAULT_TRANSMIT_RATE/8.0),
|
||||
backoff_factor(DEFAULT_BACKOFF_FACTOR), is_server(false), session_id(0),
|
||||
ndata(DEFAULT_NDATA), nparity(DEFAULT_NPARITY), auto_parity(0), extra_parity(0),
|
||||
next_tx_object_id(0), tx_cache_count_min(8), tx_cache_count_max(256),
|
||||
tx_cache_size_max((UINT32)20*1024*1024),
|
||||
flush_count(NORM_ROBUST_FACTOR+1),
|
||||
posted_tx_queue_empty(false), advertise_repairs(false),
|
||||
posted_tx_queue_empty(false),
|
||||
acking_node_count(0), watermark_pending(false), advertise_repairs(false),
|
||||
suppress_nonconfirmed(false), suppress_rate(-1.0), suppress_rtt(-1.0),
|
||||
probe_proactive(true), probe_pending(false), probe_reset(false),
|
||||
grtt_interval(0.5),
|
||||
|
|
@ -36,6 +38,8 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
|
|||
grtt_response(false), grtt_current_peak(0.0), grtt_age(0.0),
|
||||
cc_enable(false), cc_sequence(0), cc_slow_start(true),
|
||||
is_client(false), unicast_nacks(false), client_silent(false),
|
||||
default_repair_boundary(NormServerNode::BLOCK_BOUNDARY),
|
||||
default_nacking_mode(NormObject::NACK_NORMAL),
|
||||
trace(false), tx_loss_rate(0.0), rx_loss_rate(0.0),
|
||||
next(NULL)
|
||||
{
|
||||
|
|
@ -73,7 +77,7 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
|
|||
// (It may be used to trigger transmission of report messages
|
||||
// in the future for debugging, etc
|
||||
report_timer.SetListener(this, &NormSession::OnReportTimeout);
|
||||
report_timer.SetInterval(60.0);
|
||||
report_timer.SetInterval(10.0);
|
||||
report_timer.SetRepeat(-1);
|
||||
}
|
||||
|
||||
|
|
@ -86,6 +90,7 @@ NormSession::~NormSession()
|
|||
bool NormSession::Open(const char* interfaceName)
|
||||
{
|
||||
ASSERT(address.IsValid());
|
||||
// (TBD) support single socket option
|
||||
if (!tx_socket.IsOpen())
|
||||
{
|
||||
if (!tx_socket.Open())
|
||||
|
|
@ -118,6 +123,12 @@ bool NormSession::Open(const char* interfaceName)
|
|||
Close();
|
||||
return false;
|
||||
}
|
||||
if (!tx_socket.SetLoopback(loopback))
|
||||
{
|
||||
DMSG(0, "NormSession::Open() tx_socket set loopback error\n");
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
if (interfaceName)
|
||||
{
|
||||
rx_socket.SetMulticastInterface(interfaceName);
|
||||
|
|
@ -160,7 +171,33 @@ void NormSession::Close()
|
|||
} // end NormSession::Close()
|
||||
|
||||
|
||||
bool NormSession::StartServer(unsigned long bufferSpace,
|
||||
void NormSession::SetTxRate(double txRate)
|
||||
{
|
||||
txRate /= 8.0; // convert to bytes/sec
|
||||
if (tx_timer.IsActive())
|
||||
{
|
||||
tx_timer.Deactivate();
|
||||
if (txRate > 0.0)
|
||||
{
|
||||
double adjustInterval = (tx_rate/txRate) * tx_timer.GetTimeRemaining();
|
||||
tx_timer.SetInterval(adjustInterval);
|
||||
ActivateTimer(tx_timer);
|
||||
}
|
||||
tx_rate = txRate;
|
||||
}
|
||||
else if (0.0 == tx_rate)
|
||||
{
|
||||
tx_rate = txRate;
|
||||
tx_timer.SetInterval(0.0);
|
||||
ActivateTimer(tx_timer);
|
||||
}
|
||||
else
|
||||
{
|
||||
tx_rate = txRate;
|
||||
}
|
||||
} // end NormSession::SetTxRate()
|
||||
|
||||
bool NormSession::StartServer(UINT32 bufferSpace,
|
||||
UINT16 segmentSize,
|
||||
UINT16 numData,
|
||||
UINT16 numParity,
|
||||
|
|
@ -284,30 +321,108 @@ void NormSession::Serve()
|
|||
// Only send new data when no other messages are queued for transmission
|
||||
if (!message_queue.IsEmpty()) return;
|
||||
|
||||
NormObject* obj = NULL;
|
||||
// Queue next server message
|
||||
NormObjectId objectId;
|
||||
NormObject* obj = NULL;
|
||||
if (ServerGetFirstPending(objectId))
|
||||
{
|
||||
obj = tx_table.Find(objectId);
|
||||
ASSERT(obj);
|
||||
}
|
||||
|
||||
if (watermark_pending)
|
||||
{
|
||||
// Determine next message (objectId::blockId::segmentId) to be sent
|
||||
NormObject* nextObj;
|
||||
NormObjectId nextObjectId;
|
||||
NormBlockId nextBlockId = 0;
|
||||
NormSegmentId nextSegmentId = 0;
|
||||
if (obj)
|
||||
{
|
||||
// Use current transmit pending object
|
||||
nextObj = obj;
|
||||
nextObjectId = objectId;
|
||||
if (nextObj->IsPending())
|
||||
{
|
||||
if(nextObj->GetFirstPending(nextBlockId))
|
||||
{
|
||||
NormBlock* block = nextObj->FindBlock(nextBlockId);
|
||||
if (block)
|
||||
{
|
||||
#ifdef PROTO_DEBUG
|
||||
ASSERT(block->GetFirstPending(nextSegmentId));
|
||||
#else
|
||||
block->GetFirstPending(nextSegmentId);
|
||||
#endif // if/else PROTO_DEBUG
|
||||
// Adjust so watermark segmentId < block length
|
||||
if (nextSegmentId >= nextObj->GetBlockSize(nextBlockId))
|
||||
nextSegmentId = nextObj->GetBlockSize(nextBlockId) - 1;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!posted_tx_queue_empty)
|
||||
// info only pending; so blockId = segmentId = 0 (as inited)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
posted_tx_queue_empty = true;
|
||||
Notify(NormController::TX_QUEUE_EMPTY,
|
||||
(NormServerNode*)NULL,
|
||||
(NormObject*)NULL);
|
||||
// (TBD) Was session deleted?
|
||||
// Must be an active, but non-pending stream object
|
||||
nextBlockId = static_cast<NormStreamObject*>(nextObj)->GetNextBlockId();
|
||||
nextSegmentId = static_cast<NormStreamObject*>(nextObj)->GetNextSegmentId();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing transmit pending, check for repair pending object
|
||||
NormObjectTable::Iterator iterator(tx_table);
|
||||
while ((nextObj = iterator.GetNextObject()))
|
||||
if (nextObj->IsRepairPending()) break;
|
||||
if (ServerGetFirstRepairPending(nextObjectId))
|
||||
{
|
||||
if (nextObj && (nextObj->GetId() < nextObjectId))
|
||||
{
|
||||
nextObjectId = nextObj->GetId();
|
||||
}
|
||||
else
|
||||
{
|
||||
nextObj = tx_table.Find(nextObjectId);
|
||||
ASSERT(nextObj);
|
||||
}
|
||||
}
|
||||
if (nextObj)
|
||||
{
|
||||
#ifdef PROTO_DEBUG
|
||||
ASSERT(nextObj->FindRepairIndex(nextBlockId, nextSegmentId));
|
||||
#else
|
||||
nextObj->FindRepairIndex(nextBlockId, nextSegmentId);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
nextObjectId = next_tx_object_id;
|
||||
}
|
||||
}
|
||||
if ((nextObjectId > watermark_object_id) ||
|
||||
((nextObjectId == watermark_object_id) &&
|
||||
((nextBlockId > watermark_block_id) ||
|
||||
(((nextBlockId == watermark_block_id) &&
|
||||
(nextSegmentId > watermark_segment_id))))))
|
||||
{
|
||||
if (ServerQueueWatermarkFlush())
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// (TBD) optionally return here to have ack collection temporarily suspend data transmission
|
||||
return;
|
||||
}
|
||||
}
|
||||
} // end if (watermark_pending)
|
||||
|
||||
if (obj)
|
||||
{
|
||||
|
||||
NormObjectMsg* msg = (NormObjectMsg*)GetMessageFromPool();
|
||||
if (msg)
|
||||
{
|
||||
|
|
@ -319,7 +434,7 @@ void NormSession::Serve()
|
|||
msg->SetGroupSize(gsize_quantized);
|
||||
QueueMessage(msg);
|
||||
flush_count = 0;
|
||||
if (flush_timer.IsActive()) flush_timer.Deactivate();
|
||||
//if (flush_timer.IsActive()) flush_timer.Deactivate();
|
||||
if (!obj->IsPending())
|
||||
{
|
||||
if (obj->IsStream())
|
||||
|
|
@ -333,25 +448,35 @@ void NormSession::Serve()
|
|||
ReturnMessageToPool(msg);
|
||||
if (obj->IsStream())
|
||||
{
|
||||
NormStreamObject* stream = (NormStreamObject*)obj;
|
||||
if (stream->IsFlushPending() &&
|
||||
(flush_count < NORM_ROBUST_FACTOR))
|
||||
NormStreamObject* stream = static_cast<NormStreamObject*>(obj);
|
||||
if (stream->IsFlushPending())
|
||||
{
|
||||
// Queue flush message
|
||||
if (!flush_timer.IsActive())
|
||||
if (flush_count < NORM_ROBUST_FACTOR)
|
||||
{
|
||||
ServerQueueFlush();
|
||||
}
|
||||
else if (NORM_ROBUST_FACTOR == flush_count)
|
||||
{
|
||||
DMSG(6, "NormSession::Serve() node>%lu server flush complete ...\n",
|
||||
LocalNodeId());
|
||||
flush_count++;
|
||||
}
|
||||
}
|
||||
if (!posted_tx_queue_empty)
|
||||
{
|
||||
posted_tx_queue_empty = true;
|
||||
Notify(NormController::TX_QUEUE_EMPTY, (NormServerNode*)NULL, obj);
|
||||
// (TBD) Was session deleted?
|
||||
//Serve();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormSession::Serve() pending non-stream obj, no message?.\n");
|
||||
//ASSERT(0);
|
||||
ASSERT(repair_timer.IsActive());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -361,7 +486,20 @@ void NormSession::Serve()
|
|||
LocalNodeId());
|
||||
}
|
||||
}
|
||||
else if (flush_count < NORM_ROBUST_FACTOR)
|
||||
else
|
||||
{
|
||||
// No pending objects or positive acknowledgement request
|
||||
if (!posted_tx_queue_empty)
|
||||
{
|
||||
posted_tx_queue_empty = true;
|
||||
Notify(NormController::TX_QUEUE_EMPTY,
|
||||
(NormServerNode*)NULL,
|
||||
(NormObject*)NULL);
|
||||
// (TBD) Was session deleted?
|
||||
//Serve();
|
||||
return;
|
||||
}
|
||||
if (flush_count < NORM_ROBUST_FACTOR)
|
||||
{
|
||||
// Queue flush message
|
||||
ServerQueueFlush();
|
||||
|
|
@ -372,8 +510,123 @@ void NormSession::Serve()
|
|||
LocalNodeId());
|
||||
flush_count++;
|
||||
}
|
||||
}
|
||||
} // end NormSession::Serve()
|
||||
|
||||
void NormSession::ServerSetWatermark(NormObjectId objectId,
|
||||
NormBlockId blockId,
|
||||
NormSegmentId segmentId)
|
||||
{
|
||||
TRACE("NormSession::ServerSetWatermark(%hu:%lu:%hu) ...\n",
|
||||
(UINT16)objectId, (UINT32)blockId, (UINT16)segmentId);
|
||||
watermark_pending = true;
|
||||
watermark_object_id = objectId;
|
||||
watermark_block_id = blockId;
|
||||
watermark_segment_id = segmentId;
|
||||
acks_collected = 0;
|
||||
// Reset acking_node_list
|
||||
NormNodeTreeIterator iterator(acking_node_tree);
|
||||
NormNode* next;
|
||||
while ((next = iterator.GetNextNode()))
|
||||
static_cast<NormAckingNode*>(next)->Reset(NORM_ROBUST_FACTOR);
|
||||
PromptServer();
|
||||
} // end Norm::ServerSetWatermark()
|
||||
|
||||
bool NormSession::ServerAddAckingNode(NormNodeId nodeId)
|
||||
{
|
||||
NormAckingNode* theNode = static_cast<NormAckingNode*>(acking_node_tree.FindNodeById(nodeId));
|
||||
if (NULL == theNode)
|
||||
{
|
||||
theNode = new NormAckingNode(*this, nodeId);
|
||||
if (NULL != theNode)
|
||||
{
|
||||
theNode->Reset(NORM_ROBUST_FACTOR);
|
||||
acking_node_tree.AttachNode(theNode);
|
||||
acking_node_count++;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormSession::AddAckingNode() new NormAckingNode error: %s\n", GetErrorString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormSession::AddAckingNode() warning: node already in list!?\n");
|
||||
}
|
||||
return true;
|
||||
} // end NormSession::AddAckingNode(NormNodeId nodeId)
|
||||
|
||||
void NormSession::ServerRemoveAckingNode(NormNodeId nodeId)
|
||||
{
|
||||
NormAckingNode* theNode = static_cast<NormAckingNode*>(acking_node_tree.FindNodeById(nodeId));
|
||||
if (theNode)
|
||||
{
|
||||
if (watermark_pending && theNode->AckReceived())
|
||||
acks_collected--;
|
||||
acking_node_tree.DeleteNode(theNode);
|
||||
acking_node_count--;
|
||||
}
|
||||
} // end NormSession::RemoveAckingNode()
|
||||
|
||||
bool NormSession::ServerQueueWatermarkFlush()
|
||||
{
|
||||
if (flush_timer.IsActive()) return false;
|
||||
NormCmdFlushMsg* flush = static_cast<NormCmdFlushMsg*>(GetMessageFromPool());
|
||||
if (flush)
|
||||
{
|
||||
flush->Init();
|
||||
flush->SetDestination(address);
|
||||
flush->SetGrtt(grtt_quantized);
|
||||
flush->SetBackoffFactor((unsigned char)backoff_factor);
|
||||
flush->SetGroupSize(gsize_quantized);
|
||||
flush->SetObjectId(watermark_object_id);
|
||||
flush->SetFecBlockId(watermark_block_id);
|
||||
flush->SetFecSymbolId(watermark_segment_id);
|
||||
NormNodeTreeIterator iterator(acking_node_tree);
|
||||
NormAckingNode* next;
|
||||
watermark_pending = false;
|
||||
while ((next = static_cast<NormAckingNode*>(iterator.GetNextNode())))
|
||||
{
|
||||
if (next->IsPending())
|
||||
{
|
||||
// Add node to list
|
||||
if (flush->AppendAckingNode(next->GetId(), segment_size))
|
||||
{
|
||||
next->DecrementReqCount();
|
||||
watermark_pending = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(8, "NormSession::ServeQueueWatermarkFlush() full cmd ...\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (watermark_pending)
|
||||
{
|
||||
flush_count++;
|
||||
QueueMessage(flush);
|
||||
DMSG(8, "NormSession::ServeQueueWatermarkFlush() node>%lu cmd queued ...\n",
|
||||
LocalNodeId());
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(4, "NormSession::ServeQueueWatermarkFlush() node>%lu watermark ack finished incomplete\n");
|
||||
// (TBD) notify app
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormSession::ServerQueueWatermarkRequest() node>%lu message_pool exhausted! (couldn't req)\n",
|
||||
LocalNodeId());
|
||||
}
|
||||
flush_timer.SetInterval(2*grtt_advertised);
|
||||
ActivateTimer(flush_timer);
|
||||
return true;
|
||||
} // end NormSession::ServerQueueWatermarkFlush()
|
||||
|
||||
void NormSession::ServerQueueFlush()
|
||||
{
|
||||
// (TBD) Deal with EOT or pre-queued squelch on squelch case
|
||||
|
|
@ -400,6 +653,7 @@ void NormSession::ServerQueueFlush()
|
|||
}
|
||||
else
|
||||
{
|
||||
// Why did I do this? - Brian
|
||||
// (TBD) send NORM_CMD(EOT) instead?
|
||||
if (ServerQueueSquelch(next_tx_object_id))
|
||||
{
|
||||
|
|
@ -424,22 +678,22 @@ void NormSession::ServerQueueFlush()
|
|||
flush->SetFecSymbolId(segmentId);
|
||||
QueueMessage(flush);
|
||||
flush_count++;
|
||||
flush_timer.SetInterval(2*grtt_advertised);
|
||||
ActivateTimer(flush_timer);
|
||||
DMSG(8, "NormSession::ServerQueueFlush() node>%lu, flush queued (flush_count:%u)...\n",
|
||||
DMSG(0, "NormSession::ServerQueueFlush() node>%lu, flush queued (flush_count:%u)...\n",
|
||||
LocalNodeId(), flush_count);
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, " NormSession::ServerQueueFlush() node>%lu message_pool exhausted! (couldn't flush)\n",
|
||||
DMSG(0, "NormSession::ServerQueueFlush() node>%lu message_pool exhausted! (couldn't flush)\n",
|
||||
LocalNodeId());
|
||||
}
|
||||
flush_timer.SetInterval(2*grtt_advertised);
|
||||
ActivateTimer(flush_timer);
|
||||
} // end NormSession::ServerQueueFlush()
|
||||
|
||||
bool NormSession::OnFlushTimeout(ProtoTimer& /*theTimer*/)
|
||||
{
|
||||
flush_timer.Deactivate();
|
||||
Serve(); // (TBD) Change this to PromptServer() ??
|
||||
PromptServer();//Serve(); // (TBD) Change this to PromptServer() ??
|
||||
return false;
|
||||
} // NormSession::OnFlushTimeout()
|
||||
|
||||
|
|
@ -459,12 +713,12 @@ void NormSession::QueueMessage(NormMsg* msg)
|
|||
}
|
||||
lastTime = currentTime;
|
||||
*/
|
||||
if (!tx_timer.IsActive())
|
||||
if (!tx_timer.IsActive() && (tx_rate > 0.0))
|
||||
{
|
||||
tx_timer.SetInterval(0.0);
|
||||
ActivateTimer(tx_timer);
|
||||
}
|
||||
message_queue.Append(msg);
|
||||
if (msg) message_queue.Append(msg);
|
||||
} // end NormSesssion::QueueMessage(NormMsg& msg)
|
||||
|
||||
|
||||
|
|
@ -478,7 +732,7 @@ NormFileObject* NormSession::QueueTxFile(const char* path,
|
|||
DMSG(0, "NormSession::QueueTxFile() Error: server is closed\n");
|
||||
return NULL;
|
||||
}
|
||||
NormFileObject* file = new NormFileObject(this, (NormServerNode*)NULL, next_tx_object_id);
|
||||
NormFileObject* file = new NormFileObject(*this, (NormServerNode*)NULL, next_tx_object_id);
|
||||
if (!file)
|
||||
{
|
||||
DMSG(0, "NormSession::QueueTxFile() new file object error: %s\n",
|
||||
|
|
@ -491,7 +745,7 @@ NormFileObject* NormSession::QueueTxFile(const char* path,
|
|||
delete file;
|
||||
return NULL;
|
||||
}
|
||||
if (QueueTxObject(file, false))
|
||||
if (QueueTxObject(file))
|
||||
{
|
||||
return file;
|
||||
}
|
||||
|
|
@ -503,6 +757,42 @@ NormFileObject* NormSession::QueueTxFile(const char* path,
|
|||
}
|
||||
} // end NormSession::QueueTxFile()
|
||||
|
||||
NormDataObject* NormSession::QueueTxData(const char* dataPtr,
|
||||
UINT32 dataLen,
|
||||
const char* infoPtr,
|
||||
UINT16 infoLen)
|
||||
{
|
||||
if (!IsServer())
|
||||
{
|
||||
DMSG(0, "NormSession::QueueTxData() Error: server is closed\n");
|
||||
return NULL;
|
||||
}
|
||||
NormDataObject* obj = new NormDataObject(*this, (NormServerNode*)NULL, next_tx_object_id);
|
||||
if (!obj)
|
||||
{
|
||||
DMSG(0, "NormSession::QueueTxData() new data object error: %s\n",
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
if (!obj->Open((char*)dataPtr, dataLen, infoPtr, infoLen))
|
||||
{
|
||||
DMSG(0, "NormSession::QueueTxData() object open error\n");
|
||||
delete obj;
|
||||
return NULL;
|
||||
}
|
||||
if (QueueTxObject(obj))
|
||||
{
|
||||
return obj;
|
||||
}
|
||||
else
|
||||
{
|
||||
obj->Close();
|
||||
delete obj;
|
||||
return NULL;
|
||||
}
|
||||
} // end NormSession::QueueTxData()
|
||||
|
||||
|
||||
NormStreamObject* NormSession::QueueTxStream(UINT32 bufferSize,
|
||||
const char* infoPtr,
|
||||
UINT16 infoLen)
|
||||
|
|
@ -512,7 +802,7 @@ NormStreamObject* NormSession::QueueTxStream(UINT32 bufferSize,
|
|||
DMSG(0, "NormSession::QueueTxStream() Error: server is closed\n");
|
||||
return NULL;
|
||||
}
|
||||
NormStreamObject* stream = new NormStreamObject(this, (NormServerNode*)NULL, next_tx_object_id);
|
||||
NormStreamObject* stream = new NormStreamObject(*this, (NormServerNode*)NULL, next_tx_object_id);
|
||||
if (!stream)
|
||||
{
|
||||
DMSG(0, "NormSession::QueueTxStream() new stream object error: %s\n",
|
||||
|
|
@ -525,7 +815,7 @@ NormStreamObject* NormSession::QueueTxStream(UINT32 bufferSize,
|
|||
delete stream;
|
||||
return NULL;
|
||||
}
|
||||
if (QueueTxObject(stream, true))
|
||||
if (QueueTxObject(stream))
|
||||
{
|
||||
// (???: stream has nothing pending until user writes to it???)
|
||||
//stream->Reset();
|
||||
|
|
@ -547,7 +837,7 @@ NormSimObject* NormSession::QueueTxSim(unsigned long objectSize)
|
|||
DMSG(0, "NormSession::QueueTxSim() Error: server is closed\n");
|
||||
return NULL;
|
||||
}
|
||||
NormSimObject* simObject = new NormSimObject(this, NULL, next_tx_object_id);
|
||||
NormSimObject* simObject = new NormSimObject(*this, NULL, next_tx_object_id);
|
||||
if (!simObject)
|
||||
{
|
||||
DMSG(0, "NormSession::QueueTxSim() new sim object error: %s\n",
|
||||
|
|
@ -561,7 +851,7 @@ NormSimObject* NormSession::QueueTxSim(unsigned long objectSize)
|
|||
delete simObject;
|
||||
return NULL;
|
||||
}
|
||||
if (QueueTxObject(simObject, false))
|
||||
if (QueueTxObject(simObject))
|
||||
{
|
||||
return simObject;
|
||||
}
|
||||
|
|
@ -573,7 +863,7 @@ NormSimObject* NormSession::QueueTxSim(unsigned long objectSize)
|
|||
} // end NormSession::QueueTxSim()
|
||||
#endif // SIMULATE
|
||||
|
||||
bool NormSession::QueueTxObject(NormObject* obj, bool touchServer)
|
||||
bool NormSession::QueueTxObject(NormObject* obj)
|
||||
{
|
||||
if (!IsServer())
|
||||
{
|
||||
|
|
@ -599,9 +889,8 @@ bool NormSession::QueueTxObject(NormObject* obj, bool touchServer)
|
|||
}
|
||||
else
|
||||
{
|
||||
tx_table.Remove(oldest);
|
||||
oldest->Close();
|
||||
delete oldest;
|
||||
Notify(NormController::TX_OBJECT_PURGED, (NormServerNode*)NULL, oldest);
|
||||
DeleteTxObject(oldest);
|
||||
}
|
||||
count = tx_table.Count();
|
||||
}
|
||||
|
|
@ -613,6 +902,7 @@ bool NormSession::QueueTxObject(NormObject* obj, bool touchServer)
|
|||
ASSERT(0);
|
||||
return false;
|
||||
}
|
||||
obj->Retain();
|
||||
tx_pending_mask.Set(obj->GetId());
|
||||
ASSERT(tx_pending_mask.Test(obj->GetId()));
|
||||
next_tx_object_id++;
|
||||
|
|
@ -624,13 +914,14 @@ bool NormSession::QueueTxObject(NormObject* obj, bool touchServer)
|
|||
|
||||
void NormSession::DeleteTxObject(NormObject* obj)
|
||||
{
|
||||
if (tx_table.Remove(obj))
|
||||
{
|
||||
NormObjectId objectId = obj->GetId();
|
||||
ASSERT(obj == tx_table.Find(objectId));
|
||||
tx_table.Remove(obj);
|
||||
obj->Close();
|
||||
tx_pending_mask.Unset(objectId);
|
||||
tx_repair_mask.Unset(objectId);
|
||||
delete obj;
|
||||
}
|
||||
obj->Close();
|
||||
obj->Release();
|
||||
} // end NormSession::DeleteTxObject()
|
||||
|
||||
NormBlock* NormSession::ServerGetFreeBlock(NormObjectId objectId,
|
||||
|
|
@ -919,11 +1210,7 @@ void NormSession::HandleReceiveMessage(NormMsg& msg, bool wasUnicast)
|
|||
{
|
||||
// for suppression of unicast nack feedback
|
||||
advertise_repairs = true;
|
||||
if (!tx_timer.IsActive())
|
||||
{
|
||||
tx_timer.SetInterval(0.0);
|
||||
ActivateTimer(tx_timer);
|
||||
}
|
||||
QueueMessage(NULL); // to prompt transmit timeout
|
||||
}
|
||||
}
|
||||
if (IsClient()) ClientHandleNackMessage((NormNackMsg&)msg);
|
||||
|
|
@ -949,23 +1236,48 @@ void NormSession::ClientHandleObjectMessage(const struct timeval& currentTime,
|
|||
// Do common updates for servers we already know.
|
||||
NormNodeId sourceId = msg.GetSourceId();
|
||||
NormServerNode* theServer = (NormServerNode*)server_tree.FindNodeById(sourceId);
|
||||
if (!theServer)
|
||||
if (theServer)
|
||||
{
|
||||
if ((theServer = new NormServerNode(this, msg.GetSourceId())))
|
||||
if (msg.GetSessionId() != theServer->GetSessionId())
|
||||
{
|
||||
DMSG(2, "NormSession::ClientHandleObjectMessage() node>%lu server>%lu sessionId change - resyncing.\n",
|
||||
LocalNodeId(), theServer->GetId());
|
||||
theServer->Close();
|
||||
if (!theServer->Open(msg.GetSessionId()))
|
||||
{
|
||||
DMSG(0, "NormSession::ClientHandleObjectMessage() node>%lu error re-opening NormServerNode\n");
|
||||
// (TBD) notify application of error
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((theServer = new NormServerNode(*this, msg.GetSourceId())))
|
||||
{
|
||||
if (theServer->Open(msg.GetSessionId()))
|
||||
{
|
||||
server_tree.AttachNode(theServer);
|
||||
theServer->Retain();
|
||||
DMSG(4, "NormSession::ClientHandleObjectMessage() node>%lu new remote server:%lu ...\n",
|
||||
LocalNodeId(), msg.GetSourceId());
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormSession::ClientHandleObjectMessage() new server node error: %s\n",
|
||||
DMSG(0, "NormSession::ClientHandleObjectMessage() node>%lu error opening NormServerNode\n");
|
||||
// (TBD) notify application of error
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormSession::ClientHandleObjectMessage() new NormServerNode error: %s\n",
|
||||
strerror(errno));
|
||||
// (TBD) notify application of error
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (theServer->IsOpen()) theServer->Activate();
|
||||
theServer->Activate();
|
||||
theServer->UpdateLossEstimate(currentTime, msg.GetSequence());
|
||||
theServer->SetAddress(msg.GetSource());
|
||||
theServer->IncrementRecvTotal(msg.GetLength()); // for statistics only (TBD) #ifdef NORM_DEBUG
|
||||
|
|
@ -979,26 +1291,50 @@ void NormSession::ClientHandleCommand(const struct timeval& currentTime,
|
|||
// Do common updates for servers we already know.
|
||||
NormNodeId sourceId = cmd.GetSourceId();
|
||||
NormServerNode* theServer = (NormServerNode*)server_tree.FindNodeById(sourceId);
|
||||
if (!theServer)
|
||||
if (theServer)
|
||||
{
|
||||
if (cmd.GetSessionId() != theServer->GetSessionId())
|
||||
{
|
||||
DMSG(2, "NormSession::ClientHandleCommand() node>%lu server>%lu sessionId change - resyncing.\n",
|
||||
LocalNodeId(), theServer->GetId());
|
||||
theServer->Close();
|
||||
if (!theServer->Open(cmd.GetSessionId()))
|
||||
{
|
||||
DMSG(0, "NormSession::ClientHandleCommand() node>%lu error re-opening NormServerNode\n");
|
||||
// (TBD) notify application of error
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//DMSG(0, "NormSession::ClientHandleCommand() node>%lu recvd command from unknown server ...\n",
|
||||
// LocalNodeId());
|
||||
if ((theServer = new NormServerNode(this, cmd.GetSourceId())))
|
||||
if ((theServer = new NormServerNode(*this, cmd.GetSourceId())))
|
||||
{
|
||||
if (theServer->Open(cmd.GetSessionId()))
|
||||
{
|
||||
|
||||
server_tree.AttachNode(theServer);
|
||||
theServer->Retain();
|
||||
DMSG(4, "NormSession::ClientHandleCommand() node>%lu new remote server:%lu ...\n",
|
||||
LocalNodeId(), cmd.GetSourceId());
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormSession::ClientHandleCommand() new server node error: %s\n",
|
||||
DMSG(0, "NormSession::ClientHandleCommand() node>%lu error opening NormServerNode\n");
|
||||
// (TBD) notify application of error
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormSession::ClientHandleCommand() new NormServerNode error: %s\n",
|
||||
strerror(errno));
|
||||
// (TBD) notify application of error
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (theServer->IsOpen()) theServer->Activate();
|
||||
theServer->Activate();
|
||||
theServer->UpdateLossEstimate(currentTime, cmd.GetSequence());
|
||||
theServer->SetAddress(cmd.GetSource());
|
||||
theServer->IncrementRecvTotal(cmd.GetLength()); // for statistics only (TBD) #ifdef NORM_DEBUG
|
||||
|
|
@ -1159,7 +1495,7 @@ void NormSession::ServerHandleCCFeedback(NormNodeId nodeId,
|
|||
// There was no active CLR
|
||||
if (!next)
|
||||
{
|
||||
if ((next = new NormCCNode(this, nodeId)))
|
||||
if ((next = new NormCCNode(*this, nodeId)))
|
||||
{
|
||||
cc_node_list.Append(next);
|
||||
}
|
||||
|
|
@ -1186,7 +1522,7 @@ void NormSession::ServerHandleCCFeedback(NormNodeId nodeId,
|
|||
NormCCNode* candidate = NULL;
|
||||
if (cc_node_list.GetCount() < 5)
|
||||
{
|
||||
if ((candidate = new NormCCNode(this, nodeId)))
|
||||
if ((candidate = new NormCCNode(*this, nodeId)))
|
||||
{
|
||||
cc_node_list.Append(candidate);
|
||||
}
|
||||
|
|
@ -1288,11 +1624,7 @@ void NormSession::ServerHandleAckMessage(const struct timeval& currentTime, cons
|
|||
{
|
||||
// for suppression of unicast feedback
|
||||
advertise_repairs = true;
|
||||
if (!tx_timer.IsActive())
|
||||
{
|
||||
tx_timer.SetInterval(0.0);
|
||||
ActivateTimer(tx_timer);
|
||||
}
|
||||
QueueMessage(NULL);
|
||||
}
|
||||
|
||||
switch (ack.GetAckType())
|
||||
|
|
@ -1301,8 +1633,51 @@ void NormSession::ServerHandleAckMessage(const struct timeval& currentTime, cons
|
|||
// Everything is in the ACK header for this one
|
||||
break;
|
||||
|
||||
// (TBD) Handle other acknowledgement types
|
||||
case NormAck::FLUSH:
|
||||
if (watermark_pending)
|
||||
{
|
||||
NormAckingNode* acker =
|
||||
static_cast<NormAckingNode*>(acking_node_tree.FindNodeById(ack.GetSourceId()));
|
||||
if (acker)
|
||||
{
|
||||
if (!acker->AckReceived())
|
||||
{
|
||||
const NormAckFlushMsg& flushAck = static_cast<const NormAckFlushMsg&>(ack);
|
||||
if ((watermark_object_id == flushAck.GetObjectId()) &&
|
||||
(watermark_block_id == flushAck.GetFecBlockId()) &&
|
||||
(watermark_segment_id == flushAck.GetFecSymbolId()))
|
||||
{
|
||||
acker->MarkAckReceived();
|
||||
acks_collected++;
|
||||
if (acks_collected >= acking_node_count)
|
||||
{
|
||||
watermark_pending = false;
|
||||
DMSG(4, "NormSession::ServerHandleAckMessage() watermark acknowledgement complete\n");
|
||||
// (TBD) notify app
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormSession::ServerHandleAckMessage() received wrong watermark ACK?!\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormSession::ServerHandleAckMessage() received redundant watermark ACK?!\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormSession::ServerHandleAckMessage() received watermark ACK from unknown acker?!\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormSession::ServerHandleAckMessage() received unsolicited watermark ACK?!\n");
|
||||
}
|
||||
break;
|
||||
|
||||
// (TBD) Handle other acknowledgement types
|
||||
default:
|
||||
DMSG(0, "NormSession::ServerHandleAckMessage() node>%lu received "
|
||||
"unsupported ack type:%d\n", LocalNodeId(), ack.GetAckType());
|
||||
|
|
@ -1357,15 +1732,19 @@ void NormSession::ServerHandleNackMessage(const struct timeval& currentTime, Nor
|
|||
if (ServerGetFirstPending(txObjectIndex))
|
||||
{
|
||||
NormObject* obj = tx_table.Find(txObjectIndex);
|
||||
ASSERT(obj && obj->IsPending());
|
||||
ASSERT(obj);
|
||||
if (obj->IsPendingInfo())
|
||||
{
|
||||
txBlockIndex = 0;
|
||||
}
|
||||
else if (obj->GetFirstPending(txBlockIndex))
|
||||
{
|
||||
txBlockIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
obj->GetFirstPending(txBlockIndex);
|
||||
txBlockIndex++;
|
||||
txObjectIndex = next_tx_object_id;
|
||||
txBlockIndex = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -1583,6 +1962,9 @@ void NormSession::ServerHandleNackMessage(const struct timeval& currentTime, Nor
|
|||
continue;
|
||||
}
|
||||
if (!(block = object->FindBlock(nextBlockId)))
|
||||
{
|
||||
// Is this entire block already tx pending?
|
||||
if (!object->IsPendingSet(nextBlockId))
|
||||
{
|
||||
// Try to recover block including parity calculation
|
||||
if (!(block = object->ServerRecoverBlock(nextBlockId)))
|
||||
|
|
@ -1610,6 +1992,14 @@ void NormSession::ServerHandleNackMessage(const struct timeval& currentTime, Nor
|
|||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Entire block already tx pending, don't recover
|
||||
DMSG(0, "NormSession::ServerHandleNackMessage() node>%lu "
|
||||
"recvd SEGMENT repair request for pending block.\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
freshBlock = false;
|
||||
numErasures = extra_parity;
|
||||
prevBlockId = nextBlockId;
|
||||
|
|
@ -1902,7 +2292,13 @@ bool NormSession::ServerBuildRepairAdv(NormCmdRepairAdvMsg& cmd)
|
|||
if (form != prevForm)
|
||||
{
|
||||
if (NormRepairRequest::INVALID != prevForm)
|
||||
cmd.PackRepairRequest(req); // (TBD) error check;
|
||||
{
|
||||
if (0 == cmd.PackRepairRequest(req))
|
||||
{
|
||||
DMSG(0, "NormSession::ServerBuildRepairAdv() warning: full msg\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
req.SetForm(form);
|
||||
cmd.AttachRepairRequest(req, segment_size);
|
||||
prevForm = form;
|
||||
|
|
@ -1945,8 +2341,8 @@ bool NormSession::ServerBuildRepairAdv(NormCmdRepairAdvMsg& cmd)
|
|||
} // end while (nextObject)
|
||||
if (NormRepairRequest::INVALID != prevForm)
|
||||
{
|
||||
cmd.PackRepairRequest(req); // (TBD) error check;
|
||||
prevForm = NormRepairRequest::INVALID;
|
||||
if (0 == cmd.PackRepairRequest(req))
|
||||
DMSG(0, "NormSession::ServerBuildRepairAdv() warning: full msg\n");
|
||||
}
|
||||
return true;
|
||||
} // end NormSession::ServerBuildRepairAdv()
|
||||
|
|
@ -2011,7 +2407,6 @@ bool NormSession::OnRepairTimeout(ProtoTimer& /*theTimer*/)
|
|||
return true;
|
||||
} // end NormSession::OnRepairTimeout()
|
||||
|
||||
|
||||
// (TBD) Should pass current system time to ProtoTimer timeout handlers
|
||||
// for more efficiency ...
|
||||
bool NormSession::OnTxTimeout(ProtoTimer& /*theTimer*/)
|
||||
|
|
@ -2069,6 +2464,8 @@ bool NormSession::OnTxTimeout(ProtoTimer& /*theTimer*/)
|
|||
advertise_repairs = false;
|
||||
else
|
||||
ReturnMessageToPool(msg);
|
||||
// Pre-serve to allow pre-prompt for empty tx queue
|
||||
if (message_queue.IsEmpty() && IsServer()) Serve();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -2089,7 +2486,7 @@ bool NormSession::OnTxTimeout(ProtoTimer& /*theTimer*/)
|
|||
// Check that any possible notifications posted in
|
||||
// the previous call to Serve() may have caused a
|
||||
// change in server state making it ready to send
|
||||
if (IsServer()) Serve();
|
||||
//if (IsServer()) Serve();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
|
@ -2100,6 +2497,7 @@ bool NormSession::OnTxTimeout(ProtoTimer& /*theTimer*/)
|
|||
}
|
||||
} // end NormSession::OnTxTimeout()
|
||||
|
||||
|
||||
bool NormSession::SendMessage(NormMsg& msg)
|
||||
{
|
||||
struct timeval currentTime;
|
||||
|
|
@ -2163,7 +2561,7 @@ bool NormSession::SendMessage(NormMsg& msg)
|
|||
msg.SetSourceId(local_node_id);
|
||||
UINT16 msgSize = msg.GetLength();
|
||||
bool result = true;
|
||||
// Drop some tx messages for testing purposes
|
||||
// Possibly drop some tx messages for testing purposes
|
||||
bool drop = (UniformRand(100.0) < tx_loss_rate);
|
||||
if (drop || (clientMsg && client_silent))
|
||||
{
|
||||
|
|
@ -2236,6 +2634,11 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
|
|||
probe_timer.Deactivate();
|
||||
return false;
|
||||
}
|
||||
else if (0.0 == tx_rate)
|
||||
{
|
||||
// Sender paused, just idle probing until transmission is resumed
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2) Update grtt_estimate _if_ sufficient time elapsed.
|
||||
// This new code allows more liberal downward adjustment of
|
||||
|
|
@ -2447,12 +2850,12 @@ bool NormSession::OnReportTimeout(ProtoTimer& /*theTimer*/)
|
|||
struct timeval currentTime;
|
||||
ProtoSystemTime(currentTime);
|
||||
struct tm* ct = gmtime((time_t*)¤tTime.tv_sec);
|
||||
DMSG(2, "Report time>%02d:%02d:%02d.%06lu node>%lu ***************************************\n",
|
||||
DMSG(2, "REPORT time>%02d:%02d:%02d.%06lu node>%lu ***************************************\n",
|
||||
ct->tm_hour, ct->tm_min, ct->tm_sec, currentTime.tv_usec, LocalNodeId());
|
||||
if (IsServer())
|
||||
{
|
||||
DMSG(2, "Local server:\n");
|
||||
DMSG(2, " tx_rate>%9.3lf kbps grtt>%lf\n",
|
||||
DMSG(2, "Local status:\n");
|
||||
DMSG(2, " txRate>%9.3lf kbps grtt>%lf\n",
|
||||
((double)tx_rate)*8.0/1000.0, grtt_advertised);
|
||||
}
|
||||
if (IsClient())
|
||||
|
|
@ -2461,18 +2864,19 @@ bool NormSession::OnReportTimeout(ProtoTimer& /*theTimer*/)
|
|||
NormServerNode* next;
|
||||
while ((next = (NormServerNode*)iterator.GetNextNode()))
|
||||
{
|
||||
DMSG(2, "Remote server>%lu\n", next->GetId());
|
||||
DMSG(2, "Remote sender>%lu\n", next->GetId());
|
||||
double rxRate = 8.0e-03*((double)next->RecvTotal()) / report_timer.GetInterval(); // kbps
|
||||
double rxGoodput = 8.0e-03*((double)next->RecvGoodput()) / report_timer.GetInterval(); // kbps
|
||||
next->ResetRecvStats();
|
||||
DMSG(2, " rx_rate>%9.3lf kbps rx_goodput>%9.3lf kbps\n", rxRate, rxGoodput);
|
||||
DMSG(2, " objects completed>%lu pending>%lu failed:%lu\n",
|
||||
DMSG(2, " rxRate>%9.3lf kbps rx_goodput>%9.3lf kbps\n", rxRate, rxGoodput);
|
||||
DMSG(2, " rxObjects> completed>%lu pending>%lu failed:%lu\n",
|
||||
next->CompletionCount(), next->PendingCount(), next->FailureCount());
|
||||
DMSG(2, " buffer usage> current:%lu peak:%lu (overuns:%lu)\n", next->CurrentBufferUsage(),
|
||||
DMSG(2, " bufferUsage> current>%lu peak>%lu (overuns>%lu)\n", next->CurrentBufferUsage(),
|
||||
next->PeakBufferUsage(),
|
||||
next->BufferOverunCount());
|
||||
DMSG(2, " resyncs>%lu nacks>%lu suppressed>%lu\n", next->ResyncCount(),
|
||||
next->NackCount(), next->SuppressCount());
|
||||
next->NackCount(),
|
||||
next->SuppressCount());
|
||||
|
||||
}
|
||||
} // end if (IsClient())
|
||||
|
|
@ -2506,7 +2910,7 @@ NormSession* NormSessionMgr::NewSession(const char* sessionAddress,
|
|||
UINT16 sessionPort,
|
||||
NormNodeId localNodeId)
|
||||
{
|
||||
if (NORM_NODE_ANY == localNodeId)
|
||||
if ((NORM_NODE_ANY == localNodeId) || (NORM_NODE_NONE == localNodeId))
|
||||
{
|
||||
// Use local ip address to assign default localNodeId
|
||||
ProtoAddress localAddr;
|
||||
|
|
|
|||
|
|
@ -13,11 +13,20 @@ class NormController
|
|||
public:
|
||||
enum Event
|
||||
{
|
||||
EVENT_INVALID = 0,
|
||||
TX_QUEUE_VACANCY,
|
||||
TX_QUEUE_EMPTY,
|
||||
TX_OBJECT_SENT,
|
||||
TX_OBJECT_PURGED,
|
||||
LOCAL_SERVER_CLOSED,
|
||||
REMOTE_SERVER_NEW,
|
||||
REMOTE_SERVER_INACTIVE,
|
||||
REMOTE_SERVER_ACTIVE,
|
||||
RX_OBJECT_NEW,
|
||||
RX_OBJECT_INFO,
|
||||
RX_OBJECT_UPDATE,
|
||||
RX_OBJECT_COMPLETE,
|
||||
RX_OBJECT_COMPLETED,
|
||||
RX_OBJECT_ABORTED
|
||||
};
|
||||
|
||||
virtual void Notify(NormController::Event event,
|
||||
|
|
@ -54,9 +63,10 @@ class NormSessionMgr
|
|||
}
|
||||
|
||||
void ActivateTimer(ProtoTimer& timer) {timer_mgr.ActivateTimer(timer);}
|
||||
ProtoTimerMgr& GetTimerMgr() {return timer_mgr;}
|
||||
ProtoSocket::Notifier& GetSocketNotifier() {return socket_notifier;}
|
||||
ProtoTimerMgr& GetTimerMgr() const {return timer_mgr;}
|
||||
ProtoSocket::Notifier& GetSocketNotifier() const {return socket_notifier;}
|
||||
|
||||
NormController* GetController() const {return controller;}
|
||||
private:
|
||||
ProtoTimerMgr& timer_mgr;
|
||||
ProtoSocket::Notifier& socket_notifier;
|
||||
|
|
@ -86,26 +96,34 @@ class NormSession
|
|||
static const UINT16 DEFAULT_NPARITY;
|
||||
|
||||
// General methods
|
||||
const NormNodeId& LocalNodeId() {return local_node_id;}
|
||||
const NormNodeId& LocalNodeId() const {return local_node_id;}
|
||||
bool Open(const char* interfaceName = NULL);
|
||||
void Close();
|
||||
bool IsOpen() {return (rx_socket.IsOpen() || tx_socket.IsOpen());}
|
||||
const ProtoAddress& Address() {return address;}
|
||||
void SetAddress(const ProtoAddress& addr) {address = addr;}
|
||||
bool SetTTL(UINT8 theTTL)
|
||||
{
|
||||
bool result = tx_socket.IsOpen() ? tx_socket.SetTTL(theTTL) : true;
|
||||
ttl = result ? theTTL : ttl;
|
||||
return result;
|
||||
}
|
||||
bool SetLoopback(bool state)
|
||||
{
|
||||
bool result = tx_socket.IsOpen() ? tx_socket.SetLoopback(state) : true;
|
||||
loopback = result ? state : loopback;
|
||||
return result;
|
||||
}
|
||||
static double CalculateRate(double size, double rtt, double loss);
|
||||
|
||||
NormSessionMgr& GetSessionMgr() {return session_mgr;}
|
||||
|
||||
// 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;}
|
||||
void SetTxRate(double txRate);
|
||||
double BackoffFactor() {return backoff_factor;}
|
||||
void SetBackoffFactor(double value) {backoff_factor = value;}
|
||||
void SetLoopback(bool state)
|
||||
{
|
||||
rx_socket.SetLoopback(state);
|
||||
tx_socket.SetLoopback(state);
|
||||
}
|
||||
bool CongestionControl() {return cc_enable;}
|
||||
void SetCongestionControl(bool state) {cc_enable = state;}
|
||||
|
||||
|
|
@ -130,7 +148,8 @@ class NormSession
|
|||
next_tx_object_id = IsServer() ? next_tx_object_id : baseId;
|
||||
session_id = IsServer() ? session_id : (UINT16)baseId;
|
||||
}
|
||||
bool StartServer(unsigned long bufferSpace,
|
||||
bool IsServer() {return is_server;}
|
||||
bool StartServer(UINT32 bufferSpace,
|
||||
UINT16 segmentSize,
|
||||
UINT16 numData,
|
||||
UINT16 numParity,
|
||||
|
|
@ -142,15 +161,27 @@ class NormSession
|
|||
NormFileObject* QueueTxFile(const char* path,
|
||||
const char* infoPtr = NULL,
|
||||
UINT16 infoLen = 0);
|
||||
NormDataObject* QueueTxData(const char* dataPtr,
|
||||
UINT32 dataLen,
|
||||
const char* infoPtr = NULL,
|
||||
UINT16 infoLen = 0);
|
||||
void DeleteTxObject(NormObject* obj);
|
||||
|
||||
bool IsServer() {return is_server;}
|
||||
UINT16 ServerSegmentSize() {return segment_size;}
|
||||
UINT16 ServerBlockSize() {return ndata;}
|
||||
UINT16 ServerNumParity() {return nparity;}
|
||||
UINT16 ServerAutoParity() {return auto_parity;}
|
||||
// postive ack mgmnt
|
||||
void ServerSetWatermark(NormObjectId objectId,
|
||||
NormBlockId blockId,
|
||||
NormSegmentId segmentId);
|
||||
bool ServerAddAckingNode(NormNodeId nodeId);
|
||||
void ServerRemoveAckingNode(NormNodeId nodeId);
|
||||
|
||||
|
||||
UINT16 ServerSegmentSize() const {return segment_size;}
|
||||
UINT16 ServerBlockSize() const {return ndata;}
|
||||
UINT16 ServerNumParity() const {return nparity;}
|
||||
UINT16 ServerAutoParity() const {return auto_parity;}
|
||||
void ServerSetAutoParity(UINT16 autoParity)
|
||||
{ASSERT(autoParity <= nparity); auto_parity = autoParity;}
|
||||
UINT16 ServerExtraParity() {return extra_parity;}
|
||||
UINT16 ServerExtraParity() const {return extra_parity;}
|
||||
void ServerSetExtraParity(UINT16 extraParity)
|
||||
{extra_parity = extraParity;}
|
||||
|
||||
|
|
@ -161,6 +192,13 @@ class NormSession
|
|||
objectId = (UINT16)index;
|
||||
return result;
|
||||
}
|
||||
bool ServerGetFirstRepairPending(NormObjectId& objectId)
|
||||
{
|
||||
UINT32 index;
|
||||
bool result = tx_repair_mask.GetFirstSet(index);
|
||||
objectId = (UINT16)index;
|
||||
return result;
|
||||
}
|
||||
|
||||
double ServerGrtt() {return grtt_advertised;}
|
||||
void ServerSetGrtt(double grttValue)
|
||||
|
|
@ -192,15 +230,7 @@ class NormSession
|
|||
void ServerPutFreeSegment(char* segment) {segment_pool.Put(segment);}
|
||||
|
||||
|
||||
void PromptServer()
|
||||
{
|
||||
if (!tx_timer.IsActive())
|
||||
{
|
||||
tx_timer.SetInterval(0.0);
|
||||
ActivateTimer(tx_timer);
|
||||
}
|
||||
}
|
||||
|
||||
void PromptServer() {QueueMessage(NULL);}
|
||||
|
||||
void TouchServer()
|
||||
{
|
||||
|
|
@ -213,13 +243,23 @@ class NormSession
|
|||
bool StartClient(unsigned long bufferSpace,
|
||||
const char* interfaceName = NULL);
|
||||
void StopClient();
|
||||
bool IsClient() {return is_client;}
|
||||
unsigned long RemoteServerBufferSize()
|
||||
bool IsClient() const {return is_client;}
|
||||
unsigned long RemoteServerBufferSize() const
|
||||
{return remote_server_buffer_size;}
|
||||
void SetUnicastNacks(bool state) {unicast_nacks = state;}
|
||||
bool UnicastNacks() {return unicast_nacks;}
|
||||
bool UnicastNacks() const {return unicast_nacks;}
|
||||
void ClientSetSilent(bool state) {client_silent = state;}
|
||||
bool ClientIsSilent() {return client_silent;}
|
||||
bool ClientIsSilent() const {return client_silent;}
|
||||
|
||||
NormObject::NackingMode ClientGetDefaultNackingMode() const
|
||||
{return default_nacking_mode;}
|
||||
void ClientSetDefaultNackingMode(NormObject::NackingMode nackingMode)
|
||||
{default_nacking_mode = nackingMode;}
|
||||
|
||||
NormServerNode::RepairBoundary ClientGetDefaultRepairBoundary() const
|
||||
{return default_repair_boundary;}
|
||||
void ClientSetDefaultRepairBoundary(NormServerNode::RepairBoundary repairBoundary)
|
||||
{default_repair_boundary = repairBoundary;}
|
||||
|
||||
// Debug settings
|
||||
void SetTrace(bool state) {trace = state;}
|
||||
|
|
@ -239,13 +279,12 @@ class NormSession
|
|||
~NormSession();
|
||||
|
||||
void Serve();
|
||||
bool QueueTxObject(NormObject* obj, bool touchServer = true);
|
||||
void DeleteTxObject(NormObject* obj);
|
||||
bool QueueTxObject(NormObject* obj);
|
||||
|
||||
|
||||
bool OnTxTimeout(ProtoTimer& theTimer);
|
||||
bool OnRepairTimeout(ProtoTimer& theTimer);
|
||||
bool OnFlushTimeout(ProtoTimer& theTimer);
|
||||
bool OnWatermarkTimeout(ProtoTimer& theTimer);
|
||||
bool OnProbeTimeout(ProtoTimer& theTimer);
|
||||
bool OnReportTimeout(ProtoTimer& theTimer);
|
||||
|
||||
|
|
@ -271,6 +310,7 @@ class NormSession
|
|||
void AdjustRate(bool onResponse);
|
||||
bool ServerQueueSquelch(NormObjectId objectId);
|
||||
void ServerQueueFlush();
|
||||
bool ServerQueueWatermarkFlush();
|
||||
bool ServerBuildRepairAdv(NormCmdRepairAdvMsg& cmd);
|
||||
void ServerUpdateGroupSize();
|
||||
|
||||
|
|
@ -296,6 +336,7 @@ class NormSession
|
|||
NormNodeId local_node_id;
|
||||
ProtoAddress address; // session destination address & port
|
||||
UINT8 ttl; // session multicast ttl
|
||||
bool loopback; // to receive own traffic
|
||||
double tx_rate; // bytes per second
|
||||
double backoff_factor;
|
||||
|
||||
|
|
@ -323,9 +364,15 @@ class NormSession
|
|||
ProtoTimer flush_timer;
|
||||
int flush_count;
|
||||
bool posted_tx_queue_empty;
|
||||
ProtoTimer watermark_timer;
|
||||
int watermark_count;
|
||||
// (TBD) watermark_object_id, watermark_block_id, watermark_symbol_id
|
||||
|
||||
// For postive acknowledgement collection
|
||||
NormNodeTree acking_node_tree;
|
||||
unsigned int acking_node_count;
|
||||
bool watermark_pending;
|
||||
NormObjectId watermark_object_id;
|
||||
NormBlockId watermark_block_id;
|
||||
NormSegmentId watermark_segment_id;
|
||||
unsigned int acks_collected;
|
||||
|
||||
// for unicast nack/cc feedback suppression
|
||||
bool advertise_repairs;
|
||||
|
|
@ -370,6 +417,8 @@ class NormSession
|
|||
unsigned long remote_server_buffer_size;
|
||||
bool unicast_nacks;
|
||||
bool client_silent;
|
||||
NormServerNode::RepairBoundary default_repair_boundary;
|
||||
NormObject::NackingMode default_nacking_mode;
|
||||
|
||||
// Protocol test/debug parameters
|
||||
bool trace;
|
||||
|
|
|
|||
|
|
@ -831,7 +831,7 @@ void NormSimAgent::Notify(NormController::Event event,
|
|||
break;
|
||||
} // end switch (object->GetType())
|
||||
break;
|
||||
case RX_OBJECT_COMPLETE:
|
||||
case RX_OBJECT_COMPLETED:
|
||||
{
|
||||
switch(object->GetType())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,231 @@
|
|||
////////////////////////////////////////////////////
|
||||
// This is a test application for experimenting
|
||||
// with the NORM API implementation during its
|
||||
// development. A better-documented and complete
|
||||
// example of the NORM API usage will be provided
|
||||
// when the NORM API is more complete.
|
||||
|
||||
#include "normApi.h"
|
||||
#include "protokit.h" // for protolib debug, stuff, etc
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef UNIX
|
||||
#include <unistd.h> // for "sleep()"
|
||||
#endif // UNIX
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
printf("normTest starting ...\n");
|
||||
|
||||
SetDebugLevel(4);
|
||||
|
||||
NormInstanceHandle instance = NormCreateInstance();
|
||||
|
||||
#ifdef WIN32
|
||||
const char* cachePath = "C:\\Adamson\\Temp\\cache\\";
|
||||
#else
|
||||
const char* cachePath = "/tmp/";
|
||||
#endif // if/else WIN32/UNIX
|
||||
|
||||
NormSetCacheDirectory(instance, cachePath);
|
||||
|
||||
NormSessionHandle session = NormCreateSession(instance,
|
||||
"224.1.2.3",
|
||||
6003,
|
||||
NORM_NODE_ANY);
|
||||
|
||||
NormSetMessageTrace(session, true);
|
||||
|
||||
NormSetTxLoss(session, 10.0); // 1% packet loss
|
||||
|
||||
NormSetGrttEstimate(session, 0.1);//0.001); // 1 msec initial grtt
|
||||
|
||||
NormSetTransmitRate(session, 1.0e+05); // in bits/second
|
||||
|
||||
NormSetDefaultRepairBoundary(session, NORM_BOUNDARY_BLOCK);
|
||||
|
||||
// Uncomment to receive own traffic
|
||||
NormSetLoopback(session, true);
|
||||
|
||||
// Uncomment this line to participate as a receiver
|
||||
NormStartReceiver(session, 1024*1024);
|
||||
|
||||
// Uncomment the following line to start sender
|
||||
NormStartSender(session, 1024*1024, 1024, 64, 0);
|
||||
|
||||
NormAddAckingNode(session, NormGetLocalNodeId(session));
|
||||
|
||||
NormObjectHandle stream = NORM_OBJECT_INVALID;
|
||||
const char* filePath = "/home/adamson/images/art/giger/giger205.jpg";
|
||||
const char* fileName = "ferrari.jpg";
|
||||
|
||||
// Uncomment this line to send a stream instead of the file
|
||||
stream = NormOpenStream(session, 1024*1024);
|
||||
NormSetStreamFlushMode(stream, NORM_FLUSH_NONE);
|
||||
|
||||
int index = -1; // used to monitor reliable stream reception
|
||||
int sendCount = 0;
|
||||
int sendMax = 200;
|
||||
NormEvent theEvent;
|
||||
while (NormGetNextEvent(instance, &theEvent))
|
||||
{
|
||||
switch (theEvent.type)
|
||||
{
|
||||
case NORM_TX_QUEUE_EMPTY:
|
||||
if (NORM_OBJECT_INVALID != stream)
|
||||
{
|
||||
// Write a message to the "stream"
|
||||
char buffer[1024];
|
||||
sprintf(buffer, "normTest says hello %d ...\n", sendCount++);
|
||||
unsigned int len = strlen(buffer);
|
||||
TRACE("writing to stream ...\n");
|
||||
if (len != NormWriteStream(stream, buffer, len))
|
||||
TRACE("incomplete write:%u\n", len);
|
||||
else
|
||||
{
|
||||
NormFlushStream(stream);
|
||||
NormSetWatermark(session, stream);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NormObjectHandle txFile =
|
||||
NormQueueFile(session,
|
||||
filePath,
|
||||
fileName,
|
||||
strlen(fileName));
|
||||
// Repeatedly queue our file for sending
|
||||
if (NORM_OBJECT_INVALID == txFile)
|
||||
{
|
||||
DMSG(0, "normTest: error queuing file: %s\n", filePath);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE("QUEUED FILE ...\n");
|
||||
NormSetWatermark(session, txFile);
|
||||
}
|
||||
sendCount++;
|
||||
}
|
||||
break;
|
||||
|
||||
case NORM_TX_OBJECT_PURGED:
|
||||
DMSG(3, "normTest: NORM_TX_OBJECT_PURGED event ...\n");
|
||||
break;
|
||||
|
||||
case NORM_RX_OBJECT_NEW:
|
||||
DMSG(3, "normTest: NORM_RX_OBJECT_NEW event ...\n");
|
||||
break;
|
||||
|
||||
case NORM_RX_OBJECT_INFO:
|
||||
// Assume info contains '/' delimited <path/fileName> string
|
||||
if (NORM_OBJECT_FILE == NormGetObjectType(theEvent.object))
|
||||
{
|
||||
NormObjectTransportId id = NormGetObjectTransportId(theEvent.object);
|
||||
if (0 != (id & 0x01))
|
||||
{
|
||||
//NormCancelObject(theEvent.object);
|
||||
//break;
|
||||
}
|
||||
|
||||
char fileName[PATH_MAX];
|
||||
strcpy(fileName, cachePath);
|
||||
int pathLen = strlen(fileName);
|
||||
unsigned short nameLen = PATH_MAX - pathLen;
|
||||
NormGetObjectInfo(theEvent.object, fileName+pathLen, &nameLen);
|
||||
fileName[nameLen + pathLen] = '\0';
|
||||
char* ptr = fileName + 5;
|
||||
while ('\0' != *ptr)
|
||||
{
|
||||
if ('/' == *ptr) *ptr = PROTO_PATH_DELIMITER;
|
||||
ptr++;
|
||||
}
|
||||
if (!NormSetFileName(theEvent.object, fileName))
|
||||
TRACE("normTest: NormSetFileName(%s) error\n", fileName);
|
||||
DMSG(3, "normTest: recv'd info for file: %s\n", fileName);
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case NORM_RX_OBJECT_UPDATE:
|
||||
{
|
||||
//TRACE("normTest: NORM_RX_OBJECT_UPDATE event ...\n");
|
||||
if (NORM_OBJECT_STREAM != NormGetObjectType(theEvent.object))
|
||||
break;
|
||||
char buffer[1024];
|
||||
unsigned int len = 1023;
|
||||
do
|
||||
{
|
||||
len = 1023;
|
||||
if (NormReadStream(theEvent.object, buffer, &len))
|
||||
{
|
||||
buffer[len] = '\0';
|
||||
if (len)
|
||||
{
|
||||
TRACE("normTest: recvd(%u):\n\"%s\"\n", len, buffer);
|
||||
// This while() loop is cheesy test, looking for broken stream
|
||||
//
|
||||
char* ptr = buffer;
|
||||
while ((ptr = strstr(ptr, "hello")))
|
||||
{
|
||||
int value;
|
||||
if (1 == sscanf(ptr, "hello %d", &value))
|
||||
{
|
||||
if (index >= 0)
|
||||
{
|
||||
if (1 != (value - index))
|
||||
TRACE("WARNING! possible break? value:%d index:%d\n",
|
||||
value, index);
|
||||
}
|
||||
index = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE("couldn't find index\n");
|
||||
}
|
||||
ptr += 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE("normTest: error reading stream\n");
|
||||
break;
|
||||
}
|
||||
} while (0 != len);
|
||||
break;
|
||||
}
|
||||
|
||||
case NORM_RX_OBJECT_COMPLETED:
|
||||
TRACE("normTest: NORM_RX_OBJECT_COMPLETED event ...\n");
|
||||
break;
|
||||
|
||||
case NORM_RX_OBJECT_ABORTED:
|
||||
TRACE("normTest: NORM_RX_OBJECT_ABORTED event ...\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
TRACE("Got event type: %d\n", theEvent.type);
|
||||
} // end switch(theEvent.type)
|
||||
|
||||
// Break after sending "sendMax" messages or files
|
||||
if (sendCount >= sendMax) break;
|
||||
|
||||
} // end while (NormGetNextEvent())
|
||||
|
||||
fprintf(stderr, "normTest shutting down in 30 sec ...\n");
|
||||
#ifdef WIN32
|
||||
Sleep(30000);
|
||||
#else
|
||||
sleep(30); // allows time for cleanup if we're sending to someone else
|
||||
#endif // if/else WIN32/UNIX
|
||||
|
||||
NormCloseStream(stream);
|
||||
NormStopReceiver(session);
|
||||
NormStopSender(session);
|
||||
NormDestroySession(session);
|
||||
NormDestroyInstance(instance);
|
||||
|
||||
fprintf(stderr, "normTest: Done.\n");
|
||||
return 0;
|
||||
} // end main()
|
||||
|
|
@ -32,6 +32,6 @@
|
|||
|
||||
#ifndef _NORM_VERSION
|
||||
#define _NORM_VERSION
|
||||
#define VERSION "1.2b1"
|
||||
#define VERSION "1.2b2"
|
||||
#endif // _NORM_VERSION
|
||||
|
||||
|
|
|
|||
|
|
@ -467,7 +467,7 @@ void RaftApp::OnClientSocketEvent(ProtoSocket& /*theSocket*/,
|
|||
while (rtsp_client_socket.Recv(buffer, buflen))
|
||||
{
|
||||
buffer[buflen] = '\0';
|
||||
TRACE("%s");
|
||||
TRACE("%s", buffer);
|
||||
}
|
||||
TRACE("\n");
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ for {set i 2} {$i <= $numNodes} {incr i} {
|
|||
}
|
||||
$ns_ at 0.0 "$norm(1) sendFile 64000"
|
||||
|
||||
$ns_ at 3000.0 "finish $ns_ $f $nf"
|
||||
$ns_ at 300.0 "finish $ns_ $f $nf"
|
||||
|
||||
proc finish {ns_ f nf} {
|
||||
$ns_ flush-trace
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ NS = ../ns
|
|||
|
||||
INCLUDES = $(TCL_INCL_PATH) $(SYSTEM_INCLUDES) -I$(UNIX) -I$(COMMON) -I$(PROTOLIB)/common
|
||||
|
||||
CFLAGS = -DPROTO_DEBUG -DUNIX -O -fPIC $(SYSTEM_HAVES) $(INCLUDES)
|
||||
CFLAGS = -g -DPROTO_DEBUG -DUNIX -D_FILE_OFFSET_BITS=64 -O -fPIC $(SYSTEM_HAVES) $(INCLUDES)
|
||||
|
||||
LDFLAGS = $(SYSTEM_LDFLAGS)
|
||||
|
||||
|
|
@ -84,6 +84,14 @@ APP_OBJ = $(APP_SRC:.cpp=.o)
|
|||
norm: $(APP_OBJ) libnorm.a $(LIBPROTO)
|
||||
$(CC) $(CFLAGS) -o $@ $(APP_OBJ) $(LDFLAGS) libnorm.a $(LIBPROTO) $(LIBS)
|
||||
|
||||
|
||||
# (normTest) test of NORM API
|
||||
TEST_SRC = $(COMMON)/normApi.cpp $(COMMON)/normTest.cpp
|
||||
TEST_OBJ = $(TEST_SRC:.cpp=.o)
|
||||
|
||||
normTest: $(TEST_OBJ) libnorm.a $(LIBPROTO)
|
||||
$(CC) $(CFLAGS) -o $@ $(TEST_OBJ) $(LDFLAGS) libnorm.a $(LIBPROTO) $(LIBS)
|
||||
|
||||
# (raft) command-line reliable tunnel helper
|
||||
RAFT_SRC = $(COMMON)/raft.cpp
|
||||
RAFT_OBJ = $(RAFT_SRC:.cpp=.o)
|
||||
|
|
|
|||
|
|
@ -62,8 +62,8 @@ SYSTEM_LIBS = -ldl
|
|||
# (We export these for other Makefiles as needed)
|
||||
#
|
||||
|
||||
SYSTEM_HAVES = -DLINUX -DHAVE_IPV6 -DHAVE_GETLOGIN -DHAVE_LOCKF \
|
||||
-DHAVE_OLD_SIGNALHANDLER -DHAVE_DIRFD -DHAVE_ASSERT $(NETSEC)
|
||||
SYSTEM_HAVES = -DLINUX -DHAVE_IPV6 -DHAVE_GETLOGIN -D_FILE_OFFSET_BITS=64 -DHAVE_LOCKF \
|
||||
-DHAVE_OLD_SIGNALHANDLER -DHAVE_DIRFD -DHAVE_ASSERT
|
||||
|
||||
SYSTEM_SRC =
|
||||
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@
|
|||
# (Where to find X11 libraries, etc)
|
||||
#
|
||||
|
||||
SYSTEM_INCLUDES = -I/usr/X11R6/include
|
||||
SYSTEM_LDFLAGS = -L/usr/X11R6/lib
|
||||
SYSTEM_LIBS =
|
||||
SYSTEM_INCLUDES =
|
||||
SYSTEM_LDFLAGS =
|
||||
SYSTEM_LIBS = -lresolv
|
||||
|
||||
# 2) System specific capabilities
|
||||
# Must choose appropriate for the following:
|
||||
|
|
@ -36,15 +36,16 @@ SYSTEM_LIBS =
|
|||
# (We export these for other Makefiles as needed)
|
||||
#
|
||||
|
||||
export SYSTEM_HAVES = -DMACOSX -DHAVE_IPV6 -DHAVE_ASSERT -DHAVE_GETLOGIN -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC) -DSOCKLEN_T=int
|
||||
SYSTEM_HAVES = -DMACOSX -DHAVE_IPV6 -DHAVE_ASSERT -DHAVE_GETLOGIN -DHAVE_FLOCK \
|
||||
-D_FILE_OFFSET_BITS=64 -DHAVE_DIRFD -DSOCKLEN_T=int
|
||||
|
||||
SYSTEM_SRC = bsdRouteMgr.cpp
|
||||
|
||||
# The "SYSTEM" keyword can be used for dependent makes
|
||||
SYSTEM = macosx
|
||||
|
||||
export CC = g++
|
||||
export RANLIB = ranlib
|
||||
export AR = ar
|
||||
CC = g++
|
||||
RANLIB = ranlib
|
||||
AR = ar
|
||||
|
||||
include Makefile.common
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
# 1) System specific additional libraries, include paths, etc
|
||||
# (Where to find X11 libraries, etc)
|
||||
#
|
||||
SYSTEM_INCLUDES = -I/usr/openwin/include
|
||||
SYSTEM_LDFLAGS = -L/usr/openwin/lib -R/usr/openwin/lib
|
||||
SYSTEM_INCLUDES =
|
||||
SYSTEM_LDFLAGS =
|
||||
SYSTEM_LIBS = -ldl -lnsl -lsocket -lresolv
|
||||
|
||||
# 2) System specific capabilities
|
||||
|
|
@ -35,7 +35,8 @@ SYSTEM_LIBS = -ldl -lnsl -lsocket -lresolv
|
|||
# (We export these for other Makefiles as needed)
|
||||
#
|
||||
|
||||
SYSTEM_HAVES = -DHAVE_IPV6 -DHAVE_ASSERT -DHAVE_CUSERID -DHAVE_LOCKF $(NETSEC) -DSOLARIS
|
||||
SYSTEM_HAVES = -DHAVE_IPV6 -DHAVE_ASSERT -DHAVE_CUSERID -DHAVE_LOCKF \
|
||||
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -DSOLARIS
|
||||
|
||||
SYSTEM = solaris
|
||||
|
||||
|
|
|
|||
|
|
@ -234,6 +234,10 @@ bool UnixPostProcessor::ProcessFile(const char* path)
|
|||
// Restore signal handlers for parent
|
||||
signal(SIGTERM, sigtermHandler);
|
||||
signal(SIGINT, sigintHandler);
|
||||
// The use of "waitpid()" here is a work-around
|
||||
// for an IRIX SIGCHLD issue
|
||||
int status;
|
||||
while (waitpid(-1, &status, WNOHANG) > 0);
|
||||
signal(SIGCHLD, sigchldHandler);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,24 @@ Package=<4>
|
|||
|
||||
###############################################################################
|
||||
|
||||
Project: "normTest"=..\normTest.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
Begin Project Dependency
|
||||
Project_Dep_Name NormLib
|
||||
End Project Dependency
|
||||
Begin Project Dependency
|
||||
Project_Dep_Name Protokit
|
||||
End Project Dependency
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
|
|
|
|||
BIN
win32/Norm.opt
BIN
win32/Norm.opt
Binary file not shown.
|
|
@ -0,0 +1,106 @@
|
|||
# Microsoft Developer Studio Project File - Name="normTest" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
CFG=normTest - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "normTest.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "normTest.mak" CFG="normTest - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "normTest - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "normTest - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "normTest - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\common" /I "..\protolib\common" /I "..\protolib\win32" /D "NDEBUG" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
# ADD LINK32 iphlpapi.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
|
||||
!ELSEIF "$(CFG)" == "normTest - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /GX /Od /I "..\common" /I "..\protolib\common" /I "..\protolib\win32" /D "_DEBUG" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 iphlpapi.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "normTest - Win32 Release"
|
||||
# Name "normTest - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\normApi.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\normTest.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
||||
Loading…
Reference in New Issue