pull/2/head
Jeff Weston 2019-09-11 11:50:36 -04:00
parent 9c3ea04ba8
commit 14d4ab80c6
26 changed files with 966 additions and 435 deletions

View File

@ -3,10 +3,10 @@
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-15">
<TITLE>NORM Developer&rsquo;s Guide</TITLE>
<META NAME="GENERATOR" CONTENT="OpenOffice.org 1.1.2 (Linux)">
<META NAME="GENERATOR" CONTENT="OpenOffice.org 1.1.3 (Linux)">
<META NAME="AUTHOR" CONTENT="Robert Adamson">
<META NAME="CREATED" CONTENT="20040824;15180000">
<META NAME="CHANGED" CONTENT="20050427;11094100">
<META NAME="CHANGED" CONTENT="20050609;13321500">
<META NAME="DESCRIPTION" CONTENT="NORM Object Functions 42 NORM Object Functions NORM_OBJECT_STREAM NORM Sender Functions 19 NORM Sender Functions ">
<META NAME="KEYWORDS" CONTENT="norm object value application function ">
<STYLE>
@ -70,7 +70,7 @@ Engineering Task Force RFC 3940.</P>
<P CLASS="western" STYLE="font-style: normal">The NORM protocol is
designed to provide end-to-end reliable transport of bulk data
objects or streams over generic IP multicast routing and forwarding
services. NORM uses a selective, negative acknowledgment (NACK)
services. NORM uses a selective, negative acknowledgement (NACK)
mechanism for transport reliability and offers additional protocol
mechanisms to conduct reliable multicast sessions with limited &quot;a
priori&quot; coordination among senders and receivers. A congestion
@ -84,6 +84,18 @@ to allow different types of applications or possibly other higher
level transport protocols to utilize its service in different ways.
The protocol leverages the use of FEC-based repair and other proven
reliable multicast transport techniques in its design.</P>
<P CLASS="western" STYLE="font-style: normal">The NRL NORM library
attempts to provide a general useful capability for development of
reliable multicast applications for bulk file or other data delivery
as well as support of stream-based transport with possible real-time
delivery requirements. The API allows access to many NORM protocol
parameters and control functions to tailor performance for specific
applications. While default parameters, where provided, can be
useful to a potential wide range of requirements, the many different
possible group communication paradigms dictate different needs for
different applications. Even with NORM, the developer should have a
thorough understanding of the specific application's group
communication needs.</P>
<H1 CLASS="western" ALIGN=CENTER STYLE="page-break-before: always">Table
of Contents</H1>
<DIV ID="Table of Contents1" DIR="LTR">
@ -95,103 +107,113 @@ of Contents</H1>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>NORM
Data Transport</B></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2>NORM
Data Transmission </FONT></P>
Data Transmission</FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2>NORM
Data Reception </FONT></P>
Data Reception</FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>API
Event Notification</B></FONT></P>
<P STYLE="margin-top: 0.25in; font-style: normal"><FONT FACE="Helvetica, sans-serif"><B>Build
Notes</B></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>Unix
Platforms</B></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>Win32/WiNCE
Platforms</B></FONT></P>
<P STYLE="margin-top: 0.25in; font-style: normal"><FONT FACE="Helvetica, sans-serif"><B>API
Reference</B></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>API
Variable Types and Constants</B></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormInstanceHandle">NormInstanceHandle</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSessionHandle">NormSessionHandle</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeHandle">NormNodeHandle</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeId">NormNodeId</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectHandle">NormObjectHandle</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectType">NormObjectType</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectTransportId">NormObjectTransportId</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormEventType">NormEventType</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormEvent">NormEvent</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormInstanceHandle">NormInstanceHandle</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSessionHandle">NormSessionHandle</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSessionId">NormSessionId</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeHandle">NormNodeHandle</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeId">NormNodeId</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectHandle">NormObjectHandle</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectType">NormObjectType</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSize">NormSize</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectTransportId">NormObjectTransportId</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormEventType">NormEventType</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormEvent">NormEvent</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormDescriptor">NormDescriptor</A></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>API
Initialization and Operation</B></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormCreateInstance()">NormCreateInstance()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormDestroyInstance()">NormDestroyInstance()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetCacheDirectory()">NormSetCacheDirectory()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormGetNextEvent()">NormGetNextEvent()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormGetDescriptor()">NormGetDescriptor()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormCreateInstance()">NormCreateInstance()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormDestroyInstance()">NormDestroyInstance()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetCacheDirectory()">NormSetCacheDirectory()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormGetNextEvent()">NormGetNextEvent()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormGetDescriptor()">NormGetDescriptor()</A></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>Session
Creation and Control</B></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormCreateSession()">NormCreateSession()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormDestroySession()">NormDestroySession()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetUserData()">NormSetUserData()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormGetUserData()">NormGetUserData()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormGetLocalNodeId()">NormGetLocalNodeId()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTxPort()">NormSetTxPort()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetMulticastInterface()">NormSetMulticastInterface()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTTL()">NormSetTTL()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTOS()">NormSetTOS()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetLoopback()">NormSetLoopback()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormCreateSession()">NormCreateSession()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormDestroySession()">NormDestroySession()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetUserData()">NormSetUserData()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormGetUserData()">NormGetUserData()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormGetLocalNodeId()">NormGetLocalNodeId()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTxPort()">NormSetTxPort()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetMulticastInterface()">NormSetMulticastInterface()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTTL()">NormSetTTL()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTOS()">NormSetTOS()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetLoopback()">NormSetLoopback()</A></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>NORM
Sender Functions</B></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStartSender()">NormStartSender()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStopSender()">NormStopSender()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTransmitRate()">NormSetTransmitRate()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTxSocketBuffer()">NormSetTxSocketBuffer()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetCongestionControl()">NormSetCongestionControl()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTransmitRateBounds()">NormSetTransmitRateBounds()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetAutoParity()">NormSetAutoParity()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetGrttEstimate()">NormSetGrttEstimate()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormAddAckingNode()">NormAddAckingNode()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormRemoveAckingNode()">NormRemoveAckingNode()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormFileEnqueue()">NormFileEnqueue()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormDataEnqueue()">NormDataEnqueue()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamOpen()">NormStreamOpen()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamClose()">NormStreamClose()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamWrite()">NormStreamWrite()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamFlush()">NormStreamFlush()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamSetAutoFlush()">NormStreamSetAutoFlush()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamSetPushEnable()">NormStreamSetPushEnable()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamHasVacancy()">NormStreamHasVacancy()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamMarkEom()">NormStreamMarkEom()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetWatermark()">NormSetWatermark()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStartSender()">NormStartSender()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStopSender()">NormStopSender()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTransmitRate()">NormSetTransmitRate()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTxSocketBuffer()">NormSetTxSocketBuffer()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetCongestionControl()">NormSetCongestionControl()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTransmitRateBounds()">NormSetTransmitRateBounds()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetAutoParity()">NormSetAutoParity()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetGrttEstimate()">NormSetGrttEstimate()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormAddAckingNode()">NormAddAckingNode()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormRemoveAckingNode()">NormRemoveAckingNode()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormFileEnqueue()">NormFileEnqueue()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormDataEnqueue()">NormDataEnqueue()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamOpen()">NormStreamOpen()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamClose()">NormStreamClose()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamWrite()">NormStreamWrite()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamFlush()">NormStreamFlush()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamSetAutoFlush()">NormStreamSetAutoFlush()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamSetPushEnable()">NormStreamSetPushEnable()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamHasVacancy()">NormStreamHasVacancy()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamMarkEom()">NormStreamMarkEom()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetWatermark()">NormSetWatermark()</A></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>NORM
Receiver Functions</B></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStartReceiver()">NormStartReceiver()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStopReceiver()">NormStopReceiver()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetRxSocketBuffer()">NormSetRxSocketBuffer()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetSilentReceiver()">NormSetSilentReceiver()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetDefaultUnicastNack()">NormSetDefaultUnicastNack()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeSetUnicastNack()">NormNodeSetUnicastNack()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetDefaultNackingMode()">NormSetDefaultNackingMode()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeSetNackingMode()">NormNodeSetNackingMode()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectSetNackingMode()">NormObjectSetNackingMode()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetDefaultRepairBoundary()">NormSetDefaultRepairBoundary()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeSetRepairBoundary()">NormNodeSetRepairBoundary()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamRead()">NormStreamRead()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamSeekMsgStart()">NormStreamSeekMsgStart()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamGetReadOffset()">NormStreamGetReadOffset()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStartReceiver()">NormStartReceiver()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStopReceiver()">NormStopReceiver()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetRxSocketBuffer()">NormSetRxSocketBuffer()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetSilentReceiver()">NormSetSilentReceiver()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetDefaultUnicastNack()">NormSetDefaultUnicastNack()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeSetUnicastNack()">NormNodeSetUnicastNack()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetDefaultNackingMode()">NormSetDefaultNackingMode()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeSetNackingMode()">NormNodeSetNackingMode()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectSetNackingMode()">NormObjectSetNackingMode()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetDefaultRepairBoundary()">NormSetDefaultRepairBoundary()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeSetRepairBoundary()">NormNodeSetRepairBoundary()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamRead()">NormStreamRead()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamSeekMsgStart()">NormStreamSeekMsgStart()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamGetReadOffset()">NormStreamGetReadOffset()</A></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>NORM
Object Functions</B></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectGetType()">NormObjectGetType()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectHasInfo()">NormObjectHasInfo()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectGetInfoLength()">NormObjectGetInfoLength()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectGetInfo()">NormObjectGetInfo()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectGetSize()">NormObjectGetSize()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectCancel()">NormObjectCancel()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectRetain()">NormObjectRetain()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectRelease()">NormObjectRelease()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormFileGetName()">NormFileGetName()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormFileRename()">NormFileRename()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormDataAccessData()">NormDataAccessData()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormDataDetachData()">NormDataDetachData()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectGetSender()">NormObjectGetSender()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectGetType()">NormObjectGetType()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectHasInfo()">NormObjectHasInfo()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectGetInfoLength()">NormObjectGetInfoLength()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectGetInfo()">NormObjectGetInfo()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectGetSize()">NormObjectGetSize()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectGetBytesPending()">NormObjectGetBytesPending()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectCancel()">NormObjectCancel()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectRetain()">NormObjectRetain()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectRelease()">NormObjectRelease()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormFileGetName()">NormFileGetName()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormFileRename()">NormFileRename()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormDataAccessData()">NormDataAccessData()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormDataDetachData()">NormDataDetachData()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectGetSender()">NormObjectGetSender()</A></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>NORM
Node Functions</B></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeGetId()">NormNodeGetId()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeGetAddress()">NormNodeGetAddress()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeRetain()">NormNodeRetain()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeRelease()">NormNodeRelease()</A> </FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeGetId()">NormNodeGetId()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeGetAddress()">NormNodeGetAddress()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeRetain()">NormNodeRetain()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeRelease()">NormNodeRelease()</A></FONT></P>
</DIV>
<H1 CLASS="western" STYLE="page-break-before: always">Overview</H1>
<P CLASS="western" STYLE="font-style: normal">The NORM API has been
@ -358,7 +380,76 @@ disabling receiver feedback (silent receiver operation) entirely.</P>
<H2 CLASS="western">API Event Notification</H2>
<P CLASS="western" STYLE="font-style: normal">An asynchronous event
dispatching mechanism is provided to notify the application of
significant NORM protocol events ...</P>
significant NORM protocol events. The centerpiece of this is the
<FONT FACE="Courier"><A HREF="#NormGetNextEvent()">NormGetNextEvent()</A></FONT> function which can be
used to retrieve the next NORM protocol engine event in the form of a
<FONT FACE="Courier"><A HREF="#NormEvent">NormEvent</A></FONT> structure. This function will
typically block until a <FONT FACE="Courier"><A HREF="#NormEvent">NormEvent</A></FONT> occurs.
However, non-blocking operation may be achieved by using the
<FONT FACE="Courier"><A HREF="#NormGetDescriptor()">NormGetDescriptor()</A></FONT> call to get a value
(file descriptor (Unix) or HANDLE (Win32) suitable for use in a
asynchronous I/O monitoring functions such as <I>select()</I> (Unix)
or <I>MsgWaitForMultipleObjects()</I> (Win32). The descriptor will
be signaled when a <FONT FACE="Courier"><A HREF="#NormEvent">NormEvent</A></FONT> is
available. For Win32 platforms, dispatching of a user-defined
Windows message for NORM event notification is also planned for a
future update to the API.</P>
<H1 CLASS="western">Build Notes</H1>
<P CLASS="western" STYLE="font-style: normal">To build applications
that use the NORM library, a path to the &quot;normApi.h&quot; header
file must be provided and the linker step needs to reference the NORM
library file (&quot;libnorm.a&quot; for Unix platforms and &quot;Norm.lib&quot;
for Win32 platforms). NORM also depends upon the NRL Protean
Protocol Prototyping toolkit&quot;Protokit&quot; library (a.k.a
&quot;Protolib&quot;) (static library files &quot;libProtokit.a&quot;
for Unix and &quot;Protokit.lib&quot; for Win32). Depending upon the
platform, some additional library dependencies may be required to
support the needs of NORM and/or Protokit. These are described
below.</P>
<H2 CLASS="western">Unix Platforms</H2>
<P CLASS="western" STYLE="font-style: normal">NORM has been built and
tested on Linux (various architectures), MacOS (BSD), Solaris, and
IRIX (SGI) platforms. The code should be readily portable to other
Unix platforms.</P>
<P CLASS="western" STYLE="font-style: normal">To support IPv6
operation, the NORM and the Protokit library must be compiled with
the &quot;HAVE_IPV6&quot; macro defined. This is default in the NORM
and Protokit Makefiles for platforms that support IPv6. It is
important that NORM and Protokit be built with this macro defined the
same. With NORM, it is recommended that &quot;large file support&quot;
options be enabled when possible.</P>
<P CLASS="western" STYLE="font-style: normal">The NORM API uses
threading so that the NORM protocol engine may run independent of the
application. Thus the &quot;Posix Threads&quot; library must be
included (&quot;-'pthread&quot;) in the linking step. MacOS/BSD also
requires the addition of the &quot;-lresolv&quot; (resolver) library
and Solaris requires the dynamic loader, network/socket, and resolver
libraries (&quot;-ldl &ndash;lnsl &ndash;lsocket &ndash;lresolv&quot;)
to achieve successful compilation. The Makefiles in the NORM source
code distribution are a reference for these requirements.</P>
<H2 CLASS="western">Win32/WiNCE Platforms</H2>
<P CLASS="western" STYLE="font-style: normal">NORM has been built
using Microsoft's Visual C++ (6.0 and .NET) and Embedded VC++ 4.2
environments. In addition to proper macro definitions (e.g.,
HAVE_IPV6, etc) that are included in the respective &quot;Protokit&quot;
and &quot;NORM&quot; project files, it is important that common code
generation settings be used when building the NORM application. The
NORM and Protokit projects are built with the &quot;Multithreading
DLL&quot; library usage set. The NORM API requires multithreading
support. This is a critical setting and numerous compiler and linker
errors will result if this is not properly set for your application
project.</P>
<P CLASS="western" STYLE="font-style: normal">NORM and Protokit also
depend on the Winsock 2.0 (&quot;ws2_32.lib&quot; (or &quot;ws2.lib&quot;
(WinCE)) and the IP Helper API (&quot;iphlpapi.lib&quot;) libraries
and these must be included in the project &quot;Link&quot;
attributes.</P>
<P CLASS="western" STYLE="font-style: normal">An additional note is
that a bug in VC++ 6.0 and earlier compilers (includes embedded VC++
4.x compilers) prevent compilation of Protokit-based code with
debugging capabilities enabled. However, this has been resolved in
VC++ .NET and is hoped to be resolved in the future for the WinCE
build tools.</P>
<H1 CLASS="western">API Reference</H1>
<P CLASS="western" STYLE="font-style: normal">This section provides a
reference to the NORM API variable types, constants and functions.</P>
@ -388,6 +479,22 @@ call. Multiple <FONT FACE="Courier">NormSessionHandles</FONT> may be
associated with a given <FONT FACE="Courier"><A HREF="#NormInstanceHandle">NormInstanceHandle</A></FONT>.
The special value <FONT FACE="Courier">NORM_SESSION_INVALID </FONT>is
used to refer to invalid session references.</P>
<H3 CLASS="functionheading-western"><A NAME="NormSessionId">NormSessionId</A></H3>
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormSessionId">NormSessionId</A></FONT>
type is used by applications to uniquely identify their instance of
participation as a sender within a <I>NormSession</I>. This type is
a parameter to the <FONT FACE="Courier"><A HREF="#NormStartSender()">NormStartSender()</A></FONT>
function. Robust applications can use different <FONT FACE="Courier"><A HREF="#NormSessionId">NormSessionId</A></FONT>
values when initiating sender operation so that receivers can
discriminate when a sender has terminated and restarted (whether
intentional or due to system failure). For example, an application
could cache its prior <FONT FACE="Courier"><A HREF="#NormSessionId">NormSessionId</A></FONT> value
in non-volatile storage which could then be recovered and incremented
(for example) upon system restart to produce a new value. The
<FONT FACE="Courier"><A HREF="#NormSessionId">NormSessionId</A></FONT> value is used for the value
of the <I>instance_id</I> field in NORM protocol sender messages (see
the NORM protocol specification) and receivers use this field to
detect sender restart within a <I>NormSession</I>.</P>
<H3 CLASS="functionheading-western"><A NAME="NormNodeHandle">NormNodeHandle</A></H3>
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormNodeHandle">NormNodeHandle</A>
</FONT>type is used to reference state kept by the NORM
@ -441,6 +548,17 @@ function call. A special <FONT FACE="Courier"><A HREF="#NormObjectType">NormObj
value, <I><FONT FACE="Courier">NORM_OBJECT_NONE</FONT></I>, indicates
an invalid object type.
</P>
<H3 CLASS="functionheading-western"><A NAME="NormSize">NormSize</A></H3>
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormSize">NormSize</A></FONT>
is the type used for <I>NormObject</I> size information. For
example, the <FONT FACE="Courier"><A HREF="#NormObjectGetSize()">NormObjectGetSize()</A></FONT> function
returns a value of type <FONT FACE="Courier"><A HREF="#NormSize">NormSize</A></FONT>. The
range of <FONT FACE="Courier"><A HREF="#NormSize">NormSize</A></FONT> values depends upon the
operating system and NORM library compilation settings. With &quot;large
file support&quot; enabled, as is the case with distributed NORM
library &quot;Makefiles&quot;, the <FONT FACE="Courier"><A HREF="#NormSize">NormSize</A></FONT>
type is a 64-bit integer. However, some platforms may support only
32-bit object sizes.</P>
<H3 CLASS="functionheading-western"><A NAME="NormObjectTransportId">NormObjectTransportId</A></H3>
<P CLASS="western" STYLE="font-style: normal">The
<FONT FACE="Courier"><A HREF="#NormObjectTransportId">NormObjectTransportId</A></FONT> type is a 16-bit
@ -452,7 +570,7 @@ values in a monotonically increasing fashion during the course of a
session as part of protocol operation. Typically, the application
should not need access to these values, but an API call
<FONT FACE="Courier">NormObjectGetTransportId() </FONT>is provided to
retrieve these values if needed. (<I>Note this function may be
retrieve these values if needed. (<I>Note this type may be
deprecated &ndash; it may not be needed at all if the
NormObjectRequeue() function (TBD) is implemented using handles only,
but _some_ applications requiring persistence even after a system
@ -483,7 +601,17 @@ and <FONT FACE="Courier">object</FONT> fields indicate the applicable
and <FONT FACE="Courier"><A HREF="#NormObjectHandle">NormObjectHandle</A></FONT>, respectively, to
which the event applies. NORM protocol events are made available to
the application via the <FONT FACE="Courier"><A HREF="#NormGetNextEvent()">NormGetNextEvent()</A></FONT>
function call.
function call.</P>
<H3 CLASS="functionheading-western"><A NAME="NormDescriptor">NormDescriptor</A></H3>
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormDescriptor">NormDescriptor</A></FONT>
type provides reference to a file descriptor (Unix) or HANDLE
(Win32). For a given <FONT FACE="Courier"><A HREF="#NormInstanceHandle">NormInstanceHandle</A></FONT>,
the <FONT FACE="Courier"><A HREF="#NormGetDescriptor()">NormGetDescriptor()</A></FONT> function can be
used to retrieve a <A HREF="#NormDescriptor">NormDescriptor</A> value that may, in turn, used in
appropriate system calls (e.g. <I>select()</I> or
<I>MsgWaitForMultipleObjects()</I>) to asynchronously monitor the
NORM protocol engine for notification events (see <FONT FACE="Courier"><A HREF="#NormEvent">NormEvent</A></FONT>
description).
</P>
<H2 CLASS="western">API Initialization and Operation</H2>
<P CLASS="western" STYLE="font-style: normal">The first step in using
@ -640,6 +768,26 @@ function call.</P>
objects for transmission.</P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=269>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
<FONT FACE="Courier"><I>NORM_TX_FLUSH_COMPLETED</I></FONT></P>
</TD>
<TD WIDTH=293>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
This event indicates that the flushing process the NORM sender
observes when it no longer has data ready for transmission has
completed. The completion of the flushing process is a reasonable
indicator (with a sufficient NORM &quot;robust factor&quot; value)
that the receiver set no longer has any pending repair requests.
Note the use of NORM's optional positive acknowledgement feature
is more deterministic in this regards, but this notification is
useful when there are non-acking (NACK-only) receivers. The
default NORM robust factor of 20 (20 flush messages are sent at
end-of-transmission) provides a high assurance of reliable
transmission, even with packet loss rates of 50%.</P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=269>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
@ -843,14 +991,14 @@ events if undesired)).</P>
<H4 CLASS="western">Synopsis</H4>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>#include
&lt;normApi.h&gt;</FONT></FONT></P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>NormDescriptor
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2><A HREF="#NormDescriptor">NormDescriptor</A>
NormGetDescriptor(<A HREF="#NormInstanceHandle">NormInstanceHandle</A> instance);</FONT></FONT></P>
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function is used
to retrieve a <FONT FACE="Courier">NormDescriptor</FONT> (integer
to retrieve a <FONT FACE="Courier"><A HREF="#NormDescriptor">NormDescriptor</A></FONT> (integer
file descriptor (UNIX) or HANDLE (WIN32)) suitable for asynchronous
I/O notification to avoid blocking calls to <FONT FACE="Courier"><A HREF="#NormGetNextEvent()">NormGetNextEvent()</A></FONT>.
A <FONT FACE="Courier">NormDescriptor</FONT> is available for each
A <FONT FACE="Courier"><A HREF="#NormDescriptor">NormDescriptor</A></FONT> is available for each
protocol engine <U><FONT FACE="Courier">instance</FONT></U>. The
descriptor (or WIN32 HANDLE) is suitable for use as an input (or
&quot;read&quot;) descriptor which is signaled when a NORM protocol
@ -858,7 +1006,7 @@ event is ready for retrieval via <FONT FACE="Courier"><A HREF="#NormGetNextEvent
Hence, a call to <FONT FACE="Courier"><A HREF="#NormGetNextEvent()">NormGetNextEvent()</A></FONT> will
not block when the descriptor has been signaled. The <I><FONT FACE="Courier">select()</FONT></I>
system call (UNIX) (or <I><FONT FACE="Courier">WaitForMultipleObjects()</FONT></I>
(WIN32)) can be used to detect when the returned <FONT FACE="Courier">NormDescriptor</FONT>
(WIN32)) can be used to detect when the returned <FONT FACE="Courier"><A HREF="#NormDescriptor">NormDescriptor</A></FONT>
is signaled. For the <FONT FACE="Courier">select()</FONT> call
usage, the NORM descriptor should be treated as a &quot;read&quot;
descriptor.</P>
@ -1186,7 +1334,7 @@ Functions</H2>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>#include
&lt;normApi.h&gt;</FONT></FONT></P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>bool
NormStartSender(<A HREF="#NormSessionHandle">NormSessionHandle</A>&nbsp;session<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned
NormStartSender(<A HREF="#NormSessionHandle">NormSessionHandle</A>&nbsp;sessionHandle<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A HREF="#NormSessionId">NormSessionId</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sessionId<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned
long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bufferSpace<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned
short&nbsp;&nbsp;&nbsp;&nbsp;segmentSize,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned
char&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;blockSize,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned
@ -1200,25 +1348,44 @@ feedback collection and application API activity such as posting of
sender-related <I>NormEvents</I>. The parameters required for this
function call include:</P>
<TABLE WIDTH=590 BORDER=0 CELLPADDING=7 CELLSPACING=0>
<COL WIDTH=106>
<COL WIDTH=456>
<COL WIDTH=125>
<COL WIDTH=437>
<TR VALIGN=TOP>
<TD WIDTH=106>
<TD WIDTH=125>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
<FONT FACE="Courier"><U>session</U></FONT></P>
<FONT FACE="Courier"><U>sessionHandle</U></FONT></P>
</TD>
<TD WIDTH=456>
<TD WIDTH=437>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
This must be a valid <FONT FACE="Courier"><A HREF="#NormSessionHandle">NormSessionHandle</A></FONT>
previously obtained with a call to <FONT FACE="Courier"><A HREF="#NormCreateSession()">NormCreateSession()</A></FONT>.</P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=106>
<TD WIDTH=125>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
<FONT FACE="Courier"><U>sessionId</U></FONT></P>
</TD>
<TD WIDTH=437>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
Application-defined value used as the <I>instance_id</I> field of
NORM sender messages for the application's participation within a
session. Receivers can detect when a sender has terminated and
restarted if the application uses different <FONT FACE="Courier"><U>sessionId</U></FONT>
values when initiating sender operation. For example, a robust
application could cache previous <FONT FACE="Courier"><U>sessionId</U></FONT>
values in non-volatile storage and gracefully recover (without
confusing receivers) from a total system shutdown and reboot by
using a new <FONT FACE="Courier"><U>sessionId</U></FONT> value
upon restart.</P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=125>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
<FONT FACE="Courier"><U>bufferSpace</U></FONT></P>
</TD>
<TD WIDTH=456>
<TD WIDTH=437>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
This specifies the maximum memory space the NORM protocol engine
is allowed to use to buffer any sender calculated FEC segments and
@ -1236,11 +1403,11 @@ function call include:</P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=106>
<TD WIDTH=125>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
<FONT FACE="Courier"><U>segmentSize</U></FONT></P>
</TD>
<TD WIDTH=456>
<TD WIDTH=437>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
This parameter sets the maximum <I>payload</I> size (in bytes) of
NORM sender messages (<I>not</I> including any NORM message header
@ -1262,11 +1429,11 @@ function call include:</P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=106>
<TD WIDTH=125>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
<FONT FACE="Courier"><U>blockSize</U></FONT></P>
</TD>
<TD WIDTH=456>
<TD WIDTH=437>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
This parameter sets the number of source symbol segments (packets)
per coding block, for the systematic Reed-Solomon FEC code used in
@ -1286,11 +1453,11 @@ function call include:</P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=106>
<TD WIDTH=125>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
<FONT FACE="Courier"><U>numParity</U></FONT></P>
</TD>
<TD WIDTH=456>
<TD WIDTH=437>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
This parameter sets the maximum number of parity symbol segments
(packets) the sender is willing to <I>calculate</I> per FEC coding
@ -2713,8 +2880,8 @@ yet been received (or is non-existent) for the specified object.</P>
<H4 CLASS="western">Synopsis</H4>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>#include
&lt;normApi.h&gt;</FONT></FONT></P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>off_t
NormObjectHasInfo(<A HREF="#NormObjectHandle">NormObjectHandle</A> objectHandle);</FONT></FONT></P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2><A HREF="#NormSize">NormSize</A>
NormObjectGetSize(<A HREF="#NormObjectHandle">NormObjectHandle</A> objectHandle);</FONT></FONT></P>
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function can be
used to determine the size (in bytes) of the transport object
@ -2724,11 +2891,9 @@ parameter. NORM can support large object sizes for the
typically the NORM library is built with any necessary, related
macros defined such that operating system large file support is
enabled (e.g., &quot;<FONT FACE="Courier">#define _FILE_OFFSET_BITS
64</FONT>&quot; or equivalent). Developers should configure their
build environment to correspond with the NORM library used to ensure
that the &quot;<FONT SIZE=2><FONT FACE="Courier">off_t</FONT></FONT>&quot;
type is appropriately defined.
</P>
64</FONT>&quot; or equivalent). The <FONT FACE="Courier"><A HREF="#NormSize">NormSize</A></FONT>
type is defined accordingly, so the application should be built with
the same large file support configuration.</P>
<P CLASS="western" STYLE="font-style: normal">For objects of type
<FONT FACE="Courier"><I>NORM_OBJECT_STREAM</I></FONT>, the size
returned here corresponds to the stream buffer size set by the sender
@ -2738,6 +2903,28 @@ application when opening the referenced stream object.</P>
content of the specified object, in bytes, is returned. Note that it
may be possible that some objects have zero data content, but do have
NORM_INFO content available.</P>
<H3 CLASS="functionheading-western"><A NAME="NormObjectGetBytesPending()">NormObjectGetBytesPending()</A></H3>
<H4 CLASS="western">Synopsis</H4>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>#include
&lt;normApi.h&gt;</FONT></FONT></P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2><A HREF="#NormSize">NormSize</A>
NormObjectGetBytesPending(<A HREF="#NormObjectHandle">NormObjectHandle</A> objectHandle);</FONT></FONT></P>
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function can be
used to determine the progress of reception of the NORM transport
object identified by the <FONT FACE="Courier"><U>objectHandle</U></FONT>
parameter. This function indicates the number of bytes that are
pending reception (I.e., when the object is completely received,
&quot;bytes pending&quot; will equal ZERO). This function is not
necessarily applicable to objects of type NORM_OBJECT_STREAM which do
not have a finite size. Note it is possible that this function might
also be useful to query the &quot;transmit pending&quot; status of
sender objects, but it does not account for pending FEC repair
transmissions and thus may not produce useful results for this
purpose.</P>
<H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">A number of object
source data bytes pending reception (or transmission) is returned.</P>
<H3 CLASS="functionheading-western"><A NAME="NormObjectCancel()">NormObjectCancel()</A></H3>
<H4 CLASS="western">Synopsis</H4>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>#include

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,14 @@
NORM Version History
Version 1.3b3
=============
- Added NORM_TX_FLUSH_COMPLETE notification so the sender app
can make an educated guess as to when his receivers are
all happy.
- Added NORM API sample code in "examples" directory.
- Added NormObjectGetBytesPending() call for receivers to
use to monitor reception progress.
Version 1.3b2
=============
- Added "graceful" stream shutdown option to

View File

@ -1,4 +1,3 @@
#include "normApi.h"
#include "normSession.h"
@ -143,8 +142,10 @@ class NormInstance : public NormController
NormInstance::Notification::Queue::Queue()
: head(NULL), tail(NULL)
{
}
NormInstance::Notification::Queue::~Queue()
{
Destroy();
@ -168,7 +169,7 @@ NormInstance::NormInstance()
#else
notify_fd[0] = notify_fd[1] = -1;
#endif // if/else WIN32/UNIX
session_mgr.SetController(this);
session_mgr.SetController(static_cast<NormController*>(this));
}
NormInstance::~NormInstance()
@ -314,6 +315,7 @@ void NormInstance::Notify(NormController::Event event,
else
{
// we're ignoring files
DMSG(8, "NormInstance::Notify() warning: receive file but no cache directory set, so ignoring file\n");
return;
}
break;
@ -849,6 +851,7 @@ void NormSetRxLoss(NormSessionHandle sessionHandle, double percent)
/** NORM Sender Functions */
bool NormStartSender(NormSessionHandle sessionHandle,
NormSessionId sessionId,
unsigned long bufferSpace,
unsigned short segmentSize,
unsigned char numData,
@ -860,7 +863,7 @@ bool NormStartSender(NormSessionHandle sessionHandle,
{
NormSession* session = (NormSession*)sessionHandle;
if (session)
result = session->StartServer(bufferSpace, segmentSize, numData, numParity);
result = session->StartServer(sessionId, bufferSpace, segmentSize, numData, numParity);
else
result = false;
instance->dispatcher.ResumeThread();
@ -1362,11 +1365,26 @@ unsigned short NormObjectGetInfo(NormObjectHandle objectHandle,
return result;
} // end NormObjectGetInfo()
off_t NormObjectGetSize(NormObjectHandle objectHandle)
NormSize NormObjectGetSize(NormObjectHandle objectHandle)
{
return ((NormObject*)objectHandle)->GetSize().GetOffset();
return ((NormSize)((NormObject*)objectHandle)->GetSize().GetOffset());
} // end NormObjectGetSize()
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()
void NormObjectCancel(NormObjectHandle objectHandle)
{
if (NORM_OBJECT_INVALID != objectHandle)

View File

@ -4,15 +4,10 @@
#ifdef WIN32
#include <winsock2.h>
#include <windows.h>
#else
#include <sys/types.h> // for "off_t"
#endif // WIN32
#ifdef _WIN32_WCE
#include <stdio.h>
//typedef fpos_t off_t;
typedef long off_t;
#else
#include <sys/types.h> // for "off_t" type
#endif // if/else _WIN32_WCE
////////////////////////////////////////////////////////////
// IMPORTANT NOTICE
// The NORM API is _very_ much in a developmental phase
@ -35,6 +30,7 @@ extern const NormInstanceHandle NORM_INSTANCE_INVALID;
typedef const void* NormSessionHandle;
extern const NormSessionHandle NORM_SESSION_INVALID;
typedef unsigned short NormSessionId;
typedef const void* NormNodeHandle;
extern const NormNodeHandle NORM_NODE_INVALID;
@ -46,6 +42,12 @@ typedef const void* NormObjectHandle;
extern const NormObjectHandle NORM_OBJECT_INVALID;
typedef unsigned short NormObjectTransportId;
#ifdef WIN32
typedef __int64 NormSize;
#else
typedef off_t NormSize;
#endif // WIN32
enum NormObjectType
{
NORM_OBJECT_NONE,
@ -80,6 +82,7 @@ enum NormEventType
NORM_EVENT_INVALID = 0,
NORM_TX_QUEUE_VACANCY,
NORM_TX_QUEUE_EMPTY,
NORM_TX_FLUSH_COMPLETED,
NORM_TX_OBJECT_SENT,
NORM_TX_OBJECT_PURGED,
NORM_LOCAL_SERVER_CLOSED,
@ -172,6 +175,7 @@ void NormSetRxLoss(NormSessionHandle sessionHandle, double percent);
/** NORM Sender Functions */
bool NormStartSender(NormSessionHandle sessionHandle,
NormSessionId sessionId,
unsigned long bufferSpace,
unsigned short segmentSize,
unsigned char numData,
@ -298,7 +302,9 @@ unsigned short NormObjectGetInfo(NormObjectHandle objectHandle,
char* buffer,
unsigned short bufferLen);
off_t NormObjectGetSize(NormObjectHandle objectHandle);
NormSize NormObjectGetSize(NormObjectHandle objectHandle);
NormSize NormObjectGetBytesPending(NormObjectHandle objectHandle);
void NormObjectCancel(NormObjectHandle objectHandle);

View File

@ -353,7 +353,7 @@ bool NormApp::OnCommand(const char* cmd, const char* val)
len = strlen(buffer);
len = (len > 8191) ? 8191 : len;
buffer[len++] = '\0';
if (!control_pipe.Send(buffer, len))
if (!control_pipe.Send(buffer, (unsigned int)len))
{
DMSG(0, "NormApp::OnCommand() error sending command to remote instance\n");
return false;
@ -1104,10 +1104,10 @@ void NormApp::Notify(NormController::Event event,
// object Size() has recommended buffering size
NormObjectSize size;
if (silent_client)
size = NormObjectSize((UINT32)rx_buffer_size);
size = rx_buffer_size;
else
size = object->GetSize();
size = (UINT32)object->GetSize().LSB();
ASSERT(0 == size.MSB());
if (((NormStreamObject*)object)->Accept(size.LSB()))
{
rx_stream = (NormStreamObject*)object;
@ -1544,7 +1544,9 @@ bool NormApp::OnStartup(int argc, const char*const* argv)
session->SetBackoffFactor(backoff_factor);
session->ServerSetGrtt(grtt_estimate);
session->ServerSetGroupSize(group_size);
if (!session->StartServer(tx_buffer_size, segment_size, ndata, nparity, interface_name))
// We also use the baseId as our server's "instance id" for illustrative purposes
UINT16 instanceId = baseId;
if (!session->StartServer(instanceId, tx_buffer_size, segment_size, ndata, nparity, interface_name))
{
DMSG(0, "NormApp::OnStartup() start server error!\n");
session_mgr.Destroy();

View File

@ -344,7 +344,7 @@ int NormFile::Read(char* buffer, int len)
#else
int result = read(fd, buffer, len);
#endif // if/else WIN32
if (result > 0) offset += (off_t)result;
if (result > 0) offset += (Offset)result;
return result;
} // end NormFile::Read()
@ -360,24 +360,24 @@ int NormFile::Write(const char* buffer, int len)
#else
int result = write(fd, buffer, len);
#endif // if/else WIN32
if (result > 0) offset += (off_t)result;
if (result > 0) offset += (Offset)result;
return result;
} // end NormFile::Write()
bool NormFile::Seek(off_t theOffset)
bool NormFile::Seek(Offset theOffset)
{
ASSERT(IsOpen());
#ifdef WIN32
#ifdef _WIN32_WCE
// (TBD) properly support big files on WinCE
off_t result = fseek(file_ptr, (long)theOffset, SEEK_SET);
Offset result = fseek(file_ptr, (long)theOffset, SEEK_SET);
#else
off_t result = _lseek(fd, theOffset, SEEK_SET);
Offset result = _lseeki64(fd, theOffset, SEEK_SET);
#endif // if/else _WIN32_WCE
#else
off_t result = lseek(fd, theOffset, SEEK_SET);
Offset result = lseek(fd, theOffset, SEEK_SET);
#endif // if/else WIN32
if (result == (off_t)-1)
if (result == (Offset)-1)
{
DMSG(0, "NormFile::Seek() lseek() error: %s", GetErrorString());
return false;
@ -389,12 +389,12 @@ bool NormFile::Seek(off_t theOffset)
}
} // end NormFile::Seek()
off_t NormFile::GetSize() const
NormFile::Offset NormFile::GetSize() const
{
ASSERT(IsOpen());
#ifdef _WIN32_WCE
DWORD fileSize = GetFileSize(_fileno(file_ptr), NULL);
return ((off_t)fileSize);
return ((Offset)fileSize);
#else
#ifdef WIN32
struct _stat info;
@ -787,7 +787,7 @@ NormFile::Type NormFile::GetType(const char* path)
#endif // if/else WIN32
} // end NormFile::GetType()
off_t NormFile::GetSize(const char* path)
NormFile::Offset NormFile::GetSize(const char* path)
{
#ifdef _WIN32_WCE
WIN32_FIND_DATA findData;
@ -799,7 +799,10 @@ off_t NormFile::GetSize(const char* path)
if (INVALID_HANDLE_VALUE != FindFirstFile(path, &findData))
#endif // if/else _UNICODE
{
return ((off_t)findData.nFileSizeLow); // (TBD) support big files
Offset fileSize = findData.nFileSizeLow;
if (sizeof(Offset) > 4)
fileSize |= ((Offset)findData.nFileSizeHigh) << (8*sizeof(DWORD));
return fileSize;
}
else
{

View File

@ -17,8 +17,6 @@
#ifdef _WIN32_WCE
#include <stdio.h>
//typedef fpos_t off_t;
typedef long off_t;
#else
#include <sys/types.h>
#endif // if/else _WIN32_WCE
@ -45,8 +43,12 @@ enum
class NormFile
{
// Methods
public:
#ifdef WIN32
typedef __int64 Offset;
#else
typedef off_t Offset;
#endif // if/else WIN32/UNIX
enum Type {INVALID, NORMAL, DIRECTORY};
NormFile();
~NormFile();
@ -66,13 +68,13 @@ class NormFile
}
int Read(char* buffer, int len);
int Write(const char* buffer, int len);
bool Seek(off_t theOffset);
off_t GetOffset() const {return (offset);}
off_t GetSize() const;
bool Seek(Offset theOffset);
NormFile::Offset GetOffset() const {return (offset);}
NormFile::Offset GetSize() const;
// static helper methods
static NormFile::Type GetType(const char *path);
static off_t GetSize(const char* path);
static NormFile::Offset GetSize(const char* path);
static time_t GetUpdateTime(const char* path);
static bool IsLocked(const char *path);
@ -117,7 +119,11 @@ class NormFile
int fd;
#endif // if/else _WIN32_WCE
int flags;
#ifdef WIN32
__int64 offset;
#else
off_t offset;
#endif // if/else WIN32/UNIX
}; // end class NormFile
@ -204,7 +210,7 @@ class NormFileList
FileItem(const char* thePath);
virtual ~FileItem();
NormFile::Type GetType() {return NormFile::GetType(path);}
off_t Size() const {return size;}
NormFile::Offset Size() const {return size;}
virtual bool GetNextFile(char* thePath,
bool reset,
bool updatesOnly,
@ -215,10 +221,10 @@ class NormFileList
protected:
const char* Path() {return path;}
char path[PATH_MAX];
off_t size;
FileItem* prev;
FileItem* next;
char path[PATH_MAX];
NormFile::Offset size;
FileItem* prev;
FileItem* next;
};
class DirectoryItem : public FileItem
{

View File

@ -431,111 +431,3 @@ unsigned char NormQuantizeRtt(double rtt)
return ((unsigned char)(ceil(255.0 - (13.0*log(NORM_RTT_MAX/rtt)))));
} // end NormQuantizeRtt()
NormObjectSize NormObjectSize::operator+(const NormObjectSize& size) const
{
NormObjectSize total;
total.msb = msb + size.msb;
total.lsb = lsb + size.lsb;
if ((total.lsb < lsb) || (total.lsb < size.lsb)) total.msb++;
return total;
} // end NormObjectSize::operator+(NormObjectSize id)
NormObjectSize NormObjectSize::operator-(const NormObjectSize& b) const
{
NormObjectSize result;
result.lsb = lsb - b.lsb;
result.msb = msb - b.msb;
if (lsb < b.lsb) result.msb--;
return result;
} // end NormObjectSize::operator-(NormObjectSize id)
NormObjectSize NormObjectSize::operator*(const NormObjectSize& b) const
{
UINT32 ll = (lsb & 0x0000ffff) * (b.lsb & 0x0000ffff);
UINT32 lm = (lsb & 0x0000ffff) * ((b.lsb >> 16) & 0x0000ffff);
UINT32 ml = ((lsb >> 16) & 0x0000ffff) * (b.lsb & 0x0000ffff);
UINT32 lu = (lsb & 0x0000ffff) * (UINT32)b.msb;
UINT32 mm = ((lsb >> 16) & 0x0000ffff) *
((b.lsb >> 16) & 0x0000ffff);
NormObjectSize result;
result.lsb = ll + (lm << 16) + (ml << 16);
result.msb = lu + mm + ((lm >> 16) & 0x0000ffff) +
((ml >> 16) & 0x0000ffff);
return result;
} // end NormObjectSize::operator*(NormObjectSize size)
// Note: This always rounds up if there is _any_ remainder
NormObjectSize NormObjectSize::operator/(const NormObjectSize& b) const
{
// Zero dividend is special case
if ((0 == lsb) && (0 == msb)) return NormObjectSize(0, 0);
// Zero divisor is special case
if ((0 == b.lsb) && (0 == b.msb)) return NormObjectSize(0xffff, 0xffffffff);
// Divisor >= dividend is special case
if ((b.lsb >= lsb) && (b.msb >= msb)) return NormObjectSize(0,1);
// divisor
UINT32 divisor[2];
divisor[0] = (UINT32)b.msb;
divisor[1] = b.lsb;
// dividend
UINT32 dividend[2];
dividend[0] = msb;
dividend[1] = (UINT32)lsb;
// remainder
UINT32 remainder[2];
remainder[0] = remainder[1] = 0;
unsigned int numBits = 64;
UINT32 d[2];
while (((divisor[1] > remainder[1]) && (divisor[0] == remainder[0])) ||
(divisor[0] > remainder[0]))
{
remainder[0] <<= 1;
remainder[0] |= (remainder[1] >> 31) & 0x00000001;
remainder[1] <<= 1;
remainder[1] |= (dividend[0] >> 31) & 0x00000001;
d[0] = dividend[0];
d[1] = dividend[1];
dividend[0] <<= 1;
dividend[0] |= (dividend[1] >> 31) & 0x00000001;
dividend[1] <<= 1;
numBits--;
}
// Note: above loop goes one step too far
// so we incr numBits, use old dividend (d)
numBits++;
UINT32 quotient[2];
quotient[0] = quotient[1] = 0;
bool extra = false;
for (unsigned int i = 0; i < numBits; i++)
{
UINT32 t[2];
t[0] = remainder[0] - divisor[0];
t[1] = remainder[1] - divisor[1];
if (remainder[1] < divisor[1]) t[0]--;
UINT32 q = ((t[0] >> 31) & 0x00000001) ^ 0x00000001;
d[0] <<= 1;
d[0] |= (d[1] >> 31) & 0x00000001;
d[1] <<= 1;
quotient[0] <<= 1;
quotient[1] = (quotient[1] << 1) | q;
if (q)
{
remainder[0] = t[0];
remainder[1] = t[1];
}
if (remainder[0] || remainder[1])
extra = true;
else
extra = false;
remainder[0] <<= 1;
remainder[0] |= (remainder[1] >> 31) & 0x00000001;
remainder[1] <<= 1;
remainder[1] |= (d[0] >> 31) & 0x00000001;
}
NormObjectSize result((UINT16)quotient[0], quotient[1]);
// If there was _any_ remainder, round up
if (extra) result++;
return result;
} // end NormObjectSize::operator/(NormObjectSize b)

View File

@ -11,8 +11,6 @@
#ifdef _WIN32_WCE
#include <stdio.h>
//typedef fpos_t off_t;
typedef long off_t;
#else
#include <sys/types.h> // for off_t
#endif // if/else _WIN32_WCE
@ -23,9 +21,6 @@ typedef long off_t;
const UINT8 NORM_PROTOCOL_VERSION = 1;
// (TBD) Alot of the "memcpy()" calls could be eliminated by
// taking advantage of the alignment of NORM messsages
const int NORM_ROBUST_FACTOR = 20; // default robust factor
// Pick a random number from 0..max
@ -101,85 +96,66 @@ inline double NormUnquantizeRate(unsigned short rate)
return mantissa * pow(10.0, exponent);
}
// This class is used to describe object "size" and/or "offset"
// (TBD) This hokey implementation should just use "off_t" as it's
// native storage format and get rid of this custom crap !!!
// (We should just get rid of this class !!!!!!!!)
class NormObjectSize
{
public:
NormObjectSize() : msb(0), lsb(0) {}
NormObjectSize(UINT16 upper, UINT32 lower) : msb(upper), lsb(lower) {}
NormObjectSize(UINT32 size) : msb(0), lsb(size) {}
NormObjectSize(UINT16 size) : msb(0), lsb(size) {}
NormObjectSize(const NormObjectSize& size) : msb(size.msb), lsb(size.lsb) {}
NormObjectSize(off_t size)
#ifdef WIN32
typedef __int64 Offset;
#else
typedef off_t Offset;
#endif
NormObjectSize() : size(0) {}
NormObjectSize(Offset theSize) : size(theSize) {}
NormObjectSize(UINT16 msb, UINT32 lsb)
{
lsb = (unsigned long)(size & 0x00000000ffffffff);
size >>= 32;
ASSERT(0 == (size & 0xffff0000));
msb = (unsigned short)(size & 0x0000ffff);
msb = 0;
size = (Offset)lsb;
size |= (sizeof(Offset) > 4) ? (((Offset)msb) << 32): (Offset)0;
}
Offset GetOffset() const {return size;}
UINT16 MSB() const
{return ((sizeof(Offset) > 4) ? (UINT16)((size >> 32) & 0x0000ffff) : 0);}
UINT32 LSB() const
{return ((UINT32)(size & 0xffffffff));}
UINT16 MSB() const {return msb;}
UINT32 LSB() const {return lsb;}
bool operator==(const NormObjectSize& size) const
{return ((msb == size.msb) && (lsb == size.lsb));}
bool operator>(const NormObjectSize& size) const
// Operators
bool operator==(const NormObjectSize& b) const
{return (b.size == size);}
NormObjectSize operator+(const NormObjectSize& b) const
{
return ((msb == size.msb) ?
(lsb > size.lsb) :
(msb > size.msb));
NormObjectSize result(size);
result.size += b.size;
return result;
}
bool operator<(const NormObjectSize& size) const
void operator+=(const NormObjectSize& b)
{size += b.size;}
NormObjectSize operator-(const NormObjectSize& b) const
{
return ((msb == size.msb) ?
(lsb < size.lsb) :
(msb < size.msb));
NormObjectSize result(size);
result.size -= b.size;
return result;
}
bool operator<=(const NormObjectSize& size) const
{return ((*this == size) || (*this<size));}
bool operator>=(const NormObjectSize& size) const
{return ((*this == size) || (*this>size));}
bool operator!=(const NormObjectSize& size) const
{return ((lsb != size.lsb) || (msb != size.msb));}
NormObjectSize operator+(const NormObjectSize& size) const;
NormObjectSize operator-(const NormObjectSize& size) const;
void operator+=(UINT32 increment)
void operator-=(const NormObjectSize& b)
{size -= b.size;}
void operator+=(Offset increment)
{size += increment;}
bool operator>(const NormObjectSize& b) const
{return (size > b.size);}
NormObjectSize operator*(const NormObjectSize& b) const
{
UINT32 temp32 = lsb + increment;
if (temp32 < lsb) msb++;
lsb = temp32;
NormObjectSize result(size);
result.size *= b.size;
return result;
}
NormObjectSize operator+(UINT32 increment) const
// Note: this is a "round-upwards" division operator
NormObjectSize operator/(const NormObjectSize& b) const
{
NormObjectSize total;
total.msb = msb;
total.lsb = lsb + increment;
if (total.lsb < lsb) total.msb++;
return total;
NormObjectSize result(size);
result.size /= b.size;
result.size = ((result.size * b.size) < size) ? result.size + 1 : result.size;
return result;
}
NormObjectSize& operator++(int)
{
lsb++;
if (0 == lsb) msb++;
return (*this);
}
NormObjectSize operator*(const NormObjectSize& b) const;
NormObjectSize operator/(const NormObjectSize& b) const;
off_t GetOffset() const
{
off_t offset = msb;
offset <<= 32;
offset += lsb;
return offset;
}
private:
UINT16 msb;
UINT32 lsb;
Offset size;
}; // end class NormObjectSize
#ifndef _NORM_API
@ -426,9 +402,9 @@ class NormObjectMsg : public NormMsg
FLAG_STREAM = 0x20,
FLAG_MSG_START = 0x40
};
UINT16 GetSessionId() const
UINT16 GetInstanceId() const
{
return (ntohs(((UINT16*)buffer)[SESSION_ID_OFFSET]));
return (ntohs(((UINT16*)buffer)[INSTANCE_ID_OFFSET]));
}
UINT8 GetGrtt() const {return ((UINT8*)buffer)[GRTT_OFFSET];}
UINT8 GetBackoffFactor() const {return ((((UINT8*)buffer)[GSIZE_OFFSET] >> 4) & 0x0f);}
@ -443,9 +419,9 @@ class NormObjectMsg : public NormMsg
}
// Message building routines
void SetSessionId(UINT16 sessionId)
void SetInstanceId(UINT16 instanceId)
{
((UINT16*)buffer)[SESSION_ID_OFFSET] = htons(sessionId);
((UINT16*)buffer)[INSTANCE_ID_OFFSET] = htons(instanceId);
}
void SetGrtt(UINT8 grtt) {((UINT8*)buffer)[GRTT_OFFSET] = grtt;}
void SetBackoffFactor(UINT8 backoff)
@ -467,8 +443,8 @@ class NormObjectMsg : public NormMsg
protected:
enum
{
SESSION_ID_OFFSET = MSG_OFFSET/2,
GRTT_OFFSET = (SESSION_ID_OFFSET*2)+2,
INSTANCE_ID_OFFSET = MSG_OFFSET/2,
GRTT_OFFSET = (INSTANCE_ID_OFFSET*2)+2,
BACKOFF_OFFSET = GRTT_OFFSET+1,
GSIZE_OFFSET = BACKOFF_OFFSET,
FLAGS_OFFSET = GSIZE_OFFSET+1,
@ -733,9 +709,9 @@ class NormCmdMsg : public NormMsg
};
// Message building
void SetSessionId(UINT16 sessionId)
void SetInstanceId(UINT16 instanceId)
{
((UINT16*)buffer)[SESSION_ID_OFFSET] = htons(sessionId);
((UINT16*)buffer)[INSTANCE_ID_OFFSET] = htons(instanceId);
}
void SetGrtt(UINT8 quantizedGrtt)
{((UINT8*)buffer)[GRTT_OFFSET] = quantizedGrtt;}
@ -751,7 +727,7 @@ class NormCmdMsg : public NormMsg
{((UINT8*)buffer)[FLAVOR_OFFSET] = (UINT8)flavor;}
// Message processing
UINT16 GetSessionId() const {return (ntohs(((UINT16*)buffer)[SESSION_ID_OFFSET]));}
UINT16 GetInstanceId() const {return (ntohs(((UINT16*)buffer)[INSTANCE_ID_OFFSET]));}
UINT8 GetGrtt() const {return ((UINT8*)buffer)[GRTT_OFFSET];}
UINT8 GetBackoffFactor() const {return ((((UINT8*)buffer)[GSIZE_OFFSET] >> 4) & 0x0f);}
UINT8 GetGroupSize() const {return (((UINT8*)buffer)[GSIZE_OFFSET] & 0x0f);}
@ -761,8 +737,8 @@ class NormCmdMsg : public NormMsg
friend class NormMsg;
enum
{
SESSION_ID_OFFSET = MSG_OFFSET/2,
GRTT_OFFSET = (SESSION_ID_OFFSET*2)+2,
INSTANCE_ID_OFFSET = MSG_OFFSET/2,
GRTT_OFFSET = (INSTANCE_ID_OFFSET*2)+2,
BACKOFF_OFFSET = GRTT_OFFSET + 1,
GSIZE_OFFSET = BACKOFF_OFFSET,
FLAVOR_OFFSET = GSIZE_OFFSET + 1
@ -1396,9 +1372,9 @@ class NormNackMsg : public NormMsg
{
buffer[SERVER_ID_OFFSET] = htonl(serverId);
}
void SetSessionId(UINT16 sessionId)
void SetInstanceId(UINT16 instanceId)
{
((UINT16*)buffer)[SESSION_ID_OFFSET] = htons(sessionId);
((UINT16*)buffer)[INSTANCE_ID_OFFSET] = htons(instanceId);
}
void SetGrttResponse(const struct timeval& grttResponse)
{
@ -1424,9 +1400,9 @@ class NormNackMsg : public NormMsg
{
return (ntohl(buffer[SERVER_ID_OFFSET]));
}
UINT16 GetSessionId() const
UINT16 GetInstanceId() const
{
return (ntohs(((UINT16*)buffer)[SESSION_ID_OFFSET]));
return (ntohs(((UINT16*)buffer)[INSTANCE_ID_OFFSET]));
}
void GetGrttResponse(struct timeval& grttResponse) const
{
@ -1449,8 +1425,8 @@ class NormNackMsg : public NormMsg
enum
{
SERVER_ID_OFFSET = MSG_OFFSET/4,
SESSION_ID_OFFSET = ((SERVER_ID_OFFSET*4)+4)/2,
RESERVED_OFFSET = ((SESSION_ID_OFFSET*2)+2)/2,
INSTANCE_ID_OFFSET = ((SERVER_ID_OFFSET*4)+4)/2,
RESERVED_OFFSET = ((INSTANCE_ID_OFFSET*2)+2)/2,
GRTT_RESPONSE_SEC_OFFSET = ((RESERVED_OFFSET*2)+2)/4,
GRTT_RESPONSE_USEC_OFFSET = ((GRTT_RESPONSE_SEC_OFFSET*4)+4)/4,
NACK_HEADER_LEN = (GRTT_RESPONSE_USEC_OFFSET*4)+4
@ -1472,9 +1448,9 @@ class NormAckMsg : public NormMsg
{
buffer[SERVER_ID_OFFSET] = htonl(serverId);
}
void SetSessionId(UINT16 sessionId)
void SetInstanceId(UINT16 instanceId)
{
((UINT16*)buffer)[SESSION_ID_OFFSET] = htons(sessionId);
((UINT16*)buffer)[INSTANCE_ID_OFFSET] = htons(instanceId);
}
void SetAckType(NormAck::Type ackType) {((UINT8*)buffer)[ACK_TYPE_OFFSET] = (UINT8)ackType;}
void SetAckId(UINT8 ackId) {((UINT8*)buffer)[ACK_ID_OFFSET] = ackId;}
@ -1496,9 +1472,9 @@ class NormAckMsg : public NormMsg
{
return (ntohl(buffer[SERVER_ID_OFFSET]));
}
UINT16 GetSessionId() const
UINT16 GetInstanceId() const
{
return (ntohs(((UINT16*)buffer)[SESSION_ID_OFFSET]));
return (ntohs(((UINT16*)buffer)[INSTANCE_ID_OFFSET]));
}
void GetGrttResponse(struct timeval& grttResponse) const
{
@ -1514,8 +1490,8 @@ class NormAckMsg : public NormMsg
enum
{
SERVER_ID_OFFSET = MSG_OFFSET/4,
SESSION_ID_OFFSET = ((SERVER_ID_OFFSET*4)+4)/2,
ACK_TYPE_OFFSET = (SESSION_ID_OFFSET*2)+2,
INSTANCE_ID_OFFSET = ((SERVER_ID_OFFSET*4)+4)/2,
ACK_TYPE_OFFSET = (INSTANCE_ID_OFFSET*2)+2,
ACK_ID_OFFSET = ACK_TYPE_OFFSET + 1,
GRTT_RESPONSE_SEC_OFFSET = (ACK_ID_OFFSET + 1)/4,
GRTT_RESPONSE_USEC_OFFSET = ((GRTT_RESPONSE_SEC_OFFSET*4)+4)/4,

View File

@ -43,7 +43,7 @@ NormCCNode::~NormCCNode()
NormServerNode::NormServerNode(class NormSession& theSession, NormNodeId nodeId)
: NormNode(theSession, nodeId), session_id(0), synchronized(false), sync_id(0),
: NormNode(theSession, nodeId), instance_id(0), synchronized(false), sync_id(0),
max_pending_range(256), is_open(false), segment_size(0), ndata(0), nparity(0),
repair_boundary(BLOCK_BOUNDARY), erasure_loc(NULL),
retrieval_loc(NULL), retrieval_pool(NULL),
@ -100,9 +100,9 @@ NormServerNode::~NormServerNode()
Close();
}
bool NormServerNode::Open(UINT16 sessionId)
bool NormServerNode::Open(UINT16 instanceId)
{
session_id = sessionId;
instance_id = instanceId;
if (!rx_table.Init(max_pending_range))
{
DMSG(0, "NormServerNode::Open() rx_table init error\n");
@ -123,6 +123,7 @@ bool NormServerNode::Open(UINT16 sessionId)
}
is_open = true;
synchronized = false;
resync_count = 0; // reset resync_count
return true;
} // end NormServerNode::Open()
@ -178,7 +179,7 @@ bool NormServerNode::AllocateBuffers(UINT16 segmentSize,
if (!block_pool.Init(numBlocks, blockSize))
{
DMSG(0, "NormServerNode::Open() block_pool init error\n");
DMSG(0, "NormServerNode::AllocateBuffers() block_pool init error\n");
Close();
return false;
}
@ -188,7 +189,7 @@ bool NormServerNode::AllocateBuffers(UINT16 segmentSize,
// a NormStreamObject
if (!segment_pool.Init(numSegments, segmentSize+NormDataMsg::GetStreamPayloadHeaderLength()+1))
{
DMSG(0, "NormServerNode::Open() segment_pool init error\n");
DMSG(0, "NormServerNode::AllocateBuffers() segment_pool init error\n");
Close();
return false;
}
@ -198,7 +199,7 @@ bool NormServerNode::AllocateBuffers(UINT16 segmentSize,
// needed for block decoding (new rx buffer mgmt scheme)
if (!(retrieval_pool = new char*[numData]))
{
DMSG(0, "NormServerNode::Open() new retrieval_pool error: %s\n", GetErrorString());
DMSG(0, "NormServerNode::AllocateBuffers() new retrieval_pool error: %s\n", GetErrorString());
Close();
return false;
}
@ -208,7 +209,7 @@ bool NormServerNode::AllocateBuffers(UINT16 segmentSize,
char* s = new char[segmentSize+NormDataMsg::GetStreamPayloadHeaderLength()];
if (NULL == s)
{
DMSG(0, "NormServerNode::Open() new retrieval segment error: %s\n", GetErrorString());
DMSG(0, "NormServerNode::AllocateBuffers() new retrieval segment error: %s\n", GetErrorString());
Close();
return false;
}
@ -218,20 +219,20 @@ bool NormServerNode::AllocateBuffers(UINT16 segmentSize,
if (!(retrieval_loc = new UINT16[numData]))
{
DMSG(0, "NormServerNode::Open() retrieval_loc allocation error: %s\n", GetErrorString());
DMSG(0, "NormServerNode::AllocateBuffers() retrieval_loc allocation error: %s\n", GetErrorString());
Close();
return false;
}
if (!decoder.Init(numParity, segmentSize+NormDataMsg::GetStreamPayloadHeaderLength()))
{
DMSG(0, "NormServerNode::Open() decoder init error\n");
DMSG(0, "NormServerNode::AllocateBuffers() decoder init error\n");
Close();
return false;
}
if (!(erasure_loc = new UINT16[numParity]))
{
DMSG(0, "NormServerNode::Open() erasure_loc allocation error: %s\n", GetErrorString());
DMSG(0, "NormServerNode::AllocateBuffers() erasure_loc allocation error: %s\n", GetErrorString());
Close();
return false;
}
@ -1006,6 +1007,8 @@ void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg)
if (obj)
{
rx_table.Insert(obj);
obj->Retain();
NormFtiExtension fti;
while (msg.GetNextExtension(fti))
{
@ -1021,8 +1024,6 @@ void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg)
session.Notify(NormController::RX_OBJECT_NEW, this, obj);
if (obj->Accepted())
{
rx_table.Insert(obj);
obj->Retain();
// (TBD) Do I _need_ to call "StreamUpdateStatus()" here?
if (obj->IsStream())
(static_cast<NormStreamObject*>(obj))->StreamUpdateStatus(blockId);
@ -1031,12 +1032,14 @@ void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg)
}
else
{
DMSG(0, "NormServerNode::HandleObjectMessage() object not accepted\n");
DeleteObject(obj);
obj = NULL;
}
}
else
{
DMSG(0, "NormServerNode::HandleObjectMessage() error opening object\n");
DeleteObject(obj);
obj = NULL;
}
@ -1608,7 +1611,7 @@ bool NormServerNode::OnRepairTimeout(ProtoTimer& /*theTimer*/)
}
// Queue NACK for transmission
nack->SetServerId(GetId());
nack->SetSessionId(session_id);
nack->SetInstanceId(instance_id);
// GRTT response is deferred until transmit time
if (unicast_nacks)
@ -1742,7 +1745,7 @@ bool NormServerNode::OnActivityTimeout(ProtoTimer& /*theTimer*/)
NormObject* objMax = rx_table.Find(max_pending_object);
if (NULL != objMax)
{
NormSegmentId segMax = objMax->GetMaxPendingSegmentId();
/*NormSegmentId segMax = objMax->GetMaxPendingSegmentId();
if (0 != segMax)
RepairCheck(NormObject::THRU_SEGMENT,
max_pending_object,
@ -1752,7 +1755,10 @@ bool NormServerNode::OnActivityTimeout(ProtoTimer& /*theTimer*/)
RepairCheck(NormObject::TO_BLOCK,
max_pending_object,
objMax->GetMaxPendingBlockId(),
0);
0);*/
// Let's try this instead
RepairCheck(NormObject::THRU_OBJECT, // (TBD) thru object???
max_pending_object, 0, 0);
}
else
RepairCheck(NormObject::TO_BLOCK, // (TBD) thru object???
@ -1837,7 +1843,7 @@ bool NormServerNode::OnCCTimeout(ProtoTimer& /*theTimer*/)
}
ack->Init();
ack->SetServerId(GetId());
ack->SetSessionId(session_id);
ack->SetInstanceId(instance_id);
ack->SetAckType(NormAck::CC);
ack->SetAckId(0);
@ -1878,7 +1884,7 @@ bool NormServerNode::OnAckTimeout(ProtoTimer& /*theTimer*/)
{
ack->Init();
ack->SetServerId(GetId());
ack->SetSessionId(session_id);
ack->SetInstanceId(instance_id);
ack->SetAckId(0);
AttachCCFeedback(*ack);
ack->SetObjectId(watermark_object_id);

View File

@ -245,8 +245,8 @@ class NormServerNode : public NormNode
void HandleNackMessage(const NormNackMsg& nack);
void HandleAckMessage(const NormAckMsg& ack);
bool Open(UINT16 sessionId);
UINT16 GetSessionId() {return session_id;}
bool Open(UINT16 instanceId);
UINT16 GetInstanceId() {return instance_id;}
bool IsOpen() const {return is_open;}
void Close();
bool AllocateBuffers(UINT16 segmentSize, UINT16 numData, UINT16 numParity);
@ -371,7 +371,7 @@ class NormServerNode : public NormNode
void AttachCCFeedback(NormAckMsg& ack);
void HandleRepairContent(const UINT32* buffer, UINT16 bufferLen);
UINT16 session_id;
UINT16 instance_id;
bool synchronized;
NormObjectId sync_id; // only valid if(synchronized)
NormObjectId next_id; // only valid if(synchronized)

View File

@ -45,7 +45,10 @@ void NormObject::Release()
if (reference_count)
reference_count--;
else
{
DMSG(0, "NormObject::Release() releasing non-retained object?!\n");
ASSERT(0);
}
if (0 == reference_count) delete this;
} // end NormObject::Release()
@ -109,7 +112,7 @@ bool NormObject::Open(const NormObjectSize& objectSize,
}
// Compute number of segments and coding blocks for the object
// (Note NormObjectSize divide operator always rounds _up_)
// (Note NormObjectSize divide operator always rounds _upwards_)
NormObjectSize numSegments = objectSize / NormObjectSize(segmentSize);
NormObjectSize numBlocks = numSegments / NormObjectSize(numData);
ASSERT(0 == numBlocks.MSB());
@ -124,7 +127,8 @@ bool NormObject::Open(const NormObjectSize& objectSize,
// Init pending_mask (everything pending)
if (!pending_mask.Init(numBlocks.LSB(), 0xffffffff))
{
DMSG(0, "NormObject::Open() init pending_mask error\n");
DMSG(0, "NormObject::Open() init pending_mask (%lu) error: %s\n",
numBlocks.GetOffset(), GetErrorString());
Close();
return false;
}
@ -206,7 +210,42 @@ void NormObject::Close()
pending_mask.Destroy();
block_buffer.Destroy();
segment_size = 0;
} // end NormObject::Close();
} // end NormObject::Close()
NormObjectSize NormObject::GetBytesPending() const
{
NormObjectSize bytesCompleted;
NormBlockId nextId;
if (GetFirstPending(nextId))
{
NormObjectSize largeBlockBytes = NormObjectSize(large_block_size) *
NormObjectSize(segment_size);
NormObjectSize smallBlockBytes = NormObjectSize(small_block_size) *
NormObjectSize(segment_size);
NormObjectSize lastBlockBytes = smallBlockBytes - NormObjectSize(segment_size) +
NormObjectSize(final_segment_size);
NormObjectSize pendingBytes(0);
do
{
NormBlock* block = block_buffer.Find(nextId);
if (block)
pendingBytes += block->GetBytesPending(GetBlockSize(nextId), segment_size,
final_block_id, final_segment_size);
else if ((UINT32)nextId < large_block_count)
pendingBytes += largeBlockBytes;
else if (nextId == final_block_id)
pendingBytes += lastBlockBytes;
else
pendingBytes += smallBlockBytes;
nextId++;
} while (GetNextPending(nextId));
return pendingBytes;
}
else
{
return NormObjectSize(0);
}
} // end NormObject::GetBytesCompleted()
// Used by server
bool NormObject::HandleInfoRequest()
@ -1732,7 +1771,7 @@ NormFileObject::NormFileObject(class NormSession& theSession,
class NormServerNode* theServer,
const NormObjectId& objectId)
: NormObject(FILE, theSession, theServer, objectId),
large_block_length(0,0), small_block_length(0,0)
large_block_length(0), small_block_length(0)
{
path[0] = '\0';
}
@ -1775,7 +1814,7 @@ bool NormFileObject::Open(const char* thePath,
// We're sending this file
if (file.Open(thePath, O_RDONLY))
{
off_t size = file.GetSize();
NormObjectSize::Offset size = file.GetSize();
if (size)
{
if (!NormObject::Open(NormObjectSize(size),
@ -1861,7 +1900,7 @@ bool NormFileObject::WriteSegment(NormBlockId blockId,
segmentOffset = segmentOffset + small_block_length*smallBlockIndex +
segmentSize*segmentId;
}
off_t offset = segmentOffset.GetOffset();
NormFile::Offset offset = segmentOffset.GetOffset();
if (offset != file.GetOffset())
{
if (!file.Seek(offset)) return false;
@ -1903,9 +1942,7 @@ UINT16 NormFileObject::ReadSegment(NormBlockId blockId,
segmentOffset = segmentOffset + small_block_length*smallBlockIndex +
segmentSize*segmentId;
}
//off_t offsetScaleMSB = 0xffffffff + 1; // yuk! can't we do better
//off_t offset = (off_t)segmentOffset.LSB() + ((off_t)segmentOffset.MSB() * offsetScaleMSB);
off_t offset = segmentOffset.GetOffset();
NormFile::Offset offset = segmentOffset.GetOffset();
if (offset != file.GetOffset())
{
if (!file.Seek(offset))
@ -1952,7 +1989,7 @@ NormDataObject::NormDataObject(class NormSession& theSession,
class NormServerNode* theServer,
const NormObjectId& objectId)
: NormObject(DATA, theSession, theServer, objectId),
large_block_length(0,0), small_block_length(0,0),
large_block_length(0), small_block_length(0),
data_ptr(NULL), data_max(0), data_released(false)
{
@ -2709,9 +2746,9 @@ bool NormStreamObject::Read(char* buffer, unsigned int* buflen, bool findMsgStar
{
if (stream_closing)
{
DMSG(0, "NormStreamObject::Read() attempted to read from closed stream\n");
DMSG(4, "NormStreamObject::Read() attempted to read from closed stream\n");
*buflen = 0;
return false;
return true;
}
Retain();
SetNotifyOnUpdate(true); // reset notification when streams are read
@ -3220,7 +3257,7 @@ char* NormSimObject::RetrieveSegment(NormBlockId blockId,
NormObjectTable::NormObjectTable()
: table((NormObject**)NULL), range_max(0), range(0),
count(0), size(0,0)
count(0), size(0)
{
}

View File

@ -112,6 +112,8 @@ class NormObject
small_block_size);
}
NormObjectSize GetBytesPending() const;
bool IsPending(bool flush = true) const;
bool IsRepairPending() const;
bool IsPendingInfo() {return pending_info;}
@ -542,7 +544,7 @@ class NormObjectTable
NormObjectId RangeHi() const {return range_hi;}
bool IsEmpty() const {return (0 == range);}
UINT32 Count() const {return count;}
const NormObjectSize& Size() const {return size;}
const NormObjectSize& GetSize() const {return size;}
class Iterator
{

View File

@ -474,6 +474,34 @@ bool NormBlock::AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
return true;
} // end NormBlock::AppendRepairAdv()
NormObjectSize NormBlock::GetBytesPending(UINT16 numData,
UINT16 segmentSize,
NormBlockId finalBlockId,
UINT16 finalSegmentSize) const
{
NormObjectSize pendingBytes(0);
NormSegmentId nextId;
if (GetFirstPending(nextId))
{
do
{
if (nextId < numData)
pendingBytes += NormObjectSize(segmentSize);
else
break;
nextId++;
} while (GetNextPending(nextId));
}
// Correct for final_segment_size, if applicable
if ((id == finalBlockId) &&
(IsPending(numData - 1)))
{
pendingBytes -= NormObjectSize(segmentSize);
pendingBytes += NormObjectSize(finalSegmentSize);
}
return pendingBytes;
} // end NormBlock::GetBytesPending()
// Called by client
// (TBD) this should return true iff something appended, false otherwise
bool NormBlock::AppendRepairRequest(NormNackMsg& nack,

View File

@ -219,6 +219,11 @@ class NormBlock
bool IsTransmitPending() const
{return (pending_mask.IsSet() || repair_mask.IsSet());}
NormObjectSize GetBytesPending(UINT16 numData,
UINT16 segmentSize,
NormBlockId finalBlockId,
UINT16 finalSegmentSize) const;
bool AppendRepairRequest(NormNackMsg& nack,
UINT16 numData,
UINT16 numParity,

View File

@ -20,7 +20,7 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
rx_socket(ProtoSocket::UDP), local_node_id(localNodeId),
ttl(DEFAULT_TTL), loopback(false),
tx_rate(DEFAULT_TRANSMIT_RATE/8.0), tx_rate_min(-1.0), tx_rate_max(-1.0),
backoff_factor(DEFAULT_BACKOFF_FACTOR), is_server(false), session_id(0),
backoff_factor(DEFAULT_BACKOFF_FACTOR), is_server(false), instance_id(0),
ndata(DEFAULT_NDATA), nparity(DEFAULT_NPARITY), auto_parity(0), extra_parity(0),
next_tx_object_id(0), tx_cache_count_min(8), tx_cache_count_max(256),
tx_cache_size_max((UINT32)20*1024*1024),
@ -269,7 +269,8 @@ void NormSession::SetTxRateBounds(double rateMin, double rateMax)
} // end NormSession::SetTxRateBounds()
bool NormSession::StartServer(UINT32 bufferSpace,
bool NormSession::StartServer(UINT16 instanceId,
UINT32 bufferSpace,
UINT16 segmentSize,
UINT16 numData,
UINT16 numParity,
@ -337,6 +338,7 @@ bool NormSession::StartServer(UINT32 bufferSpace,
}
}
instance_id = instanceId;
segment_size = segmentSize;
sent_rate = 0.0;
prev_update_time.tv_sec = prev_update_time.tv_usec = 0;
@ -622,6 +624,10 @@ void NormSession::Serve()
{
DMSG(6, "NormSession::Serve() node>%lu server flush complete ...\n",
LocalNodeId());
Notify(NormController::TX_FLUSH_COMPLETED,
(NormServerNode*)NULL,
(NormObject*)NULL);
flush_count++;
}
}
@ -993,7 +999,7 @@ bool NormSession::QueueTxObject(NormObject* obj)
unsigned long count = tx_table.Count();
while ((count >= tx_cache_count_min) &&
((count >= tx_cache_count_max) ||
((tx_table.Size() + obj->GetSize()) > tx_cache_size_max)))
((tx_table.GetSize() + obj->GetSize()) > tx_cache_size_max)))
{
// Remove oldest non-pending
NormObject* oldest = tx_table.Find(tx_table.RangeLo());
@ -1173,9 +1179,6 @@ void NormTrace(const struct timeval& currentTime,
"CMD(ACK_REQ)",
"CMD(APP)"
};
static const char* REQ_NAME[] =
{
"INVALID",
@ -1202,26 +1205,26 @@ void NormTrace(const struct timeval& currentTime,
#else
struct tm* ct = gmtime((time_t*)&currentTime.tv_sec);
#endif // if/else _WIN32_WCE
DMSG(0, "trace>%02d:%02d:%02d.%06lu node>%lu %s>%s seq>%hu ",
DMSG(0, "trace>%02d:%02d:%02d.%06lu node>%lu %s>%s ",
ct->tm_hour, ct->tm_min, ct->tm_sec, currentTime.tv_usec,
(UINT32)localId, status, addr.GetHostString(), seq);
(UINT32)localId, status, addr.GetHostString());
bool clrFlag = false;
switch (msgType)
{
case NormMsg::INFO:
{
const NormInfoMsg& info = (const NormInfoMsg&)msg;
DMSG(0, "INFO obj>%hu ", (UINT16)info.GetObjectId());
DMSG(0, "inst>%hu seq>%hu INFO obj>%hu ",
info.GetInstanceId(), seq, (UINT16)info.GetObjectId());
break;
}
case NormMsg::DATA:
{
const NormDataMsg& data = (const NormDataMsg&)msg;
if (data.IsData())
DMSG(0, "DATA ");
else
DMSG(0, "PRTY ");
DMSG(0, "obj>%hu blk>%lu seg>%hu ",
DMSG(0, "inst>%hu seq>%hu %s obj>%hu blk>%lu seg>%hu ",
data.GetInstanceId(),
seq,
data.IsData() ? "DATA" : "PRTY",
(UINT16)data.GetObjectId(),
(UINT32)data.GetFecBlockId(),
(UINT16)data.GetFecSymbolId());
@ -1242,8 +1245,9 @@ void NormTrace(const struct timeval& currentTime,
}
case NormMsg::CMD:
{
NormCmdMsg::Flavor flavor = ((const NormCmdMsg&)msg).GetFlavor();
DMSG(0, "%s ", CMD_NAME[flavor]);
const NormCmdMsg& cmd = static_cast<const NormCmdMsg&>(msg);
NormCmdMsg::Flavor flavor = cmd.GetFlavor();
DMSG(0, "inst>%hu seq>%hu %s ", cmd.GetInstanceId(), seq, CMD_NAME[flavor]);
switch (flavor)
{
case NormCmdMsg::ACK_REQ:
@ -1255,7 +1259,8 @@ void NormTrace(const struct timeval& currentTime,
}
case NormCmdMsg::SQUELCH:
{
const NormCmdSquelchMsg& squelch = (const NormCmdSquelchMsg&)msg;
const NormCmdSquelchMsg& squelch =
static_cast<const NormCmdSquelchMsg&>(msg);
DMSG(0, " obj>%hu blk>%lu seg>%hu ",
(UINT16)squelch.GetObjectId(),
(UINT32)squelch.GetFecBlockId(),
@ -1264,7 +1269,8 @@ void NormTrace(const struct timeval& currentTime,
}
case NormCmdMsg::FLUSH:
{
const NormCmdFlushMsg& flush = (const NormCmdFlushMsg&)msg;
const NormCmdFlushMsg& flush =
static_cast<const NormCmdFlushMsg&>(msg);
DMSG(0, " obj>%hu blk>%lu seg>%hu ",
(UINT16)flush.GetObjectId(),
(UINT32)flush.GetFecBlockId(),
@ -1273,7 +1279,8 @@ void NormTrace(const struct timeval& currentTime,
}
case NormCmdMsg::CC:
{
const NormCmdCCMsg& cc = (const NormCmdCCMsg&)msg;
const NormCmdCCMsg& cc =
static_cast<const NormCmdCCMsg&>(msg);
DMSG(0, " seq>%u ", cc.GetCCSequence());
NormHeaderExtension ext;
while (cc.GetNextExtension(ext))
@ -1382,12 +1389,12 @@ void NormSession::ClientHandleObjectMessage(const struct timeval& currentTime,
NormServerNode* theServer = (NormServerNode*)server_tree.FindNodeById(sourceId);
if (theServer)
{
if (msg.GetSessionId() != theServer->GetSessionId())
if (msg.GetInstanceId() != theServer->GetInstanceId())
{
DMSG(2, "NormSession::ClientHandleObjectMessage() node>%lu server>%lu sessionId change - resyncing.\n",
DMSG(2, "NormSession::ClientHandleObjectMessage() node>%lu server>%lu instanceId change - resyncing.\n",
LocalNodeId(), theServer->GetId());
theServer->Close();
if (!theServer->Open(msg.GetSessionId()))
if (!theServer->Open(msg.GetInstanceId()))
{
DMSG(0, "NormSession::ClientHandleObjectMessage() node>%lu error re-opening NormServerNode\n");
// (TBD) notify application of error
@ -1400,7 +1407,7 @@ void NormSession::ClientHandleObjectMessage(const struct timeval& currentTime,
if ((theServer = new NormServerNode(*this, msg.GetSourceId())))
{
Notify(NormController::REMOTE_SERVER_NEW, theServer, NULL);
if (theServer->Open(msg.GetSessionId()))
if (theServer->Open(msg.GetInstanceId()))
{
server_tree.AttachNode(theServer);
theServer->Retain();
@ -1438,12 +1445,12 @@ void NormSession::ClientHandleCommand(const struct timeval& currentTime,
NormServerNode* theServer = (NormServerNode*)server_tree.FindNodeById(sourceId);
if (theServer)
{
if (cmd.GetSessionId() != theServer->GetSessionId())
if (cmd.GetInstanceId() != theServer->GetInstanceId())
{
DMSG(2, "NormSession::ClientHandleCommand() node>%lu server>%lu sessionId change - resyncing.\n",
DMSG(2, "NormSession::ClientHandleCommand() node>%lu server>%lu instanceId change - resyncing.\n",
LocalNodeId(), theServer->GetId());
theServer->Close();
if (!theServer->Open(cmd.GetSessionId()))
if (!theServer->Open(cmd.GetInstanceId()))
{
DMSG(0, "NormSession::ClientHandleCommand() node>%lu error re-opening NormServerNode\n");
// (TBD) notify application of error
@ -1457,7 +1464,8 @@ void NormSession::ClientHandleCommand(const struct timeval& currentTime,
// LocalNodeId());
if ((theServer = new NormServerNode(*this, cmd.GetSourceId())))
{
if (theServer->Open(cmd.GetSessionId()))
Notify(NormController::REMOTE_SERVER_NEW, theServer, NULL);
if (theServer->Open(cmd.GetInstanceId()))
{
server_tree.AttachNode(theServer);
theServer->Retain();
@ -2645,16 +2653,16 @@ bool NormSession::SendMessage(NormMsg& msg)
bool isProbe = false;
// Fill in any last minute timestamps
// (TBD) fill in SessionId fields on all messages as needed
// (TBD) fill in InstanceId fields on all messages as needed
switch (msg.GetType())
{
case NormMsg::INFO:
case NormMsg::DATA:
((NormObjectMsg&)msg).SetSessionId(session_id);
((NormObjectMsg&)msg).SetInstanceId(instance_id);
msg.SetSequence(tx_sequence++); // (TBD) set for session dst msgs
break;
case NormMsg::CMD:
((NormCmdMsg&)msg).SetSessionId(session_id);
((NormCmdMsg&)msg).SetInstanceId(instance_id);
switch (((NormCmdMsg&)msg).GetFlavor())
{
case NormCmdMsg::CC:

View File

@ -16,6 +16,7 @@ class NormController
EVENT_INVALID = 0,
TX_QUEUE_VACANCY,
TX_QUEUE_EMPTY,
TX_FLUSH_COMPLETED,
TX_OBJECT_SENT,
TX_OBJECT_PURGED,
LOCAL_SERVER_CLOSED,
@ -158,10 +159,11 @@ class NormSession
void ServerSetBaseObjectId(NormObjectId baseId)
{
next_tx_object_id = IsServer() ? next_tx_object_id : baseId;
session_id = IsServer() ? session_id : (UINT16)baseId;
//instance_id = IsServer() ? instance_id : (UINT16)baseId;
}
bool IsServer() {return is_server;}
bool StartServer(UINT32 bufferSpace,
bool StartServer(UINT16 instanceId,
UINT32 bufferSpace,
UINT16 segmentSize,
UINT16 numData,
UINT16 numParity,
@ -363,7 +365,7 @@ class NormSession
// Server parameters and state
bool is_server;
UINT16 session_id;
UINT16 instance_id;
UINT16 segment_size;
UINT16 ndata;
UINT16 nparity;

View File

@ -15,12 +15,7 @@
#endif // UNIX
int main(int argc, char* argv[])
{
printf("normTest starting ...\n");
printf("normTest starting (sizeof(NormOffset) = %d)...\n", sizeof(NormOffset));
NormInstanceHandle instance = NormCreateInstance();
@ -40,17 +35,18 @@ int main(int argc, char* argv[])
// NOTE: These are debugging routines available (not for normal app use)
SetDebugLevel(2);
// Uncomment to turn on debug NORM message tracing
NormSetMessageTrace(session, true);
//NormSetMessageTrace(session, true);
// Uncomment to turn on some random packet loss
//NormSetTxLoss(session, 1.0); // 10% packet loss
NormSetTxLoss(session, 10.0); // 10% packet loss
struct timeval currentTime;
ProtoSystemTime(currentTime);
// Uncomment to get different packet loss patterns from run to run
//srand(currentTime.tv_sec); // seed random number generator
// (and a different sender sessionId)
srand(currentTime.tv_sec); // seed random number generator
NormSetGrttEstimate(session, 0.001); // 1 msec initial grtt
NormSetTransmitRate(session, 60.0e+06); // in bits/second
NormSetTransmitRate(session, 60.0e+03); // in bits/second
NormSetDefaultRepairBoundary(session, NORM_BOUNDARY_BLOCK);
@ -64,7 +60,7 @@ int main(int argc, char* argv[])
NormSetLoopback(session, true);
// Uncomment this line to participate as a receiver
//NormStartReceiver(session, 1024*1024);
NormStartReceiver(session, 1024*1024);
// Uncomment to set large rx socket buffer size
// (might be needed for high rate sessions)
@ -73,8 +69,12 @@ int main(int argc, char* argv[])
// Uncomment to enable TCP-friendly congestion control
//NormSetCongestionControl(session, true);
// We use a random "sessionId"
NormSessionId sessionId = (NormSessionId)rand();
// Uncomment the following line to start sender
NormStartSender(session, 4096*1024, 1400, 64, 0);
NormStartSender(session, sessionId, 4096*1024, 1400, 64, 0);
// Uncomment to set large tx socket buffer size
// (might be needed for high rate sessions)
@ -87,7 +87,7 @@ int main(int argc, char* argv[])
const char* fileName = "ferrari.jpg";
// Uncomment this line to send a stream instead of the file
stream = NormStreamOpen(session, 4096*1024);
//stream = NormStreamOpen(session, 4096*1024);
// NORM_FLUSH_PASSIVE automatically flushes full writes to
// the stream.

View File

@ -32,6 +32,6 @@
#ifndef _NORM_VERSION
#define _NORM_VERSION
#define VERSION "1.3b2"
#define VERSION "1.3b3"
#endif // _NORM_VERSION

33
examples/README.TXT Normal file
View File

@ -0,0 +1,33 @@
NORM API Examples
=================
This directory contains some purposely simplified examples of NORM
API usage. See comments in the source code files on how to build
these on Unix platforms. Eventually, "Makefiles" (and hopefully
"configure" scripts) will be provided as well as Visual C++
project files for Win32 builds.
The following example programs are included:
normFileSend.cpp - simple file transmission program. Sends one
file and exits.
normFileRecv.cpp - simple file reception program. Receives one
file and exits.
(These two programs use a hard-coded multicast address and port,
but take a file name and directory name, respectively, as a
command-line argument to determine the file sent and the
directory to which receive files are stored.)
Other examples will be added later including examples using the
"NormGetDescriptor()" function to allow NORM API events to be
multiplexed with other possible application events (e.g. other I/O
or Windows messages, etc).
------------- Brian Adamson <mailto:adamson@itd.nrl.navy.mil> 9
June 2005

167
examples/normFileRecv.cpp Normal file
View File

@ -0,0 +1,167 @@
/******************************************************************************
Simple NORM file receiver example app using the NORM API
USAGE:
normRecvFile <rxCacheDirectory>
BUILD (Unix):
g++ -o normRecvFile normRecvFile.cpp -I../common/ -I../protolib/common \
-DPROTO_DEBUG ../unix/libnorm.a ../protolib/unix/libProtokit.a -lpthread
(for MacOS/BSD, add "-lresolv")
(for Solaris, add "-ldl -lnsl -lsocket -lresolv")
******************************************************************************/
// Notes:
// 1) The program exits once a single file has been received ...
// 2) The received file is written to the <rxCacheDirectory>
// 3) The program also will exit on <CTRL-C> from user
// 4) "normFileRecv" should be started before "normFileSend"
#include "normApi.h" // for NORM API
#include "protoDefs.h" // for ProtoSystemTime
#include "protoDebug.h" // for SetDebugLevel(), etc
#include <stdio.h> // for printf(), etc
#include <stdlib.h> // for srand()
#include <string.h> // for strrchr()
#ifdef WIN32
const char DIR_DELIMITER = '\\';
#else
const char DIR_DELIMITER = '/';
#endif // if/else WIN32/UNIX
int main(int argc, char* argv[])
{
// 0) The rxCachePath should be argv[1] ...
if (argc != 2)
{
fprintf(stderr, "normFileRecv error: invalid argument(s)\n");
fprintf(stderr, "Usage: normRecvFile <rxCachePath>\n");
return -1;
}
const char* rxCachePath = argv[1];
// 1) Create a NORM API "NormInstance"
NormInstanceHandle instance = NormCreateInstance();
// 2) Create a NormSession using default "automatic" local node id
NormSessionHandle session = NormCreateSession(instance,
"224.1.2.3",
6003,
NORM_NODE_ANY);
// NOTE: These are debugging routines available
// (not necessary for normal app use)
// (Need to include "protolib/common/protoDebug.h" for this
//SetDebugLevel(2);
// Uncomment to turn on debug NORM message tracing
//NormSetMessageTrace(session, true);
// Uncomment to turn on some random packet loss for testing
//NormSetRxLoss(session, 10.0); // 10% packet loss
struct timeval currentTime;
ProtoSystemTime(currentTime);
// Uncomment to get different packet loss patterns from run to run
srand(currentTime.tv_sec); // seed random number generator
// 3) Set receiver file cache path (where received files are mstored)
if (!NormSetCacheDirectory(instance, rxCachePath))
{
fprintf(stderr, "normFileReceive: error setting cache directory\n");
return -1;
}
// 4) Start the receiver with 1 Mbyte buffer per sender
NormStartReceiver(session, 1024*1024);
// 5) Enter NORM event loop
bool keepGoing = true;
NormEvent theEvent;
while (keepGoing && NormGetNextEvent(instance, &theEvent))
{
switch (theEvent.type)
{
case NORM_RX_OBJECT_NEW:
fprintf(stderr, "normFileRecv: NORM_RX_OBJECT_NEW event ...\n");
break;
case NORM_RX_OBJECT_INFO:
// Assume info contains '/' delimited <path/fileName> string
fprintf(stderr, "normFileRecv: NORM_RX_OBJECT_INFO event ...\n");
if (NORM_OBJECT_FILE == NormObjectGetType(theEvent.object))
{
char fileName[PATH_MAX];
strcpy(fileName, rxCachePath);
int pathLen = strlen(fileName);
if (DIR_DELIMITER != fileName[pathLen-1])
{
fileName[pathLen++] = DIR_DELIMITER;
fileName[pathLen] = '\0';
}
unsigned short nameLen = PATH_MAX - pathLen;
nameLen = NormObjectGetInfo(theEvent.object, fileName+pathLen, nameLen);
fileName[nameLen + pathLen] = '\0';
char* ptr = fileName + 5;
while ('\0' != *ptr)
{
if ('/' == *ptr) *ptr = DIR_DELIMITER;
ptr++;
}
if (!NormFileRename(theEvent.object, fileName))
fprintf(stderr, "normFileRecv: NormSetFileName(%s) error\n", fileName);
}
break;
case NORM_RX_OBJECT_UPDATED:
{
//fprintf(stderr, "normFileRecv: NORM_RX_OBJECT_UPDATE event ...\n");
// Uncomment this stuff to monitor file receive progress
// (At high packet rates, you may want to be careful here and
// only calculate/post updates occasionally rather than for
// each and every RX_OBJECT_UPDATE event)
NormSize objectSize = NormObjectGetSize(theEvent.object);
NormSize completed = objectSize - NormObjectGetBytesPending(theEvent.object);
double percentComplete = 100.0 * ((double)completed/(double)objectSize);
fprintf(stderr, "normFileRecv: completion status %lu/%lu (%3.0lf%%)\n",
completed, objectSize, percentComplete);
break;
}
case NORM_RX_OBJECT_COMPLETED:
fprintf(stderr, "normFileRecv: NORM_RX_OBJECT_COMPLETED event ...\n");
keepGoing = false;
break;
case NORM_RX_OBJECT_ABORTED:
fprintf(stderr, "normFileRecv: NORM_RX_OBJECT_ABORTED event ...\n");
break;
case NORM_REMOTE_SERVER_NEW:
fprintf(stderr, "normFileRecv: NORM_REMOTE_SERVER_NEW event ...\n");
break;
case NORM_REMOTE_SERVER_ACTIVE:
fprintf(stderr, "normFileRecv: NORM_REMOTE_SERVER_ACTIVE event ...\n");
break;
case NORM_REMOTE_SERVER_INACTIVE:
fprintf(stderr, "normFileRecv: NORM_REMOTE_SERVER_INACTIVE event ...\n");
break;
default:
fprintf(stderr, "normFileRecv: Got event type: %d\n", theEvent.type);
} // end switch(theEvent.type)
}
NormStopReceiver(session);
NormDestroySession(session);
NormDestroyInstance(instance);
fprintf(stderr, "normFileRecv: Done.\n");
return 0;
} // end main()

144
examples/normFileSend.cpp Normal file
View File

@ -0,0 +1,144 @@
/******************************************************************************
Simple NORM file sender example app using the NORM API
USAGE:
normSendFile <fileName>
BUILD (Unix):
g++ -o normFileSend normFileSend.cpp -I../common/ -I../protolib/common \
../unix/libnorm.a ../protolib/unix/libProtokit.a -lpthread
(for MacOS/BSD, add "-lresolv")
(for Solaris, add "-ldl -lnsl -lsocket -lresolv")
******************************************************************************/
// Notes:
// 1) A single file is sent.
// 2) The program exits upon NORM_TX_FLUSH_COMPLETED notification (or user <CTRL-C>)
// 3) NORM receiver should be started first (before sender starts)
#include "normApi.h" // for NORM API
#include "protoDefs.h" // for ProtoSystemTime
#include "protoDebug.h" // for SetDebugLevel(), etc
#include <stdio.h> // for printf(), etc
#include <stdlib.h> // for srand()
#include <string.h> // for strrchr()
#ifdef WIN32
const char DIR_DELIMITER = '\\';
#else
const char DIR_DELIMITER = '/';
#endif // if/else WIN32/UNIX
int main(int argc, char* argv[])
{
// 0) The filePath should be argv[1] ...
if (argc != 2)
{
fprintf(stderr, "normFileSend error: invalid argument(s)\n");
fprintf(stderr, "Usage: normFileSend <file>\n");
return -1;
}
const char* filePath = argv[1];
// Here we determine the "name" portion of the filePath
// (The file "name" is later used for NORM_INFO content)
const char* fileName = strrchr(filePath, DIR_DELIMITER);
if (fileName)
fileName++;
else
fileName = filePath;
// 1) Create a NORM API "NormInstance"
NormInstanceHandle instance = NormCreateInstance();
// 2) Create a NormSession using default "automatic" local node id
NormSessionHandle session = NormCreateSession(instance,
"224.1.2.3",
6003,
NORM_NODE_ANY);
// NOTE: These are some debugging routines available
// (not necessary for normal app use)
// (Need to include "protolib/common/protoDebug.h" for this
//SetDebugLevel(2);
// Uncomment to turn on debug NORM message tracing
//NormSetMessageTrace(session, true);
// Uncomment to turn on some random packet loss
// NormSetTxLoss(session, 10.0); // 10% packet loss
struct timeval currentTime;
ProtoSystemTime(currentTime);
// Uncomment to get different packet loss patterns from run to run
// (and a different sender sessionId)
srand(currentTime.tv_sec); // seed random number generator
// 3) Set transmission rate
NormSetTransmitRate(session, 256.0e+03); // in bits/second
// Uncomment to use a _specific_ transmit port number
// (Can be the same as session port (rx port), but this
// is _not_ recommended when unicast feedback may be
// possible! - must be called _before_ NormStartSender())
//NormSetTxPort(session, 6001);
// Uncomment to enable TCP-friendly congestion control
//NormSetCongestionControl(session, true);
// 4) Start the sender using a random "sessionId"
NormSessionId sessionId = (NormSessionId)rand();
NormStartSender(session, sessionId, 1024*1024, 1400, 64, 16);
// Uncomment to set large tx socket buffer size
// (might be needed for high rate sessions)
//NormSetTxSocketBuffer(session, 512000);
// 5) Enqueue the file for transmission
// (We use the file _name_ for NORM_INFO)
//
NormObjectHandle txFile =
NormFileEnqueue(session, filePath,
fileName, strlen(fileName));
// 6) Enter NORM event loop
bool keepGoing = true;
NormEvent theEvent;
while (keepGoing && NormGetNextEvent(instance, &theEvent))
{
switch (theEvent.type)
{
case NORM_TX_QUEUE_VACANCY:
fprintf(stderr, "normFileSend: NORM_TX_QUEUE_VACANCY event...\n");
break;
case NORM_TX_QUEUE_EMPTY:
fprintf(stderr, "normFileSend: NORM_TX_QUEUE_EMPTY event...\n");
break;
case NORM_TX_OBJECT_PURGED:
fprintf(stderr, "normFileSend: NORM_TX_OBJECT_PURGED event ...\n");
break;
case NORM_TX_FLUSH_COMPLETED:
fprintf(stderr, "normFileSend: NORM_TX_FLUSH_COMPLETED event ...\n");
keepGoing = false; // our file has been sent (we think)
break;
default:
TRACE("normFileSend: Got event type: %d\n", theEvent.type);
} // end switch(theEvent.type)
} // end while (NormGetNextEvent())
NormStopSender(session);
NormDestroySession(session);
NormDestroyInstance(instance);
fprintf(stderr, "normFileSend: Done.\n");
return 0;
} // end main()

Binary file not shown.

Binary file not shown.