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 <stdlib.h>
|
||||||
#include <ctype.h> // for "isspace()"
|
#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
|
// Command-line application using Protolib EventDispatcher
|
||||||
class NormApp : public NormController, public ProtoApp
|
class NormApp : public NormController, public ProtoApp
|
||||||
{
|
{
|
||||||
|
|
@ -64,8 +69,8 @@ class NormApp : public NormController, public ProtoApp
|
||||||
unsigned int input_index;
|
unsigned int input_index;
|
||||||
unsigned int input_length;
|
unsigned int input_length;
|
||||||
bool input_active;
|
bool input_active;
|
||||||
bool push_stream;
|
bool push_mode;
|
||||||
NormStreamObject::FlushType msg_flush_mode;
|
NormStreamObject::FlushMode msg_flush_mode;
|
||||||
bool input_messaging; // stream input mode
|
bool input_messaging; // stream input mode
|
||||||
UINT16 input_msg_length;
|
UINT16 input_msg_length;
|
||||||
UINT16 input_msg_index;
|
UINT16 input_msg_index;
|
||||||
|
|
@ -79,6 +84,7 @@ class NormApp : public NormController, public ProtoApp
|
||||||
char* address; // session address
|
char* address; // session address
|
||||||
UINT16 port; // session port number
|
UINT16 port; // session port number
|
||||||
UINT8 ttl;
|
UINT8 ttl;
|
||||||
|
bool loopback;
|
||||||
char* interface_name; // for multi-home hosts
|
char* interface_name; // for multi-home hosts
|
||||||
double tx_rate; // bits/sec
|
double tx_rate; // bits/sec
|
||||||
bool cc_enable;
|
bool cc_enable;
|
||||||
|
|
@ -90,6 +96,8 @@ class NormApp : public NormController, public ProtoApp
|
||||||
UINT8 auto_parity;
|
UINT8 auto_parity;
|
||||||
UINT8 extra_parity;
|
UINT8 extra_parity;
|
||||||
double backoff_factor;
|
double backoff_factor;
|
||||||
|
double grtt_estimate; // initial grtt estimate
|
||||||
|
double group_size;
|
||||||
unsigned long tx_buffer_size; // bytes
|
unsigned long tx_buffer_size; // bytes
|
||||||
NormFileList tx_file_list;
|
NormFileList tx_file_list;
|
||||||
double tx_object_interval;
|
double tx_object_interval;
|
||||||
|
|
@ -118,13 +126,15 @@ NormApp::NormApp()
|
||||||
session_mgr(GetTimerMgr(), GetSocketNotifier()),
|
session_mgr(GetTimerMgr(), GetSocketNotifier()),
|
||||||
session(NULL), tx_stream(NULL), rx_stream(NULL), input(NULL), output(NULL),
|
session(NULL), tx_stream(NULL), rx_stream(NULL), input(NULL), output(NULL),
|
||||||
input_index(0), input_length(0), input_active(false),
|
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),
|
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),
|
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),
|
tx_rate(64000.0), cc_enable(false),
|
||||||
segment_size(1024), ndata(32), nparity(16), auto_parity(0), extra_parity(0),
|
segment_size(1024), ndata(32), nparity(16), auto_parity(0), extra_parity(0),
|
||||||
backoff_factor(NormSession::DEFAULT_BACKOFF_FACTOR),
|
backoff_factor(NormSession::DEFAULT_BACKOFF_FACTOR),
|
||||||
|
grtt_estimate(NormSession::DEFAULT_GRTT_ESTIMATE),
|
||||||
|
group_size(NormSession::DEFAULT_GSIZE_ESTIMATE),
|
||||||
tx_buffer_size(1024*1024),
|
tx_buffer_size(1024*1024),
|
||||||
tx_object_interval(0.0), tx_repeat_count(0), tx_repeat_interval(2.0), tx_repeat_clear(true),
|
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),
|
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;
|
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[] =
|
const char* const NormApp::cmd_list[] =
|
||||||
{
|
{
|
||||||
"+debug", // debug level
|
"+debug", // debug level
|
||||||
"+log", // log file name
|
"+log", // log file name
|
||||||
"-trace", // message tracing on
|
"+trace", // message tracing on
|
||||||
"+txloss", // tx packet loss percent (for testing)
|
"+txloss", // tx packet loss percent (for testing)
|
||||||
"+rxloss", // rx packet loss percent (for testing)
|
"+rxloss", // rx packet loss percent (for testing)
|
||||||
"+address", // session destination address
|
"+address", // session destination address
|
||||||
"+ttl", // multicast hop count scope
|
"+ttl", // multicast hop count scope
|
||||||
|
"+loopback", // "off" or "on" to recv our own packets
|
||||||
"+interface", // multicast interface name to use
|
"+interface", // multicast interface name to use
|
||||||
"+cc", // congestion control on/off
|
"+cc", // congestion control on/off
|
||||||
"+rate", // tx date rate (bps)
|
"+rate", // tx date rate (bps)
|
||||||
|
|
@ -184,18 +211,19 @@ const char* const NormApp::cmd_list[] =
|
||||||
"+auto", // Number of FEC packets to proactively send (<= nparity)
|
"+auto", // Number of FEC packets to proactively send (<= nparity)
|
||||||
"+extra", // Number of extra FEC packets sent in response to repair requests
|
"+extra", // Number of extra FEC packets sent in response to repair requests
|
||||||
"+backoff", // Backoff factor to use
|
"+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
|
"+txbuffer", // Size of sender's buffer
|
||||||
"+rxbuffer", // Size receiver allocates for buffering each sender
|
"+rxbuffer", // Size receiver allocates for buffering each sender
|
||||||
"-unicastNacks", // unicast instead of multicast feedback messages
|
"-unicastNacks", // unicast instead of multicast feedback messages
|
||||||
"-silentClient", // "silent" (non-nacking) client (EMCON mode)
|
"-silentClient", // "silent" (non-nacking) client (EMCON mode)
|
||||||
"+processor", // receive file post processing command
|
"+processor", // receive file post processing command
|
||||||
"+instance", // specify norm instance name for commands
|
"+instance", // specify norm instance name for remote control commands
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
void NormApp::OnControlEvent(ProtoSocket& /*theSocket*/, ProtoSocket::Event theEvent)
|
void NormApp::OnControlEvent(ProtoSocket& /*theSocket*/, ProtoSocket::Event theEvent)
|
||||||
{
|
{
|
||||||
TRACE("NormApp::OnControlEvent() ...\n");
|
|
||||||
switch (theEvent)
|
switch (theEvent)
|
||||||
{
|
{
|
||||||
case ProtoSocket::RECV:
|
case ProtoSocket::RECV:
|
||||||
|
|
@ -205,7 +233,7 @@ void NormApp::OnControlEvent(ProtoSocket& /*theSocket*/, ProtoSocket::Event theE
|
||||||
if (control_pipe.Recv(buffer, len))
|
if (control_pipe.Recv(buffer, len))
|
||||||
{
|
{
|
||||||
buffer[len] = '\0';
|
buffer[len] = '\0';
|
||||||
TRACE("norm: received command \"%s\"\n", buffer);
|
DMSG(0, "norm: received command \"%s\"\n", buffer);
|
||||||
char* cmd = buffer;
|
char* cmd = buffer;
|
||||||
char* val = NULL;
|
char* val = NULL;
|
||||||
for (unsigned int i = 0; i < len; i++)
|
for (unsigned int i = 0; i < len; i++)
|
||||||
|
|
@ -214,6 +242,7 @@ void NormApp::OnControlEvent(ProtoSocket& /*theSocket*/, ProtoSocket::Event theE
|
||||||
{
|
{
|
||||||
buffer[i++] = '\0';
|
buffer[i++] = '\0';
|
||||||
val = buffer + i;
|
val = buffer + i;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!OnCommand(cmd, val))
|
if (!OnCommand(cmd, val))
|
||||||
|
|
@ -288,8 +317,16 @@ bool NormApp::OnCommand(const char* cmd, const char* val)
|
||||||
}
|
}
|
||||||
else if (!strncmp("trace", cmd, len))
|
else if (!strncmp("trace", cmd, len))
|
||||||
{
|
{
|
||||||
|
if (!strcmp("on", val))
|
||||||
tracing = true;
|
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))
|
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))
|
else if (!strncmp("ttl", cmd, len))
|
||||||
{
|
{
|
||||||
int ttlTemp = atoi(val);
|
int ttlTemp = atoi(val);
|
||||||
if ((ttlTemp < 1) || (ttlTemp > 255))
|
if ((ttlTemp < 0) || (ttlTemp > 255))
|
||||||
{
|
{
|
||||||
DMSG(0, "NormApp::OnCommand(ttl) invalid value!\n");
|
DMSG(0, "NormApp::OnCommand(ttl) invalid value!\n");
|
||||||
return false;
|
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))
|
else if (!strncmp("interface", cmd, len))
|
||||||
{
|
{
|
||||||
|
|
@ -580,12 +643,34 @@ bool NormApp::OnCommand(const char* cmd, const char* val)
|
||||||
double backoffFactor = atof(val);
|
double backoffFactor = atof(val);
|
||||||
if (backoffFactor < 0)
|
if (backoffFactor < 0)
|
||||||
{
|
{
|
||||||
DMSG(0, "NormSimAgent::OnCommand(backoff) invalid txRate!\n");
|
DMSG(0, "NormApp::OnCommand(backoff) invalid value!\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
backoff_factor = backoffFactor;
|
backoff_factor = backoffFactor;
|
||||||
if (session) session->SetBackoffFactor(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))
|
else if (!strncmp("txbuffer", cmd, len))
|
||||||
{
|
{
|
||||||
if (1 != sscanf(val, "%lu", &tx_buffer_size))
|
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))
|
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))
|
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");
|
DMSG(0, "NormApp::OnCommand(flush) invalid msg flush mode!\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (tx_stream) tx_stream->SetFlushMode(msg_flush_mode);
|
||||||
}
|
}
|
||||||
else if (!strncmp("processor", cmd, len))
|
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
|
// First, try to connect to see if instance is already running
|
||||||
if (control_pipe.Connect(val))
|
if (control_pipe.Connect(val))
|
||||||
{
|
{
|
||||||
TRACE("connected to \"%s\"\n", val);
|
|
||||||
control_remote = true;
|
control_remote = true;
|
||||||
}
|
}
|
||||||
else if (control_pipe.Listen(val))
|
else if (control_pipe.Listen(val))
|
||||||
{
|
{
|
||||||
TRACE("listening as \"%s\"\n", val);
|
|
||||||
control_remote = false;
|
control_remote = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -740,7 +825,7 @@ void NormApp::OnInputReady()
|
||||||
{
|
{
|
||||||
|
|
||||||
//DMSG(0, "NormApp::OnInputReady() ...\n");
|
//DMSG(0, "NormApp::OnInputReady() ...\n");
|
||||||
NormStreamObject::FlushType flushType = NormStreamObject::FLUSH_NONE;
|
bool endOfStream = false;
|
||||||
// write to the stream while input is available _and_
|
// write to the stream while input is available _and_
|
||||||
// the stream has buffer space for input
|
// the stream has buffer space for input
|
||||||
while (input)
|
while (input)
|
||||||
|
|
@ -816,7 +901,8 @@ void NormApp::OnInputReady()
|
||||||
}
|
}
|
||||||
if (stdin != input) fclose(input);
|
if (stdin != input) fclose(input);
|
||||||
input = NULL;
|
input = NULL;
|
||||||
flushType = NormStreamObject::FLUSH_ACTIVE;
|
endOfStream = true;
|
||||||
|
tx_stream->SetFlushMode(NormStreamObject::FLUSH_ACTIVE);
|
||||||
}
|
}
|
||||||
else if (ferror(input))
|
else if (ferror(input))
|
||||||
{
|
{
|
||||||
|
|
@ -839,11 +925,10 @@ void NormApp::OnInputReady()
|
||||||
|
|
||||||
unsigned int writeLength = input_length;// ? input_length - input_index : 0;
|
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,
|
unsigned int wroteLength = tx_stream->Write(input_buffer+input_index,
|
||||||
writeLength, flushType, false,
|
writeLength, false);
|
||||||
push_stream);
|
|
||||||
input_length -= wroteLength;
|
input_length -= wroteLength;
|
||||||
if (0 == input_length)
|
if (0 == input_length)
|
||||||
input_index = 0;
|
input_index = 0;
|
||||||
|
|
@ -857,7 +942,9 @@ void NormApp::OnInputReady()
|
||||||
input_msg_index = 0;
|
input_msg_index = 0;
|
||||||
input_msg_length = 0;
|
input_msg_length = 0;
|
||||||
// Mark EOM _and_ flush
|
// 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)
|
if (wroteLength < writeLength)
|
||||||
|
|
@ -890,7 +977,7 @@ void NormApp::OnInputReady()
|
||||||
#endif // if/else WIN32/UNIX
|
#endif // if/else WIN32/UNIX
|
||||||
input_active = true;
|
input_active = true;
|
||||||
else
|
else
|
||||||
DMSG(0, "NormApp::Notify(TX_QUEUE_EMPTY) error adding input notification!\n");
|
DMSG(0, "NormApp::OnInputReady() error adding input notification!\n");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -992,6 +1079,9 @@ void NormApp::Notify(NormController::Event event,
|
||||||
case NormObject::DATA:
|
case NormObject::DATA:
|
||||||
DMSG(0, "NormApp::Notify() FILE/DATA objects not _yet_ supported...\n");
|
DMSG(0, "NormApp::Notify() FILE/DATA objects not _yet_ supported...\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NormObject::NONE:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1032,6 +1122,7 @@ void NormApp::Notify(NormController::Event event,
|
||||||
}
|
}
|
||||||
case NormObject::DATA:
|
case NormObject::DATA:
|
||||||
case NormObject::STREAM:
|
case NormObject::STREAM:
|
||||||
|
case NormObject::NONE:
|
||||||
break;
|
break;
|
||||||
} // end switch(object->GetType())
|
} // end switch(object->GetType())
|
||||||
break;
|
break;
|
||||||
|
|
@ -1042,6 +1133,8 @@ void NormApp::Notify(NormController::Event event,
|
||||||
{
|
{
|
||||||
case NormObject::FILE:
|
case NormObject::FILE:
|
||||||
// (TBD) update reception progress display when applicable
|
// (TBD) update reception progress display when applicable
|
||||||
|
// Call object->SetNotifyOnUpdate(true) here to keep
|
||||||
|
// the update notifications coming. Otherwise they stop!
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NormObject::STREAM:
|
case NormObject::STREAM:
|
||||||
|
|
@ -1161,17 +1254,22 @@ void NormApp::Notify(NormController::Event event,
|
||||||
case NormObject::DATA:
|
case NormObject::DATA:
|
||||||
DMSG(0, "NormApp::Notify() DATA objects not _yet_ supported...\n");
|
DMSG(0, "NormApp::Notify() DATA objects not _yet_ supported...\n");
|
||||||
break;
|
break;
|
||||||
|
case NormObject::NONE:
|
||||||
|
break;
|
||||||
} // end switch (object->GetType())
|
} // end switch (object->GetType())
|
||||||
break;
|
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");
|
//DMSG(0, "NormApp::Notify(RX_OBJECT_COMPLETE) ...\n");
|
||||||
switch(object->GetType())
|
switch(object->GetType())
|
||||||
{
|
{
|
||||||
case NormObject::FILE:
|
case NormObject::FILE:
|
||||||
{
|
{
|
||||||
const char* filePath = ((NormFileObject*)object)->Path();
|
const char* filePath = ((NormFileObject*)object)->GetPath();
|
||||||
//DMSG(0, "norm: Completed rx file: %s\n", filePath);
|
//DMSG(0, "norm: Completed rx file: %s\n", filePath);
|
||||||
if (post_processor->IsEnabled())
|
if (post_processor->IsEnabled())
|
||||||
{
|
{
|
||||||
|
|
@ -1189,9 +1287,15 @@ void NormApp::Notify(NormController::Event event,
|
||||||
case NormObject::DATA:
|
case NormObject::DATA:
|
||||||
ASSERT(0);
|
ASSERT(0);
|
||||||
break;
|
break;
|
||||||
|
case NormObject::NONE:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
DMSG(4, "NormApp::Notify() unhandled event: %d\n", event);
|
||||||
|
}
|
||||||
} // end switch(event)
|
} // end switch(event)
|
||||||
} // end NormApp::Notify()
|
} // end NormApp::Notify()
|
||||||
|
|
||||||
|
|
@ -1315,14 +1419,17 @@ bool NormApp::OnStartup(int argc, const char*const* argv)
|
||||||
session->SetTrace(tracing);
|
session->SetTrace(tracing);
|
||||||
session->SetTxLoss(tx_loss);
|
session->SetTxLoss(tx_loss);
|
||||||
session->SetRxLoss(rx_loss);
|
session->SetRxLoss(rx_loss);
|
||||||
session->SetBackoffFactor(backoff_factor);
|
session->SetTTL(ttl);
|
||||||
|
session->SetLoopback(loopback);
|
||||||
|
|
||||||
if (input || !tx_file_list.IsEmpty())
|
if (input || !tx_file_list.IsEmpty())
|
||||||
{
|
{
|
||||||
NormObjectId baseId = (unsigned short)(rand() * (65535.0/ (double)RAND_MAX));
|
NormObjectId baseId = (unsigned short)(rand() * (65535.0/ (double)RAND_MAX));
|
||||||
session->ServerSetBaseObjectId(baseId);
|
session->ServerSetBaseObjectId(baseId);
|
||||||
|
|
||||||
session->SetCongestionControl(cc_enable);
|
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))
|
if (!session->StartServer(tx_buffer_size, segment_size, ndata, nparity, interface_name))
|
||||||
{
|
{
|
||||||
DMSG(0, "NormApp::OnStartup() start server error!\n");
|
DMSG(0, "NormApp::OnStartup() start server error!\n");
|
||||||
|
|
@ -1341,6 +1448,8 @@ bool NormApp::OnStartup(int argc, const char*const* argv)
|
||||||
session_mgr.Destroy();
|
session_mgr.Destroy();
|
||||||
return false;
|
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());
|
NormApp* app = static_cast<NormApp*>(ProtoApp::GetApp());
|
||||||
if (app->post_processor) app->post_processor->OnDeath();
|
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);
|
signal(SIGCHLD, SignalHandler);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -378,7 +378,9 @@ bool NormBitmask::Add(const NormBitmask& b)
|
||||||
if (b.num_bits > num_bits) return false;
|
if (b.num_bits > num_bits) return false;
|
||||||
for(unsigned int i = 0; i < b.mask_len; i++)
|
for(unsigned int i = 0; i < b.mask_len; i++)
|
||||||
mask[i] |= b.mask[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;
|
return true;
|
||||||
} // end NormBitmask::Add()
|
} // end NormBitmask::Add()
|
||||||
|
|
||||||
|
|
@ -406,13 +408,14 @@ bool NormBitmask::XCopy(const NormBitmask& b)
|
||||||
for (unsigned int i = begin; i < len; i++)
|
for (unsigned int i = begin; i < len; i++)
|
||||||
mask[i] = b.mask[i] & ~mask[i];
|
mask[i] = b.mask[i] & ~mask[i];
|
||||||
if (len < mask_len) memset(&mask[len], 0, mask_len - len);
|
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;
|
first_set = b.first_set;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
first_set = b.first_set;
|
first_set = theFirst;
|
||||||
if (!GetNextSet(first_set)) first_set = num_bits;
|
if (!GetNextSet(first_set)) first_set = num_bits;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -425,6 +428,7 @@ bool NormBitmask::Multiply(const NormBitmask& b)
|
||||||
for(unsigned int i = 0; i < len; i++)
|
for(unsigned int i = 0; i < len; i++)
|
||||||
mask[i] |= b.mask[i];
|
mask[i] |= b.mask[i];
|
||||||
if (len < mask_len) memset(&mask[len], 0, mask_len - len);
|
if (len < mask_len) memset(&mask[len], 0, mask_len - len);
|
||||||
|
|
||||||
if (b.first_set > first_set)
|
if (b.first_set > first_set)
|
||||||
{
|
{
|
||||||
first_set = b.first_set;
|
first_set = b.first_set;
|
||||||
|
|
@ -557,7 +561,7 @@ bool NormSlidingMask::CanSet(UINT32 index) const
|
||||||
|
|
||||||
bool NormSlidingMask::Set(UINT32 index)
|
bool NormSlidingMask::Set(UINT32 index)
|
||||||
{
|
{
|
||||||
ASSERT(CanSet(index));
|
//ASSERT(CanSet(index));
|
||||||
if (IsSet())
|
if (IsSet())
|
||||||
{
|
{
|
||||||
// Determine position with respect to current start
|
// Determine position with respect to current start
|
||||||
|
|
|
||||||
|
|
@ -218,8 +218,8 @@ void NormEncoder::Encode(const char *data, char **pVec)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
NormDecoder::NormDecoder()
|
NormDecoder::NormDecoder()
|
||||||
: npar(0), vector_size(0),
|
: npar(0), vector_size(0), Lambda(NULL),
|
||||||
Lambda(NULL), sVec(NULL), oVec(NULL)
|
sVec(NULL), oVec(NULL), scratch(NULL)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
#include "normFile.h"
|
#include "normFile.h"
|
||||||
|
|
||||||
#include <string.h> // for strerror()
|
#include <string.h> // for strerror()
|
||||||
|
|
@ -63,7 +62,7 @@ bool NormFile::Open(const char* thePath, int theFlags)
|
||||||
if (mkdir(tempPath, 0755))
|
if (mkdir(tempPath, 0755))
|
||||||
#endif // if/else WIN32/UNIX
|
#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));
|
tempPath, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -159,10 +158,21 @@ bool NormFile::Rename(const char* oldName, const char* newName)
|
||||||
if (!strcmp(oldName, newName)) return true; // no change required
|
if (!strcmp(oldName, newName)) return true; // no change required
|
||||||
// Make sure the new file name isn't an existing "busy" file
|
// Make sure the new file name isn't an existing "busy" file
|
||||||
// (This also builds sub-directories as needed)
|
// (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
|
#ifdef WIN32
|
||||||
// In Win32, the new file can't already exist
|
// 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
|
// In Win32, the old file can't be open
|
||||||
int oldFlags = 0;
|
int oldFlags = 0;
|
||||||
if (IsOpen())
|
if (IsOpen())
|
||||||
|
|
@ -171,7 +181,7 @@ bool NormFile::Rename(const char* oldName, const char* newName)
|
||||||
oldFlags &= ~(O_CREAT | O_TRUNC); // unset these
|
oldFlags &= ~(O_CREAT | O_TRUNC); // unset these
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
#else
|
#endif // WIN32
|
||||||
// Create sub-directories as needed.
|
// Create sub-directories as needed.
|
||||||
char tempPath[PATH_MAX];
|
char tempPath[PATH_MAX];
|
||||||
strncpy(tempPath, newName, 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);
|
ptr = strchr(ptr, PROTO_PATH_DELIMITER);
|
||||||
if (ptr) *ptr = '\0';
|
if (ptr) *ptr = '\0';
|
||||||
|
#ifdef WIN32
|
||||||
|
if (0 != _mkdir(tempPath))
|
||||||
|
#else
|
||||||
if (mkdir(tempPath, 0755))
|
if (mkdir(tempPath, 0755))
|
||||||
|
#endif // if/else WIN32/UNIX
|
||||||
{
|
{
|
||||||
DMSG(0, "NormFile::Rename() mkdir(%s) error: %s\n",
|
DMSG(0, "NormFile::Rename() mkdir(%s) error: %s\n",
|
||||||
tempPath, strerror(errno));
|
tempPath, GetErrorString());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (ptr) *ptr++ = PROTO_PATH_DELIMITER;
|
if (ptr) *ptr++ = PROTO_PATH_DELIMITER;
|
||||||
}
|
}
|
||||||
#endif // if/else WIN32
|
|
||||||
if (rename(oldName, newName))
|
if (rename(oldName, newName))
|
||||||
{
|
{
|
||||||
DMSG(0, "NormFile::Rename() rename() error: %s\n", strerror(errno));
|
DMSG(0, "NormFile::Rename() rename() error: %s\n", strerror(errno));
|
||||||
#ifdef WIN32
|
#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
|
#endif // WIN32
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
// (TBD) Is the file offset OK doing this???
|
// (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
|
#endif // WIN32
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -234,7 +259,7 @@ int NormFile::Read(char* buffer, int len)
|
||||||
#else
|
#else
|
||||||
int result = read(fd, buffer, len);
|
int result = read(fd, buffer, len);
|
||||||
#endif // if/else WIN32
|
#endif // if/else WIN32
|
||||||
if (result > 0) offset += result;
|
if (result > 0) offset += (off_t)result;
|
||||||
return result;
|
return result;
|
||||||
} // end NormFile::Read()
|
} // end NormFile::Read()
|
||||||
|
|
||||||
|
|
@ -246,7 +271,7 @@ int NormFile::Write(const char* buffer, int len)
|
||||||
#else
|
#else
|
||||||
int result = write(fd, buffer, len);
|
int result = write(fd, buffer, len);
|
||||||
#endif // if/else WIN32
|
#endif // if/else WIN32
|
||||||
if (result > 0) offset += result;
|
if (result > 0) offset += (off_t)result;
|
||||||
return result;
|
return result;
|
||||||
} // end NormFile::Write()
|
} // end NormFile::Write()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,14 +29,14 @@ bool NormMsg::InitFromBuffer(UINT16 msgLength)
|
||||||
case DATA:
|
case DATA:
|
||||||
// (TBD) look at "fec_id" to determine "fec_payload_id" size
|
// (TBD) look at "fec_id" to determine "fec_payload_id" size
|
||||||
// (we _assume_ "fec_id" == 129 here
|
// (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;
|
header_length_base = 24;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DMSG(0, "NormMsg::InitFromBuffer(DATA) unknown fec_id value: %u\n",
|
DMSG(0, "NormMsg::InitFromBuffer(DATA) unknown fec_id value: %u\n",
|
||||||
buffer[NormDataMsg::FEC_ID_OFFSET]);
|
buffer[NormObjectMsg::FEC_ID_OFFSET]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -54,7 +54,7 @@ bool NormMsg::InitFromBuffer(UINT16 msgLength)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DMSG(0, "NormMsg::InitFromBuffer(FLUSH|SQUELCH) unknown fec_id value: %u\n",
|
DMSG(0, "NormMsg::InitFromBuffer(FLUSH|SQUELCH) unknown fec_id value: %u\n",
|
||||||
buffer[NormDataMsg::FEC_ID_OFFSET]);
|
buffer[NormCmdFlushMsg::FEC_ID_OFFSET]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -420,7 +420,7 @@ unsigned char NormQuantizeRtt(double rtt)
|
||||||
else if (rtt < NORM_RTT_MIN)
|
else if (rtt < NORM_RTT_MIN)
|
||||||
rtt = NORM_RTT_MIN;
|
rtt = NORM_RTT_MIN;
|
||||||
if (rtt < 3.3e-05)
|
if (rtt < 3.3e-05)
|
||||||
return ((unsigned char)ceil((rtt*NORM_RTT_MIN)) - 1);
|
return ((unsigned char)((rtt/NORM_RTT_MIN)) - 1);
|
||||||
else
|
else
|
||||||
return ((unsigned char)(ceil(255.0 - (13.0*log(NORM_RTT_MAX/rtt)))));
|
return ((unsigned char)(ceil(255.0 - (13.0*log(NORM_RTT_MAX/rtt)))));
|
||||||
} // end NormQuantizeRtt()
|
} // end NormQuantizeRtt()
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ const UINT8 NORM_PROTOCOL_VERSION = 1;
|
||||||
|
|
||||||
const int NORM_ROBUST_FACTOR = 20; // default robust factor
|
const int NORM_ROBUST_FACTOR = 20; // default robust factor
|
||||||
|
|
||||||
|
|
||||||
// Pick a random number from 0..max
|
// Pick a random number from 0..max
|
||||||
inline double UniformRand(double max)
|
inline double UniformRand(double max)
|
||||||
{
|
{
|
||||||
|
|
@ -46,7 +45,7 @@ const double NORM_RTT_MAX = 1000.0;
|
||||||
inline double NormUnquantizeRtt(unsigned char qrtt)
|
inline double NormUnquantizeRtt(unsigned char qrtt)
|
||||||
{
|
{
|
||||||
return ((qrtt < 31) ?
|
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)));
|
(NORM_RTT_MAX/exp(((double)(255-qrtt))/(double)13.0)));
|
||||||
}
|
}
|
||||||
unsigned char NormQuantizeRtt(double rtt);
|
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"
|
// This class is used to describe object "size" and/or "offset"
|
||||||
|
// (TBD) This hokey implementation should use "off_t"
|
||||||
class NormObjectSize
|
class NormObjectSize
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -103,6 +103,13 @@ class NormObjectSize
|
||||||
NormObjectSize(UINT32 size) : msb(0), lsb(size) {}
|
NormObjectSize(UINT32 size) : msb(0), lsb(size) {}
|
||||||
NormObjectSize(UINT16 size) : msb(0), lsb(size) {}
|
NormObjectSize(UINT16 size) : msb(0), lsb(size) {}
|
||||||
NormObjectSize(const NormObjectSize& size) : msb(size.msb), lsb(size.lsb) {}
|
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;}
|
UINT16 MSB() const {return msb;}
|
||||||
UINT32 LSB() const {return lsb;}
|
UINT32 LSB() const {return lsb;}
|
||||||
|
|
@ -150,15 +157,24 @@ class NormObjectSize
|
||||||
}
|
}
|
||||||
NormObjectSize operator*(const NormObjectSize& b) const;
|
NormObjectSize operator*(const NormObjectSize& b) const;
|
||||||
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:
|
private:
|
||||||
UINT16 msb;
|
UINT16 msb;
|
||||||
UINT32 lsb;
|
UINT32 lsb;
|
||||||
}; // end class NormObjectSize
|
}; // end class NormObjectSize
|
||||||
|
|
||||||
typedef UINT32 NormNodeId;
|
#ifndef _NORM_API
|
||||||
const NormNodeId NORM_NODE_INVALID = 0x00000000;
|
typedef unsigned long NormNodeId;
|
||||||
|
const NormNodeId NORM_NODE_NONE = 0x00000000;
|
||||||
const NormNodeId NORM_NODE_ANY = 0xffffffff;
|
const NormNodeId NORM_NODE_ANY = 0xffffffff;
|
||||||
|
#endif // !_NORM_API
|
||||||
|
|
||||||
class NormObjectId
|
class NormObjectId
|
||||||
{
|
{
|
||||||
|
|
@ -167,18 +183,12 @@ class NormObjectId
|
||||||
NormObjectId(UINT16 id) {value = id;}
|
NormObjectId(UINT16 id) {value = id;}
|
||||||
NormObjectId(const NormObjectId& id) {value = id.value;}
|
NormObjectId(const NormObjectId& id) {value = id.value;}
|
||||||
operator UINT16() const {return value;}
|
operator UINT16() const {return value;}
|
||||||
int operator-(const NormObjectId& id) const
|
INT16 operator-(const NormObjectId& id) const
|
||||||
{
|
{return ((INT16)(value - id.value));}
|
||||||
int result = value - id.value;
|
|
||||||
return ((0 == (result & 0x00008000)) ?
|
|
||||||
(result & 0x0000ffff) :
|
|
||||||
(((result != 0x00008000) || (value < id.value)) ?
|
|
||||||
result | 0xffff0000 : result));
|
|
||||||
}
|
|
||||||
bool operator<(const NormObjectId& id) const
|
bool operator<(const NormObjectId& id) const
|
||||||
{return ((*this - id) < 0);}
|
{return (((short)(value - id.value)) < 0);}
|
||||||
bool operator>(const NormObjectId& id) const
|
bool operator>(const NormObjectId& id) const
|
||||||
{return ((*this - id) > 0);}
|
{return (((INT16)(value - id.value)) > 0);}
|
||||||
bool operator<=(const NormObjectId& id) const
|
bool operator<=(const NormObjectId& id) const
|
||||||
{return ((value == id.value) || (*this<id));}
|
{return ((value == id.value) || (*this<id));}
|
||||||
bool operator>=(const NormObjectId& id) const
|
bool operator>=(const NormObjectId& id) const
|
||||||
|
|
@ -187,7 +197,7 @@ class NormObjectId
|
||||||
{return (value == id.value);}
|
{return (value == id.value);}
|
||||||
bool operator!=(const NormObjectId& id) const
|
bool operator!=(const NormObjectId& id) const
|
||||||
{return (value != id.value);}
|
{return (value != id.value);}
|
||||||
NormObjectId& operator++(int ) {value++; return *this;}
|
NormObjectId& operator++(int) {value++; return *this;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UINT16 value;
|
UINT16 value;
|
||||||
|
|
@ -204,17 +214,17 @@ class NormBlockId
|
||||||
{return (value == (UINT32)id);}
|
{return (value == (UINT32)id);}
|
||||||
bool operator!=(const NormBlockId& id) const
|
bool operator!=(const NormBlockId& id) const
|
||||||
{return (value != (UINT32)id);}
|
{return (value != (UINT32)id);}
|
||||||
long operator-(const NormBlockId& id) const
|
INT32 operator-(const NormBlockId& id) const
|
||||||
{return ((long)value - id.value);}
|
{return ((INT32)value - id.value);}
|
||||||
bool operator<(const NormBlockId& id) const
|
bool operator<(const NormBlockId& id) const
|
||||||
{return ((*this - id) < 0);}
|
{return (((INT32)(value-id.value)) < 0);}
|
||||||
bool operator>(const NormBlockId& id) const
|
bool operator>(const NormBlockId& id) const
|
||||||
{return ((*this - id) > 0);}
|
{return (((INT32)(value-id.value)) > 0);}
|
||||||
NormBlockId& operator++(int ) {value++; return *this;}
|
NormBlockId& operator++(int ) {value++; return *this;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UINT32 value;
|
UINT32 value;
|
||||||
}; // end class NormObjectId
|
}; // end class NormBlockId
|
||||||
|
|
||||||
typedef UINT16 NormSymbolId;
|
typedef UINT16 NormSymbolId;
|
||||||
typedef NormSymbolId NormSegmentId;
|
typedef NormSymbolId NormSegmentId;
|
||||||
|
|
@ -361,7 +371,7 @@ class NormMsg
|
||||||
void ExtendHeaderLength(UINT16 len)
|
void ExtendHeaderLength(UINT16 len)
|
||||||
{
|
{
|
||||||
header_length += len;
|
header_length += len;
|
||||||
length = header_length;
|
length += len;
|
||||||
buffer[HDR_LEN_OFFSET] = header_length >> 2;
|
buffer[HDR_LEN_OFFSET] = header_length >> 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -624,6 +634,7 @@ class NormDataMsg : public NormObjectMsg
|
||||||
return (length - dataIndex);
|
return (length - dataIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// These routines are only applicable to messages containing NORM_OBJECT_STREAM content
|
// These routines are only applicable to messages containing NORM_OBJECT_STREAM content
|
||||||
// Some static helper routines for reading/writing embedded payload length/offsets
|
// Some static helper routines for reading/writing embedded payload length/offsets
|
||||||
static UINT16 GetStreamPayloadHeaderLength() {return (PAYLOAD_DATA_OFFSET);}
|
static UINT16 GetStreamPayloadHeaderLength() {return (PAYLOAD_DATA_OFFSET);}
|
||||||
|
|
@ -1049,7 +1060,7 @@ class NormRepairRequest
|
||||||
void SetForm(NormRepairRequest::Form theForm) {form = theForm;}
|
void SetForm(NormRepairRequest::Form theForm) {form = theForm;}
|
||||||
void ResetFlags() {flags = 0;}
|
void ResetFlags() {flags = 0;}
|
||||||
void SetFlag(NormRepairRequest::Flag theFlag) {flags |= theFlag;}
|
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)
|
// Returns length (each repair item requires 8 bytes of space)
|
||||||
bool AppendRepairItem(const NormObjectId& objectId,
|
bool AppendRepairItem(const NormObjectId& objectId,
|
||||||
|
|
@ -1417,6 +1428,7 @@ class NormAckMsg : public NormMsg
|
||||||
{
|
{
|
||||||
UINT16 len = MIN(payloadLen, segmentSize);
|
UINT16 len = MIN(payloadLen, segmentSize);
|
||||||
memcpy(buffer+header_length, payload, len);
|
memcpy(buffer+header_length, payload, len);
|
||||||
|
length += len;
|
||||||
return (payloadLen <= segmentSize);
|
return (payloadLen <= segmentSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1439,7 +1451,7 @@ class NormAckMsg : public NormMsg
|
||||||
UINT16 GetPayloadLength() const {return (length - header_length);}
|
UINT16 GetPayloadLength() const {return (length - header_length);}
|
||||||
const char* GetPayload() const {return (buffer + header_length);}
|
const char* GetPayload() const {return (buffer + header_length);}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
SERVER_ID_OFFSET = MSG_OFFSET,
|
SERVER_ID_OFFSET = MSG_OFFSET,
|
||||||
|
|
@ -1451,6 +1463,75 @@ class NormAckMsg : public NormMsg
|
||||||
};
|
};
|
||||||
}; // end class NormAckMsg
|
}; // 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
|
class NormReportMsg : public NormMsg
|
||||||
{
|
{
|
||||||
// (TBD)
|
// (TBD)
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -14,8 +14,10 @@ class NormNode
|
||||||
friend class NormNodeListIterator;
|
friend class NormNodeListIterator;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NormNode(class NormSession* theSession, NormNodeId nodeId);
|
NormNode(class NormSession& theSession, NormNodeId nodeId);
|
||||||
virtual ~NormNode();
|
virtual ~NormNode();
|
||||||
|
void Retain();
|
||||||
|
void Release();
|
||||||
|
|
||||||
const ProtoAddress& GetAddress() const {return addr;}
|
const ProtoAddress& GetAddress() const {return addr;}
|
||||||
void SetAddress(const ProtoAddress& address) {addr = address;}
|
void SetAddress(const ProtoAddress& address) {addr = address;}
|
||||||
|
|
@ -24,12 +26,13 @@ class NormNode
|
||||||
inline const NormNodeId& LocalNodeId() const;
|
inline const NormNodeId& LocalNodeId() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
class NormSession* session;
|
class NormSession& session;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NormNodeId id;
|
NormNodeId id;
|
||||||
ProtoAddress addr;
|
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* parent;
|
||||||
NormNode* right;
|
NormNode* right;
|
||||||
NormNode* left;
|
NormNode* left;
|
||||||
|
|
@ -137,11 +140,33 @@ class NormLossEstimator2
|
||||||
|
|
||||||
}; // end 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
|
class NormCCNode : public NormNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NormCCNode(class NormSession* theSession, NormNodeId nodeId);
|
NormCCNode(class NormSession& theSession, NormNodeId nodeId);
|
||||||
~NormCCNode();
|
~NormCCNode();
|
||||||
|
|
||||||
bool IsClr() const {return is_clr;}
|
bool IsClr() const {return is_clr;}
|
||||||
|
|
@ -182,9 +207,26 @@ class NormServerNode : public NormNode
|
||||||
public:
|
public:
|
||||||
enum ObjectStatus {OBJ_INVALID, OBJ_NEW, OBJ_PENDING, OBJ_COMPLETE};
|
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();
|
~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,
|
bool UpdateLossEstimate(const struct timeval& currentTime,
|
||||||
unsigned short theSequence,
|
unsigned short theSequence,
|
||||||
bool ecnStatus = false);
|
bool ecnStatus = false);
|
||||||
|
|
@ -201,10 +243,15 @@ class NormServerNode : public NormNode
|
||||||
void HandleNackMessage(const NormNackMsg& nack);
|
void HandleNackMessage(const NormNackMsg& nack);
|
||||||
void HandleAckMessage(const NormAckMsg& ack);
|
void HandleAckMessage(const NormAckMsg& ack);
|
||||||
|
|
||||||
bool Open(UINT16 sessionId, UINT16 segmentSize, UINT16 numData, UINT16 numParity);
|
bool Open(UINT16 sessionId);
|
||||||
void Activate();
|
UINT16 GetSessionId() {return session_id;}
|
||||||
void Close();
|
|
||||||
bool IsOpen() const {return is_open;}
|
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;
|
bool SyncTest(const NormObjectMsg& msg) const;
|
||||||
void Sync(NormObjectId objectId);
|
void Sync(NormObjectId objectId);
|
||||||
|
|
@ -234,7 +281,7 @@ class NormServerNode : public NormNode
|
||||||
}
|
}
|
||||||
void SetPending(NormObjectId objectId);
|
void SetPending(NormObjectId objectId);
|
||||||
|
|
||||||
void DeleteObject(NormObject* obj);
|
void DeleteObject(NormObject* obj, int which);
|
||||||
|
|
||||||
UINT16 SegmentSize() {return segment_size;}
|
UINT16 SegmentSize() {return segment_size;}
|
||||||
UINT16 BlockSize() {return ndata;}
|
UINT16 BlockSize() {return ndata;}
|
||||||
|
|
@ -287,6 +334,9 @@ class NormServerNode : public NormNode
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool PassiveRepairCheck(NormObjectId objectId,
|
||||||
|
NormBlockId blockId,
|
||||||
|
NormSegmentId segmentId);
|
||||||
void RepairCheck(NormObject::CheckLevel checkLevel,
|
void RepairCheck(NormObject::CheckLevel checkLevel,
|
||||||
NormObjectId objectId,
|
NormObjectId objectId,
|
||||||
NormBlockId blockId,
|
NormBlockId blockId,
|
||||||
|
|
@ -295,12 +345,18 @@ class NormServerNode : public NormNode
|
||||||
bool OnActivityTimeout(ProtoTimer& theTimer);
|
bool OnActivityTimeout(ProtoTimer& theTimer);
|
||||||
bool OnRepairTimeout(ProtoTimer& theTimer);
|
bool OnRepairTimeout(ProtoTimer& theTimer);
|
||||||
bool OnCCTimeout(ProtoTimer& theTimer);
|
bool OnCCTimeout(ProtoTimer& theTimer);
|
||||||
|
bool OnAckTimeout(ProtoTimer& theTimer);
|
||||||
|
|
||||||
|
void AttachCCFeedback(NormAckMsg& ack);
|
||||||
void HandleRepairContent(const char* buffer, UINT16 bufferLen);
|
void HandleRepairContent(const char* buffer, UINT16 bufferLen);
|
||||||
|
|
||||||
UINT16 session_id;
|
UINT16 session_id;
|
||||||
bool synchronized;
|
bool synchronized;
|
||||||
NormObjectId sync_id; // only valid if(synchronized)
|
NormObjectId sync_id; // only valid if(synchronized)
|
||||||
NormObjectId next_id; // only valid if(synchronized)
|
NormObjectId next_id; // only valid if(synchronized)
|
||||||
|
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;
|
bool is_open;
|
||||||
UINT16 segment_size;
|
UINT16 segment_size;
|
||||||
|
|
@ -310,15 +366,23 @@ class NormServerNode : public NormNode
|
||||||
NormObjectTable rx_table;
|
NormObjectTable rx_table;
|
||||||
NormSlidingMask rx_pending_mask;
|
NormSlidingMask rx_pending_mask;
|
||||||
NormSlidingMask rx_repair_mask;
|
NormSlidingMask rx_repair_mask;
|
||||||
|
RepairBoundary repair_boundary;
|
||||||
|
NormObject::NackingMode default_nacking_mode;
|
||||||
|
bool unicast_nacks;
|
||||||
NormBlockPool block_pool;
|
NormBlockPool block_pool;
|
||||||
NormSegmentPool segment_pool;
|
NormSegmentPool segment_pool;
|
||||||
NormDecoder decoder;
|
NormDecoder decoder;
|
||||||
UINT16* erasure_loc;
|
UINT16* erasure_loc;
|
||||||
|
|
||||||
|
bool server_active;
|
||||||
ProtoTimer activity_timer;
|
ProtoTimer activity_timer;
|
||||||
ProtoTimer repair_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
|
// Remote server grtt measurement state
|
||||||
double grtt_estimate;
|
double grtt_estimate;
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -14,6 +14,7 @@ class NormObject
|
||||||
public:
|
public:
|
||||||
enum Type
|
enum Type
|
||||||
{
|
{
|
||||||
|
NONE,
|
||||||
DATA,
|
DATA,
|
||||||
FILE,
|
FILE,
|
||||||
STREAM
|
STREAM
|
||||||
|
|
@ -21,6 +22,7 @@ class NormObject
|
||||||
|
|
||||||
enum CheckLevel
|
enum CheckLevel
|
||||||
{
|
{
|
||||||
|
TO_OBJECT,
|
||||||
THRU_INFO,
|
THRU_INFO,
|
||||||
TO_BLOCK,
|
TO_BLOCK,
|
||||||
THRU_SEGMENT,
|
THRU_SEGMENT,
|
||||||
|
|
@ -28,7 +30,21 @@ class NormObject
|
||||||
THRU_OBJECT
|
THRU_OBJECT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum NackingMode
|
||||||
|
{
|
||||||
|
NACK_NONE,
|
||||||
|
NACK_INFO_ONLY,
|
||||||
|
NACK_NORMAL
|
||||||
|
};
|
||||||
|
|
||||||
virtual ~NormObject();
|
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
|
// Object information
|
||||||
NormObject::Type GetType() const {return type;}
|
NormObject::Type GetType() const {return type;}
|
||||||
|
|
@ -39,19 +55,33 @@ class NormObject
|
||||||
UINT16 GetInfoLength() const {return info_len;}
|
UINT16 GetInfoLength() const {return info_len;}
|
||||||
bool IsStream() const {return (STREAM == type);}
|
bool IsStream() const {return (STREAM == type);}
|
||||||
|
|
||||||
|
class NormSession& GetSession() const {return session;}
|
||||||
NormNodeId LocalNodeId() const;
|
NormNodeId LocalNodeId() const;
|
||||||
class NormServerNode* GetServer() {return server;}
|
class NormServerNode* GetServer() const {return server;}
|
||||||
|
NormNodeId GetServerNodeId() const;
|
||||||
|
|
||||||
bool IsOpen() {return (0 != segment_size);}
|
bool IsOpen() {return (0 != segment_size);}
|
||||||
// Opens (inits) object for tx operation
|
// Opens (inits) object for tx operation
|
||||||
bool Open(const NormObjectSize& objectSize,
|
bool Open(const NormObjectSize& objectSize,
|
||||||
const char* infoPtr,
|
const char* infoPtr,
|
||||||
UINT16 infoLen);
|
UINT16 infoLen,
|
||||||
|
UINT16 segmentSize,
|
||||||
|
UINT16 numData,
|
||||||
|
UINT16 numParity);
|
||||||
// Opens (inits) object for rx operation
|
// Opens (inits) object for rx operation
|
||||||
bool Open(const NormObjectSize& objectSize, bool hasInfo)
|
bool Open(const NormObjectSize& objectSize,
|
||||||
{return Open(objectSize, (char*)NULL, hasInfo ? 1 : 0);}
|
bool hasInfo,
|
||||||
|
UINT16 segmentSize,
|
||||||
|
UINT16 numData,
|
||||||
|
UINT16 numParity)
|
||||||
|
{
|
||||||
|
return Open(objectSize, (char*)NULL, hasInfo ? 1 : 0,
|
||||||
|
segmentSize, numData, numParity);
|
||||||
|
}
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool WriteSegment(NormBlockId blockId,
|
virtual bool WriteSegment(NormBlockId blockId,
|
||||||
NormSegmentId segmentId,
|
NormSegmentId segmentId,
|
||||||
const char* buffer) = 0;
|
const char* buffer) = 0;
|
||||||
|
|
@ -59,9 +89,17 @@ class NormObject
|
||||||
NormSegmentId segmentId,
|
NormSegmentId segmentId,
|
||||||
char* buffer) = 0;
|
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
|
// These are only valid after object is open
|
||||||
NormBlockId GetFinalBlockId() const {return final_block_id;}
|
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 :
|
return (((UINT32)blockId < large_block_count) ? large_block_size :
|
||||||
small_block_size);
|
small_block_size);
|
||||||
|
|
@ -114,6 +152,7 @@ class NormObject
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FindRepairIndex(NormBlockId& blockId, NormSegmentId& segmentId) const;
|
||||||
|
|
||||||
// Methods available to server for transmission
|
// Methods available to server for transmission
|
||||||
bool NextServerMsg(NormObjectMsg* msg);
|
bool NextServerMsg(NormObjectMsg* msg);
|
||||||
|
|
@ -141,6 +180,7 @@ class NormObject
|
||||||
NormBlock* FindBlock(NormBlockId blockId) {return block_buffer.Find(blockId);}
|
NormBlock* FindBlock(NormBlockId blockId) {return block_buffer.Find(blockId);}
|
||||||
bool ActivateRepairs();
|
bool ActivateRepairs();
|
||||||
bool IsRepairSet(NormBlockId blockId) {return repair_mask.Test(blockId);}
|
bool IsRepairSet(NormBlockId blockId) {return repair_mask.Test(blockId);}
|
||||||
|
bool IsPendingSet(NormBlockId blockId) {return pending_mask.Test(blockId);}
|
||||||
bool AppendRepairAdv(NormCmdRepairAdvMsg& cmd);
|
bool AppendRepairAdv(NormCmdRepairAdvMsg& cmd);
|
||||||
|
|
||||||
NormBlockId GetMaxPendingBlockId() const {return max_pending_block;}
|
NormBlockId GetMaxPendingBlockId() const {return max_pending_block;}
|
||||||
|
|
@ -161,7 +201,8 @@ class NormObject
|
||||||
// Used by receiver for resource management scheme
|
// Used by receiver for resource management scheme
|
||||||
NormBlock* StealNewestBlock(bool excludeBlock, NormBlockId excludeId = 0);
|
NormBlock* StealNewestBlock(bool excludeBlock, NormBlockId excludeId = 0);
|
||||||
NormBlock* StealOldestBlock(bool excludeBlock, NormBlockId excludeId = 0);
|
NormBlock* StealOldestBlock(bool excludeBlock, NormBlockId excludeId = 0);
|
||||||
|
bool PassiveRepairCheck(NormBlockId blockId,
|
||||||
|
NormSegmentId segmentId);
|
||||||
bool ClientRepairCheck(CheckLevel level,
|
bool ClientRepairCheck(CheckLevel level,
|
||||||
NormBlockId blockId,
|
NormBlockId blockId,
|
||||||
NormSegmentId segmentId,
|
NormSegmentId segmentId,
|
||||||
|
|
@ -178,15 +219,16 @@ class NormObject
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NormObject(Type theType,
|
NormObject(Type theType,
|
||||||
class NormSession* theSession,
|
class NormSession& theSession,
|
||||||
class NormServerNode* theServer,
|
class NormServerNode* theServer,
|
||||||
const NormObjectId& objectId);
|
const NormObjectId& objectId);
|
||||||
|
|
||||||
void Accept() {accepted = true;}
|
void Accept() {accepted = true;}
|
||||||
|
|
||||||
NormObject::Type type;
|
NormObject::Type type;
|
||||||
class NormSession* session;
|
class NormSession& session;
|
||||||
class NormServerNode* server; // NULL value indicates local (tx) object
|
class NormServerNode* server; // NULL value indicates local (tx) object
|
||||||
|
unsigned int reference_count;
|
||||||
NormObjectId transport_id;
|
NormObjectId transport_id;
|
||||||
|
|
||||||
NormObjectSize object_size;
|
NormObjectSize object_size;
|
||||||
|
|
@ -194,9 +236,9 @@ class NormObject
|
||||||
UINT16 ndata;
|
UINT16 ndata;
|
||||||
UINT16 nparity;
|
UINT16 nparity;
|
||||||
NormBlockBuffer block_buffer;
|
NormBlockBuffer block_buffer;
|
||||||
bool pending_info;
|
bool pending_info; // set when we need to send or recv info
|
||||||
NormSlidingMask pending_mask;
|
NormSlidingMask pending_mask;
|
||||||
bool repair_info;
|
bool repair_info; // client: set when
|
||||||
NormSlidingMask repair_mask;
|
NormSlidingMask repair_mask;
|
||||||
NormBlockId current_block_id; // for suppression
|
NormBlockId current_block_id; // for suppression
|
||||||
NormSegmentId next_segment_id; // for suppression
|
NormSegmentId next_segment_id; // for suppression
|
||||||
|
|
@ -208,11 +250,14 @@ class NormObject
|
||||||
UINT32 small_block_size;
|
UINT32 small_block_size;
|
||||||
NormBlockId final_block_id;
|
NormBlockId final_block_id;
|
||||||
UINT16 final_segment_size;
|
UINT16 final_segment_size;
|
||||||
|
NackingMode nacking_mode;
|
||||||
char* info;
|
char* info;
|
||||||
UINT16 info_len;
|
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 accepted;
|
||||||
|
bool notify_on_update;
|
||||||
|
|
||||||
NormObject* next;
|
NormObject* next;
|
||||||
}; // end class NormObject
|
}; // end class NormObject
|
||||||
|
|
@ -221,7 +266,7 @@ class NormObject
|
||||||
class NormFileObject : public NormObject
|
class NormFileObject : public NormObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NormFileObject(class NormSession* theSession,
|
NormFileObject(class NormSession& theSession,
|
||||||
class NormServerNode* theServer,
|
class NormServerNode* theServer,
|
||||||
const NormObjectId& objectId);
|
const NormObjectId& objectId);
|
||||||
~NormFileObject();
|
~NormFileObject();
|
||||||
|
|
@ -231,7 +276,8 @@ class NormFileObject : public NormObject
|
||||||
UINT16 infoLen = 0);
|
UINT16 infoLen = 0);
|
||||||
bool Accept(const char* thePath);
|
bool Accept(const char* thePath);
|
||||||
void Close();
|
void Close();
|
||||||
const char* Path() {return path;}
|
|
||||||
|
const char* GetPath() {return path;}
|
||||||
bool Rename(const char* newPath)
|
bool Rename(const char* newPath)
|
||||||
{
|
{
|
||||||
bool result = file.Rename(path, newPath);
|
bool result = file.Rename(path, newPath);
|
||||||
|
|
@ -254,11 +300,44 @@ class NormFileObject : public NormObject
|
||||||
NormObjectSize small_block_length;
|
NormObjectSize small_block_length;
|
||||||
}; // end class NormFileObject
|
}; // 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
|
class NormStreamObject : public NormObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NormStreamObject(class NormSession* theSession,
|
NormStreamObject(class NormSession& theSession,
|
||||||
class NormServerNode* theServer,
|
class NormServerNode* theServer,
|
||||||
const NormObjectId& objectId);
|
const NormObjectId& objectId);
|
||||||
~NormStreamObject();
|
~NormStreamObject();
|
||||||
|
|
@ -269,19 +348,35 @@ class NormStreamObject : public NormObject
|
||||||
void Close();
|
void Close();
|
||||||
bool Accept(UINT32 bufferSize);
|
bool Accept(UINT32 bufferSize);
|
||||||
|
|
||||||
enum FlushType
|
enum FlushMode
|
||||||
{
|
{
|
||||||
FLUSH_NONE, // no flush action taken
|
FLUSH_NONE, // no flush action taken
|
||||||
FLUSH_PASSIVE, // pending queued data is transmitted, but no CMD(FLUSH) sent
|
FLUSH_PASSIVE, // pending queued data is transmitted, but no CMD(FLUSH) sent
|
||||||
FLUSH_ACTIVE // pending queued data is transmitted, _and_ active CMD(FLUSH)
|
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);
|
bool StreamUpdateStatus(NormBlockId blockId);
|
||||||
void StreamResync(NormBlockId nextBlockId)
|
void StreamResync(NormBlockId nextBlockId)
|
||||||
{stream_next_id = nextBlockId;}
|
{
|
||||||
|
stream_next_id = nextBlockId;
|
||||||
|
}
|
||||||
void StreamAdvance();
|
void StreamAdvance();
|
||||||
|
|
||||||
virtual bool WriteSegment(NormBlockId blockId,
|
virtual bool WriteSegment(NormBlockId blockId,
|
||||||
|
|
@ -309,6 +404,10 @@ class NormStreamObject : public NormObject
|
||||||
{return (write_index.segment ? (write_index.segment-1) :
|
{return (write_index.segment ? (write_index.segment-1) :
|
||||||
(ndata-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:
|
private:
|
||||||
class Index
|
class Index
|
||||||
{
|
{
|
||||||
|
|
@ -320,6 +419,8 @@ class NormStreamObject : public NormObject
|
||||||
bool stream_sync;
|
bool stream_sync;
|
||||||
NormBlockId stream_sync_id;
|
NormBlockId stream_sync_id;
|
||||||
NormBlockId stream_next_id;
|
NormBlockId stream_next_id;
|
||||||
|
UINT32 sync_offset;
|
||||||
|
bool sync_offset_valid;
|
||||||
|
|
||||||
NormBlockPool block_pool;
|
NormBlockPool block_pool;
|
||||||
NormSegmentPool segment_pool;
|
NormSegmentPool segment_pool;
|
||||||
|
|
@ -330,6 +431,8 @@ class NormStreamObject : public NormObject
|
||||||
UINT32 read_offset;
|
UINT32 read_offset;
|
||||||
bool flush_pending;
|
bool flush_pending;
|
||||||
bool msg_start;
|
bool msg_start;
|
||||||
|
FlushMode flush_mode;
|
||||||
|
bool push_mode;
|
||||||
}; // end class NormStreamObject
|
}; // end class NormStreamObject
|
||||||
|
|
||||||
#ifdef SIMULATE
|
#ifdef SIMULATE
|
||||||
|
|
@ -338,7 +441,7 @@ class NormStreamObject : public NormObject
|
||||||
class NormSimObject : public NormObject
|
class NormSimObject : public NormObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NormSimObject(class NormSession* theSession,
|
NormSimObject(class NormSession& theSession,
|
||||||
class NormServerNode* theServer,
|
class NormServerNode* theServer,
|
||||||
const NormObjectId& objectId);
|
const NormObjectId& objectId);
|
||||||
~NormSimObject();
|
~NormSimObject();
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,6 @@ void NormPostProcessor::GetCommand(char* buffer, unsigned int buflen)
|
||||||
|
|
||||||
bool NormPostProcessor::SetCommand(const char* cmd)
|
bool NormPostProcessor::SetCommand(const char* cmd)
|
||||||
{
|
{
|
||||||
|
|
||||||
// 1) Delete old command resources
|
// 1) Delete old command resources
|
||||||
if (process_argv)
|
if (process_argv)
|
||||||
{
|
{
|
||||||
|
|
@ -81,10 +80,10 @@ bool NormPostProcessor::SetCommand(const char* cmd)
|
||||||
{
|
{
|
||||||
argCount++;
|
argCount++;
|
||||||
while (!isspace(*ptr) && ('\0' != *ptr)) ptr++;
|
while (!isspace(*ptr) && ('\0' != *ptr)) ptr++;
|
||||||
|
while (isspace(*ptr) && ('\0' != *ptr)) ptr++;
|
||||||
}
|
}
|
||||||
if (!argCount) return true; // post processing disabled
|
if (!argCount) return true; // post processing disabled
|
||||||
|
|
||||||
|
|
||||||
// 3) Allocate new process_argv array (2 extra slots, one for "target",
|
// 3) Allocate new process_argv array (2 extra slots, one for "target",
|
||||||
// and one for terminating NULL pointer.
|
// and one for terminating NULL pointer.
|
||||||
if (!(process_argv = new char*[argCount+2]))
|
if (!(process_argv = new char*[argCount+2]))
|
||||||
|
|
@ -115,7 +114,8 @@ bool NormPostProcessor::SetCommand(const char* cmd)
|
||||||
}
|
}
|
||||||
strncpy(arg, argStart, argLength);
|
strncpy(arg, argStart, argLength);
|
||||||
arg[argLength] = '\0';
|
arg[argLength] = '\0';
|
||||||
process_argv[index] = arg;
|
process_argv[index++] = arg;
|
||||||
|
while (isspace(*ptr) && ('\0' != *ptr)) ptr++;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} // end NormPostProcessor::SetCommand()
|
} // end NormPostProcessor::SetCommand()
|
||||||
|
|
|
||||||
|
|
@ -257,6 +257,7 @@ bool NormBlock::ActivateRepairs(UINT16 numParity)
|
||||||
if (repair_mask.IsSet())
|
if (repair_mask.IsSet())
|
||||||
{
|
{
|
||||||
pending_mask.Add(repair_mask);
|
pending_mask.Add(repair_mask);
|
||||||
|
ASSERT(pending_mask.IsSet());
|
||||||
repair_mask.Clear();
|
repair_mask.Clear();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -390,7 +391,7 @@ bool NormBlock::HandleSegmentRequest(NormSegmentId nextId, NormSegmentId lastId,
|
||||||
return increasedRepair;
|
return increasedRepair;
|
||||||
} // end NormBlock::HandleSegmentRequest()
|
} // end NormBlock::HandleSegmentRequest()
|
||||||
|
|
||||||
|
// (TBD) this should return true is something is appending, false otherwise
|
||||||
bool NormBlock::AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
|
bool NormBlock::AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
|
||||||
NormObjectId objectId,
|
NormObjectId objectId,
|
||||||
bool repairInfo,
|
bool repairInfo,
|
||||||
|
|
@ -433,7 +434,13 @@ bool NormBlock::AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
|
||||||
if (form != prevForm)
|
if (form != prevForm)
|
||||||
{
|
{
|
||||||
if (NormRepairRequest::INVALID != 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);
|
req.SetForm(form);
|
||||||
cmd.AttachRepairRequest(req, segmentSize); // (TBD) error check
|
cmd.AttachRepairRequest(req, segmentSize); // (TBD) error check
|
||||||
prevForm = form;
|
prevForm = form;
|
||||||
|
|
@ -460,12 +467,16 @@ bool NormBlock::AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
|
||||||
}
|
}
|
||||||
} // end while (nextId < totalSize)
|
} // end while (nextId < totalSize)
|
||||||
if (NormRepairRequest::INVALID != prevForm)
|
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;
|
return true;
|
||||||
} // end NormBlock::AppendRepairAdv()
|
} // end NormBlock::AppendRepairAdv()
|
||||||
|
|
||||||
// Called by client
|
// Called by client
|
||||||
|
// (TBD) this should return true iff something appended, false otherwise
|
||||||
bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
|
bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
|
||||||
UINT16 numData,
|
UINT16 numData,
|
||||||
UINT16 numParity,
|
UINT16 numParity,
|
||||||
|
|
@ -527,7 +538,13 @@ bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
|
||||||
if (form != prevForm)
|
if (form != prevForm)
|
||||||
{
|
{
|
||||||
if (NormRepairRequest::INVALID != 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
|
nack.AttachRepairRequest(req, segmentSize); // (TBD) error check
|
||||||
req.SetForm(form);
|
req.SetForm(form);
|
||||||
prevForm = form;
|
prevForm = form;
|
||||||
|
|
@ -554,76 +571,10 @@ bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
|
||||||
}
|
}
|
||||||
} // end while (nextId < lastId)
|
} // end while (nextId < lastId)
|
||||||
if (NormRepairRequest::INVALID != prevForm)
|
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 (0 == nack.PackRepairRequest(req))
|
||||||
if (nextId == lastId) nextId++;
|
DMSG(0, "NormBlock::AppendRepairRequest() warning: full NACK msg\n");
|
||||||
if (segmentCount && (segmentCount == (nextId - prevId)))
|
|
||||||
{
|
|
||||||
segmentCount++; // consecutive series continues
|
|
||||||
}
|
}
|
||||||
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;
|
return true;
|
||||||
} // end NormBlock::AppendRepairRequest()
|
} // end NormBlock::AppendRepairRequest()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,15 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
|
||||||
: session_mgr(sessionMgr), notify_pending(false),
|
: session_mgr(sessionMgr), notify_pending(false),
|
||||||
tx_socket(ProtoSocket::UDP), rx_socket(ProtoSocket::UDP),
|
tx_socket(ProtoSocket::UDP), rx_socket(ProtoSocket::UDP),
|
||||||
local_node_id(localNodeId),
|
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),
|
backoff_factor(DEFAULT_BACKOFF_FACTOR), is_server(false), session_id(0),
|
||||||
ndata(DEFAULT_NDATA), nparity(DEFAULT_NPARITY), auto_parity(0), extra_parity(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),
|
next_tx_object_id(0), tx_cache_count_min(8), tx_cache_count_max(256),
|
||||||
tx_cache_size_max((UINT32)20*1024*1024),
|
tx_cache_size_max((UINT32)20*1024*1024),
|
||||||
flush_count(NORM_ROBUST_FACTOR+1),
|
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),
|
suppress_nonconfirmed(false), suppress_rate(-1.0), suppress_rtt(-1.0),
|
||||||
probe_proactive(true), probe_pending(false), probe_reset(false),
|
probe_proactive(true), probe_pending(false), probe_reset(false),
|
||||||
grtt_interval(0.5),
|
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),
|
grtt_response(false), grtt_current_peak(0.0), grtt_age(0.0),
|
||||||
cc_enable(false), cc_sequence(0), cc_slow_start(true),
|
cc_enable(false), cc_sequence(0), cc_slow_start(true),
|
||||||
is_client(false), unicast_nacks(false), client_silent(false),
|
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),
|
trace(false), tx_loss_rate(0.0), rx_loss_rate(0.0),
|
||||||
next(NULL)
|
next(NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -73,7 +77,7 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
|
||||||
// (It may be used to trigger transmission of report messages
|
// (It may be used to trigger transmission of report messages
|
||||||
// in the future for debugging, etc
|
// in the future for debugging, etc
|
||||||
report_timer.SetListener(this, &NormSession::OnReportTimeout);
|
report_timer.SetListener(this, &NormSession::OnReportTimeout);
|
||||||
report_timer.SetInterval(60.0);
|
report_timer.SetInterval(10.0);
|
||||||
report_timer.SetRepeat(-1);
|
report_timer.SetRepeat(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,6 +90,7 @@ NormSession::~NormSession()
|
||||||
bool NormSession::Open(const char* interfaceName)
|
bool NormSession::Open(const char* interfaceName)
|
||||||
{
|
{
|
||||||
ASSERT(address.IsValid());
|
ASSERT(address.IsValid());
|
||||||
|
// (TBD) support single socket option
|
||||||
if (!tx_socket.IsOpen())
|
if (!tx_socket.IsOpen())
|
||||||
{
|
{
|
||||||
if (!tx_socket.Open())
|
if (!tx_socket.Open())
|
||||||
|
|
@ -118,6 +123,12 @@ bool NormSession::Open(const char* interfaceName)
|
||||||
Close();
|
Close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!tx_socket.SetLoopback(loopback))
|
||||||
|
{
|
||||||
|
DMSG(0, "NormSession::Open() tx_socket set loopback error\n");
|
||||||
|
Close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (interfaceName)
|
if (interfaceName)
|
||||||
{
|
{
|
||||||
rx_socket.SetMulticastInterface(interfaceName);
|
rx_socket.SetMulticastInterface(interfaceName);
|
||||||
|
|
@ -160,7 +171,33 @@ void NormSession::Close()
|
||||||
} // end 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 segmentSize,
|
||||||
UINT16 numData,
|
UINT16 numData,
|
||||||
UINT16 numParity,
|
UINT16 numParity,
|
||||||
|
|
@ -284,30 +321,108 @@ void NormSession::Serve()
|
||||||
// Only send new data when no other messages are queued for transmission
|
// Only send new data when no other messages are queued for transmission
|
||||||
if (!message_queue.IsEmpty()) return;
|
if (!message_queue.IsEmpty()) return;
|
||||||
|
|
||||||
NormObject* obj = NULL;
|
|
||||||
// Queue next server message
|
// Queue next server message
|
||||||
NormObjectId objectId;
|
NormObjectId objectId;
|
||||||
|
NormObject* obj = NULL;
|
||||||
if (ServerGetFirstPending(objectId))
|
if (ServerGetFirstPending(objectId))
|
||||||
{
|
{
|
||||||
obj = tx_table.Find(objectId);
|
obj = tx_table.Find(objectId);
|
||||||
ASSERT(obj);
|
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
|
else
|
||||||
{
|
{
|
||||||
if (!posted_tx_queue_empty)
|
// info only pending; so blockId = segmentId = 0 (as inited)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
posted_tx_queue_empty = true;
|
// Must be an active, but non-pending stream object
|
||||||
Notify(NormController::TX_QUEUE_EMPTY,
|
nextBlockId = static_cast<NormStreamObject*>(nextObj)->GetNextBlockId();
|
||||||
(NormServerNode*)NULL,
|
nextSegmentId = static_cast<NormStreamObject*>(nextObj)->GetNextSegmentId();
|
||||||
(NormObject*)NULL);
|
}
|
||||||
// (TBD) Was session deleted?
|
}
|
||||||
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} // end if (watermark_pending)
|
||||||
|
|
||||||
if (obj)
|
if (obj)
|
||||||
{
|
{
|
||||||
|
|
||||||
NormObjectMsg* msg = (NormObjectMsg*)GetMessageFromPool();
|
NormObjectMsg* msg = (NormObjectMsg*)GetMessageFromPool();
|
||||||
if (msg)
|
if (msg)
|
||||||
{
|
{
|
||||||
|
|
@ -319,7 +434,7 @@ void NormSession::Serve()
|
||||||
msg->SetGroupSize(gsize_quantized);
|
msg->SetGroupSize(gsize_quantized);
|
||||||
QueueMessage(msg);
|
QueueMessage(msg);
|
||||||
flush_count = 0;
|
flush_count = 0;
|
||||||
if (flush_timer.IsActive()) flush_timer.Deactivate();
|
//if (flush_timer.IsActive()) flush_timer.Deactivate();
|
||||||
if (!obj->IsPending())
|
if (!obj->IsPending())
|
||||||
{
|
{
|
||||||
if (obj->IsStream())
|
if (obj->IsStream())
|
||||||
|
|
@ -333,25 +448,35 @@ void NormSession::Serve()
|
||||||
ReturnMessageToPool(msg);
|
ReturnMessageToPool(msg);
|
||||||
if (obj->IsStream())
|
if (obj->IsStream())
|
||||||
{
|
{
|
||||||
NormStreamObject* stream = (NormStreamObject*)obj;
|
NormStreamObject* stream = static_cast<NormStreamObject*>(obj);
|
||||||
if (stream->IsFlushPending() &&
|
if (stream->IsFlushPending())
|
||||||
(flush_count < NORM_ROBUST_FACTOR))
|
|
||||||
{
|
{
|
||||||
// Queue flush message
|
// Queue flush message
|
||||||
|
if (!flush_timer.IsActive())
|
||||||
|
if (flush_count < NORM_ROBUST_FACTOR)
|
||||||
|
{
|
||||||
ServerQueueFlush();
|
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)
|
if (!posted_tx_queue_empty)
|
||||||
{
|
{
|
||||||
posted_tx_queue_empty = true;
|
posted_tx_queue_empty = true;
|
||||||
Notify(NormController::TX_QUEUE_EMPTY, (NormServerNode*)NULL, obj);
|
Notify(NormController::TX_QUEUE_EMPTY, (NormServerNode*)NULL, obj);
|
||||||
// (TBD) Was session deleted?
|
// (TBD) Was session deleted?
|
||||||
|
//Serve();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DMSG(0, "NormSession::Serve() pending non-stream obj, no message?.\n");
|
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());
|
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
|
// Queue flush message
|
||||||
ServerQueueFlush();
|
ServerQueueFlush();
|
||||||
|
|
@ -372,8 +510,123 @@ void NormSession::Serve()
|
||||||
LocalNodeId());
|
LocalNodeId());
|
||||||
flush_count++;
|
flush_count++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} // end NormSession::Serve()
|
} // 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()
|
void NormSession::ServerQueueFlush()
|
||||||
{
|
{
|
||||||
// (TBD) Deal with EOT or pre-queued squelch on squelch case
|
// (TBD) Deal with EOT or pre-queued squelch on squelch case
|
||||||
|
|
@ -400,6 +653,7 @@ void NormSession::ServerQueueFlush()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Why did I do this? - Brian
|
||||||
// (TBD) send NORM_CMD(EOT) instead?
|
// (TBD) send NORM_CMD(EOT) instead?
|
||||||
if (ServerQueueSquelch(next_tx_object_id))
|
if (ServerQueueSquelch(next_tx_object_id))
|
||||||
{
|
{
|
||||||
|
|
@ -424,22 +678,22 @@ void NormSession::ServerQueueFlush()
|
||||||
flush->SetFecSymbolId(segmentId);
|
flush->SetFecSymbolId(segmentId);
|
||||||
QueueMessage(flush);
|
QueueMessage(flush);
|
||||||
flush_count++;
|
flush_count++;
|
||||||
flush_timer.SetInterval(2*grtt_advertised);
|
DMSG(0, "NormSession::ServerQueueFlush() node>%lu, flush queued (flush_count:%u)...\n",
|
||||||
ActivateTimer(flush_timer);
|
|
||||||
DMSG(8, "NormSession::ServerQueueFlush() node>%lu, flush queued (flush_count:%u)...\n",
|
|
||||||
LocalNodeId(), flush_count);
|
LocalNodeId(), flush_count);
|
||||||
}
|
}
|
||||||
else
|
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());
|
LocalNodeId());
|
||||||
}
|
}
|
||||||
|
flush_timer.SetInterval(2*grtt_advertised);
|
||||||
|
ActivateTimer(flush_timer);
|
||||||
} // end NormSession::ServerQueueFlush()
|
} // end NormSession::ServerQueueFlush()
|
||||||
|
|
||||||
bool NormSession::OnFlushTimeout(ProtoTimer& /*theTimer*/)
|
bool NormSession::OnFlushTimeout(ProtoTimer& /*theTimer*/)
|
||||||
{
|
{
|
||||||
flush_timer.Deactivate();
|
flush_timer.Deactivate();
|
||||||
Serve(); // (TBD) Change this to PromptServer() ??
|
PromptServer();//Serve(); // (TBD) Change this to PromptServer() ??
|
||||||
return false;
|
return false;
|
||||||
} // NormSession::OnFlushTimeout()
|
} // NormSession::OnFlushTimeout()
|
||||||
|
|
||||||
|
|
@ -459,12 +713,12 @@ void NormSession::QueueMessage(NormMsg* msg)
|
||||||
}
|
}
|
||||||
lastTime = currentTime;
|
lastTime = currentTime;
|
||||||
*/
|
*/
|
||||||
if (!tx_timer.IsActive())
|
if (!tx_timer.IsActive() && (tx_rate > 0.0))
|
||||||
{
|
{
|
||||||
tx_timer.SetInterval(0.0);
|
tx_timer.SetInterval(0.0);
|
||||||
ActivateTimer(tx_timer);
|
ActivateTimer(tx_timer);
|
||||||
}
|
}
|
||||||
message_queue.Append(msg);
|
if (msg) message_queue.Append(msg);
|
||||||
} // end NormSesssion::QueueMessage(NormMsg& 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");
|
DMSG(0, "NormSession::QueueTxFile() Error: server is closed\n");
|
||||||
return NULL;
|
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)
|
if (!file)
|
||||||
{
|
{
|
||||||
DMSG(0, "NormSession::QueueTxFile() new file object error: %s\n",
|
DMSG(0, "NormSession::QueueTxFile() new file object error: %s\n",
|
||||||
|
|
@ -491,7 +745,7 @@ NormFileObject* NormSession::QueueTxFile(const char* path,
|
||||||
delete file;
|
delete file;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (QueueTxObject(file, false))
|
if (QueueTxObject(file))
|
||||||
{
|
{
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
@ -503,6 +757,42 @@ NormFileObject* NormSession::QueueTxFile(const char* path,
|
||||||
}
|
}
|
||||||
} // end NormSession::QueueTxFile()
|
} // 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,
|
NormStreamObject* NormSession::QueueTxStream(UINT32 bufferSize,
|
||||||
const char* infoPtr,
|
const char* infoPtr,
|
||||||
UINT16 infoLen)
|
UINT16 infoLen)
|
||||||
|
|
@ -512,7 +802,7 @@ NormStreamObject* NormSession::QueueTxStream(UINT32 bufferSize,
|
||||||
DMSG(0, "NormSession::QueueTxStream() Error: server is closed\n");
|
DMSG(0, "NormSession::QueueTxStream() Error: server is closed\n");
|
||||||
return NULL;
|
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)
|
if (!stream)
|
||||||
{
|
{
|
||||||
DMSG(0, "NormSession::QueueTxStream() new stream object error: %s\n",
|
DMSG(0, "NormSession::QueueTxStream() new stream object error: %s\n",
|
||||||
|
|
@ -525,7 +815,7 @@ NormStreamObject* NormSession::QueueTxStream(UINT32 bufferSize,
|
||||||
delete stream;
|
delete stream;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (QueueTxObject(stream, true))
|
if (QueueTxObject(stream))
|
||||||
{
|
{
|
||||||
// (???: stream has nothing pending until user writes to it???)
|
// (???: stream has nothing pending until user writes to it???)
|
||||||
//stream->Reset();
|
//stream->Reset();
|
||||||
|
|
@ -547,7 +837,7 @@ NormSimObject* NormSession::QueueTxSim(unsigned long objectSize)
|
||||||
DMSG(0, "NormSession::QueueTxSim() Error: server is closed\n");
|
DMSG(0, "NormSession::QueueTxSim() Error: server is closed\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
NormSimObject* simObject = new NormSimObject(this, NULL, next_tx_object_id);
|
NormSimObject* simObject = new NormSimObject(*this, NULL, next_tx_object_id);
|
||||||
if (!simObject)
|
if (!simObject)
|
||||||
{
|
{
|
||||||
DMSG(0, "NormSession::QueueTxSim() new sim object error: %s\n",
|
DMSG(0, "NormSession::QueueTxSim() new sim object error: %s\n",
|
||||||
|
|
@ -561,7 +851,7 @@ NormSimObject* NormSession::QueueTxSim(unsigned long objectSize)
|
||||||
delete simObject;
|
delete simObject;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (QueueTxObject(simObject, false))
|
if (QueueTxObject(simObject))
|
||||||
{
|
{
|
||||||
return simObject;
|
return simObject;
|
||||||
}
|
}
|
||||||
|
|
@ -573,7 +863,7 @@ NormSimObject* NormSession::QueueTxSim(unsigned long objectSize)
|
||||||
} // end NormSession::QueueTxSim()
|
} // end NormSession::QueueTxSim()
|
||||||
#endif // SIMULATE
|
#endif // SIMULATE
|
||||||
|
|
||||||
bool NormSession::QueueTxObject(NormObject* obj, bool touchServer)
|
bool NormSession::QueueTxObject(NormObject* obj)
|
||||||
{
|
{
|
||||||
if (!IsServer())
|
if (!IsServer())
|
||||||
{
|
{
|
||||||
|
|
@ -599,9 +889,8 @@ bool NormSession::QueueTxObject(NormObject* obj, bool touchServer)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tx_table.Remove(oldest);
|
Notify(NormController::TX_OBJECT_PURGED, (NormServerNode*)NULL, oldest);
|
||||||
oldest->Close();
|
DeleteTxObject(oldest);
|
||||||
delete oldest;
|
|
||||||
}
|
}
|
||||||
count = tx_table.Count();
|
count = tx_table.Count();
|
||||||
}
|
}
|
||||||
|
|
@ -613,6 +902,7 @@ bool NormSession::QueueTxObject(NormObject* obj, bool touchServer)
|
||||||
ASSERT(0);
|
ASSERT(0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
obj->Retain();
|
||||||
tx_pending_mask.Set(obj->GetId());
|
tx_pending_mask.Set(obj->GetId());
|
||||||
ASSERT(tx_pending_mask.Test(obj->GetId()));
|
ASSERT(tx_pending_mask.Test(obj->GetId()));
|
||||||
next_tx_object_id++;
|
next_tx_object_id++;
|
||||||
|
|
@ -624,13 +914,14 @@ bool NormSession::QueueTxObject(NormObject* obj, bool touchServer)
|
||||||
|
|
||||||
void NormSession::DeleteTxObject(NormObject* obj)
|
void NormSession::DeleteTxObject(NormObject* obj)
|
||||||
{
|
{
|
||||||
|
if (tx_table.Remove(obj))
|
||||||
|
{
|
||||||
NormObjectId objectId = obj->GetId();
|
NormObjectId objectId = obj->GetId();
|
||||||
ASSERT(obj == tx_table.Find(objectId));
|
|
||||||
tx_table.Remove(obj);
|
|
||||||
obj->Close();
|
|
||||||
tx_pending_mask.Unset(objectId);
|
tx_pending_mask.Unset(objectId);
|
||||||
tx_repair_mask.Unset(objectId);
|
tx_repair_mask.Unset(objectId);
|
||||||
delete obj;
|
}
|
||||||
|
obj->Close();
|
||||||
|
obj->Release();
|
||||||
} // end NormSession::DeleteTxObject()
|
} // end NormSession::DeleteTxObject()
|
||||||
|
|
||||||
NormBlock* NormSession::ServerGetFreeBlock(NormObjectId objectId,
|
NormBlock* NormSession::ServerGetFreeBlock(NormObjectId objectId,
|
||||||
|
|
@ -919,11 +1210,7 @@ void NormSession::HandleReceiveMessage(NormMsg& msg, bool wasUnicast)
|
||||||
{
|
{
|
||||||
// for suppression of unicast nack feedback
|
// for suppression of unicast nack feedback
|
||||||
advertise_repairs = true;
|
advertise_repairs = true;
|
||||||
if (!tx_timer.IsActive())
|
QueueMessage(NULL); // to prompt transmit timeout
|
||||||
{
|
|
||||||
tx_timer.SetInterval(0.0);
|
|
||||||
ActivateTimer(tx_timer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (IsClient()) ClientHandleNackMessage((NormNackMsg&)msg);
|
if (IsClient()) ClientHandleNackMessage((NormNackMsg&)msg);
|
||||||
|
|
@ -949,23 +1236,48 @@ void NormSession::ClientHandleObjectMessage(const struct timeval& currentTime,
|
||||||
// Do common updates for servers we already know.
|
// Do common updates for servers we already know.
|
||||||
NormNodeId sourceId = msg.GetSourceId();
|
NormNodeId sourceId = msg.GetSourceId();
|
||||||
NormServerNode* theServer = (NormServerNode*)server_tree.FindNodeById(sourceId);
|
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);
|
server_tree.AttachNode(theServer);
|
||||||
|
theServer->Retain();
|
||||||
DMSG(4, "NormSession::ClientHandleObjectMessage() node>%lu new remote server:%lu ...\n",
|
DMSG(4, "NormSession::ClientHandleObjectMessage() node>%lu new remote server:%lu ...\n",
|
||||||
LocalNodeId(), msg.GetSourceId());
|
LocalNodeId(), msg.GetSourceId());
|
||||||
}
|
}
|
||||||
else
|
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));
|
strerror(errno));
|
||||||
// (TBD) notify application of error
|
// (TBD) notify application of error
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (theServer->IsOpen()) theServer->Activate();
|
theServer->Activate();
|
||||||
theServer->UpdateLossEstimate(currentTime, msg.GetSequence());
|
theServer->UpdateLossEstimate(currentTime, msg.GetSequence());
|
||||||
theServer->SetAddress(msg.GetSource());
|
theServer->SetAddress(msg.GetSource());
|
||||||
theServer->IncrementRecvTotal(msg.GetLength()); // for statistics only (TBD) #ifdef NORM_DEBUG
|
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.
|
// Do common updates for servers we already know.
|
||||||
NormNodeId sourceId = cmd.GetSourceId();
|
NormNodeId sourceId = cmd.GetSourceId();
|
||||||
NormServerNode* theServer = (NormServerNode*)server_tree.FindNodeById(sourceId);
|
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",
|
//DMSG(0, "NormSession::ClientHandleCommand() node>%lu recvd command from unknown server ...\n",
|
||||||
// LocalNodeId());
|
// LocalNodeId());
|
||||||
if ((theServer = new NormServerNode(this, cmd.GetSourceId())))
|
if ((theServer = new NormServerNode(*this, cmd.GetSourceId())))
|
||||||
|
{
|
||||||
|
if (theServer->Open(cmd.GetSessionId()))
|
||||||
{
|
{
|
||||||
|
|
||||||
server_tree.AttachNode(theServer);
|
server_tree.AttachNode(theServer);
|
||||||
|
theServer->Retain();
|
||||||
DMSG(4, "NormSession::ClientHandleCommand() node>%lu new remote server:%lu ...\n",
|
DMSG(4, "NormSession::ClientHandleCommand() node>%lu new remote server:%lu ...\n",
|
||||||
LocalNodeId(), cmd.GetSourceId());
|
LocalNodeId(), cmd.GetSourceId());
|
||||||
}
|
}
|
||||||
else
|
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));
|
strerror(errno));
|
||||||
// (TBD) notify application of error
|
// (TBD) notify application of error
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (theServer->IsOpen()) theServer->Activate();
|
theServer->Activate();
|
||||||
theServer->UpdateLossEstimate(currentTime, cmd.GetSequence());
|
theServer->UpdateLossEstimate(currentTime, cmd.GetSequence());
|
||||||
theServer->SetAddress(cmd.GetSource());
|
theServer->SetAddress(cmd.GetSource());
|
||||||
theServer->IncrementRecvTotal(cmd.GetLength()); // for statistics only (TBD) #ifdef NORM_DEBUG
|
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
|
// There was no active CLR
|
||||||
if (!next)
|
if (!next)
|
||||||
{
|
{
|
||||||
if ((next = new NormCCNode(this, nodeId)))
|
if ((next = new NormCCNode(*this, nodeId)))
|
||||||
{
|
{
|
||||||
cc_node_list.Append(next);
|
cc_node_list.Append(next);
|
||||||
}
|
}
|
||||||
|
|
@ -1186,7 +1522,7 @@ void NormSession::ServerHandleCCFeedback(NormNodeId nodeId,
|
||||||
NormCCNode* candidate = NULL;
|
NormCCNode* candidate = NULL;
|
||||||
if (cc_node_list.GetCount() < 5)
|
if (cc_node_list.GetCount() < 5)
|
||||||
{
|
{
|
||||||
if ((candidate = new NormCCNode(this, nodeId)))
|
if ((candidate = new NormCCNode(*this, nodeId)))
|
||||||
{
|
{
|
||||||
cc_node_list.Append(candidate);
|
cc_node_list.Append(candidate);
|
||||||
}
|
}
|
||||||
|
|
@ -1288,11 +1624,7 @@ void NormSession::ServerHandleAckMessage(const struct timeval& currentTime, cons
|
||||||
{
|
{
|
||||||
// for suppression of unicast feedback
|
// for suppression of unicast feedback
|
||||||
advertise_repairs = true;
|
advertise_repairs = true;
|
||||||
if (!tx_timer.IsActive())
|
QueueMessage(NULL);
|
||||||
{
|
|
||||||
tx_timer.SetInterval(0.0);
|
|
||||||
ActivateTimer(tx_timer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ack.GetAckType())
|
switch (ack.GetAckType())
|
||||||
|
|
@ -1301,8 +1633,51 @@ void NormSession::ServerHandleAckMessage(const struct timeval& currentTime, cons
|
||||||
// Everything is in the ACK header for this one
|
// Everything is in the ACK header for this one
|
||||||
break;
|
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:
|
default:
|
||||||
DMSG(0, "NormSession::ServerHandleAckMessage() node>%lu received "
|
DMSG(0, "NormSession::ServerHandleAckMessage() node>%lu received "
|
||||||
"unsupported ack type:%d\n", LocalNodeId(), ack.GetAckType());
|
"unsupported ack type:%d\n", LocalNodeId(), ack.GetAckType());
|
||||||
|
|
@ -1357,15 +1732,19 @@ void NormSession::ServerHandleNackMessage(const struct timeval& currentTime, Nor
|
||||||
if (ServerGetFirstPending(txObjectIndex))
|
if (ServerGetFirstPending(txObjectIndex))
|
||||||
{
|
{
|
||||||
NormObject* obj = tx_table.Find(txObjectIndex);
|
NormObject* obj = tx_table.Find(txObjectIndex);
|
||||||
ASSERT(obj && obj->IsPending());
|
ASSERT(obj);
|
||||||
if (obj->IsPendingInfo())
|
if (obj->IsPendingInfo())
|
||||||
{
|
{
|
||||||
txBlockIndex = 0;
|
txBlockIndex = 0;
|
||||||
}
|
}
|
||||||
|
else if (obj->GetFirstPending(txBlockIndex))
|
||||||
|
{
|
||||||
|
txBlockIndex++;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
obj->GetFirstPending(txBlockIndex);
|
txObjectIndex = next_tx_object_id;
|
||||||
txBlockIndex++;
|
txBlockIndex = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -1583,6 +1962,9 @@ void NormSession::ServerHandleNackMessage(const struct timeval& currentTime, Nor
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!(block = object->FindBlock(nextBlockId)))
|
if (!(block = object->FindBlock(nextBlockId)))
|
||||||
|
{
|
||||||
|
// Is this entire block already tx pending?
|
||||||
|
if (!object->IsPendingSet(nextBlockId))
|
||||||
{
|
{
|
||||||
// Try to recover block including parity calculation
|
// Try to recover block including parity calculation
|
||||||
if (!(block = object->ServerRecoverBlock(nextBlockId)))
|
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;
|
freshBlock = false;
|
||||||
numErasures = extra_parity;
|
numErasures = extra_parity;
|
||||||
prevBlockId = nextBlockId;
|
prevBlockId = nextBlockId;
|
||||||
|
|
@ -1902,7 +2292,13 @@ bool NormSession::ServerBuildRepairAdv(NormCmdRepairAdvMsg& cmd)
|
||||||
if (form != prevForm)
|
if (form != prevForm)
|
||||||
{
|
{
|
||||||
if (NormRepairRequest::INVALID != 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);
|
req.SetForm(form);
|
||||||
cmd.AttachRepairRequest(req, segment_size);
|
cmd.AttachRepairRequest(req, segment_size);
|
||||||
prevForm = form;
|
prevForm = form;
|
||||||
|
|
@ -1945,8 +2341,8 @@ bool NormSession::ServerBuildRepairAdv(NormCmdRepairAdvMsg& cmd)
|
||||||
} // end while (nextObject)
|
} // end while (nextObject)
|
||||||
if (NormRepairRequest::INVALID != prevForm)
|
if (NormRepairRequest::INVALID != prevForm)
|
||||||
{
|
{
|
||||||
cmd.PackRepairRequest(req); // (TBD) error check;
|
if (0 == cmd.PackRepairRequest(req))
|
||||||
prevForm = NormRepairRequest::INVALID;
|
DMSG(0, "NormSession::ServerBuildRepairAdv() warning: full msg\n");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} // end NormSession::ServerBuildRepairAdv()
|
} // end NormSession::ServerBuildRepairAdv()
|
||||||
|
|
@ -2011,7 +2407,6 @@ bool NormSession::OnRepairTimeout(ProtoTimer& /*theTimer*/)
|
||||||
return true;
|
return true;
|
||||||
} // end NormSession::OnRepairTimeout()
|
} // end NormSession::OnRepairTimeout()
|
||||||
|
|
||||||
|
|
||||||
// (TBD) Should pass current system time to ProtoTimer timeout handlers
|
// (TBD) Should pass current system time to ProtoTimer timeout handlers
|
||||||
// for more efficiency ...
|
// for more efficiency ...
|
||||||
bool NormSession::OnTxTimeout(ProtoTimer& /*theTimer*/)
|
bool NormSession::OnTxTimeout(ProtoTimer& /*theTimer*/)
|
||||||
|
|
@ -2069,6 +2464,8 @@ bool NormSession::OnTxTimeout(ProtoTimer& /*theTimer*/)
|
||||||
advertise_repairs = false;
|
advertise_repairs = false;
|
||||||
else
|
else
|
||||||
ReturnMessageToPool(msg);
|
ReturnMessageToPool(msg);
|
||||||
|
// Pre-serve to allow pre-prompt for empty tx queue
|
||||||
|
if (message_queue.IsEmpty() && IsServer()) Serve();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -2089,7 +2486,7 @@ bool NormSession::OnTxTimeout(ProtoTimer& /*theTimer*/)
|
||||||
// Check that any possible notifications posted in
|
// Check that any possible notifications posted in
|
||||||
// the previous call to Serve() may have caused a
|
// the previous call to Serve() may have caused a
|
||||||
// change in server state making it ready to send
|
// change in server state making it ready to send
|
||||||
if (IsServer()) Serve();
|
//if (IsServer()) Serve();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -2100,6 +2497,7 @@ bool NormSession::OnTxTimeout(ProtoTimer& /*theTimer*/)
|
||||||
}
|
}
|
||||||
} // end NormSession::OnTxTimeout()
|
} // end NormSession::OnTxTimeout()
|
||||||
|
|
||||||
|
|
||||||
bool NormSession::SendMessage(NormMsg& msg)
|
bool NormSession::SendMessage(NormMsg& msg)
|
||||||
{
|
{
|
||||||
struct timeval currentTime;
|
struct timeval currentTime;
|
||||||
|
|
@ -2163,7 +2561,7 @@ bool NormSession::SendMessage(NormMsg& msg)
|
||||||
msg.SetSourceId(local_node_id);
|
msg.SetSourceId(local_node_id);
|
||||||
UINT16 msgSize = msg.GetLength();
|
UINT16 msgSize = msg.GetLength();
|
||||||
bool result = true;
|
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);
|
bool drop = (UniformRand(100.0) < tx_loss_rate);
|
||||||
if (drop || (clientMsg && client_silent))
|
if (drop || (clientMsg && client_silent))
|
||||||
{
|
{
|
||||||
|
|
@ -2236,6 +2634,11 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
|
||||||
probe_timer.Deactivate();
|
probe_timer.Deactivate();
|
||||||
return false;
|
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.
|
// 2) Update grtt_estimate _if_ sufficient time elapsed.
|
||||||
// This new code allows more liberal downward adjustment of
|
// This new code allows more liberal downward adjustment of
|
||||||
|
|
@ -2447,12 +2850,12 @@ bool NormSession::OnReportTimeout(ProtoTimer& /*theTimer*/)
|
||||||
struct timeval currentTime;
|
struct timeval currentTime;
|
||||||
ProtoSystemTime(currentTime);
|
ProtoSystemTime(currentTime);
|
||||||
struct tm* ct = gmtime((time_t*)¤tTime.tv_sec);
|
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());
|
ct->tm_hour, ct->tm_min, ct->tm_sec, currentTime.tv_usec, LocalNodeId());
|
||||||
if (IsServer())
|
if (IsServer())
|
||||||
{
|
{
|
||||||
DMSG(2, "Local server:\n");
|
DMSG(2, "Local status:\n");
|
||||||
DMSG(2, " tx_rate>%9.3lf kbps grtt>%lf\n",
|
DMSG(2, " txRate>%9.3lf kbps grtt>%lf\n",
|
||||||
((double)tx_rate)*8.0/1000.0, grtt_advertised);
|
((double)tx_rate)*8.0/1000.0, grtt_advertised);
|
||||||
}
|
}
|
||||||
if (IsClient())
|
if (IsClient())
|
||||||
|
|
@ -2461,18 +2864,19 @@ bool NormSession::OnReportTimeout(ProtoTimer& /*theTimer*/)
|
||||||
NormServerNode* next;
|
NormServerNode* next;
|
||||||
while ((next = (NormServerNode*)iterator.GetNextNode()))
|
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 rxRate = 8.0e-03*((double)next->RecvTotal()) / report_timer.GetInterval(); // kbps
|
||||||
double rxGoodput = 8.0e-03*((double)next->RecvGoodput()) / report_timer.GetInterval(); // kbps
|
double rxGoodput = 8.0e-03*((double)next->RecvGoodput()) / report_timer.GetInterval(); // kbps
|
||||||
next->ResetRecvStats();
|
next->ResetRecvStats();
|
||||||
DMSG(2, " rx_rate>%9.3lf kbps rx_goodput>%9.3lf kbps\n", rxRate, rxGoodput);
|
DMSG(2, " rxRate>%9.3lf kbps rx_goodput>%9.3lf kbps\n", rxRate, rxGoodput);
|
||||||
DMSG(2, " objects completed>%lu pending>%lu failed:%lu\n",
|
DMSG(2, " rxObjects> completed>%lu pending>%lu failed:%lu\n",
|
||||||
next->CompletionCount(), next->PendingCount(), next->FailureCount());
|
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->PeakBufferUsage(),
|
||||||
next->BufferOverunCount());
|
next->BufferOverunCount());
|
||||||
DMSG(2, " resyncs>%lu nacks>%lu suppressed>%lu\n", next->ResyncCount(),
|
DMSG(2, " resyncs>%lu nacks>%lu suppressed>%lu\n", next->ResyncCount(),
|
||||||
next->NackCount(), next->SuppressCount());
|
next->NackCount(),
|
||||||
|
next->SuppressCount());
|
||||||
|
|
||||||
}
|
}
|
||||||
} // end if (IsClient())
|
} // end if (IsClient())
|
||||||
|
|
@ -2506,7 +2910,7 @@ NormSession* NormSessionMgr::NewSession(const char* sessionAddress,
|
||||||
UINT16 sessionPort,
|
UINT16 sessionPort,
|
||||||
NormNodeId localNodeId)
|
NormNodeId localNodeId)
|
||||||
{
|
{
|
||||||
if (NORM_NODE_ANY == localNodeId)
|
if ((NORM_NODE_ANY == localNodeId) || (NORM_NODE_NONE == localNodeId))
|
||||||
{
|
{
|
||||||
// Use local ip address to assign default localNodeId
|
// Use local ip address to assign default localNodeId
|
||||||
ProtoAddress localAddr;
|
ProtoAddress localAddr;
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,20 @@ class NormController
|
||||||
public:
|
public:
|
||||||
enum Event
|
enum Event
|
||||||
{
|
{
|
||||||
|
EVENT_INVALID = 0,
|
||||||
|
TX_QUEUE_VACANCY,
|
||||||
TX_QUEUE_EMPTY,
|
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_NEW,
|
||||||
RX_OBJECT_INFO,
|
RX_OBJECT_INFO,
|
||||||
RX_OBJECT_UPDATE,
|
RX_OBJECT_UPDATE,
|
||||||
RX_OBJECT_COMPLETE,
|
RX_OBJECT_COMPLETED,
|
||||||
|
RX_OBJECT_ABORTED
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual void Notify(NormController::Event event,
|
virtual void Notify(NormController::Event event,
|
||||||
|
|
@ -54,9 +63,10 @@ class NormSessionMgr
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivateTimer(ProtoTimer& timer) {timer_mgr.ActivateTimer(timer);}
|
void ActivateTimer(ProtoTimer& timer) {timer_mgr.ActivateTimer(timer);}
|
||||||
ProtoTimerMgr& GetTimerMgr() {return timer_mgr;}
|
ProtoTimerMgr& GetTimerMgr() const {return timer_mgr;}
|
||||||
ProtoSocket::Notifier& GetSocketNotifier() {return socket_notifier;}
|
ProtoSocket::Notifier& GetSocketNotifier() const {return socket_notifier;}
|
||||||
|
|
||||||
|
NormController* GetController() const {return controller;}
|
||||||
private:
|
private:
|
||||||
ProtoTimerMgr& timer_mgr;
|
ProtoTimerMgr& timer_mgr;
|
||||||
ProtoSocket::Notifier& socket_notifier;
|
ProtoSocket::Notifier& socket_notifier;
|
||||||
|
|
@ -86,26 +96,34 @@ class NormSession
|
||||||
static const UINT16 DEFAULT_NPARITY;
|
static const UINT16 DEFAULT_NPARITY;
|
||||||
|
|
||||||
// General methods
|
// General methods
|
||||||
const NormNodeId& LocalNodeId() {return local_node_id;}
|
const NormNodeId& LocalNodeId() const {return local_node_id;}
|
||||||
bool Open(const char* interfaceName = NULL);
|
bool Open(const char* interfaceName = NULL);
|
||||||
void Close();
|
void Close();
|
||||||
bool IsOpen() {return (rx_socket.IsOpen() || tx_socket.IsOpen());}
|
bool IsOpen() {return (rx_socket.IsOpen() || tx_socket.IsOpen());}
|
||||||
const ProtoAddress& Address() {return address;}
|
const ProtoAddress& Address() {return address;}
|
||||||
void SetAddress(const ProtoAddress& addr) {address = addr;}
|
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);
|
static double CalculateRate(double size, double rtt, double loss);
|
||||||
|
|
||||||
|
NormSessionMgr& GetSessionMgr() {return session_mgr;}
|
||||||
|
|
||||||
// Session parameters
|
// Session parameters
|
||||||
double TxRate() {return (tx_rate * 8.0);}
|
double TxRate() {return (tx_rate * 8.0);}
|
||||||
// (TBD) watch timer scheduling and min/max bounds
|
// (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;}
|
double BackoffFactor() {return backoff_factor;}
|
||||||
void SetBackoffFactor(double value) {backoff_factor = value;}
|
void SetBackoffFactor(double value) {backoff_factor = value;}
|
||||||
void SetLoopback(bool state)
|
|
||||||
{
|
|
||||||
rx_socket.SetLoopback(state);
|
|
||||||
tx_socket.SetLoopback(state);
|
|
||||||
}
|
|
||||||
bool CongestionControl() {return cc_enable;}
|
bool CongestionControl() {return cc_enable;}
|
||||||
void SetCongestionControl(bool state) {cc_enable = state;}
|
void SetCongestionControl(bool state) {cc_enable = state;}
|
||||||
|
|
||||||
|
|
@ -130,7 +148,8 @@ class NormSession
|
||||||
next_tx_object_id = IsServer() ? next_tx_object_id : baseId;
|
next_tx_object_id = IsServer() ? next_tx_object_id : baseId;
|
||||||
session_id = IsServer() ? session_id : (UINT16)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 segmentSize,
|
||||||
UINT16 numData,
|
UINT16 numData,
|
||||||
UINT16 numParity,
|
UINT16 numParity,
|
||||||
|
|
@ -142,15 +161,27 @@ class NormSession
|
||||||
NormFileObject* QueueTxFile(const char* path,
|
NormFileObject* QueueTxFile(const char* path,
|
||||||
const char* infoPtr = NULL,
|
const char* infoPtr = NULL,
|
||||||
UINT16 infoLen = 0);
|
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;}
|
// postive ack mgmnt
|
||||||
UINT16 ServerSegmentSize() {return segment_size;}
|
void ServerSetWatermark(NormObjectId objectId,
|
||||||
UINT16 ServerBlockSize() {return ndata;}
|
NormBlockId blockId,
|
||||||
UINT16 ServerNumParity() {return nparity;}
|
NormSegmentId segmentId);
|
||||||
UINT16 ServerAutoParity() {return auto_parity;}
|
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)
|
void ServerSetAutoParity(UINT16 autoParity)
|
||||||
{ASSERT(autoParity <= nparity); auto_parity = autoParity;}
|
{ASSERT(autoParity <= nparity); auto_parity = autoParity;}
|
||||||
UINT16 ServerExtraParity() {return extra_parity;}
|
UINT16 ServerExtraParity() const {return extra_parity;}
|
||||||
void ServerSetExtraParity(UINT16 extraParity)
|
void ServerSetExtraParity(UINT16 extraParity)
|
||||||
{extra_parity = extraParity;}
|
{extra_parity = extraParity;}
|
||||||
|
|
||||||
|
|
@ -161,6 +192,13 @@ class NormSession
|
||||||
objectId = (UINT16)index;
|
objectId = (UINT16)index;
|
||||||
return result;
|
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;}
|
double ServerGrtt() {return grtt_advertised;}
|
||||||
void ServerSetGrtt(double grttValue)
|
void ServerSetGrtt(double grttValue)
|
||||||
|
|
@ -192,15 +230,7 @@ class NormSession
|
||||||
void ServerPutFreeSegment(char* segment) {segment_pool.Put(segment);}
|
void ServerPutFreeSegment(char* segment) {segment_pool.Put(segment);}
|
||||||
|
|
||||||
|
|
||||||
void PromptServer()
|
void PromptServer() {QueueMessage(NULL);}
|
||||||
{
|
|
||||||
if (!tx_timer.IsActive())
|
|
||||||
{
|
|
||||||
tx_timer.SetInterval(0.0);
|
|
||||||
ActivateTimer(tx_timer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void TouchServer()
|
void TouchServer()
|
||||||
{
|
{
|
||||||
|
|
@ -213,13 +243,23 @@ class NormSession
|
||||||
bool StartClient(unsigned long bufferSpace,
|
bool StartClient(unsigned long bufferSpace,
|
||||||
const char* interfaceName = NULL);
|
const char* interfaceName = NULL);
|
||||||
void StopClient();
|
void StopClient();
|
||||||
bool IsClient() {return is_client;}
|
bool IsClient() const {return is_client;}
|
||||||
unsigned long RemoteServerBufferSize()
|
unsigned long RemoteServerBufferSize() const
|
||||||
{return remote_server_buffer_size;}
|
{return remote_server_buffer_size;}
|
||||||
void SetUnicastNacks(bool state) {unicast_nacks = state;}
|
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;}
|
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
|
// Debug settings
|
||||||
void SetTrace(bool state) {trace = state;}
|
void SetTrace(bool state) {trace = state;}
|
||||||
|
|
@ -239,13 +279,12 @@ class NormSession
|
||||||
~NormSession();
|
~NormSession();
|
||||||
|
|
||||||
void Serve();
|
void Serve();
|
||||||
bool QueueTxObject(NormObject* obj, bool touchServer = true);
|
bool QueueTxObject(NormObject* obj);
|
||||||
void DeleteTxObject(NormObject* obj);
|
|
||||||
|
|
||||||
bool OnTxTimeout(ProtoTimer& theTimer);
|
bool OnTxTimeout(ProtoTimer& theTimer);
|
||||||
bool OnRepairTimeout(ProtoTimer& theTimer);
|
bool OnRepairTimeout(ProtoTimer& theTimer);
|
||||||
bool OnFlushTimeout(ProtoTimer& theTimer);
|
bool OnFlushTimeout(ProtoTimer& theTimer);
|
||||||
bool OnWatermarkTimeout(ProtoTimer& theTimer);
|
|
||||||
bool OnProbeTimeout(ProtoTimer& theTimer);
|
bool OnProbeTimeout(ProtoTimer& theTimer);
|
||||||
bool OnReportTimeout(ProtoTimer& theTimer);
|
bool OnReportTimeout(ProtoTimer& theTimer);
|
||||||
|
|
||||||
|
|
@ -271,6 +310,7 @@ class NormSession
|
||||||
void AdjustRate(bool onResponse);
|
void AdjustRate(bool onResponse);
|
||||||
bool ServerQueueSquelch(NormObjectId objectId);
|
bool ServerQueueSquelch(NormObjectId objectId);
|
||||||
void ServerQueueFlush();
|
void ServerQueueFlush();
|
||||||
|
bool ServerQueueWatermarkFlush();
|
||||||
bool ServerBuildRepairAdv(NormCmdRepairAdvMsg& cmd);
|
bool ServerBuildRepairAdv(NormCmdRepairAdvMsg& cmd);
|
||||||
void ServerUpdateGroupSize();
|
void ServerUpdateGroupSize();
|
||||||
|
|
||||||
|
|
@ -296,6 +336,7 @@ class NormSession
|
||||||
NormNodeId local_node_id;
|
NormNodeId local_node_id;
|
||||||
ProtoAddress address; // session destination address & port
|
ProtoAddress address; // session destination address & port
|
||||||
UINT8 ttl; // session multicast ttl
|
UINT8 ttl; // session multicast ttl
|
||||||
|
bool loopback; // to receive own traffic
|
||||||
double tx_rate; // bytes per second
|
double tx_rate; // bytes per second
|
||||||
double backoff_factor;
|
double backoff_factor;
|
||||||
|
|
||||||
|
|
@ -323,9 +364,15 @@ class NormSession
|
||||||
ProtoTimer flush_timer;
|
ProtoTimer flush_timer;
|
||||||
int flush_count;
|
int flush_count;
|
||||||
bool posted_tx_queue_empty;
|
bool posted_tx_queue_empty;
|
||||||
ProtoTimer watermark_timer;
|
|
||||||
int watermark_count;
|
// For postive acknowledgement collection
|
||||||
// (TBD) watermark_object_id, watermark_block_id, watermark_symbol_id
|
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
|
// for unicast nack/cc feedback suppression
|
||||||
bool advertise_repairs;
|
bool advertise_repairs;
|
||||||
|
|
@ -370,6 +417,8 @@ class NormSession
|
||||||
unsigned long remote_server_buffer_size;
|
unsigned long remote_server_buffer_size;
|
||||||
bool unicast_nacks;
|
bool unicast_nacks;
|
||||||
bool client_silent;
|
bool client_silent;
|
||||||
|
NormServerNode::RepairBoundary default_repair_boundary;
|
||||||
|
NormObject::NackingMode default_nacking_mode;
|
||||||
|
|
||||||
// Protocol test/debug parameters
|
// Protocol test/debug parameters
|
||||||
bool trace;
|
bool trace;
|
||||||
|
|
|
||||||
|
|
@ -831,7 +831,7 @@ void NormSimAgent::Notify(NormController::Event event,
|
||||||
break;
|
break;
|
||||||
} // end switch (object->GetType())
|
} // end switch (object->GetType())
|
||||||
break;
|
break;
|
||||||
case RX_OBJECT_COMPLETE:
|
case RX_OBJECT_COMPLETED:
|
||||||
{
|
{
|
||||||
switch(object->GetType())
|
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
|
#ifndef _NORM_VERSION
|
||||||
#define _NORM_VERSION
|
#define _NORM_VERSION
|
||||||
#define VERSION "1.2b1"
|
#define VERSION "1.2b2"
|
||||||
#endif // _NORM_VERSION
|
#endif // _NORM_VERSION
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -467,7 +467,7 @@ void RaftApp::OnClientSocketEvent(ProtoSocket& /*theSocket*/,
|
||||||
while (rtsp_client_socket.Recv(buffer, buflen))
|
while (rtsp_client_socket.Recv(buffer, buflen))
|
||||||
{
|
{
|
||||||
buffer[buflen] = '\0';
|
buffer[buflen] = '\0';
|
||||||
TRACE("%s");
|
TRACE("%s", buffer);
|
||||||
}
|
}
|
||||||
TRACE("\n");
|
TRACE("\n");
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ for {set i 2} {$i <= $numNodes} {incr i} {
|
||||||
}
|
}
|
||||||
$ns_ at 0.0 "$norm(1) sendFile 64000"
|
$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} {
|
proc finish {ns_ f nf} {
|
||||||
$ns_ flush-trace
|
$ns_ flush-trace
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ NS = ../ns
|
||||||
|
|
||||||
INCLUDES = $(TCL_INCL_PATH) $(SYSTEM_INCLUDES) -I$(UNIX) -I$(COMMON) -I$(PROTOLIB)/common
|
INCLUDES = $(TCL_INCL_PATH) $(SYSTEM_INCLUDES) -I$(UNIX) -I$(COMMON) -I$(PROTOLIB)/common
|
||||||
|
|
||||||
CFLAGS = -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)
|
LDFLAGS = $(SYSTEM_LDFLAGS)
|
||||||
|
|
||||||
|
|
@ -84,6 +84,14 @@ APP_OBJ = $(APP_SRC:.cpp=.o)
|
||||||
norm: $(APP_OBJ) libnorm.a $(LIBPROTO)
|
norm: $(APP_OBJ) libnorm.a $(LIBPROTO)
|
||||||
$(CC) $(CFLAGS) -o $@ $(APP_OBJ) $(LDFLAGS) libnorm.a $(LIBPROTO) $(LIBS)
|
$(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) command-line reliable tunnel helper
|
||||||
RAFT_SRC = $(COMMON)/raft.cpp
|
RAFT_SRC = $(COMMON)/raft.cpp
|
||||||
RAFT_OBJ = $(RAFT_SRC:.cpp=.o)
|
RAFT_OBJ = $(RAFT_SRC:.cpp=.o)
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,8 @@ SYSTEM_LIBS = -ldl
|
||||||
# (We export these for other Makefiles as needed)
|
# (We export these for other Makefiles as needed)
|
||||||
#
|
#
|
||||||
|
|
||||||
SYSTEM_HAVES = -DLINUX -DHAVE_IPV6 -DHAVE_GETLOGIN -DHAVE_LOCKF \
|
SYSTEM_HAVES = -DLINUX -DHAVE_IPV6 -DHAVE_GETLOGIN -D_FILE_OFFSET_BITS=64 -DHAVE_LOCKF \
|
||||||
-DHAVE_OLD_SIGNALHANDLER -DHAVE_DIRFD -DHAVE_ASSERT $(NETSEC)
|
-DHAVE_OLD_SIGNALHANDLER -DHAVE_DIRFD -DHAVE_ASSERT
|
||||||
|
|
||||||
SYSTEM_SRC =
|
SYSTEM_SRC =
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@
|
||||||
# (Where to find X11 libraries, etc)
|
# (Where to find X11 libraries, etc)
|
||||||
#
|
#
|
||||||
|
|
||||||
SYSTEM_INCLUDES = -I/usr/X11R6/include
|
SYSTEM_INCLUDES =
|
||||||
SYSTEM_LDFLAGS = -L/usr/X11R6/lib
|
SYSTEM_LDFLAGS =
|
||||||
SYSTEM_LIBS =
|
SYSTEM_LIBS = -lresolv
|
||||||
|
|
||||||
# 2) System specific capabilities
|
# 2) System specific capabilities
|
||||||
# Must choose appropriate for the following:
|
# Must choose appropriate for the following:
|
||||||
|
|
@ -36,15 +36,16 @@ SYSTEM_LIBS =
|
||||||
# (We export these for other Makefiles as needed)
|
# (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
|
SYSTEM_SRC = bsdRouteMgr.cpp
|
||||||
|
|
||||||
# The "SYSTEM" keyword can be used for dependent makes
|
# The "SYSTEM" keyword can be used for dependent makes
|
||||||
SYSTEM = macosx
|
SYSTEM = macosx
|
||||||
|
|
||||||
export CC = g++
|
CC = g++
|
||||||
export RANLIB = ranlib
|
RANLIB = ranlib
|
||||||
export AR = ar
|
AR = ar
|
||||||
|
|
||||||
include Makefile.common
|
include Makefile.common
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@
|
||||||
# 1) System specific additional libraries, include paths, etc
|
# 1) System specific additional libraries, include paths, etc
|
||||||
# (Where to find X11 libraries, etc)
|
# (Where to find X11 libraries, etc)
|
||||||
#
|
#
|
||||||
SYSTEM_INCLUDES = -I/usr/openwin/include
|
SYSTEM_INCLUDES =
|
||||||
SYSTEM_LDFLAGS = -L/usr/openwin/lib -R/usr/openwin/lib
|
SYSTEM_LDFLAGS =
|
||||||
SYSTEM_LIBS = -ldl -lnsl -lsocket -lresolv
|
SYSTEM_LIBS = -ldl -lnsl -lsocket -lresolv
|
||||||
|
|
||||||
# 2) System specific capabilities
|
# 2) System specific capabilities
|
||||||
|
|
@ -35,7 +35,8 @@ SYSTEM_LIBS = -ldl -lnsl -lsocket -lresolv
|
||||||
# (We export these for other Makefiles as needed)
|
# (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
|
SYSTEM = solaris
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -234,6 +234,10 @@ bool UnixPostProcessor::ProcessFile(const char* path)
|
||||||
// Restore signal handlers for parent
|
// Restore signal handlers for parent
|
||||||
signal(SIGTERM, sigtermHandler);
|
signal(SIGTERM, sigtermHandler);
|
||||||
signal(SIGINT, sigintHandler);
|
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);
|
signal(SIGCHLD, sigchldHandler);
|
||||||
break;
|
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:
|
Global:
|
||||||
|
|
||||||
Package=<5>
|
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