3099 lines
106 KiB
C++
Executable File
3099 lines
106 KiB
C++
Executable File
#define _NORM_API_BUILD // force 'dllexport' in "normApi.h"
|
|
#include "normApi.h"
|
|
#include "normSession.h"
|
|
|
|
#ifdef WIN32
|
|
#ifndef _WIN32_WCE
|
|
#include <io.h> // for _mktemp()
|
|
#endif // !_WIN32_WCE
|
|
#endif // WIN32
|
|
|
|
// const defs
|
|
extern NORM_API_LINKAGE
|
|
const NormInstanceHandle NORM_INSTANCE_INVALID = ((NormInstanceHandle)0);
|
|
extern NORM_API_LINKAGE
|
|
const NormSessionHandle NORM_SESSION_INVALID = ((NormSessionHandle)0);
|
|
extern NORM_API_LINKAGE
|
|
const NormNodeHandle NORM_NODE_INVALID = ((NormNodeHandle)0);
|
|
extern NORM_API_LINKAGE
|
|
const NormNodeId NORM_NODE_NONE = ((NormNodeId)0x00000000);
|
|
extern NORM_API_LINKAGE
|
|
const NormNodeId NORM_NODE_ANY = ((NormNodeId)0xffffffff);
|
|
extern NORM_API_LINKAGE
|
|
const NormObjectHandle NORM_OBJECT_INVALID = ((NormObjectHandle)0);
|
|
extern NORM_API_LINKAGE
|
|
const NormDescriptor NORM_DESCRIPTOR_INVALID = ProtoDispatcher::INVALID_DESCRIPTOR;
|
|
|
|
|
|
/** The "NormInstance" class is a C++ helper class that keeps
|
|
* state for an instance of the NORM API. It acts as a
|
|
* "go between" the API's procedural function calls and
|
|
* the underlying NORM C++ implementation
|
|
*/
|
|
class NormInstance : public NormController
|
|
{
|
|
public:
|
|
NormInstance();
|
|
virtual ~NormInstance();
|
|
|
|
void Notify(NormController::Event event,
|
|
class NormSessionMgr* sessionMgr,
|
|
class NormSession* session,
|
|
class NormNode* node,
|
|
class NormObject* object);
|
|
|
|
bool Startup(bool priorityBoost = false);
|
|
void Shutdown();
|
|
|
|
void Stop() // pause NORM protocol engine
|
|
{
|
|
dispatcher.Stop();
|
|
Notify(NormController::EVENT_INVALID, &session_mgr, NULL, NULL, NULL);
|
|
}
|
|
bool Start()
|
|
{
|
|
if (dispatcher.StartThread(priority_boost))
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
PLOG(PL_FATAL, "NormInstance::Resume() error restarting NORM thread\n");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool WaitForEvent();
|
|
bool GetNextEvent(NormEvent* theEvent);
|
|
bool SetCacheDirectory(const char* cachePath);
|
|
|
|
void SetAllocationFunctions(NormAllocFunctionHandle allocFunc,
|
|
NormFreeFunctionHandle freeFunc)
|
|
{
|
|
data_alloc_func = allocFunc;
|
|
session_mgr.SetDataFreeFunction(freeFunc);
|
|
}
|
|
|
|
void ReleasePreviousEvent();
|
|
|
|
bool NotifyQueueIsEmpty() const
|
|
{return notify_queue.IsEmpty();}
|
|
|
|
void PurgeSessionNotifications(NormSessionHandle sessionHandle);
|
|
void PurgeNodeNotifications(NormNodeHandle nodeHandle);
|
|
void PurgeObjectNotifications(NormObjectHandle objectHandle);
|
|
void PurgeNotifications(NormSessionHandle sessionHandle, NormEventType eventType);
|
|
|
|
UINT32 CountCompletedObjects(NormSession* theSession);
|
|
|
|
ProtoDispatcher::Descriptor GetDescriptor() const
|
|
{
|
|
#ifdef WIN32
|
|
return notify_event;
|
|
#else
|
|
return notify_fd[0];
|
|
#endif // if/else WIN32/UNIX
|
|
}
|
|
|
|
static NormInstance* GetInstanceFromSession(NormSessionHandle sessionHandle)
|
|
{
|
|
if (NORM_SESSION_INVALID == sessionHandle) return ((NormInstance*)NULL);
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
NormInstance* theInstance = static_cast<NormInstance*>(session->GetSessionMgr().GetController());
|
|
return theInstance;
|
|
}
|
|
static NormInstance* GetInstanceFromNode(NormNodeHandle nodeHandle)
|
|
{
|
|
if (NORM_NODE_INVALID == nodeHandle) return ((NormInstance*)NULL);
|
|
NormSession& session = ((NormNode*)nodeHandle)->GetSession();
|
|
return static_cast<NormInstance*>(session.GetSessionMgr().GetController());
|
|
}
|
|
static NormInstance* GetInstanceFromObject(NormObjectHandle objectHandle)
|
|
{
|
|
if (NORM_OBJECT_INVALID == objectHandle) return ((NormInstance*)NULL);
|
|
NormSession& session = ((NormObject*)objectHandle)->GetSession();;
|
|
return static_cast<NormInstance*>(session.GetSessionMgr().GetController());
|
|
}
|
|
|
|
class Notification : public ProtoList::Item
|
|
{
|
|
public:
|
|
NormEvent event;
|
|
|
|
class Queue : public ProtoListTemplate<Notification> {};
|
|
}; // end class NormInstance::Notification
|
|
|
|
ProtoDispatcher dispatcher;
|
|
bool priority_boost;
|
|
NormSessionMgr session_mgr;
|
|
NormAllocFunctionHandle data_alloc_func;
|
|
|
|
private:
|
|
void ResetNotificationEvent()
|
|
{
|
|
#ifdef WIN32
|
|
if (0 == ResetEvent(notify_event))
|
|
PLOG(PL_ERROR, "NormInstance::ResetNotificationEvent() ResetEvent error: %s\n", GetErrorString());
|
|
#else
|
|
char byte[32];
|
|
while (read(notify_fd[0], byte, 32) > 0); // TBD - error check
|
|
#endif // if/else WIN32/UNIX
|
|
}
|
|
|
|
Notification::Queue notify_pool;
|
|
Notification::Queue notify_queue;
|
|
Notification* previous_notification;
|
|
|
|
const char* rx_cache_path;
|
|
|
|
#ifdef WIN32
|
|
HANDLE notify_event;
|
|
#else
|
|
int notify_fd[2]; // TBD - use eventfd on Linux for this, may EVT_USER on MacOS
|
|
#endif // if/else WIN32/UNIX
|
|
}; // end class NormInstance
|
|
|
|
|
|
////////////////////////////////////////////////////
|
|
// NormInstance implementation
|
|
NormInstance::NormInstance()
|
|
: priority_boost(false),
|
|
session_mgr(static_cast<ProtoTimerMgr&>(dispatcher),
|
|
static_cast<ProtoSocket::Notifier&>(dispatcher),
|
|
static_cast<ProtoChannel::Notifier*>(&dispatcher)),
|
|
data_alloc_func(NULL), previous_notification(NULL), rx_cache_path(NULL)
|
|
{
|
|
#ifdef WIN32
|
|
notify_event = NULL;
|
|
#else
|
|
notify_fd[0] = notify_fd[1] = -1;
|
|
#endif // if/else WIN32/UNIX
|
|
dispatcher.SetUserData(&session_mgr); // for debugging
|
|
session_mgr.SetController(static_cast<NormController*>(this));
|
|
}
|
|
|
|
NormInstance::~NormInstance()
|
|
{
|
|
Shutdown();
|
|
}
|
|
|
|
bool NormInstance::SetCacheDirectory(const char* cachePath)
|
|
{
|
|
// (TBD) verify that we can _write_ to this directory!
|
|
bool result = false;
|
|
if (dispatcher.SuspendThread())
|
|
{
|
|
size_t length = strlen(cachePath);
|
|
if (PROTO_PATH_DELIMITER != cachePath[length-1])
|
|
length += 2;
|
|
else
|
|
length += 1;
|
|
length = (length < PATH_MAX) ? length : PATH_MAX;
|
|
char* pathStorage = new char[length];
|
|
if (pathStorage)
|
|
{
|
|
strncpy(pathStorage, cachePath, length);
|
|
pathStorage[length - 2] = PROTO_PATH_DELIMITER;
|
|
pathStorage[length - 1] = '\0';
|
|
if (rx_cache_path) delete[] (char*)rx_cache_path;
|
|
rx_cache_path = pathStorage;
|
|
result = true;
|
|
}
|
|
else
|
|
{
|
|
PLOG(PL_ERROR, "NormInstance::SetCacheDirectory() new pathStorage error: %s\n",
|
|
GetErrorString());
|
|
}
|
|
dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormInstance::SetCacheDirectory()
|
|
|
|
void NormInstance::Notify(NormController::Event event,
|
|
class NormSessionMgr* sessionMgr,
|
|
class NormSession* session,
|
|
class NormNode* node,
|
|
class NormObject* object)
|
|
{
|
|
switch (event)
|
|
{
|
|
case SEND_OK:
|
|
// Purge any pending NORM_SEND_ERROR notifications for session
|
|
PurgeNotifications(session, NORM_SEND_ERROR);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// (TBD) set a limit on how many pending notifications
|
|
// we allow to queue up (it could be large and probably
|
|
// we could base it on how much memory space the pending
|
|
// notifications are allowed to consume.
|
|
Notification* next = notify_pool.RemoveHead();
|
|
if (NULL == next)
|
|
{
|
|
if (NULL == (next = new Notification))
|
|
{
|
|
PLOG(PL_FATAL, "NormInstance::Notify() new Notification error: %s\n", GetErrorString());
|
|
return;
|
|
}
|
|
}
|
|
|
|
switch (event)
|
|
{
|
|
case RX_OBJECT_NEW:
|
|
{
|
|
// new recv object "Accept()" policy implemented here
|
|
switch (object->GetType())
|
|
{
|
|
case NormObject::STREAM:
|
|
{
|
|
NormStreamObject* stream = static_cast<NormStreamObject*>(object);
|
|
// (TBD) implement silent_receiver accept differently
|
|
NormObjectSize size = stream->GetSize();
|
|
// We double the stream buffer to prevent unecessary data loss
|
|
// for our threaded API
|
|
if (!stream->Accept(size.LSB(), true))
|
|
{
|
|
PLOG(PL_FATAL, "NormInstance::Notify() stream accept error\n");
|
|
notify_pool.Append(*next);
|
|
return;
|
|
}
|
|
// By setting a non-zero "block pool threshold", this
|
|
// gives the API a chance to "catch up" on reading
|
|
// when the receive stream becomes buffer-constrained
|
|
UINT32 blockPoolCount = stream->GetBlockPoolCount();
|
|
stream->SetBlockPoolThreshold(blockPoolCount / 2);
|
|
break;
|
|
}
|
|
case NormObject::FILE:
|
|
{
|
|
if (NULL != rx_cache_path)
|
|
{
|
|
char fileName[PATH_MAX];
|
|
#ifdef WIN32
|
|
#ifdef _WIN32_WCE
|
|
bool tempFileOK = false;
|
|
for (int i = 0; i < 255; i++)
|
|
{
|
|
snprintf(fileName, PATH_MAX, "%snormTemp%06u", rx_cache_path, i);
|
|
if(!NormFile::IsLocked(fileName))
|
|
{
|
|
tempFileOK = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!tempFileOK)
|
|
#else
|
|
snprintf(fileName, PATH_MAX, "%snormTempXXXXXX", rx_cache_path);
|
|
if (!_mktemp(fileName))
|
|
#endif // if/else _WIN32_WCE
|
|
#else
|
|
snprintf(fileName, PATH_MAX, "%snormTempXXXXXX", rx_cache_path);
|
|
int fd = mkstemp(fileName);
|
|
if (fd >= 0)
|
|
{
|
|
close(fd);
|
|
}
|
|
else
|
|
#endif // if/else WIN32
|
|
{
|
|
PLOG(PL_ERROR, "NormInstance::Notify(RX_OBJECT_NEW) Warning: mkstemp() error: %s\n",
|
|
GetErrorString());
|
|
}
|
|
if (!static_cast<NormFileObject*>(object)->Accept(fileName))
|
|
{
|
|
PLOG(PL_ERROR, "NormInstance::Notify(RX_OBJECT_NEW) file object accept error!\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we're ignoring files
|
|
PLOG(PL_DETAIL, "NormInstance::Notify() warning: receive file but no cache directory set, so ignoring file\n");
|
|
notify_pool.Append(*next);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case NormObject::DATA:
|
|
{
|
|
NormDataObject* dataObj = static_cast<NormDataObject*>(object);
|
|
unsigned int dataLen = (unsigned int)(object->GetSize().GetOffset());
|
|
char* dataPtr = (NULL != data_alloc_func) ? data_alloc_func(dataLen) : new char[dataLen];
|
|
if (NULL == dataPtr)
|
|
{
|
|
PLOG(PL_FATAL, "NormInstance::Notify(RX_OBJECT_NEW) new dataPtr error: %s\n",
|
|
GetErrorString());
|
|
notify_pool.Append(*next);
|
|
return;
|
|
}
|
|
// Note that the "true" parameter means the
|
|
// NORM protocol engine will free the allocated
|
|
// data on object deletion, so the app should
|
|
// use NormDataDetachData() to keep the received
|
|
// data (or copy it before the data object is deleted)
|
|
if (!dataObj->Accept(dataPtr, dataLen, true))
|
|
{
|
|
PLOG(PL_FATAL, "NormInstance::Notify() data object accept error\n");
|
|
notify_pool.Append(*next);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
// This shouldn't occur
|
|
notify_pool.Append(*next);
|
|
return;
|
|
} // end switch(object->GetType())
|
|
break;
|
|
} // end case RX_OBJECT_NEW
|
|
|
|
default:
|
|
break;
|
|
} // end switch(event)
|
|
|
|
// "Retain" any valid "object" or "sender" handles for API access
|
|
if (NORM_OBJECT_INVALID != object)
|
|
((NormObject*)object)->Retain();
|
|
else if (NORM_NODE_INVALID != node)
|
|
((NormNode*)node)->Retain();
|
|
|
|
bool doNotify = notify_queue.IsEmpty();
|
|
next->event.type = (NormEventType)event;
|
|
next->event.session = session;
|
|
next->event.sender = node;
|
|
next->event.object = object;
|
|
notify_queue.Append(*next);
|
|
|
|
if (doNotify)
|
|
{
|
|
#ifdef WIN32
|
|
if (0 == SetEvent(notify_event))
|
|
{
|
|
PLOG(PL_ERROR, "NormInstance::Notify() SetEvent() error: %s\n",
|
|
GetErrorString());
|
|
}
|
|
#else
|
|
char byte = 0;
|
|
while (1 != write(notify_fd[1], &byte, 1))
|
|
{
|
|
if ((EINTR != errno) && (EAGAIN != errno))
|
|
{
|
|
PLOG(PL_FATAL, "NormInstance::Notify() write() error: %s\n",
|
|
GetErrorString());
|
|
break;
|
|
}
|
|
}
|
|
#endif // if/else WIN32/UNIX
|
|
}
|
|
} // end NormInstance::Notify()
|
|
|
|
// Purge any notifications associated with a specific object
|
|
void NormInstance::PurgeObjectNotifications(NormObjectHandle objectHandle)
|
|
{
|
|
if (NORM_OBJECT_INVALID == objectHandle) return;
|
|
|
|
Notification::Queue::Iterator iterator(notify_queue);
|
|
Notification* next;
|
|
while (NULL != (next = iterator.GetNextItem()))
|
|
{
|
|
if (objectHandle == next->event.object)
|
|
{
|
|
// "Release" the previously-retained object handle
|
|
((NormObject*)objectHandle)->Release();
|
|
// Remove from queue and put in pool
|
|
notify_queue.Remove(*next);
|
|
notify_pool.Append(*next);
|
|
}
|
|
}
|
|
if ((NULL != previous_notification) && (objectHandle == previous_notification->event.object))
|
|
{
|
|
// "Release" any previously-retained object or node handle
|
|
((NormObject*)(previous_notification->event.object))->Release();
|
|
notify_pool.Append(*previous_notification);
|
|
previous_notification = NULL;
|
|
}
|
|
// TBD - check if event queue is emptied and reset event/fd
|
|
} // end NormInstance::PurgeObjectNotifications()
|
|
|
|
// Purge any notifications associated with a specific remote sender node
|
|
void NormInstance::PurgeNodeNotifications(NormNodeHandle nodeHandle)
|
|
{
|
|
if (NORM_NODE_INVALID == nodeHandle) return;
|
|
Notification::Queue::Iterator iterator(notify_queue);
|
|
Notification* next;
|
|
while (NULL != (next = iterator.GetNextItem()))
|
|
{
|
|
if (nodeHandle == next->event.sender)
|
|
{
|
|
// "Release" the previously-retained object handle
|
|
((NormNode*)nodeHandle)->Release();
|
|
// Remove this notification from queue and return to pool
|
|
notify_queue.Remove(*next);
|
|
notify_pool.Append(*next);
|
|
}
|
|
}
|
|
if ((NULL != previous_notification) && (nodeHandle == previous_notification->event.sender))
|
|
{
|
|
// "Release" any previously-retained object or node handle
|
|
if (NORM_OBJECT_INVALID != previous_notification->event.object)
|
|
((NormObject*)(previous_notification->event.object))->Release();
|
|
else
|
|
((NormNode*)(previous_notification->event.sender))->Release();
|
|
notify_pool.Append(*previous_notification);
|
|
previous_notification = NULL;
|
|
}
|
|
if (notify_queue.IsEmpty()) ResetNotificationEvent();
|
|
} // end NormInstance::PurgeNodeNotifications()
|
|
|
|
void NormInstance::PurgeSessionNotifications(NormSessionHandle sessionHandle)
|
|
{
|
|
if (NORM_SESSION_INVALID == sessionHandle) return;
|
|
Notification::Queue::Iterator iterator(notify_queue);
|
|
Notification* next;
|
|
while (NULL != (next = iterator.GetNextItem()))
|
|
{
|
|
if (next->event.session == sessionHandle)
|
|
{
|
|
if (NORM_OBJECT_INVALID != next->event.object)
|
|
((NormObject*)next->event.object)->Release();
|
|
else if (NORM_NODE_INVALID != next->event.sender)
|
|
((NormNode*)next->event.sender)->Release();
|
|
// Remove this notification from queue and return to pool
|
|
notify_queue.Remove(*next);
|
|
notify_pool.Append(*next);
|
|
}
|
|
}
|
|
if ((NULL != previous_notification) && (sessionHandle == previous_notification->event.session))
|
|
{
|
|
// "Release" any previously-retained object or node handle
|
|
if (NORM_OBJECT_INVALID != previous_notification->event.object)
|
|
((NormObject*)(previous_notification->event.object))->Release();
|
|
else if (NORM_NODE_INVALID != previous_notification->event.sender)
|
|
((NormNode*)(previous_notification->event.sender))->Release();
|
|
notify_pool.Append(*previous_notification);
|
|
previous_notification = NULL;
|
|
}
|
|
if (notify_queue.IsEmpty()) ResetNotificationEvent();
|
|
} // end NormInstance::PurgeSessionNotifications()
|
|
|
|
// Purges notifications of a specific type for a specific session
|
|
void NormInstance::PurgeNotifications(NormSessionHandle sessionHandle, NormEventType eventType)
|
|
{
|
|
if (NORM_SESSION_INVALID == sessionHandle) return;
|
|
Notification::Queue::Iterator iterator(notify_queue);
|
|
Notification* next;
|
|
while (NULL != (next = iterator.GetNextItem()))
|
|
{
|
|
if ((next->event.session == sessionHandle) &&
|
|
(next->event.type == eventType))
|
|
{
|
|
if (NORM_OBJECT_INVALID != next->event.object)
|
|
((NormObject*)next->event.object)->Release();
|
|
else if (NORM_NODE_INVALID != next->event.sender)
|
|
((NormNode*)next->event.sender)->Release();
|
|
// Remove this notification from queue and return to pool
|
|
notify_queue.Remove(*next);
|
|
notify_pool.Append(*next);
|
|
}
|
|
}
|
|
if (notify_queue.IsEmpty()) ResetNotificationEvent();
|
|
} // end NormInstance::PurgeNotifications()
|
|
|
|
// NormInstance::dispatcher MUST be suspended _before_ calling this
|
|
bool NormInstance::GetNextEvent(NormEvent* theEvent)
|
|
{
|
|
// First, do any garbage collection for "previous_notification"
|
|
if (NULL != previous_notification)
|
|
{
|
|
// "Release" any previously-retained object or node handle
|
|
if (NORM_OBJECT_INVALID != previous_notification->event.object)
|
|
((NormObject*)(previous_notification->event.object))->Release();
|
|
else if (NORM_NODE_INVALID != previous_notification->event.sender)
|
|
((NormNode*)(previous_notification->event.sender))->Release();
|
|
notify_pool.Append(*previous_notification);
|
|
previous_notification = NULL;
|
|
}
|
|
Notification* next;
|
|
while (NULL != (next = notify_queue.RemoveHead()))
|
|
{
|
|
switch (next->event.type)
|
|
{
|
|
case NORM_EVENT_INVALID:
|
|
if (!notify_queue.IsEmpty())
|
|
{
|
|
// Discard this invalid event and get next one
|
|
notify_pool.Append(*next);
|
|
continue;
|
|
}
|
|
break;
|
|
case NORM_RX_OBJECT_UPDATED:
|
|
{
|
|
// reset update event notification for non-streams
|
|
// (NormStreamRead() takes care of streams)
|
|
NormObject* obj = ((NormObject*)next->event.object);
|
|
if (!obj->IsStream()) obj->SetNotifyOnUpdate(true);
|
|
break;
|
|
}
|
|
case NORM_SEND_ERROR:
|
|
{
|
|
NormSession* session = (NormSession*)next->event.session;
|
|
session->ClearSendError();
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
if (NULL != next)
|
|
{
|
|
previous_notification = next; // keep dispatched event for garbage collection
|
|
if (NULL != theEvent) *theEvent = next->event;
|
|
}
|
|
else if (NULL != theEvent)
|
|
{
|
|
theEvent->type = NORM_EVENT_INVALID;
|
|
theEvent->session = NORM_SESSION_INVALID;
|
|
theEvent->sender = NORM_NODE_INVALID;
|
|
theEvent->object = NORM_OBJECT_INVALID;
|
|
}
|
|
if (notify_queue.IsEmpty()) ResetNotificationEvent();
|
|
return (NULL != next);
|
|
} // end NormInstance::GetNextEvent()
|
|
|
|
bool NormInstance::WaitForEvent()
|
|
{
|
|
if (!dispatcher.IsThreaded())
|
|
{
|
|
PLOG(PL_FATAL, "NormInstance::WaitForEvent() warning: NORM thread not running!\n");
|
|
return false;
|
|
}
|
|
#ifdef WIN32
|
|
WaitForSingleObject(notify_event, INFINITE);
|
|
#else
|
|
fd_set fdSet;
|
|
FD_ZERO(&fdSet);
|
|
FD_SET(notify_fd[0], &fdSet);
|
|
while (1)
|
|
{
|
|
if (0 > select(notify_fd[0] + 1, &fdSet, (fd_set*)NULL,
|
|
(fd_set*)NULL, (struct timeval*)NULL))
|
|
{
|
|
if (EINTR != errno)
|
|
{
|
|
PLOG(PL_FATAL, "NormInstance::WaitForEvent() select() error: %s\n",
|
|
GetErrorString());
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
return true;
|
|
} // end NormInstance::WaitForEvent()
|
|
|
|
|
|
bool NormInstance::Startup(bool priorityBoost)
|
|
{
|
|
// 1) Create descriptor to use for event notification
|
|
#ifdef WIN32
|
|
// Create initially non-signalled, manual reset event
|
|
notify_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
if (NULL == notify_event)
|
|
{
|
|
PLOG(PL_FATAL, "NormInstance::Startup() CreateEvent() error: %s\n", GetErrorString());
|
|
return false;
|
|
}
|
|
#else
|
|
if (0 != pipe(notify_fd))
|
|
{
|
|
PLOG(PL_FATAL, "NormInstance::Startup() pipe() error: %s\n", GetErrorString());
|
|
return false;
|
|
}
|
|
// make reading non-blocking
|
|
if(-1 == fcntl(notify_fd[0], F_SETFL, fcntl(notify_fd[0], F_GETFL, 0) | O_NONBLOCK))
|
|
{
|
|
PLOG(PL_FATAL, "NormInstance::Startup() fcntl(F_SETFL(O_NONBLOCK)) error: %s\n", GetErrorString());
|
|
close(notify_fd[0]);
|
|
close(notify_fd[1]);
|
|
notify_fd[0] = notify_fd[1] = -1;
|
|
return false;
|
|
}
|
|
#endif // if/else WIN32/UNIX
|
|
// 2) Start thread
|
|
priority_boost = priorityBoost;
|
|
return dispatcher.StartThread(priorityBoost);
|
|
} // end NormInstance::Startup()
|
|
|
|
|
|
|
|
void NormInstance::ReleasePreviousEvent()
|
|
{
|
|
// Garbage collect our "previous_notification"
|
|
if (NULL != previous_notification)
|
|
{
|
|
// Release any previously-retained object or node handles
|
|
if (NORM_OBJECT_INVALID != previous_notification->event.object)
|
|
((NormObject*)(previous_notification->event.object))->Release();
|
|
else if (NORM_NODE_INVALID != previous_notification->event.sender)
|
|
((NormNode*)(previous_notification->event.sender))->Release();
|
|
notify_pool.Append(*previous_notification);
|
|
previous_notification = NULL;
|
|
}
|
|
} // end NormInstance::ReleasePreviousEvent()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormReleasePreviousEvent(NormInstanceHandle instanceHandle)
|
|
{
|
|
NormInstance* instance = (NormInstance*)instanceHandle;
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
instance->ReleasePreviousEvent();
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormReleasePreviousEvent()
|
|
|
|
|
|
void NormInstance::Shutdown()
|
|
{
|
|
dispatcher.Stop();
|
|
#ifdef WIN32
|
|
if (NULL != notify_event)
|
|
{
|
|
CloseHandle(notify_event);
|
|
notify_event = NULL;
|
|
}
|
|
#else
|
|
if (notify_fd[0] >= 0)
|
|
{
|
|
close(notify_fd[0]); // close read end of pipe
|
|
close(notify_fd[1]); // close write end of pipe
|
|
notify_fd[0] = notify_fd[1] = -1;
|
|
}
|
|
#endif // if/else WIN32/UNIX
|
|
if (rx_cache_path)
|
|
{
|
|
delete[] (char*)rx_cache_path;
|
|
rx_cache_path = NULL;
|
|
}
|
|
|
|
// Garbage collect our "previous_notification"
|
|
if (NULL != previous_notification)
|
|
{
|
|
// Release any previously-retained object or node handles
|
|
if (NORM_OBJECT_INVALID != previous_notification->event.object)
|
|
((NormObject*)(previous_notification->event.object))->Release();
|
|
else if (NORM_NODE_INVALID != previous_notification->event.sender)
|
|
((NormNode*)(previous_notification->event.sender))->Release();
|
|
notify_pool.Append(*previous_notification);
|
|
previous_notification = NULL;
|
|
}
|
|
|
|
Notification* next;
|
|
while (NULL != (next = notify_queue.RemoveHead()))
|
|
{
|
|
switch (next->event.type)
|
|
{
|
|
case NORM_RX_OBJECT_NEW:
|
|
{
|
|
NormObject* obj = (NormObject*)next->event.object;
|
|
switch (obj->GetType())
|
|
{
|
|
case NormObject::FILE:
|
|
// (TBD) unlink temp file?
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
if (NORM_OBJECT_INVALID != next->event.object)
|
|
((NormObject*)(next->event.object))->Release();
|
|
else if (NORM_NODE_INVALID != next->event.sender)
|
|
((NormNode*)(next->event.sender))->Release();
|
|
delete next;
|
|
}
|
|
notify_pool.Destroy();
|
|
} // end NormInstance::Shutdown()
|
|
|
|
// This function doesn't make sense?
|
|
UINT32 NormInstance::CountCompletedObjects(NormSession* session)
|
|
{
|
|
UINT32 result = 0UL;
|
|
Notification::Queue::Iterator iterator(notify_queue);
|
|
Notification* next;
|
|
while (NULL != (next = iterator.GetNextItem()))
|
|
{
|
|
if ((session == next->event.session) &&
|
|
(NORM_RX_OBJECT_COMPLETED == next->event.type))
|
|
{
|
|
result ++;
|
|
}
|
|
}
|
|
return result;
|
|
} // end NormInstance::CountCompletedObjects()
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// NORM API FUNCTION IMPLEMENTATIONS
|
|
//
|
|
|
|
NORM_API_LINKAGE
|
|
int NormGetVersion(int* major, int* minor, int* patch)
|
|
{
|
|
// TBD - use normVersion.h info instead
|
|
if (NULL != major) *major = NORM_VERSION_MAJOR;
|
|
if (NULL != minor) *minor = NORM_VERSION_MINOR;
|
|
if (NULL != patch) *patch = NORM_VERSION_PATCH;
|
|
return NORM_VERSION_MAJOR;
|
|
} // end NormGetVersion()
|
|
|
|
/** NORM API Initialization */
|
|
|
|
NORM_API_LINKAGE
|
|
NormInstanceHandle NormCreateInstance(bool priorityBoost)
|
|
{
|
|
NormInstance* normInstance = new NormInstance;
|
|
if (normInstance)
|
|
{
|
|
if (normInstance->Startup(priorityBoost))
|
|
return ((NormInstanceHandle)normInstance);
|
|
else
|
|
delete normInstance;
|
|
}
|
|
return NORM_INSTANCE_INVALID;
|
|
} // end NormCreateInstance()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormDestroyInstance(NormInstanceHandle instanceHandle)
|
|
{
|
|
delete ((NormInstance*)instanceHandle);
|
|
} // end NormDestroyInstance()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormStopInstance(NormInstanceHandle instanceHandle)
|
|
{
|
|
NormInstance* instance = (NormInstance*)instanceHandle;
|
|
if (instance) instance->Stop(); // stops NORM protocol thread
|
|
} // end NormStopInstance()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormRestartInstance(NormInstanceHandle instanceHandle)
|
|
{
|
|
NormInstance* instance = (NormInstance*)instanceHandle;
|
|
if (instance)
|
|
{
|
|
if (instance->dispatcher.IsThreaded())
|
|
instance->Stop();
|
|
return instance->Start();
|
|
}
|
|
return false; // invalid instanceHandle
|
|
} // end NormStartInstance()
|
|
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormSuspendInstance(NormInstanceHandle instanceHandle)
|
|
{
|
|
NormInstance* instance = (NormInstance*)instanceHandle;
|
|
if (instance)
|
|
return instance->dispatcher.SuspendThread(); // stops NORM protocol thread
|
|
else
|
|
return false;
|
|
} // end NormSuspendInstance()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormResumeInstance(NormInstanceHandle instanceHandle)
|
|
{
|
|
NormInstance* instance = (NormInstance*)instanceHandle;
|
|
if (instance) instance->dispatcher.ResumeThread();
|
|
} // end NormResumeInstance()
|
|
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormSetCacheDirectory(NormInstanceHandle instanceHandle,
|
|
const char* cachePath)
|
|
{
|
|
NormInstance* instance = (NormInstance*)instanceHandle;
|
|
if (instance)
|
|
return instance->SetCacheDirectory(cachePath);
|
|
else
|
|
return false;
|
|
} // end NormSetCacheDirectory()
|
|
|
|
NORM_API_LINKAGE
|
|
NormDescriptor NormGetDescriptor(NormInstanceHandle instanceHandle)
|
|
{
|
|
NormInstance* instance = (NormInstance*)instanceHandle;
|
|
if (instance)
|
|
return (instance->GetDescriptor());
|
|
else
|
|
return NORM_DESCRIPTOR_INVALID;
|
|
} // end NormGetDescriptor()
|
|
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetAllocationFunctions(NormInstanceHandle instanceHandle,
|
|
NormAllocFunctionHandle allocFunc,
|
|
NormFreeFunctionHandle freeFunc)
|
|
{
|
|
NormInstance* instance = (NormInstance*)instanceHandle;
|
|
instance->SetAllocationFunctions(allocFunc, freeFunc);
|
|
} // end NormSetAllocationFunctions()
|
|
|
|
|
|
// if "waitForEvent" is false, this is a non-blocking call
|
|
// (TBD) add a timeout option to this?
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormGetNextEvent(NormInstanceHandle instanceHandle, NormEvent* theEvent, bool waitForEvent)
|
|
{
|
|
NormInstance* instance = (NormInstance*)instanceHandle;
|
|
bool result = false;
|
|
if (instance)
|
|
{
|
|
if (instance->dispatcher.SuspendThread())
|
|
{
|
|
if (waitForEvent)
|
|
{
|
|
if (instance->NotifyQueueIsEmpty())
|
|
{
|
|
// no pending events, so resume and wait
|
|
instance->dispatcher.ResumeThread();
|
|
if (!instance->WaitForEvent())
|
|
{
|
|
// Indication that NormInstance is dead
|
|
// TBD - how do we inform app although this shouldn't
|
|
// happen unless the app destroys the "instance"
|
|
return false;
|
|
}
|
|
// re-suspend thread after wait
|
|
if (!instance->dispatcher.SuspendThread()) return false;
|
|
}
|
|
}
|
|
result = instance->GetNextEvent(theEvent);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
return result;
|
|
} // end NormGetNextEvent()
|
|
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormIsUnicastAddress(const char* address)
|
|
{
|
|
// TBD - is this really a thread-safe thing to do?
|
|
ProtoAddress addr;
|
|
if ((NULL != address) && addr.ResolveFromString(address))
|
|
return addr.IsUnicast();
|
|
else
|
|
return false; // not valid, so not unicast
|
|
} // end NormIsUnicast()
|
|
|
|
/** NORM Session Creation and Control Functions */
|
|
NORM_API_LINKAGE
|
|
NormSessionHandle NormCreateSession(NormInstanceHandle instanceHandle,
|
|
const char* sessionAddr,
|
|
UINT16 sessionPort,
|
|
NormNodeId localNodeId)
|
|
{
|
|
// (TBD) wrap this with SuspendThread/ResumeThread ???
|
|
NormInstance* instance = (NormInstance*)instanceHandle;
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session =
|
|
instance->session_mgr.NewSession(sessionAddr, sessionPort, localNodeId);
|
|
instance->dispatcher.ResumeThread();
|
|
if (NULL != session)
|
|
return ((NormSessionHandle)session);
|
|
}
|
|
return NORM_SESSION_INVALID;
|
|
} // end NormCreateSession()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormDestroySession(NormSessionHandle sessionHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (NULL != session)
|
|
{
|
|
session->Close();
|
|
session->GetSessionMgr().DeleteSession(session);
|
|
instance->PurgeSessionNotifications(sessionHandle);
|
|
}
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormDestroySession()
|
|
|
|
NORM_API_LINKAGE
|
|
NormInstanceHandle NormGetInstance(NormSessionHandle sessionHandle)
|
|
{
|
|
|
|
return (NormInstanceHandle)NormInstance::GetInstanceFromSession(sessionHandle);
|
|
} // end NormGetIntance()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetUserData(NormSessionHandle sessionHandle, const void* userData)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->SetUserData(userData);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetUserData()
|
|
|
|
NORM_API_LINKAGE
|
|
const void* NormGetUserData(NormSessionHandle sessionHandle)
|
|
{
|
|
const void* userData = NULL;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance)
|
|
{
|
|
if (instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
userData = session->GetUserData();
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
return userData;
|
|
} // end NormGetUserData()
|
|
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetUserTimer(NormSessionHandle sessionHandle, double seconds)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance)
|
|
{
|
|
if (instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->SetUserTimer(seconds);
|
|
instance->PurgeNotifications(sessionHandle, NORM_USER_TIMEOUT);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
} // end NormSetUserTimer()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormCancelUserTimer(NormSessionHandle sessionHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (NULL != instance)
|
|
{
|
|
if (instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->SetUserTimer(-1.0); // interval less than zero cancels timer
|
|
instance->PurgeNotifications(sessionHandle, NORM_USER_TIMEOUT);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
} // end NormCancelUserTimer()
|
|
|
|
|
|
NORM_API_LINKAGE
|
|
NormNodeId NormGetLocalNodeId(NormSessionHandle sessionHandle)
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (NULL != session)
|
|
return session->LocalNodeId();
|
|
else
|
|
return NORM_NODE_NONE;
|
|
} // end NormGetLocalNodeId()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormGetAddress(NormSessionHandle sessionHandle,
|
|
char* addrBuffer,
|
|
unsigned int* bufferLen,
|
|
UINT16* port)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (NULL != instance)
|
|
{
|
|
if (instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
const ProtoAddress& sessionAddr = session->Address();
|
|
unsigned int addrLen = sessionAddr.GetLength();
|
|
if (addrBuffer && bufferLen && (addrLen <= *bufferLen))
|
|
{
|
|
memcpy(addrBuffer, sessionAddr.GetRawHostAddress(), addrLen);
|
|
result = true;
|
|
}
|
|
else if (NULL == addrBuffer)
|
|
{
|
|
result = true; // just a query for addrLen and/or port
|
|
}
|
|
if (bufferLen) *bufferLen = addrLen;
|
|
if (port) *port = sessionAddr.GetPort();
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
return result;
|
|
} // end NormGetAddress()
|
|
|
|
NORM_API_LINKAGE
|
|
UINT16 NormGetRxPort(NormSessionHandle sessionHandle)
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (NULL != session)
|
|
return session->GetRxPort();
|
|
else
|
|
return 0;
|
|
} // end NormGetRxPort()
|
|
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormGetRxBindAddress(NormSessionHandle sessionHandle, char* addr, unsigned int& addrLen, UINT16& port)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if ((NULL != instance) && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
port = session->GetRxPort();
|
|
ProtoAddress bindAddr = session->GetRxBindAddr();
|
|
if (!bindAddr.IsValid())
|
|
{
|
|
addrLen = 0;
|
|
result = true;
|
|
}
|
|
else if (addrLen < bindAddr.GetLength())
|
|
{
|
|
addrLen = bindAddr.GetLength();
|
|
}
|
|
else
|
|
{
|
|
addrLen = bindAddr.GetLength();
|
|
memcpy(addr, bindAddr.GetRawHostAddress(), addrLen);
|
|
result = true;
|
|
}
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
else
|
|
{
|
|
addrLen = port = 0;
|
|
}
|
|
return result;
|
|
} // end NormGetRxBindAddress()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormSetTxPort(NormSessionHandle sessionHandle,
|
|
UINT16 txPort,
|
|
bool enableReuse,
|
|
const char* txAddress)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (NULL != instance)
|
|
{
|
|
if (instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (NULL != session)
|
|
result = session->SetTxPort(txPort, enableReuse, txAddress);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
return result;
|
|
} // end NormSetTxPort()
|
|
|
|
NORM_API_LINKAGE
|
|
UINT16 NormGetTxPort(NormSessionHandle sessionHandle)
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (NULL != session)
|
|
return session->GetTxPort();
|
|
else
|
|
return 0;
|
|
} // end NormGetTxPort()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetTxOnly(NormSessionHandle sessionHandle,
|
|
bool txOnly,
|
|
bool connectToSessionAddress)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->SetTxOnly(txOnly, connectToSessionAddress);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetTxOnly()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormPresetObjectInfo(NormSessionHandle sessionHandle,
|
|
unsigned long objectSize,
|
|
UINT16 segmentSize,
|
|
UINT16 numData,
|
|
UINT16 numParity)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
{
|
|
result = session->SetPresetFtiData((unsigned int)objectSize, segmentSize, numData, numParity);
|
|
if (result) session->SenderSetFtiMode(NormSession::FTI_PRESET);
|
|
}
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormPresetObjectInfo()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormLimitObjectInfo(NormSessionHandle sessionHandle, bool state)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
{
|
|
if (state)
|
|
session->SenderSetFtiMode(NormSession::FTI_INFO);
|
|
else
|
|
session->SenderSetFtiMode(NormSession::FTI_ALWAYS);
|
|
}
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormLimitObjectInfo()
|
|
|
|
// These functions are used internally by the NormSocket API extension
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetId(NormSessionHandle sessionHandle, NormNodeId normId)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (NULL != session) session->SetNodeId(normId);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetId()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormChangeDestination(NormSessionHandle sessionHandle,
|
|
const char* sessionAddress,
|
|
UINT16 sessionPort,
|
|
bool connectToSessionAddress)
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (NULL == session) return false;
|
|
// First, see if we can make a valid ProtoAddress
|
|
ProtoAddress dest;
|
|
if (NULL != sessionAddress)
|
|
{
|
|
if (!dest.ResolveFromString(sessionAddress))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
dest = session->Address();
|
|
}
|
|
dest.SetPort(sessionPort);
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
if (NULL != session)
|
|
{
|
|
session->SetAddress(dest);
|
|
if (connectToSessionAddress)
|
|
session->SetTxOnly(session->GetTxOnly(), true);
|
|
}
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return true;
|
|
} // end NormChangeDestination()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetServerListener(NormSessionHandle sessionHandle, bool state)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (NULL != instance)
|
|
{
|
|
if (instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->SetServerListener(state);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
} // end NormSetServerListener()
|
|
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormTransferSender(NormSessionHandle sessionHandle, NormNodeHandle senderHandle)
|
|
{
|
|
// The NormSession::InsertRemoteSender() used below synthesizes a NORM_CMD(CC) that
|
|
// is injected into the "sessionHandle" NormSession which results in a new remote
|
|
// sender being established. I.e., it basically "clones" the sender from another
|
|
// NormSession into the target NormSession
|
|
bool result = false;
|
|
NormInstance* dstInstance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (NULL != dstInstance)
|
|
{
|
|
if (dstInstance->dispatcher.SuspendThread())
|
|
{
|
|
NormInstance* srcInstance = NormInstance::GetInstanceFromNode(senderHandle);
|
|
if (srcInstance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
NormSenderNode* sender = (NormSenderNode*)senderHandle;
|
|
if ((NULL != session) && (NULL != sender))
|
|
result = session->InsertRemoteSender(*sender);
|
|
srcInstance->dispatcher.ResumeThread();
|
|
}
|
|
dstInstance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
return result;
|
|
} // end NormTransferSender()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetRxPortReuse(NormSessionHandle sessionHandle,
|
|
bool enableReuse,
|
|
const char* rxAddress, // bind() to <rxAddress>/<sessionPort>
|
|
const char* senderAddress, // connect() to <senderAddress>/<senderPort>
|
|
UINT16 senderPort)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (NULL != instance)
|
|
{
|
|
if (instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->SetRxPortReuse(enableReuse, rxAddress, senderAddress, senderPort);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
} // end NormSetRxPortReuse()
|
|
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetEcnSupport(NormSessionHandle sessionHandle, bool ecnEnable, bool ignoreLoss, bool tolerateLoss)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (NULL != instance)
|
|
{
|
|
if (instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->SetEcnSupport(ecnEnable, ignoreLoss, tolerateLoss);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
} // end NormSetEcnSupport()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormSetMulticastInterface(NormSessionHandle sessionHandle,
|
|
const char* interfaceName)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (NULL != instance)
|
|
{
|
|
if (instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
result = session->SetMulticastInterface(interfaceName);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
return result;
|
|
} // end NormSetMulticastInterface()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormSetSSM(NormSessionHandle sessionHandle,
|
|
const char* sourceAddress)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (NULL != instance)
|
|
{
|
|
if (instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
result = session->SetSSM(sourceAddress);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
return result;
|
|
} // end NormSetSSM()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormSetTTL(NormSessionHandle sessionHandle,
|
|
unsigned char ttl)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (NULL != instance)
|
|
{
|
|
if (instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
result = session->SetTTL(ttl);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
return result;
|
|
} // end NormSetTTL()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormSetTOS(NormSessionHandle sessionHandle,
|
|
unsigned char tos)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance)
|
|
{
|
|
if (instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
result = session->SetTOS(tos);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
return result;
|
|
} // end NormSetTOS()
|
|
|
|
/** Special test/debug support functions */
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormSetLoopback(NormSessionHandle sessionHandle, bool state)
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
return session->SetLoopback(state);
|
|
else
|
|
return false;
|
|
} // end NormSetLoopback()
|
|
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormSetMulticastLoopback(NormSessionHandle sessionHandle, bool state)
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
return session->SetMulticastLoopback(state);
|
|
else
|
|
return false;
|
|
} // end NormSetLoopback()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormSetFragmentation(NormSessionHandle sessionHandle, bool state)
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
return session->SetFragmentation(state);
|
|
else
|
|
return false;
|
|
} // end NormSetFragmentation()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetMessageTrace(NormSessionHandle sessionHandle, bool state)
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->SetTrace(state);
|
|
} // end NormSetMessageTrace()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetTxLoss(NormSessionHandle sessionHandle, double percent)
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->SetTxLoss(percent);
|
|
} // end NormSetTxLoss()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetRxLoss(NormSessionHandle sessionHandle, double percent)
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->SetRxLoss(percent);
|
|
} // end NormSetRxLoss()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormOpenDebugLog(NormInstanceHandle instanceHandle, const char *path)
|
|
{
|
|
/* NOTE: This only locks one thread. Multiple NormInstances could
|
|
cause problems with this. */
|
|
bool result = false;
|
|
NormInstance* instance = (NormInstance*)instanceHandle;
|
|
if (instance->dispatcher.SuspendThread()) {
|
|
result = OpenDebugLog(path);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NORM_API_LINKAGE
|
|
void NormCloseDebugLog(NormInstanceHandle instanceHandle)
|
|
{
|
|
/* NOTE: This only locks one thread. Multiple NormInstances could
|
|
cause problems with this. */
|
|
NormInstance* instance = (NormInstance*)instanceHandle;
|
|
if (instance->dispatcher.SuspendThread()) {
|
|
CloseDebugLog();
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormOpenDebugPipe(NormInstanceHandle instanceHandle, const char *pipeName)
|
|
{
|
|
/* NOTE: This only locks one thread. Multiple NormInstances could
|
|
cause problems with this. */
|
|
bool result = false;
|
|
NormInstance* instance = (NormInstance*)instanceHandle;
|
|
if (instance->dispatcher.SuspendThread()) {
|
|
result = OpenDebugPipe(pipeName);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormOpenDebugPipe()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormCloseDebugPipe(NormInstanceHandle instanceHandle)
|
|
{
|
|
/* NOTE: This only locks one thread. Multiple NormInstances could
|
|
cause problems with this. */
|
|
NormInstance* instance = (NormInstance*)instanceHandle;
|
|
if (instance->dispatcher.SuspendThread()) {
|
|
CloseDebugPipe();
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormCloseDebugPipe()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetDebugLevel(unsigned int level)
|
|
{
|
|
// Sets underlying Protolib debug leve
|
|
SetDebugLevel(level);
|
|
}
|
|
|
|
NORM_API_LINKAGE
|
|
unsigned int NormGetDebugLevel()
|
|
{
|
|
return GetDebugLevel();
|
|
}
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetReportInterval(NormSessionHandle sessionHandle, double interval)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
session->SetReportTimerInterval(interval);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetReportInterval()
|
|
|
|
NORM_API_LINKAGE
|
|
double NormGetReportInterval(NormSessionHandle sessionHandle)
|
|
{
|
|
double result = 0;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
result = session->GetReportTimerInterval();
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormGetReportInterval()
|
|
|
|
/** NORM Sender Functions */
|
|
|
|
NORM_API_LINKAGE
|
|
NormSessionId NormGetRandomSessionId()
|
|
{
|
|
ProtoTime currentTime;
|
|
currentTime.GetCurrentTime();
|
|
srand((unsigned int)currentTime.usec()); // seed random number generator
|
|
return (NormSessionId)rand();
|
|
} // end NormGetRandomSessionId()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormStartSender(NormSessionHandle sessionHandle,
|
|
NormSessionId sessionId,
|
|
UINT32 bufferSpace,
|
|
UINT16 segmentSize,
|
|
UINT16 numData,
|
|
UINT16 numParity,
|
|
UINT8 fecId)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
result = session->StartSender(sessionId, bufferSpace, segmentSize, numData, numParity, fecId);
|
|
else
|
|
result = false;
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormStartSender()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormStopSender(NormSessionHandle sessionHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->StopSender();
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormStopSender()
|
|
|
|
|
|
NORM_API_LINKAGE
|
|
double NormGetTxRate(NormSessionHandle sessionHandle)
|
|
{
|
|
if (NORM_SESSION_INVALID != sessionHandle)
|
|
return (((NormSession*)sessionHandle)->GetTxRate());
|
|
else
|
|
return -1.0;
|
|
} // end NormGetTxRate()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetTxRate(NormSessionHandle sessionHandle,
|
|
double bitsPerSecond)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->SetTxRate(bitsPerSecond);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetTxRate()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormSetTxSocketBuffer(NormSessionHandle sessionHandle,
|
|
unsigned int bufferSize)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
result = session->SetTxSocketBuffer(bufferSize);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormSetTxSocketBuffer()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetFlowControl(NormSessionHandle sessionHandle, double flowControlFactor)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->SetFlowControl(flowControlFactor);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetFlowControl()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetCongestionControl(NormSessionHandle sessionHandle, bool enable, bool adjustRate)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->SetCongestionControl(enable, adjustRate);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetCongestionControl()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetTxRateBounds(NormSessionHandle sessionHandle,
|
|
double rateMin,
|
|
double rateMax)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->SetTxRateBounds(rateMin, rateMax);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetTxRateBounds()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetTxCacheBounds(NormSessionHandle sessionHandle,
|
|
NormSize sizeMax,
|
|
UINT32 countMin,
|
|
UINT32 countMax)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
NormObjectSize theSize(sizeMax);
|
|
if (session) session->SetTxCacheBounds(theSize, countMin, countMax);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetTxCacheBounds()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetAutoParity(NormSessionHandle sessionHandle, unsigned char autoParity)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->SenderSetAutoParity(autoParity);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetAutoParity()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormRegisterFecCoder(NormSessionHandle sessionHandle,
|
|
UINT8 fecId,
|
|
NormEncoderFactory encoderFactory,
|
|
NormDecoderFactory decoderFactory,
|
|
bool isRateless)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
{
|
|
session->GetSessionMgr().RegisterFecCoder(fecId, encoderFactory, decoderFactory, isRateless);
|
|
instance->dispatcher.ResumeThread();
|
|
return true;
|
|
}
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return false;
|
|
} // end NormRegisterFecCoder()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormRegisterFecLayout(NormInstanceHandle instanceHandle, UINT8 fecId, const NormFecLayout* layout)
|
|
{
|
|
NormInstance* instance = (NormInstance*)instanceHandle;
|
|
if (instance)
|
|
instance->SetFecLayout(fecId, layout);
|
|
} // end NormRegisterFecLayout()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetGrttEstimate(NormSessionHandle sessionHandle,
|
|
double grttEstimate)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->SenderSetGrtt(grttEstimate);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetGrttEstimate()
|
|
|
|
NORM_API_LINKAGE
|
|
double NormGetGrttEstimate(NormSessionHandle sessionHandle)
|
|
{
|
|
if (NORM_SESSION_INVALID != sessionHandle)
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
session->ResetGrttNotification();
|
|
return (session->SenderGrtt());
|
|
}
|
|
else
|
|
{
|
|
return -1.0;
|
|
}
|
|
} // end NormGetGrttEstimate()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetGrttMax(NormSessionHandle sessionHandle,
|
|
double grttMax)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->SetGrttMax(grttMax);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetGrttMax()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetGrttProbingMode(NormSessionHandle sessionHandle,
|
|
NormProbingMode probingMode)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
session->SetGrttProbingMode((NormSession::ProbingMode)probingMode);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetGrttProbingMode()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetGrttProbingInterval(NormSessionHandle sessionHandle,
|
|
double intervalMin,
|
|
double intervalMax)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->SetGrttProbingInterval(intervalMin, intervalMax);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetGrttProbingInterval()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetGrttProbingTOS(NormSessionHandle sessionHandle,
|
|
UINT8 probeTOS)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
session->SetProbeTOS(probeTOS);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetGrttProbingTOS()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetBackoffFactor(NormSessionHandle sessionHandle,
|
|
double backoffFactor)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (backoffFactor >= 0.0)
|
|
session->SetBackoffFactor(backoffFactor);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetBackoffFactor()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetGroupSize(NormSessionHandle sessionHandle,
|
|
unsigned int groupSize)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
session->SenderSetGroupSize((double)groupSize);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetGroupSize()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetTxRobustFactor(NormSessionHandle sessionHandle,
|
|
int robustFactor)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
session->SetTxRobustFactor(robustFactor);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetTxRobustFactor()
|
|
|
|
NORM_API_LINKAGE
|
|
NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle,
|
|
const char* fileName,
|
|
const char* infoPtr,
|
|
unsigned int infoLen)
|
|
{
|
|
NormObjectHandle objectHandle = NORM_OBJECT_INVALID;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
{
|
|
NormObject* obj =
|
|
static_cast<NormObject*>(session->QueueTxFile(fileName, infoPtr, infoLen));
|
|
if (obj) objectHandle = (NormObjectHandle)(obj);
|
|
}
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return objectHandle;
|
|
} // end NormFileEnqueue()
|
|
|
|
NORM_API_LINKAGE
|
|
NormObjectHandle NormDataEnqueue(NormSessionHandle sessionHandle,
|
|
const char* dataPtr,
|
|
UINT32 dataLen,
|
|
const char* infoPtr,
|
|
unsigned int infoLen)
|
|
{
|
|
NormObjectHandle objectHandle = NORM_OBJECT_INVALID;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
{
|
|
NormObject* obj =
|
|
static_cast<NormObject*>(session->QueueTxData(dataPtr, dataLen, infoPtr, infoLen));
|
|
if (NULL != obj) objectHandle = (NormObjectHandle)obj;
|
|
}
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return objectHandle;
|
|
} // end NormDataEnqueue()
|
|
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormRequeueObject(NormSessionHandle sessionHandle, NormObjectHandle objectHandle)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
{
|
|
if (NORM_OBJECT_INVALID != objectHandle)
|
|
result = session->RequeueTxObject((NormObject*)objectHandle);
|
|
}
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormRequeueObject()
|
|
|
|
NORM_API_LINKAGE
|
|
NormObjectHandle NormStreamOpen(NormSessionHandle sessionHandle,
|
|
UINT32 bufferSize,
|
|
const char* infoPtr,
|
|
unsigned int infoLen)
|
|
{
|
|
NormObjectHandle objectHandle = NORM_OBJECT_INVALID;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
{
|
|
NormStreamObject* streamObj = session->QueueTxStream(bufferSize, true, infoPtr, infoLen);
|
|
NormObject* obj =
|
|
static_cast<NormObject*>(streamObj);
|
|
if (obj) objectHandle = (NormObjectHandle)obj;
|
|
}
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return objectHandle;
|
|
} // end NormStreamOpen()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormStreamClose(NormObjectHandle streamHandle, bool graceful)
|
|
{
|
|
NormStreamObject* stream =
|
|
static_cast<NormStreamObject*>((NormObject*)streamHandle);
|
|
if (NULL != stream)
|
|
{
|
|
if (graceful && (NULL == stream->GetSender()))
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
stream->Close(true); // graceful stream closure
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NormObjectCancel(streamHandle);
|
|
}
|
|
}
|
|
} // end NormStreamClose()
|
|
|
|
NORM_API_LINKAGE
|
|
unsigned int NormGetStreamBufferSegmentCount(unsigned int bufferBytes, UINT16 segmentSize, UINT16 blockSize)
|
|
{
|
|
// This same computation is performed in NormStreamObject::Open() in "normObject.cpp"
|
|
// (Note the number of stream buffer segments is always smaller than the
|
|
// blockSize*pending_mask.GetSize())
|
|
unsigned int numBlocks = bufferBytes / (blockSize * segmentSize);
|
|
if (numBlocks < 2) numBlocks = 2; // NORM enforces a 2-block minimum buffer size
|
|
return (numBlocks * blockSize);
|
|
} // end NormGetStreamBufferSegmentCount()
|
|
|
|
NORM_API_LINKAGE
|
|
unsigned int NormStreamWrite(NormObjectHandle streamHandle,
|
|
const char* buffer,
|
|
unsigned int numBytes)
|
|
{
|
|
// Note: Since an underlying issue with ProtoDispatcher::SignalThread() had been resolved,
|
|
// using ProtoDispatcher::SuspendThread() should be sufficient since the underlying
|
|
// protolib time scheduling, etc. code actually invokes SignalThread() on an
|
|
// as-needed basis. Thus, using SuspendThread() (lighter weight) should suffice
|
|
unsigned int result = 0;
|
|
NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle);
|
|
if ((NULL != instance) && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormStreamObject* stream =
|
|
static_cast<NormStreamObject*>((NormObject*)streamHandle);
|
|
result = stream->Write(buffer, numBytes, false);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormStreamWrite()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormStreamFlush(NormObjectHandle streamHandle,
|
|
bool eom,
|
|
NormFlushMode flushMode)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle);
|
|
if ((NULL != instance) && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormStreamObject* stream =
|
|
static_cast<NormStreamObject*>((NormObject*)streamHandle);
|
|
NormStreamObject::FlushMode saveFlushMode = stream->GetFlushMode();
|
|
stream->SetFlushMode((NormStreamObject::FlushMode)flushMode);
|
|
stream->Flush(eom);
|
|
stream->SetFlushMode(saveFlushMode);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormStreamFlush()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormStreamSetAutoFlush(NormObjectHandle streamHandle,
|
|
NormFlushMode flushMode)
|
|
{
|
|
NormStreamObject* stream =
|
|
static_cast<NormStreamObject*>((NormObject*)streamHandle);
|
|
if (stream)
|
|
stream->SetFlushMode((NormStreamObject::FlushMode)flushMode);
|
|
} // end NormStreamSetAutoFlush()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormStreamSetPushEnable(NormObjectHandle streamHandle, bool state)
|
|
{
|
|
NormStreamObject* stream =
|
|
static_cast<NormStreamObject*>((NormObject*)streamHandle);
|
|
if (stream) stream->SetPushMode(state);
|
|
} // end NormStreamSetPushEnable()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormStreamHasVacancy(NormObjectHandle streamHandle)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormStreamObject* stream =
|
|
static_cast<NormStreamObject*>((NormObject*)streamHandle);
|
|
if (NULL != stream)
|
|
result = stream->HasVacancy();
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormStreamHasVacancy()
|
|
|
|
NORM_API_LINKAGE
|
|
unsigned int NormStreamGetVacancy(NormObjectHandle streamHandle, unsigned int bytesWanted)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormStreamObject* stream =
|
|
static_cast<NormStreamObject*>((NormObject*)streamHandle);
|
|
if (NULL != stream)
|
|
result = stream->GetVacancy(bytesWanted);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormStreamGetVacancy()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormStreamMarkEom(NormObjectHandle streamHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormStreamObject* stream =
|
|
static_cast<NormStreamObject*>((NormObject*)streamHandle);
|
|
if (stream) stream->Write(NULL, 0, true);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormStreamMarkEom()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormSetWatermark(NormSessionHandle sessionHandle,
|
|
NormObjectHandle objectHandle,
|
|
bool overrideFlush)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
NormObject* obj = (NormObject*)objectHandle;
|
|
if (session && obj)
|
|
{
|
|
// Purge any existing NORM_TX_WATERMARK_COMPLETED notifications to be safe
|
|
instance->PurgeNotifications(sessionHandle, NORM_TX_WATERMARK_COMPLETED);
|
|
// (segmentId doesn't matter for non-stream)
|
|
if (obj->IsStream())
|
|
{
|
|
NormStreamObject* stream = static_cast<NormStreamObject*>(obj);
|
|
session->SenderSetWatermark(stream->GetId(),
|
|
stream->FlushBlockId(),
|
|
stream->FlushSegmentId(),
|
|
overrideFlush);
|
|
}
|
|
else
|
|
{
|
|
NormBlockId blockId = obj->GetFinalBlockId();
|
|
NormSegmentId segmentId = obj->GetBlockSize(blockId) - 1;
|
|
session->SenderSetWatermark(obj->GetId(),
|
|
blockId,
|
|
segmentId,
|
|
overrideFlush);
|
|
}
|
|
result = true;
|
|
}
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormSetWatermark()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormSetWatermarkEx(NormSessionHandle sessionHandle,
|
|
NormObjectHandle objectHandle,
|
|
const char* buffer,
|
|
unsigned int numBytes,
|
|
bool overrideFlush)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
NormObject* obj = (NormObject*)objectHandle;
|
|
if (session && obj)
|
|
{
|
|
// Purge any existing NORM_TX_WATERMARK_COMPLETED notifications to be safe
|
|
instance->PurgeNotifications(sessionHandle, NORM_TX_WATERMARK_COMPLETED);
|
|
// (segmentId doesn't matter for non-stream)
|
|
if (obj->IsStream())
|
|
{
|
|
NormStreamObject* stream = static_cast<NormStreamObject*>(obj);
|
|
result = session->SenderSetWatermark(stream->GetId(),
|
|
stream->FlushBlockId(),
|
|
stream->FlushSegmentId(),
|
|
overrideFlush,
|
|
buffer, numBytes);
|
|
}
|
|
else
|
|
{
|
|
NormBlockId blockId = obj->GetFinalBlockId();
|
|
NormSegmentId segmentId = obj->GetBlockSize(blockId) - 1;
|
|
result = session->SenderSetWatermark(obj->GetId(),
|
|
blockId,
|
|
segmentId,
|
|
overrideFlush,
|
|
buffer, numBytes);
|
|
}
|
|
}
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormSetWatermarkEx()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormResetWatermark(NormSessionHandle sessionHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
// Purge any existing NORM_TX_WATERMARK_COMPLETED notifications to be safe
|
|
instance->PurgeNotifications(sessionHandle, NORM_TX_WATERMARK_COMPLETED);
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
session->SenderResetWatermark();
|
|
instance->dispatcher.ResumeThread();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
} // end NormResetWatermark()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormCancelWatermark(NormSessionHandle sessionHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
session->SenderCancelWatermark();
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetWatermark()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormAddAckingNode(NormSessionHandle sessionHandle,
|
|
NormNodeId nodeId)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
result = (NULL != session->SenderAddAckingNode(nodeId));
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormAddAckingNode()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormRemoveAckingNode(NormSessionHandle sessionHandle,
|
|
NormNodeId nodeId)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->SenderRemoveAckingNode(nodeId);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormRemoveAckingNode()
|
|
|
|
NORM_API_LINKAGE
|
|
NormNodeHandle NormGetAckingNodeHandle(NormSessionHandle sessionHandle,
|
|
NormNodeId nodeId)
|
|
{
|
|
if (NORM_SESSION_INVALID != sessionHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
NormAckingNode* acker = session->SenderFindAckingNode(nodeId);
|
|
instance->dispatcher.ResumeThread();
|
|
if (NULL != acker)
|
|
return ((NormNodeHandle)static_cast<NormNode*>(acker));
|
|
}
|
|
}
|
|
return NORM_NODE_INVALID;
|
|
} // end NormGetAckingNodeHandle()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetAutoAckingNodes(NormSessionHandle sessionHandle,
|
|
NormTrackingStatus trackingStatus)
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
switch (trackingStatus)
|
|
{
|
|
case NORM_TRACK_NONE:
|
|
session->SenderSetAutoAckingNodes(NormSession::TRACK_NONE);
|
|
break;
|
|
case NORM_TRACK_RECEIVERS:
|
|
session->SenderSetAutoAckingNodes(NormSession::TRACK_RECEIVERS);
|
|
break;
|
|
case NORM_TRACK_SENDERS:
|
|
session->SenderSetAutoAckingNodes(NormSession::TRACK_SENDERS);
|
|
break;
|
|
case NORM_TRACK_ALL:
|
|
session->SenderSetAutoAckingNodes(NormSession::TRACK_ALL);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} // end NormSetAutoAckingNodes()
|
|
|
|
NORM_API_LINKAGE
|
|
NormAckingStatus NormGetAckingStatus(NormSessionHandle sessionHandle,
|
|
NormNodeId nodeId)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
NormAckingStatus status =
|
|
(NormAckingStatus)session->SenderGetAckingStatus(nodeId);
|
|
instance->dispatcher.ResumeThread();
|
|
return status;
|
|
}
|
|
else
|
|
{
|
|
return NORM_ACK_INVALID;
|
|
}
|
|
} // end NormGetAckingNodeStatus()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormGetNextAckingNode(NormSessionHandle sessionHandle,
|
|
NormNodeId* nodeId,
|
|
NormAckingStatus* ackingStatus)
|
|
{
|
|
if (NULL == nodeId) return false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
bool result = session->SenderGetNextAckingNode(*nodeId, (NormSession::AckingStatus*)ackingStatus);
|
|
instance->dispatcher.ResumeThread();
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
} // end NormGetNextAckingNode()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormGetAckEx(NormSessionHandle sessionHandle,
|
|
NormNodeId nodeId,
|
|
char* buffer,
|
|
unsigned int* buflen)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
bool result = (NormAckingStatus)session->SenderGetAckEx(nodeId, buffer, buflen);
|
|
instance->dispatcher.ResumeThread();
|
|
return result;
|
|
}
|
|
if (NULL != buflen) *buflen = 0;
|
|
return false;
|
|
} // end NormGetAckEx()
|
|
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormSendCommand(NormSessionHandle sessionHandle,
|
|
const char* cmdBuffer,
|
|
unsigned int cmdLength,
|
|
bool robust)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
bool result = session->SenderSendCmd(cmdBuffer, cmdLength, robust);
|
|
instance->dispatcher.ResumeThread();
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
} // end NormSendCommand()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormCancelCommand(NormSessionHandle sessionHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
session->SenderCancelCmd();
|
|
// we purge in case command was already sent notification posted
|
|
instance->PurgeNotifications(sessionHandle, NORM_TX_CMD_SENT);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormCancelCommand()
|
|
|
|
|
|
// This one is not part of the public API (for NormSocket use currently)
|
|
bool NormSendCommandTo(NormSessionHandle sessionHandle,
|
|
const char* cmdBuffer,
|
|
unsigned int cmdLength,
|
|
const char* addr,
|
|
UINT16 port)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
ProtoAddress dest;
|
|
if (dest.ResolveFromString(addr))
|
|
{
|
|
dest.SetPort(port);
|
|
result = session->SenderSendAppCmd(cmdBuffer, cmdLength, dest);
|
|
}
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormSendCommandTo()
|
|
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetSynStatus(NormSessionHandle sessionHandle, bool state)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
session->SenderSetSynStatus(state);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetSynStatus()
|
|
|
|
|
|
/** NORM Receiver Functions */
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormStartReceiver(NormSessionHandle sessionHandle,
|
|
UINT32 bufferSpace)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
result = session->StartReceiver(bufferSpace);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormStartReceiver()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormStopReceiver(NormSessionHandle sessionHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
session->StopReceiver();
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormStopReceiver()
|
|
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetRxCacheLimit(NormSessionHandle sessionHandle,
|
|
unsigned short countMax)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->SetRxCacheMax(countMax);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetRxCacheLimit()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormSetRxSocketBuffer(NormSessionHandle sessionHandle,
|
|
unsigned int bufferSize)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
result = session->SetRxSocketBuffer(bufferSize);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormSetRxSocketBuffer()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetSilentReceiver(NormSessionHandle sessionHandle,
|
|
bool silent,
|
|
INT32 maxDelay)
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
{
|
|
session->ReceiverSetSilent(silent);
|
|
session->RcvrSetMaxDelay(maxDelay);
|
|
}
|
|
} // end NormSetSilentReceiver()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetDefaultUnicastNack(NormSessionHandle sessionHandle,
|
|
bool unicastNacks)
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->ReceiverSetUnicastNacks(unicastNacks);
|
|
} // end NormSetDefaultUnicastNack()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormNodeSetUnicastNack(NormNodeHandle nodeHandle,
|
|
bool unicastNacks)
|
|
{
|
|
|
|
NormNode* node = (NormNode*)nodeHandle;
|
|
if ((NULL != node) && (NormNode::SENDER == node->GetType()))
|
|
{
|
|
NormSenderNode* sender = static_cast<NormSenderNode*>(node);
|
|
sender->SetUnicastNacks(unicastNacks);
|
|
}
|
|
} // end NormNodeSetUnicastNack()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetDefaultSyncPolicy(NormSessionHandle sessionHandle,
|
|
NormSyncPolicy syncPolicy)
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->ReceiverSetDefaultSyncPolicy((NormSenderNode::SyncPolicy)syncPolicy);
|
|
} // end NormSetDefaultSyncPolicy()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetDefaultNackingMode(NormSessionHandle sessionHandle,
|
|
NormNackingMode nackingMode)
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session) session->ReceiverSetDefaultNackingMode((NormObject::NackingMode)nackingMode);
|
|
} // end NormSetDefaultNackingMode()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormNodeSetNackingMode(NormNodeHandle nodeHandle,
|
|
NormNackingMode nackingMode)
|
|
{
|
|
NormNode* node = (NormNode*)nodeHandle;
|
|
if ((NULL != node) && (NormNode::SENDER == node->GetType()))
|
|
{
|
|
NormSenderNode* sender = static_cast<NormSenderNode*>(node);
|
|
sender->SetDefaultNackingMode((NormObject::NackingMode)nackingMode);
|
|
}
|
|
} // end NormNodeSetNackingMode()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormObjectSetNackingMode(NormObjectHandle objectHandle,
|
|
NormNackingMode nackingMode)
|
|
{
|
|
NormObject* object = (NormObject*)objectHandle;
|
|
if (object) object->SetNackingMode((NormObject::NackingMode)nackingMode);
|
|
} // end NormObjectSetNackingMode()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetDefaultRepairBoundary(NormSessionHandle sessionHandle,
|
|
NormRepairBoundary repairBoundary)
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
if (session)
|
|
session->ReceiverSetDefaultRepairBoundary((NormSenderNode::RepairBoundary)repairBoundary);
|
|
} // end NormSetDefaultRepairBoundary()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormNodeSetRepairBoundary(NormNodeHandle nodeHandle,
|
|
NormRepairBoundary repairBoundary)
|
|
{
|
|
NormNode* node = (NormNode*)nodeHandle;
|
|
if ((NULL != node) && (NormNode::SENDER == node->GetType()))
|
|
{
|
|
NormSenderNode* sender = static_cast<NormSenderNode*>(node);
|
|
sender->SetRepairBoundary((NormSenderNode::RepairBoundary)repairBoundary);
|
|
}
|
|
} // end NormNodeSetRepairBoundary()
|
|
|
|
|
|
NORM_API_LINKAGE
|
|
void NormSetDefaultRxRobustFactor(NormSessionHandle sessionHandle,
|
|
int robustFactor)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
session->SetRxRobustFactor(robustFactor);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
} // end NormSetDefaultRxRobustFactor()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormNodeSetRxRobustFactor(NormNodeHandle nodeHandle,
|
|
int robustFactor)
|
|
{
|
|
if (NORM_NODE_INVALID != nodeHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromNode(nodeHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormNode* node = (NormNode*)nodeHandle;
|
|
if (NormNode::SENDER == node->GetType())
|
|
{
|
|
NormSenderNode* sender = static_cast<NormSenderNode*>(node);
|
|
sender->SetRobustFactor(robustFactor);
|
|
}
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
} // end NormNodeSetRxRobustFactor()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormPreallocateRemoteSender(NormSessionHandle sessionHandle,
|
|
unsigned long bufferSize,
|
|
UINT16 segmentSize,
|
|
UINT16 numData,
|
|
UINT16 numParity,
|
|
unsigned int streamBufferSize)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
result = session->PreallocateRemoteSender((unsigned int)bufferSize, segmentSize, numData, numParity, streamBufferSize);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormPreallocateRemoteSender()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormStreamRead(NormObjectHandle streamHandle,
|
|
char* buffer,
|
|
unsigned int* numBytes)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormStreamObject* stream =
|
|
static_cast<NormStreamObject*>((NormObject*)streamHandle);
|
|
result = stream->Read(buffer, numBytes);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormStreamRead()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormStreamSeekMsgStart(NormObjectHandle streamHandle)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormStreamObject* stream =
|
|
static_cast<NormStreamObject*>((NormObject*)streamHandle);
|
|
unsigned int numBytes = 0;
|
|
result = stream->Read(NULL, &numBytes, true);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormStreamSeekMsgStart()
|
|
|
|
|
|
NORM_API_LINKAGE
|
|
UINT32 NormStreamGetReadOffset(NormObjectHandle streamHandle)
|
|
{
|
|
NormStreamObject* stream = static_cast<NormStreamObject*>((NormObject*)streamHandle);
|
|
if (stream)
|
|
return stream->GetCurrentReadOffset();
|
|
else
|
|
return 0;
|
|
} // end NormStreamGetReadOffset()
|
|
|
|
NORM_API_LINKAGE
|
|
unsigned int NormStreamGetBufferUsage(NormObjectHandle streamHandle)
|
|
{
|
|
unsigned int usage = 0;
|
|
NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormStreamObject* stream =
|
|
static_cast<NormStreamObject*>((NormObject*)streamHandle);
|
|
usage = stream->GetCurrentBufferUsage() ;
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return usage;
|
|
} // end NormStreamGetBufferUsage()
|
|
|
|
|
|
/** NORM Object Functions */
|
|
|
|
NORM_API_LINKAGE
|
|
NormObjectType NormObjectGetType(NormObjectHandle objectHandle)
|
|
{
|
|
if (NORM_OBJECT_INVALID != objectHandle)
|
|
return ((NormObjectType)(((NormObject*)objectHandle)->GetType()));
|
|
else
|
|
return NORM_OBJECT_NONE;
|
|
} // end NormObjectGetType()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormObjectHasInfo(NormObjectHandle objectHandle)
|
|
{
|
|
return ((NormObject*)objectHandle)->HasInfo();
|
|
} // end NormObjectHasInfo()
|
|
|
|
NORM_API_LINKAGE
|
|
UINT16 NormObjectGetInfoLength(NormObjectHandle objectHandle)
|
|
{
|
|
return ((NormObject*)objectHandle)->GetInfoLength();
|
|
} // end NormObjectGetInfoLength()
|
|
|
|
NORM_API_LINKAGE
|
|
UINT16 NormObjectGetInfo(NormObjectHandle objectHandle,
|
|
char* buffer,
|
|
UINT16 bufferLen)
|
|
{
|
|
UINT16 result = 0;
|
|
if (NORM_OBJECT_INVALID != objectHandle)
|
|
{
|
|
NormObject* object = (NormObject*)objectHandle;
|
|
if (object->HaveInfo())
|
|
{
|
|
result = object->GetInfoLength();
|
|
if (result < bufferLen)
|
|
bufferLen = result;
|
|
if (buffer)
|
|
memcpy(buffer, object->GetInfo(), bufferLen);
|
|
}
|
|
}
|
|
return result;
|
|
} // end NormObjectGetInfo()
|
|
|
|
NORM_API_LINKAGE
|
|
NormSize NormObjectGetSize(NormObjectHandle objectHandle)
|
|
{
|
|
return ((NormSize)((NormObject*)objectHandle)->GetSize().GetOffset());
|
|
} // end NormObjectGetSize()
|
|
|
|
NORM_API_LINKAGE
|
|
NormSize NormObjectGetBytesPending(NormObjectHandle objectHandle)
|
|
{
|
|
NormSize bytesPending = 0;
|
|
if (NORM_OBJECT_INVALID != objectHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromObject(objectHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
bytesPending = ((NormSize)((NormObject*)objectHandle)->GetBytesPending().GetOffset());
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
return bytesPending;
|
|
} // end NormObjectGetBytesPending()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormObjectCancel(NormObjectHandle objectHandle)
|
|
{
|
|
if (NORM_OBJECT_INVALID != objectHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromObject(objectHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormObject* obj = (NormObject*)objectHandle;
|
|
NormSenderNode* sender = obj->GetSender();
|
|
if (sender)
|
|
sender->DeleteObject(obj);
|
|
else
|
|
obj->GetSession().DeleteTxObject(obj, false);
|
|
instance->PurgeObjectNotifications(objectHandle);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
} // end NormObjectCancel()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormObjectSetUserData(NormObjectHandle objectHandle, const void* userData)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromObject(objectHandle);
|
|
if (instance)
|
|
{
|
|
if (instance->dispatcher.SuspendThread())
|
|
{
|
|
((NormObject*)objectHandle)->SetUserData(userData);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
} // end NormObjectSetUserData()
|
|
|
|
NORM_API_LINKAGE
|
|
const void* NormObjectGetUserData(NormObjectHandle objectHandle)
|
|
{
|
|
return (((NormObject*)objectHandle)->GetUserData());
|
|
} // end NormNormObjectGetUserData()
|
|
|
|
|
|
NORM_API_LINKAGE
|
|
void NormObjectRetain(NormObjectHandle objectHandle)
|
|
{
|
|
if (NORM_OBJECT_INVALID != objectHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromObject(objectHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
((NormObject*)objectHandle)->Retain();
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
} // end NormRetainObject()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormObjectRelease(NormObjectHandle objectHandle)
|
|
{
|
|
// (TBD) we could maintain separate "app_retain" and "interval_retain"
|
|
// counts to prevent bad apps from messing up NORM interval code ???
|
|
if (NORM_OBJECT_INVALID != objectHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromObject(objectHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
((NormObject*)objectHandle)->Release();
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
} // end NormObjectRelease()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormFileGetName(NormObjectHandle fileHandle,
|
|
char* nameBuffer,
|
|
unsigned int bufferLen)
|
|
{
|
|
bool result = false;
|
|
if (NORM_OBJECT_INVALID != fileHandle)
|
|
{
|
|
// (TBD) verify "fileHandle" is a NORM_FILE ?>??
|
|
NormFileObject* file =
|
|
static_cast<NormFileObject*>((NormObject*)fileHandle);
|
|
bufferLen = (bufferLen < PATH_MAX) ? bufferLen : PATH_MAX;
|
|
strncpy(nameBuffer, file->GetPath(), bufferLen);
|
|
nameBuffer[bufferLen - 1] = '\0'; // (TBD) should we always do this
|
|
result = true;
|
|
}
|
|
return result;
|
|
} // end NormFileGetName()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormFileRename(NormObjectHandle fileHandle,
|
|
const char* fileName)
|
|
{
|
|
bool result = false;
|
|
NormInstance* instance = NormInstance::GetInstanceFromObject(fileHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
// (TBD) verify "fileHandle" is a NORM_FILE ?>??
|
|
NormFileObject* file =
|
|
static_cast<NormFileObject*>((NormObject*)fileHandle);
|
|
result = file->Rename(fileName);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormFileRename()
|
|
|
|
NORM_API_LINKAGE
|
|
const char* NormDataAccessData(NormObjectHandle dataHandle)
|
|
{
|
|
NormDataObject* dataObj =
|
|
static_cast<NormDataObject*>((NormObject*)dataHandle);
|
|
return dataObj->GetData();
|
|
} // end NormDataAccessData()
|
|
|
|
NORM_API_LINKAGE
|
|
char* NormDataDetachData(NormObjectHandle dataHandle)
|
|
{
|
|
char* ptr = NULL;
|
|
NormInstance* instance = NormInstance::GetInstanceFromObject(dataHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormDataObject* dataObj = static_cast<NormDataObject*>((NormObject*)dataHandle);
|
|
ptr = dataObj->DetachData();
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return ptr;
|
|
} // end NormDataDetachData()
|
|
|
|
NORM_API_LINKAGE
|
|
char* NormAlloc(size_t numBytes)
|
|
{
|
|
return new char[numBytes];
|
|
} // end NormAlloc()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormFree(char* dataPtr)
|
|
{
|
|
if (NULL != dataPtr)
|
|
delete[] dataPtr;
|
|
} // end NormFree()
|
|
|
|
NORM_API_LINKAGE
|
|
NormNodeHandle NormObjectGetSender(NormObjectHandle objectHandle)
|
|
{
|
|
return (NormNodeHandle)(((NormObject*)objectHandle)->GetSender());
|
|
} // end NormObjectGetSender()
|
|
|
|
|
|
/** NORM Node Functions */
|
|
|
|
NORM_API_LINKAGE
|
|
NormNodeId NormNodeGetId(NormNodeHandle nodeHandle)
|
|
{
|
|
NormNode* node = (NormNode*)nodeHandle;
|
|
if (NULL != node)
|
|
return node->GetId();
|
|
else
|
|
return NORM_NODE_NONE;
|
|
} // end NormNodeGetId()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormNodeGetAddress(NormNodeHandle nodeHandle,
|
|
char* addrBuffer,
|
|
unsigned int* bufferLen,
|
|
UINT16* port)
|
|
{
|
|
bool result = false;
|
|
if (NORM_NODE_INVALID != nodeHandle)
|
|
{
|
|
//NormInstance* instance = NormInstance::GetInstanceFromNode(nodeHandle);
|
|
//if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormNode* node = (NormNode*)nodeHandle;
|
|
const ProtoAddress& nodeAddr = node->GetAddress();
|
|
unsigned int addrLen = nodeAddr.GetLength();
|
|
if (addrBuffer && bufferLen && (addrLen <= *bufferLen))
|
|
{
|
|
memcpy(addrBuffer, nodeAddr.GetRawHostAddress(), addrLen);
|
|
result = true;
|
|
}
|
|
else if (NULL == addrBuffer)
|
|
{
|
|
result = true; // just a query for addrLen and/or port
|
|
}
|
|
if (bufferLen) *bufferLen = addrLen;
|
|
if (port) *port = nodeAddr.GetPort();
|
|
//instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
return result;
|
|
} // end NormNodeGetAddress()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormNodeSetUserData(NormNodeHandle nodeHandle, const void* userData)
|
|
{
|
|
if (NORM_NODE_INVALID != nodeHandle)
|
|
{
|
|
NormNode* node = (NormNode*)nodeHandle;
|
|
return node->SetUserData(userData);
|
|
}
|
|
}
|
|
|
|
NORM_API_LINKAGE
|
|
const void* NormNodeGetUserData(NormNodeHandle nodeHandle)
|
|
{
|
|
NormNode* node = (NormNode*)nodeHandle;
|
|
if (NULL != node)
|
|
return node->GetUserData();
|
|
else
|
|
return NULL;
|
|
} // end NormNodeGetUserData()
|
|
|
|
NORM_API_LINKAGE
|
|
double NormNodeGetGrtt(NormNodeHandle nodeHandle)
|
|
{
|
|
NormNode* node = (NormNode*)nodeHandle;
|
|
if ((NULL != node) && (NormNode::SENDER == node->GetType()))
|
|
{
|
|
NormSenderNode* sender = static_cast<NormSenderNode*>(node);
|
|
sender->ResetGrttNotification();
|
|
return sender->GetGrttEstimate();
|
|
}
|
|
else
|
|
{
|
|
return -1.0;
|
|
}
|
|
} // end NormNodeGetGrtt()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormNodeGetCommand(NormNodeHandle nodeHandle,
|
|
char* cmdBuffer,
|
|
unsigned int* cmdLength)
|
|
{
|
|
bool result = false;
|
|
if (NORM_NODE_INVALID != nodeHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromNode(nodeHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormNode* node = (NormNode*)nodeHandle;
|
|
if (NormNode::SENDER == node->GetType())
|
|
{
|
|
NormSenderNode* sender = static_cast<NormSenderNode*>(node);
|
|
result = sender->ReadNextCmd(cmdBuffer, cmdLength);
|
|
}
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
return result;
|
|
} // end NormNodeGetCommand()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormNodeSendAckEx(NormNodeHandle nodeHandle,
|
|
const char* buffer,
|
|
unsigned int numBytes)
|
|
{
|
|
bool result = false;
|
|
if (NORM_NODE_INVALID != nodeHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromNode(nodeHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormNode* node = (NormNode*)nodeHandle;
|
|
if (NormNode::SENDER == node->GetType())
|
|
{
|
|
NormSenderNode* sender = static_cast<NormSenderNode*>(node);
|
|
result = sender->SendAckEx(buffer, numBytes);
|
|
}
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
return result;
|
|
} // end NormNodeSendAckEx()
|
|
|
|
NORM_API_LINKAGE
|
|
bool NormNodeGetWatermarkEx(NormNodeHandle nodeHandle,
|
|
char* buffer,
|
|
unsigned int* buflen)
|
|
{
|
|
bool result = false;
|
|
if (NORM_NODE_INVALID != nodeHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromNode(nodeHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormNode* node = (NormNode*)nodeHandle;
|
|
if (NormNode::SENDER == node->GetType())
|
|
{
|
|
NormSenderNode* sender = static_cast<NormSenderNode*>(node);
|
|
result = sender->GetWatermarkEx(buffer, buflen);
|
|
}
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
return result;
|
|
} // end NormNodeGetWatermarkEx()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormNodeFreeBuffers(NormNodeHandle nodeHandle)
|
|
{
|
|
if (NORM_NODE_INVALID != nodeHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromNode(nodeHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormNode* node = (NormNode*)nodeHandle;
|
|
if (NormNode::SENDER == node->GetType())
|
|
{
|
|
NormSenderNode* sender = static_cast<NormSenderNode*>(node);
|
|
sender->FreeBuffers();
|
|
// Since this results in aborted objects, should we purge those object notifications?
|
|
// or let the be delivered since the app may have associate state
|
|
}
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
} // end NormNodeFreeBuffers()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormNodeDelete(NormNodeHandle nodeHandle)
|
|
{
|
|
if (NORM_NODE_INVALID != nodeHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromNode(nodeHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
NormNode* node = (NormNode*)nodeHandle;
|
|
if (NormNode::SENDER == node->GetType())
|
|
{
|
|
NormSenderNode* sender = static_cast<NormSenderNode*>(node);
|
|
sender->GetSession().DeleteRemoteSender(*sender);
|
|
}
|
|
// else if NormNode::ACKER, should we remove from acking node list???
|
|
instance->PurgeNodeNotifications(nodeHandle);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
} // end NormNodeDelete()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormNodeRetain(NormNodeHandle nodeHandle)
|
|
{
|
|
if (NORM_NODE_INVALID != nodeHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromNode(nodeHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
((NormNode*)nodeHandle)->Retain();
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
} // end NormNodeRetain()
|
|
|
|
NORM_API_LINKAGE
|
|
void NormNodeRelease(NormNodeHandle nodeHandle)
|
|
{
|
|
if (NORM_NODE_INVALID != nodeHandle)
|
|
{
|
|
NormInstance* instance = NormInstance::GetInstanceFromNode(nodeHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
((NormNode*)nodeHandle)->Release();
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
}
|
|
} // end NormNodeRelease()
|
|
|
|
// (TBD) Some stream i/o performance improvement can be realized
|
|
// if the option to make "NormWriteStream()" and
|
|
// "NormReadStream()" _blocking_ calls is implemented.
|
|
// Right now, the stream read/write are non-blocking
|
|
// so applications should use "NormGetNextEvent()" to
|
|
// know when to read or write ... This results in the
|
|
// underlying NORM thread to be suspended/resumed _twice_
|
|
// per read or write ... It would be more efficient to
|
|
// "suspend" the NORM thread while the application
|
|
// processes all pending events and _then_ "resume" the
|
|
// NORM thread ... an approach to this would be enable
|
|
// the app to install an event handler callback and dispatch
|
|
// events with a "NormDispatchEvents()" call ...
|
|
// (Update: I've improved the way the NORM thread suspend/resume
|
|
// is done so that this current approach is not very costly)
|
|
//
|
|
|
|
// Not sure why this function exists. It just counts the number
|
|
// of RX_OBJECT_COMPLETED events currently in notification queue
|
|
// which is a temporary and transitory thing???
|
|
NORM_API_LINKAGE
|
|
UINT32 NormCountCompletedObjects(NormSessionHandle sessionHandle)
|
|
{
|
|
UINT32 result = 0;
|
|
NormSession* session = (NormSession*)sessionHandle;
|
|
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
|
|
if (instance && instance->dispatcher.SuspendThread())
|
|
{
|
|
result = instance->CountCompletedObjects(session);
|
|
instance->dispatcher.ResumeThread();
|
|
}
|
|
return result;
|
|
} // end NormCountCompletedObjects()
|