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="GENERATOR" CONTENT="NeoOffice/J 1.1 (Unix)">
<META NAME="AUTHOR" CONTENT="Robert Adamson"> <META NAME="AUTHOR" CONTENT="Robert Adamson">
<META NAME="CREATED" CONTENT="20040824;14180000"> <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="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 "> <META NAME="KEYWORDS" CONTENT="norm object value application function ">
<STYLE> <STYLE>
@ -51,22 +51,24 @@
</TD> </TD>
<TD WIDTH=371> <TD WIDTH=371>
<P ALIGN=LEFT STYLE="margin-left: 0.86in; margin-top: 0.17in; font-style: normal"> <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 <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</B></FONT></FONT></P> <BR>Guide<BR></FONT><FONT SIZE=4>(version 1.3b6)</FONT></B></FONT></FONT></P>
</TD> </TD>
</TR> </TR>
</TABLE> </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 <P CLASS="western" STYLE="font-style: normal">This document describes
an application programming interface (API) for the Nack-Oriented 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) protocol implementation developed by the Reliable Multicast (NORM)</A></U></FONT> protocol implementation
United States Naval Research Laboratory (NRL). The NORM protocol developed by the United States <FONT COLOR="#0000ff"><U><A HREF="http://www.nrl.navy.mil/">Naval
provides general purpose reliable data transport for applications Research Laboratory</A></U></FONT> (NRL). The NORM protocol provides
wishing to use Internet Protocol (IP) Multicast services for group general purpose reliable data transport for applications wishing to
data delivery. NORM can also support unicast (point-to-point) data 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 communication and may be used for such when deemed appropriate. The
current NORM protocol specification is given in the Internet current NORM protocol specification is given in the <FONT COLOR="#0000ff"><U><A HREF="http://www.ietf.org/">Internet
Engineering Task Force RFC 3940.</P> 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 <P CLASS="western" STYLE="font-style: normal">The NORM protocol is
designed to provide end-to-end reliable transport of bulk data designed to provide end-to-end reliable transport of bulk data
objects or streams over generic IP multicast routing and forwarding 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 different applications. Even with NORM, the developer should have a
thorough understanding of the specific application's group thorough understanding of the specific application's group
communication needs.</P> communication needs.</P>
<H1 CLASS="western" ALIGN=CENTER STYLE="page-break-before: always">Table <H1 CLASS="western" ALIGN=CENTER STYLE="page-break-before: always"><A NAME="Table
of Contents</H1> of Contents">Table
of Contents</A></H1>
<DIV ID="Table of Contents1" DIR="LTR"> <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.25in; font-style: normal"><BR>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>API </P>
Initialization</B></FONT></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>Session <P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B><A HREF="#API Initialization">API Initialization</A></B></FONT></P>
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">Session Creation and Control</A></B></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>NORM <P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B><A HREF="#Data Transport">Data Transport</A></B></FONT></P>
Data Transport</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>NORM <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#Data Reception">Data Reception</A></FONT></P>
Data Transmission</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-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2>NORM <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>
Data Reception</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>API <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>
Event Notification</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.25in; font-style: normal"><FONT FACE="Helvetica, sans-serif"><B>Build <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>
Notes</B></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>Unix
Platforms</B></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>Win32/WiNCE
Platforms</B></FONT></P>
<P STYLE="margin-top: 0.25in; font-style: normal"><FONT FACE="Helvetica, sans-serif"><B>API
Reference</B></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>API
Variable Types and Constants</B></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormInstanceHandle">NormInstanceHandle</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#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="#NormSessionHandle">NormSessionHandle</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSessionId">NormSessionId</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#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="#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="#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-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 <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormAckingStatus">NormAckingStatus</A></FONT></P>
Initialization and Operation</B></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="#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="#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="#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="#NormGetNextEvent()">NormGetNextEvent()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormGetDescriptor()">NormGetDescriptor()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormGetDescriptor()">NormGetDescriptor()</A></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>Session <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>
Creation and Control</B></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormCreateSession()">NormCreateSession()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#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="#NormDestroySession()">NormDestroySession()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetUserData()">NormSetUserData()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#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="#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="#NormSetTOS()">NormSetTOS()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetLoopback()">NormSetLoopback()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetLoopback()">NormSetLoopback()</A></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>NORM <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>
Sender Functions</B></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStartSender()">NormStartSender()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#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="#NormStopSender()">NormStopSender()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTransmitRate()">NormSetTransmitRate()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#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="#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="#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="#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="#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="#NormDataEnqueue()">NormDataEnqueue()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamOpen()">NormStreamOpen()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#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="#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="#NormStreamMarkEom()">NormStreamMarkEom()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetWatermark()">NormSetWatermark()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetWatermark()">NormSetWatermark()</A></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>NORM <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormAddAckingNode()">NormAddAckingNode()</A></FONT></P>
Receiver Functions</B></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="#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="#NormStopReceiver()">NormStopReceiver()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetRxSocketBuffer()">NormSetRxSocketBuffer()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#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="#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="#NormStreamSeekMsgStart()">NormStreamSeekMsgStart()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamGetReadOffset()">NormStreamGetReadOffset()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStreamGetReadOffset()">NormStreamGetReadOffset()</A></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>NORM <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>
Object Functions</B></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectGetType()">NormObjectGetType()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#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="#NormObjectHasInfo()">NormObjectHasInfo()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectGetInfoLength()">NormObjectGetInfoLength()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#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="#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="#NormDataDetachData()">NormDataDetachData()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectGetSender()">NormObjectGetSender()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectGetSender()">NormObjectGetSender()</A></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>NORM <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>
Node Functions</B></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeGetId()">NormNodeGetId()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#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="#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="#NormNodeRetain()">NormNodeRetain()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeRelease()">NormNodeRelease()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeRelease()">NormNodeRelease()</A></FONT></P>
</DIV> </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 <P CLASS="western" STYLE="font-style: normal">The NORM API has been
designed to provide simple, straightforward access to and control of designed to provide simple, straightforward access to and control of
NORM protocol state and functions. Functions are provided to create 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 through a thread-safe event dispatching mechanism and API calls are
provided to allow the application to control NORM operation. (<I>Note: provided to allow the application to control NORM operation. (<I>Note:
API mechanisms for lower-level, non-threaded control and execution 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 <P CLASS="western" STYLE="font-style: normal">The NORM API operation
can be roughly summarized with the following categories of functions:</P> can be roughly summarized with the following categories of functions:</P>
<OL> <OL>
<LI><P CLASS="western" STYLE="font-style: normal">API Initialization</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">Session Creation <LI><P CLASS="western" STYLE="font-style: normal"><A HREF="#Session Creation and Control">Session Creation and Control</A></P>
and Control</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">Data Transport</P> <LI><P CLASS="western" STYLE="font-style: normal"><A HREF="#API Event Notification">API Event Notification</A></P>
<LI><P CLASS="western" STYLE="font-style: normal">Event Notification</P>
</OL> </OL>
<P CLASS="western" STYLE="font-style: normal">Note the order of these <P CLASS="western" STYLE="font-style: normal">Note the order of these
categories roughly reflects the order of function calls required to 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 also a number support functions provided for the application to
control and monitor its participation within a NORM transport control and monitor its participation within a NORM transport
session.</P> 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 <P CLASS="western" STYLE="font-style: normal">The NORM API requires
that an application explicitly create at least one instance of the that an application explicitly create at least one instance of the
NORM protocol engine which is subsequently used as a conduit for NORM protocol engine which is subsequently used as a conduit for
further NORM API calls. By default, the NORM protocol engine runs in further NORM API calls. By default, the NORM protocol engine runs in
its own operating system thread and interacts with the application in its own operating system thread and interacts with the application in
a thread-safe manner through the API calls and event dispatching a thread-safe manner through the API calls and event dispatching
mechanism. In general, only the thread creating the NORM API mechanism.
instance should invoke API calls referencing that instance or any </P>
sessions or state created within that instance (<I>NOTE: This <P CLASS="western" STYLE="font-style: normal">In general, only a
limitation may change in the future. The current implementation is single thread should access the <FONT FACE="Courier"><A HREF="#NormGetNextEvent()">NormGetNextEvent()</A></FONT>
theoretically safe for concurrent access, but this has not been fully API call for a given <FONT FACE="Courier">NormInstance</FONT>. This
tested</I>). Multiple API instances may be created as needed for function serves as the conduit for delivering NORM protocol engine
applications with specific requirements for accessing and controlling events to the application. While a NORM application can be designed
participation in multiple NORM sessions from operating system to be single-threaded, even with multiple active <I>NormSessions</I>,
multiple threads.</P> multiple API instances can be created (see <FONT FACE="Courier"><A HREF="#NormCreateInstance()">NormCreateInstance()</A></FONT>)
<H2 CLASS="western">Session Creation and Control</H2> 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 <P CLASS="western" STYLE="font-style: normal">Once an API instance
has been successfully created, the application may then create NORM has been successfully created, the application may then create NORM
transport session instances as needed. The application can 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, application with finer control over receive buffer allocation,
perhaps on a per sender basis</I>). perhaps on a per sender basis</I>).
</P> </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 <P CLASS="western" STYLE="font-style: normal">The NORM protocol
supports transport of three basic types of data content. These supports transport of three basic types of data content. These
include the types <FONT FACE="Courier"><I>NORM_OBJECT_FILE</I></FONT> 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 recover message boundaries without any “handshake” with the
sender. Stream content is buffered by the NORM implementation for sender. Stream content is buffered by the NORM implementation for
transmission/retransmission and as it is received.</P> 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 <P CLASS="western" STYLE="font-style: normal">The behavior of data
transport operation is largely placed in the control of the NORM transport operation is largely placed in the control of the NORM
sender(s). NORM senders controls their data transmission rate, 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 positive acknowledgement is collected. This process can provide the
application with explicit flow control for an application-determined application with explicit flow control for an application-determined
critical set of receivers in the group.</P> 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 <P CLASS="western" STYLE="font-style: normal">NORM receiver
applications learn of active senders and their corresponding pending applications learn of active senders and their corresponding pending
and completed data transfers, etc via the API event dispatching 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 to achieve reliable transfer. Some API functions are available to
provide some additional control over the NACKing behavior, such as provide some additional control over the NACKing behavior, such as
initially NACKing for NORM_INFO content only or even to the extent of initially NACKing for NORM_INFO content only or even to the extent of
disabling receiver feedback (silent receiver operation) entirely.</P> disabling receiver feedback (silent receiver or emission-controlled
<H2 CLASS="western">API Event Notification</H2> (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 <P CLASS="western" STYLE="font-style: normal">An asynchronous event
dispatching mechanism is provided to notify the application of dispatching mechanism is provided to notify the application of
significant NORM protocol events. The centerpiece of this is the 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 available. For Win32 platforms, dispatching of a user-defined
Windows message for NORM event notification is also planned for a Windows message for NORM event notification is also planned for a
future update to the API.</P> 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 <P CLASS="western" STYLE="font-style: normal">To build applications
that use the NORM library, a path to the &quot;normApi.h&quot; header 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 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 for Win32 platforms). NORM also depends upon the NRL Protean
Protocol Prototyping toolkit &quot;Protokit&quot; library (a.k.a Protocol Prototyping toolkit &quot;Protokit&quot; library (a.k.a
&quot;Protolib&quot;) (static library files &quot;libProtokit.a&quot; &quot;Protolib&quot;) (static library files &quot;libProtokit.a&quot;
for Unix and &quot;Protokit.lib&quot; for Win32). Depending upon the for Unix and &quot;Protokit.lib&quot; for Win32). Shared or
platform, some additional library dependencies may be required to dynamically-linked versions of these libraries may also be built from
support the needs of NORM and/or Protokit. These are described the NORM source code or provided. Depending upon the platform, some
below.</P> additional library dependencies may be required to support the needs
<H2 CLASS="western">Unix Platforms</H2> 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 <P CLASS="western" STYLE="font-style: normal">NORM has been built and
tested on Linux (various architectures), MacOS (BSD), Solaris, and tested on Linux (various architectures), MacOS (BSD), Solaris, and
IRIX (SGI) platforms. The code should be readily portable to other IRIX (SGI) platforms. The code should be readily portable to other
Unix platforms.</P> Unix platforms.</P>
<P CLASS="western" STYLE="font-style: normal">To support IPv6 <P CLASS="western" STYLE="font-style: normal">To support IPv6
operation, the NORM and the Protokit library must be compiled with operation, the NORM and the <I>Protokit</I> library must be compiled
the &quot;HAVE_IPV6&quot; macro defined. This is default in the NORM with the &quot;HAVE_IPV6&quot; macro defined. This is default in the
and Protokit Makefiles for platforms that support IPv6. It is NORM and <I>Protokit</I> Makefiles for platforms that support IPv6.
important that NORM and Protokit be built with this macro defined the It is important that NORM and <I>Protokit</I> be built with this
same. With NORM, it is recommended that &quot;large file support&quot; macro defined the same. With NORM, it is recommended that &quot;large
options be enabled when possible.</P> file support&quot; options be enabled when possible.</P>
<P CLASS="western" STYLE="font-style: normal">The NORM API uses <P CLASS="western" STYLE="font-style: normal">The NORM API uses
threading so that the NORM protocol engine may run independent of the threading so that the NORM protocol engine may run independent of the
application. Thus the &quot;POSIX Threads&quot; library must be 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 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> 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> 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 <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 using Microsoft's Visual C++ (6.0 and .NET) and Embedded VC++ 4.2
environments. In addition to proper macro definitions (e.g., 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> attributes.</P>
<P CLASS="western" STYLE="font-style: normal">An additional note is <P CLASS="western" STYLE="font-style: normal">An additional note is
that a bug in VC++ 6.0 and earlier compilers (includes embedded VC++ 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 debugging capabilities enabled. However, this has been resolved in
VC++ .NET and is hoped to be resolved in the future for the WinCE VC++ .NET and is hoped to be resolved in the future for the WinCE
build tools.</P> 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 <P CLASS="western" STYLE="font-style: normal">This section provides a
reference to the NORM API variable types, constants and functions.</P> 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 <P CLASS="western" STYLE="font-style: normal">The NORM API defines
and enumerates a number of supporting variable types and values which and enumerates a number of supporting variable types and values which
are used in different function calls. The variable types are 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> function.</P>
<H3 CLASS="functionheading-western"><A NAME="NormNackingMode">NormNackingMode</A></H3> <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> <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 <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> <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 <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> <FONT FACE="Courier"><A HREF="#NormObjectSetNackingMode()">NormObjectSetNackingMode()</A></FONT> functions.</P>
<H3 CLASS="functionheading-western"><A NAME="NormRepairBoundary">NormRepairBoundary</A></H3> <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> <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 <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> <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 <P CLASS="western" STYLE="font-style: normal">The interpretation of
these values is given in the descriptions of the these values is given in the descriptions of the
<FONT FACE="Courier"><A HREF="#NormSetDefaultRepairBoundary()">NormSetDefaultRepairBoundary()</A> </FONT>and <FONT FACE="Courier"><A HREF="#NormSetDefaultRepairBoundary()">NormSetDefaultRepairBoundary()</A> </FONT>and
<FONT FACE="Courier"><A HREF="#NormNodeSetRepairBoundary()">NormNodeSetRepairBoundary()</A></FONT> functions.</P> <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 <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 the NORM API is to create an &quot;instance&quot; of the NORM
protocol engine. Note that multiple instances may be created by the 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"> <P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
This event indicates that there is room for additional transmit 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> 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 is given in the corresponding event &quot;object&quot; field, the
may successfully write to the indicated stream object.</P> 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> </TD>
</TR> </TR>
<TR VALIGN=TOP> <TR VALIGN=TOP>
@ -817,7 +899,14 @@ function call.</P>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid"> <P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
This event indicates the NORM protocol engine has no new data This event indicates the NORM protocol engine has no new data
pending transmission and the application may enqueue additional 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> </TD>
</TR> </TR>
<TR VALIGN=TOP> <TR VALIGN=TOP>
@ -840,6 +929,20 @@ function call.</P>
transmission, even with packet loss rates of 50%.</P> transmission, even with packet loss rates of 50%.</P>
</TD> </TD>
</TR> </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> <TR VALIGN=TOP>
<TD WIDTH=269> <TD WIDTH=269>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid"> <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> 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 made. Upon error, a value of <I><FONT FACE="Courier">NORM_DESCRIPTOR_INVALID</FONT></I>
is returned.</P> 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> <H3 CLASS="functionheading-western"><A NAME="NormCreateSession()">NormCreateSession()</A></H3>
<H4 CLASS="western">Synopsis</H4> <H4 CLASS="western">Synopsis</H4>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>#include <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> <H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">This function has no <P CLASS="western" STYLE="font-style: normal">This function has no
return values.</P> return values.</P>
<H2 CLASS="western">NORM<SPAN STYLE="font-style: normal"> </SPAN>Sender <H2 CLASS="western"><A NAME="NORM Sender Functions">NORM Sender Functions</A></H2>
Functions</H2>
<H3 CLASS="functionheading-western"><A NAME="NormStartSender()">NormStartSender()</A></H3> <H3 CLASS="functionheading-western"><A NAME="NormStartSender()">NormStartSender()</A></H3>
<H4 CLASS="western">Synopsis</H4> <H4 CLASS="western">Synopsis</H4>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>#include <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> &lt;normApi.h&gt;</FONT></FONT></P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void <P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void
NormSetGrttProbingMode(<A HREF="#NormSessionHandle">NormSessionHandle</A>&nbsp;session, 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> <H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function sets the <P CLASS="western" STYLE="font-style: normal">This function sets the
sender's mode of probing for round trip timing measurement responses 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> <H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">This function has no <P CLASS="western" STYLE="font-style: normal">This function has no
return values.</P> 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> <H3 CLASS="functionheading-western"><A NAME="NormFileEnqueue()">NormFileEnqueue()</A></H3>
<H4 CLASS="western">Synopsis</H4> <H4 CLASS="western">Synopsis</H4>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>#include <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 degree of implicit flow control in limiting writing new data to the
stream against pending repairs. stream against pending repairs.
</P> </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> <H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">This function returns <P CLASS="western" STYLE="font-style: normal">This function returns
the number of bytes of data successfully enqueued for NORM stream 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> <H3 CLASS="functionheading-western"><A NAME="NormStreamFlush()">NormStreamFlush()</A></H3>
<H4 CLASS="western">Synopsis</H4> <H4 CLASS="western">Synopsis</H4>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>#include <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> <H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function specifies <P CLASS="western" STYLE="font-style: normal">This function specifies
a &quot;watermark&quot; transmission point at which NORM sender a &quot;watermark&quot; transmission point at which NORM sender
protocol operation should perform positive acknowledgment collection protocol operation should perform a flushing process and/or positive
for a given <FONT FACE="Courier"><U>session</U></FONT>. For acknowledgment collection for a given <FONT FACE="Courier"><U>session</U></FONT>.
<FONT FACE="Courier"><I>NORM_OBJECT_FILE</I></FONT> and For <FONT FACE="Courier"><I>NORM_OBJECT_FILE</I></FONT> and
<FONT FACE="Courier"><I>NORM_OBJECT_DATA</I></FONT> transmissions, <FONT FACE="Courier"><I>NORM_OBJECT_DATA</I></FONT> transmissions,
the positive acknowledgement collection will begin when the specified the positive acknowledgement collection will begin when the specified
<FONT FACE="Courier"><U>object</U></FONT> has been completely <FONT FACE="Courier"><U>object</U></FONT> has been completely
transmitted. The object parameter must be a valid handle to a 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> previously-created sender object (see <FONT FACE="Courier">NormEnqueueFile()</FONT><FONT SIZE=2><FONT FACE="Courier">,</FONT></FONT>
<FONT SIZE=2><FONT FACE="Courier">NormEnqueueData()</FONT></FONT>, or <FONT FACE="Courier">NormEnqueueData()</FONT>, or <FONT FACE="Courier"><A HREF="#NormStreamOpen()">NormStreamOpen()</A></FONT>).
<FONT SIZE=2><FONT FACE="Courier"><A HREF="#NormStreamOpen()">NormStreamOpen()</A></FONT></FONT>). For <FONT FACE="Courier"><I>NORM_OBJECT_STREAM</I></FONT>
For <FONT FACE="Courier"><I>NORM_OBJECT_STREAM</I></FONT>
transmission, the positive acknowledgment collection begins transmission, the positive acknowledgment collection begins
immediately, using the current position (last data written) of the immediately, using the current position (offset of most recent data
sender stream as a reference. written) of the sender stream as a reference.
</P> </P>
<P CLASS="western" STYLE="font-style: normal">As the acknowledgment <P CLASS="western" STYLE="font-style: normal">The functions
collection proceeds, <FONT FACE="Courier"><I>NORM_ACK_FAILED</I></FONT> <FONT FACE="Courier"><A HREF="#NormAddAckingNode()">NormAddAckingNode()</A></FONT> and
events will be posted for individual receiver <I>NormNodes</I> which <FONT FACE="Courier"><A HREF="#NormRemoveAckingNode()">NormRemoveAckingNode()</A></FONT> are used to manage
fail to acknowledge the request. The <FONT FACE="Courier"><A HREF="#NormEvent">NormEvent</A>::node</FONT> the list of <FONT FACE="Courier"><A HREF="#NormNodeId">NormNodeId</A></FONT> values
field contains a <FONT FACE="Courier"><A HREF="#NormNodeHandle">NormNodeHandle</A></FONT> for the corresponding to NORM receivers that are expected to explicitly
failed node and <FONT FACE="Courier"><A HREF="#NormNodeGetId()">NormNodeGetId()</A></FONT> can be acknowledge the watermark flushing messages transmitted by the
used to retrieve the failing node's <FONT FACE="Courier"><A HREF="#NormNodeId">NormNodeId</A></FONT>. sender. Note that the <FONT FACE="Courier"><A HREF="#NormNodeId">NormNodeId</A></FONT>
When the sender acknowledgment collection process has completed, the <FONT FACE="Courier"><I>NORM_NODE_NONE</I></FONT> may be included in
<FONT FACE="Courier"><I>NORM_ACK_COMPLETE</I></FONT> event is posted the list. Inclusion of <FONT FACE="Courier"><I>NORM_NODE_NONE</I></FONT>
and the application may assume that the remaining nodes (those for forces the watermark flushing process to proceed through a full
which there was no <FONT FACE="Courier"><I>NORM_ACK_FAILED</I></FONT> <FONT FACE="Courier"><I>NORM_ROBUST_FACTOR</I></FONT> number of
event) successfully acknowledged the request.</P> rounds before completing, prompting any receivers that have not
<P CLASS="western" STYLE="font-style: normal">If a subsequent call is completed reliable reception to the given watermark point to NACK for
made to <FONT FACE="Courier"><A HREF="#NormSetWatermark()">NormSetWatermark()</A></FONT> before the any repair needs. If NACKs occur, the flushing process is reset and
prior acknowledgement request has completed, the pending repeated until completing with no NACKs for data through the given
acknowledgment request is canceled and new one may begin.</P> watermark transmission point are received. Thus, even without
<P CLASS="western" STYLE="font-style: normal">Note that the sender explicit positive acknowledgment, the sender can use this process (by
may still enqueue <I>NormObjects</I> for transmission (or write to adding <FONT FACE="Courier"><I>NORM_NODE_NONE</I></FONT> to the
the existing stream) and the positive acknowledgement collection will <FONT FACE="Courier"><U>session</U></FONT>'s list of acking nodes)
be multiplexed with the ongoing data transmission. However, the for a high level of assurance that the receiver set is &quot;happy&quot;
sender application may wish to defer sending more data until a (completed reliable data reception) through the given <FONT FACE="Courier"><U>object</U></FONT>
<FONT FACE="Courier"><I>NORM_ACK_COMPLETE</I></FONT> event is (or stream transmission point).
received for the <FONT FACE="Courier"><U>session</U></FONT>. This </P>
provides a form of explicit sender-&gt;receiver(s) flow control (with <P CLASS="western" STYLE="font-style: normal">The event
respect to the current list of &quot;acking&quot; receivers) which <FONT FACE="Courier"><I>NORM_TX_WATERMARK_COMPLETED</I></FONT> is
does not exist in NORM's default NACK-only operation.</P> 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> <H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">The function returns <P CLASS="western" STYLE="font-style: normal">The function returns
<FONT FACE="Courier"><I>true</I></FONT> upon successful establishment <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> 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> 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> <H3 CLASS="functionheading-western"><A NAME="NormStartReceiver()">NormStartReceiver()</A></H3>
<H4 CLASS="western">Synopsis</H4> <H4 CLASS="western">Synopsis</H4>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>#include <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 the current read offset in bytes. The return value is undefined for
sender streams. There is no error result. sender streams. There is no error result.
</P> </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 <P CLASS="western" STYLE="font-style: normal">The functions described
in this section may be used for sender or receiver purposes to manage in this section may be used for sender or receiver purposes to manage
transmission and reception of NORM transport objects. In most cases, 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> is valid. The returned <FONT FACE="Courier"><A HREF="#NormNodeHandle">NormNodeHandle</A></FONT>
may optionally be retained for further use by the application using may optionally be retained for further use by the application using
the <FONT FACE="Courier"><A HREF="#NormNodeRetain()">NormNodeRetain()</A></FONT> function call. The 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> in this document.</P>
<H4 CLASS="western">Return Values</H4> <H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">This function returns <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 <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> of NORM_NODE_INVALID is returned if the specified <FONT FACE="Courier"><U>objectHandle</U></FONT>
references a locally originated, sender object.</P> 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 <P CLASS="western" STYLE="font-style: normal">The functions described
in this section may be used for NORM sender or receiver (most in this section may be used for NORM sender or receiver (most
typically receiver) purposes to retrieve additional information about typically receiver) purposes to retrieve additional information about

Binary file not shown.

View File

@ -1,5 +1,23 @@
NORM Version History 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 Version 1.3b5
============= =============
- Changed ProtoSocket::GetInterfaceAddress() and related methods on Win32 - Changed ProtoSocket::GetInterfaceAddress() and related methods on Win32

View File

@ -46,6 +46,8 @@ class NormInstance : public NormController
void PurgeObjectNotifications(NormObjectHandle objectHandle); void PurgeObjectNotifications(NormObjectHandle objectHandle);
unsigned long CountCompletedObjects(NormSession* theSession);
ProtoDispatcher::Descriptor GetDescriptor() const ProtoDispatcher::Descriptor GetDescriptor() const
{ {
#ifdef WIN32 #ifdef WIN32
@ -57,6 +59,7 @@ class NormInstance : public NormController
static NormInstance* GetInstanceFromSession(NormSessionHandle sessionHandle) static NormInstance* GetInstanceFromSession(NormSessionHandle sessionHandle)
{ {
if (NORM_SESSION_INVALID == sessionHandle) return ((NormInstance*)NULL);
NormSession* session = (NormSession*)sessionHandle; NormSession* session = (NormSession*)sessionHandle;
NormInstance* theInstance = static_cast<NormInstance*>(session->GetSessionMgr().GetController()); NormInstance* theInstance = static_cast<NormInstance*>(session->GetSessionMgr().GetController());
return theInstance; return theInstance;
@ -64,11 +67,13 @@ class NormInstance : public NormController
} }
static NormInstance* GetInstanceFromNode(NormNodeHandle nodeHandle) static NormInstance* GetInstanceFromNode(NormNodeHandle nodeHandle)
{ {
if (NORM_NODE_INVALID == nodeHandle) return ((NormInstance*)NULL);
NormSession& session = ((NormNode*)nodeHandle)->GetSession(); NormSession& session = ((NormNode*)nodeHandle)->GetSession();
return static_cast<NormInstance*>(session.GetSessionMgr().GetController()); return static_cast<NormInstance*>(session.GetSessionMgr().GetController());
} }
static NormInstance* GetInstanceFromObject(NormObjectHandle objectHandle) static NormInstance* GetInstanceFromObject(NormObjectHandle objectHandle)
{ {
if (NORM_OBJECT_INVALID == objectHandle) return ((NormInstance*)NULL);
NormSession& session = ((NormObject*)objectHandle)->GetSession();; NormSession& session = ((NormObject*)objectHandle)->GetSession();;
return static_cast<NormInstance*>(session.GetSessionMgr().GetController()); return static_cast<NormInstance*>(session.GetSessionMgr().GetController());
} }
@ -610,6 +615,21 @@ void NormInstance::Shutdown()
notify_pool.Destroy(); notify_pool.Destroy();
} // end NormInstance::Shutdown() } // 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 // NORM API FUNCTION IMPLEMENTATIONS
@ -1024,35 +1044,6 @@ void NormSetGrttProbingInterval(NormSessionHandle sessionHandle,
} }
} // end NormSetGrttProbingInterval() } // 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, NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle,
const char* fileName, const char* fileName,
const char* infoPtr, const char* infoPtr,
@ -1249,6 +1240,50 @@ bool NormSetWatermark(NormSessionHandle sessionHandle,
return result; return result;
} // end NormSetWatermark() } // 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 */ /** NORM Receiver Functions */
@ -1260,10 +1295,7 @@ bool NormStartReceiver(NormSessionHandle sessionHandle,
if (instance && instance->dispatcher.SuspendThread()) if (instance && instance->dispatcher.SuspendThread())
{ {
NormSession* session = (NormSession*)sessionHandle; NormSession* session = (NormSession*)sessionHandle;
if (session) result = session->StartClient(bufferSpace);
result = session->StartClient(bufferSpace);
else
result = false;
instance->dispatcher.ResumeThread(); instance->dispatcher.ResumeThread();
} }
return result; return result;
@ -1276,7 +1308,7 @@ void NormStopReceiver(NormSessionHandle sessionHandle)
if (instance && instance->dispatcher.SuspendThread()) if (instance && instance->dispatcher.SuspendThread())
{ {
NormSession* session = (NormSession*)sessionHandle; NormSession* session = (NormSession*)sessionHandle;
if (session) session->StopClient(); session->StopClient();
instance->dispatcher.ResumeThread(); instance->dispatcher.ResumeThread();
} }
} // end NormStopReceiver() } // end NormStopReceiver()
@ -1364,8 +1396,7 @@ bool NormStreamRead(NormObjectHandle streamHandle,
{ {
NormStreamObject* stream = NormStreamObject* stream =
static_cast<NormStreamObject*>((NormObject*)streamHandle); static_cast<NormStreamObject*>((NormObject*)streamHandle);
if (stream) result = stream->Read(buffer, numBytes);
result = stream->Read(buffer, numBytes);
instance->dispatcher.ResumeThread(); instance->dispatcher.ResumeThread();
} }
return result; return result;
@ -1380,8 +1411,7 @@ bool NormStreamSeekMsgStart(NormObjectHandle streamHandle)
NormStreamObject* stream = NormStreamObject* stream =
static_cast<NormStreamObject*>((NormObject*)streamHandle); static_cast<NormStreamObject*>((NormObject*)streamHandle);
unsigned int numBytes = 0; unsigned int numBytes = 0;
if (stream) result = stream->Read(NULL, &numBytes, true);
result = stream->Read(NULL, &numBytes, true);
instance->dispatcher.ResumeThread(); instance->dispatcher.ResumeThread();
} }
return result; return result;
@ -1391,7 +1421,10 @@ bool NormStreamSeekMsgStart(NormObjectHandle streamHandle)
unsigned long NormStreamGetReadOffset(NormObjectHandle streamHandle) unsigned long NormStreamGetReadOffset(NormObjectHandle streamHandle)
{ {
NormStreamObject* stream = static_cast<NormStreamObject*>((NormObject*)streamHandle); NormStreamObject* stream = static_cast<NormStreamObject*>((NormObject*)streamHandle);
return stream->GetCurrentReadOffset(); if (stream)
return stream->GetCurrentReadOffset();
else
return 0;
} // end NormStreamGetReadOffset() } // end NormStreamGetReadOffset()
@ -1641,3 +1674,16 @@ void NormNodeRelease(NormNodeHandle nodeHandle)
// the app to install an event handler callback and dispatch // the app to install an event handler callback and dispatch
// events with a "NormDispatchEvents()" call ... // 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 // C++ code continues to evolve. But, until this notice
// is removed, the API shouldn't be considered final. // is removed, the API shouldn't be considered final.
// NORM API control /** NORM API Types */
typedef const void* NormInstanceHandle; typedef const void* NormInstanceHandle;
extern const NormInstanceHandle NORM_INSTANCE_INVALID; extern const NormInstanceHandle NORM_INSTANCE_INVALID;
@ -66,6 +66,14 @@ enum NormNackingMode
NORM_NACK_NORMAL NORM_NACK_NORMAL
}; };
enum NormAckingStatus
{
NORM_ACK_INVALID,
NORM_ACK_FAILURE,
NORM_ACK_PENDING,
NORM_ACK_SUCCESS
};
enum NormProbingMode enum NormProbingMode
{ {
NORM_PROBE_NONE, NORM_PROBE_NONE,
@ -85,6 +93,7 @@ enum NormEventType
NORM_TX_QUEUE_VACANCY, NORM_TX_QUEUE_VACANCY,
NORM_TX_QUEUE_EMPTY, NORM_TX_QUEUE_EMPTY,
NORM_TX_FLUSH_COMPLETED, NORM_TX_FLUSH_COMPLETED,
NORM_TX_WATERMARK_COMPLETED,
NORM_TX_OBJECT_SENT, NORM_TX_OBJECT_SENT,
NORM_TX_OBJECT_PURGED, NORM_TX_OBJECT_PURGED,
NORM_LOCAL_SERVER_CLOSED, NORM_LOCAL_SERVER_CLOSED,
@ -221,12 +230,6 @@ void NormSetGrttProbingInterval(NormSessionHandle sessionHandle,
double intervalMin, double intervalMin,
double intervalMax); double intervalMax);
bool NormAddAckingNode(NormSessionHandle sessionHandle,
NormNodeId nodeId);
void NormRemoveAckingNode(NormSessionHandle sessionHandle,
NormNodeId nodeId);
NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle, NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle,
const char* fileName, const char* fileName,
const char* infoPtr = (const char*)0, const char* infoPtr = (const char*)0,
@ -261,13 +264,22 @@ void NormStreamSetPushEnable(NormObjectHandle streamHandle,
bool NormStreamHasVacancy(NormObjectHandle streamHandle); bool NormStreamHasVacancy(NormObjectHandle streamHandle);
NormSize NormGetObjectSize(NormObjectHandle objectHandle);
void NormStreamMarkEom(NormObjectHandle streamHandle); void NormStreamMarkEom(NormObjectHandle streamHandle);
bool NormSetWatermark(NormSessionHandle sessionHandle, bool NormSetWatermark(NormSessionHandle sessionHandle,
NormObjectHandle objectHandle); 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, bool NormStartReceiver(NormSessionHandle sessionHandle,
unsigned long bufferSpace); unsigned long bufferSpace);
@ -359,5 +371,9 @@ void NormNodeRetain(NormNodeHandle nodeHandle);
void NormNodeRelease(NormNodeHandle nodeHandle); void NormNodeRelease(NormNodeHandle nodeHandle);
/** Some experimental functions */
unsigned long NormCountCompletedObjects(NormSessionHandle sessionHandle);
#endif // _NORM_API #endif // _NORM_API

View File

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

View File

@ -148,13 +148,14 @@ class NormAckingNode : public NormNode
NormAckingNode(class NormSession& theSession, NormNodeId nodeId); NormAckingNode(class NormSession& theSession, NormNodeId nodeId);
~NormAckingNode(); ~NormAckingNode();
bool IsPending() const bool IsPending() const
{return (!ack_received &&( req_count > 0));} {return (!ack_received && ( req_count > 0));}
void Reset(unsigned int maxAttempts = NORM_ROBUST_FACTOR) void Reset(unsigned int maxAttempts = NORM_ROBUST_FACTOR)
{ {
ack_received = false; ack_received = false;
req_count = maxAttempts; req_count = maxAttempts;
} }
void DecrementReqCount() {if (req_count > 0) req_count--;} void DecrementReqCount() {if (req_count > 0) req_count--;}
void ResetReqCount() {req_count = NORM_ROBUST_FACTOR;}
unsigned int GetReqCount() const {return req_count;} unsigned int GetReqCount() const {return req_count;}
bool AckReceived() const {return ack_received;} bool AckReceived() const {return ack_received;}
void MarkAckReceived() {ack_received = true;} 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) info_ptr(NULL), info_len(0), accepted(false), notify_on_update(true)
{ {
if (theServer) if (theServer)
{
nacking_mode = theServer->GetDefaultNackingMode(); nacking_mode = theServer->GetDefaultNackingMode();
else theServer->Retain();
}
else
{
nacking_mode = NACK_NORMAL; // it doesn't really matter if !theServer nacking_mode = NACK_NORMAL; // it doesn't really matter if !theServer
}
} }
NormObject::~NormObject() NormObject::~NormObject()
@ -47,7 +52,6 @@ void NormObject::Release()
else else
{ {
DMSG(0, "NormObject::Release() releasing non-retained object?!\n"); DMSG(0, "NormObject::Release() releasing non-retained object?!\n");
ASSERT(0);
} }
if (0 == reference_count) delete this; if (0 == reference_count) delete this;
} // end NormObject::Release() } // end NormObject::Release()
@ -1677,6 +1681,7 @@ void NormStreamObject::StreamAdvance()
bool NormObject::CalculateBlockParity(NormBlock* block) bool NormObject::CalculateBlockParity(NormBlock* block)
{ {
if (0 == nparity) return true;
char buffer[NormMsg::MAX_SIZE]; char buffer[NormMsg::MAX_SIZE];
UINT16 numData = GetBlockSize(block->GetId()); UINT16 numData = GetBlockSize(block->GetId());
for (UINT16 i = 0; i < numData; i++) for (UINT16 i = 0; i < numData; i++)
@ -2548,14 +2553,18 @@ UINT16 NormStreamObject::ReadSegment(NormBlockId blockId,
if ((UINT32)offsetDelta < object_size.LSB()) if ((UINT32)offsetDelta < object_size.LSB())
{ {
NormBlock* b = stream_buffer.Find(stream_buffer.RangeLo()); 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; posted_tx_queue_vacancy = true;
session.Notify(NormController::TX_QUEUE_VACANCY, NULL, this); session.Notify(NormController::TX_QUEUE_VACANCY, NULL, this);
} } */
UINT16 segmentLength = NormDataMsg::ReadStreamPayloadLength(segment); UINT16 segmentLength = NormDataMsg::ReadStreamPayloadLength(segment);
ASSERT(segmentLength <= segment_size); ASSERT(segmentLength <= segment_size);
@ -3103,7 +3112,7 @@ UINT32 NormStreamObject::Write(const char* buffer, UINT32 len, bool eom)
{ {
if (0 != len) 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; len = 0;
} }
break; break;
@ -3254,7 +3263,7 @@ UINT32 NormStreamObject::Write(const char* buffer, UINT32 len, bool eom)
msg_start = true; msg_start = true;
if (FLUSH_ACTIVE == flush_mode) if (FLUSH_ACTIVE == flush_mode)
flush_pending = true; flush_pending = true;
else else if (!stream_closing)
flush_pending = false; flush_pending = false;
if ((0 != nBytes) || (FLUSH_NONE != flush_mode)) if ((0 != nBytes) || (FLUSH_NONE != flush_mode))
session.TouchServer(); session.TouchServer();

View File

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

View File

@ -22,7 +22,8 @@ class NormSegmentPool
//char** ptr = (char**)segment; //char** ptr = (char**)segment;
//ptr = seg_list; //ptr = seg_list;
// (TBD) avoid this system call // (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_list = segment;
seg_count++; seg_count++;
} }
@ -39,6 +40,7 @@ class NormSegmentPool
unsigned int seg_count; unsigned int seg_count;
unsigned int seg_total; unsigned int seg_total;
char* seg_list; char* seg_list;
char** seg_pool;
unsigned long peak_usage; unsigned long peak_usage;
unsigned long overruns; unsigned long overruns;

View File

@ -240,12 +240,19 @@ void NormSession::SetTxRateInternal(double txRate)
{ {
if (tx_timer.IsActive()) if (tx_timer.IsActive())
{ {
tx_timer.Deactivate();
if (txRate > 0.0) if (txRate > 0.0)
{ {
double adjustInterval = (tx_rate/txRate) * tx_timer.GetTimeRemaining(); double adjustInterval = (tx_rate/txRate) * tx_timer.GetTimeRemaining();
tx_timer.SetInterval(adjustInterval); if (adjustInterval > 0.100)
ActivateTimer(tx_timer); {
tx_timer.SetInterval(adjustInterval);
tx_timer.Reschedule();
}
}
else
{
tx_timer.Deactivate();
} }
tx_rate = txRate; tx_rate = txRate;
} }
@ -379,6 +386,7 @@ bool NormSession::StartServer(UINT16 instanceId,
prev_update_time.tv_sec = prev_update_time.tv_usec = 0; prev_update_time.tv_sec = prev_update_time.tv_usec = 0;
sent_accumulator = 0; sent_accumulator = 0;
nominal_packet_size = (double)segmentSize; nominal_packet_size = (double)segmentSize;
data_active = false;
ndata = numData; ndata = numData;
nparity = numParity; nparity = numParity;
is_server = true; is_server = true;
@ -420,7 +428,7 @@ void NormSession::StopServer()
NormObject* obj = tx_table.Find(tx_table.RangeLo()); NormObject* obj = tx_table.Find(tx_table.RangeLo());
ASSERT(obj); ASSERT(obj);
tx_table.Remove(obj); tx_table.Remove(obj);
obj->Release(); obj->Release();
} }
// Then destroy table // Then destroy table
tx_table.Destroy(); tx_table.Destroy();
@ -478,7 +486,7 @@ void NormSession::Serve()
{ {
// Determine next message (objectId::blockId::segmentId) to be sent // Determine next message (objectId::blockId::segmentId) to be sent
NormObject* nextObj; NormObject* nextObj;
NormObjectId nextObjectId; NormObjectId nextObjectId = next_tx_object_id;
NormBlockId nextBlockId = 0; NormBlockId nextBlockId = 0;
NormSegmentId nextSegmentId = 0; NormSegmentId nextSegmentId = 0;
if (obj) if (obj)
@ -520,19 +528,33 @@ void NormSession::Serve()
{ {
// Nothing transmit pending, check for repair pending object // Nothing transmit pending, check for repair pending object
NormObjectTable::Iterator iterator(tx_table); NormObjectTable::Iterator iterator(tx_table);
while ((nextObj = iterator.GetNextObject()))
if (nextObj->IsRepairPending()) break;
if (ServerGetFirstRepairPending(nextObjectId)) if (ServerGetFirstRepairPending(nextObjectId))
{ {
if (nextObj && (nextObj->GetId() < nextObjectId)) while ((nextObj = iterator.GetNextObject()))
{ {
nextObjectId = nextObj->GetId(); if (nextObjectId < nextObj->GetId())
} {
else nextObj = tx_table.Find(nextObjectId);
break;
}
else if (nextObj->IsRepairPending())
{
nextObjectId = nextObj->GetId();
break;
}
}
}
else
{
nextObjectId = next_tx_object_id;
while ((nextObj = iterator.GetNextObject()))
{ {
nextObj = tx_table.Find(nextObjectId); if (nextObj->IsRepairPending())
ASSERT(nextObj); {
} nextObjectId = nextObj->GetId();
break;
}
}
} }
if (nextObj) if (nextObj)
{ {
@ -542,10 +564,6 @@ void NormSession::Serve()
nextObj->FindRepairIndex(nextBlockId, nextSegmentId); nextObj->FindRepairIndex(nextBlockId, nextSegmentId);
#endif #endif
} }
else
{
nextObjectId = next_tx_object_id;
}
} }
if ((nextObjectId > watermark_object_id) || if ((nextObjectId > watermark_object_id) ||
((nextObjectId == watermark_object_id) && ((nextObjectId == watermark_object_id) &&
@ -555,14 +573,31 @@ void NormSession::Serve()
{ {
if (ServerQueueWatermarkFlush()) if (ServerQueueWatermarkFlush())
{ {
watermark_active = true;
return; return;
} }
else else
{ {
// (TBD) optionally return here to have ack collection temporarily suspend data transmission // (TBD) optionally return here to have ack collection temporarily
return; // 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) } // end if (watermark_pending)
if (obj) if (obj)
@ -572,6 +607,23 @@ void NormSession::Serve()
{ {
if (obj->NextServerMsg(msg)) 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->SetDestination(address);
msg->SetGrtt(grtt_quantized); msg->SetGrtt(grtt_quantized);
msg->SetBackoffFactor((unsigned char)backoff_factor); msg->SetBackoffFactor((unsigned char)backoff_factor);
@ -602,28 +654,29 @@ void NormSession::Serve()
{ {
// Queue flush message // Queue flush message
if (!flush_timer.IsActive()) if (!flush_timer.IsActive())
{
if (flush_count < NORM_ROBUST_FACTOR) if (flush_count < NORM_ROBUST_FACTOR)
{
ServerQueueFlush();
}
else if (NORM_ROBUST_FACTOR == flush_count)
{
DMSG(6, "NormSession::Serve() node>%lu server flush complete ...\n",
LocalNodeId());
flush_count++;
if (stream->IsClosing())
{ {
stream->Close(); ServerQueueFlush();
stream->Retain(); }
Notify(NormController::TX_OBJECT_PURGED, (NormServerNode*)NULL, stream); else if (NORM_ROBUST_FACTOR == flush_count)
stream->Release(); {
DeleteTxObject(stream); DMSG(6, "NormSession::Serve() node>%lu server flush complete ...\n",
obj = NULL; LocalNodeId());
flush_count++;
if (stream->IsClosing())
{
stream->Close();
Notify(NormController::TX_OBJECT_PURGED, (NormServerNode*)NULL, stream);
DeleteTxObject(stream);
obj = NULL;
}
} }
} }
} }
if (!posted_tx_queue_empty) if (!posted_tx_queue_empty && !stream->IsClosing())
{ {
//data_active = false;
posted_tx_queue_empty = true; posted_tx_queue_empty = true;
Notify(NormController::TX_QUEUE_EMPTY, (NormServerNode*)NULL, obj); Notify(NormController::TX_QUEUE_EMPTY, (NormServerNode*)NULL, obj);
// (TBD) Was session deleted? // (TBD) Was session deleted?
@ -649,6 +702,7 @@ void NormSession::Serve()
// No pending objects or positive acknowledgement request // No pending objects or positive acknowledgement request
if (!posted_tx_queue_empty) if (!posted_tx_queue_empty)
{ {
data_active = false;
posted_tx_queue_empty = true; posted_tx_queue_empty = true;
Notify(NormController::TX_QUEUE_EMPTY, Notify(NormController::TX_QUEUE_EMPTY,
(NormServerNode*)NULL, (NormServerNode*)NULL,
@ -666,7 +720,6 @@ void NormSession::Serve()
{ {
DMSG(6, "NormSession::Serve() node>%lu server flush complete ...\n", DMSG(6, "NormSession::Serve() node>%lu server flush complete ...\n",
LocalNodeId()); LocalNodeId());
Notify(NormController::TX_FLUSH_COMPLETED, Notify(NormController::TX_FLUSH_COMPLETED,
(NormServerNode*)NULL, (NormServerNode*)NULL,
(NormObject*)NULL); (NormObject*)NULL);
@ -682,10 +735,11 @@ void NormSession::ServerSetWatermark(NormObjectId objectId,
TRACE("NormSession::ServerSetWatermark(%hu:%lu:%hu) ...\n", TRACE("NormSession::ServerSetWatermark(%hu:%lu:%hu) ...\n",
(UINT16)objectId, (UINT32)blockId, (UINT16)segmentId); (UINT16)objectId, (UINT32)blockId, (UINT16)segmentId);
watermark_pending = true; watermark_pending = true;
watermark_active = false;
watermark_object_id = objectId; watermark_object_id = objectId;
watermark_block_id = blockId; watermark_block_id = blockId;
watermark_segment_id = segmentId; watermark_segment_id = segmentId;
acks_collected = 0; acking_success_count = 0;
// Reset acking_node_list // Reset acking_node_list
NormNodeTreeIterator iterator(acking_node_tree); NormNodeTreeIterator iterator(acking_node_tree);
NormNode* next; NormNode* next;
@ -721,16 +775,54 @@ bool NormSession::ServerAddAckingNode(NormNodeId nodeId)
void NormSession::ServerRemoveAckingNode(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 (theNode)
{ {
if (watermark_pending && theNode->AckReceived())
acks_collected--;
acking_node_tree.DetachNode(theNode); acking_node_tree.DetachNode(theNode);
acking_node_count--; acking_node_count--;
} }
} // end NormSession::RemoveAckingNode() } // 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() bool NormSession::ServerQueueWatermarkFlush()
{ {
if (flush_timer.IsActive()) return false; if (flush_timer.IsActive()) return false;
@ -748,9 +840,24 @@ bool NormSession::ServerQueueWatermarkFlush()
NormNodeTreeIterator iterator(acking_node_tree); NormNodeTreeIterator iterator(acking_node_tree);
NormAckingNode* next; NormAckingNode* next;
watermark_pending = false; watermark_pending = false;
NormAckingNode* nodeNone = NULL;
acking_success_count = 0;
while ((next = static_cast<NormAckingNode*>(iterator.GetNextNode()))) while ((next = static_cast<NormAckingNode*>(iterator.GetNextNode())))
{ {
if (next->IsPending()) // 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 // Add node to list
if (flush->AppendAckingNode(next->GetId(), segment_size)) if (flush->AppendAckingNode(next->GetId(), segment_size))
@ -761,22 +868,40 @@ bool NormSession::ServerQueueWatermarkFlush()
else else
{ {
DMSG(8, "NormSession::ServeQueueWatermarkFlush() full cmd ...\n"); DMSG(8, "NormSession::ServeQueueWatermarkFlush() full cmd ...\n");
nodeNone = NULL;
break; 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) if (watermark_pending)
{ {
flush_count++; if (flush_count < NORM_ROBUST_FACTOR) flush_count++;
QueueMessage(flush); QueueMessage(flush);
DMSG(8, "NormSession::ServeQueueWatermarkFlush() node>%lu cmd queued ...\n", DMSG(8, "NormSession::ServeQueueWatermarkFlush() node>%lu cmd queued ...\n",
LocalNodeId()); 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 else
{ {
DMSG(4, "NormSession::ServeQueueWatermarkFlush() node>%lu watermark ack finished incomplete\n"); DMSG(2, "NormSession::ServeQueueWatermarkFlush() node>%lu no acking nodes specified?!\n");
// (TBD) notify app return false;
return false;
} }
} }
else else
@ -819,7 +944,7 @@ void NormSession::ServerQueueFlush()
// (TBD) send NORM_CMD(EOT) instead? - no // (TBD) send NORM_CMD(EOT) instead? - no
if (ServerQueueSquelch(next_tx_object_id)) if (ServerQueueSquelch(next_tx_object_id))
{ {
flush_count++; if (flush_count < NORM_ROBUST_FACTOR) flush_count++;
flush_timer.SetInterval(2*grtt_advertised); flush_timer.SetInterval(2*grtt_advertised);
ActivateTimer(flush_timer); ActivateTimer(flush_timer);
} }
@ -839,7 +964,7 @@ void NormSession::ServerQueueFlush()
flush->SetFecBlockId(blockId); flush->SetFecBlockId(blockId);
flush->SetFecSymbolId(segmentId); flush->SetFecSymbolId(segmentId);
QueueMessage(flush); QueueMessage(flush);
flush_count++; if (flush_count < NORM_ROBUST_FACTOR) flush_count++;
DMSG(4, "NormSession::ServerQueueFlush() node>%lu, flush queued (flush_count:%u)...\n", DMSG(4, "NormSession::ServerQueueFlush() node>%lu, flush queued (flush_count:%u)...\n",
LocalNodeId(), flush_count); LocalNodeId(), flush_count);
} }
@ -1058,7 +1183,7 @@ bool NormSession::QueueTxObject(NormObject* obj)
count = tx_table.Count(); 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)) if (!tx_table.Insert(obj))
{ {
DMSG(0, "NormSession::QueueTxObject() tx_table insert error\n"); DMSG(0, "NormSession::QueueTxObject() tx_table insert error\n");
@ -1074,6 +1199,7 @@ bool NormSession::QueueTxObject(NormObject* obj)
void NormSession::DeleteTxObject(NormObject* obj) void NormSession::DeleteTxObject(NormObject* obj)
{ {
ASSERT(obj);
if (tx_table.Remove(obj)) if (tx_table.Remove(obj))
{ {
NormObjectId objectId = obj->GetId(); NormObjectId objectId = obj->GetId();
@ -1101,6 +1227,7 @@ void NormSession::SetTxCacheBounds(NormObjectSize sizeMax,
{ {
// Remove oldest non-pending // Remove oldest non-pending
NormObject* oldest = tx_table.Find(tx_table.RangeLo()); NormObject* oldest = tx_table.Find(tx_table.RangeLo());
ASSERT(oldest);
Notify(NormController::TX_OBJECT_PURGED, (NormServerNode*)NULL, oldest); Notify(NormController::TX_OBJECT_PURGED, (NormServerNode*)NULL, oldest);
DeleteTxObject(oldest); DeleteTxObject(oldest);
count = tx_table.Count(); count = tx_table.Count();
@ -1878,13 +2005,6 @@ void NormSession::ServerHandleAckMessage(const struct timeval& currentTime, cons
(watermark_segment_id == flushAck.GetFecSymbolId())) (watermark_segment_id == flushAck.GetFecSymbolId()))
{ {
acker->MarkAckReceived(); 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 else
{ {
@ -2840,7 +2960,8 @@ bool NormSession::SendMessage(NormMsg& msg)
if (probe_reset) if (probe_reset)
{ {
probe_reset = false; 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); ActivateTimer(probe_timer);
} }
} }
@ -2870,12 +2991,11 @@ void NormSession::SetGrttProbingInterval(double intervalMin, double intervalMax)
{ {
double elapsed = probe_timer.GetInterval() - probe_timer.GetTimeRemaining(); double elapsed = probe_timer.GetInterval() - probe_timer.GetTimeRemaining();
if (elapsed < 0.0) elapsed = 0.0; if (elapsed < 0.0) elapsed = 0.0;
probe_timer.Deactivate();
if (elapsed > grtt_interval) if (elapsed > grtt_interval)
probe_timer.SetInterval(0.0); probe_timer.SetInterval(0.0);
else else
probe_timer.SetInterval(grtt_interval - elapsed); probe_timer.SetInterval(grtt_interval - elapsed);
ActivateTimer(probe_timer); probe_timer.Reschedule();
} }
} }
} // end NormSession::SetGrttProbingInterval() } // end NormSession::SetGrttProbingInterval()
@ -3088,23 +3208,31 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
AdjustRate(false); AdjustRate(false);
// Determine next probe_interval // Determine next probe_interval
const NormCCNode* clr = static_cast<const NormCCNode*>(cc_node_list.Head()); if (data_active)
probeInterval = clr ? MIN(grtt_advertised, clr->GetRtt()) : grtt_advertised; {
//double nominalRate = ((double)segment_size)/((double)tx_rate); const NormCCNode* clr = static_cast<const NormCCNode*>(cc_node_list.Head());
//probeInterval = MAX(probeInterval, nominalRate); probeInterval = (clr && clr->IsActive()) ? MIN(grtt_advertised, clr->GetRtt()) : grtt_advertised;
}
else
{
probeInterval = grtt_interval;
}
} }
else else
{ {
// Determine next probe_interval // Determine next probe_interval
probeInterval = grtt_interval; probeInterval = grtt_interval;
} }
// perhaps this instead of the commented out probe_reset case???
QueueMessage(cmd); double nominalInterval = ((double)segment_size)/((double)tx_rate);
probe_pending = true; if (nominalInterval > probeInterval) probeInterval = nominalInterval;
// 3) Set probe_timer interval // Set probe_timer interval for next probe
probe_timer.SetInterval(probeInterval); probe_timer.SetInterval(probeInterval);
QueueMessage(cmd);
probe_pending = true;
return true; return true;
} // end NormSession::OnProbeTimeout() } // end NormSession::OnProbeTimeout()
@ -3117,33 +3245,42 @@ void NormSession::AdjustRate(bool onResponse)
double txRate = tx_rate; double txRate = tx_rate;
if (onResponse) if (onResponse)
{ {
// Adjust rate based on CLR feedback and if (data_active) // adjust only if actively transmitting
// adjust probe schedule
ASSERT(clr);
// (TBD) check feedback age
if (cc_slow_start)
{ {
txRate = clr->GetRate(); // Adjust rate based on CLR feedback and
DMSG(6, "NormSession::AdjustRate(slow start) clr>%lu newRate>%lf (oldRate>%lf sentRate>%lf clrRate>%lf\n", // adjust probe schedule
clr->GetId(), txRate*8.0/1000.0, tx_rate*8.0/1000.0, sent_rate*8.0/1000.0, ASSERT(clr);
clr->GetRate()*8.0/1000.0); // (TBD) check feedback age
} if (cc_slow_start)
else
{
double clrRate = clr->GetRate();
if (clrRate > txRate)
{ {
double linRate = txRate + segment_size; txRate = clr->GetRate();
txRate = MIN(clrRate, linRate); DMSG(6, "NormSession::AdjustRate(slow start) clr>%lu newRate>%lf (oldRate>%lf sentRate>%lf clrRate>%lf\n",
clr->GetId(), txRate*8.0/1000.0, tx_rate*8.0/1000.0, sent_rate*8.0/1000.0,
clr->GetRate()*8.0/1000.0);
} }
else else
{ {
txRate = clrRate; double clrRate = clr->GetRate();
} if (clrRate > txRate)
DMSG(6, "NormSession::AdjustRate(stdy state) clr>%lu newRate>%lf (rtt>%lf loss>%lf)\n", {
clr->GetId(), txRate*8.0/1000.0, clr->GetRtt(), clr->GetLoss()); double linRate = txRate + segment_size;
txRate = MIN(clrRate, linRate);
}
else
{
txRate = clrRate;
}
DMSG(6, "NormSession::AdjustRate(stdy state) clr>%lu newRate>%lf (rtt>%lf loss>%lf)\n",
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()) else if (clr && clr->IsActive())
{ {
// (TBD) fix CC feedback aging ... // (TBD) fix CC feedback aging ...

View File

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

View File

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

View File

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

View File

@ -7,7 +7,7 @@
BUILD (Unix): 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 \ -I../common/ -I../protolib/common ../unix/libnorm.a \
../protolib/unix/libProtokit.a -lpthread ../protolib/unix/libProtokit.a -lpthread

View File

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