pull/2/head
Jeff Weston 2019-09-11 11:53:09 -04:00
parent de8a3c799b
commit 602326e415
16 changed files with 886 additions and 394 deletions

View File

@ -6,7 +6,7 @@
<META NAME="GENERATOR" CONTENT="NeoOffice/J 1.1 (Unix)">
<META NAME="AUTHOR" CONTENT="Robert Adamson">
<META NAME="CREATED" CONTENT="20040824;14180000">
<META NAME="CHANGED" CONTENT="20050907;17092400">
<META NAME="CHANGED" CONTENT="20050919;14362900">
<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>
@ -51,22 +51,24 @@
</TD>
<TD WIDTH=371>
<P ALIGN=LEFT STYLE="margin-left: 0.86in; margin-top: 0.17in; font-style: normal">
<FONT FACE="Helvetica, sans-serif"><FONT SIZE=6 STYLE="font-size: 28pt"><B>NORM<BR>Developers
<BR>Guide</B></FONT></FONT></P>
<FONT FACE="Helvetica, sans-serif"><FONT SIZE=4 STYLE="font-size: 16pt"><B><FONT SIZE=6 STYLE="font-size: 28pt">NORM<BR>Developers
<BR>Guide<BR></FONT><FONT SIZE=4>(version 1.3b6)</FONT></B></FONT></FONT></P>
</TD>
</TR>
</TABLE>
<H1 CLASS="western">Background</H1>
<H1 CLASS="western"><A NAME="Background">Background</A></H1>
<P CLASS="western" STYLE="font-style: normal">This document describes
an application programming interface (API) for the Nack-Oriented
Reliable Multicast (NORM) protocol implementation developed by the
United States Naval Research Laboratory (NRL). The NORM protocol
provides general purpose reliable data transport for applications
wishing to use Internet Protocol (IP) Multicast services for group
data delivery. NORM can also support unicast (point-to-point) data
an application programming interface (API) for the <FONT COLOR="#0000ff"><U><A HREF="http://norm.pf.itd.nrl.navy.mil/">Nack-Oriented
Reliable Multicast (NORM)</A></U></FONT> protocol implementation
developed by the United States <FONT COLOR="#0000ff"><U><A HREF="http://www.nrl.navy.mil/">Naval
Research Laboratory</A></U></FONT> (NRL). The NORM protocol provides
general purpose reliable data transport for applications wishing to
use Internet Protocol (IP) Multicast services for group data
delivery. NORM can also support unicast (point-to-point) data
communication and may be used for such when deemed appropriate. The
current NORM protocol specification is given in the Internet
Engineering Task Force RFC 3940.</P>
current NORM protocol specification is given in the <FONT COLOR="#0000ff"><U><A HREF="http://www.ietf.org/">Internet
Engineering Task Force</A></U></FONT> (IETF) <FONT COLOR="#0000ff"><U><A HREF="http://norm.pf.itd.nrl.navy.mil/rfc3940.pdf">RFC
3940</A></U></FONT>.</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
@ -96,32 +98,24 @@ 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>
<H1 CLASS="western" ALIGN=CENTER STYLE="page-break-before: always"><A NAME="Table
of Contents">Table
of Contents</A></H1>
<DIV ID="Table of Contents1" DIR="LTR">
<P STYLE="margin-top: 0.25in; font-style: normal"><FONT FACE="Helvetica, sans-serif"><B>Overview</B></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>API
Initialization</B></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-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>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2>NORM
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-top: 0.25in; font-style: normal"><BR>
</P>
<P STYLE="margin-top: 0.25in; font-style: normal"><FONT FACE="Helvetica, sans-serif"><B><A HREF="#Overview">Overview</A></B></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B><A HREF="#API Initialization">API Initialization</A></B></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B><A HREF="#Session Creation and Control">Session Creation and Control</A></B></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B><A HREF="#Data Transport">Data Transport</A></B></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#Data Transmission">Data Transmission</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#Data Reception">Data Reception</A></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B><A HREF="#API Event Notification">API Event Notification</A></B></FONT></P>
<P STYLE="margin-top: 0.25in; font-style: normal"><FONT FACE="Helvetica, sans-serif"><B><A HREF="#Build Notes">Build Notes</A></B></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B><A HREF="#Unix Platforms">Unix Platforms</A></B></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B><A HREF="#Win32/WiNCE Platforms">Win32/WiNCE Platforms</A></B></FONT></P>
<P STYLE="margin-top: 0.25in; font-style: normal"><FONT FACE="Helvetica, sans-serif"><B><A HREF="#API Reference">API Reference</A></B></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B><A HREF="#API Variable Types and Constants">API Variable Types and Constants</A></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="#NormSessionId">NormSessionId</A></FONT></P>
@ -138,15 +132,14 @@ of Contents</H1>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormProbingMode">NormProbingMode</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNackingMode">NormNackingMode</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormRepairBoundary">NormRepairBoundary</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="#NormAckingStatus">NormAckingStatus</A></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B><A HREF="#API Initialization and Operation">API Initialization and Operation</A></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-top: 0.17in; font-style: normal"><FONT SIZE=2><B>Session
Creation and Control</B></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B><A HREF="#Session Creation and Control Functions">Session Creation and Control Functions</A></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>
@ -158,8 +151,7 @@ of Contents</H1>
<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-top: 0.17in; font-style: normal"><FONT SIZE=2><B><A HREF="#NORM Sender Functions">NORM Sender Functions</A></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>
@ -172,8 +164,6 @@ of Contents</H1>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetGrttMax()">NormSetGrttMax()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetGrttProbingMode()">NormSetGrttProbingMode()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetGrttProbingInterval()">NormSetGrttProbingInterval()</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>
@ -185,8 +175,10 @@ of Contents</H1>
<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="#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="#NormGetAckingStatus()">NormGetAckingStatus()</A></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B><A HREF="#NORM Receiver Functions">NORM Receiver Functions</A></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>
@ -201,8 +193,7 @@ of Contents</H1>
<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-top: 0.17in; font-style: normal"><FONT SIZE=2><B><A HREF="#NORM Object Functions">NORM Object Functions</A></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>
@ -217,14 +208,13 @@ of Contents</H1>
<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-top: 0.17in; font-style: normal"><FONT SIZE=2><B><A HREF="#NORM Node Functions">NORM Node Functions</A></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>
</DIV>
<H1 CLASS="western" STYLE="page-break-before: always">Overview</H1>
<H1 CLASS="western" STYLE="page-break-before: always"><A NAME="Overview">Overview</A></H1>
<P CLASS="western" STYLE="font-style: normal">The NORM API has been
designed to provide simple, straightforward access to and control of
NORM protocol state and functions. Functions are provided to create
@ -244,15 +234,14 @@ protocol thread notifies the application of various protocol events
through a thread-safe event dispatching mechanism and API calls are
provided to allow the application to control NORM operation. (<I>Note:
API mechanisms for lower-level, non-threaded control and execution
of the NORM protocol engine will also be provided in the future</I>.)</P>
of the NORM protocol engine may also be provided in the future</I>.)</P>
<P CLASS="western" STYLE="font-style: normal">The NORM API operation
can be roughly summarized with the following categories of functions:</P>
<OL>
<LI><P CLASS="western" STYLE="font-style: normal">API Initialization</P>
<LI><P CLASS="western" STYLE="font-style: normal">Session Creation
and Control</P>
<LI><P CLASS="western" STYLE="font-style: normal">Data Transport</P>
<LI><P CLASS="western" STYLE="font-style: normal">Event Notification</P>
<LI><P CLASS="western" STYLE="font-style: normal"><A HREF="#API Initialization">API Initialization</A></P>
<LI><P CLASS="western" STYLE="font-style: normal"><A HREF="#Session Creation and Control">Session Creation and Control</A></P>
<LI><P CLASS="western" STYLE="font-style: normal"><A HREF="#Data Transport">Data Transport</A></P>
<LI><P CLASS="western" STYLE="font-style: normal"><A HREF="#API Event Notification">API Event Notification</A></P>
</OL>
<P CLASS="western" STYLE="font-style: normal">Note the order of these
categories roughly reflects the order of function calls required to
@ -269,23 +258,37 @@ application of significant sender and receiver events. There are
also a number support functions provided for the application to
control and monitor its participation within a NORM transport
session.</P>
<H2 CLASS="western">API Initialization</H2>
<H2 CLASS="western"><A NAME="API Initialization">API Initialization</A></H2>
<P CLASS="western" STYLE="font-style: normal">The NORM API requires
that an application explicitly create at least one instance of the
NORM protocol engine which is subsequently used as a conduit for
further NORM API calls. By default, the NORM protocol engine runs in
its own operating system thread and interacts with the application in
a thread-safe manner through the API calls and event dispatching
mechanism. In general, only the thread creating the NORM API
instance should invoke API calls referencing that instance or any
sessions or state created within that instance (<I>NOTE: This
limitation may change in the future. The current implementation is
theoretically safe for concurrent access, but this has not been fully
tested</I>). Multiple API instances may be created as needed for
applications with specific requirements for accessing and controlling
participation in multiple NORM sessions from operating system
multiple threads.</P>
<H2 CLASS="western">Session Creation and Control</H2>
mechanism.
</P>
<P CLASS="western" STYLE="font-style: normal">In general, only a
single thread should access the <FONT FACE="Courier"><A HREF="#NormGetNextEvent()">NormGetNextEvent()</A></FONT>
API call for a given <FONT FACE="Courier">NormInstance</FONT>. This
function serves as the conduit for delivering NORM protocol engine
events to the application. While a NORM application can be designed
to be single-threaded, even with multiple active <I>NormSessions</I>,
multiple API instances can be created (see <FONT FACE="Courier"><A HREF="#NormCreateInstance()">NormCreateInstance()</A></FONT>)
as needed for applications with specific requirements for accessing
and controlling participation in multiple <I>NormSessions</I> from
separate operating system multiple threads. Or, alternatively, a
single <FONT FACE="Courier">NormInstance</FONT> could be used, with a
&quot;master thread&quot; serving as an intermediary between the
<FONT FACE="Courier"><A HREF="#NormGetNextEvent()">NormGetNextEvent()</A></FONT> function,
demultiiplexing and dispatching events as appropriate to other &quot;child
threads&quot; that are created to handle &quot;per-<I>NormSession</I>&quot;
input/output. The advantage of this alternative approach is that the
end result would be one NORM protocol engine thread plus one &quot;master
thread&quot; plus one &quot;child thread&quot; per <I>NormSession</I>
instead of two threads (protocol engine plus application thread) per
<I>NormSession</I> if such multi-threaded operation is needed by the
application.</P>
<H2 CLASS="western"><A NAME="Session Creation and Control">Session Creation and Control</A></H2>
<P CLASS="western" STYLE="font-style: normal">Once an API instance
has been successfully created, the application may then create NORM
transport session instances as needed. The application can
@ -310,7 +313,7 @@ limit the number of active senders monitored and/or provide the
application with finer control over receive buffer allocation,
perhaps on a per sender basis</I>).
</P>
<H2 CLASS="western">NORM Data Transport</H2>
<H2 CLASS="western"><A NAME="Data Transport">Data Transport</A></H2>
<P CLASS="western" STYLE="font-style: normal">The NORM protocol
supports transport of three basic types of data content. These
include the types <FONT FACE="Courier"><I>NORM_OBJECT_FILE</I></FONT>
@ -333,7 +336,7 @@ application-defined message-oriented transport where receivers can
recover message boundaries without any “handshake” with the
sender. Stream content is buffered by the NORM implementation for
transmission/retransmission and as it is received.</P>
<H3 CLASS="western">NORM Data Transmission</H3>
<H3 CLASS="western"><A NAME="Data Transmission">Data Transmission</A></H3>
<P CLASS="western" STYLE="font-style: normal">The behavior of data
transport operation is largely placed in the control of the NORM
sender(s). NORM senders controls their data transmission rate,
@ -375,7 +378,59 @@ node list&quot;) and set &quot;watermark&quot; points for which
positive acknowledgement is collected. This process can provide the
application with explicit flow control for an application-determined
critical set of receivers in the group.</P>
<H3 CLASS="western">NORM Data Reception</H3>
<P CLASS="western" STYLE="font-style: normal">For a NORM application
to perform data transmission, it must first create a session using
<FONT FACE="Courier"><A HREF="#NormCreateSession()">NormCreateSession()</A></FONT> and make a call to
<FONT FACE="Courier"><A HREF="#NormStartSender()">NormStartSender()</A></FONT> before sending actual
user data. The functions <FONT FACE="Courier">NormEnqueueFile()</FONT>,
<FONT FACE="Courier">NormEnqueueData()</FONT>, and <FONT FACE="Courier"><A HREF="#NormStreamWrite()">NormStreamWrite()</A></FONT>
are available for the application to pass data to the NORM protocol
engine for transmission. Note that to use <FONT FACE="Courier"><A HREF="#NormStreamWrite()">NormStreamWrite()</A></FONT>,
a &quot;sender stream&quot; must first be created using
<FONT FACE="Courier"><A HREF="#NormStreamOpen()">NormStreamOpen()</A></FONT>.
</P>
<P CLASS="western" STYLE="font-style: normal">The calls to enqueue
transport objects or write to a stream may be called at any time, but
the <FONT FACE="Courier"><I>NORM_TX_QUEUE_EMPTY</I></FONT> and
<FONT FACE="Courier"><I>NORM_TX_QUEUE_VACANCY</I></FONT> notification
events (see <FONT FACE="Courier"><A HREF="#NormGetNextEvent()">NormGetNextEvent()</A></FONT>) provide
useful cues for when these functions may be successfully called.
Typically, an application might catch both <FONT FACE="Courier"><I>NORM_TX_QUEUE_EMPTY</I></FONT>
and <FONT FACE="Courier"><I>NORM_TX_QUEUE_VACANCY</I></FONT> event
types as cues for enqueuing additional transport objects or writing
to a stream. However, an application may choose to cue off of
<FONT FACE="Courier"><I>NORM_TX_QUEUE_EMPTY</I></FONT> only if it
wishes to provide the &quot;freshest&quot; data to NORM for
transmission. The advantage of additionally using
<FONT FACE="Courier"><I>NORM_TX_QUEUE_VACANCY</I></FONT> is that if
the application uses this cue to fill up NORM transport object or
stream buffers, it can keep the NORM stream busy sending data and
realize the highest possible transmission rate when attempting very
high speed communication (Otherwise, the NORM protocol engine may
experience some &quot;dead air time&quot; waiting for the application
thread to respond to a <FONT FACE="Courier"><I>NORM_TX_QUEUE_EMPTY</I></FONT>
event). Note the sender application can control buffer depths as
needed with the <A HREF="#NormSetTransmitCacheBounds()">NormSetTransmitCacheBounds()</A> and <A HREF="#NormStreamOpen()">NormStreamOpen()</A>
calls.</P>
<P CLASS="western" STYLE="font-style: normal">Another cue that can be
leveraged by the sender application to determine when it is
appropriate to enqueue (or write) additional data for transmission is
the <FONT FACE="Courier"><I>NORM_TX_WATERMARK_COMPLETED</I></FONT>
event. This event is posted when the flushing or explicit positive
acknowledgment collection process has completed for a &quot;watermark&quot;
point in transmission that was set by the sender (see
<FONT FACE="Courier"><A HREF="#NormSetWatermark()">NormSetWatermark()</A></FONT> and
<FONT FACE="Courier"><A HREF="#NormAddAckingNode()">NormAddAckingNode()</A></FONT>). A list of
<FONT FACE="Courier">NormNodeIds</FONT> can be supplied from which
explicit acknowledgement is expected and/or the <FONT FACE="Courier"><A HREF="#NormNodeId">NormNodeId</A></FONT>
NORM_NODE_NONE can be set (using <FONT FACE="Courier"><A HREF="#NormAddAckingNode()">NormAddAckingNode()</A></FONT>)
for completion of a NACK-based version of the watermark flushing
procedure. This flushing process can be used as a flow control
mechanism for NORM applications. Note this is distinct from NORM's
congestion control mechanism that, while it provides network-friendly
transmission rate control, does guarantee flow control to receiving
nodes.</P>
<H3 CLASS="western"><A NAME="Data Reception">Data Reception</A></H3>
<P CLASS="western" STYLE="font-style: normal">NORM receiver
applications learn of active senders and their corresponding pending
and completed data transfers, etc via the API event dispatching
@ -384,8 +439,12 @@ repair of transmitted content from the originating sender as needed
to achieve reliable transfer. Some API functions are available to
provide some additional control over the NACKing behavior, such as
initially NACKing for NORM_INFO content only or even to the extent of
disabling receiver feedback (silent receiver operation) entirely.</P>
<H2 CLASS="western">API Event Notification</H2>
disabling receiver feedback (silent receiver or emission-controlled
(EMCON) operation) entirely. Otherwise, the parameters and operation
of reliable data transmission are left to sender applications and
receivers learn of sender parameters in NORM protocol message headers
and are instructed by NORM_CMD messages from the sender(s).</P>
<H2 CLASS="western"><A NAME="API Event Notification">API Event Notification</A></H2>
<P CLASS="western" STYLE="font-style: normal">An asynchronous event
dispatching mechanism is provided to notify the application of
significant NORM protocol events. The centerpiece of this is the
@ -402,7 +461,7 @@ be signaled when a <FONT FACE="Courier"><A HREF="#NormEvent">NormEvent</A></FON
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>
<H1 CLASS="western"><A NAME="Build Notes">Build Notes</A></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
@ -410,22 +469,23 @@ 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>
for Unix and &quot;Protokit.lib&quot; for Win32). Shared or
dynamically-linked versions of these libraries may also be built from
the NORM source code or provided. 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"><A NAME="Unix Platforms">Unix Platforms</A></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>
operation, the NORM and the <I>Protokit</I> library must be compiled
with the &quot;HAVE_IPV6&quot; macro defined. This is default in the
NORM and <I>Protokit</I> Makefiles for platforms that support IPv6.
It is important that NORM and <I>Protokit</I> 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
@ -444,7 +504,7 @@ the compilation to enable &quot;large file support&quot;.
Applications built using NORM should have the same compilation option
set to operate correctly (The definition of the <FONT FACE="Courier"><A HREF="#NormSize">NormSize</A></FONT>
type in &quot;normApi.h&quot; depends upon this compilation flag).</P>
<H2 CLASS="western">Win32/WiNCE Platforms</H2>
<H2 CLASS="western"><A NAME="Win32/WiNCE Platforms">Win32/WiNCE Platforms</A></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.,
@ -463,14 +523,24 @@ 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
4.x compilers) prevent compilation of <I>Protokit</I>-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">Operation on Windows
NT4 (and perhaps other older Windows operating systems) requires that
the compile time macro <FONT FACE="Courier"><I>WINVER=0x0400</I></FONT>
defined. This is because the version of the IP Helper API library
(<I>iphlpapi.lib</I>) used y Protolib (and hence NORM) for this
system doesn't support some of the functions defined for this
library. This may be related to IPv6 support issues so it may be
possible that the Protolib build could be tweaked to provide a single
binary executable suitable for IPv4 operation only across a large
range of Windows platforms.</P>
<H1 CLASS="western"><A NAME="API Reference">API Reference</A></H1>
<P CLASS="western" STYLE="font-style: normal">This section provides a
reference to the NORM API variable types, constants and functions.</P>
<H2 CLASS="western">API Variable Types and Constants</H2>
<H2 CLASS="western"><A NAME="API Variable Types and Constants">API Variable Types and Constants</A></H2>
<P CLASS="western" STYLE="font-style: normal">The NORM API defines
and enumerates a number of supporting variable types and values which
are used in different function calls. The variable types are
@ -648,7 +718,7 @@ these values is given in the description of <FONT FACE="Courier"><A HREF="#Norm
function.</P>
<H3 CLASS="functionheading-western"><A NAME="NormNackingMode">NormNackingMode</A></H3>
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormNackingMode">NormNackingMode</A></FONT>
consist of the following enumeration:</P>
type consists of the following enumeration:</P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>enum
<A HREF="#NormNackingMode">NormNackingMode</A><BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_NACK_NONE,<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_NACK_INFO_ONLY,<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_NACK_NORMAL<BR>};</FONT></FONT></P>
<P CLASS="western" STYLE="font-style: normal">The interpretation of
@ -658,14 +728,22 @@ these values is given in the descriptions of the
<FONT FACE="Courier"><A HREF="#NormObjectSetNackingMode()">NormObjectSetNackingMode()</A></FONT> functions.</P>
<H3 CLASS="functionheading-western"><A NAME="NormRepairBoundary">NormRepairBoundary</A></H3>
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormRepairBoundary">NormRepairBoundary</A></FONT>
consist of the following enumeration:</P>
types consists of the following enumeration:</P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>enum
<A HREF="#NormRepairBoundary">NormRepairBoundary</A><BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_BOUNDARY_BLOCK,<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_BOUNDARY_OBJECT<BR>};</FONT></FONT></P>
<P CLASS="western" STYLE="font-style: normal">The interpretation of
these values is given in the descriptions of the
<FONT FACE="Courier"><A HREF="#NormSetDefaultRepairBoundary()">NormSetDefaultRepairBoundary()</A> </FONT>and
<FONT FACE="Courier"><A HREF="#NormNodeSetRepairBoundary()">NormNodeSetRepairBoundary()</A></FONT> functions.</P>
<H2 CLASS="western">API Initialization and Operation</H2>
<H3 CLASS="functionheading-western"><A NAME="NormAckingStatus">NormAckingStatus</A></H3>
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormAckingStatus">NormAckingStatus</A></FONT>
consist of the following enumeration:</P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>enum
<A HREF="#NormAckingStatus">NormAckingStatus</A><BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_ACK_INVALID,<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_ACK_FAILURE,<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_ACK_PENDING,<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_ACK_SUCCESS<BR>};</FONT></FONT></P>
<P CLASS="western" STYLE="font-style: normal">The interpretation of
these values is given in the descriptions of the
<FONT FACE="Courier"><A HREF="#NormGetAckingStatus()">NormGetAckingStatus()</A></FONT> function.</P>
<H2 CLASS="western"><A NAME="API Initialization and Operation">API Initialization and Operation</A></H2>
<P CLASS="western" STYLE="font-style: normal">The first step in using
the NORM API is to create an &quot;instance&quot; of the NORM
protocol engine. Note that multiple instances may be created by the
@ -804,8 +882,12 @@ function call.</P>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
This event indicates that there is room for additional transmit
objects to be enqueued, or, if the handle of <FONT FACE="Courier"><I>NORM_OBJECT_STREAM</I></FONT>
is given in the event &quot;object&quot; field, the application
may successfully write to the indicated stream object.</P>
is given in the corresponding event &quot;object&quot; field, the
application may successfully write to the indicated stream object.
Note this event is not dispatched until a call to
<FONT FACE="Courier">NormEnqueueFile()</FONT>, <FONT FACE="Courier">NormEnqueueData()</FONT>,
or <FONT FACE="Courier"><A HREF="#NormStreamWrite()">NormStreamWrite()</A></FONT> fails because of
a filled transmit cache or stream buffer.</P>
</TD>
</TR>
<TR VALIGN=TOP>
@ -817,7 +899,14 @@ function call.</P>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
This event indicates the NORM protocol engine has no new data
pending transmission and the application may enqueue additional
objects for transmission.</P>
objects for transmission. If the handle of a sender
<FONT FACE="Courier"><I>NORM_OBJECT_STREAM</I></FONT> is given in
the corresponding event &quot;object&quot; field, this indicates
the stream transmit buffer has been emptied and the sender
application may write to the stream (Use of <FONT FACE="Courier"><I>NORM_TX_QUEUE_VACANCY</I></FONT>
may be preferred for this purpose since it allows the application
to keep the NORM protocol engine busier sending data, resulting in
higher throughput when attempting very high transfer rates).</P>
</TD>
</TR>
<TR VALIGN=TOP>
@ -840,6 +929,20 @@ function call.</P>
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">
<FONT FACE="Courier"><I>NORM_TX_WATERMARK_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 initiated by a
prior application call to <FONT FACE="Courier"><A HREF="#NormSetWatermark()">NormSetWatermark()</A></FONT>
has completed The posting of this event indicates the appropriate
time for the application to make a call <FONT FACE="Courier"><A HREF="#NormGetAckingStatus()">NormGetAckingStatus()</A></FONT>
to determine the results of the watermark flushing process.</P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=269>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
@ -1068,7 +1171,7 @@ descriptor.</P>
returned which is valid until a call to <FONT FACE="Courier"><A HREF="#NormDestroyInstance()">NormDestroyInstance()</A></FONT>
is made. Upon error, a value of <I><FONT FACE="Courier">NORM_DESCRIPTOR_INVALID</FONT></I>
is returned.</P>
<H2 CLASS="western">Session Creation and Control</H2>
<H2 CLASS="western"><A NAME="Session Creation and Control Functions">Session Creation and Control Functions</A></H2>
<H3 CLASS="functionheading-western"><A NAME="NormCreateSession()">NormCreateSession()</A></H3>
<H4 CLASS="western">Synopsis</H4>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>#include
@ -1428,8 +1531,7 @@ created.</P>
<H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">This function has no
return values.</P>
<H2 CLASS="western">NORM<SPAN STYLE="font-style: normal"> </SPAN>Sender
Functions</H2>
<H2 CLASS="western"><A NAME="NORM Sender Functions">NORM Sender Functions</A></H2>
<H3 CLASS="functionheading-western"><A NAME="NormStartSender()">NormStartSender()</A></H3>
<H4 CLASS="western">Synopsis</H4>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>#include
@ -1925,7 +2027,7 @@ return values.</P>
&lt;normApi.h&gt;</FONT></FONT></P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void
NormSetGrttProbingMode(<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NormProbingMode&nbsp;&nbsp;&nbsp;probingMode);</FONT></FONT></P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A HREF="#NormProbingMode">NormProbingMode</A>&nbsp;&nbsp;&nbsp;probingMode);</FONT></FONT></P>
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function sets the
sender's mode of probing for round trip timing measurement responses
@ -2010,44 +2112,6 @@ values are 1.0 second and 30.0 seconds, respectively.</P>
<H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">This function has no
return values.</P>
<H3 CLASS="functionheading-western"><A NAME="NormAddAckingNode()">NormAddAckingNode()</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>bool
NormAddAckingNode(<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;&nbsp;&nbsp;<A HREF="#NormNodeId">NormNodeId</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nodeId);</FONT></FONT></P>
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">When this function is
called, the specified <FONT FACE="Courier"><U>nodeId</U></FONT> is
added to the list of <I>NormNodes</I> used when NORM sender operation
performs positive acknowledgement (ACK) collection for the specified
<FONT FACE="Courier"><U>session</U></FONT>. The optional NORM
positive acknowledgement collection occurs when a specified
transmission point (see <FONT FACE="Courier"><A HREF="#NormSetWatermark()">NormSetWatermark()</A>)</FONT>
is reached or for specialized protocol actions such as
positively-acknowledged application-defined commands (<I>TBD</I>).</P>
<H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">The function returns
<FONT FACE="Courier"><I>true</I></FONT> upon success and <FONT FACE="Courier"><I>false</I></FONT>
upon failure. The only failure condition is that insufficient memory
resources were available. If a specific <FONT FACE="Courier"><U>nodeId</U></FONT>
is added more than once, this has no effect.</P>
<H3 CLASS="functionheading-western"><A NAME="NormRemoveAckingNode()">NormRemoveAckingNode()</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>void
NormRemoveAckingNode(<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A HREF="#NormNodeId">NormNodeId</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nodeId);</FONT></FONT></P>
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function deletes
the specified <FONT FACE="Courier"><U>nodeId</U></FONT> from the list
of <I>NormNodes</I> used when NORM sender operation performs positive
acknowledgement (ACK) collection for the specified <FONT FACE="Courier"><U>session</U></FONT>.
</P>
<H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">The function has no
return values.</P>
<H3 CLASS="functionheading-western"><A NAME="NormFileEnqueue()">NormFileEnqueue()</A></H3>
<H4 CLASS="western">Synopsis</H4>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>#include
@ -2330,10 +2394,21 @@ reliability does not provide explicit flow control, there is some
degree of implicit flow control in limiting writing new data to the
stream against pending repairs.
</P>
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormEvent">NormEvent</A></FONT>
NORM_TX_QUEUE_VACANCY is posted with its <I><A HREF="#NormEvent">NormEvent</A>::object</I>
field set to a valid sender stream <FONT FACE="Courier"><A HREF="#NormObjectHandle">NormObjectHandle</A></FONT>
to indicate when the stream is ready for writing via this function.
Note that, after this event type is posted, the application <I>must</I>
make a call to <FONT FACE="Courier"><A HREF="#NormStreamWrite()">NormStreamWrite()</A></FONT> with a
non-zero <FONT FACE="Courier"><U>numBytes</U></FONT> value before
addition NORM_TX_QUEUE_VACANCY events are posted for the given
<FONT FACE="Courier"><U>streamHandle</U></FONT>.</P>
<H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">This function returns
the number of bytes of data successfully enqueued for NORM stream
transmission.</P>
transmission. If the underlying send stream buffer is full, this
function may return zero.
</P>
<H3 CLASS="functionheading-western"><A NAME="NormStreamFlush()">NormStreamFlush()</A></H3>
<H4 CLASS="western">Synopsis</H4>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>#include
@ -2548,53 +2623,218 @@ NormSetWatermark(<A HREF="#NormSessionHandle">NormSessionHandle</A>&nbsp;session
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function specifies
a &quot;watermark&quot; transmission point at which NORM sender
protocol operation should perform positive acknowledgment collection
for a given <FONT FACE="Courier"><U>session</U></FONT>. For
<FONT FACE="Courier"><I>NORM_OBJECT_FILE</I></FONT> and
protocol operation should perform a flushing process and/or positive
acknowledgment collection for a given <FONT FACE="Courier"><U>session</U></FONT>.
For <FONT FACE="Courier"><I>NORM_OBJECT_FILE</I></FONT> and
<FONT FACE="Courier"><I>NORM_OBJECT_DATA</I></FONT> transmissions,
the positive acknowledgement collection will begin when the specified
<FONT FACE="Courier"><U>object</U></FONT> has been completely
transmitted. The object parameter must be a valid handle to a
previously-created sender object (see <FONT SIZE=2><FONT FACE="Courier">NormEnqueueFile(),</FONT></FONT>
<FONT SIZE=2><FONT FACE="Courier">NormEnqueueData()</FONT></FONT>, or
<FONT SIZE=2><FONT FACE="Courier"><A HREF="#NormStreamOpen()">NormStreamOpen()</A></FONT></FONT>).
For <FONT FACE="Courier"><I>NORM_OBJECT_STREAM</I></FONT>
previously-created sender object (see <FONT FACE="Courier">NormEnqueueFile()</FONT><FONT SIZE=2><FONT FACE="Courier">,</FONT></FONT>
<FONT FACE="Courier">NormEnqueueData()</FONT>, or <FONT FACE="Courier"><A HREF="#NormStreamOpen()">NormStreamOpen()</A></FONT>).
For <FONT FACE="Courier"><I>NORM_OBJECT_STREAM</I></FONT>
transmission, the positive acknowledgment collection begins
immediately, using the current position (last data written) of the
sender stream as a reference.
immediately, using the current position (offset of most recent data
written) of the sender stream as a reference.
</P>
<P CLASS="western" STYLE="font-style: normal">As the acknowledgment
collection proceeds, <FONT FACE="Courier"><I>NORM_ACK_FAILED</I></FONT>
events will be posted for individual receiver <I>NormNodes</I> which
fail to acknowledge the request. The <FONT FACE="Courier"><A HREF="#NormEvent">NormEvent</A>::node</FONT>
field contains a <FONT FACE="Courier"><A HREF="#NormNodeHandle">NormNodeHandle</A></FONT> for the
failed node and <FONT FACE="Courier"><A HREF="#NormNodeGetId()">NormNodeGetId()</A></FONT> can be
used to retrieve the failing node's <FONT FACE="Courier"><A HREF="#NormNodeId">NormNodeId</A></FONT>.
When the sender acknowledgment collection process has completed, the
<FONT FACE="Courier"><I>NORM_ACK_COMPLETE</I></FONT> event is posted
and the application may assume that the remaining nodes (those for
which there was no <FONT FACE="Courier"><I>NORM_ACK_FAILED</I></FONT>
event) successfully acknowledged the request.</P>
<P CLASS="western" STYLE="font-style: normal">If a subsequent call is
made to <FONT FACE="Courier"><A HREF="#NormSetWatermark()">NormSetWatermark()</A></FONT> before the
prior acknowledgement request has completed, the pending
acknowledgment request is canceled and new one may begin.</P>
<P CLASS="western" STYLE="font-style: normal">Note that the sender
may still enqueue <I>NormObjects</I> for transmission (or write to
the existing stream) and the positive acknowledgement collection will
be multiplexed with the ongoing data transmission. However, the
sender application may wish to defer sending more data until a
<FONT FACE="Courier"><I>NORM_ACK_COMPLETE</I></FONT> event is
received for the <FONT FACE="Courier"><U>session</U></FONT>. This
provides a form of explicit sender-&gt;receiver(s) flow control (with
respect to the current list of &quot;acking&quot; receivers) which
does not exist in NORM's default NACK-only operation.</P>
<P CLASS="western" STYLE="font-style: normal">The functions
<FONT FACE="Courier"><A HREF="#NormAddAckingNode()">NormAddAckingNode()</A></FONT> and
<FONT FACE="Courier"><A HREF="#NormRemoveAckingNode()">NormRemoveAckingNode()</A></FONT> are used to manage
the list of <FONT FACE="Courier"><A HREF="#NormNodeId">NormNodeId</A></FONT> values
corresponding to NORM receivers that are expected to explicitly
acknowledge the watermark flushing messages transmitted by the
sender. Note that the <FONT FACE="Courier"><A HREF="#NormNodeId">NormNodeId</A></FONT>
<FONT FACE="Courier"><I>NORM_NODE_NONE</I></FONT> may be included in
the list. Inclusion of <FONT FACE="Courier"><I>NORM_NODE_NONE</I></FONT>
forces the watermark flushing process to proceed through a full
<FONT FACE="Courier"><I>NORM_ROBUST_FACTOR</I></FONT> number of
rounds before completing, prompting any receivers that have not
completed reliable reception to the given watermark point to NACK for
any repair needs. If NACKs occur, the flushing process is reset and
repeated until completing with no NACKs for data through the given
watermark transmission point are received. Thus, even without
explicit positive acknowledgment, the sender can use this process (by
adding <FONT FACE="Courier"><I>NORM_NODE_NONE</I></FONT> to the
<FONT FACE="Courier"><U>session</U></FONT>'s list of acking nodes)
for a high level of assurance that the receiver set is &quot;happy&quot;
(completed reliable data reception) through the given <FONT FACE="Courier"><U>object</U></FONT>
(or stream transmission point).
</P>
<P CLASS="western" STYLE="font-style: normal">The event
<FONT FACE="Courier"><I>NORM_TX_WATERMARK_COMPLETED</I></FONT> is
posted for the given <FONT FACE="Courier"><U>session</U></FONT> when
the flushing process or positive acknowledgment collection has
completed. The process completes as soon as all listed receivers
have responded unless <FONT FACE="Courier"><I>NORM_NODE_NONE</I></FONT>
is included in the acking list. The sender application may use the
function <FONT FACE="Courier"><A HREF="#NormGetAckingStatus()">NormGetAckingStatus()</A></FONT> to
determine the degree of success of the flushing process in general or
for individual <FONT FACE="Courier"><A HREF="#NormNodeId">NormNodeId</A></FONT> values.
</P>
<P CLASS="western" STYLE="font-style: normal">The flushing is
conducted concurrently with ongoing data transmission and does not
impede the progress of reliable data transfer. Thus the sender may
still enqueue <I>NormObjects</I> for transmission (or write to the
existing stream) and the positive acknowledgement collection and
flushing procedure will be multiplexed with the ongoing data
transmission. However, the sender application may wish to defer from
or limit itself in sending more data until a
<FONT FACE="Courier"><I>NORM_TX_WATERMARK_COMPLETED</I></FONT> event
is received for the given <FONT FACE="Courier"><U>session</U></FONT>.
This provides a form of sender-&gt;receiver(s) flow control which
does not exist in NORM's default protocol operation. If a subsequent
call is made to <FONT FACE="Courier"><A HREF="#NormSetWatermark()">NormSetWatermark()</A></FONT> before
the current acknowledgement request has completed, the pending
acknowledgment request is canceled and the new one begins.</P>
<H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">The function returns
<FONT FACE="Courier"><I>true</I></FONT> upon successful establishment
of the watermark point. The function may return <FONT FACE="Courier"><I>false</I></FONT>
upon failure (<I>why would it fail? TBD</I>).</P>
<H2 CLASS="western">NORM Receiver Functions</H2>
<H3 CLASS="functionheading-western"><A NAME="NormAddAckingNode()">NormAddAckingNode()</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>bool
NormAddAckingNode(<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;&nbsp;&nbsp;<A HREF="#NormNodeId">NormNodeId</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nodeId);</FONT></FONT></P>
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">When this function is
called, the specified <FONT FACE="Courier"><U>nodeId</U></FONT> is
added to the list of <I>NormNodes</I> used when NORM sender operation
performs positive acknowledgement (ACK) collection for the specified
<FONT FACE="Courier"><U>session</U></FONT>. The optional NORM
positive acknowledgement collection occurs when a specified
transmission point (see <FONT FACE="Courier"><A HREF="#NormSetWatermark()">NormSetWatermark()</A>)</FONT>
is reached or for specialized protocol actions such as
positively-acknowledged application-defined commands. Additionally a
value of <FONT FACE="Courier"><U>nodeId</U></FONT> equal to
<FONT FACE="Courier"><I>NORM_NODE_NONE</I></FONT> may be set to force
the watermark flushing process through a full <FONT FACE="Courier"><I>NORM_ROBUST_FACTOR</I></FONT>
number of rounds regardless of actual acking nodes. Otherwise the
flushing process is terminated when all of the nodes in the acking
node list have responded.</P>
<H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">The function returns
<FONT FACE="Courier"><I>true</I></FONT> upon success and <FONT FACE="Courier"><I>false</I></FONT>
upon failure. The only failure condition is that insufficient memory
resources were available. If a specific <FONT FACE="Courier"><U>nodeId</U></FONT>
is added more than once, this has no effect.</P>
<H3 CLASS="functionheading-western"><A NAME="NormRemoveAckingNode()">NormRemoveAckingNode()</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>void
NormRemoveAckingNode(<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A HREF="#NormNodeId">NormNodeId</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nodeId);</FONT></FONT></P>
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function deletes
the specified <FONT FACE="Courier"><U>nodeId</U></FONT> from the list
of <I>NormNodes</I> used when NORM sender operation performs positive
acknowledgement (ACK) collection for the specified <FONT FACE="Courier"><U>session</U></FONT>.
Note that if the <FONT FACE="Courier"><U>nodeId</U></FONT>
<FONT FACE="Courier"><I>NORM_NODE_NONE</I></FONT> has been added to
the list, it too must be removed to change the watermark flushing
behavior if desired.</P>
<H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">The function has no
return values.</P>
<H3 CLASS="functionheading-western"><A NAME="NormGetAckingStatus()">NormGetAckingStatus()</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="#NormAckingStatus">NormAckingStatus</A>
NormGetAckingStatus(<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A HREF="#NormNodeId">NormNodeId</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nodeId
=
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NORM_NODE_ANY);</FONT></FONT></P>
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function queries
the status of the watermark flushing process and/or positive
acknowledgment collection initiated by a prior call to
<FONT FACE="Courier"><A HREF="#NormSetWatermark()">NormSetWatermark()</A></FONT> for the given <FONT FACE="Courier"><U>session</U></FONT>.
In general, it is expected that applications will invoke this
function <I>after</I> the corresponding <FONT FACE="Courier"><I>NORM_TX_WATERMARK_COMPLETED</I></FONT>
event has been posted. Setting the default parameter value <FONT FACE="Courier"><U>nodeId</U></FONT>
= <FONT FACE="Courier"><I>NORM_NODE_ANY</I></FONT> returns a &quot;status&quot;
indication for the overall process. Also, individual <FONT FACE="Courier"><U>nodeId</U></FONT>
values may be queried using the <FONT FACE="Courier"><A HREF="#NormNodeId">NormNodeId</A></FONT>
values of receivers that were included in previous calls to
<FONT FACE="Courier"><A HREF="#NormAddAckingNode()">NormAddAckingNode()</A></FONT> to populate the
sender <FONT FACE="Courier"><U>session</U></FONT>'s acking node list.
</P>
<P CLASS="western" STYLE="font-style: normal">If the
flushing/acknowledgment process is being used for application flow
control, the sender application may wish to reset the watermark and
flushing process (using <FONT FACE="Courier"><A HREF="#NormSetWatermark()">NormSetWatermark()</A></FONT>)
if the response indicates that some nodes have failed to respond.
However, note that the flushing/acknowledgment process itself does
elicit NACKs from receivers as needed and is interrupted and reset by
any repair response that occurs. Thus, even by the time the flushing
process has completed (and <FONT FACE="Courier"><I>NORM_TX_WATERMARK_COMPLETED</I></FONT>
is posted) once, this is an indication that the NORM protocol has
made a valiant attempt to deliver the content. Resetting the
watermark process <I>can</I> increase robustness, but it may be in
vain to repeat this process multiple times when likely network
connectivity has been lost or expected receivers have failed (dropped
out, shut down, etc).</P>
<H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal; page-break-after: avoid">
Possible return values include:</P>
<TABLE WIDTH=592 BORDER=1 BORDERCOLOR="#000000" CELLPADDING=8 CELLSPACING=0>
<COL WIDTH=200>
<COL WIDTH=358>
<TR VALIGN=TOP>
<TD WIDTH=200>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid; page-break-after: avoid">
NORM_ACK_INVALID</P>
</TD>
<TD WIDTH=358>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid; page-break-after: avoid">
The given session is invalid or the given <FONT FACE="Courier"><U>nodeId</U></FONT>
is not in the session's acking list.</P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=200>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid; page-break-after: avoid">
NORM_ACK_FAILURE</P>
</TD>
<TD WIDTH=358>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid; page-break-after: avoid">
The positive acknowledgement collection process did not receive
acknowledgment from every listed receiver (<FONT FACE="Courier"><U>nodeId</U></FONT>
= <FONT FACE="Courier"><I>NORM_NODE_ANY</I></FONT>) or the
identified <FONT FACE="Courier"><U>nodeId</U></FONT> did not
respond.</P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=200>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid; page-break-after: avoid">
NORM_ACK_PENDING</P>
</TD>
<TD WIDTH=358>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid; page-break-after: avoid">
The flushing process at large has not yet completed (<FONT FACE="Courier"><U>nodeId</U></FONT>
= <FONT FACE="Courier"><I>NORM_NODE_ANY</I></FONT>) or the given
individual <FONT FACE="Courier"><U>nodeId</U></FONT> is still
being queried for response.</P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=200>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
NORM_ACK_SUCCESS</P>
</TD>
<TD WIDTH=358>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
All receivers (<FONT FACE="Courier"><U>nodeId</U></FONT> =
<FONT FACE="Courier"><I>NORM_NODE_ANY</I></FONT>) responded with
positive acknowledgement or the given specific <FONT FACE="Courier"><U>nodeId</U></FONT>
did acknowledge.</P>
</TD>
</TR>
</TABLE>
<H2 CLASS="western"><A NAME="NORM Receiver Functions">NORM Receiver Functions</A></H2>
<H3 CLASS="functionheading-western"><A NAME="NormStartReceiver()">NormStartReceiver()</A></H3>
<H4 CLASS="western">Synopsis</H4>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>#include
@ -3047,7 +3287,7 @@ associate some application context with stream position.</P>
the current read offset in bytes. The return value is undefined for
sender streams. There is no error result.
</P>
<H2 CLASS="western">NORM Object Functions</H2>
<H2 CLASS="western"><A NAME="NORM Object Functions">NORM Object Functions</A></H2>
<P CLASS="western" STYLE="font-style: normal">The functions described
in this section may be used for sender or receiver purposes to manage
transmission and reception of NORM transport objects. In most cases,
@ -3442,7 +3682,7 @@ valid for the same period that the <FONT FACE="Courier"><U>objectHandle</U></FON
is valid. The returned <FONT FACE="Courier"><A HREF="#NormNodeHandle">NormNodeHandle</A></FONT>
may optionally be retained for further use by the application using
the <FONT FACE="Courier"><A HREF="#NormNodeRetain()">NormNodeRetain()</A></FONT> function call. The
returned value can be used in the NORM Node Functions described later
returned value can be used in the <A HREF="#NORM Node Functions">NORM Node Functions</A> described later
in this document.</P>
<H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">This function returns
@ -3451,7 +3691,7 @@ remote sender of the transport object associated with the given
<FONT FACE="Courier"><U>objectHandle</U></FONT> parameter. A value
of NORM_NODE_INVALID is returned if the specified <FONT FACE="Courier"><U>objectHandle</U></FONT>
references a locally originated, sender object.</P>
<H2 CLASS="western">NORM Node Functions</H2>
<H2 CLASS="western"><A NAME="NORM Node Functions">NORM Node Functions</A></H2>
<P CLASS="western" STYLE="font-style: normal">The functions described
in this section may be used for NORM sender or receiver (most
typically receiver) purposes to retrieve additional information about

Binary file not shown.

View File

@ -1,5 +1,23 @@
NORM Version History
Version 1.3b6
=============
- Fixed some oversite bugs that crept in with changes in 1.3b5
(Fixed code related to NormNode/NormObject retain and release)
- Changed NORM_TX_QUEUE_VACANCY posting behavior to be less chatty.
NORM_TX_QUEUE_VACANCY now posted _only_ after a call to
NormStreamWrite() fails to fulfill a full write request
(i.e. returns less than the "numBytes" requested to be written)
This helps prevent build up of these notifications in multi-
threaded applications that write to a stream in a different
thread than is fetching events via NormGetNextEvent().
- Added NORM_TX_WATERMARK_COMPLETED notification and NormGetAckingStatus()
function to provide API support for optional positive acknowledgment
(ACK) collection in NORM implementation. Note that use of
NormAddAckingNode(session, NORM_NODE_NONE) enables a NACK-based
watermark flushing concurrent with ongoing data transmission that
can be used as a scalable application-level flow control mechanism.
Version 1.3b5
=============
- Changed ProtoSocket::GetInterfaceAddress() and related methods on Win32

View File

@ -46,6 +46,8 @@ class NormInstance : public NormController
void PurgeObjectNotifications(NormObjectHandle objectHandle);
unsigned long CountCompletedObjects(NormSession* theSession);
ProtoDispatcher::Descriptor GetDescriptor() const
{
#ifdef WIN32
@ -57,6 +59,7 @@ class NormInstance : public NormController
static NormInstance* GetInstanceFromSession(NormSessionHandle sessionHandle)
{
if (NORM_SESSION_INVALID == sessionHandle) return ((NormInstance*)NULL);
NormSession* session = (NormSession*)sessionHandle;
NormInstance* theInstance = static_cast<NormInstance*>(session->GetSessionMgr().GetController());
return theInstance;
@ -64,11 +67,13 @@ class NormInstance : public NormController
}
static NormInstance* GetInstanceFromNode(NormNodeHandle nodeHandle)
{
if (NORM_NODE_INVALID == nodeHandle) return ((NormInstance*)NULL);
NormSession& session = ((NormNode*)nodeHandle)->GetSession();
return static_cast<NormInstance*>(session.GetSessionMgr().GetController());
}
static NormInstance* GetInstanceFromObject(NormObjectHandle objectHandle)
{
if (NORM_OBJECT_INVALID == objectHandle) return ((NormInstance*)NULL);
NormSession& session = ((NormObject*)objectHandle)->GetSession();;
return static_cast<NormInstance*>(session.GetSessionMgr().GetController());
}
@ -610,6 +615,21 @@ void NormInstance::Shutdown()
notify_pool.Destroy();
} // end NormInstance::Shutdown()
unsigned long NormInstance::CountCompletedObjects(NormSession* session)
{
unsigned long result = 0UL;
Notification* n = notify_queue.GetHead();
while (NULL != n)
{
if ((session == n->event.session) &&
(NORM_RX_OBJECT_COMPLETED == n->event.type))
{
result ++;
}
n = n->GetNext();
}
return result;
} // end NormInstance::CountCompletedObjects()
//////////////////////////////////////////////////////////////////////////
// NORM API FUNCTION IMPLEMENTATIONS
@ -1024,35 +1044,6 @@ void NormSetGrttProbingInterval(NormSessionHandle sessionHandle,
}
} // end NormSetGrttProbingInterval()
bool NormAddAckingNode(NormSessionHandle sessionHandle,
NormNodeId nodeId)
{
bool result = false;
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
if (instance && instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
if (session)
result = session->ServerAddAckingNode(nodeId);
instance->dispatcher.ResumeThread();
}
return result;
} // end NormAddAckingNode()
void NormRemoveAckingNode(NormSessionHandle sessionHandle,
NormNodeId nodeId)
{
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
if (instance && instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
if (session) session->ServerRemoveAckingNode(nodeId);
instance->dispatcher.ResumeThread();
}
} // end NormRemoveAckingNode()
NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle,
const char* fileName,
const char* infoPtr,
@ -1249,6 +1240,50 @@ bool NormSetWatermark(NormSessionHandle sessionHandle,
return result;
} // end NormSetWatermark()
bool NormAddAckingNode(NormSessionHandle sessionHandle,
NormNodeId nodeId)
{
bool result = false;
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
if (instance && instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
if (session)
result = session->ServerAddAckingNode(nodeId);
instance->dispatcher.ResumeThread();
}
return result;
} // end NormAddAckingNode()
void NormRemoveAckingNode(NormSessionHandle sessionHandle,
NormNodeId nodeId)
{
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
if (instance && instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
if (session) session->ServerRemoveAckingNode(nodeId);
instance->dispatcher.ResumeThread();
}
} // end NormRemoveAckingNode()
NormAckingStatus NormGetAckingStatus(NormSessionHandle sessionHandle,
NormNodeId nodeId)
{
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
if (instance && instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
NormAckingStatus status =
(NormAckingStatus)session->ServerGetAckingStatus(nodeId);
instance->dispatcher.ResumeThread();
return status;
}
else
{
return NORM_ACK_INVALID;
}
} // end NormGetAckingNodeStatus()
/** NORM Receiver Functions */
@ -1260,10 +1295,7 @@ bool NormStartReceiver(NormSessionHandle sessionHandle,
if (instance && instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
if (session)
result = session->StartClient(bufferSpace);
else
result = false;
instance->dispatcher.ResumeThread();
}
return result;
@ -1276,7 +1308,7 @@ void NormStopReceiver(NormSessionHandle sessionHandle)
if (instance && instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
if (session) session->StopClient();
session->StopClient();
instance->dispatcher.ResumeThread();
}
} // end NormStopReceiver()
@ -1364,7 +1396,6 @@ bool NormStreamRead(NormObjectHandle streamHandle,
{
NormStreamObject* stream =
static_cast<NormStreamObject*>((NormObject*)streamHandle);
if (stream)
result = stream->Read(buffer, numBytes);
instance->dispatcher.ResumeThread();
}
@ -1380,7 +1411,6 @@ bool NormStreamSeekMsgStart(NormObjectHandle streamHandle)
NormStreamObject* stream =
static_cast<NormStreamObject*>((NormObject*)streamHandle);
unsigned int numBytes = 0;
if (stream)
result = stream->Read(NULL, &numBytes, true);
instance->dispatcher.ResumeThread();
}
@ -1391,7 +1421,10 @@ bool NormStreamSeekMsgStart(NormObjectHandle streamHandle)
unsigned long NormStreamGetReadOffset(NormObjectHandle streamHandle)
{
NormStreamObject* stream = static_cast<NormStreamObject*>((NormObject*)streamHandle);
if (stream)
return stream->GetCurrentReadOffset();
else
return 0;
} // end NormStreamGetReadOffset()
@ -1641,3 +1674,16 @@ void NormNodeRelease(NormNodeHandle nodeHandle)
// the app to install an event handler callback and dispatch
// events with a "NormDispatchEvents()" call ...
//
unsigned long NormCountCompletedObjects(NormSessionHandle sessionHandle)
{
unsigned long result = 0;
NormSession* session = (NormSession*)sessionHandle;
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
if (instance && instance->dispatcher.SuspendThread())
{
result = instance->CountCompletedObjects(session);
instance->dispatcher.ResumeThread();
}
return result;
} // end long NormCountCompletedObjects()

View File

@ -19,7 +19,7 @@
// C++ code continues to evolve. But, until this notice
// is removed, the API shouldn't be considered final.
// NORM API control
/** NORM API Types */
typedef const void* NormInstanceHandle;
extern const NormInstanceHandle NORM_INSTANCE_INVALID;
@ -66,6 +66,14 @@ enum NormNackingMode
NORM_NACK_NORMAL
};
enum NormAckingStatus
{
NORM_ACK_INVALID,
NORM_ACK_FAILURE,
NORM_ACK_PENDING,
NORM_ACK_SUCCESS
};
enum NormProbingMode
{
NORM_PROBE_NONE,
@ -85,6 +93,7 @@ enum NormEventType
NORM_TX_QUEUE_VACANCY,
NORM_TX_QUEUE_EMPTY,
NORM_TX_FLUSH_COMPLETED,
NORM_TX_WATERMARK_COMPLETED,
NORM_TX_OBJECT_SENT,
NORM_TX_OBJECT_PURGED,
NORM_LOCAL_SERVER_CLOSED,
@ -221,12 +230,6 @@ void NormSetGrttProbingInterval(NormSessionHandle sessionHandle,
double intervalMin,
double intervalMax);
bool NormAddAckingNode(NormSessionHandle sessionHandle,
NormNodeId nodeId);
void NormRemoveAckingNode(NormSessionHandle sessionHandle,
NormNodeId nodeId);
NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle,
const char* fileName,
const char* infoPtr = (const char*)0,
@ -261,13 +264,22 @@ void NormStreamSetPushEnable(NormObjectHandle streamHandle,
bool NormStreamHasVacancy(NormObjectHandle streamHandle);
NormSize NormGetObjectSize(NormObjectHandle objectHandle);
void NormStreamMarkEom(NormObjectHandle streamHandle);
bool NormSetWatermark(NormSessionHandle sessionHandle,
NormObjectHandle objectHandle);
bool NormAddAckingNode(NormSessionHandle sessionHandle,
NormNodeId nodeId);
void NormRemoveAckingNode(NormSessionHandle sessionHandle,
NormNodeId nodeId);
NormAckingStatus NormGetAckingStatus(NormSessionHandle sessionHandle,
NormNodeId nodeId = NORM_NODE_ANY);
/* NORM Receiver Functions */
bool NormStartReceiver(NormSessionHandle sessionHandle,
unsigned long bufferSpace);
@ -359,5 +371,9 @@ void NormNodeRetain(NormNodeHandle nodeHandle);
void NormNodeRelease(NormNodeHandle nodeHandle);
/** Some experimental functions */
unsigned long NormCountCompletedObjects(NormSessionHandle sessionHandle);
#endif // _NORM_API

View File

@ -437,6 +437,7 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime,
NormNodeId localId = LocalNodeId();
for (UINT16 i = 0; i < nodeCount; i++)
{
// (TBD) also ACK if NORM_NODE_ANY is listed???
if (flush.GetAckingNodeId(i) == localId)
{
doAck = true;
@ -1084,7 +1085,6 @@ void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg)
}
}
}
switch (repair_boundary)
{
case BLOCK_BOUNDARY:
@ -1296,6 +1296,7 @@ bool NormServerNode::PassiveRepairCheck(NormObjectId objectId,
NormBlockId blockId,
NormSegmentId segmentId)
{
if (!synchronized) return true;
NormObjectId nextId;
if (GetFirstPending(nextId))
{

View File

@ -148,13 +148,14 @@ class NormAckingNode : public NormNode
NormAckingNode(class NormSession& theSession, NormNodeId nodeId);
~NormAckingNode();
bool IsPending() const
{return (!ack_received &&( req_count > 0));}
{return (!ack_received && ( req_count > 0));}
void Reset(unsigned int maxAttempts = NORM_ROBUST_FACTOR)
{
ack_received = false;
req_count = maxAttempts;
}
void DecrementReqCount() {if (req_count > 0) req_count--;}
void ResetReqCount() {req_count = NORM_ROBUST_FACTOR;}
unsigned int GetReqCount() const {return req_count;}
bool AckReceived() const {return ack_received;}
void MarkAckReceived() {ack_received = true;}

View File

@ -18,9 +18,14 @@ NormObject::NormObject(NormObject::Type theType,
info_ptr(NULL), info_len(0), accepted(false), notify_on_update(true)
{
if (theServer)
{
nacking_mode = theServer->GetDefaultNackingMode();
theServer->Retain();
}
else
{
nacking_mode = NACK_NORMAL; // it doesn't really matter if !theServer
}
}
NormObject::~NormObject()
@ -47,7 +52,6 @@ void NormObject::Release()
else
{
DMSG(0, "NormObject::Release() releasing non-retained object?!\n");
ASSERT(0);
}
if (0 == reference_count) delete this;
} // end NormObject::Release()
@ -1677,6 +1681,7 @@ void NormStreamObject::StreamAdvance()
bool NormObject::CalculateBlockParity(NormBlock* block)
{
if (0 == nparity) return true;
char buffer[NormMsg::MAX_SIZE];
UINT16 numData = GetBlockSize(block->GetId());
for (UINT16 i = 0; i < numData; i++)
@ -2548,14 +2553,18 @@ UINT16 NormStreamObject::ReadSegment(NormBlockId blockId,
if ((UINT32)offsetDelta < object_size.LSB())
{
NormBlock* b = stream_buffer.Find(stream_buffer.RangeLo());
if (b && !b->IsPending()) write_vacancy = true;
if (b && !b->IsPending())
{
write_vacancy = true;
session.Notify(NormController::TX_QUEUE_VACANCY, NULL, this);
}
}
if (write_vacancy && !posted_tx_queue_vacancy)
}
/*if (HasVacancy() && !posted_tx_queue_vacancy)
{
posted_tx_queue_vacancy = true;
session.Notify(NormController::TX_QUEUE_VACANCY, NULL, this);
}
} */
UINT16 segmentLength = NormDataMsg::ReadStreamPayloadLength(segment);
ASSERT(segmentLength <= segment_size);
@ -3103,7 +3112,7 @@ UINT32 NormStreamObject::Write(const char* buffer, UINT32 len, bool eom)
{
if (0 != len)
{
DMSG(0, "NormStreamObject::Write() error: stream is closing\n");
DMSG(0, "NormStreamObject::Write() error: stream is closing (len:%lu eom:%d)\n", len, eom);
len = 0;
}
break;
@ -3254,7 +3263,7 @@ UINT32 NormStreamObject::Write(const char* buffer, UINT32 len, bool eom)
msg_start = true;
if (FLUSH_ACTIVE == flush_mode)
flush_pending = true;
else
else if (!stream_closing)
flush_pending = false;
if ((0 != nBytes) || (FLUSH_NONE != flush_mode))
session.TouchServer();

View File

@ -1,7 +1,7 @@
#include "normSegment.h"
NormSegmentPool::NormSegmentPool()
: seg_size(0), seg_count(0), seg_total(0), seg_list(NULL),
: seg_size(0), seg_count(0), seg_total(0), seg_list(NULL), seg_pool(NULL),
peak_usage(0), overruns(0), overrun_flag(false)
{
}
@ -14,7 +14,7 @@ NormSegmentPool::~NormSegmentPool()
bool NormSegmentPool::Init(unsigned int count, unsigned int size)
{
if (seg_list) Destroy();
if (seg_pool) Destroy();
peak_usage = 0;
overruns = 0;
#ifdef SIMULATE
@ -23,42 +23,37 @@ bool NormSegmentPool::Init(unsigned int count, unsigned int size)
size = MIN(size, (SIM_PAYLOAD_MAX+1));
#endif // SIMULATE
// This makes sure we get appropriate alignment
unsigned int alloc_size = size / sizeof(char*);
if ((alloc_size*sizeof(char*)) < size) alloc_size++;
seg_size = alloc_size * sizeof(char*);
for (unsigned int i = 0; i < count; i++)
unsigned int allocSize = size / sizeof(char*);
if ((allocSize*sizeof(char*)) < size) allocSize++;
seg_size = allocSize * sizeof(char*);
seg_pool = new char*[allocSize * count];
if (seg_pool)
{
char** ptr = new char*[alloc_size];
if (ptr)
char **ptr = seg_pool;
for (unsigned int i = 0; i < count; i++)
{
*ptr = seg_list;
seg_list = (char*)ptr;
seg_count++;
ptr += allocSize;
}
}
else
{
DMSG(0, "NormSegmentPool::Init() memory allocation error: %s\n",
GetErrorString());
seg_total = seg_count;
Destroy();
return false;
}
}
seg_total = seg_count;
seg_total = seg_count = count;
return true;
} // end NormSegmentPool::Init()
void NormSegmentPool::Destroy()
{
ASSERT(seg_count == seg_total);
char* ptr = seg_list;
while (ptr)
{
char* next;
memcpy(&next, ptr, sizeof(char*));
delete[] ptr;
ptr = next;
}
delete [] seg_pool;
seg_pool = NULL;
seg_list = NULL;
seg_count = 0;
seg_total = 0;

View File

@ -22,7 +22,8 @@ class NormSegmentPool
//char** ptr = (char**)segment;
//ptr = seg_list;
// (TBD) avoid this system call
memcpy(segment, &seg_list, sizeof(char*));
//memcpy(segment, &seg_list, sizeof(char*));
*((char**)segment) = seg_list; // this might make a warning on Solaris
seg_list = segment;
seg_count++;
}
@ -39,6 +40,7 @@ class NormSegmentPool
unsigned int seg_count;
unsigned int seg_total;
char* seg_list;
char** seg_pool;
unsigned long peak_usage;
unsigned long overruns;

View File

@ -240,12 +240,19 @@ void NormSession::SetTxRateInternal(double txRate)
{
if (tx_timer.IsActive())
{
tx_timer.Deactivate();
if (txRate > 0.0)
{
double adjustInterval = (tx_rate/txRate) * tx_timer.GetTimeRemaining();
if (adjustInterval > 0.100)
{
tx_timer.SetInterval(adjustInterval);
ActivateTimer(tx_timer);
tx_timer.Reschedule();
}
}
else
{
tx_timer.Deactivate();
}
tx_rate = txRate;
}
@ -379,6 +386,7 @@ bool NormSession::StartServer(UINT16 instanceId,
prev_update_time.tv_sec = prev_update_time.tv_usec = 0;
sent_accumulator = 0;
nominal_packet_size = (double)segmentSize;
data_active = false;
ndata = numData;
nparity = numParity;
is_server = true;
@ -478,7 +486,7 @@ void NormSession::Serve()
{
// Determine next message (objectId::blockId::segmentId) to be sent
NormObject* nextObj;
NormObjectId nextObjectId;
NormObjectId nextObjectId = next_tx_object_id;
NormBlockId nextBlockId = 0;
NormSegmentId nextSegmentId = 0;
if (obj)
@ -520,18 +528,32 @@ void NormSession::Serve()
{
// Nothing transmit pending, check for repair pending object
NormObjectTable::Iterator iterator(tx_table);
while ((nextObj = iterator.GetNextObject()))
if (nextObj->IsRepairPending()) break;
if (ServerGetFirstRepairPending(nextObjectId))
{
if (nextObj && (nextObj->GetId() < nextObjectId))
while ((nextObj = iterator.GetNextObject()))
{
if (nextObjectId < nextObj->GetId())
{
nextObj = tx_table.Find(nextObjectId);
break;
}
else if (nextObj->IsRepairPending())
{
nextObjectId = nextObj->GetId();
break;
}
}
}
else
{
nextObj = tx_table.Find(nextObjectId);
ASSERT(nextObj);
nextObjectId = next_tx_object_id;
while ((nextObj = iterator.GetNextObject()))
{
if (nextObj->IsRepairPending())
{
nextObjectId = nextObj->GetId();
break;
}
}
}
if (nextObj)
@ -542,10 +564,6 @@ void NormSession::Serve()
nextObj->FindRepairIndex(nextBlockId, nextSegmentId);
#endif
}
else
{
nextObjectId = next_tx_object_id;
}
}
if ((nextObjectId > watermark_object_id) ||
((nextObjectId == watermark_object_id) &&
@ -555,12 +573,29 @@ void NormSession::Serve()
{
if (ServerQueueWatermarkFlush())
{
watermark_active = true;
return;
}
else
{
// (TBD) optionally return here to have ack collection temporarily suspend data transmission
return;
// (TBD) optionally return here to have ack collection temporarily
// suspend forward progress of data transmission
//return;
}
}
else
{
// Reset non-acked acking nodes since server has rewound
if (watermark_active)
{
watermark_active = false;
NormNodeTreeIterator iterator(acking_node_tree);
NormAckingNode* next;
while ((next = static_cast<NormAckingNode*>(iterator.GetNextNode())))
{
//if (next->IsPending())
next->ResetReqCount();
}
}
}
} // end if (watermark_pending)
@ -572,6 +607,23 @@ void NormSession::Serve()
{
if (obj->NextServerMsg(msg))
{
if (cc_enable && !data_active)
{
data_active = true;
if (probe_timer.IsActive())
{
double elapsed = probe_timer.GetInterval() - probe_timer.GetTimeRemaining();
const NormCCNode* clr = static_cast<const NormCCNode*>(cc_node_list.Head());
double probeInterval = (clr && clr->IsActive()) ?
MIN(grtt_advertised, clr->GetRtt()) :
grtt_advertised;
if (elapsed > probeInterval)
probe_timer.SetInterval(0.0);
else
probe_timer.SetInterval(probeInterval - elapsed);
probe_timer.Reschedule();
}
}
msg->SetDestination(address);
msg->SetGrtt(grtt_quantized);
msg->SetBackoffFactor((unsigned char)backoff_factor);
@ -602,6 +654,7 @@ void NormSession::Serve()
{
// Queue flush message
if (!flush_timer.IsActive())
{
if (flush_count < NORM_ROBUST_FACTOR)
{
ServerQueueFlush();
@ -614,16 +667,16 @@ void NormSession::Serve()
if (stream->IsClosing())
{
stream->Close();
stream->Retain();
Notify(NormController::TX_OBJECT_PURGED, (NormServerNode*)NULL, stream);
stream->Release();
DeleteTxObject(stream);
obj = NULL;
}
}
}
if (!posted_tx_queue_empty)
}
if (!posted_tx_queue_empty && !stream->IsClosing())
{
//data_active = false;
posted_tx_queue_empty = true;
Notify(NormController::TX_QUEUE_EMPTY, (NormServerNode*)NULL, obj);
// (TBD) Was session deleted?
@ -649,6 +702,7 @@ void NormSession::Serve()
// No pending objects or positive acknowledgement request
if (!posted_tx_queue_empty)
{
data_active = false;
posted_tx_queue_empty = true;
Notify(NormController::TX_QUEUE_EMPTY,
(NormServerNode*)NULL,
@ -666,7 +720,6 @@ void NormSession::Serve()
{
DMSG(6, "NormSession::Serve() node>%lu server flush complete ...\n",
LocalNodeId());
Notify(NormController::TX_FLUSH_COMPLETED,
(NormServerNode*)NULL,
(NormObject*)NULL);
@ -682,10 +735,11 @@ void NormSession::ServerSetWatermark(NormObjectId objectId,
TRACE("NormSession::ServerSetWatermark(%hu:%lu:%hu) ...\n",
(UINT16)objectId, (UINT32)blockId, (UINT16)segmentId);
watermark_pending = true;
watermark_active = false;
watermark_object_id = objectId;
watermark_block_id = blockId;
watermark_segment_id = segmentId;
acks_collected = 0;
acking_success_count = 0;
// Reset acking_node_list
NormNodeTreeIterator iterator(acking_node_tree);
NormNode* next;
@ -721,16 +775,54 @@ bool NormSession::ServerAddAckingNode(NormNodeId nodeId)
void NormSession::ServerRemoveAckingNode(NormNodeId nodeId)
{
NormAckingNode* theNode = static_cast<NormAckingNode*>(acking_node_tree.FindNodeById(nodeId));
NormAckingNode* theNode =
static_cast<NormAckingNode*>(acking_node_tree.FindNodeById(nodeId));
if (theNode)
{
if (watermark_pending && theNode->AckReceived())
acks_collected--;
acking_node_tree.DetachNode(theNode);
acking_node_count--;
}
} // end NormSession::RemoveAckingNode()
NormSession::AckingStatus NormSession::ServerGetAckingStatus(NormNodeId nodeId)
{
if (NORM_NODE_ANY == nodeId)
{
// Return result based on overall success of acking process
if (watermark_pending)
{
return ACK_PENDING;
}
else
{
if (acking_success_count < acking_node_count)
return ACK_FAILURE;
else
return ACK_SUCCESS;
}
}
else
{
NormAckingNode* theNode =
static_cast<NormAckingNode*>(acking_node_tree.FindNodeById(nodeId));
if (theNode)
{
if (theNode->IsPending())
return ACK_PENDING;
else if (NORM_NODE_NONE == theNode->GetId())
return ACK_SUCCESS;
else if (theNode->AckReceived())
return ACK_SUCCESS;
else
return ACK_FAILURE;
}
else
{
return ACK_INVALID;
}
}
} // end NormSession::ServerGetAckingStatus()
bool NormSession::ServerQueueWatermarkFlush()
{
if (flush_timer.IsActive()) return false;
@ -748,9 +840,24 @@ bool NormSession::ServerQueueWatermarkFlush()
NormNodeTreeIterator iterator(acking_node_tree);
NormAckingNode* next;
watermark_pending = false;
NormAckingNode* nodeNone = NULL;
acking_success_count = 0;
while ((next = static_cast<NormAckingNode*>(iterator.GetNextNode())))
{
// Save NORM_NODE_NONE for last
if (NORM_NODE_NONE == next->GetId())
{
if (next->IsPending())
nodeNone = next;
else
acking_success_count++; // implicit success for NORM_NODE_NONE
continue;
}
if (next->AckReceived())
{
acking_success_count++; // ACK was received for this node
}
else if (next->IsPending())
{
// Add node to list
if (flush->AppendAckingNode(next->GetId(), segment_size))
@ -761,21 +868,39 @@ bool NormSession::ServerQueueWatermarkFlush()
else
{
DMSG(8, "NormSession::ServeQueueWatermarkFlush() full cmd ...\n");
nodeNone = NULL;
break;
}
}
}
if (NULL != nodeNone)
{
if (flush->AppendAckingNode(NORM_NODE_NONE, segment_size))
{
nodeNone->DecrementReqCount();
watermark_pending = true;
}
else
{
DMSG(8, "NormSession::ServeQueueWatermarkFlush() full cmd ...\n");
}
}
if (watermark_pending)
{
flush_count++;
if (flush_count < NORM_ROBUST_FACTOR) flush_count++;
QueueMessage(flush);
DMSG(8, "NormSession::ServeQueueWatermarkFlush() node>%lu cmd queued ...\n",
LocalNodeId());
}
else if (NULL != acking_node_tree.GetRoot())
{
DMSG(4, "NormSession::ServeQueueWatermarkFlush() node>%lu watermark ack finished.\n");
Notify(NormController::TX_WATERMARK_COMPLETED, (NormServerNode*)NULL, (NormObject*)NULL);
return false;
}
else
{
DMSG(4, "NormSession::ServeQueueWatermarkFlush() node>%lu watermark ack finished incomplete\n");
// (TBD) notify app
DMSG(2, "NormSession::ServeQueueWatermarkFlush() node>%lu no acking nodes specified?!\n");
return false;
}
}
@ -819,7 +944,7 @@ void NormSession::ServerQueueFlush()
// (TBD) send NORM_CMD(EOT) instead? - no
if (ServerQueueSquelch(next_tx_object_id))
{
flush_count++;
if (flush_count < NORM_ROBUST_FACTOR) flush_count++;
flush_timer.SetInterval(2*grtt_advertised);
ActivateTimer(flush_timer);
}
@ -839,7 +964,7 @@ void NormSession::ServerQueueFlush()
flush->SetFecBlockId(blockId);
flush->SetFecSymbolId(segmentId);
QueueMessage(flush);
flush_count++;
if (flush_count < NORM_ROBUST_FACTOR) flush_count++;
DMSG(4, "NormSession::ServerQueueFlush() node>%lu, flush queued (flush_count:%u)...\n",
LocalNodeId(), flush_count);
}
@ -1058,7 +1183,7 @@ bool NormSession::QueueTxObject(NormObject* obj)
count = tx_table.Count();
}
}
// Attempt to queue the object
// Attempt to queue the object (note it gets "retained" by the tx_table)
if (!tx_table.Insert(obj))
{
DMSG(0, "NormSession::QueueTxObject() tx_table insert error\n");
@ -1074,6 +1199,7 @@ bool NormSession::QueueTxObject(NormObject* obj)
void NormSession::DeleteTxObject(NormObject* obj)
{
ASSERT(obj);
if (tx_table.Remove(obj))
{
NormObjectId objectId = obj->GetId();
@ -1101,6 +1227,7 @@ void NormSession::SetTxCacheBounds(NormObjectSize sizeMax,
{
// Remove oldest non-pending
NormObject* oldest = tx_table.Find(tx_table.RangeLo());
ASSERT(oldest);
Notify(NormController::TX_OBJECT_PURGED, (NormServerNode*)NULL, oldest);
DeleteTxObject(oldest);
count = tx_table.Count();
@ -1878,13 +2005,6 @@ void NormSession::ServerHandleAckMessage(const struct timeval& currentTime, cons
(watermark_segment_id == flushAck.GetFecSymbolId()))
{
acker->MarkAckReceived();
acks_collected++;
if (acks_collected >= acking_node_count)
{
watermark_pending = false;
DMSG(4, "NormSession::ServerHandleAckMessage() watermark acknowledgement complete\n");
// (TBD) notify app
}
}
else
{
@ -2840,7 +2960,8 @@ bool NormSession::SendMessage(NormMsg& msg)
if (probe_reset)
{
probe_reset = false;
OnProbeTimeout(probe_timer);
OnProbeTimeout(probe_timer); //we commented this out to give data a chance at low rates
// we may want to re-visit this, it might compromis high rate performance a little
ActivateTimer(probe_timer);
}
}
@ -2870,12 +2991,11 @@ void NormSession::SetGrttProbingInterval(double intervalMin, double intervalMax)
{
double elapsed = probe_timer.GetInterval() - probe_timer.GetTimeRemaining();
if (elapsed < 0.0) elapsed = 0.0;
probe_timer.Deactivate();
if (elapsed > grtt_interval)
probe_timer.SetInterval(0.0);
else
probe_timer.SetInterval(grtt_interval - elapsed);
ActivateTimer(probe_timer);
probe_timer.Reschedule();
}
}
} // end NormSession::SetGrttProbingInterval()
@ -3088,23 +3208,31 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
AdjustRate(false);
// Determine next probe_interval
if (data_active)
{
const NormCCNode* clr = static_cast<const NormCCNode*>(cc_node_list.Head());
probeInterval = clr ? MIN(grtt_advertised, clr->GetRtt()) : grtt_advertised;
//double nominalRate = ((double)segment_size)/((double)tx_rate);
//probeInterval = MAX(probeInterval, nominalRate);
probeInterval = (clr && clr->IsActive()) ? MIN(grtt_advertised, clr->GetRtt()) : grtt_advertised;
}
else
{
probeInterval = grtt_interval;
}
}
else
{
// Determine next probe_interval
probeInterval = grtt_interval;
}
// perhaps this instead of the commented out probe_reset case???
double nominalInterval = ((double)segment_size)/((double)tx_rate);
if (nominalInterval > probeInterval) probeInterval = nominalInterval;
// Set probe_timer interval for next probe
probe_timer.SetInterval(probeInterval);
QueueMessage(cmd);
probe_pending = true;
// 3) Set probe_timer interval
probe_timer.SetInterval(probeInterval);
return true;
} // end NormSession::OnProbeTimeout()
@ -3116,6 +3244,8 @@ void NormSession::AdjustRate(bool onResponse)
double ccLoss = clr ? clr->GetLoss() : 0.0;
double txRate = tx_rate;
if (onResponse)
{
if (data_active) // adjust only if actively transmitting
{
// Adjust rate based on CLR feedback and
// adjust probe schedule
@ -3144,6 +3274,13 @@ void NormSession::AdjustRate(bool onResponse)
clr->GetId(), txRate*8.0/1000.0, clr->GetRtt(), clr->GetLoss());
}
}
}
else if (!data_active)
{
// reduce rate if no active data transmission
// (TBD) Perhaps we want to be less aggressive here someday
txRate *= 0.5;
}
else if (clr && clr->IsActive())
{
// (TBD) fix CC feedback aging ...

View File

@ -18,6 +18,7 @@ class NormController
TX_QUEUE_VACANCY,
TX_QUEUE_EMPTY,
TX_FLUSH_COMPLETED,
TX_WATERMARK_COMPLETED,
TX_OBJECT_SENT,
TX_OBJECT_PURGED,
LOCAL_SERVER_CLOSED,
@ -98,6 +99,13 @@ class NormSession
static const UINT16 DEFAULT_NDATA;
static const UINT16 DEFAULT_NPARITY;
enum ProbingMode {PROBE_NONE, PROBE_PASSIVE, PROBE_ACTIVE};
enum AckingStatus
{
ACK_INVALID,
ACK_FAILURE,
ACK_PENDING,
ACK_SUCCESS
};
// General methods
const NormNodeId& LocalNodeId() const {return local_node_id;}
@ -205,6 +213,7 @@ class NormSession
NormSegmentId segmentId);
bool ServerAddAckingNode(NormNodeId nodeId);
void ServerRemoveAckingNode(NormNodeId nodeId);
AckingStatus ServerGetAckingStatus(NormNodeId nodeId);
UINT16 ServerSegmentSize() const {return segment_size;}
@ -411,11 +420,12 @@ class NormSession
// For postive acknowledgement collection
NormNodeTree acking_node_tree;
unsigned int acking_node_count;
unsigned int acking_success_count;
bool watermark_pending;
bool watermark_active;
NormObjectId watermark_object_id;
NormBlockId watermark_block_id;
NormSegmentId watermark_segment_id;
unsigned int acks_collected;
// for unicast nack/cc feedback suppression
bool advertise_repairs;
@ -454,6 +464,7 @@ class NormSession
struct timeval prev_update_time; // for sent_rate measurement
unsigned long sent_accumulator; // for sent_rate measurement
double nominal_packet_size;
bool data_active; // true when actively sending data
// Client parameters
bool is_client;

View File

@ -28,16 +28,14 @@ int main(int argc, char* argv[])
NormSetCacheDirectory(instance, cachePath);
// Here's a trick to generate a _hopefully_ unique NormNodeId
// based on an XOR of the system's IP address and the process id.
// (We use ProtoAddress::GetEndIdentifier() to get the local
// "default" IP address for the system)
// (Note that passing "NORM_NODE_ANY" to the last arg of
// NormCreateSession() does a similar thing but without
// the process id ... perhaps we should add the process id
// hack to that default NormNodeId picker?
// the processId XOR ... perhaps we should add the processId
// hack to that default "NORM_NODE_ANY" local NormNodeId picker???
ProtoAddress localAddr;
if (!localAddr.ResolveLocalAddress())
{
@ -59,10 +57,9 @@ int main(int argc, char* argv[])
{
localId ^= (NormNodeId)rand();
}
//localId = 15; // for testing purposes
// Create a NORM session instance
NormSessionHandle session = NormCreateSession(instance,
"224.1.2.3",
6003,
@ -74,6 +71,7 @@ int main(int argc, char* argv[])
//NormSetMessageTrace(session, true);
// Uncomment to turn on some random packet loss
//NormSetTxLoss(session, 10.0); // 10% packet loss
//NormSetRxLoss(session, 20.0);
struct timeval currentTime;
ProtoSystemTime(currentTime);
// Uncomment to get different packet loss patterns from run to run
@ -82,7 +80,10 @@ int main(int argc, char* argv[])
//NormSetGrttEstimate(session, 0.001); // 1 msec initial grtt
NormSetTransmitRate(session, 6000.0e+03); // in bits/second
NormSetTransmitRate(session, 256.0e+03); // in bits/second
// Uncomment to enable TCP-friendly congestion control (overrides NormSetTransmitRate())
NormSetCongestionControl(session, true);
NormSetDefaultRepairBoundary(session, NORM_BOUNDARY_BLOCK);
@ -100,7 +101,7 @@ int main(int argc, char* argv[])
NormSetRxPortReuse(session, true);
// Uncomment to receive your own traffic
NormSetLoopback(session, true);
//NormSetLoopback(session, true);
// Uncomment this line to participate as a receiver
//NormStartReceiver(session, 1024*1024);
@ -109,13 +110,9 @@ int main(int argc, char* argv[])
// (might be needed for high rate sessions)
NormSetRxSocketBuffer(session, 512000);
// 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, sessionId, 1024*1024, 1420, 64, 0);
@ -123,12 +120,13 @@ int main(int argc, char* argv[])
// (might be needed for high rate sessions)
NormSetTxSocketBuffer(session, 512000);
NormAddAckingNode(session, NormGetLocalNodeId(session));
NormAddAckingNode(session, NORM_NODE_NONE); //15); //NormGetLocalNodeId(session));
NormObjectHandle stream = NORM_OBJECT_INVALID;
const char* filePath = "/home/adamson/images/art/giger/giger205.jpg";
const char* fileName = "ferrari.jpg";
//const char* filePath = "/home/adamson/pkgs/rh73.tgz";
const char* fileName = "file1.jpg";
const char* fileName2 = "file2.jpg";
// Uncomment this line to send a stream instead of the file
stream = NormStreamOpen(session, 10*1024*1024);
@ -148,18 +146,20 @@ int main(int argc, char* argv[])
int msgCount = 0;
int recvCount = -1; // used to monitor reliable stream reception
int sendCount = 0;
int sendMax = 20;
int sendMax = -1; // -1 means unlimited
NormEvent theEvent;
while (NormGetNextEvent(instance, &theEvent))
{
switch (theEvent.type)
{
case NORM_TX_QUEUE_VACANCY:
// TRACE("NORM_TX_QUEUE_VACANCY ...\n");
case NORM_TX_QUEUE_EMPTY:
//TRACE("NORM_TX_QUEUE_EMPTY ...\n");
//if (sendCount >= sendMax) break;
if (NORM_OBJECT_INVALID != stream)
/*if (NORM_TX_QUEUE_VACANCY == theEvent.type)
TRACE("NORM_TX_QUEUE_VACANCY ...\n");
else
TRACE("NORM_TX_QUEUE_EMPTY ...\n");*/
if ((sendMax > 0) && (sendCount >= sendMax)) break;
if (NORM_OBJECT_INVALID != theEvent.object)
{
// We loop here to keep stream buffer full ....
bool keepWriting = true;
@ -187,22 +187,27 @@ int main(int argc, char* argv[])
NormStreamMarkEom(stream);
txLen = txIndex = 0;
sendCount++;
if (sendCount >= sendMax)
if (sendCount == 15)
{
NormSetWatermark(session, stream);
}
if ((sendMax > 0) && (sendCount >= sendMax))
{
// Uncomment to gracefully shut down the stream
// after "sendMax" messages
//NormStreamClose(stream, true);
//keepWriting = false;
NormStreamClose(stream, true);
keepWriting = false;
}
}
} // end while(keepWriting)
}
}
else
else if (NORM_OBJECT_INVALID == stream) // we weren't sending a stream that finished
{
const char* namePtr = (0 == (sendCount & 0x01)) ? fileName : fileName2;
NormObjectHandle txFile =
NormFileEnqueue(session,
filePath,
fileName,
namePtr,
strlen(fileName));
// Repeatedly queue our file for sending
if (NORM_OBJECT_INVALID == txFile)
@ -214,7 +219,7 @@ int main(int argc, char* argv[])
{
TRACE("QUEUED FILE ...\n");
sendCount++;
NormSetWatermark(session, txFile);
if (sendCount < 2) NormSetWatermark(session, txFile);
}
}
break;
@ -223,6 +228,14 @@ int main(int argc, char* argv[])
DMSG(2, "normTest: NORM_TX_OBJECT_PURGED event ...\n");
break;
case NORM_TX_FLUSH_COMPLETED:
DMSG(2, "normTest: NORM_TX_FLUSH_COMPLETED event ...\n");
break;
case NORM_TX_WATERMARK_COMPLETED:
DMSG(2, "normTest: NORM_TX_WATERMARK_COMPLETED event ...\n");
break;
case NORM_RX_OBJECT_NEW:
DMSG(3, "normTest: NORM_RX_OBJECT_NEW event ...\n");
break;
@ -335,6 +348,7 @@ int main(int argc, char* argv[])
case NORM_RX_OBJECT_COMPLETED:
TRACE("normTest: NORM_RX_OBJECT_COMPLETED event ...\n");
//NormStopReceiver(session);
break;
case NORM_RX_OBJECT_ABORTED:
@ -345,8 +359,8 @@ int main(int argc, char* argv[])
TRACE("Got event type: %d\n", theEvent.type);
} // end switch(theEvent.type)
// Break after sending "sendMax" messages or files
//if (sendCount >= sendMax) break;
// Uncomment to exit program after sending "sendMax" messages or files
//if ((sendMax > 0) && (sendCount >= sendMax)) break;
} // end while (NormGetNextEvent())

View File

@ -32,6 +32,6 @@
#ifndef _NORM_VERSION
#define _NORM_VERSION
#define VERSION "1.3b5"
#define VERSION "1.3b6"
#endif // _NORM_VERSION

View File

@ -7,7 +7,7 @@
BUILD (Unix):
g++ -o normFileSend normFileSend.cpp -D_FILE_OFFSET_BITS=64 -DPROTO_DEBUG \
g++ -o normFileRecv normFileRecv.cpp -D_FILE_OFFSET_BITS=64 -DPROTO_DEBUG \
-I../common/ -I../protolib/common ../unix/libnorm.a \
../protolib/unix/libProtokit.a -lpthread

View File

@ -3,6 +3,8 @@
This directory contains files for incorporating the NORM protocol
into the ns-2 network simulation tool.
(The NORM ns-2 support may need a little tweaking to work)
FILES:
nsNormAgent.h