pull/2/head
Jeff Weston 2019-09-11 11:53:54 -04:00
parent 602326e415
commit 3dd25deec9
33 changed files with 1639 additions and 619 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="20050919;14362900"> <META NAME="CHANGED" CONTENT="20051028;14285700">
<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>
@ -52,7 +52,7 @@
<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=4 STYLE="font-size: 16pt"><B><FONT SIZE=6 STYLE="font-size: 28pt">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<BR></FONT><FONT SIZE=4>(version 1.3b6)</FONT></B></FONT></FONT></P> <BR>Guide<BR></FONT><FONT SIZE=4>(version 1.3b7)</FONT></B></FONT></FONT></P>
</TD> </TD>
</TR> </TR>
</TABLE> </TABLE>
@ -60,7 +60,9 @@
<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 <FONT COLOR="#0000ff"><U><A HREF="http://norm.pf.itd.nrl.navy.mil/">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)</A></U></FONT> protocol implementation Reliable Multicast (NORM)</A></U></FONT> protocol implementation
developed by the United States <FONT COLOR="#0000ff"><U><A HREF="http://www.nrl.navy.mil/">Naval developed by the Protocol Engineering and Advance Networking
(<FONT COLOR="#0000ff"><U><A HREF="http://cs.itd.nrl.navy.mil/">PROTEAN</A></U></FONT>)
Research Group of the United States <FONT COLOR="#0000ff"><U><A HREF="http://www.nrl.navy.mil/">Naval
Research Laboratory</A></U></FONT> (NRL). The NORM protocol provides Research Laboratory</A></U></FONT> (NRL). The NORM protocol provides
general purpose reliable data transport for applications wishing to general purpose reliable data transport for applications wishing to
use Internet Protocol (IP) Multicast services for group data use Internet Protocol (IP) Multicast services for group data
@ -102,8 +104,6 @@ communication needs.</P>
of Contents">Table of Contents">Table
of Contents</A></H1> 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"><BR>
</P>
<P STYLE="margin-top: 0.25in; font-style: normal"><FONT FACE="Helvetica, sans-serif"><B><A HREF="#Overview">Overview</A></B></FONT></P> <P STYLE="margin-top: 0.25in; font-style: normal"><FONT FACE="Helvetica, sans-serif"><B><A HREF="#Overview">Overview</A></B></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B><A HREF="#API Initialization">API Initialization</A></B></FONT></P> <P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B><A HREF="#API Initialization">API Initialization</A></B></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B><A HREF="#Session Creation and Control">Session Creation and Control</A></B></FONT></P> <P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B><A HREF="#Session Creation and Control">Session Creation and Control</A></B></FONT></P>
@ -136,6 +136,8 @@ of Contents</A></H1>
<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-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="#NormStopInstance()">NormStopInstance()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormRestartInstance()">NormRestartInstance()</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>
@ -151,7 +153,8 @@ of Contents</A></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><A HREF="#NORM Sender Functions">NORM Sender Functions</A></B></FONT></P> <P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>NORM
Sender Functions</B></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormStartSender()">NormStartSender()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#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>
@ -164,6 +167,8 @@ of Contents</A></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="#NormSetBackoffFactor()">NormSetBackoffFactor()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetGroupSize()">NormSetGroupSize()</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>
@ -234,7 +239,8 @@ 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 may also be provided in the future</I>.)</P> of the NORM protocol engine code <U>may</U> 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>
@ -248,16 +254,16 @@ categories roughly reflects the order of function calls required to
use NORM in an application. The first step is to create and use NORM in an application. The first step is to create and
initialize, as needed, at least one instance of the NORM API. Then initialize, as needed, at least one instance of the NORM API. Then
one or more NORM transport sessions (where a “session” one or more NORM transport sessions (where a “session”
corresponds to data exchanges on a given multicast group and host corresponds to data exchanges on a given multicast group (or unicast
port number) may be created and controlled. Applications may address) and host port number) may be created and controlled.
participate as senders and/or receivers within a NORM session. NORM Applications may participate as senders and/or receivers within a
senders transmit data to the session destination address (usually an NORM session. NORM senders transmit data to the session destination
IP multicast group) while receivers are notified of incoming data. address (usually an IP multicast group) while receivers are notified
The NORM API provides and event notification scheme to notify the of incoming data. The NORM API provides and event notification
application of significant sender and receiver events. There are scheme to notify the application of significant sender and receiver
also a number support functions provided for the application to events. There are also a number support functions provided for the
control and monitor its participation within a NORM transport application to control and monitor its participation within a NORM
session.</P> transport session.</P>
<H2 CLASS="western"><A NAME="API Initialization">API Initialization</A></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
@ -271,9 +277,9 @@ mechanism.
single thread should access the <FONT FACE="Courier"><A HREF="#NormGetNextEvent()">NormGetNextEvent()</A></FONT> single thread should access the <FONT FACE="Courier"><A HREF="#NormGetNextEvent()">NormGetNextEvent()</A></FONT>
API call for a given <FONT FACE="Courier">NormInstance</FONT>. This API call for a given <FONT FACE="Courier">NormInstance</FONT>. This
function serves as the conduit for delivering NORM protocol engine function serves as the conduit for delivering NORM protocol engine
events to the application. While a NORM application can be designed events to the application. A NORM application can be designed to be
to be single-threaded, even with multiple active <I>NormSessions</I>, single-threaded, even with multiple active <I>NormSessions</I>, but
multiple API instances can be created (see <FONT FACE="Courier"><A HREF="#NormCreateInstance()">NormCreateInstance()</A></FONT>) also multiple API instances can be created (see <FONT FACE="Courier"><A HREF="#NormCreateInstance()">NormCreateInstance()</A></FONT>)
as needed for applications with specific requirements for accessing as needed for applications with specific requirements for accessing
and controlling participation in multiple <I>NormSessions</I> from and controlling participation in multiple <I>NormSessions</I> from
separate operating system multiple threads. Or, alternatively, a separate operating system multiple threads. Or, alternatively, a
@ -295,7 +301,7 @@ transport session instances as needed. The application can
participate in each session as a sender and/or receiver of data. If participate in each session as a sender and/or receiver of data. If
an application is participating as a sender, it may enqueue data an application is participating as a sender, it may enqueue data
transport objects for transmission. The control of transmission is transport objects for transmission. The control of transmission is
largely left to the sender and API calls are provided to control largely left to the senders and API calls are provided to control
transmission rate, FEC parameters, etc. Applications participating transmission rate, FEC parameters, etc. Applications participating
as receivers will be notified via the NORM API's event dispatching as receivers will be notified via the NORM API's event dispatching
mechanism of pending and completed reliable reception of data along mechanism of pending and completed reliable reception of data along
@ -531,12 +537,12 @@ build tools.</P>
NT4 (and perhaps other older Windows operating systems) requires that NT4 (and perhaps other older Windows operating systems) requires that
the compile time macro <FONT FACE="Courier"><I>WINVER=0x0400</I></FONT> the compile time macro <FONT FACE="Courier"><I>WINVER=0x0400</I></FONT>
defined. This is because the version of the IP Helper API library defined. This is because the version of the IP Helper API library
(<I>iphlpapi.lib</I>) used y Protolib (and hence NORM) for this (<I>iphlpapi.lib</I>) used by <I>Protolib</I> (and hence NORM) for
system doesn't support some of the functions defined for this 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 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 possible that the <I>Protolib</I> build could be tweaked to provide a
binary executable suitable for IPv4 operation only across a large single binary executable suitable for IPv4 operation only across a
range of Windows platforms.</P> large range of Windows platforms.</P>
<H1 CLASS="western"><A NAME="API Reference">API Reference</A></H1> <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>
@ -702,7 +708,7 @@ description).
</P> </P>
<H3 CLASS="functionheading-western"><A NAME="NormFlushMode">NormFlushMode</A></H3> <H3 CLASS="functionheading-western"><A NAME="NormFlushMode">NormFlushMode</A></H3>
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormFlushMode">NormFlushMode</A></FONT> <P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormFlushMode">NormFlushMode</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="#NormFlushMode">NormFlushMode</A><BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_FLUSH_NONE,<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_FLUSH_PASSIVE,<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_FLUSH_ACTIVE<BR>};</FONT></FONT></P> <A HREF="#NormFlushMode">NormFlushMode</A><BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_FLUSH_NONE,<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_FLUSH_PASSIVE,<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_FLUSH_ACTIVE<BR>};</FONT></FONT></P>
<P CLASS="western" STYLE="font-style: normal">The interpretation of <P CLASS="western" STYLE="font-style: normal">The interpretation of
@ -710,7 +716,7 @@ these values is given in the descriptions of <FONT FACE="Courier"><A HREF="#Nor
and <FONT FACE="Courier"><A HREF="#NormStreamSetAutoFlush()">NormStreamSetAutoFlush()</A></FONT> functions.</P> and <FONT FACE="Courier"><A HREF="#NormStreamSetAutoFlush()">NormStreamSetAutoFlush()</A></FONT> functions.</P>
<H3 CLASS="functionheading-western"><A NAME="NormProbingMode">NormProbingMode</A></H3> <H3 CLASS="functionheading-western"><A NAME="NormProbingMode">NormProbingMode</A></H3>
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormProbingMode">NormProbingMode</A></FONT> <P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormProbingMode">NormProbingMode</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="#NormProbingMode">NormProbingMode</A><BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_PROBE_NONE,<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_PROBE_PASSIVE,<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_PROBE_ACTIVE<BR>};</FONT></FONT></P> <A HREF="#NormProbingMode">NormProbingMode</A><BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_PROBE_NONE,<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_PROBE_PASSIVE,<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_PROBE_ACTIVE<BR>};</FONT></FONT></P>
<P CLASS="western" STYLE="font-style: normal">The interpretation of <P CLASS="western" STYLE="font-style: normal">The interpretation of
@ -802,6 +808,57 @@ has retained (see <FONT FACE="Courier"><A HREF="#NormObjectRetain()">NormObjectR
<H4 CLASS="western">Return Values</H4> <H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">The function has no <P CLASS="western" STYLE="font-style: normal">The function has no
return value.</P> return value.</P>
<H3 CLASS="functionheading-western"><A NAME="NormStopInstance()">NormStopInstance()</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
NormStopInstance(<A HREF="#NormInstanceHandle">NormInstanceHandle</A> instance);</FONT></FONT></P>
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function
immediately stops the NORM protocol engine thread corresponding to
the given <FONT FACE="Courier"><U>instance</U></FONT> parameter. It
also posts a &quot;dummy&quot; notification event so that if another
thread is blocked on a call to <FONT FACE="Courier"><A HREF="#NormGetNextEvent()">NormGetNextEvent()</A></FONT>,
that thread will be released. Hence, for some multithreaded uses of
the NORM API, this function may be useful as a preliminary step to
safely coordinate thread shutdown before a call is made to
<FONT FACE="Courier"><A HREF="#NormDestroyInstance()">NormDestroyInstance()</A></FONT>. After
<FONT FACE="Courier"><A HREF="#NormStopInstance()">NormStopInstance()</A></FONT> is called and any
pending events posted prior to its call have been retrieved,
<FONT FACE="Courier"><A HREF="#NormGetNextEvent()">NormGetNextEvent()</A></FONT> will return a value of
<FONT FACE="Courier"><I>false</I></FONT>.</P>
<P CLASS="western" STYLE="font-style: normal">When this function is
invoked, state for any <I>NormSessions</I> associated with the given
<FONT FACE="Courier"><U>instance</U></FONT> is &quot;frozen&quot;.
The complementary function, <FONT FACE="Courier"><A HREF="#NormRestartInstance()">NormRestartInstance()</A></FONT>
can be subsequently used to &quot;unfreeze&quot; and resume NORM
protocol operation (a new thread is created and started).</P>
<H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">The function has no
return value.</P>
<H3 CLASS="functionheading-western"><A NAME="NormRestartInstance()">NormRestartInstance()</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
NormRestartInstance(<A HREF="#NormInstanceHandle">NormInstanceHandle</A> instance);</FONT></FONT></P>
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function creates
and starts an operating system thread to resume NORM protocol engine
operation for the given <FONT FACE="Courier"><U>instance</U></FONT>
that was previously stopped by a call to <FONT FACE="Courier"><A HREF="#NormStopInstance()">NormStopInstance()</A></FONT>.
It is not expected that this function will be used often, but there
may be special application cases where &quot;freezing&quot; and later
resuming NORM protocol operation may be useful.
</P>
<H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">The function returns
<FONT FACE="Courier"><I>true</I></FONT> when the NORM protocol engine
thread is successfully restarted, and <FONT FACE="Courier"><I>false</I></FONT>
otherwise.</P>
<P CLASS="western" STYLE="font-style: normal"><BR>
</P>
<H3 CLASS="functionheading-western"><A NAME="NormSetCacheDirectory()">NormSetCacheDirectory()</A></H3> <H3 CLASS="functionheading-western"><A NAME="NormSetCacheDirectory()">NormSetCacheDirectory()</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
@ -1142,7 +1199,7 @@ even when no event is pending. In these cases, the return value is
provide an option to have a user-defined Window message posted when a provide an option to have a user-defined Window message posted when a
NORM API event is pending. (Also some event filtering calls may be NORM API event is pending. (Also some event filtering calls may be
provided (e.g. avoid the potentially numerous <FONT FACE="Courier"><I>NORM_RX_OBJECT_UPDATED</I></FONT> provided (e.g. avoid the potentially numerous <FONT FACE="Courier"><I>NORM_RX_OBJECT_UPDATED</I></FONT>
events if undesired)).</P> events if not needed by the application)).</P>
<H3 CLASS="functionheading-western"><A NAME="NormGetDescriptor()">NormGetDescriptor()</A></H3> <H3 CLASS="functionheading-western"><A NAME="NormGetDescriptor()">NormGetDescriptor()</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
@ -1172,6 +1229,14 @@ returned which is valid until a call to <FONT FACE="Courier"><A HREF="#NormDestr
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"><A NAME="Session Creation and Control Functions">Session Creation and Control Functions</A></H2> <H2 CLASS="western"><A NAME="Session Creation and Control Functions">Session Creation and Control Functions</A></H2>
<P CLASS="western" STYLE="font-style: normal">Whether participating
in a NORM protocol session as a sender, receiver, or both, there are
some common API calls used to instantiate a <I>NormSession</I> and
set some common session parameters. Functions are provided to
control network socket and multicast parameters. Additionally, a
&quot;user data&quot; value may be associated with a
<FONT FACE="Courier"><A HREF="#NormSessionHandle">NormSessionHandle</A></FONT> for programming
convenience when dealing with multiple sessions.</P>
<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
@ -1182,20 +1247,21 @@ char*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;address,<BR>&nbsp;&nbsp;&nb
short&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;port,<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;<A HREF="#NormNodeId">NormNodeId</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;localId);</FONT></FONT></P> short&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;port,<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;<A HREF="#NormNodeId">NormNodeId</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;localId);</FONT></FONT></P>
<H4 CLASS="western">Description</H4> <H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function creates a <P CLASS="western" STYLE="font-style: normal">This function creates a
NORM reliable multicast session (<I>NormSession</I>) using the NORM protocol session (<I>NormSession</I>) using the address
address parameters provided. While session state is allocated and (multicast or unicast) parameters provided. While session state is
initialized, active session participation does not begin until a call allocated and initialized, active session participation does not
is made to <FONT FACE="Courier"><A HREF="#NormStartSender()">NormStartSender()</A></FONT> and/or begin until a call is made to <FONT FACE="Courier"><A HREF="#NormStartSender()">NormStartSender()</A></FONT>
<FONT FACE="Courier"><A HREF="#NormStartReceiver()">NormStartReceiver()</A></FONT> to join the specified and/or <FONT FACE="Courier"><A HREF="#NormStartReceiver()">NormStartReceiver()</A></FONT> to join the
multicast group (if applicable) and start protocol operation. The specified multicast group (if applicable) and start protocol
following parameters are required in this function call:</P> operation. The following parameters are required in this function
call:</P>
<TABLE WIDTH=590 BORDER=0 CELLPADDING=7 CELLSPACING=0> <TABLE WIDTH=590 BORDER=0 CELLPADDING=7 CELLSPACING=0>
<COL WIDTH=101> <COL WIDTH=101>
<COL WIDTH=461> <COL WIDTH=461>
<TR VALIGN=TOP> <TR VALIGN=TOP>
<TD WIDTH=101> <TD WIDTH=101>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid"> <P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
<FONT FACE="Courier">instance</FONT></P> <FONT FACE="Courier"><U>instance</U></FONT></P>
</TD> </TD>
<TD WIDTH=461> <TD WIDTH=461>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid"> <P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
@ -1206,7 +1272,7 @@ following parameters are required in this function call:</P>
<TR VALIGN=TOP> <TR VALIGN=TOP>
<TD WIDTH=101> <TD WIDTH=101>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid"> <P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
<FONT FACE="Courier">address</FONT></P> <FONT FACE="Courier"><U>address</U></FONT></P>
</TD> </TD>
<TD WIDTH=461> <TD WIDTH=461>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid"> <P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
@ -1228,7 +1294,7 @@ following parameters are required in this function call:</P>
<TR VALIGN=TOP> <TR VALIGN=TOP>
<TD WIDTH=101> <TD WIDTH=101>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid"> <P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
<FONT FACE="Courier">port</FONT></P> <FONT FACE="Courier"><U>port</U></FONT></P>
</TD> </TD>
<TD WIDTH=461> <TD WIDTH=461>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid"> <P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
@ -1240,7 +1306,7 @@ following parameters are required in this function call:</P>
<TR VALIGN=TOP> <TR VALIGN=TOP>
<TD WIDTH=101> <TD WIDTH=101>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid"> <P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
<FONT FACE="Courier">localId</FONT></P> <FONT FACE="Courier"><U>localId</U></FONT></P>
</TD> </TD>
<TD WIDTH=461> <TD WIDTH=461>
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid"> <P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
@ -1378,27 +1444,27 @@ 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
NormSetRxPortReuse(<A HREF="#NormSessionHandle">NormSessionHandle</A> NormSetRxPortReuse(<A HREF="#NormSessionHandle">NormSessionHandle</A>
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;bool 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;bool&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enable,<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;bool&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bindToSessionAddr
state);</FONT></FONT></P> = true);</FONT></FONT></P>
<H4 CLASS="western">Description</H4> <H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function allows <P CLASS="western" STYLE="font-style: normal">This function allows
the user to control the port reuse and binding behavior for the the user to control the port reuse and binding behavior for the
receive socket used for the given NORM <FONT FACE="Courier"><U>session</U></FONT>. receive socket used for the given NORM <FONT FACE="Courier"><U>session</U></FONT>.
When the <FONT FACE="Courier"><U>state</U></FONT> parameter is set When the <FONT FACE="Courier"><U>enable</U></FONT> parameter is set
to <FONT FACE="Courier"><I>true</I></FONT>:</P> to <FONT FACE="Courier"><I>true</I></FONT>, reuse of the <I>NormSession</I>
<OL> port number is enabled, and, if the <FONT FACE="Courier"><U>bindToSessionAddr</U></FONT>
<LI><P CLASS="western" STYLE="font-style: normal">Reuse of the is also set to <FONT FACE="Courier"><I>true</I></FONT> (default), the
<I>NormSession</I> port number is enabled, and</P> underlying socket is also bound (see the <FONT FACE="Courier">bind()</FONT>
<LI><P CLASS="western" STYLE="font-style: normal">the underlying system call) to the <I>NormSession</I> destination address instead of
socket is also bound (see the <FONT FACE="Courier">bind()</FONT> the default behavior of binding to INADDR_ANY.
system call) to the <I>NormSession</I> destination address instead </P>
of the default behavior of binding to INADDR_ANY. <P CLASS="western" STYLE="font-style: normal">When this call is not
</P> made, the default binding to IP address INADDR_ANY (equivalent to
</OL> when this call is made and <FONT FACE="Courier"><U>bindToSessionAddr</U></FONT>
<P CLASS="western" STYLE="font-style: normal">The default binding to is set to <FONT FACE="Courier"><I>false</I></FONT>) allows the
INADDR_ANY (<FONT FACE="Courier"><U>state</U></FONT> equals <FONT FACE="Courier"><I>false</I></FONT>) <I>NormSession</I> receive socket to receive <I>any</I> multicast or
allows the <I>NormSession</I> receive socket to receive any multicast unicast transmissions to the session port number provided in the call
or unicast transmissions to the given port number. This allows a to <FONT FACE="Courier"><A HREF="#NormCreateSession()">NormCreateSession()</A></FONT>. This allows a
NORM receiver to receive from senders sending to a multicast session NORM receiver to receive from senders sending to a multicast session
address or the receiver's unicast address. Enabling port reuse and address or the receiver's unicast address. Enabling port reuse and
binding the session destination address allows multiple NORM sessions binding the session destination address allows multiple NORM sessions
@ -1531,7 +1597,16 @@ 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"><A NAME="NORM Sender Functions">NORM Sender Functions</A></H2> <H2 CLASS="western"><A NAME="NORM<SPAN STYLE="font-style: normal"> </SPAN>Sender
Functions">NORM<SPAN STYLE="font-style: normal"> </SPAN>Sender
Functions</A></H2>
<P CLASS="western" STYLE="font-style: normal">The functions described
in this section apply only to NORM sender operation. Applications
may participate strictly as senders or as receivers, or may act as
both in the context of a NORM protocol session. The NORM sender is
responsible for most parameters pertaining to its transmission of
data. This includes transmission rate, data segmentation sizes, FEC
coding parameters, stream buffer sizes, etc.</P>
<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
@ -2112,6 +2187,75 @@ 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="NormSetBackoffFactor()">NormSetBackoffFactor()</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
NormSetBackoffFactor(<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;double&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;backoffFactor);</FONT></FONT></P>
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal"><A NAME="OLE_LINK3"></A><A NAME="OLE_LINK2"></A>
This function sets the sender's &quot;backoff factor&quot; for the
given <FONT FACE="Courier"><U>session</U></FONT>.. The backoff
factor is used to scale various timeouts related to the NACK repair
process. The sender advertises its backoff factor setting to the
receiver group in NORM protocol message headers. The default backoff
factor for NORM sessions is <FONT FACE="Courier"><I>4.0</I></FONT>.
The backoff factor is used to determine the maximum time that
receivers may delay NACK transmissions (and other feedback messages)
as part of NORM's probabilistic feedback suppression technique. For
example, the maximum NACK delay time is <FONT FACE="Courier"><U>backoffFactor</U></FONT><FONT FACE="Courier">*GRTT</FONT>.
Thus a large <FONT FACE="Courier"><U>backoffFactor</U></FONT> value
introduces latency into the NORM repair process. However, a small
<FONT FACE="Courier"><U>backoffFactor</U></FONT> value causes
feedback suppression to be less effective and increases the risk of
feedback implosion for large receiver group sizes. The default
setting of <FONT FACE="Courier"><I>4.0</I></FONT> provides reasonable
feedback suppression for moderate to large group sizes when multicast
feedback is possible. The NORM specification recommends a backoff
factor value of <FONT FACE="Courier"><I>6.0</I></FONT> when unicast
feedback is used. However, for demanding applications (with respect
to repair latency) when group sizes are modest, a small (even <FONT FACE="Courier"><I>0.0</I></FONT>)
<FONT FACE="Courier"><U>backoffFactor</U></FONT> value can be
specified to reduce the latency of reliable data delivery.</P>
<H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">This function has no
return values.</P>
<H3 CLASS="functionheading-western"><A NAME="NormSetGroupSize()">NormSetGroupSize()</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
NormSetGroupSize(<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;unsigned
int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;groupSize);</FONT></FONT></P>
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function sets the
sender's estimate of receiver group size for the given session. The
sender advertises its group size setting to the receiver group in
NORM protocol message headers that, in turn, use this information to
shape the distribution curve of their random timeouts for the
timer-based, probabilistic feedback suppression technique used in the
NORM protocol. Note that the <FONT FACE="Courier"><U>groupSize</U></FONT>
estimate does not have to be very accurate and values within an order
of magnitude of the actual group size tend to produce acceptable
performance. The default group size setting in NORM is <FONT FACE="Courier"><I>1,000</I></FONT>
and thus can work well for a wide range of actual receiver group
sizes. The penalty of an overly large estimate is statistically a
little more latency in reliable data delivery with respect to the
round trip time and some potential for excess feedback. A
substantial underestimation of group size increases the risk of
feedback implosion. Currently, the NORM implementation does not
attempt to automatically measure group size from receiver feedback.
Applications could add their own mechanism for this (perhaps keeping
explicit track of group membership), or it is possible that future
versions of the NRL NORM implementation may have some provision for
automatic group size estimation by the sender based on receiver
feedback messages.</P>
<H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">This function has no
return values.</P>
<H3 CLASS="functionheading-western"><A NAME="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
@ -2392,22 +2536,36 @@ previously enqueued data pending transmission (original or repair)
being dropped by the NORM protocol engine. While NORM NACK-based being dropped by the NORM protocol engine. While NORM NACK-based
reliability does not provide explicit flow control, there is some 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. Other flow control strategies are
</P> possible using the <FONT FACE="Courier"><A HREF="#NormSetWatermark()">NormSetWatermark()</A></FONT>
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormEvent">NormEvent</A></FONT> function.</P>
NORM_TX_QUEUE_VACANCY is posted with its <I><A HREF="#NormEvent">NormEvent</A>::object</I> <P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier">NormEvents
field set to a valid sender stream <FONT FACE="Courier"><A HREF="#NormObjectHandle">NormObjectHandle</A></FONT> </FONT><FONT FACE="Courier"><I>NORM_TX_QUEUE_EMPTY</I></FONT> and
to indicate when the stream is ready for writing via this function. <FONT FACE="Courier"><I>NORM_TX_QUEUE_VACANCY</I></FONT> are posted
Note that, after this event type is posted, the application <I>must</I> with the <I><A HREF="#NormEvent">NormEvent</A>::object</I> field set to a valid sender stream
make a call to <FONT FACE="Courier"><A HREF="#NormStreamWrite()">NormStreamWrite()</A></FONT> with a <FONT FACE="Courier"><A HREF="#NormObjectHandle">NormObjectHandle</A></FONT> to indicate when the
non-zero <FONT FACE="Courier"><U>numBytes</U></FONT> value before stream is ready for writing via this function. Note that the
addition NORM_TX_QUEUE_VACANCY events are posted for the given <FONT FACE="Courier"><I>NORM_TX_QUEUE_VACANCY </I></FONT>event type
<FONT FACE="Courier"><U>streamHandle</U></FONT>.</P> is posted <I>only after</I> the stream's transmit buffer has been
completely filled. Thus, the application <I>must</I> make a call to
<FONT FACE="Courier"><A HREF="#NormStreamWrite()">NormStreamWrite()</A></FONT> that copies less than
the requested <FONT FACE="Courier"><U>numBytes</U></FONT> value
(return value less than <FONT FACE="Courier"><U>numBytes</U></FONT>)
before additional <FONT FACE="Courier"><I>NORM_TX_QUEUE_VACANCY</I></FONT>
events are posted for the given <FONT FACE="Courier"><U>streamHandle</U></FONT>
(i.e., the event type is not re-posted until the application has
again filled the available stream transmit buffer space). By cueing
off of <FONT FACE="Courier"><I>NORM_TX_QUEUE_EMPTY</I></FONT>, the
application can write its &quot;freshest&quot; available data to the
stream, but by cueing off of <FONT FACE="Courier"><I>NORM_TX_QUEUE_VACANCY</I></FONT>,
an application can keep the NORM protocol engine busiest, to achieve
the maximum possible throughput at high data rates.</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. If the underlying send stream buffer is full, this transmission. If the underlying send stream buffer is full, this
function may return zero. function may return zero or a value less than the requested <FONT FACE="Courier"><U>numBytes</U></FONT>.
</P> </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>

Binary file not shown.

42
TODO.TXT Normal file
View File

@ -0,0 +1,42 @@
0) Fix implementation of NORM_DATA_FLAG_REPAIR.
1) Implement unicast feedback of NACK messages and server
re-advertisement for suppressing the unicast feedback.
(COMPLETED)
2) Add mechanism to allow window-based control of NORM server
transmission rate.
3) Implement TFMCC and/or PGM-CC congestion control mechanisms
within NORM. (TFMCC COMPLETED)
4) A single squelch message should be sent per repair cycle?
The squelch works to "synchronize" clients to the server
repair window. As the code is currently implemented, the
server might generate a squelch per NACK. This might be OK
since the occurrence of squelch _should_ be rare. The
debug statistics should keep a count of squelch events.
(COMPLETED)
5) Implement positive acknowledgement mechanism per the NORM spec.
(COMPLETED - needs more testing)
6) Implement and document simple API to control and access NORM
features. (COMPLETED and enhancement in progress)
7) Build "norm daemon" using API.
8) JAVA API for NRL NORM Protocol library
9) Correct/complete user guide for "norm" demo app
10) Release wxNormChat project
11) Test, release "naft" (updated "raft") for reliable streaming.
12) Can we eliminate rapid clr norm-cc probing when data is
not being actively sent? (COMPLETED)

View File

@ -1,5 +1,38 @@
NORM Version History NORM Version History
Version 1.3b7
=============
- Deprecated NORM stream payload flags in favor of "payload_msg_start"
field per revised NORM specification (draft-ietf-rmt-pi-nom-revised-00)
This included interpreting NORM_DATA (source segment) messages for
NORM_OBJECT_STREAM with "payload_len" field value of ZERO as
"stream control" messages where the "payload_msg_start" field serves
as the stream control message type indications. The "End-of-Stream"
control message consists of "payload_msg_start" = 0
when "payload_len" = 0. No other stream control messages are yet
defined. The next revision of the NORM spec will describe this.
(Thus for NORM stream purposes, this NORM version is _not_ interoperable
with previous versions)
- Fixed problem where NormServerNode "retrieval_pool" had allocated
segments one byte too small (although this is OBE with the above
deprecation of stream flags which is what the byte was used for)
- Fixed bug where sender objects were not properly "closed" when the
object table was cleaned upon NormStopSender()
- Added support to VC++ .Net workspace for building "Norm.dll"
(NORM as a dynamic linked library) and similarly added option
to build "libnorm.dylib" for MacOS. ("libnorm.so" for other
Unix platforms should already work).
- Fixed NormSetTOS() call.
- Added option to NormSetPortReuse() to maintain INADDR_ANY binding
if desired.
- Refined management of NORM sender stream buffer so sender wouldn't
prematurely discard buffer stream blocks when alot of small
segments (smaller than segment_size) were buffered.
- Added NormStopInstance() call to provide means for multi-threaded
NORM apps to stop the NORM protocol engine and awake any other thread
blocked on NormGetNextEvent() to signal shutdown of NormInstance.
- Also updated code so ns-2 build works and tested w/ ns-2.29
Version 1.3b6 Version 1.3b6
============= =============
- Fixed some oversite bugs that crept in with changes in 1.3b5 - Fixed some oversite bugs that crept in with changes in 1.3b5

View File

@ -1,3 +1,4 @@
#define _NORM_API_BUILD // force 'dllexport' in "normApi.h"
#include "normApi.h" #include "normApi.h"
#include "normSession.h" #include "normSession.h"
@ -8,15 +9,23 @@
#endif // WIN32 #endif // WIN32
// const defs // const defs
extern NORM_API_LINKAGE
const NormInstanceHandle NORM_INSTANCE_INVALID = ((NormInstanceHandle)0); const NormInstanceHandle NORM_INSTANCE_INVALID = ((NormInstanceHandle)0);
extern NORM_API_LINKAGE
const NormSessionHandle NORM_SESSION_INVALID = ((NormSessionHandle)0); const NormSessionHandle NORM_SESSION_INVALID = ((NormSessionHandle)0);
extern NORM_API_LINKAGE
const NormNodeHandle NORM_NODE_INVALID = ((NormNodeHandle)0); const NormNodeHandle NORM_NODE_INVALID = ((NormNodeHandle)0);
extern NORM_API_LINKAGE
const NormNodeId NORM_NODE_NONE = ((NormNodeId)0x00000000); const NormNodeId NORM_NODE_NONE = ((NormNodeId)0x00000000);
extern NORM_API_LINKAGE
const NormNodeId NORM_NODE_ANY = ((NormNodeId)0xffffffff); const NormNodeId NORM_NODE_ANY = ((NormNodeId)0xffffffff);
extern NORM_API_LINKAGE
const NormObjectHandle NORM_OBJECT_INVALID = ((NormObjectHandle)0); const NormObjectHandle NORM_OBJECT_INVALID = ((NormObjectHandle)0);
extern NORM_API_LINKAGE
const NormDescriptor NORM_DESCRIPTOR_INVALID = ProtoDispatcher::INVALID_DESCRIPTOR; const NormDescriptor NORM_DESCRIPTOR_INVALID = ProtoDispatcher::INVALID_DESCRIPTOR;
/** The "NormInstance" class is a C++ helper class that keeps /** The "NormInstance" class is a C++ helper class that keeps
* state for an instance of the NORM API. It acts as a * state for an instance of the NORM API. It acts as a
* "go between" the API's procedural function calls and * "go between" the API's procedural function calls and
@ -37,6 +46,24 @@ class NormInstance : public NormController
bool Startup(bool priorityBoost = false); bool Startup(bool priorityBoost = false);
void Shutdown(); void Shutdown();
void Pause() // pause NORM protocol engine
{
dispatcher.Stop();
Notify(NormController::EVENT_INVALID, &session_mgr, NULL, NULL, NULL);
}
bool Resume()
{
if (dispatcher.StartThread(priority_boost))
{
return true;
}
else
{
DMSG(0, "NormInstance::Resume() error restarting NORM thread\n");
return false;
}
}
bool WaitForEvent(); bool WaitForEvent();
bool GetNextEvent(NormEvent* theEvent); bool GetNextEvent(NormEvent* theEvent);
bool SetCacheDirectory(const char* cachePath); bool SetCacheDirectory(const char* cachePath);
@ -63,7 +90,6 @@ class NormInstance : public NormController
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;
//return static_cast<NormInstance*>(session->GetSessionMgr().GetController());
} }
static NormInstance* GetInstanceFromNode(NormNodeHandle nodeHandle) static NormInstance* GetInstanceFromNode(NormNodeHandle nodeHandle)
{ {
@ -126,6 +152,7 @@ class NormInstance : public NormController
}; // end class NormInstance::Notification }; // end class NormInstance::Notification
ProtoDispatcher dispatcher; ProtoDispatcher dispatcher;
bool priority_boost;
NormSessionMgr session_mgr; NormSessionMgr session_mgr;
private: private:
@ -165,7 +192,8 @@ void NormInstance::Notification::Queue::Destroy()
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
// NormInstance implementation // NormInstance implementation
NormInstance::NormInstance() NormInstance::NormInstance()
: session_mgr(static_cast<ProtoTimerMgr&>(dispatcher), : priority_boost(false),
session_mgr(static_cast<ProtoTimerMgr&>(dispatcher),
static_cast<ProtoSocket::Notifier&>(dispatcher)), static_cast<ProtoSocket::Notifier&>(dispatcher)),
previous_notification(NULL), rx_cache_path(NULL) previous_notification(NULL), rx_cache_path(NULL)
{ {
@ -188,7 +216,7 @@ bool NormInstance::SetCacheDirectory(const char* cachePath)
bool result = false; bool result = false;
if (dispatcher.SuspendThread()) if (dispatcher.SuspendThread())
{ {
int length = strlen(cachePath); size_t length = strlen(cachePath);
if (PROTO_PATH_DELIMITER != cachePath[length-1]) if (PROTO_PATH_DELIMITER != cachePath[length-1])
length += 2; length += 2;
else else
@ -481,6 +509,11 @@ bool NormInstance::GetNextEvent(NormEvent* theEvent)
bool NormInstance::WaitForEvent() bool NormInstance::WaitForEvent()
{ {
if (!dispatcher.IsThreaded())
{
DMSG(0, "NormInstance::WaitForEvent() warning: NORM thread not running!\n");
return false;
}
#ifdef WIN32 #ifdef WIN32
WaitForSingleObject(notify_event, INFINITE); WaitForSingleObject(notify_event, INFINITE);
#else #else
@ -537,6 +570,7 @@ bool NormInstance::Startup(bool priorityBoost)
} }
#endif // if/else WIN32/UNIX #endif // if/else WIN32/UNIX
// 2) Start thread // 2) Start thread
priority_boost = priorityBoost;
return dispatcher.StartThread(priorityBoost); return dispatcher.StartThread(priorityBoost);
} // end NormInstance::Startup() } // end NormInstance::Startup()
@ -637,6 +671,7 @@ unsigned long NormInstance::CountCompletedObjects(NormSession* session)
/** NORM API Initialization */ /** NORM API Initialization */
NORM_API_LINKAGE
NormInstanceHandle NormCreateInstance(bool priorityBoost) NormInstanceHandle NormCreateInstance(bool priorityBoost)
{ {
NormInstance* normInstance = new NormInstance; NormInstance* normInstance = new NormInstance;
@ -650,11 +685,35 @@ NormInstanceHandle NormCreateInstance(bool priorityBoost)
return NORM_INSTANCE_INVALID; return NORM_INSTANCE_INVALID;
} // end NormCreateInstance() } // end NormCreateInstance()
NORM_API_LINKAGE
void NormDestroyInstance(NormInstanceHandle instanceHandle) void NormDestroyInstance(NormInstanceHandle instanceHandle)
{ {
delete ((NormInstance*)instanceHandle); delete ((NormInstance*)instanceHandle);
} // end NormDestroyInstance() } // end NormDestroyInstance()
NORM_API_LINKAGE
bool NormRestartInstance(NormInstanceHandle instanceHandle)
{
NormInstance* instance = (NormInstance*)instanceHandle;
if (instance)
{
if (instance->dispatcher.IsThreaded())
instance->Pause();
return instance->Resume();
}
return false; // invalid instanceHandle
} // end NormStartInstance()
NORM_API_LINKAGE
void NormStopInstance(NormInstanceHandle instanceHandle)
{
NormInstance* instance = (NormInstance*)instanceHandle;
if (instance) instance->Pause(); // stops NORM protocol thread
} // end NormStopInstance()
NORM_API_LINKAGE
bool NormSetCacheDirectory(NormInstanceHandle instanceHandle, bool NormSetCacheDirectory(NormInstanceHandle instanceHandle,
const char* cachePath) const char* cachePath)
{ {
@ -665,6 +724,7 @@ bool NormSetCacheDirectory(NormInstanceHandle instanceHandle,
return false; return false;
} // end NormSetCacheDirectory() } // end NormSetCacheDirectory()
NORM_API_LINKAGE
NormDescriptor NormGetDescriptor(NormInstanceHandle instanceHandle) NormDescriptor NormGetDescriptor(NormInstanceHandle instanceHandle)
{ {
NormInstance* instance = (NormInstance*)instanceHandle; NormInstance* instance = (NormInstance*)instanceHandle;
@ -675,6 +735,7 @@ NormDescriptor NormGetDescriptor(NormInstanceHandle instanceHandle)
} // end NormGetDescriptor() } // end NormGetDescriptor()
// (TBD) add a timeout option to this? // (TBD) add a timeout option to this?
NORM_API_LINKAGE
bool NormGetNextEvent(NormInstanceHandle instanceHandle, NormEvent* theEvent) bool NormGetNextEvent(NormInstanceHandle instanceHandle, NormEvent* theEvent)
{ {
bool result = false; bool result = false;
@ -682,7 +743,12 @@ bool NormGetNextEvent(NormInstanceHandle instanceHandle, NormEvent* theEvent)
if (instance) if (instance)
{ {
if (instance->NotifyQueueIsEmpty()) //(TBD) perform this check??? if (instance->NotifyQueueIsEmpty()) //(TBD) perform this check???
instance->WaitForEvent(); {
if (!instance->WaitForEvent())
{
return false;
}
}
if (instance->dispatcher.SuspendThread()) if (instance->dispatcher.SuspendThread())
{ {
result = instance->GetNextEvent(theEvent); result = instance->GetNextEvent(theEvent);
@ -695,6 +761,7 @@ bool NormGetNextEvent(NormInstanceHandle instanceHandle, NormEvent* theEvent)
/** NORM Session Creation and Control Functions */ /** NORM Session Creation and Control Functions */
NORM_API_LINKAGE
NormSessionHandle NormCreateSession(NormInstanceHandle instanceHandle, NormSessionHandle NormCreateSession(NormInstanceHandle instanceHandle,
const char* sessionAddr, const char* sessionAddr,
unsigned short sessionPort, unsigned short sessionPort,
@ -711,6 +778,7 @@ NormSessionHandle NormCreateSession(NormInstanceHandle instanceHandle,
return NORM_SESSION_INVALID; return NORM_SESSION_INVALID;
} // end NormCreateSession() } // end NormCreateSession()
NORM_API_LINKAGE
void NormDestroySession(NormSessionHandle sessionHandle) void NormDestroySession(NormSessionHandle sessionHandle)
{ {
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
@ -729,6 +797,7 @@ void NormDestroySession(NormSessionHandle sessionHandle)
} }
} // end NormDestroySession() } // end NormDestroySession()
NORM_API_LINKAGE
void NormSetUserData(NormSessionHandle sessionHandle, const void* userData) void NormSetUserData(NormSessionHandle sessionHandle, const void* userData)
{ {
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
@ -743,6 +812,7 @@ void NormSetUserData(NormSessionHandle sessionHandle, const void* userData)
} }
} // end NormSetUserData() } // end NormSetUserData()
NORM_API_LINKAGE
const void* NormGetUserData(NormSessionHandle sessionHandle) const void* NormGetUserData(NormSessionHandle sessionHandle)
{ {
const void* userData = NULL; const void* userData = NULL;
@ -760,6 +830,7 @@ const void* NormGetUserData(NormSessionHandle sessionHandle)
return userData; return userData;
} // end NormGetUserData() } // end NormGetUserData()
NORM_API_LINKAGE
NormNodeId NormGetLocalNodeId(NormSessionHandle sessionHandle) NormNodeId NormGetLocalNodeId(NormSessionHandle sessionHandle)
{ {
NormSession* session = (NormSession*)sessionHandle; NormSession* session = (NormSession*)sessionHandle;
@ -769,6 +840,7 @@ NormNodeId NormGetLocalNodeId(NormSessionHandle sessionHandle)
return NORM_NODE_NONE; return NORM_NODE_NONE;
} // end NormGetLocalNodeId() } // end NormGetLocalNodeId()
NORM_API_LINKAGE
void NormSetTxPort(NormSessionHandle sessionHandle, void NormSetTxPort(NormSessionHandle sessionHandle,
unsigned short txPort) unsigned short txPort)
{ {
@ -784,8 +856,10 @@ void NormSetTxPort(NormSessionHandle sessionHandle,
} }
} // end NormSetTxPort() } // end NormSetTxPort()
NORM_API_LINKAGE
void NormSetRxPortReuse(NormSessionHandle sessionHandle, void NormSetRxPortReuse(NormSessionHandle sessionHandle,
bool state) bool enable,
bool bindToSessionAddress)
{ {
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
if (NULL != instance) if (NULL != instance)
@ -793,12 +867,13 @@ void NormSetRxPortReuse(NormSessionHandle sessionHandle,
if (instance->dispatcher.SuspendThread()) if (instance->dispatcher.SuspendThread())
{ {
NormSession* session = (NormSession*)sessionHandle; NormSession* session = (NormSession*)sessionHandle;
if (session) session->SetRxPortReuse(state); if (session) session->SetRxPortReuse(enable, bindToSessionAddress);
instance->dispatcher.ResumeThread(); instance->dispatcher.ResumeThread();
} }
} }
} // end NormSetTxPort() } // end NormSetTxPort()
NORM_API_LINKAGE
bool NormSetMulticastInterface(NormSessionHandle sessionHandle, bool NormSetMulticastInterface(NormSessionHandle sessionHandle,
const char* interfaceName) const char* interfaceName)
{ {
@ -817,6 +892,7 @@ bool NormSetMulticastInterface(NormSessionHandle sessionHandle,
return result; return result;
} // end NormSetMulticastInterface() } // end NormSetMulticastInterface()
NORM_API_LINKAGE
bool NormSetTTL(NormSessionHandle sessionHandle, bool NormSetTTL(NormSessionHandle sessionHandle,
unsigned char ttl) unsigned char ttl)
{ {
@ -835,6 +911,7 @@ bool NormSetTTL(NormSessionHandle sessionHandle,
return result; return result;
} // end NormSetTTL() } // end NormSetTTL()
NORM_API_LINKAGE
bool NormSetTOS(NormSessionHandle sessionHandle, bool NormSetTOS(NormSessionHandle sessionHandle,
unsigned char tos) unsigned char tos)
{ {
@ -846,7 +923,7 @@ bool NormSetTOS(NormSessionHandle sessionHandle,
{ {
NormSession* session = (NormSession*)sessionHandle; NormSession* session = (NormSession*)sessionHandle;
if (session) if (session)
result = session->SetTTL(tos); result = session->SetTOS(tos);
instance->dispatcher.ResumeThread(); instance->dispatcher.ResumeThread();
} }
} }
@ -855,6 +932,7 @@ bool NormSetTOS(NormSessionHandle sessionHandle,
/** Special test/debug support functions */ /** Special test/debug support functions */
NORM_API_LINKAGE
bool NormSetLoopback(NormSessionHandle sessionHandle, bool state) bool NormSetLoopback(NormSessionHandle sessionHandle, bool state)
{ {
NormSession* session = (NormSession*)sessionHandle; NormSession* session = (NormSession*)sessionHandle;
@ -864,18 +942,21 @@ bool NormSetLoopback(NormSessionHandle sessionHandle, bool state)
return false; return false;
} // end NormSetLoopback() } // end NormSetLoopback()
NORM_API_LINKAGE
void NormSetMessageTrace(NormSessionHandle sessionHandle, bool state) void NormSetMessageTrace(NormSessionHandle sessionHandle, bool state)
{ {
NormSession* session = (NormSession*)sessionHandle; NormSession* session = (NormSession*)sessionHandle;
if (session) session->SetTrace(state); if (session) session->SetTrace(state);
} // end NormSetMessageTrace() } // end NormSetMessageTrace()
NORM_API_LINKAGE
void NormSetTxLoss(NormSessionHandle sessionHandle, double percent) void NormSetTxLoss(NormSessionHandle sessionHandle, double percent)
{ {
NormSession* session = (NormSession*)sessionHandle; NormSession* session = (NormSession*)sessionHandle;
if (session) session->SetTxLoss(percent); if (session) session->SetTxLoss(percent);
} // end NormSetTxLoss() } // end NormSetTxLoss()
NORM_API_LINKAGE
void NormSetRxLoss(NormSessionHandle sessionHandle, double percent) void NormSetRxLoss(NormSessionHandle sessionHandle, double percent)
{ {
NormSession* session = (NormSession*)sessionHandle; NormSession* session = (NormSession*)sessionHandle;
@ -885,6 +966,7 @@ void NormSetRxLoss(NormSessionHandle sessionHandle, double percent)
/** NORM Sender Functions */ /** NORM Sender Functions */
NORM_API_LINKAGE
bool NormStartSender(NormSessionHandle sessionHandle, bool NormStartSender(NormSessionHandle sessionHandle,
NormSessionId sessionId, NormSessionId sessionId,
unsigned long bufferSpace, unsigned long bufferSpace,
@ -906,6 +988,7 @@ bool NormStartSender(NormSessionHandle sessionHandle,
return result; return result;
} // end NormStartSender() } // end NormStartSender()
NORM_API_LINKAGE
void NormStopSender(NormSessionHandle sessionHandle) void NormStopSender(NormSessionHandle sessionHandle)
{ {
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
@ -917,6 +1000,17 @@ void NormStopSender(NormSessionHandle sessionHandle)
} }
} // end NormStopSender() } // end NormStopSender()
NORM_API_LINKAGE
double NormGetTransmitRate(NormSessionHandle sessionHandle)
{
if (NORM_SESSION_INVALID != sessionHandle)
return (((NormSession*)sessionHandle)->GetTxRate());
else
return -1.0;
} // end NormGetTransmitRate()
NORM_API_LINKAGE
void NormSetTransmitRate(NormSessionHandle sessionHandle, void NormSetTransmitRate(NormSessionHandle sessionHandle,
double bitsPerSecond) double bitsPerSecond)
{ {
@ -929,6 +1023,7 @@ void NormSetTransmitRate(NormSessionHandle sessionHandle,
} }
} // end NormSetTransmitRate() } // end NormSetTransmitRate()
NORM_API_LINKAGE
bool NormSetTxSocketBuffer(NormSessionHandle sessionHandle, bool NormSetTxSocketBuffer(NormSessionHandle sessionHandle,
unsigned int bufferSize) unsigned int bufferSize)
{ {
@ -944,6 +1039,7 @@ bool NormSetTxSocketBuffer(NormSessionHandle sessionHandle,
return result; return result;
} // end NormSetTxSocketBuffer() } // end NormSetTxSocketBuffer()
NORM_API_LINKAGE
void NormSetCongestionControl(NormSessionHandle sessionHandle, bool enable) void NormSetCongestionControl(NormSessionHandle sessionHandle, bool enable)
{ {
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
@ -955,6 +1051,7 @@ void NormSetCongestionControl(NormSessionHandle sessionHandle, bool enable)
} }
} // end NormSetCongestionControl() } // end NormSetCongestionControl()
NORM_API_LINKAGE
void NormSetTransmitRateBounds(NormSessionHandle sessionHandle, void NormSetTransmitRateBounds(NormSessionHandle sessionHandle,
double rateMin, double rateMin,
double rateMax) double rateMax)
@ -968,6 +1065,7 @@ void NormSetTransmitRateBounds(NormSessionHandle sessionHandle,
} }
} // end NormSetTransmitRateBounds() } // end NormSetTransmitRateBounds()
NORM_API_LINKAGE
void NormSetTransmitCacheBounds(NormSessionHandle sessionHandle, void NormSetTransmitCacheBounds(NormSessionHandle sessionHandle,
NormSize sizeMax, NormSize sizeMax,
unsigned long countMin, unsigned long countMin,
@ -983,6 +1081,7 @@ void NormSetTransmitCacheBounds(NormSessionHandle sessionHandle,
} }
} // end NormSetTransmitCacheBounds() } // end NormSetTransmitCacheBounds()
NORM_API_LINKAGE
void NormSetAutoParity(NormSessionHandle sessionHandle, unsigned char autoParity) void NormSetAutoParity(NormSessionHandle sessionHandle, unsigned char autoParity)
{ {
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
@ -994,6 +1093,7 @@ void NormSetAutoParity(NormSessionHandle sessionHandle, unsigned char autoParity
} }
} // end NormSetAutoParity() } // end NormSetAutoParity()
NORM_API_LINKAGE
void NormSetGrttEstimate(NormSessionHandle sessionHandle, void NormSetGrttEstimate(NormSessionHandle sessionHandle,
double grttEstimate) double grttEstimate)
{ {
@ -1006,6 +1106,7 @@ void NormSetGrttEstimate(NormSessionHandle sessionHandle,
} }
} // end NormSetGrttEstimate() } // end NormSetGrttEstimate()
NORM_API_LINKAGE
void NormSetGrttMax(NormSessionHandle sessionHandle, void NormSetGrttMax(NormSessionHandle sessionHandle,
double grttMax) double grttMax)
{ {
@ -1018,6 +1119,7 @@ void NormSetGrttMax(NormSessionHandle sessionHandle,
} }
} // end NormSetGrttMax() } // end NormSetGrttMax()
NORM_API_LINKAGE
void NormSetGrttProbingMode(NormSessionHandle sessionHandle, void NormSetGrttProbingMode(NormSessionHandle sessionHandle,
NormProbingMode probingMode) NormProbingMode probingMode)
{ {
@ -1025,12 +1127,12 @@ void NormSetGrttProbingMode(NormSessionHandle sessionHandle,
if (instance && instance->dispatcher.SuspendThread()) if (instance && instance->dispatcher.SuspendThread())
{ {
NormSession* session = (NormSession*)sessionHandle; NormSession* session = (NormSession*)sessionHandle;
if (session) session->SetGrttProbingMode((NormSession::ProbingMode)probingMode);
session->SetGrttProbingMode((NormSession::ProbingMode)probingMode);
instance->dispatcher.ResumeThread(); instance->dispatcher.ResumeThread();
} }
} // end NormSetGrttProbingMode() } // end NormSetGrttProbingMode()
NORM_API_LINKAGE
void NormSetGrttProbingInterval(NormSessionHandle sessionHandle, void NormSetGrttProbingInterval(NormSessionHandle sessionHandle,
double intervalMin, double intervalMin,
double intervalMax) double intervalMax)
@ -1044,6 +1146,34 @@ void NormSetGrttProbingInterval(NormSessionHandle sessionHandle,
} }
} // end NormSetGrttProbingInterval() } // end NormSetGrttProbingInterval()
NORM_API_LINKAGE
void NormSetBackoffFactor(NormSessionHandle sessionHandle,
double backoffFactor)
{
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
if (instance && instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
if (backoffFactor >= 0.0)
session->SetBackoffFactor(backoffFactor);
instance->dispatcher.ResumeThread();
}
} // end NormSetBackoffFactor()
NORM_API_LINKAGE
void NormSetGroupSize(NormSessionHandle sessionHandle,
unsigned int groupSize)
{
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
if (instance && instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
session->ServerSetGroupSize((double)groupSize);
instance->dispatcher.ResumeThread();
}
} // end NormSetGroupSize()
NORM_API_LINKAGE
NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle, NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle,
const char* fileName, const char* fileName,
const char* infoPtr, const char* infoPtr,
@ -1064,6 +1194,7 @@ NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle,
return objectHandle; return objectHandle;
} // end NormFileEnqueue() } // end NormFileEnqueue()
NORM_API_LINKAGE
NormObjectHandle NormDataEnqueue(NormSessionHandle sessionHandle, NormObjectHandle NormDataEnqueue(NormSessionHandle sessionHandle,
const char* dataPtr, const char* dataPtr,
unsigned long dataLen, unsigned long dataLen,
@ -1085,6 +1216,7 @@ NormObjectHandle NormDataEnqueue(NormSessionHandle sessionHandle,
return objectHandle; return objectHandle;
} // end NormDataEnqueue() } // end NormDataEnqueue()
NORM_API_LINKAGE
NormObjectHandle NormStreamOpen(NormSessionHandle sessionHandle, NormObjectHandle NormStreamOpen(NormSessionHandle sessionHandle,
unsigned long bufferSize) unsigned long bufferSize)
{ {
@ -1104,6 +1236,7 @@ NormObjectHandle NormStreamOpen(NormSessionHandle sessionHandle,
return objectHandle; return objectHandle;
} // end NormStreamOpen() } // end NormStreamOpen()
NORM_API_LINKAGE
void NormStreamClose(NormObjectHandle streamHandle, bool graceful) void NormStreamClose(NormObjectHandle streamHandle, bool graceful)
{ {
NormStreamObject* stream = NormStreamObject* stream =
@ -1126,6 +1259,7 @@ void NormStreamClose(NormObjectHandle streamHandle, bool graceful)
} }
} // end NormStreamClose() } // end NormStreamClose()
NORM_API_LINKAGE
unsigned int NormStreamWrite(NormObjectHandle streamHandle, unsigned int NormStreamWrite(NormObjectHandle streamHandle,
const char* buffer, const char* buffer,
unsigned int numBytes) unsigned int numBytes)
@ -1143,6 +1277,7 @@ unsigned int NormStreamWrite(NormObjectHandle streamHandle,
return result; return result;
} // end NormStreamWrite() } // end NormStreamWrite()
NORM_API_LINKAGE
void NormStreamFlush(NormObjectHandle streamHandle, void NormStreamFlush(NormObjectHandle streamHandle,
bool eom, bool eom,
NormFlushMode flushMode) NormFlushMode flushMode)
@ -1163,6 +1298,7 @@ void NormStreamFlush(NormObjectHandle streamHandle,
} }
} // end NormStreamFlush() } // end NormStreamFlush()
NORM_API_LINKAGE
void NormStreamSetAutoFlush(NormObjectHandle streamHandle, void NormStreamSetAutoFlush(NormObjectHandle streamHandle,
NormFlushMode flushMode) NormFlushMode flushMode)
{ {
@ -1172,6 +1308,7 @@ void NormStreamSetAutoFlush(NormObjectHandle streamHandle,
stream->SetFlushMode((NormStreamObject::FlushMode)flushMode); stream->SetFlushMode((NormStreamObject::FlushMode)flushMode);
} // end NormStreamSetAutoFlush() } // end NormStreamSetAutoFlush()
NORM_API_LINKAGE
void NormStreamSetPushEnable(NormObjectHandle streamHandle, bool state) void NormStreamSetPushEnable(NormObjectHandle streamHandle, bool state)
{ {
NormStreamObject* stream = NormStreamObject* stream =
@ -1179,6 +1316,7 @@ void NormStreamSetPushEnable(NormObjectHandle streamHandle, bool state)
if (stream) stream->SetPushMode(state); if (stream) stream->SetPushMode(state);
} // end NormStreamSetPushEnable() } // end NormStreamSetPushEnable()
NORM_API_LINKAGE
bool NormStreamHasVacancy(NormObjectHandle streamHandle) bool NormStreamHasVacancy(NormObjectHandle streamHandle)
{ {
bool result = false; bool result = false;
@ -1194,6 +1332,7 @@ bool NormStreamHasVacancy(NormObjectHandle streamHandle)
return result; return result;
} // end NormStreamHasVacancy() } // end NormStreamHasVacancy()
NORM_API_LINKAGE
void NormStreamMarkEom(NormObjectHandle streamHandle) void NormStreamMarkEom(NormObjectHandle streamHandle)
{ {
NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle); NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle);
@ -1206,6 +1345,7 @@ void NormStreamMarkEom(NormObjectHandle streamHandle)
} }
} // end NormStreamMarkEom() } // end NormStreamMarkEom()
NORM_API_LINKAGE
bool NormSetWatermark(NormSessionHandle sessionHandle, bool NormSetWatermark(NormSessionHandle sessionHandle,
NormObjectHandle objectHandle) NormObjectHandle objectHandle)
{ {
@ -1240,6 +1380,7 @@ bool NormSetWatermark(NormSessionHandle sessionHandle,
return result; return result;
} // end NormSetWatermark() } // end NormSetWatermark()
NORM_API_LINKAGE
bool NormAddAckingNode(NormSessionHandle sessionHandle, bool NormAddAckingNode(NormSessionHandle sessionHandle,
NormNodeId nodeId) NormNodeId nodeId)
{ {
@ -1255,6 +1396,7 @@ bool NormAddAckingNode(NormSessionHandle sessionHandle,
return result; return result;
} // end NormAddAckingNode() } // end NormAddAckingNode()
NORM_API_LINKAGE
void NormRemoveAckingNode(NormSessionHandle sessionHandle, void NormRemoveAckingNode(NormSessionHandle sessionHandle,
NormNodeId nodeId) NormNodeId nodeId)
{ {
@ -1267,6 +1409,7 @@ void NormRemoveAckingNode(NormSessionHandle sessionHandle,
} }
} // end NormRemoveAckingNode() } // end NormRemoveAckingNode()
NORM_API_LINKAGE
NormAckingStatus NormGetAckingStatus(NormSessionHandle sessionHandle, NormAckingStatus NormGetAckingStatus(NormSessionHandle sessionHandle,
NormNodeId nodeId) NormNodeId nodeId)
{ {
@ -1287,6 +1430,7 @@ NormAckingStatus NormGetAckingStatus(NormSessionHandle sessionHandle,
/** NORM Receiver Functions */ /** NORM Receiver Functions */
NORM_API_LINKAGE
bool NormStartReceiver(NormSessionHandle sessionHandle, bool NormStartReceiver(NormSessionHandle sessionHandle,
unsigned long bufferSpace) unsigned long bufferSpace)
{ {
@ -1301,6 +1445,7 @@ bool NormStartReceiver(NormSessionHandle sessionHandle,
return result; return result;
} // end NormStartReceiver() } // end NormStartReceiver()
NORM_API_LINKAGE
void NormStopReceiver(NormSessionHandle sessionHandle) void NormStopReceiver(NormSessionHandle sessionHandle)
{ {
@ -1313,6 +1458,7 @@ void NormStopReceiver(NormSessionHandle sessionHandle)
} }
} // end NormStopReceiver() } // end NormStopReceiver()
NORM_API_LINKAGE
bool NormSetRxSocketBuffer(NormSessionHandle sessionHandle, bool NormSetRxSocketBuffer(NormSessionHandle sessionHandle,
unsigned int bufferSize) unsigned int bufferSize)
{ {
@ -1328,6 +1474,7 @@ bool NormSetRxSocketBuffer(NormSessionHandle sessionHandle,
return result; return result;
} // end NormSetRxSocketBuffer() } // end NormSetRxSocketBuffer()
NORM_API_LINKAGE
void NormSetSilentReceiver(NormSessionHandle sessionHandle, void NormSetSilentReceiver(NormSessionHandle sessionHandle,
bool silent) bool silent)
{ {
@ -1335,6 +1482,7 @@ void NormSetSilentReceiver(NormSessionHandle sessionHandle,
if (session) session->ClientSetSilent(silent); if (session) session->ClientSetSilent(silent);
} // end NormSetSilentReceiver() } // end NormSetSilentReceiver()
NORM_API_LINKAGE
void NormSetDefaultUnicastNack(NormSessionHandle sessionHandle, void NormSetDefaultUnicastNack(NormSessionHandle sessionHandle,
bool unicastNacks) bool unicastNacks)
{ {
@ -1342,6 +1490,7 @@ void NormSetDefaultUnicastNack(NormSessionHandle sessionHandle,
if (session) session->ClientSetUnicastNacks(unicastNacks); if (session) session->ClientSetUnicastNacks(unicastNacks);
} // end NormSetDefaultUnicastNack() } // end NormSetDefaultUnicastNack()
NORM_API_LINKAGE
void NormNodeSetUnicastNack(NormNodeHandle nodeHandle, void NormNodeSetUnicastNack(NormNodeHandle nodeHandle,
bool unicastNacks) bool unicastNacks)
{ {
@ -1349,6 +1498,7 @@ void NormNodeSetUnicastNack(NormNodeHandle nodeHandle,
if (node) node->SetUnicastNacks(unicastNacks); if (node) node->SetUnicastNacks(unicastNacks);
} // end NormNodeSetUnicastNack() } // end NormNodeSetUnicastNack()
NORM_API_LINKAGE
void NormSetDefaultNackingMode(NormSessionHandle sessionHandle, void NormSetDefaultNackingMode(NormSessionHandle sessionHandle,
NormNackingMode nackingMode) NormNackingMode nackingMode)
{ {
@ -1356,6 +1506,7 @@ void NormSetDefaultNackingMode(NormSessionHandle sessionHandle,
if (session) session->ClientSetDefaultNackingMode((NormObject::NackingMode)nackingMode); if (session) session->ClientSetDefaultNackingMode((NormObject::NackingMode)nackingMode);
} // end NormSetDefaultNackingMode() } // end NormSetDefaultNackingMode()
NORM_API_LINKAGE
void NormNodeSetNackingMode(NormNodeHandle nodeHandle, void NormNodeSetNackingMode(NormNodeHandle nodeHandle,
NormNackingMode nackingMode) NormNackingMode nackingMode)
{ {
@ -1363,6 +1514,7 @@ void NormNodeSetNackingMode(NormNodeHandle nodeHandle,
if (node) node->SetDefaultNackingMode((NormObject::NackingMode)nackingMode); if (node) node->SetDefaultNackingMode((NormObject::NackingMode)nackingMode);
} // end NormNodeSetNackingMode() } // end NormNodeSetNackingMode()
NORM_API_LINKAGE
void NormObjectSetNackingMode(NormObjectHandle objectHandle, void NormObjectSetNackingMode(NormObjectHandle objectHandle,
NormNackingMode nackingMode) NormNackingMode nackingMode)
{ {
@ -1370,6 +1522,7 @@ void NormObjectSetNackingMode(NormObjectHandle objectHandle,
if (object) object->SetNackingMode((NormObject::NackingMode)nackingMode); if (object) object->SetNackingMode((NormObject::NackingMode)nackingMode);
} // end NormObjectSetNackingMode() } // end NormObjectSetNackingMode()
NORM_API_LINKAGE
void NormSetDefaultRepairBoundary(NormSessionHandle sessionHandle, void NormSetDefaultRepairBoundary(NormSessionHandle sessionHandle,
NormRepairBoundary repairBoundary) NormRepairBoundary repairBoundary)
{ {
@ -1378,6 +1531,7 @@ void NormSetDefaultRepairBoundary(NormSessionHandle sessionHandle,
session->ClientSetDefaultRepairBoundary((NormServerNode::RepairBoundary)repairBoundary); session->ClientSetDefaultRepairBoundary((NormServerNode::RepairBoundary)repairBoundary);
} // end NormSetDefaultRepairBoundary() } // end NormSetDefaultRepairBoundary()
NORM_API_LINKAGE
void NormNodeSetRepairBoundary(NormNodeHandle nodeHandle, void NormNodeSetRepairBoundary(NormNodeHandle nodeHandle,
NormRepairBoundary repairBoundary) NormRepairBoundary repairBoundary)
{ {
@ -1386,6 +1540,7 @@ void NormNodeSetRepairBoundary(NormNodeHandle nodeHandle,
node->SetRepairBoundary((NormServerNode::RepairBoundary)repairBoundary); node->SetRepairBoundary((NormServerNode::RepairBoundary)repairBoundary);
} // end NormNodeSetRepairBoundary() } // end NormNodeSetRepairBoundary()
NORM_API_LINKAGE
bool NormStreamRead(NormObjectHandle streamHandle, bool NormStreamRead(NormObjectHandle streamHandle,
char* buffer, char* buffer,
unsigned int* numBytes) unsigned int* numBytes)
@ -1402,6 +1557,7 @@ bool NormStreamRead(NormObjectHandle streamHandle,
return result; return result;
} // end NormStreamRead() } // end NormStreamRead()
NORM_API_LINKAGE
bool NormStreamSeekMsgStart(NormObjectHandle streamHandle) bool NormStreamSeekMsgStart(NormObjectHandle streamHandle)
{ {
bool result = false; bool result = false;
@ -1418,6 +1574,7 @@ bool NormStreamSeekMsgStart(NormObjectHandle streamHandle)
} // end NormStreamSeekMsgStart() } // end NormStreamSeekMsgStart()
NORM_API_LINKAGE
unsigned long NormStreamGetReadOffset(NormObjectHandle streamHandle) unsigned long NormStreamGetReadOffset(NormObjectHandle streamHandle)
{ {
NormStreamObject* stream = static_cast<NormStreamObject*>((NormObject*)streamHandle); NormStreamObject* stream = static_cast<NormStreamObject*>((NormObject*)streamHandle);
@ -1430,6 +1587,7 @@ unsigned long NormStreamGetReadOffset(NormObjectHandle streamHandle)
/** NORM Object Functions */ /** NORM Object Functions */
NORM_API_LINKAGE
NormObjectType NormObjectGetType(NormObjectHandle objectHandle) NormObjectType NormObjectGetType(NormObjectHandle objectHandle)
{ {
if (NORM_OBJECT_INVALID != objectHandle) if (NORM_OBJECT_INVALID != objectHandle)
@ -1438,16 +1596,19 @@ NormObjectType NormObjectGetType(NormObjectHandle objectHandle)
return NORM_OBJECT_NONE; return NORM_OBJECT_NONE;
} // end NormObjectGetType() } // end NormObjectGetType()
NORM_API_LINKAGE
bool NormObjectHasInfo(NormObjectHandle objectHandle) bool NormObjectHasInfo(NormObjectHandle objectHandle)
{ {
return ((NormObject*)objectHandle)->HasInfo(); return ((NormObject*)objectHandle)->HasInfo();
} // end NormObjectHasInfo() } // end NormObjectHasInfo()
NORM_API_LINKAGE
unsigned short NormObjectGetInfoLength(NormObjectHandle objectHandle) unsigned short NormObjectGetInfoLength(NormObjectHandle objectHandle)
{ {
return ((NormObject*)objectHandle)->GetInfoLength(); return ((NormObject*)objectHandle)->GetInfoLength();
} // end NormObjectGetInfoLength() } // end NormObjectGetInfoLength()
NORM_API_LINKAGE
unsigned short NormObjectGetInfo(NormObjectHandle objectHandle, unsigned short NormObjectGetInfo(NormObjectHandle objectHandle,
char* buffer, char* buffer,
unsigned short bufferLen) unsigned short bufferLen)
@ -1468,11 +1629,13 @@ unsigned short NormObjectGetInfo(NormObjectHandle objectHandle,
return result; return result;
} // end NormObjectGetInfo() } // end NormObjectGetInfo()
NORM_API_LINKAGE
NormSize NormObjectGetSize(NormObjectHandle objectHandle) NormSize NormObjectGetSize(NormObjectHandle objectHandle)
{ {
return ((NormSize)((NormObject*)objectHandle)->GetSize().GetOffset()); return ((NormSize)((NormObject*)objectHandle)->GetSize().GetOffset());
} // end NormObjectGetSize() } // end NormObjectGetSize()
NORM_API_LINKAGE
NormSize NormObjectGetBytesPending(NormObjectHandle objectHandle) NormSize NormObjectGetBytesPending(NormObjectHandle objectHandle)
{ {
NormSize bytesPending = 0; NormSize bytesPending = 0;
@ -1488,6 +1651,7 @@ NormSize NormObjectGetBytesPending(NormObjectHandle objectHandle)
return bytesPending; return bytesPending;
} // end NormObjectGetBytesPending() } // end NormObjectGetBytesPending()
NORM_API_LINKAGE
void NormObjectCancel(NormObjectHandle objectHandle) void NormObjectCancel(NormObjectHandle objectHandle)
{ {
if (NORM_OBJECT_INVALID != objectHandle) if (NORM_OBJECT_INVALID != objectHandle)
@ -1507,6 +1671,7 @@ void NormObjectCancel(NormObjectHandle objectHandle)
} }
} // end NormObjectCancel() } // end NormObjectCancel()
NORM_API_LINKAGE
void NormObjectRetain(NormObjectHandle objectHandle) void NormObjectRetain(NormObjectHandle objectHandle)
{ {
if (NORM_OBJECT_INVALID != objectHandle) if (NORM_OBJECT_INVALID != objectHandle)
@ -1521,6 +1686,7 @@ void NormObjectRetain(NormObjectHandle objectHandle)
} }
} // end NormRetainObject() } // end NormRetainObject()
NORM_API_LINKAGE
void NormObjectRelease(NormObjectHandle objectHandle) void NormObjectRelease(NormObjectHandle objectHandle)
{ {
if (NORM_OBJECT_INVALID != objectHandle) if (NORM_OBJECT_INVALID != objectHandle)
@ -1536,6 +1702,7 @@ void NormObjectRelease(NormObjectHandle objectHandle)
} }
} // end NormObjectRelease() } // end NormObjectRelease()
NORM_API_LINKAGE
bool NormFileGetName(NormObjectHandle fileHandle, bool NormFileGetName(NormObjectHandle fileHandle,
char* nameBuffer, char* nameBuffer,
unsigned int bufferLen) unsigned int bufferLen)
@ -1554,6 +1721,7 @@ bool NormFileGetName(NormObjectHandle fileHandle,
return result; return result;
} // end NormFileGetName() } // end NormFileGetName()
NORM_API_LINKAGE
bool NormFileRename(NormObjectHandle fileHandle, bool NormFileRename(NormObjectHandle fileHandle,
const char* fileName) const char* fileName)
{ {
@ -1570,6 +1738,7 @@ bool NormFileRename(NormObjectHandle fileHandle,
return result; return result;
} // end NormFileRename() } // end NormFileRename()
NORM_API_LINKAGE
const char*volatile NormDataAccessData(NormObjectHandle dataHandle) const char*volatile NormDataAccessData(NormObjectHandle dataHandle)
{ {
NormDataObject* dataObj = NormDataObject* dataObj =
@ -1577,6 +1746,7 @@ const char*volatile NormDataAccessData(NormObjectHandle dataHandle)
return dataObj->GetData(); return dataObj->GetData();
} // end NormDataAccessData() } // end NormDataAccessData()
NORM_API_LINKAGE
char* NormDataDetachData(NormObjectHandle dataHandle) char* NormDataDetachData(NormObjectHandle dataHandle)
{ {
NormDataObject* dataObj = NormDataObject* dataObj =
@ -1584,6 +1754,7 @@ char* NormDataDetachData(NormObjectHandle dataHandle)
return dataObj->DetachData(); return dataObj->DetachData();
} // end NormDataDetachData() } // end NormDataDetachData()
NORM_API_LINKAGE
NormNodeHandle NormObjectGetSender(NormObjectHandle objectHandle) NormNodeHandle NormObjectGetSender(NormObjectHandle objectHandle)
{ {
return (NormNodeHandle)(((NormObject*)objectHandle)->GetServer()); return (NormNodeHandle)(((NormObject*)objectHandle)->GetServer());
@ -1592,6 +1763,7 @@ NormNodeHandle NormObjectGetSender(NormObjectHandle objectHandle)
/** NORM Node Functions */ /** NORM Node Functions */
NORM_API_LINKAGE
NormNodeId NormNodeGetId(NormNodeHandle nodeHandle) NormNodeId NormNodeGetId(NormNodeHandle nodeHandle)
{ {
NormNode* node = (NormNode*)nodeHandle; NormNode* node = (NormNode*)nodeHandle;
@ -1601,6 +1773,7 @@ NormNodeId NormNodeGetId(NormNodeHandle nodeHandle)
return NORM_NODE_NONE; return NORM_NODE_NONE;
} // end NormNodeGetId() } // end NormNodeGetId()
NORM_API_LINKAGE
bool NormNodeGetAddress(NormNodeHandle nodeHandle, bool NormNodeGetAddress(NormNodeHandle nodeHandle,
char* addrBuffer, char* addrBuffer,
unsigned int* bufferLen, unsigned int* bufferLen,
@ -1632,6 +1805,7 @@ bool NormNodeGetAddress(NormNodeHandle nodeHandle,
return result; return result;
} // end NormNodeGetId() } // end NormNodeGetId()
NORM_API_LINKAGE
void NormNodeRetain(NormNodeHandle nodeHandle) void NormNodeRetain(NormNodeHandle nodeHandle)
{ {
if (NORM_NODE_INVALID != nodeHandle) if (NORM_NODE_INVALID != nodeHandle)
@ -1646,6 +1820,7 @@ void NormNodeRetain(NormNodeHandle nodeHandle)
} }
} // end NormNodeRetain() } // end NormNodeRetain()
NORM_API_LINKAGE
void NormNodeRelease(NormNodeHandle nodeHandle) void NormNodeRelease(NormNodeHandle nodeHandle)
{ {
if (NORM_NODE_INVALID != nodeHandle) if (NORM_NODE_INVALID != nodeHandle)
@ -1675,6 +1850,7 @@ void NormNodeRelease(NormNodeHandle nodeHandle)
// events with a "NormDispatchEvents()" call ... // events with a "NormDispatchEvents()" call ...
// //
NORM_API_LINKAGE
unsigned long NormCountCompletedObjects(NormSessionHandle sessionHandle) unsigned long NormCountCompletedObjects(NormSessionHandle sessionHandle)
{ {
unsigned long result = 0; unsigned long result = 0;

View File

@ -1,12 +1,28 @@
#ifndef _NORM_API #ifndef _NORM_API
#define _NORM_API #define _NORM_API
/*******************************************************************************
* NOTE: To use NORM as a DLL on Win32 platforms, the macro "NORM_USE_DLL" must be
* defined. Otherwise, the static library "NormLib.lib" is built and should
* be used for your code compilation and linking.
********************************************************************************/
#ifdef WIN32 #ifdef WIN32
#include <winsock2.h> #include <winsock2.h>
#include <windows.h> #include <windows.h>
#ifdef NORM_USE_DLL
#ifdef _NORM_API_BUILD
#define NORM_API_LINKAGE __declspec(dllexport) // to support building of "Norm.dll"
#else
#define NORM_API_LINKAGE __declspec(dllimport) // to let apps use "Norm.dll" functions
#endif // if/else _NORM_API_BUILD
#else
#define NORM_API_LINKAGE
#endif // if/else NORM_USE_DLL
#else #else
#include <sys/types.h> // for "off_t" #include <sys/types.h> // for "off_t"
#endif // WIN32 #define NORM_API_LINKAGE
#endif // if/else WIN32/UNIX
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// IMPORTANT NOTICE // IMPORTANT NOTICE
@ -21,20 +37,26 @@
/** NORM API Types */ /** NORM API Types */
typedef const void* NormInstanceHandle; typedef const void* NormInstanceHandle;
extern const NormInstanceHandle NORM_INSTANCE_INVALID; extern NORM_API_LINKAGE
const NormInstanceHandle NORM_INSTANCE_INVALID;
typedef const void* NormSessionHandle; typedef const void* NormSessionHandle;
extern const NormSessionHandle NORM_SESSION_INVALID; extern NORM_API_LINKAGE
const NormSessionHandle NORM_SESSION_INVALID;
typedef unsigned short NormSessionId; typedef unsigned short NormSessionId;
typedef const void* NormNodeHandle; typedef const void* NormNodeHandle;
extern const NormNodeHandle NORM_NODE_INVALID; extern NORM_API_LINKAGE
const NormNodeHandle NORM_NODE_INVALID;
typedef unsigned long NormNodeId; typedef unsigned long NormNodeId;
extern const NormNodeId NORM_NODE_NONE; extern NORM_API_LINKAGE
extern const NormNodeId NORM_NODE_ANY; const NormNodeId NORM_NODE_NONE;
extern NORM_API_LINKAGE
const NormNodeId NORM_NODE_ANY;
typedef const void* NormObjectHandle; typedef const void* NormObjectHandle;
extern const NormObjectHandle NORM_OBJECT_INVALID; extern NORM_API_LINKAGE
const NormObjectHandle NORM_OBJECT_INVALID;
typedef unsigned short NormObjectTransportId; typedef unsigned short NormObjectTransportId;
#ifdef WIN32 #ifdef WIN32
@ -43,6 +65,7 @@ typedef __int64 NormSize;
typedef off_t NormSize; typedef off_t NormSize;
#endif // WIN32 #endif // WIN32
NORM_API_LINKAGE
enum NormObjectType enum NormObjectType
{ {
NORM_OBJECT_NONE, NORM_OBJECT_NONE,
@ -50,7 +73,8 @@ enum NormObjectType
NORM_OBJECT_FILE, NORM_OBJECT_FILE,
NORM_OBJECT_STREAM NORM_OBJECT_STREAM
}; };
NORM_API_LINKAGE
enum NormFlushMode enum NormFlushMode
{ {
NORM_FLUSH_NONE, NORM_FLUSH_NONE,
@ -58,14 +82,15 @@ enum NormFlushMode
NORM_FLUSH_ACTIVE NORM_FLUSH_ACTIVE
}; };
NORM_API_LINKAGE
enum NormNackingMode enum NormNackingMode
{ {
NORM_NACK_NONE, NORM_NACK_NONE,
NORM_NACK_INFO_ONLY, NORM_NACK_INFO_ONLY,
NORM_NACK_NORMAL NORM_NACK_NORMAL
}; };
NORM_API_LINKAGE
enum NormAckingStatus enum NormAckingStatus
{ {
NORM_ACK_INVALID, NORM_ACK_INVALID,
@ -73,7 +98,8 @@ enum NormAckingStatus
NORM_ACK_PENDING, NORM_ACK_PENDING,
NORM_ACK_SUCCESS NORM_ACK_SUCCESS
}; };
NORM_API_LINKAGE
enum NormProbingMode enum NormProbingMode
{ {
NORM_PROBE_NONE, NORM_PROBE_NONE,
@ -81,12 +107,14 @@ enum NormProbingMode
NORM_PROBE_ACTIVE NORM_PROBE_ACTIVE
}; };
NORM_API_LINKAGE
enum NormRepairBoundary enum NormRepairBoundary
{ {
NORM_BOUNDARY_BLOCK, NORM_BOUNDARY_BLOCK,
NORM_BOUNDARY_OBJECT NORM_BOUNDARY_OBJECT
}; };
NORM_API_LINKAGE
enum NormEventType enum NormEventType
{ {
NORM_EVENT_INVALID = 0, NORM_EVENT_INVALID = 0,
@ -118,17 +146,26 @@ typedef struct
/** NORM API General Initialization and Operation Functions */ /** NORM API General Initialization and Operation Functions */
NORM_API_LINKAGE
NormInstanceHandle NormCreateInstance(bool priorityBoost = false); NormInstanceHandle NormCreateInstance(bool priorityBoost = false);
NORM_API_LINKAGE
void NormDestroyInstance(NormInstanceHandle instanceHandle); void NormDestroyInstance(NormInstanceHandle instanceHandle);
NORM_API_LINKAGE
void NormStopInstance(NormInstanceHandle instanceHandle);
NORM_API_LINKAGE
bool NormRestartInstance(NormInstanceHandle instanceHandle);
// This MUST be set to enable NORM_OBJECT_FILE reception! // This MUST be set to enable NORM_OBJECT_FILE reception!
NORM_API_LINKAGE
bool NormSetCacheDirectory(NormInstanceHandle instanceHandle, bool NormSetCacheDirectory(NormInstanceHandle instanceHandle,
const char* cachePath); const char* cachePath);
// This call blocks until the next NormEvent is ready unless asynchronous // This call blocks until the next NormEvent is ready unless asynchronous
// notification is used (see below) // notification is used (see below)
NORM_API_LINKAGE
bool NormGetNextEvent(NormInstanceHandle instanceHandle, NormEvent* theEvent); bool NormGetNextEvent(NormInstanceHandle instanceHandle, NormEvent* theEvent);
// The "NormGetDescriptor()" function returns a HANDLE (WIN32) or // The "NormGetDescriptor()" function returns a HANDLE (WIN32) or
@ -144,49 +181,67 @@ typedef HANDLE NormDescriptor;
#else #else
typedef int NormDescriptor; typedef int NormDescriptor;
#endif // if/else WIN32/UNIX #endif // if/else WIN32/UNIX
extern const NormDescriptor NORM_DESCRIPTOR_INVALID; extern NORM_API_LINKAGE
const NormDescriptor NORM_DESCRIPTOR_INVALID;
NORM_API_LINKAGE
NormDescriptor NormGetDescriptor(NormInstanceHandle instanceHandle); NormDescriptor NormGetDescriptor(NormInstanceHandle instanceHandle);
/** NORM Session Creation and Control Functions */ /** NORM Session Creation and Control Functions */
NORM_API_LINKAGE
NormSessionHandle NormCreateSession(NormInstanceHandle instanceHandle, NormSessionHandle NormCreateSession(NormInstanceHandle instanceHandle,
const char* sessionAddress, const char* sessionAddress,
unsigned short sessionPort, unsigned short sessionPort,
NormNodeId localNodeId); NormNodeId localNodeId);
NORM_API_LINKAGE
void NormDestroySession(NormSessionHandle sessionHandle); void NormDestroySession(NormSessionHandle sessionHandle);
NORM_API_LINKAGE
void NormSetUserData(NormSessionHandle sessionHandle, const void* userData); void NormSetUserData(NormSessionHandle sessionHandle, const void* userData);
NORM_API_LINKAGE
const void* NormGetUserData(NormSessionHandle sessionHandle); const void* NormGetUserData(NormSessionHandle sessionHandle);
NORM_API_LINKAGE
NormNodeId NormGetLocalNodeId(NormSessionHandle sessionHandle); NormNodeId NormGetLocalNodeId(NormSessionHandle sessionHandle);
NORM_API_LINKAGE
void NormSetTxPort(NormSessionHandle sessionHandle, void NormSetTxPort(NormSessionHandle sessionHandle,
unsigned short txPortNumber); unsigned short txPortNumber);
NORM_API_LINKAGE
void NormSetRxPortReuse(NormSessionHandle sessionHandle, void NormSetRxPortReuse(NormSessionHandle sessionHandle,
bool state); bool enable,
bool bindToSessionAddress = true);
NORM_API_LINKAGE
bool NormSetMulticastInterface(NormSessionHandle sessionHandle, bool NormSetMulticastInterface(NormSessionHandle sessionHandle,
const char* interfaceName); const char* interfaceName);
NORM_API_LINKAGE
bool NormSetTTL(NormSessionHandle sessionHandle, bool NormSetTTL(NormSessionHandle sessionHandle,
unsigned char ttl); unsigned char ttl);
NORM_API_LINKAGE
bool NormSetTOS(NormSessionHandle sessionHandle, bool NormSetTOS(NormSessionHandle sessionHandle,
unsigned char tos); unsigned char tos);
NORM_API_LINKAGE
bool NormSetLoopback(NormSessionHandle sessionHandle, bool NormSetLoopback(NormSessionHandle sessionHandle,
bool loopback); bool loopback);
// Special functions for debug support // Special functions for debug support
NORM_API_LINKAGE
void NormSetMessageTrace(NormSessionHandle sessionHandle, bool state); void NormSetMessageTrace(NormSessionHandle sessionHandle, bool state);
NORM_API_LINKAGE
void NormSetTxLoss(NormSessionHandle sessionHandle, double percent); void NormSetTxLoss(NormSessionHandle sessionHandle, double percent);
NORM_API_LINKAGE
void NormSetRxLoss(NormSessionHandle sessionHandle, double percent); void NormSetRxLoss(NormSessionHandle sessionHandle, double percent);
/** NORM Sender Functions */ /** NORM Sender Functions */
NORM_API_LINKAGE
bool NormStartSender(NormSessionHandle sessionHandle, bool NormStartSender(NormSessionHandle sessionHandle,
NormSessionId sessionId, NormSessionId sessionId,
unsigned long bufferSpace, unsigned long bufferSpace,
@ -194,47 +249,71 @@ bool NormStartSender(NormSessionHandle sessionHandle,
unsigned char numData, unsigned char numData,
unsigned char numParity); unsigned char numParity);
NORM_API_LINKAGE
void NormStopSender(NormSessionHandle sessionHandle); void NormStopSender(NormSessionHandle sessionHandle);
NORM_API_LINKAGE
double NormGetTransmitRate(NormSessionHandle sessionHandle);
NORM_API_LINKAGE
void NormSetTransmitRate(NormSessionHandle sessionHandle, void NormSetTransmitRate(NormSessionHandle sessionHandle,
double bitsPerSecond); double bitsPerSecond);
NORM_API_LINKAGE
bool NormSetTxSocketBuffer(NormSessionHandle sessionHandle, bool NormSetTxSocketBuffer(NormSessionHandle sessionHandle,
unsigned int bufferSize); unsigned int bufferSize);
NORM_API_LINKAGE
void NormSetCongestionControl(NormSessionHandle sessionHandle, void NormSetCongestionControl(NormSessionHandle sessionHandle,
bool state); bool state);
NORM_API_LINKAGE
void NormSetTransmitRateBounds(NormSessionHandle sessionHandle, void NormSetTransmitRateBounds(NormSessionHandle sessionHandle,
double rateMin, double rateMin,
double rateMax); double rateMax);
NORM_API_LINKAGE
void NormSetTransmitCacheBounds(NormSessionHandle sessionHandle, void NormSetTransmitCacheBounds(NormSessionHandle sessionHandle,
NormSize sizeMax, NormSize sizeMax,
unsigned long countMin, unsigned long countMin,
unsigned long countMax); unsigned long countMax);
NORM_API_LINKAGE
void NormSetAutoParity(NormSessionHandle sessionHandle, void NormSetAutoParity(NormSessionHandle sessionHandle,
unsigned char autoParity); unsigned char autoParity);
NORM_API_LINKAGE
void NormSetGrttEstimate(NormSessionHandle sessionHandle, void NormSetGrttEstimate(NormSessionHandle sessionHandle,
double grttEstimate); double grttEstimate);
NORM_API_LINKAGE
void NormSetGrttMax(NormSessionHandle sessionHandle, void NormSetGrttMax(NormSessionHandle sessionHandle,
double grttMax); double grttMax);
NORM_API_LINKAGE
void NormSetGrttProbingMode(NormSessionHandle sessionHandle, void NormSetGrttProbingMode(NormSessionHandle sessionHandle,
NormProbingMode probingMode); NormProbingMode probingMode);
NORM_API_LINKAGE
void NormSetGrttProbingInterval(NormSessionHandle sessionHandle, void NormSetGrttProbingInterval(NormSessionHandle sessionHandle,
double intervalMin, double intervalMin,
double intervalMax); double intervalMax);
NORM_API_LINKAGE
void NormSetBackoffFactor(NormSessionHandle sessionHandle,
double backoffFactor);
NORM_API_LINKAGE
void NormSetGroupSize(NormSessionHandle sessionHandle,
unsigned int groupSize);
NORM_API_LINKAGE
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,
unsigned int infoLen = 0); unsigned int infoLen = 0);
NORM_API_LINKAGE
NormObjectHandle NormDataEnqueue(NormSessionHandle sessionHandle, NormObjectHandle NormDataEnqueue(NormSessionHandle sessionHandle,
const char* dataPtr, const char* dataPtr,
unsigned long dataLen, unsigned long dataLen,
@ -242,138 +321,182 @@ NormObjectHandle NormDataEnqueue(NormSessionHandle sessionHandle,
unsigned int infoLen = 0); unsigned int infoLen = 0);
NORM_API_LINKAGE
NormObjectHandle NormStreamOpen(NormSessionHandle sessionHandle, NormObjectHandle NormStreamOpen(NormSessionHandle sessionHandle,
unsigned long bufferSize); unsigned long bufferSize);
NORM_API_LINKAGE
void NormStreamClose(NormObjectHandle streamHandle, bool graceful = false); void NormStreamClose(NormObjectHandle streamHandle, bool graceful = false);
NORM_API_LINKAGE
unsigned int NormStreamWrite(NormObjectHandle streamHandle, unsigned int NormStreamWrite(NormObjectHandle streamHandle,
const char* buffer, const char* buffer,
unsigned int numBytes); unsigned int numBytes);
NORM_API_LINKAGE
void NormStreamFlush(NormObjectHandle streamHandle, void NormStreamFlush(NormObjectHandle streamHandle,
bool eom = false, bool eom = false,
NormFlushMode flushMode = NORM_FLUSH_PASSIVE); NormFlushMode flushMode = NORM_FLUSH_PASSIVE);
NORM_API_LINKAGE
void NormStreamSetAutoFlush(NormObjectHandle streamHandle, void NormStreamSetAutoFlush(NormObjectHandle streamHandle,
NormFlushMode flushMode); NormFlushMode flushMode);
NORM_API_LINKAGE
void NormStreamSetPushEnable(NormObjectHandle streamHandle, void NormStreamSetPushEnable(NormObjectHandle streamHandle,
bool pushEnable); bool pushEnable);
NORM_API_LINKAGE
bool NormStreamHasVacancy(NormObjectHandle streamHandle); bool NormStreamHasVacancy(NormObjectHandle streamHandle);
NORM_API_LINKAGE
void NormStreamMarkEom(NormObjectHandle streamHandle); void NormStreamMarkEom(NormObjectHandle streamHandle);
NORM_API_LINKAGE
bool NormSetWatermark(NormSessionHandle sessionHandle, bool NormSetWatermark(NormSessionHandle sessionHandle,
NormObjectHandle objectHandle); NormObjectHandle objectHandle);
NORM_API_LINKAGE
bool NormAddAckingNode(NormSessionHandle sessionHandle, bool NormAddAckingNode(NormSessionHandle sessionHandle,
NormNodeId nodeId); NormNodeId nodeId);
NORM_API_LINKAGE
void NormRemoveAckingNode(NormSessionHandle sessionHandle, void NormRemoveAckingNode(NormSessionHandle sessionHandle,
NormNodeId nodeId); NormNodeId nodeId);
NORM_API_LINKAGE
NormAckingStatus NormGetAckingStatus(NormSessionHandle sessionHandle, NormAckingStatus NormGetAckingStatus(NormSessionHandle sessionHandle,
NormNodeId nodeId = NORM_NODE_ANY); NormNodeId nodeId = NORM_NODE_ANY);
/* NORM Receiver Functions */ /* NORM Receiver Functions */
NORM_API_LINKAGE
bool NormStartReceiver(NormSessionHandle sessionHandle, bool NormStartReceiver(NormSessionHandle sessionHandle,
unsigned long bufferSpace); unsigned long bufferSpace);
NORM_API_LINKAGE
void NormStopReceiver(NormSessionHandle sessionHandle); void NormStopReceiver(NormSessionHandle sessionHandle);
NORM_API_LINKAGE
bool NormSetRxSocketBuffer(NormSessionHandle sessionHandle, bool NormSetRxSocketBuffer(NormSessionHandle sessionHandle,
unsigned int bufferSize); unsigned int bufferSize);
NORM_API_LINKAGE
void NormSetSilentReceiver(NormSessionHandle sessionHandle, void NormSetSilentReceiver(NormSessionHandle sessionHandle,
bool silent); bool silent);
NORM_API_LINKAGE
void NormSetDefaultUnicastNack(NormSessionHandle sessionHandle, void NormSetDefaultUnicastNack(NormSessionHandle sessionHandle,
bool unicastNacks); bool unicastNacks);
NORM_API_LINKAGE
void NormNodeSetUnicastNack(NormNodeHandle remoteSender, void NormNodeSetUnicastNack(NormNodeHandle remoteSender,
bool unicastNacks); bool unicastNacks);
NORM_API_LINKAGE
void NormSetDefaultNackingMode(NormSessionHandle sessionHandle, void NormSetDefaultNackingMode(NormSessionHandle sessionHandle,
NormNackingMode nackingMode); NormNackingMode nackingMode);
NORM_API_LINKAGE
void NormNodeSetNackingMode(NormNodeHandle nodeHandle, void NormNodeSetNackingMode(NormNodeHandle nodeHandle,
NormNackingMode nackingMode); NormNackingMode nackingMode);
NORM_API_LINKAGE
void NormObjectSetNackingMode(NormObjectHandle objectHandle, void NormObjectSetNackingMode(NormObjectHandle objectHandle,
NormNackingMode nackingMode); NormNackingMode nackingMode);
NORM_API_LINKAGE
void NormSetDefaultRepairBoundary(NormSessionHandle sessionHandle, void NormSetDefaultRepairBoundary(NormSessionHandle sessionHandle,
NormRepairBoundary repairBoundary); NormRepairBoundary repairBoundary);
NORM_API_LINKAGE
void NormNodeSetRepairBoundary(NormNodeHandle nodeHandle, void NormNodeSetRepairBoundary(NormNodeHandle nodeHandle,
NormRepairBoundary repairBoundary); NormRepairBoundary repairBoundary);
NORM_API_LINKAGE
bool NormStreamRead(NormObjectHandle streamHandle, bool NormStreamRead(NormObjectHandle streamHandle,
char* buffer, char* buffer,
unsigned int* numBytes); unsigned int* numBytes);
NORM_API_LINKAGE
bool NormStreamSeekMsgStart(NormObjectHandle streamHandle); bool NormStreamSeekMsgStart(NormObjectHandle streamHandle);
NORM_API_LINKAGE
unsigned long NormStreamGetReadOffset(NormObjectHandle streamHandle); unsigned long NormStreamGetReadOffset(NormObjectHandle streamHandle);
/** NORM Object Functions */ /** NORM Object Functions */
NORM_API_LINKAGE
NormObjectType NormObjectGetType(NormObjectHandle objectHandle); NormObjectType NormObjectGetType(NormObjectHandle objectHandle);
NORM_API_LINKAGE
bool NormObjectHasInfo(NormObjectHandle objectHandle); bool NormObjectHasInfo(NormObjectHandle objectHandle);
NORM_API_LINKAGE
unsigned short NormObjectGetInfoLength(NormObjectHandle objectHandle); unsigned short NormObjectGetInfoLength(NormObjectHandle objectHandle);
NORM_API_LINKAGE
unsigned short NormObjectGetInfo(NormObjectHandle objectHandle, unsigned short NormObjectGetInfo(NormObjectHandle objectHandle,
char* buffer, char* buffer,
unsigned short bufferLen); unsigned short bufferLen);
NORM_API_LINKAGE
NormSize NormObjectGetSize(NormObjectHandle objectHandle); NormSize NormObjectGetSize(NormObjectHandle objectHandle);
NORM_API_LINKAGE
NormSize NormObjectGetBytesPending(NormObjectHandle objectHandle); NormSize NormObjectGetBytesPending(NormObjectHandle objectHandle);
NORM_API_LINKAGE
void NormObjectCancel(NormObjectHandle objectHandle); void NormObjectCancel(NormObjectHandle objectHandle);
NORM_API_LINKAGE
void NormObjectRetain(NormObjectHandle objectHandle); void NormObjectRetain(NormObjectHandle objectHandle);
NORM_API_LINKAGE
void NormObjectRelease(NormObjectHandle objectHandle); void NormObjectRelease(NormObjectHandle objectHandle);
NORM_API_LINKAGE
bool NormFileGetName(NormObjectHandle fileHandle, bool NormFileGetName(NormObjectHandle fileHandle,
char* nameBuffer, char* nameBuffer,
unsigned int bufferLen); unsigned int bufferLen);
NORM_API_LINKAGE
bool NormFileRename(NormObjectHandle fileHandle, bool NormFileRename(NormObjectHandle fileHandle,
const char* fileName); const char* fileName);
NORM_API_LINKAGE
const char*volatile NormDataAccessData(NormObjectHandle objectHandle); const char*volatile NormDataAccessData(NormObjectHandle objectHandle);
NORM_API_LINKAGE
char* NormDataDetachData(NormObjectHandle objectHandle); char* NormDataDetachData(NormObjectHandle objectHandle);
NORM_API_LINKAGE
NormNodeHandle NormObjectGetSender(NormObjectHandle objectHandle); NormNodeHandle NormObjectGetSender(NormObjectHandle objectHandle);
NORM_API_LINKAGE
char* NormGetData(NormObjectHandle dataHandle); char* NormGetData(NormObjectHandle dataHandle);
/** NORM Node Functions */ /** NORM Node Functions */
NORM_API_LINKAGE
NormNodeId NormNodeGetId(NormNodeHandle nodeHandle); NormNodeId NormNodeGetId(NormNodeHandle nodeHandle);
NORM_API_LINKAGE
bool NormNodeGetAddress(NormNodeHandle nodeHandle, bool NormNodeGetAddress(NormNodeHandle nodeHandle,
char* addrBuffer, char* addrBuffer,
unsigned int* bufferLen, unsigned int* bufferLen,
unsigned short* port = (unsigned short*)0); unsigned short* port = (unsigned short*)0);
NORM_API_LINKAGE
void NormNodeRetain(NormNodeHandle nodeHandle); void NormNodeRetain(NormNodeHandle nodeHandle);
NORM_API_LINKAGE
void NormNodeRelease(NormNodeHandle nodeHandle); void NormNodeRelease(NormNodeHandle nodeHandle);
/** Some experimental functions */ /** Some experimental functions */
NORM_API_LINKAGE
unsigned long NormCountCompletedObjects(NormSessionHandle sessionHandle); unsigned long NormCountCompletedObjects(NormSessionHandle sessionHandle);
#endif // _NORM_API #endif // _NORM_API

View File

@ -69,7 +69,7 @@ class NormApp : public NormController, public ProtoApp
// application parameters // application parameters
FILE* input; // input stream FILE* input; // input stream
FILE* output; // output stream FILE* output; // output stream
char input_buffer[1250]; char input_buffer[65535];
unsigned int input_index; unsigned int input_index;
unsigned int input_length; unsigned int input_length;
bool input_active; bool input_active;
@ -78,7 +78,7 @@ class NormApp : public NormController, public ProtoApp
bool input_messaging; // stream input mode bool input_messaging; // stream input mode
UINT16 input_msg_length; UINT16 input_msg_length;
UINT16 input_msg_index; UINT16 input_msg_index;
char output_buffer[65536]; char output_buffer[65535];
UINT16 output_index; UINT16 output_index;
bool output_messaging; bool output_messaging;
UINT16 output_msg_length; UINT16 output_msg_length;
@ -104,6 +104,7 @@ class NormApp : public NormController, public ProtoApp
double group_size; double group_size;
unsigned long tx_buffer_size; // bytes unsigned long tx_buffer_size; // bytes
NormFileList tx_file_list; NormFileList tx_file_list;
bool tx_one_shot;
double tx_object_interval; double tx_object_interval;
int tx_repeat_count; int tx_repeat_count;
double tx_repeat_interval; double tx_repeat_interval;
@ -140,7 +141,7 @@ NormApp::NormApp()
backoff_factor(NormSession::DEFAULT_BACKOFF_FACTOR), backoff_factor(NormSession::DEFAULT_BACKOFF_FACTOR),
grtt_estimate(NormSession::DEFAULT_GRTT_ESTIMATE), grtt_estimate(NormSession::DEFAULT_GRTT_ESTIMATE),
group_size(NormSession::DEFAULT_GSIZE_ESTIMATE), group_size(NormSession::DEFAULT_GSIZE_ESTIMATE),
tx_buffer_size(1024*1024), tx_buffer_size(1024*1024), tx_one_shot(false),
tx_object_interval(0.0), tx_repeat_count(0), tx_repeat_interval(2.0), tx_repeat_clear(true), tx_object_interval(0.0), tx_repeat_count(0), tx_repeat_interval(2.0), tx_repeat_clear(true),
rx_buffer_size(1024*1024), rx_sock_buffer_size(0), rx_buffer_size(1024*1024), rx_sock_buffer_size(0),
rx_cache_path(NULL), post_processor(NULL), unicast_nacks(false), silent_client(false), rx_cache_path(NULL), post_processor(NULL), unicast_nacks(false), silent_client(false),
@ -211,6 +212,7 @@ const char* const NormApp::cmd_list[] =
"+interval", // delay time (sec) between files (0.0 sec default) "+interval", // delay time (sec) between files (0.0 sec default)
"+repeatcount", // How many times to repeat the file/directory list tx "+repeatcount", // How many times to repeat the file/directory list tx
"+rinterval", // Interval (sec) between file/directory list repeats "+rinterval", // Interval (sec) between file/directory list repeats
"-oneshot", // Transmit file(s), exiting upon TX_FLUSH_COMPLETED
"-updatesOnly", // only send updated files on repeat transmission "-updatesOnly", // only send updated files on repeat transmission
"+rxcachedir", // recv file cache directory "+rxcachedir", // recv file cache directory
"+segment", // payload segment size (bytes) "+segment", // payload segment size (bytes)
@ -260,6 +262,7 @@ void NormApp::ShowHelp()
" +interval, // delay time (sec) between files (0.0 sec default)\n" " +interval, // delay time (sec) between files (0.0 sec default)\n"
" +repeatcount, // How many times to repeat the file/directory list tx\n" " +repeatcount, // How many times to repeat the file/directory list tx\n"
" +rinterval, // Interval (sec) between file/directory list repeats\n" " +rinterval, // Interval (sec) between file/directory list repeats\n"
" -oneshot, // Exit upon sender TX_FLUSH_COMPLETED event (sender exits after transmission)\n"
" -updatesOnly, // only send updated files on repeat transmission\n" " -updatesOnly, // only send updated files on repeat transmission\n"
" +rxcachedir, // recv file cache directory\n" " +rxcachedir, // recv file cache directory\n"
" +segment, // payload segment size (bytes)\n" " +segment, // payload segment size (bytes)\n"
@ -628,6 +631,10 @@ bool NormApp::OnCommand(const char* cmd, const char* val)
tx_repeat_interval = 0.0; tx_repeat_interval = 0.0;
return false; return false;
} }
}
else if (!strncmp("oneshot", cmd, len))
{
tx_one_shot = true;
} }
else if (!strncmp("updatesOnly", cmd, len)) else if (!strncmp("updatesOnly", cmd, len))
{ {
@ -915,7 +922,7 @@ void NormApp::OnInputReady()
{ {
if (input_msg_length) if (input_msg_length)
{ {
UINT16 bufferSpace = 1024 - input_index; UINT16 bufferSpace = 65535 - input_index;
UINT16 msgRemainder = input_msg_length - input_msg_index; UINT16 msgRemainder = input_msg_length - input_msg_index;
readLength = MIN(bufferSpace, msgRemainder); readLength = MIN(bufferSpace, msgRemainder);
} }
@ -928,14 +935,14 @@ void NormApp::OnInputReady()
memcpy(&input_msg_length, input_buffer, 2); memcpy(&input_msg_length, input_buffer, 2);
input_msg_length = ntohs(input_msg_length); input_msg_length = ntohs(input_msg_length);
ASSERT(input_msg_length >= 2); ASSERT(input_msg_length >= 2);
UINT16 bufferSpace = 1024 - input_index; UINT16 bufferSpace = 65535 - input_index;
UINT16 msgRemainder = input_msg_length - 2; UINT16 msgRemainder = input_msg_length - 2;
readLength = MIN(bufferSpace, msgRemainder); readLength = MIN(bufferSpace, msgRemainder);
} }
} }
else else
{ {
readLength = 1024; readLength = segment_size;
} }
// Read from "input" into our "input_buffer" // Read from "input" into our "input_buffer"
@ -1005,21 +1012,21 @@ void NormApp::OnInputReady()
if (writeLength || endOfStream) if (writeLength || endOfStream)
{ {
unsigned int wroteLength = tx_stream->Write(input_buffer+input_index, unsigned int wroteLength = tx_stream->Write(input_buffer+input_index,
writeLength, false); writeLength, false);
input_length -= wroteLength; input_length -= wroteLength;
if (0 == input_length) if (0 == input_length)
input_index = 0; input_index = 0;
else else
input_index += wroteLength; input_index += wroteLength;
if (input_messaging) if (input_messaging && (0 != wroteLength))
{ {
input_msg_index += wroteLength; input_msg_index += wroteLength;
if (input_msg_index == input_msg_length) if (input_msg_index == input_msg_length)
{ {
input_msg_index = 0; input_msg_index = 0;
input_msg_length = 0; input_msg_length = 0;
// Mark EOM _and_ flush // Mark EOM
tx_stream->Write(NULL, 0, true); tx_stream->Write(NULL, 0, true);
// No need to explicitly flush with "flush mode" set. // No need to explicitly flush with "flush mode" set.
//tx_stream->Flush(); //tx_stream->Flush();
@ -1071,12 +1078,20 @@ void NormApp::Notify(NormController::Event event,
{ {
switch (event) switch (event)
{ {
case TX_QUEUE_VACANCY:
if (NULL != object)
{
if (input && (object == tx_stream))
OnInputReady();
}
break;
case TX_QUEUE_EMPTY: case TX_QUEUE_EMPTY:
// Write to stream as needed // Write to stream as needed
//DMSG(0, "NormApp::Notify(TX_QUEUE_EMPTY) ...\n"); //DMSG(0, "NormApp::Notify(TX_QUEUE_EMPTY) ...\n");
if (object && (object == tx_stream)) if (NULL != object)
{ {
if (input) OnInputReady(); if (input && (object == tx_stream))
OnInputReady();
} }
else else
{ {
@ -1088,6 +1103,14 @@ void NormApp::Notify(NormController::Event event,
OnIntervalTimeout(interval_timer); OnIntervalTimeout(interval_timer);
} }
break; break;
case TX_FLUSH_COMPLETED:
if (tx_one_shot)
{
DMSG(0, "norm: transmit flushing completed, exiting.\n");
Stop();
}
break;
case RX_OBJECT_NEW: case RX_OBJECT_NEW:
{ {
@ -1296,15 +1319,15 @@ void NormApp::Notify(NormController::Event event,
break; break;
} }
} }
else if (readLength > 0)
{
output_msg_sync = true;
output_index += readLength;
}
else else
{ {
if (readLength > 0) output_msg_sync = true;
}
if (readLength)
output_index += readLength;
else
reading = false; reading = false;
}
unsigned int writeLength; unsigned int writeLength;
if (output_messaging) if (output_messaging)
@ -1354,9 +1377,13 @@ void NormApp::Notify(NormController::Event event,
} }
} }
} // end while(put < nBytes) } // end while(put < nBytes)
if (writeLength) memset(output_buffer, 0, writeLength); if (writeLength > 0)
{
memset(output_buffer, 0, writeLength); // why did do this?
fflush(output);
}
} // end while (reading) } // end while (reading)
fflush(output);
break; break;
} }

View File

@ -36,7 +36,6 @@
#include "normEncoder.h" #include "normEncoder.h"
#include "galois.h" // for Galois math routines #include "galois.h" // for Galois math routines
#include "debug.h"
#ifdef SIMULATE #ifdef SIMULATE
#include "normMessage.h" #include "normMessage.h"
@ -44,14 +43,14 @@
NormEncoder::NormEncoder() NormEncoder::NormEncoder()
: npar(0), vector_size(0), : npar(0), vector_size(0),
genPoly(NULL), scratch(NULL) gen_poly(NULL), scratch(NULL)
{ {
} // end NormEncoder::NormEncoder() } // end NormEncoder::NormEncoder()
NormEncoder::~NormEncoder() NormEncoder::~NormEncoder()
{ {
if (genPoly) Destroy(); if (gen_poly) Destroy();
} }
bool NormEncoder::Init(int numParity, int vecSizeMax) bool NormEncoder::Init(int numParity, int vecSizeMax)
@ -59,7 +58,7 @@ bool NormEncoder::Init(int numParity, int vecSizeMax)
// Debugging assertions // Debugging assertions
ASSERT((numParity>=0)&&(numParity<129)); ASSERT((numParity>=0)&&(numParity<129));
ASSERT(vecSizeMax >= 0); ASSERT(vecSizeMax >= 0);
if (genPoly) Destroy(); if (gen_poly) Destroy();
npar = numParity; npar = numParity;
#ifdef SIMULATE #ifdef SIMULATE
@ -67,10 +66,10 @@ bool NormEncoder::Init(int numParity, int vecSizeMax)
#endif // SIMUATE #endif // SIMUATE
vector_size = vecSizeMax; vector_size = vecSizeMax;
// Create generator polynomial // Create gen_poly polynomial
if(!CreateGeneratorPolynomial()) if(!CreateGeneratorPolynomial())
{ {
DMSG(0, "NormEncoder: Error creating generator polynomial!\n"); DMSG(0, "NormEncoder: Error creating gen_poly polynomial!\n");
return false; return false;
} }
// Allocate scratch space for encoding // Allocate scratch space for encoding
@ -92,10 +91,10 @@ void NormEncoder::Destroy()
delete[] scratch; delete[] scratch;
scratch = NULL; scratch = NULL;
} }
if (NULL != genPoly) if (NULL != gen_poly)
{ {
delete[] genPoly; delete[] gen_poly;
genPoly = NULL; gen_poly = NULL;
} }
} // end NormEncoder::Destroy() } // end NormEncoder::Destroy()
@ -104,27 +103,27 @@ bool NormEncoder::CreateGeneratorPolynomial()
{ {
unsigned char *tp, *tp1, *tp2; unsigned char *tp, *tp1, *tp2;
int degree = 2*npar; int degree = 2*npar;
if(genPoly) delete genPoly; if(gen_poly) delete gen_poly;
if(!(genPoly = new unsigned char[npar+1])) if(!(gen_poly = new unsigned char[npar+1]))
{ {
DMSG(0, "NormEncoder: Error allocating memory for generator polynomial: %s\n", DMSG(0, "NormEncoder: Error allocating memory for gen_poly polynomial: %s\n",
GetErrorString()); GetErrorString());
return false; return false;
} }
/* Allocate memory for temporary polynomial arrays */ /* Allocate memory for temporary polynomial arrays */
if(!(tp = new unsigned char[2*degree])) if(!(tp = new unsigned char[2*degree]))
{ {
DMSG(0, "NormEncoder: Error allocating memory while computing genpoly: %s\n", DMSG(0, "NormEncoder: Error allocating memory while computing gen_poly: %s\n",
GetErrorString()); GetErrorString());
delete genPoly; delete gen_poly;
return false; return false;
} }
if(!(tp1 = new unsigned char[2*degree])) if(!(tp1 = new unsigned char[2*degree]))
{ {
delete tp; delete tp;
delete genPoly; delete gen_poly;
DMSG(0, "NormEncoder: Error allocating memory while computing genpoly: %s\n", DMSG(0, "NormEncoder: Error allocating memory while computing gen_poly: %s\n",
GetErrorString()); GetErrorString());
return false; return false;
} }
@ -132,8 +131,8 @@ bool NormEncoder::CreateGeneratorPolynomial()
{ {
delete tp1; delete tp1;
delete tp; delete tp;
delete genPoly; delete gen_poly;
DMSG(0, "NormEncoder: Error allocating memory while computing genpoly: %s\n", DMSG(0, "NormEncoder: Error allocating memory while computing gen_poly: %s\n",
GetErrorString()); GetErrorString());
return false; return false;
} }
@ -146,7 +145,7 @@ bool NormEncoder::CreateGeneratorPolynomial()
tp[0] = gexp(n); // set up x+a^n tp[0] = gexp(n); // set up x+a^n
tp[1] = 1; tp[1] = 1;
// Polynomial multiplication // Polynomial multiplication
memset(genPoly, 0, (npar+1)*sizeof(unsigned char)); memset(gen_poly, 0, (npar+1)*sizeof(unsigned char));
for (int i = 0; i < degree; i++) for (int i = 0; i < degree; i++)
{ {
memset(&tp2[degree], 0, degree*sizeof(unsigned char)); memset(&tp2[degree], 0, degree*sizeof(unsigned char));
@ -157,9 +156,9 @@ bool NormEncoder::CreateGeneratorPolynomial()
for (j = (degree*2)-1; j >= i; j--) tp2[j] = tp2[j-i]; for (j = (degree*2)-1; j >= i; j--) tp2[j] = tp2[j-i];
memset(tp2, 0, i*sizeof(unsigned char)); memset(tp2, 0, i*sizeof(unsigned char));
// Add into partial product // Add into partial product
for(j=0; j < (npar+1); j++) genPoly[j] ^= tp2[j]; for(j=0; j < (npar+1); j++) gen_poly[j] ^= tp2[j];
} }
memcpy(tp1, genPoly, (npar+1)*sizeof(unsigned char)); memcpy(tp1, gen_poly, (npar+1)*sizeof(unsigned char));
memset(&tp1[npar+1], 0, (2*degree)-(npar+1)); memset(&tp1[npar+1], 0, (2*degree)-(npar+1));
} }
delete tp2; delete tp2;
@ -178,7 +177,7 @@ void NormEncoder::Encode(const char *data, char **pVec)
int i, j; int i, j;
unsigned char *userData, *LSFR1, *LSFR2, *pVec0; unsigned char *userData, *LSFR1, *LSFR2, *pVec0;
int npar_minus_one = npar - 1; int npar_minus_one = npar - 1;
unsigned char *gen_poly = &genPoly[npar_minus_one]; unsigned char* genPoly = &gen_poly[npar_minus_one];
ASSERT(scratch); // Make sure it's been init'd first ASSERT(scratch); // Make sure it's been init'd first
// Assumes parity vectors are zero-filled at block start !!! // Assumes parity vectors are zero-filled at block start !!!
// Copy pVec[0] for use in calculations // Copy pVec[0] for use in calculations
@ -200,15 +199,15 @@ void NormEncoder::Encode(const char *data, char **pVec)
LSFR2 = (unsigned char *) pVec[i+1]; LSFR2 = (unsigned char *) pVec[i+1];
for(j = 0; j < vecSize; j++) for(j = 0; j < vecSize; j++)
*LSFR1++ = *LSFR2++ ^ *LSFR1++ = *LSFR2++ ^
gmult(*gen_poly, (*userData++ ^ *pVec0++)); gmult(*genPoly, (*userData++ ^ *pVec0++));
gen_poly--; genPoly--;
} }
} }
pVec0 = scratch; pVec0 = scratch;
userData = (unsigned char *) data; userData = (unsigned char *) data;
LSFR1 = (unsigned char *) pVec[npar_minus_one]; LSFR1 = (unsigned char *) pVec[npar_minus_one];
for(j = 0; j < vecSize; j++) for(j = 0; j < vecSize; j++)
*LSFR1++ = gmult(*gen_poly, (*userData++ ^ *pVec0++)); *LSFR1++ = gmult(*genPoly, (*userData++ ^ *pVec0++));
} // end NormEncoder::Encode() } // end NormEncoder::Encode()
@ -217,15 +216,15 @@ void NormEncoder::Encode(const char *data, char **pVec)
*/ */
NormDecoder::NormDecoder() NormDecoder::NormDecoder()
: npar(0), vector_size(0), Lambda(NULL), : npar(0), vector_size(0), lambda(NULL),
sVec(NULL), oVec(NULL), scratch(NULL) s_vec(NULL), o_vec(NULL), scratch(NULL)
{ {
} }
NormDecoder::~NormDecoder() NormDecoder::~NormDecoder()
{ {
if (Lambda) Destroy(); if (lambda) Destroy();
} }
bool NormDecoder::Init(int numParity, int vecSizeMax) bool NormDecoder::Init(int numParity, int vecSizeMax)
@ -238,22 +237,22 @@ bool NormDecoder::Init(int numParity, int vecSizeMax)
vecSizeMax = MIN(SIM_PAYLOAD_MAX+1, vecSizeMax); vecSizeMax = MIN(SIM_PAYLOAD_MAX+1, vecSizeMax);
#endif // SIMUATE #endif // SIMUATE
if (Lambda) Destroy(); // Check if already inited ... if (lambda) Destroy(); // Check if already inited ...
npar = numParity; npar = numParity;
vector_size = vecSizeMax; vector_size = vecSizeMax;
if(!(Lambda = new unsigned char[2*npar])) if(!(lambda = new unsigned char[2*npar]))
{ {
DMSG(0, "NormDecoder: Error allocating memory for Lambda: %s\n", DMSG(0, "NormDecoder: Error allocating memory for lambda: %s\n",
GetErrorString()); GetErrorString());
return(false); return(false);
} }
/* Allocate memory for sVec ptr and the syndrome vectors */ /* Allocate memory for s_vec ptr and the syndrome vectors */
if(!(sVec = new unsigned char*[npar])) if(!(s_vec = new unsigned char*[npar]))
{ {
DMSG(0, "NormDecoder: Error allocating memory for sVec ptr: %s\n", DMSG(0, "NormDecoder: Error allocating memory for s_vec ptr: %s\n",
GetErrorString()); GetErrorString());
Destroy(); Destroy();
return(false); return(false);
@ -261,19 +260,19 @@ bool NormDecoder::Init(int numParity, int vecSizeMax)
int i; int i;
for(i=0; i < npar; i++) for(i=0; i < npar; i++)
{ {
if(!(sVec[i] = new unsigned char[vecSizeMax])) if(!(s_vec[i] = new unsigned char[vecSizeMax]))
{ {
DMSG(0, "NormDecoder: Error allocating memory for new sVec: %s\n", DMSG(0, "NormDecoder: Error allocating memory for new s_vec: %s\n",
GetErrorString()); GetErrorString());
Destroy(); Destroy();
return(false); return(false);
} }
} }
/* Allocate memory for the oVec ptr and the Omega vectors */ /* Allocate memory for the o_vec ptr and the Omega vectors */
if(!(oVec = new unsigned char*[npar])) if(!(o_vec = new unsigned char*[npar]))
{ {
DMSG(0, "NormDecoder: Error allocating memory for new oVec ptr: %s\n", DMSG(0, "NormDecoder: Error allocating memory for new o_vec ptr: %s\n",
GetErrorString()); GetErrorString());
Destroy(); Destroy();
return(false); return(false);
@ -281,9 +280,9 @@ bool NormDecoder::Init(int numParity, int vecSizeMax)
for(i=0; i < npar; i++) for(i=0; i < npar; i++)
{ {
if(!(oVec[i] = new unsigned char[vecSizeMax])) if(!(o_vec[i] = new unsigned char[vecSizeMax]))
{ {
DMSG(0, "NormDecoder: Error allocating memory for new oVec: %s", DMSG(0, "NormDecoder: Error allocating memory for new o_vec: %s",
GetErrorString()); GetErrorString());
Destroy(); Destroy();
return(false); return(false);
@ -307,25 +306,25 @@ void NormDecoder::Destroy()
delete scratch; delete scratch;
scratch = NULL; scratch = NULL;
} }
if(oVec) if(o_vec)
{ {
for(int i=0; i<npar; i++) for(int i=0; i<npar; i++)
if (oVec[i]) delete oVec[i]; if (o_vec[i]) delete o_vec[i];
delete oVec; delete o_vec;
oVec = NULL; o_vec = NULL;
} }
if(sVec) if(s_vec)
{ {
for(int i = 0; i < npar; i++) for(int i = 0; i < npar; i++)
if (sVec[i]) delete sVec[i]; if (s_vec[i]) delete s_vec[i];
delete sVec; delete s_vec;
sVec = NULL; s_vec = NULL;
} }
if (Lambda) if (lambda)
{ {
delete Lambda; delete lambda;
Lambda = NULL; lambda = NULL;
} }
} // end NormDecoder::Destroy() } // end NormDecoder::Destroy()
@ -334,7 +333,7 @@ void NormDecoder::Destroy()
int NormDecoder::Decode(char** dVec, int ndata, UINT16 erasureCount, UINT16* erasureLocs) int NormDecoder::Decode(char** dVec, int ndata, UINT16 erasureCount, UINT16* erasureLocs)
{ {
// Debugging assertions // Debugging assertions
ASSERT(Lambda); ASSERT(lambda);
ASSERT(erasureCount && (erasureCount<=npar)); ASSERT(erasureCount && (erasureCount<=npar));
// (A) Compute syndrome vectors // (A) Compute syndrome vectors
@ -353,7 +352,7 @@ int NormDecoder::Decode(char** dVec, int ndata, UINT16 erasureCount, UINT16* era
for (i = 0; i < npar; i++) for (i = 0; i < npar; i++)
{ {
int X = gexp(i+1); int X = gexp(i+1);
unsigned char* synVec = sVec[i]; unsigned char* synVec = s_vec[i];
memset(synVec, 0, vecSize*sizeof(char)); memset(synVec, 0, vecSize*sizeof(char));
for(int j = 0; j < nvecs; j++) for(int j = 0; j < nvecs; j++)
{ {
@ -367,29 +366,29 @@ int NormDecoder::Decode(char** dVec, int ndata, UINT16 erasureCount, UINT16* era
} }
} }
// (B) Init Lambda (the erasure locator polynomial) // (B) Init lambda (the erasure locator polynomial)
int degree = 2*npar; int degree = 2*npar;
int nvecsMinusOne = nvecs - 1; int nvecsMinusOne = nvecs - 1;
memset(Lambda, 0, degree*sizeof(char)); memset(lambda, 0, degree*sizeof(char));
Lambda[0] = 1; lambda[0] = 1;
for (i = 0; i < erasureCount; i++) for (i = 0; i < erasureCount; i++)
{ {
int X = gexp(nvecsMinusOne - erasureLocs[i]); int X = gexp(nvecsMinusOne - erasureLocs[i]);
for(int j = (degree-1); j > 0; j--) for(int j = (degree-1); j > 0; j--)
Lambda[j] = Lambda[j] ^ gmult(X, Lambda[j-1]); lambda[j] = lambda[j] ^ gmult(X, lambda[j-1]);
} }
// (C) Compute modified Omega using Lambda // (C) Compute modified Omega using lambda
for(i = 0; i < npar; i++) for(i = 0; i < npar; i++)
{ {
int k = i; int k = i;
memset(oVec[i], 0, vecSize*sizeof(char)); memset(o_vec[i], 0, vecSize*sizeof(char));
int m = i + 1; int m = i + 1;
for(int j = 0; j < m; j++) for(int j = 0; j < m; j++)
{ {
unsigned char* Omega = oVec[i]; unsigned char* Omega = o_vec[i];
unsigned char* S = sVec[j]; unsigned char* S = s_vec[j];
int Lk = Lambda[k--]; int Lk = lambda[k--];
for(int n = 0; n < vecSize; n++) for(int n = 0; n < vecSize; n++)
*Omega++ ^= gmult(*S++, Lk); *Omega++ ^= gmult(*S++, Lk);
} }
@ -401,13 +400,13 @@ int NormDecoder::Decode(char** dVec, int ndata, UINT16 erasureCount, UINT16* era
// Only fill _data_ erasures // Only fill _data_ erasures
if (erasureLocs[i] >= ndata) break;//return erasureCount; if (erasureLocs[i] >= ndata) break;//return erasureCount;
// evaluate Lambda' (derivative) at alpha^(-i) // evaluate lambda' (derivative) at alpha^(-i)
// ( all odd powers disappear) // ( all odd powers disappear)
int k = nvecsMinusOne - erasureLocs[i]; int k = nvecsMinusOne - erasureLocs[i];
int denom = 0; int denom = 0;
int j; int j;
for (j = 1; j < degree; j += 2) for (j = 1; j < degree; j += 2)
denom ^= gmult(Lambda[j], gexp(((255-k)*(j-1)) % 255)); denom ^= gmult(lambda[j], gexp(((255-k)*(j-1)) % 255));
// Invert for use computing error value below // Invert for use computing error value below
denom = ginv(denom); denom = ginv(denom);
@ -416,7 +415,7 @@ int NormDecoder::Decode(char** dVec, int ndata, UINT16 erasureCount, UINT16* era
for (j = 0; j < npar; j++) for (j = 0; j < npar; j++)
{ {
unsigned char* data = eVec; unsigned char* data = eVec;
unsigned char* Omega = oVec[j]; unsigned char* Omega = o_vec[j];
int X = gexp(((255-k)*j) % 255); int X = gexp(((255-k)*j) % 255);
for(int n = 0; n < vecSize; n++) for(int n = 0; n < vecSize; n++)
*data++ ^= gmult(*Omega++, X); *data++ ^= gmult(*Omega++, X);

View File

@ -39,9 +39,9 @@ class NormEncoder
{ {
// Members // Members
private: private:
int npar; // No. of parity packets (N-k) int npar; // No. of parity packets (n-k)
int vector_size; // Size of biggest vector to encode int vector_size; // Size of biggest vector to encode
unsigned char* genPoly; // Ptr to generator polynomial unsigned char* gen_poly; // Ptr to generator polynomial
unsigned char* scratch; // scratch space for encoding unsigned char* scratch; // scratch space for encoding
// Methods // Methods
@ -50,7 +50,8 @@ class NormEncoder
~NormEncoder(); ~NormEncoder();
bool Init(int numParity, int vectorSize); bool Init(int numParity, int vectorSize);
void Destroy(); void Destroy();
bool IsReady(){return (bool)(genPoly != NULL);} bool IsReady(){return (bool)(gen_poly != NULL);}
// "Encode" must be called in order of source vector0, vector1, vector2, etc
void Encode(const char *dataVector, char **parityVectorList); void Encode(const char *dataVector, char **parityVectorList);
int NumParity() {return npar;} int NumParity() {return npar;}
int VectorSize() {return vector_size;} int VectorSize() {return vector_size;}
@ -64,18 +65,18 @@ class NormDecoder
{ {
// Members // Members
private: private:
int npar; // No. of parity packets (n-K) int npar; // No. of parity packets (n-k)
int vector_size; // Size of biggest vector to encode int vector_size; // Size of biggest vector to encode
unsigned char* Lambda; // Erasure location polynomial ("2*npar" ints) unsigned char* lambda; // Erasure location polynomial ("2*npar" ints)
unsigned char** sVec; // Syndrome vectors (pointers to "npar" vectors) unsigned char** s_vec; // Syndrome vectors (pointers to "npar" vectors)
unsigned char** oVec; // Omega vectors (pointers to "npar" vectors) unsigned char** o_vec; // Omega vectors (pointers to "npar" vectors)
unsigned char* scratch; unsigned char* scratch;
// Methods // Methods
public: public:
NormDecoder(); NormDecoder();
~NormDecoder(); ~NormDecoder();
bool Init(int numParity, int vectorSize); bool Init(int numParity, int vectorSize);
int Decode(char **vectorList, int ndata, UINT16 erasureCount, UINT16* erasureLocs); int Decode(char** vectorList, int ndata, UINT16 erasureCount, UINT16* erasureLocs);
int NumParity() {return npar;} int NumParity() {return npar;}
int VectorSize() {return vector_size;} int VectorSize() {return vector_size;}
void Destroy(); void Destroy();

View File

@ -153,7 +153,6 @@ void NormFile::Close()
close(fd); close(fd);
fd = -1; fd = -1;
#endif // if/else WIN32 #endif // if/else WIN32
} }
} // end NormFile::Close() } // end NormFile::Close()
@ -332,35 +331,52 @@ bool NormFile::Rename(const char* oldName, const char* newName)
} }
} // end NormFile::Rename() } // end NormFile::Rename()
int NormFile::Read(char* buffer, int len) size_t NormFile::Read(char* buffer, size_t len)
{ {
ASSERT(IsOpen()); ASSERT(IsOpen());
#ifdef WIN32 #ifdef WIN32
#ifdef _WIN32_WCE #ifdef _WIN32_WCE
size_t result = fread(buffer, 1, len, file_ptr); size_t result = fread(buffer, 1, len, file_ptr);
#else #else
int result = _read(fd, buffer, len); size_t result = _read(fd, buffer, (unsigned int)len);
#endif // if/else _WIN32_WCE #endif // if/else _WIN32_WCE
#else #else
int result = read(fd, buffer, len); ssize_t result = read(fd, buffer, len);
#endif // if/else WIN32 #endif // if/else WIN32
if (result > 0) offset += (Offset)result; if (result < 0)
return result; {
DMSG(0, "NormFile::Read() read(%d) error: %s (fd = %d, offset:%d)\n", len, GetErrorString(), fd, offset);
return 0;
}
else
{
offset += (Offset)result;
return result;
}
} // end NormFile::Read() } // end NormFile::Read()
int NormFile::Write(const char* buffer, int len) size_t NormFile::Write(const char* buffer, size_t len)
{ {
ASSERT(IsOpen()); ASSERT(IsOpen());
#ifdef WIN32 #ifdef WIN32
#ifdef _WIN32_WCE #ifdef _WIN32_WCE
size_t result = fwrite(buffer, 1, len, file_ptr); size_t result = fwrite(buffer, 1, len, file_ptr);
#else #else
int result = _write(fd, buffer, len); size_t result = _write(fd, buffer, (unsigned int)len);
#endif // if/else _WIN32_WCE #endif // if/else _WIN32_WCE
#else #else
int result = write(fd, buffer, len); size_t result = write(fd, buffer, len);
#endif // if/else WIN32 #endif // if/else WIN32
if (result > 0) offset += (Offset)result; if (result < 0)
{
DMSG(0, "NormFile::Write() write() error: %s\n", GetErrorString());
return 0;
}
else
{
offset += (Offset)result;
return result;
}
return result; return result;
} // end NormFile::Write() } // end NormFile::Write()
@ -451,7 +467,7 @@ bool NormDirectoryIterator::Open(const char *thePath)
current = new NormDirectory(thePath); current = new NormDirectory(thePath);
if (current && current->Open()) if (current && current->Open())
{ {
path_len = strlen(current->Path()); path_len = (int)strlen(current->Path());
path_len = MIN(PATH_MAX, path_len); path_len = MIN(PATH_MAX, path_len);
return true; return true;
} }
@ -555,7 +571,7 @@ bool NormDirectoryIterator::GetNextFile(char* fileName)
NormFile::Type type = NormFile::GetType(fileName); NormFile::Type type = NormFile::GetType(fileName);
if (NormFile::NORMAL == type) if (NormFile::NORMAL == type)
{ {
int nameLen = strlen(fileName); size_t nameLen = strlen(fileName);
nameLen = MIN(PATH_MAX, nameLen); nameLen = MIN(PATH_MAX, nameLen);
nameLen -= path_len; nameLen -= path_len;
memmove(fileName, fileName+path_len, nameLen); memmove(fileName, fileName+path_len, nameLen);
@ -682,7 +698,7 @@ NormDirectoryIterator::NormDirectory::NormDirectory(const char* thePath,
#endif // if/else WIN32 #endif // if/else WIN32
{ {
strncpy(path, thePath, PATH_MAX); strncpy(path, thePath, PATH_MAX);
int len = MIN(PATH_MAX, strlen(path)); size_t len = MIN(PATH_MAX, strlen(path));
if ((len < PATH_MAX) && (PROTO_PATH_DELIMITER != path[len-1])) if ((len < PATH_MAX) && (PROTO_PATH_DELIMITER != path[len-1]))
{ {
path[len++] = PROTO_PATH_DELIMITER; path[len++] = PROTO_PATH_DELIMITER;
@ -701,7 +717,7 @@ bool NormDirectoryIterator::NormDirectory::Open()
char fullName[PATH_MAX]; char fullName[PATH_MAX];
GetFullName(fullName); GetFullName(fullName);
// Get rid of trailing PROTO_PATH_DELIMITER // Get rid of trailing PROTO_PATH_DELIMITER
int len = MIN(PATH_MAX, strlen(fullName)); size_t len = MIN(PATH_MAX, strlen(fullName));
if (PROTO_PATH_DELIMITER == fullName[len-1]) fullName[len-1] = '\0'; if (PROTO_PATH_DELIMITER == fullName[len-1]) fullName[len-1] = '\0';
#ifdef WIN32 #ifdef WIN32
#ifdef _UNICODE #ifdef _UNICODE
@ -753,7 +769,7 @@ void NormDirectoryIterator::NormDirectory::GetFullName(char* ptr)
void NormDirectoryIterator::NormDirectory::RecursiveCatName(char* ptr) void NormDirectoryIterator::NormDirectory::RecursiveCatName(char* ptr)
{ {
if (parent) parent->RecursiveCatName(ptr); if (parent) parent->RecursiveCatName(ptr);
int len = MIN(PATH_MAX, strlen(ptr)); size_t len = MIN(PATH_MAX, strlen(ptr));
strncat(ptr, path, PATH_MAX-len); strncat(ptr, path, PATH_MAX-len);
} // end NormDirectoryIterator::NormDirectory::RecursiveCatName() } // end NormDirectoryIterator::NormDirectory::RecursiveCatName()
@ -1020,11 +1036,11 @@ bool NormFileList::Append(const char* path)
bool NormFileList::Remove(const char* path) bool NormFileList::Remove(const char* path)
{ {
FileItem* nextItem = head; FileItem* nextItem = head;
unsigned int pathLen = strlen(path); size_t pathLen = strlen(path);
pathLen = MIN(pathLen, PATH_MAX); pathLen = MIN(pathLen, PATH_MAX);
while (nextItem) while (nextItem)
{ {
unsigned nameLen = strlen(nextItem->Path()); size_t nameLen = strlen(nextItem->Path());
nameLen = MIN(nameLen, PATH_MAX); nameLen = MIN(nameLen, PATH_MAX);
nameLen = MAX(nameLen, pathLen); nameLen = MAX(nameLen, pathLen);
if (!strncmp(path, nextItem->Path(), nameLen)) if (!strncmp(path, nextItem->Path(), nameLen))
@ -1087,7 +1103,7 @@ void NormFileList::GetCurrentBasePath(char* pathBuffer)
if (NormFile::DIRECTORY == next->GetType()) if (NormFile::DIRECTORY == next->GetType())
{ {
strncpy(pathBuffer, next->Path(), PATH_MAX); strncpy(pathBuffer, next->Path(), PATH_MAX);
unsigned int len = strlen(pathBuffer); size_t len = strlen(pathBuffer);
len = MIN(len, PATH_MAX); len = MIN(len, PATH_MAX);
if (PROTO_PATH_DELIMITER != pathBuffer[len-1]) if (PROTO_PATH_DELIMITER != pathBuffer[len-1])
{ {
@ -1100,7 +1116,7 @@ void NormFileList::GetCurrentBasePath(char* pathBuffer)
const char* ptr = strrchr(next->Path(), PROTO_PATH_DELIMITER); const char* ptr = strrchr(next->Path(), PROTO_PATH_DELIMITER);
if (ptr++) if (ptr++)
{ {
unsigned int len = ptr - next->Path(); size_t len = ptr - next->Path();
strncpy(pathBuffer, next->Path(), len); strncpy(pathBuffer, next->Path(), len);
pathBuffer[len] = '\0'; pathBuffer[len] = '\0';
} }
@ -1120,7 +1136,7 @@ void NormFileList::GetCurrentBasePath(char* pathBuffer)
NormFileList::FileItem::FileItem(const char* thePath) NormFileList::FileItem::FileItem(const char* thePath)
: prev(NULL), next(NULL) : prev(NULL), next(NULL)
{ {
unsigned int len = strlen(thePath); size_t len = strlen(thePath);
len = MIN(len, PATH_MAX); len = MIN(len, PATH_MAX);
strncpy(path, thePath, PATH_MAX); strncpy(path, thePath, PATH_MAX);
size = NormFile::GetSize(thePath); size = NormFile::GetSize(thePath);
@ -1195,7 +1211,7 @@ bool NormFileList::DirectoryItem::GetNextFile(char* thePath,
} }
} }
strncpy(thePath, path, PATH_MAX); strncpy(thePath, path, PATH_MAX);
unsigned int len = strlen(thePath); size_t len = strlen(thePath);
len = MIN(len, PATH_MAX); len = MIN(len, PATH_MAX);
if ((PROTO_PATH_DELIMITER != thePath[len-1]) && (len < PATH_MAX)) if ((PROTO_PATH_DELIMITER != thePath[len-1]) && (len < PATH_MAX))
{ {
@ -1205,7 +1221,7 @@ bool NormFileList::DirectoryItem::GetNextFile(char* thePath,
char tempPath[PATH_MAX]; char tempPath[PATH_MAX];
while (diterator.GetNextFile(tempPath)) while (diterator.GetNextFile(tempPath))
{ {
unsigned int maxLen = PATH_MAX - len; size_t maxLen = PATH_MAX - len;
strncat(thePath, tempPath, maxLen); strncat(thePath, tempPath, maxLen);
if (updatesOnly) if (updatesOnly)
{ {

View File

@ -66,8 +66,8 @@ class NormFile
return (fd >= 0); return (fd >= 0);
#endif // _WIN32_WCE #endif // _WIN32_WCE
} }
int Read(char* buffer, int len); size_t Read(char* buffer, size_t len);
int Write(const char* buffer, int len); size_t Write(const char* buffer, size_t len);
bool Seek(Offset theOffset); bool Seek(Offset theOffset);
NormFile::Offset GetOffset() const {return (offset);} NormFile::Offset GetOffset() const {return (offset);}
NormFile::Offset GetSize() const; NormFile::Offset GetSize() const;
@ -112,7 +112,7 @@ class NormFile
// Members // Members
private: //private:
#ifdef _WIN32_WCE #ifdef _WIN32_WCE
FILE* file_ptr; FILE* file_ptr;
#else #else

View File

@ -23,6 +23,11 @@ const UINT8 NORM_PROTOCOL_VERSION = 1;
const int NORM_ROBUST_FACTOR = 20; // default robust factor const int NORM_ROBUST_FACTOR = 20; // default robust factor
// This value is used in a couple places in the code as
// a safety check where some critical timeouts may be
// less than expected operating system clock resolution
const double NORM_TICK_MIN = 0.100; // in seconds
// Pick a random number from 0..max // Pick a random number from 0..max
inline double UniformRand(double max) inline double UniformRand(double max)
{ {
@ -41,6 +46,7 @@ inline double ExponentialRand(double max, double groupSize)
// These are the GRTT estimation bounds set for the current // These are the GRTT estimation bounds set for the current
// NORM protocol. (Note that our Grtt quantization routines // NORM protocol. (Note that our Grtt quantization routines
// are good for the range of 1.0e-06 <= 1000.0) // are good for the range of 1.0e-06 <= 1000.0)
const double NORM_GRTT_MIN = 0.001; // 1 msec const double NORM_GRTT_MIN = 0.001; // 1 msec
const double NORM_GRTT_MAX = 15.0; // 15 sec const double NORM_GRTT_MAX = 15.0; // 15 sec
const double NORM_RTT_MIN = 1.0e-06; const double NORM_RTT_MIN = 1.0e-06;
@ -225,8 +231,8 @@ class NormHeaderExtension
enum Type enum Type
{ {
INVALID = 0, INVALID = 0,
FTI = 1, // FEC Object Transmission Information (FTI) extension FTI = 64, // FEC Object Transmission Information (FTI) extension
CC_FEEDBACK = 2, // NORM-CC Feedback extension CC_FEEDBACK = 3, // NORM-CC Feedback extension
CC_RATE = 128 // NORM-CC Rate extension CC_RATE = 128 // NORM-CC Rate extension
}; };
@ -350,6 +356,8 @@ class NormMsg
char* AccessBuffer() {return ((char*)buffer);} char* AccessBuffer() {return ((char*)buffer);}
ProtoAddress& AccessAddress() {return addr;} ProtoAddress& AccessAddress() {return addr;}
NormMsg* GetNext() {return next;}
protected: protected:
// Common message header offsets // Common message header offsets
// All of our offsets reflect their offset based on the field size! // All of our offsets reflect their offset based on the field size!
@ -400,8 +408,8 @@ class NormObjectMsg : public NormMsg
FLAG_INFO = 0x04, FLAG_INFO = 0x04,
FLAG_UNRELIABLE = 0x08, FLAG_UNRELIABLE = 0x08,
FLAG_FILE = 0x10, FLAG_FILE = 0x10,
FLAG_STREAM = 0x20, FLAG_STREAM = 0x20
FLAG_MSG_START = 0x40 //FLAG_MSG_START = 0x40 deprecated
}; };
UINT16 GetInstanceId() const UINT16 GetInstanceId() const
{ {
@ -632,6 +640,7 @@ class NormDataMsg : public NormObjectMsg
// Some static helper routines for reading/writing embedded payload length/offsets // Some static helper routines for reading/writing embedded payload length/offsets
static UINT16 GetStreamPayloadHeaderLength() {return (PAYLOAD_DATA_OFFSET);} static UINT16 GetStreamPayloadHeaderLength() {return (PAYLOAD_DATA_OFFSET);}
/* Payload flags have deprecated in the revised NORM spec
enum PayloadFlag enum PayloadFlag
{ {
FLAG_STREAM_END = 0x01, FLAG_STREAM_END = 0x01,
@ -649,6 +658,11 @@ class NormDataMsg : public NormObjectMsg
static void SetStreamPayloadFlag(char* payload, PayloadFlag flag) static void SetStreamPayloadFlag(char* payload, PayloadFlag flag)
{ {
((UINT8*)payload)[PAYLOAD_FLAGS_OFFSET] |= flag; ((UINT8*)payload)[PAYLOAD_FLAGS_OFFSET] |= flag;
}*/
static void WriteStreamPayloadMsgStart(char* payload, UINT16 msgStartOffset)
{
UINT16 temp16 = htons(msgStartOffset);
memcpy(payload+PAYLOAD_MSG_START_OFFSET, &temp16, 2);
} }
static void WriteStreamPayloadLength(char* payload, UINT16 len) static void WriteStreamPayloadLength(char* payload, UINT16 len)
{ {
@ -660,6 +674,12 @@ class NormDataMsg : public NormObjectMsg
UINT32 temp32 = htonl(offset); UINT32 temp32 = htonl(offset);
memcpy(payload+PAYLOAD_OFFSET_OFFSET, &temp32, 4); memcpy(payload+PAYLOAD_OFFSET_OFFSET, &temp32, 4);
} }
static UINT16 ReadStreamPayloadMsgStart(const char* payload)
{
UINT16 temp16;
memcpy(&temp16, payload+PAYLOAD_MSG_START_OFFSET, 2);
return (ntohs(temp16));
}
static UINT16 ReadStreamPayloadLength(const char* payload) static UINT16 ReadStreamPayloadLength(const char* payload)
{ {
UINT16 temp16; UINT16 temp16;
@ -685,11 +705,11 @@ class NormDataMsg : public NormObjectMsg
}; };
enum enum
{ {
PAYLOAD_FLAGS_OFFSET = 0, //PAYLOAD_FLAGS_OFFSET = 0, // deprecated
PAYLOAD_RESERVED_OFFSET = PAYLOAD_FLAGS_OFFSET+1, // this is not in the NORM spec! PAYLOAD_MSG_START_OFFSET = 0,
PAYLOAD_LENGTH_OFFSET = PAYLOAD_RESERVED_OFFSET+1, PAYLOAD_LENGTH_OFFSET = PAYLOAD_MSG_START_OFFSET+2,
PAYLOAD_OFFSET_OFFSET = PAYLOAD_LENGTH_OFFSET+2, PAYLOAD_OFFSET_OFFSET = PAYLOAD_LENGTH_OFFSET+2,
PAYLOAD_DATA_OFFSET = PAYLOAD_OFFSET_OFFSET+4 PAYLOAD_DATA_OFFSET = PAYLOAD_OFFSET_OFFSET+4
}; };
}; // end class NormDataMsg }; // end class NormDataMsg
@ -1589,6 +1609,7 @@ class NormMessageQueue
void Remove(NormMsg* msg); void Remove(NormMsg* msg);
NormMsg* RemoveHead(); NormMsg* RemoveHead();
NormMsg* RemoveTail(); NormMsg* RemoveTail();
NormMsg* GetHead() {return head;}
bool IsEmpty() {return ((NormMsg*)NULL == head);} bool IsEmpty() {return ((NormMsg*)NULL == head);}
private: private:

View File

@ -160,9 +160,10 @@ bool NormServerNode::AllocateBuffers(UINT16 segmentSize,
// enforced. Note that "bufferFactor" values > 0.0 help reduce "seeking" for decoding, // enforced. Note that "bufferFactor" values > 0.0 help reduce "seeking" for decoding,
// but reduce the number of blocks for which NORM can keep state. Note this only comes // but reduce the number of blocks for which NORM can keep state. Note this only comes
// into play when NORM would be "buffer constrained" // into play when NORM would be "buffer constrained"
// (TBD) perhaps we should keep more "block state" than we can even buffer parity for ??? // (TBD) perhaps we should keep state for more blocks than we can even buffer parity for ???
// (this would reduce requests for full block retransmissions when resource contrained) // (this would reduce requests for full block retransmissions when resource constrained)
double bufferFactor = 0.0; // (this would correspond to "bufferFactor < 0.0"
double bufferFactor = 0.0; // (TBD) let app control "bufferFactor"???
unsigned long segPerBlock = unsigned long segPerBlock =
(unsigned long) ((bufferFactor * (double)numData) + (unsigned long) ((bufferFactor * (double)numData) +
((1.0 - bufferFactor) * (double)numParity) + 0.5); ((1.0 - bufferFactor) * (double)numParity) + 0.5);
@ -206,7 +207,8 @@ bool NormServerNode::AllocateBuffers(UINT16 segmentSize,
memset(retrieval_pool, 0, numData*sizeof(char*)); memset(retrieval_pool, 0, numData*sizeof(char*));
for (UINT16 i = 0; i < numData; i++) for (UINT16 i = 0; i < numData; i++)
{ {
char* s = new char[segmentSize+NormDataMsg::GetStreamPayloadHeaderLength()]; // allocate segment with extra byte for stream flags ...
char* s = new char[segmentSize+NormDataMsg::GetStreamPayloadHeaderLength()+1];
if (NULL == s) if (NULL == s)
{ {
DMSG(0, "NormServerNode::AllocateBuffers() new retrieval segment error: %s\n", GetErrorString()); DMSG(0, "NormServerNode::AllocateBuffers() new retrieval segment error: %s\n", GetErrorString());
@ -240,6 +242,7 @@ bool NormServerNode::AllocateBuffers(UINT16 segmentSize,
nominal_packet_size = (double)segmentSize; nominal_packet_size = (double)segmentSize;
ndata = numData; ndata = numData;
nparity = numParity; nparity = numParity;
IncrementResyncCount();
return true; return true;
} // end NormServerNode::AllocateBuffers() } // end NormServerNode::AllocateBuffers()
@ -326,6 +329,7 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime,
static_cast<NormStreamObject*>(obj)->Prune(blockId, true); static_cast<NormStreamObject*>(obj)->Prune(blockId, true);
} }
// 3) (TBD) Go ahead and discard any invalidated objects // 3) (TBD) Go ahead and discard any invalidated objects
// (those listed with id's > objectId)
// (although they will eventually get discarded anyway) // (although they will eventually get discarded anyway)
break; break;
} }
@ -391,7 +395,6 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime,
double backoffFactor = backoff_factor; double backoffFactor = backoff_factor;
backoffFactor = MAX(backoffFactor, 4.0); backoffFactor = MAX(backoffFactor, 4.0);
maxBackoff = grtt_estimate*backoffFactor; maxBackoff = grtt_estimate*backoffFactor;
} }
double backoffTime = (maxBackoff > 0.0) ? double backoffTime = (maxBackoff > 0.0) ?
ExponentialRand(maxBackoff, gsize_estimate) : ExponentialRand(maxBackoff, gsize_estimate) :
@ -415,7 +418,7 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime,
} }
//DMSG(0, "NormServerNode::HandleCommand(CC) node>%lu bias:%lf recv_rate:%lf send_rate:%lf " //DMSG(0, "NormServerNode::HandleCommand(CC) node>%lu bias:%lf recv_rate:%lf send_rate:%lf "
// "grtt:%lf gsize:%lf\n", // "grtt:%lf gsize:%lf\n",
// LocalNodeId(), r, recv_rate*(8.0/1000.0), send_rate*(8.0/1000.0), // LocalNodeId(), r, 8.0e-03*recv_rate, 8.0e-03*send_rate,
// //
backoffTime = 0.25 * r * maxBackoff + 0.75 * backoffTime; backoffTime = 0.25 * r * maxBackoff + 0.75 * backoffTime;
@ -491,7 +494,7 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime,
case NormCmdMsg::REPAIR_ADV: case NormCmdMsg::REPAIR_ADV:
{ {
const NormCmdRepairAdvMsg& repairAdv = (const NormCmdRepairAdvMsg&)cmd; const NormCmdRepairAdvMsg& repairAdv = (const NormCmdRepairAdvMsg&)cmd;
// Does the CC feedback of this ACK suppress our CC feedback // Does the CC feedback of this ACK suppress our CC feedback?
if (!is_clr && !is_plr && cc_timer.IsActive() && if (!is_clr && !is_plr && cc_timer.IsActive() &&
cc_timer.GetRepeatCount()) cc_timer.GetRepeatCount())
{ {
@ -507,6 +510,7 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime,
} }
if (repair_timer.IsActive() && repair_timer.GetRepeatCount()) if (repair_timer.IsActive() && repair_timer.GetRepeatCount())
{ {
// (TBD) pay attention to the NORM_REPAIR_ADV_LIMIT flag
HandleRepairContent(repairAdv.GetRepairContent(), HandleRepairContent(repairAdv.GetRepairContent(),
repairAdv.GetRepairContentLength()); repairAdv.GetRepairContentLength());
} }
@ -522,7 +526,7 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime,
void NormServerNode::HandleCCFeedback(UINT8 ccFlags, double ccRate) void NormServerNode::HandleCCFeedback(UINT8 ccFlags, double ccRate)
{ {
ASSERT(cc_timer.IsActive() && cc_timer.GetRepeatCount()); //ASSERT(cc_timer.IsActive() && cc_timer.GetRepeatCount());
if (0 == (ccFlags & NormCC::CLR)) if (0 == (ccFlags & NormCC::CLR))
{ {
// We're suppressed by non-CLR receivers with no RTT confirmed // We're suppressed by non-CLR receivers with no RTT confirmed
@ -532,6 +536,8 @@ void NormServerNode::HandleCCFeedback(UINT8 ccFlags, double ccRate)
NormSession::CalculateRate(nominal_packet_size, NormSession::CalculateRate(nominal_packet_size,
rtt_estimate, rtt_estimate,
LossEstimate()); LossEstimate());
// This increases our chance of being suppressed
// (but is it a good idea?)
localRate = MAX(localRate, cc_rate); localRate = MAX(localRate, cc_rate);
bool hasRtt = (0 != (ccFlags & NormCC::RTT)); bool hasRtt = (0 != (ccFlags & NormCC::RTT));
@ -562,7 +568,9 @@ void NormServerNode::HandleCCFeedback(UINT8 ccFlags, double ccRate)
if (suppressed) if (suppressed)
{ {
if (cc_timer.IsActive()) cc_timer.Deactivate(); if (cc_timer.IsActive()) cc_timer.Deactivate();
cc_timer.SetInterval(grtt_estimate*backoff_factor); // (TBD) ??? double backoffFactor = backoff_factor;
backoffFactor = MAX(backoffFactor, 4.0); // always use at least 4 for cc purposes
cc_timer.SetInterval(grtt_estimate*backoffFactor); // (TBD) ??? xxx
session.ActivateTimer(cc_timer); session.ActivateTimer(cc_timer);
cc_timer.DecrementRepeatCount(); cc_timer.DecrementRepeatCount();
} }
@ -609,6 +617,7 @@ void NormServerNode::HandleNackMessage(const NormNackMsg& nack)
// Clients use this method to process NACK content overheard from other // Clients use this method to process NACK content overheard from other
// clients or via NORM_CMD(REPAIR_ADV) messages received from the server. // clients or via NORM_CMD(REPAIR_ADV) messages received from the server.
// Such content can "suppress" pending NACKs // Such content can "suppress" pending NACKs
// (TBD) add provision to handle case when NORM_REPAIR_ADV_FLAG_LIMIT was set
void NormServerNode::HandleRepairContent(const UINT32* buffer, UINT16 bufferLen) void NormServerNode::HandleRepairContent(const UINT32* buffer, UINT16 bufferLen)
{ {
// Parse NACK and incorporate into repair state masks // Parse NACK and incorporate into repair state masks
@ -851,7 +860,8 @@ char* NormServerNode::GetFreeSegment(NormObjectId objectId, NormBlockId blockId)
break; break;
} }
} }
return segment_pool.Get(); char* result = segment_pool.Get();
return result;
} // end NormServerNode::GetFreeSegment() } // end NormServerNode::GetFreeSegment()
void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg) void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg)
@ -1478,7 +1488,7 @@ bool NormServerNode::OnRepairTimeout(ProtoTimer& /*theTimer*/)
ext.SetCCRate(NormQuantizeRate(ccRate)); ext.SetCCRate(NormQuantizeRate(ccRate));
} }
DMSG(6, "NormServerNode::OnRepairTimeout() node>%lu sending NACK rate:%lf kbps (rtt:%lf loss:%lf s:%hu) slow_start:%d\n", DMSG(6, "NormServerNode::OnRepairTimeout() node>%lu sending NACK rate:%lf kbps (rtt:%lf loss:%lf s:%hu) slow_start:%d\n",
LocalNodeId(), NormUnquantizeRate(ext.GetCCRate()) * (8.0/1000.0), LocalNodeId(), 8.0e-03*NormUnquantizeRate(ext.GetCCRate()),
rtt_estimate, ccLoss, nominal_packet_size, slow_start); rtt_estimate, ccLoss, nominal_packet_size, slow_start);
ext.SetCCSequence(cc_sequence); ext.SetCCSequence(cc_sequence);
// Cancel potential pending NORM_ACK(RTT) // Cancel potential pending NORM_ACK(RTT)
@ -1675,25 +1685,23 @@ void NormServerNode::UpdateRecvRate(const struct timeval& currentTime, unsigned
{ {
if (prev_update_time.tv_sec || prev_update_time.tv_usec) if (prev_update_time.tv_sec || prev_update_time.tv_usec)
{ {
recv_accumulator += msgSize;
double interval = (double)(currentTime.tv_sec - prev_update_time.tv_sec); double interval = (double)(currentTime.tv_sec - prev_update_time.tv_sec);
if (currentTime.tv_usec > prev_update_time.tv_sec) if (currentTime.tv_usec > prev_update_time.tv_sec)
interval += 1.0e-06*(double)(currentTime.tv_usec - prev_update_time.tv_usec); interval += 1.0e-06*(double)(currentTime.tv_usec - prev_update_time.tv_usec);
else else
interval -= 1.0e-06*(double)(prev_update_time.tv_usec - currentTime.tv_usec); interval -= 1.0e-06*(double)(prev_update_time.tv_usec - currentTime.tv_usec);
double measurementInterval = rtt_confirmed ? rtt_estimate : grtt_estimate; double measurementInterval = rtt_confirmed ? rtt_estimate : grtt_estimate;
// Here, we put a 0.100 sec lower bound on our measurementInterval for the // Here, we put a NORM_TICK_MIN sec lower bound on our measurementInterval for the
// recv_rate because of the typical limited granularity of our system clock // recv_rate because of the typical limited granularity of our system clock
// (Note this does limit our ramp up of data rate during slow start) // (Note this does limit our ramp up of data rate during slow start)
if (measurementInterval < 0.100) measurementInterval = 0.100; if (measurementInterval < NORM_TICK_MIN) measurementInterval = NORM_TICK_MIN;
if (interval > 0.0) if (interval > 0.0)
{ {
double currentRecvRate = ((double)(recv_accumulator)) / interval; double currentRecvRate = ((double)(recv_accumulator)) / interval;
if (currentRecvRate < recv_rate) if ((interval >= measurementInterval) && (currentRecvRate < recv_rate))
{ {
// Make sure we've allowed sufficient time for a measurement // Make sure we've allowed sufficient time for a measurement at low rates
double minInterval = 4.0 * ((double)nominal_packet_size) / recv_rate; double minInterval = 4.0 * ((double)(MAX(nominal_packet_size, segment_size)))/ recv_rate;
if (measurementInterval < minInterval) if (measurementInterval < minInterval)
measurementInterval = minInterval; measurementInterval = minInterval;
} }
@ -1701,46 +1709,28 @@ void NormServerNode::UpdateRecvRate(const struct timeval& currentTime, unsigned
{ {
recv_rate = currentRecvRate; //((double)(recv_accumulator)) / interval; recv_rate = currentRecvRate; //((double)(recv_accumulator)) / interval;
prev_update_time = currentTime; prev_update_time = currentTime;
recv_accumulator = 0; recv_accumulator = msgSize;
}
else
{
recv_accumulator += msgSize;
} }
} }
/*
// We put a 0.100 sec lower bound on our rttEstimate for the recv_rate measurement
// interval because of the typical limited granularity of our system clock
// (Note this does limit our ramp up of data rate during slow start)
if (rttEstimate < 0.1) rttEstimate = 0.1;
rttEstimate = rttEstimate < 0.1 ? 0.1 : rttEstimate;
// Also, don't update more than nominal_packet_size / recv_rate
// or our measurement is subject to quantization error
double minterval = recv_rate > 0.0 ? 2.0 * ((double)nominal_packet_size) / recv_rate : rttEstimate;
rttEstimate = rttEstimate < minterval ? minterval : rttEstimate;
if (interval >= rttEstimate)
{
recv_rate = ((double)(recv_accumulator)) / interval;
prev_update_time = currentTime;
recv_accumulator = 0;
}*/
//TRACE("updated recv rate to %lf (accum:%lu) (cc_rate:%lf)\n", recv_rate,
// recv_accumulator, cc_rate);
} }
else else
{ {
if (send_rate > 0.0) /*if (send_rate > 0.0)
recv_rate = send_rate; recv_rate = send_rate;
else else
recv_rate = ((double)msgSize) / grtt_estimate; recv_rate = ((double)msgSize) / grtt_estimate;*/
recv_rate = 0.0;
prev_update_time = currentTime; prev_update_time = currentTime;
recv_accumulator = 0; recv_accumulator = msgSize;
} }
nominal_packet_size += 0.05 * (((double)msgSize) - nominal_packet_size); nominal_packet_size += 0.05 * (((double)msgSize) - nominal_packet_size);
} // end NormServerNode::UpdateRecvRate() } // end NormServerNode::UpdateRecvRate()
void NormServerNode::Activate() void NormServerNode::Activate(bool isObjectMsg)
{ {
if (!activity_timer.IsActive()) if (!activity_timer.IsActive())
{ {
@ -1749,7 +1739,7 @@ void NormServerNode::Activate()
server_active = false; server_active = false;
session.Notify(NormController::REMOTE_SERVER_ACTIVE, this, NULL); session.Notify(NormController::REMOTE_SERVER_ACTIVE, this, NULL);
} }
else else if (isObjectMsg)
{ {
server_active = true; server_active = true;
} }
@ -1797,9 +1787,19 @@ bool NormServerNode::OnActivityTimeout(ProtoTimer& /*theTimer*/)
max_pending_object, 0, 0); max_pending_object, 0, 0);
} }
else else
RepairCheck(NormObject::TO_BLOCK, // (TBD) thru object??? {
RepairCheck(NormObject::THRU_OBJECT, // (TBD) thru object???
max_pending_object, 0, 0); max_pending_object, 0, 0);
//RepairCheck(NormObject::TO_BLOCK, // (TBD) thru object???
// max_pending_object, 0, 0);
}
} }
// At low recv data rates, we adjust the activity timeout a little.
// to _help_ prevent premature timeout
double nominalInterval = nominal_packet_size / recv_rate;
if (grtt_estimate < nominalInterval)
activity_timer.SetInterval(NORM_ROBUST_FACTOR * nominalInterval);
} }
server_active = false; server_active = false;
return true; return true;
@ -1851,11 +1851,11 @@ void NormServerNode::AttachCCFeedback(NormAckMsg& ack)
rtt_estimate, ccLoss); rtt_estimate, ccLoss);
ext.SetCCRate(NormQuantizeRate(ccRate)); ext.SetCCRate(NormQuantizeRate(ccRate));
} }
//DMSG(0, "NormServerNode::OnCCTimeout() node>%lu sending ACK rate:%lf kbps (rtt:%lf loss:%lf s:%lf recvRate:%lf) slow_start:%d\n", //DMSG(0, "NormServerNode::AttachCCFeedback() node>%lu sending ACK rate:%lf kbps (rtt:%lf loss:%lf s:%lf recvRate:%lf) slow_start:%d\n",
// LocalNodeId(), NormUnquantizeRate(ext.GetCCRate()) * (8.0/1000.0), // LocalNodeId(), 8.0e-03*NormUnquantizeRate(ext.GetCCRate()) ,
// rtt_estimate, ccLoss, nominal_packet_size, recv_rate*(8.0/1000.), slow_start); // rtt_estimate, ccLoss, nominal_packet_size, 8.0e-03*recv_rate, slow_start);
ext.SetCCSequence(cc_sequence); ext.SetCCSequence(cc_sequence);
} // end } // end ormServerNode::AttachCCFeedback()
bool NormServerNode::OnCCTimeout(ProtoTimer& /*theTimer*/) bool NormServerNode::OnCCTimeout(ProtoTimer& /*theTimer*/)
{ {
@ -1901,8 +1901,16 @@ bool NormServerNode::OnCCTimeout(ProtoTimer& /*theTimer*/)
//} //}
// Begin cc_timer "holdoff" phase // Begin cc_timer "holdoff" phase
cc_timer.SetInterval(grtt_estimate*backoff_factor); if (session.Address().IsMulticast())
return true; {
cc_timer.SetInterval(grtt_estimate*backoff_factor);
return true;
}
else if (cc_timer.IsActive())
{
cc_timer.Deactivate();
}
break;
} }
default: default:
@ -1935,7 +1943,7 @@ bool NormServerNode::OnAckTimeout(ProtoTimer& /*theTimer*/)
// Don't rate limit feedback messages // Don't rate limit feedback messages
session.SendMessage(*ack); session.SendMessage(*ack);
session.ReturnMessageToPool(ack); session.ReturnMessageToPool(ack);
if (!is_clr && !is_plr) if (!is_clr && !is_plr && session.Address().IsMulticast())
{ {
// Install cc feedback holdoff // Install cc feedback holdoff
if (cc_timer.IsActive()) cc_timer.Deactivate(); if (cc_timer.IsActive()) cc_timer.Deactivate();
@ -1943,6 +1951,11 @@ bool NormServerNode::OnAckTimeout(ProtoTimer& /*theTimer*/)
session.ActivateTimer(cc_timer); session.ActivateTimer(cc_timer);
cc_timer.DecrementRepeatCount(); cc_timer.DecrementRepeatCount();
} }
else if (cc_timer.IsActive())
{
cc_timer.Deactivate();
return false;
}
} }
else else
{ {

View File

@ -261,7 +261,7 @@ class NormServerNode : public NormNode
bool AllocateBuffers(UINT16 segmentSize, UINT16 numData, UINT16 numParity); bool AllocateBuffers(UINT16 segmentSize, UINT16 numData, UINT16 numParity);
bool BuffersAllocated() {return (0 != segment_size);} bool BuffersAllocated() {return (0 != segment_size);}
void FreeBuffers(); void FreeBuffers();
void Activate(); void Activate(bool isObjectMsg);
bool SyncTest(const NormObjectMsg& msg) const; bool SyncTest(const NormObjectMsg& msg) const;

View File

@ -1208,6 +1208,7 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg,
if (isSourceSymbol) if (isSourceSymbol)
{ {
block->DecrementErasureCount(); block->DecrementErasureCount();
/* STREAM payload flags have been deprecated in favor of "payload_msg_start"
// This bit of code makes sure that NORM Protocol Version 1 // This bit of code makes sure that NORM Protocol Version 1
// use of FLAG_MSG_START is observed even when the equivalent (and better!) // use of FLAG_MSG_START is observed even when the equivalent (and better!)
// stream payload flag is not used. // stream payload flag is not used.
@ -1221,6 +1222,7 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg,
NormDataMsg::SetStreamPayloadFlag((char*)data.GetPayload(), NormDataMsg::FLAG_MSG_START); NormDataMsg::SetStreamPayloadFlag((char*)data.GetPayload(), NormDataMsg::FLAG_MSG_START);
} }
} }
*/
if (WriteSegment(blockId, segmentId, data.GetPayload())) if (WriteSegment(blockId, segmentId, data.GetPayload()))
{ {
@ -1585,13 +1587,14 @@ bool NormObject::NextServerMsg(NormObjectMsg* msg)
} }
data->SetPayloadLength(payloadLength); data->SetPayloadLength(payloadLength);
/* stream payload flags have been deprecated in favor of "payload_msg_start" field
// Set FLAG_MSG_START as appropriated for NORM Protocol Version 1 compatibility // Set FLAG_MSG_START as appropriated for NORM Protocol Version 1 compatibility
if (IsStream()) if (IsStream())
{ {
if (NormDataMsg::StreamPayloadFlagIsSet(buffer, NormDataMsg::FLAG_MSG_START)) if (NormDataMsg::StreamPayloadFlagIsSet(buffer, NormDataMsg::FLAG_MSG_START))
data->SetFlag(NormObjectMsg::FLAG_MSG_START); data->SetFlag(NormObjectMsg::FLAG_MSG_START);
} }
*/
// Perform incremental FEC encoding as needed // Perform incremental FEC encoding as needed
if ((block->ParityReadiness() == segmentId) && nparity) if ((block->ParityReadiness() == segmentId) && nparity)
// (TBD) && incrementalParity == true // (TBD) && incrementalParity == true
@ -1794,7 +1797,7 @@ bool NormFileObject::Open(const char* thePath,
} }
else else
{ {
if (file.Open(thePath, O_WRONLY | O_CREAT | O_TRUNC)) if (file.Open(thePath, O_RDWR | O_CREAT | O_TRUNC))
{ {
file.Lock(); file.Lock();
} }
@ -1849,7 +1852,7 @@ bool NormFileObject::Open(const char* thePath,
large_block_length = NormObjectSize(large_block_size) * segment_size; large_block_length = NormObjectSize(large_block_size) * segment_size;
small_block_length = NormObjectSize(small_block_size) * segment_size; small_block_length = NormObjectSize(small_block_size) * segment_size;
strncpy(path, thePath, PATH_MAX); strncpy(path, thePath, PATH_MAX);
unsigned int len = strlen(thePath); size_t len = strlen(thePath);
len = MIN(len, PATH_MAX); len = MIN(len, PATH_MAX);
if (len < PATH_MAX) path[len] = '\0'; if (len < PATH_MAX) path[len] = '\0';
return true; return true;
@ -1878,7 +1881,7 @@ bool NormFileObject::WriteSegment(NormBlockId blockId,
NormSegmentId segmentId, NormSegmentId segmentId,
const char* buffer) const char* buffer)
{ {
UINT16 len; size_t len;
if (blockId == final_block_id) if (blockId == final_block_id)
{ {
if (segmentId == (GetBlockSize(blockId)-1)) if (segmentId == (GetBlockSize(blockId)-1))
@ -1909,7 +1912,7 @@ bool NormFileObject::WriteSegment(NormBlockId blockId,
{ {
if (!file.Seek(offset)) return false; if (!file.Seek(offset)) return false;
} }
UINT16 nbytes = file.Write(buffer, len); size_t nbytes = file.Write(buffer, len);
return (nbytes == len); return (nbytes == len);
} // end NormFileObject::WriteSegment() } // end NormFileObject::WriteSegment()
@ -1919,7 +1922,7 @@ UINT16 NormFileObject::ReadSegment(NormBlockId blockId,
char* buffer) char* buffer)
{ {
// Determine segment length from blockId::segmentId // Determine segment length from blockId::segmentId
UINT16 len; size_t len;
if (blockId == final_block_id) if (blockId == final_block_id)
{ {
if (segmentId == (GetBlockSize(blockId)-1)) if (segmentId == (GetBlockSize(blockId)-1))
@ -1949,11 +1952,17 @@ UINT16 NormFileObject::ReadSegment(NormBlockId blockId,
NormFile::Offset offset = segmentOffset.GetOffset(); NormFile::Offset offset = segmentOffset.GetOffset();
if (offset != file.GetOffset()) if (offset != file.GetOffset())
{ {
if (!file.Seek(offset)) if (!file.Seek(offset))
return false; {
DMSG(0, "NormFileObject::ReadSegment() error seeking to file offset\n");
return 0;
}
} }
UINT16 nbytes = file.Read(buffer, len); size_t nbytes = file.Read(buffer, len);
return (len == nbytes) ? len : 0; if (len == nbytes)
return (UINT16)len;
else
return 0;
} // end NormFileObject::ReadSegment() } // end NormFileObject::ReadSegment()
char* NormFileObject::RetrieveSegment(NormBlockId blockId, char* NormFileObject::RetrieveSegment(NormBlockId blockId,
@ -2284,7 +2293,7 @@ bool NormStreamObject::Open(UINT32 bufferSize,
numBlocks = MAX(2, numBlocks); numBlocks = MAX(2, numBlocks);
if (doubleBuffer) numBlocks *= 2; if (doubleBuffer) numBlocks *= 2;
UINT32 numSegments = numBlocks * numData; UINT32 numSegments = numBlocks * numData;
if (!block_pool.Init(numBlocks, numData)) if (!block_pool.Init(numBlocks, numData))
{ {
DMSG(0, "NormStreamObject::Open() block_pool init error\n"); DMSG(0, "NormStreamObject::Open() block_pool init error\n");
@ -2310,6 +2319,7 @@ bool NormStreamObject::Open(UINT32 bufferSize,
read_init = true; read_init = true;
read_index.block = read_index.segment = 0; read_index.block = read_index.segment = 0;
write_index.block = write_index.segment = 0; write_index.block = write_index.segment = 0;
tx_index.block = tx_index.segment = 0;
tx_offset = write_offset = read_offset = 0; tx_offset = write_offset = read_offset = 0;
write_vacancy = true; write_vacancy = true;
posted_tx_queue_vacancy = false; posted_tx_queue_vacancy = false;
@ -2539,18 +2549,31 @@ UINT16 NormStreamObject::ReadSegment(NormBlockId blockId,
char* segment = block->GetSegment(segmentId); char* segment = block->GetSegment(segmentId);
ASSERT(segment != NULL); ASSERT(segment != NULL);
// Update tx_offset if ((segmentOffset - tx_offset) > 0) // Update tx_offset if ((segmentOffset - tx_offset) > 0) (TBD) deprecate "tx_offset"
UINT32 segmentOffset = NormDataMsg::ReadStreamPayloadOffset(segment); //UINT32 segmentOffset = NormDataMsg::ReadStreamPayloadOffset(segment);
INT32 offsetDelta = segmentOffset - tx_offset; //INT32 offsetDelta = segmentOffset - tx_offset;
if (offsetDelta > 0) tx_offset = segmentOffset; //if (offsetDelta > 0) tx_offset = segmentOffset;
// Update tx_index if (blockId::segmentId > tx_index)
if (blockId > tx_index.block)
{
tx_index.block = blockId;
tx_index.segment = segmentId;
}
else if ((blockId == tx_index.block) && (segmentId > tx_index.segment))
{
tx_index.segment = segmentId;
}
// Only advertise vacancy if stream_buffer.RangeLo() is non-pending _and_ // Only advertise vacancy if stream_buffer.RangeLo() is non-pending _and_
// (write_offset - tx_offset) < streamBufferSize // (write_index.block - tx_index.block) < block_pool.GetTotal() / 2
if (!write_vacancy) if (!write_vacancy)
{ {
offsetDelta = write_offset - tx_offset; //offsetDelta = write_offset - tx_offset;
ASSERT(offsetDelta >= 0); //ASSERT(offsetDelta >= 0);
if ((UINT32)offsetDelta < object_size.LSB()) //if ((UINT32)offsetDelta < object_size.LSB())
ASSERT(tx_index.block <= write_index.block);
UINT32 blockDelta = write_index.block - tx_index.block;
if (blockDelta < (block_pool.GetTotal() >> 1))
{ {
NormBlock* b = stream_buffer.Find(stream_buffer.RangeLo()); NormBlock* b = stream_buffer.Find(stream_buffer.RangeLo());
if (b && !b->IsPending()) if (b && !b->IsPending())
@ -2863,7 +2886,31 @@ bool NormStreamObject::Read(char* buffer, unsigned int* buflen, bool seekMsgStar
} // end if (!segment) } // end if (!segment)
UINT16 length = NormDataMsg::ReadStreamPayloadLength(segment); UINT16 length = NormDataMsg::ReadStreamPayloadLength(segment);
if (length > segment_size) if (0 == length)
{
// It's a "stream control" message, so interpret "payload_msg_start" as control code
switch (NormDataMsg::ReadStreamPayloadMsgStart(segment))
{
case 0:
// This is the "stream end" control code
break;
default:
// Invalid stream control code, skip this invalid segment
DMSG(0, "NormStreamObject::Read() invalid stream control message\n");
if (++read_index.segment >= ndata)
{
stream_buffer.Remove(block);
block->EmptyToPool(segment_pool);
block_pool.Put(block);
read_index.block++;
read_index.segment = 0;
//Prune(read_index.block, false);
}
continue;
break;
} // end switch(NormDataMsg::ReadStreamPayloadMsgStart(segment))
}
else if (length > segment_size)
{ {
Release(); Release();
if (bytesRead > 0) if (bytesRead > 0)
@ -2935,18 +2982,19 @@ bool NormStreamObject::Read(char* buffer, unsigned int* buflen, bool seekMsgStar
return false; return false;
} }
} }
UINT16 count = length - index;
count = MIN(count, bytesToRead);
if (seekMsgStart) if (seekMsgStart)
{ {
/* stream payload flags have in deprecated in favor of "payload_msg_start"
if ((0 != index) || if ((0 != index) ||
!NormDataMsg::StreamPayloadFlagIsSet(segment, NormDataMsg::FLAG_MSG_START)) !NormDataMsg::StreamPayloadFlagIsSet(segment, NormDataMsg::FLAG_MSG_START))
*/
UINT16 msgStart = NormDataMsg::ReadStreamPayloadMsgStart(segment);
if (0 == msgStart)
{ {
// make sure msg start searches don't miss stream end ... // make sure msg start searches don't miss stream end ...
if (NormDataMsg::StreamPayloadFlagIsSet(segment, NormDataMsg::FLAG_STREAM_END)) //if (NormDataMsg::StreamPayloadFlagIsSet(segment, NormDataMsg::FLAG_STREAM_END))
if (0 == NormDataMsg::ReadStreamPayloadLength(segment))
{ {
DMSG(4, "NormStreamObject::Read() stream ended by sender 1\n"); DMSG(4, "NormStreamObject::Read() stream ended by sender 1\n");
session.Notify(NormController::RX_OBJECT_COMPLETED, server, this); session.Notify(NormController::RX_OBJECT_COMPLETED, server, this);
@ -2971,10 +3019,13 @@ bool NormStreamObject::Read(char* buffer, unsigned int* buflen, bool seekMsgStar
} }
else else
{ {
seekMsgStart = false; read_offset += (msgStart - 1);
index += (msgStart - 1);
seekMsgStart = false;
} }
} }
UINT16 count = length - index;
count = MIN(count, bytesToRead);
#ifdef SIMULATE #ifdef SIMULATE
UINT16 simCount = index + count + NormDataMsg::GetStreamPayloadHeaderLength(); UINT16 simCount = index + count + NormDataMsg::GetStreamPayloadHeaderLength();
simCount = (simCount < SIM_PAYLOAD_MAX) ? (SIM_PAYLOAD_MAX - simCount) : 0; simCount = (simCount < SIM_PAYLOAD_MAX) ? (SIM_PAYLOAD_MAX - simCount) : 0;
@ -2989,8 +3040,8 @@ bool NormStreamObject::Read(char* buffer, unsigned int* buflen, bool seekMsgStar
bytesToRead -= count; bytesToRead -= count;
if (index >= length) if (index >= length)
{ {
bool streamEnded = bool streamEnded = (0 == NormDataMsg::ReadStreamPayloadLength(segment));
NormDataMsg::StreamPayloadFlagIsSet(segment, NormDataMsg::FLAG_STREAM_END); // NormDataMsg::StreamPayloadFlagIsSet(segment, NormDataMsg::FLAG_STREAM_END);
// Don't bother managing individual segments since // Don't bother managing individual segments since
// stream buffers are multiples of block size! // stream buffers are multiples of block size!
// block->DetachSegment(read_index.segment); // block->DetachSegment(read_index.segment);
@ -3022,8 +3073,8 @@ bool NormStreamObject::Read(char* buffer, unsigned int* buflen, bool seekMsgStar
void NormStreamObject::Terminate() void NormStreamObject::Terminate()
{ {
// If there's a pending buffer at our "write_index", mark it // Flush stream and create a ZERO length segment to send
// otherwise create a ZERO length segment to send Flush(); // should eom be set for this call?
NormBlock* block = stream_buffer.Find(write_index.block); NormBlock* block = stream_buffer.Find(write_index.block);
if (!block) if (!block)
{ {
@ -3057,9 +3108,9 @@ void NormStreamObject::Terminate()
ASSERT(success); ASSERT(success);
} // end if (!block) } // end if (!block)
char* segment = block->GetSegment(write_index.segment); char* segment = block->GetSegment(write_index.segment);
if (!segment) if (NULL == segment)
{ {
if (!(segment = segment_pool.Get())) if (NULL == (segment = segment_pool.Get()))
{ {
NormBlock* b = stream_buffer.Find(stream_buffer.RangeLo()); NormBlock* b = stream_buffer.Find(stream_buffer.RangeLo());
ASSERT(b != block); ASSERT(b != block);
@ -3086,13 +3137,19 @@ void NormStreamObject::Terminate()
segment = segment_pool.Get(); segment = segment_pool.Get();
ASSERT(segment); ASSERT(segment);
} }
NormDataMsg::WriteStreamPayloadOffset(segment, write_offset);
NormDataMsg::WriteStreamPayloadLength(segment, 0);
block->AttachSegment(write_index.segment, segment); block->AttachSegment(write_index.segment, segment);
} // end if (!segment) NormDataMsg::WriteStreamPayloadMsgStart(segment, 0);
UINT16 index = NormDataMsg::ReadStreamPayloadLength(segment); NormDataMsg::WriteStreamPayloadLength(segment, 0);
if (0 == index) NormDataMsg::ResetStreamPayloadFlags(segment); }
NormDataMsg::SetStreamPayloadFlag(segment, NormDataMsg::FLAG_STREAM_END); else
{
ASSERT(0 == NormDataMsg::ReadStreamPayloadMsgStart(segment));
ASSERT(0 == NormDataMsg::ReadStreamPayloadLength(segment));
}
NormDataMsg::WriteStreamPayloadOffset(segment, write_offset);
//NormDataMsg::ResetStreamPayloadFlags(segment); // flags are deprecated!
//NormDataMsg::SetStreamPayloadFlag(segment, NormDataMsg::FLAG_STREAM_END);
block->SetPending(write_index.segment); block->SetPending(write_index.segment);
if (++write_index.segment >= ndata) if (++write_index.segment >= ndata)
{ {
@ -3117,12 +3174,15 @@ UINT32 NormStreamObject::Write(const char* buffer, UINT32 len, bool eom)
} }
break; break;
} }
INT32 deltaOffset = write_offset - tx_offset; //INT32 deltaOffset = write_offset - tx_offset; // (TBD) deprecate tx_offset
ASSERT(deltaOffset >= 0); //ASSERT(deltaOffset >= 0);
if (deltaOffset >= (INT32)object_size.LSB()) //if (deltaOffset >= (INT32)object_size.LSB())
ASSERT(write_index.block >= tx_index.block);
UINT32 deltaBlock = write_index.block - tx_index.block;
if (deltaBlock >= (block_pool.GetTotal() >> 1))
{ {
write_vacancy = false; write_vacancy = false;
DMSG(4, "NormStreamObject::Write() stream buffer full (1)\n", len, eom); DMSG(8, "NormStreamObject::Write() stream buffer full (1)\n", len, eom);
if (!push_mode) break; if (!push_mode) break;
} }
NormBlock* block = stream_buffer.Find(write_index.block); NormBlock* block = stream_buffer.Find(write_index.block);
@ -3154,7 +3214,7 @@ UINT32 NormStreamObject::Write(const char* buffer, UINT32 len, bool eom)
} }
else else
{ {
DMSG(4, "NormStreamObject::Write() stream buffer full (2) len:%d eom:%d\n", len, eom); DMSG(8, "NormStreamObject::Write() stream buffer full (2) len:%d eom:%d\n", len, eom);
break; break;
} }
} }
@ -3165,7 +3225,6 @@ UINT32 NormStreamObject::Write(const char* buffer, UINT32 len, bool eom)
block->ClearPending(); block->ClearPending();
bool success = stream_buffer.Insert(block); bool success = stream_buffer.Insert(block);
ASSERT(success); ASSERT(success);
} // end if (!block) } // end if (!block)
char* segment = block->GetSegment(write_index.segment); char* segment = block->GetSegment(write_index.segment);
if (!segment) if (!segment)
@ -3196,7 +3255,7 @@ UINT32 NormStreamObject::Write(const char* buffer, UINT32 len, bool eom)
} }
else else
{ {
DMSG(4, "NormStreamObject::Write() stream buffer full (3)\n"); DMSG(8, "NormStreamObject::Write() stream buffer full (3)\n");
break; break;
} }
} }
@ -3206,27 +3265,21 @@ UINT32 NormStreamObject::Write(const char* buffer, UINT32 len, bool eom)
segment = segment_pool.Get(); segment = segment_pool.Get();
ASSERT(segment); ASSERT(segment);
} }
NormDataMsg::WriteStreamPayloadOffset(segment, write_offset); NormDataMsg::WriteStreamPayloadMsgStart(segment, 0);
NormDataMsg::WriteStreamPayloadLength(segment, 0); NormDataMsg::WriteStreamPayloadLength(segment, 0);
NormDataMsg::WriteStreamPayloadOffset(segment, write_offset);
block->AttachSegment(write_index.segment, segment); block->AttachSegment(write_index.segment, segment);
} // end if (!segment) } // end if (!segment)
UINT16 index = NormDataMsg::ReadStreamPayloadLength(segment); UINT16 index = NormDataMsg::ReadStreamPayloadLength(segment);
// If it is an application start-of-message, mark the stream header accordingly
if (0 == index) // (but only if it is the _first_ message start for this segment!)
if (msg_start && (0 != len))
{ {
NormDataMsg::ResetStreamPayloadFlags(segment); if (0 == NormDataMsg::ReadStreamPayloadMsgStart(segment))
if (msg_start && len) NormDataMsg::WriteStreamPayloadMsgStart(segment, index+1);
{ msg_start = false;
ASSERT(0 == index);
NormDataMsg::SetStreamPayloadFlag(segment, NormDataMsg::FLAG_MSG_START);
msg_start = false;
}
} }
else
{
msg_start = false;
}
UINT16 count = (UINT16)(len - nBytes); UINT16 count = (UINT16)(len - nBytes);
UINT16 space = segment_size - index; UINT16 space = segment_size - index;

View File

@ -305,8 +305,8 @@ class NormFileObject : public NormObject
virtual char* RetrieveSegment(NormBlockId blockId, virtual char* RetrieveSegment(NormBlockId blockId,
NormSegmentId segmentId); NormSegmentId segmentId);
private: //private:
char path[PATH_MAX]; char path[PATH_MAX+10];
NormFile file; NormFile file;
NormObjectSize large_block_length; NormObjectSize large_block_length;
NormObjectSize small_block_length; NormObjectSize small_block_length;
@ -474,6 +474,7 @@ class NormStreamObject : public NormObject
NormBlockBuffer stream_buffer; NormBlockBuffer stream_buffer;
Index write_index; Index write_index;
UINT32 write_offset; UINT32 write_offset;
Index tx_index;
UINT32 tx_offset; UINT32 tx_offset;
bool write_vacancy; bool write_vacancy;
bool posted_tx_queue_vacancy; bool posted_tx_queue_vacancy;

View File

@ -65,7 +65,8 @@ char* NormSegmentPool::Get()
char* ptr = seg_list; char* ptr = seg_list;
if (ptr) if (ptr)
{ {
memcpy(&seg_list, ptr, sizeof(char*)); //memcpy(&seg_list, ptr, sizeof(char*));
seg_list = *((char**)ptr);
seg_count--; seg_count--;
//#ifdef NORM_DEBUG //#ifdef NORM_DEBUG
overrun_flag = false; overrun_flag = false;
@ -601,7 +602,7 @@ bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
} // end NormBlock::AppendRepairRequest() } // end NormBlock::AppendRepairRequest()
NormBlockPool::NormBlockPool() NormBlockPool::NormBlockPool()
: head((NormBlock*)NULL), count(0), overruns(0), overrun_flag(false) : head((NormBlock*)NULL), blk_total(0), blk_count(0), overruns(0), overrun_flag(false)
{ {
} }
@ -627,6 +628,8 @@ bool NormBlockPool::Init(UINT32 numBlocks, UINT16 segsPerBlock)
} }
b->next = head; b->next = head;
head = b; head = b;
blk_count++;
blk_total++;
} }
else else
{ {
@ -635,19 +638,19 @@ bool NormBlockPool::Init(UINT32 numBlocks, UINT16 segsPerBlock)
return false; return false;
} }
} }
count = numBlocks;
return true; return true;
} // end NormBlockPool::Init() } // end NormBlockPool::Init()
void NormBlockPool::Destroy() void NormBlockPool::Destroy()
{ {
ASSERT(blk_total == blk_count);
NormBlock* next; NormBlock* next;
while ((next = head)) while ((next = head))
{ {
head = next->next; head = next->next;
delete next; delete next;
} }
count = 0; blk_count = blk_total = 0;
} // end NormBlockPool::Destroy() } // end NormBlockPool::Destroy()
NormBlockBuffer::NormBlockBuffer() NormBlockBuffer::NormBlockBuffer()

View File

@ -267,7 +267,7 @@ class NormBlockPool
head = b ? b->next : NULL; head = b ? b->next : NULL;
if (b) if (b)
{ {
count--; blk_count--;
overrun_flag = false; overrun_flag = false;
} }
else if (!overrun_flag) else if (!overrun_flag)
@ -282,14 +282,16 @@ class NormBlockPool
{ {
b->next = head; b->next = head;
head = b; head = b;
count++; blk_count++;
} }
unsigned long OverrunCount() const {return overruns;} unsigned long OverrunCount() const {return overruns;}
UINT32 GetCount() {return count;} UINT32 GetCount() {return blk_count;}
UINT32 GetTotal() {return blk_total;}
private: private:
NormBlock* head; NormBlock* head;
UINT32 count; UINT32 blk_total;
UINT32 blk_count;
unsigned long overruns; unsigned long overruns;
bool overrun_flag; bool overrun_flag;
}; // end class NormBlockPool }; // end class NormBlockPool

View File

@ -18,7 +18,7 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
: session_mgr(sessionMgr), notify_pending(false), tx_port(0), : session_mgr(sessionMgr), notify_pending(false), tx_port(0),
tx_socket(&tx_socket_actual), tx_socket_actual(ProtoSocket::UDP), tx_socket(&tx_socket_actual), tx_socket_actual(ProtoSocket::UDP),
rx_socket(ProtoSocket::UDP), local_node_id(localNodeId), rx_socket(ProtoSocket::UDP), local_node_id(localNodeId),
ttl(DEFAULT_TTL), loopback(false), rx_port_reuse(false), ttl(DEFAULT_TTL), tos(0), loopback(false), rx_port_reuse(false), rx_addr_bind(false),
tx_rate(DEFAULT_TRANSMIT_RATE/8.0), tx_rate_min(-1.0), tx_rate_max(-1.0), tx_rate(DEFAULT_TRANSMIT_RATE/8.0), tx_rate_min(-1.0), tx_rate_max(-1.0),
backoff_factor(DEFAULT_BACKOFF_FACTOR), is_server(false), instance_id(0), backoff_factor(DEFAULT_BACKOFF_FACTOR), is_server(false), instance_id(0),
ndata(DEFAULT_NDATA), nparity(DEFAULT_NPARITY), auto_parity(0), extra_parity(0), ndata(DEFAULT_NDATA), nparity(DEFAULT_NPARITY), auto_parity(0), extra_parity(0),
@ -28,7 +28,7 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
posted_tx_queue_empty(false), posted_tx_queue_empty(false),
acking_node_count(0), watermark_pending(false), advertise_repairs(false), acking_node_count(0), watermark_pending(false), advertise_repairs(false),
suppress_nonconfirmed(false), suppress_rate(-1.0), suppress_rtt(-1.0), suppress_nonconfirmed(false), suppress_rate(-1.0), suppress_rtt(-1.0),
probe_proactive(true), probe_pending(false), probe_reset(true), probe_proactive(true), probe_pending(false), probe_reset(true), probe_data_check(false),
grtt_interval(0.5), grtt_interval(0.5),
grtt_interval_min(DEFAULT_GRTT_INTERVAL_MIN), grtt_interval_min(DEFAULT_GRTT_INTERVAL_MIN),
grtt_interval_max(DEFAULT_GRTT_INTERVAL_MAX), grtt_interval_max(DEFAULT_GRTT_INTERVAL_MAX),
@ -68,7 +68,7 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
grtt_quantized = NormQuantizeRtt(DEFAULT_GRTT_ESTIMATE); grtt_quantized = NormQuantizeRtt(DEFAULT_GRTT_ESTIMATE);
grtt_measured = grtt_advertised = NormUnquantizeRtt(grtt_quantized); grtt_measured = grtt_advertised = NormUnquantizeRtt(grtt_quantized);
gsize_measured = DEFAULT_GSIZE_ESTIMATE; gsize_measured = DEFAULT_GSIZE_ESTIMATE;
gsize_quantized = NormQuantizeGroupSize(DEFAULT_GSIZE_ESTIMATE); gsize_quantized = NormQuantizeGroupSize(DEFAULT_GSIZE_ESTIMATE);
gsize_advertised = NormUnquantizeGroupSize(gsize_quantized); gsize_advertised = NormUnquantizeGroupSize(gsize_quantized);
@ -114,7 +114,7 @@ bool NormSession::Open(const char* interfaceName)
Close(); Close();
return false; return false;
} }
const ProtoAddress* bindAddr = NULL;
if (rx_port_reuse) if (rx_port_reuse)
{ {
// Enable port/addr reuse and bind socket to destination address // Enable port/addr reuse and bind socket to destination address
@ -124,6 +124,10 @@ bool NormSession::Open(const char* interfaceName)
Close(); Close();
return false; return false;
} }
}
const ProtoAddress* bindAddr = NULL;
if (rx_addr_bind)
{
#ifndef WIN32 #ifndef WIN32
if (address.IsMulticast()) // Win32 doesn't like to bind to multicast addr ??? if (address.IsMulticast()) // Win32 doesn't like to bind to multicast addr ???
bindAddr = &address; bindAddr = &address;
@ -136,6 +140,13 @@ bool NormSession::Open(const char* interfaceName)
return false; return false;
} }
} }
if (0 != tos)
{
if (!tx_socket->SetTOS(tos))
{
DMSG(0, "NormSession::Open() warning: tx_socket set tos error\n");
}
}
if (address.IsMulticast()) if (address.IsMulticast())
{ {
@ -238,12 +249,17 @@ bool NormSession::SetMulticastInterface(const char* interfaceName)
void NormSession::SetTxRateInternal(double txRate) void NormSession::SetTxRateInternal(double txRate)
{ {
if (txRate < 0.0)
{
DMSG(0, "NormSession::SetTxRateInternal() invalid transmit rate!\n");
return;
}
if (tx_timer.IsActive()) if (tx_timer.IsActive())
{ {
if (txRate > 0.0) if (txRate > 0.0)
{ {
double adjustInterval = (tx_rate/txRate) * tx_timer.GetTimeRemaining(); double adjustInterval = (tx_rate/txRate) * tx_timer.GetTimeRemaining();
if (adjustInterval > 0.100) if (adjustInterval > NORM_TICK_MIN)
{ {
tx_timer.SetInterval(adjustInterval); tx_timer.SetInterval(adjustInterval);
tx_timer.Reschedule(); tx_timer.Reschedule();
@ -254,30 +270,38 @@ void NormSession::SetTxRateInternal(double txRate)
tx_timer.Deactivate(); tx_timer.Deactivate();
} }
tx_rate = txRate;
} }
else if ((0.0 == tx_rate) && IsOpen()) else if ((0.0 == tx_rate) && IsOpen())
{ {
tx_rate = txRate;
tx_timer.SetInterval(0.0); tx_timer.SetInterval(0.0);
ActivateTimer(tx_timer); if (txRate > 0.0) ActivateTimer(tx_timer);
} }
else tx_rate = txRate;
if (tx_rate > 0.0)
{ {
tx_rate = txRate; unsigned char grttQuantizedOld = grtt_quantized;
double pktInterval = (double)(44+segment_size)/txRate;
if (grtt_measured < pktInterval)
grtt_quantized = NormQuantizeRtt(pktInterval);
else
grtt_quantized = NormQuantizeRtt(grtt_measured);
grtt_advertised = NormUnquantizeRtt(grtt_quantized);
// What do we do when "pktInterval" > "grtt_max"?
// We will take our lumps with some extra activity timeout NACKs when they happen?
if (grtt_advertised > grtt_max)
{
grtt_quantized = NormQuantizeRtt(grtt_max);
grtt_advertised = NormUnquantizeRtt(grtt_quantized);
}
if (grttQuantizedOld != grtt_quantized)
DMSG(4, "NormSession::SetTxRateInternal() node>%lu %s to new grtt to: %lf sec\n",
LocalNodeId(),
(grttQuantizedOld < grtt_quantized) ? "increased" : "decreased",
grtt_advertised);
} }
unsigned char grttQuantizedOld = grtt_quantized;
double pktInterval = (double)(44+segment_size)/tx_rate;
if (grtt_measured < pktInterval)
grtt_quantized = NormQuantizeRtt(pktInterval);
else
grtt_quantized = NormQuantizeRtt(grtt_measured);
grtt_advertised = NormUnquantizeRtt(grtt_quantized);
if (grttQuantizedOld != grtt_quantized)
DMSG(4, "NormSession::SetTxRateInternal() node>%lu %s to new grtt to: %lf sec\n",
LocalNodeId(),
(grttQuantizedOld < grtt_quantized) ? "increased" : "decreased",
grtt_advertised);
} // end NormSession::SetTxRateInternal() } // end NormSession::SetTxRateInternal()
void NormSession::SetTxRateBounds(double rateMin, double rateMax) void NormSession::SetTxRateBounds(double rateMin, double rateMax)
@ -292,8 +316,11 @@ void NormSession::SetTxRateBounds(double rateMin, double rateMax)
rateMax = temp; rateMax = temp;
} }
} }
if (rateMin < 0.0) if (rateMin < 0.0)
tx_rate_min = -1.0; tx_rate_min = -1.0;
else if (rateMin < 8.0)
tx_rate_min = 1.0; // one byte/second absolute minimum
else else
tx_rate_min = rateMin/8.0; // convert to bytes/second tx_rate_min = rateMin/8.0; // convert to bytes/second
if (rateMax < 0.0) if (rateMax < 0.0)
@ -302,11 +329,12 @@ void NormSession::SetTxRateBounds(double rateMin, double rateMax)
tx_rate_max = rateMax/8.0; // convert to bytes/second tx_rate_max = rateMax/8.0; // convert to bytes/second
if (cc_enable) if (cc_enable)
{ {
if ((tx_rate_min >= 0.0) && (tx_rate < tx_rate_min)) double txRate = tx_rate;
tx_rate = tx_rate_min; if ((tx_rate_min > 0.0) && (txRate < tx_rate_min))
if ((tx_rate_max >= 0.0) && (tx_rate > tx_rate_max)) txRate = tx_rate_min;
tx_rate = tx_rate_max; if ((tx_rate_max >= 0.0) && (txRate > tx_rate_max))
SetTxRateInternal(tx_rate); txRate = tx_rate_max;
if (txRate != tx_rate) SetTxRateInternal(txRate);
} }
} // end NormSession::SetTxRateBounds() } // end NormSession::SetTxRateBounds()
@ -382,8 +410,6 @@ bool NormSession::StartServer(UINT16 instanceId,
instance_id = instanceId; instance_id = instanceId;
segment_size = segmentSize; segment_size = segmentSize;
sent_rate = 0.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; data_active = false;
@ -394,14 +420,26 @@ bool NormSession::StartServer(UINT16 instanceId,
if (cc_enable) if (cc_enable)
{ {
tx_rate = segmentSize; double txRate;
if ((tx_rate_min >= 0.0) && (tx_rate < tx_rate_min)) if(tx_rate_min > 0.0)
tx_rate = tx_rate_min; {
txRate = tx_rate_min;
}
else
{
// Don't let txRate below MIN(one segment per grtt, one segment per seconds)
txRate = ((double)segment_size) / grtt_measured;
if (txRate > ((double)(segment_size)))
txRate = (double)(segment_size);
}
if ((tx_rate_max >= 0.0) && (tx_rate > tx_rate_max)) if ((tx_rate_max >= 0.0) && (tx_rate > tx_rate_max))
tx_rate = tx_rate_max; txRate = tx_rate_max;
tx_rate = txRate; // keep grtt at initial
//SetTxRateInternal(txRate); // adjusts grtt_advertised as needed
} }
grtt_age = 0.0; grtt_age = 0.0;
probe_pending = false; probe_pending = false;
probe_data_check = false;
if (probe_reset) if (probe_reset)
{ {
probe_reset = false; probe_reset = false;
@ -428,6 +466,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->Close();
obj->Release(); obj->Release();
} }
// Then destroy table // Then destroy table
@ -680,7 +719,6 @@ void NormSession::Serve()
posted_tx_queue_empty = true; posted_tx_queue_empty = true;
Notify(NormController::TX_QUEUE_EMPTY, (NormServerNode*)NULL, obj); Notify(NormController::TX_QUEUE_EMPTY, (NormServerNode*)NULL, obj);
// (TBD) Was session deleted? // (TBD) Was session deleted?
//Serve();
return; return;
} }
} }
@ -702,13 +740,12 @@ 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; data_active = false; // (TBD) should we wait until the flush process completes before setting 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,
(NormObject*)NULL); (NormObject*)NULL);
// (TBD) Was session deleted? // (TBD) Was session deleted?
//Serve();
return; return;
} }
if (flush_count < NORM_ROBUST_FACTOR) if (flush_count < NORM_ROBUST_FACTOR)
@ -732,8 +769,6 @@ void NormSession::ServerSetWatermark(NormObjectId objectId,
NormBlockId blockId, NormBlockId blockId,
NormSegmentId segmentId) NormSegmentId segmentId)
{ {
TRACE("NormSession::ServerSetWatermark(%hu:%lu:%hu) ...\n",
(UINT16)objectId, (UINT32)blockId, (UINT16)segmentId);
watermark_pending = true; watermark_pending = true;
watermark_active = false; watermark_active = false;
watermark_object_id = objectId; watermark_object_id = objectId;
@ -894,12 +929,14 @@ bool NormSession::ServerQueueWatermarkFlush()
} }
else if (NULL != acking_node_tree.GetRoot()) else if (NULL != acking_node_tree.GetRoot())
{ {
ReturnMessageToPool(flush);
DMSG(4, "NormSession::ServeQueueWatermarkFlush() node>%lu watermark ack finished.\n"); DMSG(4, "NormSession::ServeQueueWatermarkFlush() node>%lu watermark ack finished.\n");
Notify(NormController::TX_WATERMARK_COMPLETED, (NormServerNode*)NULL, (NormObject*)NULL); Notify(NormController::TX_WATERMARK_COMPLETED, (NormServerNode*)NULL, (NormObject*)NULL);
return false; return false;
} }
else else
{ {
ReturnMessageToPool(flush);
DMSG(2, "NormSession::ServeQueueWatermarkFlush() node>%lu no acking nodes specified?!\n"); DMSG(2, "NormSession::ServeQueueWatermarkFlush() node>%lu no acking nodes specified?!\n");
return false; return false;
} }
@ -940,16 +977,21 @@ void NormSession::ServerQueueFlush()
} }
else else
{ {
// Why did I do this? - Brian // Why did I do this? - Brian // Because a squelch keeps the receivers from NACKing in futility
// (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))
{ {
if (flush_count < NORM_ROBUST_FACTOR) flush_count++; if (flush_count < NORM_ROBUST_FACTOR) flush_count++;
flush_timer.SetInterval(2*grtt_advertised); flush_timer.SetInterval(4*grtt_advertised);
ActivateTimer(flush_timer); ActivateTimer(flush_timer);
DMSG(8, "NormSession::ServerQueueFlush() node>%lu squelch queued (flush_count:%u)...\n",
LocalNodeId(), flush_count);
}
else
{
DMSG(0, "NormSession::ServerQueueFlush() warning: node>%lu unable to queue squelch\n",
LocalNodeId());
} }
DMSG(8, "NormSession::ServerQueueFlush() node>%lu squelch queued (flush_count:%u)...\n",
LocalNodeId(), flush_count);
return; return;
} }
NormCmdFlushMsg* flush = (NormCmdFlushMsg*)GetMessageFromPool(); NormCmdFlushMsg* flush = (NormCmdFlushMsg*)GetMessageFromPool();
@ -973,14 +1015,14 @@ void NormSession::ServerQueueFlush()
DMSG(0, "NormSession::ServerQueueFlush() node>%lu message_pool exhausted! (couldn't flush)\n", DMSG(0, "NormSession::ServerQueueFlush() node>%lu message_pool exhausted! (couldn't flush)\n",
LocalNodeId()); LocalNodeId());
} }
flush_timer.SetInterval(2*grtt_advertised); flush_timer.SetInterval(4*grtt_advertised);
ActivateTimer(flush_timer); ActivateTimer(flush_timer);
} // end NormSession::ServerQueueFlush() } // end NormSession::ServerQueueFlush()
bool NormSession::OnFlushTimeout(ProtoTimer& /*theTimer*/) bool NormSession::OnFlushTimeout(ProtoTimer& /*theTimer*/)
{ {
flush_timer.Deactivate(); flush_timer.Deactivate();
PromptServer();//Serve(); // (TBD) Change this to PromptServer() ?? PromptServer();
return false; return false;
} // NormSession::OnFlushTimeout() } // NormSession::OnFlushTimeout()
@ -1000,6 +1042,8 @@ void NormSession::QueueMessage(NormMsg* msg)
} }
lastTime = currentTime; lastTime = currentTime;
*/ */
// (TBD) if (0.0 == tx_rate), should we just dump the
// message rather than queueing it?
if (!tx_timer.IsActive() && (tx_rate > 0.0)) if (!tx_timer.IsActive() && (tx_rate > 0.0))
{ {
tx_timer.SetInterval(0.0); tx_timer.SetInterval(0.0);
@ -1348,7 +1392,6 @@ void NormTrace(const struct timeval& currentTime,
const NormMsg& msg, const NormMsg& msg,
bool sent) bool sent)
{ {
//if (DebugLevel() < 8) return; // (TBD) provide per-session trace on/off switch
static const char* MSG_NAME[] = static const char* MSG_NAME[] =
{ {
"INVALID", "INVALID",
@ -1421,15 +1464,18 @@ void NormTrace(const struct timeval& currentTime,
(UINT16)data.GetFecSymbolId()); (UINT16)data.GetFecSymbolId());
if (data.IsData() && data.IsStream()) if (data.IsData() && data.IsStream())
{ {
if (NormDataMsg::StreamPayloadFlagIsSet(data.GetPayload(), NormDataMsg::FLAG_MSG_START)) //if (NormDataMsg::StreamPayloadFlagIsSet(data.GetPayload(), NormDataMsg::FLAG_MSG_START))
if (0 != NormDataMsg::ReadStreamPayloadMsgStart(data.GetPayload()))
{ {
// (TBD) use "payload_msg_start" value for this ...
// We usually use the first two bytes of "messages" // We usually use the first two bytes of "messages"
// as a "message length" header // as a "message length" header
UINT16 x; UINT16 x;
memcpy(&x, data.GetPayloadData(), 2); memcpy(&x, data.GetPayloadData(), 2);
DMSG(0, "start word>%hu ", ntohs(x)); DMSG(0, "start word>%hu ", ntohs(x));
} }
if (NormDataMsg::StreamPayloadFlagIsSet(data.GetPayload(), NormDataMsg::FLAG_STREAM_END)) //if (NormDataMsg::StreamPayloadFlagIsSet(data.GetPayload(), NormDataMsg::FLAG_STREAM_END))
if (0 == NormDataMsg::ReadStreamPayloadLength(data.GetPayload()))
DMSG(0, "(stream end) "); DMSG(0, "(stream end) ");
} }
break; break;
@ -1479,7 +1525,7 @@ void NormTrace(const struct timeval& currentTime,
if (NormHeaderExtension::CC_RATE == ext.GetType()) if (NormHeaderExtension::CC_RATE == ext.GetType())
{ {
UINT16 sendRate = ((NormCCRateExtension&)ext).GetSendRate(); UINT16 sendRate = ((NormCCRateExtension&)ext).GetSendRate();
DMSG(0, " rate>%f ", (8.0/1000.0) * NormUnquantizeRate(sendRate)); DMSG(0, " rate>%f ", 8.0e-03 * NormUnquantizeRate(sendRate));
break; break;
} }
} }
@ -1620,7 +1666,7 @@ void NormSession::ClientHandleObjectMessage(const struct timeval& currentTime,
return; return;
} }
} }
theServer->Activate(); theServer->Activate(true);
theServer->UpdateLossEstimate(currentTime, msg.GetSequence()); theServer->UpdateLossEstimate(currentTime, msg.GetSequence());
theServer->SetAddress(msg.GetSource()); theServer->SetAddress(msg.GetSource());
theServer->IncrementRecvTotal(msg.GetLength()); // for statistics only (TBD) #ifdef NORM_DEBUG theServer->IncrementRecvTotal(msg.GetLength()); // for statistics only (TBD) #ifdef NORM_DEBUG
@ -1677,7 +1723,7 @@ void NormSession::ClientHandleCommand(const struct timeval& currentTime,
return; return;
} }
} }
theServer->Activate(); theServer->Activate(false);
theServer->UpdateLossEstimate(currentTime, cmd.GetSequence()); theServer->UpdateLossEstimate(currentTime, cmd.GetSequence());
theServer->SetAddress(cmd.GetSource()); theServer->SetAddress(cmd.GetSource());
theServer->IncrementRecvTotal(cmd.GetLength()); // for statistics only (TBD) #ifdef NORM_DEBUG theServer->IncrementRecvTotal(cmd.GetLength()); // for statistics only (TBD) #ifdef NORM_DEBUG
@ -1721,14 +1767,12 @@ double NormSession::CalculateRtt(const struct timeval& currentTime,
void NormSession::ServerUpdateGrttEstimate(double clientRtt) void NormSession::ServerUpdateGrttEstimate(double clientRtt)
{ {
grtt_response = true; grtt_response = true;
if ((clientRtt > grtt_measured) || !address.IsMulticast()) if ((clientRtt > grtt_measured) || !address.IsMulticast())
{ {
// Immediately incorporate bigger RTT's // Immediately incorporate bigger RTT's
grtt_decrease_delay_count = DEFAULT_GRTT_DECREASE_DELAY; grtt_decrease_delay_count = DEFAULT_GRTT_DECREASE_DELAY;
//grtt_measured = 0.25 * grtt_measured + 0.75 * clientRtt; grtt_measured = 0.25 * grtt_measured + 0.75 * clientRtt;
grtt_measured = 0.9 * grtt_measured + 0.1 * clientRtt; //grtt_measured = 0.9 * grtt_measured + 0.1 * clientRtt;
if (grtt_measured > grtt_max) grtt_measured = grtt_max; if (grtt_measured > grtt_max) grtt_measured = grtt_max;
UINT8 grttQuantizedOld = grtt_quantized; UINT8 grttQuantizedOld = grtt_quantized;
double pktInterval = ((double)(44+segment_size))/tx_rate; double pktInterval = ((double)(44+segment_size))/tx_rate;
@ -1738,6 +1782,11 @@ void NormSession::ServerUpdateGrttEstimate(double clientRtt)
grtt_quantized = NormQuantizeRtt(grtt_measured); grtt_quantized = NormQuantizeRtt(grtt_measured);
// Calculate grtt_advertised since quantization rounds upward // Calculate grtt_advertised since quantization rounds upward
grtt_advertised = NormUnquantizeRtt(grtt_quantized); grtt_advertised = NormUnquantizeRtt(grtt_quantized);
if (grtt_advertised > grtt_max)
{
grtt_quantized = NormQuantizeRtt(grtt_max);
grtt_advertised = NormUnquantizeRtt(grtt_quantized);
}
grtt_current_peak = grtt_measured; grtt_current_peak = grtt_measured;
if (grttQuantizedOld != grtt_quantized) if (grttQuantizedOld != grtt_quantized)
DMSG(4, "NormSession::ServerUpdateGrttEstimate() node>%lu increased to new grtt>%lf sec\n", DMSG(4, "NormSession::ServerUpdateGrttEstimate() node>%lu increased to new grtt>%lf sec\n",
@ -1804,7 +1853,9 @@ void NormSession::ServerHandleCCFeedback(struct timeval currentTime,
// 1) Does this response replace the active CLR? // 1) Does this response replace the active CLR?
if (next && next->IsActive()) if (next && next->IsActive())
{ {
if (ccRate < next->GetRate() || (nodeId == next->GetId())) if ((nodeId == next->GetId()) ||
(ccRate < next->GetRate()) ||
((ccRate < (next->GetRate() * 1.1)) && (ccRtt > next->GetRtt()))) // use Rtt as tie-breaker if close
{ {
NormNodeId savedId = next->GetId(); NormNodeId savedId = next->GetId();
bool savedRttStatus = next->HasRtt(); bool savedRttStatus = next->HasRtt();
@ -2519,8 +2570,32 @@ void NormSession::ClientHandleNackMessage(const NormNackMsg& nack)
bool NormSession::ServerQueueSquelch(NormObjectId objectId) bool NormSession::ServerQueueSquelch(NormObjectId objectId)
{ {
// (TBD) if a squelch is already queued, update it if (objectId < squelch->objectId) // If a squelch is already queued, update it if (objectId < squelch->objectId)
NormCmdSquelchMsg* squelch = (NormCmdSquelchMsg*)GetMessageFromPool(); bool doEnqueue = true;
NormCmdSquelchMsg* squelch = NULL;
NormMsg* msg = message_pool.GetHead();
while (NULL != msg)
{
if (NormMsg::CMD == msg->GetType())
{
if (NormCmdMsg::SQUELCH == static_cast<NormCmdMsg*>(msg)->GetFlavor())
{
squelch = static_cast<NormCmdSquelchMsg*>(msg);
break;
}
}
msg = msg->GetNext();
}
if (NULL != squelch)
{
if (objectId >= squelch->GetObjectId())
return false; // no need to update squelch
doEnqueue = false;
}
else
{
squelch = (NormCmdSquelchMsg*)GetMessageFromPool();
}
if (squelch) if (squelch)
{ {
squelch->Init(); squelch->Init();
@ -2577,9 +2652,17 @@ bool NormSession::ServerQueueSquelch(NormObjectId objectId)
nextId++; nextId++;
} }
} }
QueueMessage(squelch); if (doEnqueue)
DMSG(4, "NormSession::ServerQueueSquelch() node>%lu server queued squelch ...\n", {
LocalNodeId()); QueueMessage(squelch);
DMSG(4, "NormSession::ServerQueueSquelch() node>%lu server queued squelch ...\n",
LocalNodeId());
}
else
{
DMSG(4, "NormSession::ServerQueueSquelch() node>%lu server updated squelch ...\n",
LocalNodeId());
}
return true; return true;
} }
else else
@ -2637,6 +2720,8 @@ bool NormSession::ServerBuildRepairAdv(NormCmdRepairAdvMsg& cmd)
if (0 == cmd.PackRepairRequest(req)) if (0 == cmd.PackRepairRequest(req))
{ {
DMSG(0, "NormSession::ServerBuildRepairAdv() warning: full msg\n"); DMSG(0, "NormSession::ServerBuildRepairAdv() warning: full msg\n");
// (TBD) set NORM_REPAIR_ADV_LIMIT flag in this case
prevForm = NormRepairRequest::INVALID;
break; break;
} }
} }
@ -2669,7 +2754,13 @@ bool NormSession::ServerBuildRepairAdv(NormCmdRepairAdvMsg& cmd)
{ {
if ((NormRepairRequest::INVALID != prevForm) && currentObject->IsRepairPending()) if ((NormRepairRequest::INVALID != prevForm) && currentObject->IsRepairPending())
{ {
cmd.PackRepairRequest(req); // (TBD) error check; if (0 == cmd.PackRepairRequest(req))
{
DMSG(0, "NormSession::ServerBuildRepairAdv() warning: full msg\n");
// (TBD) set NORM_REPAIR_ADV_LIMIT flag in this case
prevForm = NormRepairRequest::INVALID;
break;
}
prevForm = NormRepairRequest::INVALID; prevForm = NormRepairRequest::INVALID;
currentObject->AppendRepairAdv(cmd); currentObject->AppendRepairAdv(cmd);
} }
@ -2684,6 +2775,7 @@ bool NormSession::ServerBuildRepairAdv(NormCmdRepairAdvMsg& cmd)
{ {
if (0 == cmd.PackRepairRequest(req)) if (0 == cmd.PackRepairRequest(req))
DMSG(0, "NormSession::ServerBuildRepairAdv() warning: full msg\n"); DMSG(0, "NormSession::ServerBuildRepairAdv() warning: full msg\n");
// (TBD) set NORM_REPAIR_ADV_LIMIT flag in this case
} }
return true; return true;
} // end NormSession::ServerBuildRepairAdv() } // end NormSession::ServerBuildRepairAdv()
@ -2716,18 +2808,20 @@ bool NormSession::OnRepairTimeout(ProtoTimer& /*theTimer*/)
} }
else else
{ {
//DMSG(6, "NormSession::OnRepairTimeout() node>%lu activating obj>%hu repairs ...\n", DMSG(6, "NormSession::OnRepairTimeout() node>%lu activating obj>%hu repairs ...\n",
// LocalNodeId(), (UINT16)objectId); LocalNodeId(), (UINT16)objectId);
if (obj->ActivateRepairs()) if (obj->ActivateRepairs())
{ {
DMSG(6, "NormSession::OnRepairTimeout() node>%lu activated obj>%hu repairs ...\n", DMSG(6, "NormSession::OnRepairTimeout() node>%lu activated obj>%hu repairs fd=%d...\n",
LocalNodeId(), (UINT16)objectId); LocalNodeId(), (UINT16)objectId, static_cast<NormFileObject*>(obj)->file.fd);
if (!tx_pending_mask.Set(objectId)) if (!tx_pending_mask.Set(objectId))
DMSG(0, "NormSession::OnRepairTimeout() rx_pending_mask.Set(%hu) error (2)\n", DMSG(0, "NormSession::OnRepairTimeout() rx_pending_mask.Set(%hu) error (2)\n",
(UINT16)objectId); (UINT16)objectId);
} }
} }
} // end while (iterator.GetNextObject()) } // end while (iterator.GetNextObject())
// (TBD) should this be just PromptServer() instead???
// (note we do set posted_tx_queue_empty when repair state blocks stream progress)
TouchServer(); TouchServer();
// BACKOFF related code // BACKOFF related code
// Holdoff initiation of new repair cycle for one GRTT // Holdoff initiation of new repair cycle for one GRTT
@ -2800,6 +2894,8 @@ bool NormSession::OnTxTimeout(ProtoTimer& /*theTimer*/)
{ {
if (SendMessage(*msg)) if (SendMessage(*msg))
{ {
if (tx_rate > 0.0)
tx_timer.SetInterval(msg->GetLength() / tx_rate);
if (advertise_repairs) if (advertise_repairs)
advertise_repairs = false; advertise_repairs = false;
else else
@ -2840,10 +2936,7 @@ bool NormSession::OnTxTimeout(ProtoTimer& /*theTimer*/)
bool NormSession::SendMessage(NormMsg& msg) bool NormSession::SendMessage(NormMsg& msg)
{ {
struct timeval currentTime; bool isClientMsg = false;
ProtoSystemTime(currentTime);
bool clientMsg = false;
bool isProbe = false; bool isProbe = false;
// Fill in any last minute timestamps // Fill in any last minute timestamps
@ -2860,9 +2953,15 @@ bool NormSession::SendMessage(NormMsg& msg)
switch (((NormCmdMsg&)msg).GetFlavor()) switch (((NormCmdMsg&)msg).GetFlavor())
{ {
case NormCmdMsg::CC: case NormCmdMsg::CC:
{
struct timeval currentTime;
ProtoSystemTime(currentTime);
((NormCmdCCMsg&)msg).SetSendTime(currentTime); ((NormCmdCCMsg&)msg).SetSendTime(currentTime);
isProbe = true; isProbe = true;
break; break;
}
case NormCmdMsg::SQUELCH:
break;
default: default:
break; break;
} }
@ -2871,11 +2970,13 @@ bool NormSession::SendMessage(NormMsg& msg)
case NormMsg::NACK: case NormMsg::NACK:
{ {
clientMsg = true; isClientMsg = true;
NormNackMsg& nack = (NormNackMsg&)msg; NormNackMsg& nack = (NormNackMsg&)msg;
NormServerNode* theServer = NormServerNode* theServer =
(NormServerNode*)server_tree.FindNodeById(nack.GetServerId()); (NormServerNode*)server_tree.FindNodeById(nack.GetServerId());
ASSERT(theServer); ASSERT(theServer);
struct timeval currentTime;
ProtoSystemTime(currentTime);
struct timeval grttResponse; struct timeval grttResponse;
theServer->CalculateGrttResponse(currentTime, grttResponse); theServer->CalculateGrttResponse(currentTime, grttResponse);
nack.SetGrttResponse(grttResponse); nack.SetGrttResponse(grttResponse);
@ -2884,12 +2985,14 @@ bool NormSession::SendMessage(NormMsg& msg)
case NormMsg::ACK: case NormMsg::ACK:
{ {
clientMsg = true; isClientMsg = true;
NormAckMsg& ack = (NormAckMsg&)msg; NormAckMsg& ack = (NormAckMsg&)msg;
NormServerNode* theServer = NormServerNode* theServer =
(NormServerNode*)server_tree.FindNodeById(ack.GetServerId()); (NormServerNode*)server_tree.FindNodeById(ack.GetServerId());
ASSERT(theServer); ASSERT(theServer);
struct timeval grttResponse; struct timeval grttResponse;
struct timeval currentTime;
ProtoSystemTime(currentTime);
theServer->CalculateGrttResponse(currentTime, grttResponse); theServer->CalculateGrttResponse(currentTime, grttResponse);
ack.SetGrttResponse(grttResponse); ack.SetGrttResponse(grttResponse);
break; break;
@ -2905,7 +3008,7 @@ bool NormSession::SendMessage(NormMsg& msg)
bool result = true; bool result = true;
// Possibly drop some tx messages for testing purposes // Possibly drop some tx messages for testing purposes
bool drop = (UniformRand(100.0) < tx_loss_rate); bool drop = (UniformRand(100.0) < tx_loss_rate);
if (drop || (clientMsg && client_silent)) if (drop || (isClientMsg && client_silent))
{ {
//DMSG(0, "TX MESSAGE DROPPED! (tx_loss_rate:%lf\n", tx_loss_rate); //DMSG(0, "TX MESSAGE DROPPED! (tx_loss_rate:%lf\n", tx_loss_rate);
} }
@ -2915,36 +3018,14 @@ bool NormSession::SendMessage(NormMsg& msg)
msg.GetDestination())) msg.GetDestination()))
{ {
// Separate send/recv tracing // Separate send/recv tracing
if (trace) NormTrace(currentTime, LocalNodeId(), msg, true); if (trace)
// Keep track of _actual_ sent rate
// (TBD) move "sent_rate" tracking to ""OnReportTimeout()
// since it is no longer critical to protocol operation
// but just kept for information purposes ...
if (prev_update_time.tv_sec || prev_update_time.tv_usec)
{ {
double interval = (double)(currentTime.tv_sec - prev_update_time.tv_sec); struct timeval currentTime;
if (currentTime.tv_usec > prev_update_time.tv_sec) ProtoSystemTime(currentTime);
interval += 1.0e-06*(double)(currentTime.tv_usec - prev_update_time.tv_usec); NormTrace(currentTime, LocalNodeId(), msg, true);
else
interval -= 1.0e-06*(double)(prev_update_time.tv_usec - currentTime.tv_usec);
if (interval < 1.0) //grtt_advertised)
{
sent_accumulator += msgSize;
}
else
{
sent_rate = ((double)(sent_accumulator)) / interval;
prev_update_time = currentTime;
sent_accumulator = msgSize;
}
}
else
{
sent_rate = ((double)msgSize) / grtt_advertised;
prev_update_time = currentTime;
sent_accumulator = msgSize;
} }
// To keep track of _actual_ sent rate
sent_accumulator += msgSize;
// Update nominal packet size // Update nominal packet size
nominal_packet_size += 0.05 * (((double)msgSize) - nominal_packet_size); nominal_packet_size += 0.05 * (((double)msgSize) - nominal_packet_size);
} }
@ -2954,19 +3035,36 @@ bool NormSession::SendMessage(NormMsg& msg)
result = false; result = false;
} }
} }
if (result && isProbe) if (result)
{ {
probe_pending = false; if (isProbe)
if (probe_reset)
{ {
probe_reset = false; probe_pending = false;
OnProbeTimeout(probe_timer); //we commented this out to give data a chance at low rates probe_data_check = true;
// we may want to re-visit this, it might compromis high rate performance a little if (probe_reset)
ActivateTimer(probe_timer); {
probe_reset = false;
if (!probe_timer.IsActive())
ActivateTimer(probe_timer);
}
} }
else if (!isClientMsg)
{
probe_data_check = false;
if (!probe_pending && probe_reset)
{
probe_reset = false;
OnProbeTimeout(probe_timer);
if (!probe_timer.IsActive())
ActivateTimer(probe_timer);
}
}
return true;
}
else
{
return false;
} }
tx_timer.SetInterval(((double)msgSize) / tx_rate);
return result;
} // end NormSession::SendMessage() } // end NormSession::SendMessage()
void NormSession::SetGrttProbingInterval(double intervalMin, double intervalMax) void NormSession::SetGrttProbingInterval(double intervalMin, double intervalMax)
@ -2978,8 +3076,8 @@ void NormSession::SetGrttProbingInterval(double intervalMin, double intervalMax)
intervalMin = intervalMax; intervalMin = intervalMax;
intervalMax = temp; intervalMax = temp;
} }
if (intervalMin < 0.100) intervalMin = 0.100; if (intervalMin < NORM_TICK_MIN) intervalMin = NORM_TICK_MIN;
if (intervalMax < 0.100) intervalMax = 0.100; if (intervalMax < NORM_TICK_MIN) intervalMax = NORM_TICK_MIN;
grtt_interval_min = intervalMin; grtt_interval_min = intervalMin;
grtt_interval_max = intervalMax; grtt_interval_max = intervalMax;
if (grtt_interval < grtt_interval_min) if (grtt_interval < grtt_interval_min)
@ -3047,10 +3145,12 @@ void NormSession::SetGrttProbingMode(ProbingMode probingMode)
bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/) bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
{ {
// 1) Temporarily kill probe_timer if CMD(CC) not yet tx'd // 1) Temporarily kill probe_timer if CMD(CC) not yet tx'd
if (probe_pending) // (or if data has not been sent since last probe)
if (probe_pending || (data_active && probe_data_check))
{ {
probe_reset = true; probe_reset = true;
probe_timer.Deactivate(); if (probe_timer.IsActive())
probe_timer.Deactivate();
return false; return false;
} }
else if (0.0 == tx_rate) else if (0.0 == tx_rate)
@ -3100,13 +3200,17 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
// Update grtt estimate // Update grtt estimate
if (grtt_current_peak < grtt_measured) if (grtt_current_peak < grtt_measured)
{ {
if (grtt_decrease_delay_count-- == 0) grtt_measured *= 0.9;
if (grtt_current_peak > grtt_measured)
grtt_measured = grtt_current_peak;
// (TBD) "grtt_decrease_delay_count" isn't needed any more ...
/*if (grtt_decrease_delay_count-- == 0)
{ {
grtt_measured = 0.5 * grtt_measured + grtt_measured = 0.5 * grtt_measured +
0.5 * grtt_current_peak; 0.5 * grtt_current_peak;
grtt_current_peak = 0.0; grtt_current_peak = 0.0;
grtt_decrease_delay_count = DEFAULT_GRTT_DECREASE_DELAY; grtt_decrease_delay_count = DEFAULT_GRTT_DECREASE_DELAY;
} }*/
} }
else else
{ {
@ -3126,6 +3230,11 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
grtt_quantized = NormQuantizeRtt(grtt_measured); grtt_quantized = NormQuantizeRtt(grtt_measured);
// Recalculate grtt_advertise since quantization rounds upward // Recalculate grtt_advertise since quantization rounds upward
grtt_advertised = NormUnquantizeRtt(grtt_quantized); grtt_advertised = NormUnquantizeRtt(grtt_quantized);
if (grtt_advertised > grtt_max)
{
grtt_quantized = NormQuantizeRtt(grtt_max);
grtt_advertised = NormUnquantizeRtt(grtt_quantized);
}
if (grttQuantizedOld != grtt_quantized) if (grttQuantizedOld != grtt_quantized)
DMSG(4, "NormSession::OnProbeTimeout() node>%lu decreased to new grtt to: %lf sec\n", DMSG(4, "NormSession::OnProbeTimeout() node>%lu decreased to new grtt to: %lf sec\n",
LocalNodeId(), grtt_advertised); LocalNodeId(), grtt_advertised);
@ -3198,8 +3307,12 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
else else
feedbackAge -= 1.0e-06*((double)(feedbackTime.tv_usec - currentTime.tv_usec)); feedbackAge -= 1.0e-06*((double)(feedbackTime.tv_usec - currentTime.tv_usec));
double maxFeedbackAge = 5 * grtt_advertised; double maxFeedbackAge = 5 * grtt_advertised;
if (maxFeedbackAge < 0.100) // Safety bound to compensate for computer clock coarseness
maxFeedbackAge = 0.100; // due computer clock coarseness // and possible sluggish feedback from slower machines
// at higher norm data rates (keeps rate from being
// prematurely reduced)
if (maxFeedbackAge <(10*NORM_TICK_MIN))
maxFeedbackAge = (10*NORM_TICK_MIN);
if (feedbackAge > maxFeedbackAge) if (feedbackAge > maxFeedbackAge)
next->SetActive(false); next->SetActive(false);
} }
@ -3223,9 +3336,10 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
// Determine next probe_interval // Determine next probe_interval
probeInterval = grtt_interval; probeInterval = grtt_interval;
} }
// perhaps this instead of the commented out probe_reset case??? /*// perhaps this instead of the commented out probe_reset case???
double nominalInterval = ((double)segment_size)/((double)tx_rate); double nominalInterval = ((double)segment_size)/((double)tx_rate);
if (nominalInterval > probeInterval) probeInterval = nominalInterval; if (nominalInterval > grtt_max) nominalInterval = grtt_max;
if (nominalInterval > probeInterval) probeInterval = nominalInterval; */
// Set probe_timer interval for next probe // Set probe_timer interval for next probe
probe_timer.SetInterval(probeInterval); probe_timer.SetInterval(probeInterval);
@ -3254,9 +3368,12 @@ void NormSession::AdjustRate(bool onResponse)
if (cc_slow_start) if (cc_slow_start)
{ {
txRate = clr->GetRate(); txRate = clr->GetRate();
DMSG(6, "NormSession::AdjustRate(slow start) clr>%lu newRate>%lf (oldRate>%lf sentRate>%lf clrRate>%lf\n", if (GetDebugLevel() >= 6)
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); double sentRate = 8.0e-03*((double)sent_accumulator) / (report_timer.GetInterval() - report_timer.GetTimeRemaining());
DMSG(6, "NormSession::AdjustRate(slow start) clr>%lu newRate>%lf (oldRate>%lf sentRate>%lf clrRate>%lf\n",
clr->GetId(), 8.0e-03*txRate, 8.0e-03*tx_rate, sentRate, 8.0e-03*clr->GetRate());
}
} }
else else
{ {
@ -3271,8 +3388,17 @@ void NormSession::AdjustRate(bool onResponse)
txRate = clrRate; txRate = clrRate;
} }
DMSG(6, "NormSession::AdjustRate(stdy state) clr>%lu newRate>%lf (rtt>%lf loss>%lf)\n", 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()); clr->GetId(), 8.0e-03*txRate, clr->GetRtt(), clr->GetLoss());
} }
// Adjust the probe timeout right away
/* double probeInterval = probe_timer.GetInterval();
if (probeInterval > ccRtt)
{
double elapsed = probeInterval - probe_timer.GetTimeRemaining();
probeInterval = (ccRtt > elapsed) ? (ccRtt - elapsed) : 0.0;
probe_timer.SetInterval(probeInterval);
if (probe_timer.IsActive()) probe_timer.Reschedule();
} */
} }
} }
else if (!data_active) else if (!data_active)
@ -3305,38 +3431,30 @@ void NormSession::AdjustRate(bool onResponse)
// reduce rate if no active clr // reduce rate if no active clr
txRate *= 0.5; txRate *= 0.5;
} }
// Don't let txRate below MIN(one segment per grtt, one segment per 4 seconds) // Keep "tx_rate" within default or user set rate bounds (if any)
double minRate = ((double)segment_size) / grtt_measured; double minRate;
if (minRate > ((double)(segment_size >> 2))) if(tx_rate_min > 0.0)
minRate = (double)(segment_size >> 2); {
if (txRate < minRate) minRate = tx_rate_min;
txRate = minRate; }
else
// Keep "tx_rate" within user set rate bounds (if any) {
if ((tx_rate_min >= 0.0) && (txRate < tx_rate_min)) // Don't let txRate below MIN(one segment per grtt, one segment per second)
txRate = tx_rate_min; minRate = ((double)segment_size) / grtt_measured;
if (minRate > ((double)(segment_size)))
minRate = (double)(segment_size);
}
if (txRate < minRate) txRate = minRate;
if ((tx_rate_max >= 0.0) && (txRate > tx_rate_max)) if ((tx_rate_max >= 0.0) && (txRate > tx_rate_max))
txRate = tx_rate_max; txRate = tx_rate_max;
if (txRate != tx_rate) SetTxRateInternal(txRate); if (txRate != tx_rate) SetTxRateInternal(txRate);
/*if (txRate != oldRate)
{
if (tx_timer.IsActive())
{
//double ratio = tx_rate / oldRate;
double txInterval = tx_timer.GetInterval() * oldRate / tx_rate;
double timeElapsed = tx_timer.GetInterval() - tx_timer.GetTimeRemaining();
txInterval = timeElapsed < txInterval ? (txInterval - timeElapsed) : 0.0;
tx_timer.SetInterval(txInterval);
tx_timer.Reschedule();
}
}*/
struct timeval currentTime; struct timeval currentTime;
::ProtoSystemTime(currentTime); ::ProtoSystemTime(currentTime);
double theTime = (double)currentTime.tv_sec + 1.0e-06 * ((double)currentTime.tv_usec); double theTime = (double)currentTime.tv_sec + 1.0e-06 * ((double)currentTime.tv_usec);
DMSG(8, "ServerRateTracking time>%lf rate>%lf rtt>%lf loss>%lf\n\n", theTime, tx_rate*(8.0/1000.0), ccRtt, ccLoss); DMSG(8, "ServerRateTracking time>%lf rate>%lf rtt>%lf loss>%lf\n\n", theTime, 8.0e-03*tx_rate, ccRtt, ccLoss);
} // end NormSession::AdjustRate() } // end NormSession::AdjustRate()
bool NormSession::OnReportTimeout(ProtoTimer& /*theTimer*/) bool NormSession::OnReportTimeout(ProtoTimer& /*theTimer*/)
@ -3360,16 +3478,17 @@ bool NormSession::OnReportTimeout(ProtoTimer& /*theTimer*/)
if (IsServer()) if (IsServer())
{ {
DMSG(2, "Local status:\n"); DMSG(2, "Local status:\n");
double sentRate = 8.0e-03*((double)sent_accumulator) / report_timer.GetInterval(); // kbps
sent_accumulator = 0;
DMSG(2, " txRate>%9.3lf kbps sentRate>%9.3lf grtt>%lf\n", DMSG(2, " txRate>%9.3lf kbps sentRate>%9.3lf grtt>%lf\n",
((double)tx_rate)*8.0/1000.0, sent_rate*8.0/1000.0, grtt_advertised); 8.0e-03*tx_rate, sentRate, grtt_advertised);
if (cc_enable) if (cc_enable)
{ {
const NormCCNode* clr = (const NormCCNode*)cc_node_list.Head(); const NormCCNode* clr = (const NormCCNode*)cc_node_list.Head();
if (clr) if (clr)
DMSG(2, " clr>%lu rate>%9.3lf rtt>%lf loss>%lf\n", clr->GetId(), DMSG(2, " clr>%lu rate>%9.3lf rtt>%lf loss>%lf %s\n", clr->GetId(),
clr->GetRate()*8.0/1000.0, clr->GetRtt(), clr->GetLoss()); 8.0e-03*clr->GetRate(), clr->GetRtt(), clr->GetLoss(), cc_slow_start ? "(slow_start)" : "");
} }
} }
if (IsClient()) if (IsClient())
{ {
@ -3384,12 +3503,13 @@ bool NormSession::OnReportTimeout(ProtoTimer& /*theTimer*/)
DMSG(2, " rxRate>%9.3lf kbps rx_goodput>%9.3lf kbps\n", rxRate, rxGoodput); DMSG(2, " rxRate>%9.3lf kbps rx_goodput>%9.3lf kbps\n", rxRate, rxGoodput);
DMSG(2, " rxObjects> completed>%lu pending>%lu failed:%lu\n", DMSG(2, " rxObjects> completed>%lu pending>%lu failed:%lu\n",
next->CompletionCount(), next->PendingCount(), next->FailureCount()); next->CompletionCount(), next->PendingCount(), next->FailureCount());
DMSG(2, " bufferUsage> current>%lu peak>%lu (overuns>%lu)\n", next->CurrentBufferUsage(), DMSG(2, " fecBufferUsage> current>%lu peak>%lu (overuns>%lu)\n", next->CurrentBufferUsage(),
next->PeakBufferUsage(), next->PeakBufferUsage(),
next->BufferOverunCount()); next->BufferOverunCount());
DMSG(2, " resyncs>%lu nacks>%lu suppressed>%lu\n", next->ResyncCount(), DMSG(2, " resyncs>%lu nacks>%lu suppressed>%lu\n",
next->NackCount(), next->ResyncCount() ? next->ResyncCount() - 1 : 0, // "ResyncCount()" is reall "SyncCount()"
next->SuppressCount()); next->NackCount(),
next->SuppressCount());
} }
} // end if (IsClient()) } // end if (IsClient())

View File

@ -121,6 +121,14 @@ class NormSession
ttl = result ? theTTL : ttl; ttl = result ? theTTL : ttl;
return result; return result;
} }
bool SetTOS(UINT8 theTOS)
{
// (TBD) call tx_socket->SetFlowLabel() to set traffic class for IPv6 sockets
// (or should we have ProtoSocket::SetTOS() do this for us?)
bool result = tx_socket->IsOpen() ? tx_socket->SetTOS(theTOS) : true;
tos = result ? theTOS : ttl;
return result;
}
bool SetLoopback(bool state) bool SetLoopback(bool state)
{ {
bool result = tx_socket->IsOpen() ? tx_socket->SetLoopback(state) : true; bool result = tx_socket->IsOpen() ? tx_socket->SetLoopback(state) : true;
@ -128,7 +136,11 @@ class NormSession
return result; return result;
} }
void SetTxPort(UINT16 txPort) {tx_port = txPort;} void SetTxPort(UINT16 txPort) {tx_port = txPort;}
void SetRxPortReuse(bool state) {rx_port_reuse = state;} void SetRxPortReuse(bool enable, bool bindToSessionAddress = true)
{
rx_port_reuse = enable; // allow sessionPort reuse when true
rx_addr_bind = bindToSessionAddress; // bind rx_socket to sessionAddr when true
}
static double CalculateRate(double size, double rtt, double loss); static double CalculateRate(double size, double rtt, double loss);
NormSessionMgr& GetSessionMgr() {return session_mgr;} NormSessionMgr& GetSessionMgr() {return session_mgr;}
@ -139,7 +151,10 @@ class NormSession
{return rx_socket.SetRxBufferSize(bufferSize);} {return rx_socket.SetRxBufferSize(bufferSize);}
// Session parameters // Session parameters
double TxRate() {return (tx_rate * 8.0);} double GetTxRate()
{
return (tx_rate * 8.0); // convert to bits/second
}
// (TBD) watch timer scheduling and min/max bounds // (TBD) watch timer scheduling and min/max bounds
void SetTxRate(double txRate) void SetTxRate(double txRate)
{ {
@ -384,8 +399,10 @@ class NormSession
NormNodeId local_node_id; NormNodeId local_node_id;
ProtoAddress address; // session destination address & port ProtoAddress address; // session destination address & port
UINT8 ttl; // session multicast ttl UINT8 ttl; // session multicast ttl
UINT8 tos; // session IPv4 TOS (or IPv6 traffic class - TBD)
bool loopback; // to receive own traffic bool loopback; // to receive own traffic
bool rx_port_reuse; // enable port reuse bool rx_port_reuse; // enable rx_socket port (sessionPort) reuse when true
bool rx_addr_bind; // bind rx_socket to sessionAddr when true
char interface_name[32]; char interface_name[32];
double tx_rate; // bytes per second double tx_rate; // bytes per second
double tx_rate_min; double tx_rate_min;
@ -437,6 +454,7 @@ class NormSession
bool probe_proactive; bool probe_proactive;
bool probe_pending; // true while CMD(CC) enqueued bool probe_pending; // true while CMD(CC) enqueued
bool probe_reset; bool probe_reset;
bool probe_data_check; // refrain cc probe until data is send
struct timeval probe_time_last; struct timeval probe_time_last;
double grtt_interval; // current GRTT update interval double grtt_interval; // current GRTT update interval
@ -460,9 +478,7 @@ class NormSession
UINT8 cc_sequence; UINT8 cc_sequence;
NormNodeList cc_node_list; NormNodeList cc_node_list;
bool cc_slow_start; bool cc_slow_start;
double sent_rate; // measured sent rate unsigned long sent_accumulator; // for sentRate measurement
struct timeval prev_update_time; // 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 bool data_active; // true when actively sending data

View File

@ -369,7 +369,7 @@ bool NormSimAgent::ProcessCommand(const char* cmd, const char* val)
tx_object_size += tx_object_size_min; tx_object_size += tx_object_size_min;
if (session) if (session)
{ {
TRACE("Queued file size: %lu bytes\n", tx_object_size); DMSG(2, "NormSimAgent::ProcessCommand(sendRandomFile) Queued file size: %lu bytes\n", tx_object_size);
return (NULL != session->QueueTxSim(tx_object_size)); return (NULL != session->QueueTxSim(tx_object_size));
} }
else else
@ -494,7 +494,7 @@ bool NormSimAgent::ProcessCommand(const char* cmd, const char* val)
DMSG(0, "NormSimAgent::ProcessCommand(unicastNacks) invalid argument!\n"); DMSG(0, "NormSimAgent::ProcessCommand(unicastNacks) invalid argument!\n");
return false; return false;
} }
if (session) session->SetUnicastNacks(unicast_nacks); if (session) session->ClientSetUnicastNacks(unicast_nacks);
return true; return true;
} }
else if (!strncmp("silentClient", cmd, len)) else if (!strncmp("silentClient", cmd, len))
@ -590,8 +590,6 @@ bool NormSimAgent::SendMessage(unsigned int len, const char* txBuffer)
void NormSimAgent::OnInputReady() void NormSimAgent::OnInputReady()
{ {
//TRACE("NormSimAgent::OnInputReady() index:%lu len:%lu\n",
// tx_msg_index, tx_msg_len);
if (tx_msg_index < tx_msg_len) if (tx_msg_index < tx_msg_len)
{ {
unsigned int bytesWrote = stream->Write(tx_msg_buffer+tx_msg_index, unsigned int bytesWrote = stream->Write(tx_msg_buffer+tx_msg_index,
@ -618,6 +616,7 @@ bool NormSimAgent::FlushStream()
else else
{ {
DMSG(0, "NormSimAgent::FlushStream() no output stream to flush\n"); DMSG(0, "NormSimAgent::FlushStream() no output stream to flush\n");
return false;
} }
} // end NormSimAgent::FlushStream() } // end NormSimAgent::FlushStream()
@ -630,6 +629,7 @@ void NormSimAgent::Notify(NormController::Event event,
{ {
switch (event) switch (event)
{ {
//case TX_QUEUE_VACANCY:
case TX_QUEUE_EMPTY: case TX_QUEUE_EMPTY:
// Can queue a new object or write to stream for transmission // Can queue a new object or write to stream for transmission
if (object && (object == stream)) if (object && (object == stream))
@ -638,8 +638,7 @@ void NormSimAgent::Notify(NormController::Event event,
{ {
// sending a dummy byte stream // sending a dummy byte stream
char buffer[NormMsg::MAX_SIZE]; char buffer[NormMsg::MAX_SIZE];
unsigned int count = stream->Write(buffer, segment_size, false);
stream->Write(buffer, segment_size, false);
} }
else else
{ {
@ -663,7 +662,6 @@ void NormSimAgent::Notify(NormController::Event event,
case RX_OBJECT_NEW: case RX_OBJECT_NEW:
{ {
//TRACE("NormSimAgent::Notify(RX_OBJECT_NEW) ...\n");
// It's up to the app to "accept" the object // It's up to the app to "accept" the object
switch (object->GetType()) switch (object->GetType())
{ {
@ -695,23 +693,26 @@ void NormSimAgent::Notify(NormController::Event event,
case NormObject::DATA: case NormObject::DATA:
DMSG(0, "NormSimAgent::Notify() FILE/DATA objects not _yet_ supported...\n"); DMSG(0, "NormSimAgent::Notify() FILE/DATA objects not _yet_ supported...\n");
break; break;
default:
DMSG(0, "NormSimAgent::Notify() INVALID object type!\n");
ASSERT(0);
break;
} }
break; break;
} }
case RX_OBJECT_INFO: case RX_OBJECT_INFO:
//TRACE("NormSimAgent::Notify(RX_OBJECT_INFO) ...\n");
switch(object->GetType()) switch(object->GetType())
{ {
case NormObject::FILE: case NormObject::FILE:
case NormObject::DATA: case NormObject::DATA:
case NormObject::STREAM: case NormObject::STREAM:
default:
break; break;
} // end switch(object->GetType()) } // end switch(object->GetType())
break; break;
case RX_OBJECT_UPDATE: case RX_OBJECT_UPDATED:
//TRACE("NormSimAgent::Notify(RX_OBJECT_UPDATE) ...\n");
switch (object->GetType()) switch (object->GetType())
{ {
case NormObject::FILE: case NormObject::FILE:
@ -830,6 +831,10 @@ void NormSimAgent::Notify(NormController::Event event,
case NormObject::DATA: case NormObject::DATA:
DMSG(0, "NormSimAgent::Notify() FILE/DATA objects not _yet_ supported...\n"); DMSG(0, "NormSimAgent::Notify() FILE/DATA objects not _yet_ supported...\n");
break; break;
default:
// should never occur
break;
} // end switch (object->GetType()) } // end switch (object->GetType())
break; break;
case RX_OBJECT_COMPLETED: case RX_OBJECT_COMPLETED:
@ -839,16 +844,19 @@ void NormSimAgent::Notify(NormController::Event event,
case NormObject::FILE: case NormObject::FILE:
//DMSG(0, "norm: Completed rx file: %s\n", ((NormFileObject*)object)->Path()); //DMSG(0, "norm: Completed rx file: %s\n", ((NormFileObject*)object)->Path());
break; break;
case NormObject::STREAM: case NormObject::STREAM:
ASSERT(0); //DMSG(0, "norm: Completed rx stream ...\n");
break; break;
case NormObject::DATA: case NormObject::DATA:
ASSERT(0); ASSERT(0);
break; break;
default:
break;
} }
break; break;
} }
default:
DMSG(0, "NormSimAgent::Notify() unhandled NormEvent type\n");
} // end switch(event) } // end switch(event)
} // end NormSimAgent::Notify() } // end NormSimAgent::Notify()
@ -875,7 +883,7 @@ bool NormSimAgent::OnIntervalTimeout(ProtoTimer& theTimer)
{ {
DMSG(0, "NormSimAgent::OnIntervalTimeout() Error queueing tx object.\n"); DMSG(0, "NormSimAgent::OnIntervalTimeout() Error queueing tx object.\n");
} }
TRACE("Queued file size: %lu bytes\n", tx_object_size); DMSG(2, "NormSimAgent::OnIntervalTimeout(() Queued file size: %lu bytes\n", tx_object_size);
} }
interval_timer.SetInterval(tx_object_interval); interval_timer.SetInterval(tx_object_interval);
return true; return true;
@ -917,7 +925,8 @@ bool NormSimAgent::StartServer()
session->ServerSetGroupSize(group_size); session->ServerSetGroupSize(group_size);
session->ServerSetGrtt(grtt_estimate); session->ServerSetGrtt(grtt_estimate);
// StartServer(bufferMax, segmentSize, fec_ndata, fec_nparity) // StartServer(bufferMax, segmentSize, fec_ndata, fec_nparity)
if (!session->StartServer(tx_buffer_size, segment_size, ndata, nparity)) UINT16 instanceId = (rand() * 65535) / RAND_MAX;
if (!session->StartServer(instanceId, tx_buffer_size, segment_size, ndata, nparity, NULL))
{ {
DMSG(0, "NormSimAgent::OnStartup() start server error!\n"); DMSG(0, "NormSimAgent::OnStartup() start server error!\n");
session_mgr.Destroy(); session_mgr.Destroy();
@ -961,7 +970,7 @@ bool NormSimAgent::StartClient()
session->SetTxLoss(tx_loss); session->SetTxLoss(tx_loss);
session->SetRxLoss(rx_loss); session->SetRxLoss(rx_loss);
session->SetUnicastNacks(unicast_nacks); session->ClientSetUnicastNacks(unicast_nacks);
session->ClientSetSilent(silent_client); session->ClientSetSilent(silent_client);
// StartClient(bufferSize) // StartClient(bufferSize)

View File

@ -65,12 +65,14 @@ int main(int argc, char* argv[])
6003, 6003,
localId); localId);
//NormSetTOS(session, 0x20);
// NOTE: These are debugging routines available (not for normal app use) // NOTE: These are debugging routines available (not for normal app use)
SetDebugLevel(2); SetDebugLevel(2);
// Uncomment to turn on debug NORM message tracing // Uncomment to turn on debug NORM message tracing
//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, 25.0); // 10% packet loss
//NormSetRxLoss(session, 20.0); //NormSetRxLoss(session, 20.0);
struct timeval currentTime; struct timeval currentTime;
ProtoSystemTime(currentTime); ProtoSystemTime(currentTime);
@ -78,19 +80,21 @@ int main(int argc, char* argv[])
// (and a different sender sessionId) // (and a different sender sessionId)
srand(currentTime.tv_sec); // seed random number generator srand(currentTime.tv_sec); // seed random number generator
//NormSetGrttEstimate(session, 0.001); // 1 msec initial grtt NormSetGrttEstimate(session, 0.001); // 1 msec initial grtt
NormSetTransmitRate(session, 256.0e+03); // in bits/second NormSetTransmitRate(session, 256.0e+04); // in bits/second
// Uncomment to enable TCP-friendly congestion control (overrides NormSetTransmitRate()) // Uncomment to enable TCP-friendly congestion control (overrides NormSetTransmitRate())
NormSetCongestionControl(session, true); //NormSetCongestionControl(session, true);
NormSetTransmitRateBounds(session, 1000.0, -1.0);
NormSetDefaultRepairBoundary(session, NORM_BOUNDARY_BLOCK); NormSetDefaultRepairBoundary(session, NORM_BOUNDARY_BLOCK);
// Uncomment to use a _specific_ transmit port number // Uncomment to use a _specific_ transmit port number
// (Can be the same as session port (rx port), but this // (Can be the same as session port (rx port), but this
// is _not_ recommended when unicast feedback may be // is _not_ recommended when unicast feedback may be
// possible! // possible!)
//NormSetTxPort(session, 6001); //NormSetTxPort(session, 6001);
@ -101,10 +105,12 @@ 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);
//NormSetSilentReceiver(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);
// Uncomment to set large rx socket buffer size // Uncomment to set large rx socket buffer size
// (might be needed for high rate sessions) // (might be needed for high rate sessions)
@ -114,7 +120,9 @@ int main(int argc, char* argv[])
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, 1400, 64, 8);
//NormSetAutoParity(session, 6);
// Uncomment to set large tx socket buffer size // Uncomment to set large tx socket buffer size
// (might be needed for high rate sessions) // (might be needed for high rate sessions)
@ -128,7 +136,7 @@ int main(int argc, char* argv[])
const char* fileName = "file1.jpg"; const char* fileName = "file1.jpg";
const char* fileName2 = "file2.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, 2*1024*1024);
// NORM_FLUSH_PASSIVE automatically flushes full writes to // NORM_FLUSH_PASSIVE automatically flushes full writes to
// the stream. // the stream.
@ -139,21 +147,26 @@ int main(int argc, char* argv[])
int txIndex = 0; int txIndex = 0;
int txLen = 0; int txLen = 0;
int rxIndex = 0; int rxIndex = 0;
char refBuffer[1037];
memset(refBuffer, 'a', 1037); #define STREAM_MSG_PREFIX_SIZE 1024 // we pad with 'a' character value (the msgPrefix is a prefix)
char msgPrefix[STREAM_MSG_PREFIX_SIZE];
memset(msgPrefix, 'a', STREAM_MSG_PREFIX_SIZE);
bool msgSync = false; bool msgSync = false;
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 = -1; // -1 means unlimited int sendMax = 300;//-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:
case NORM_TX_QUEUE_EMPTY: case NORM_TX_QUEUE_EMPTY:
fprintf(stderr, "stopping ....\n");
NormStopInstance(instance);
/*if (NORM_TX_QUEUE_VACANCY == theEvent.type) /*if (NORM_TX_QUEUE_VACANCY == theEvent.type)
TRACE("NORM_TX_QUEUE_VACANCY ...\n"); TRACE("NORM_TX_QUEUE_VACANCY ...\n");
else else
@ -167,9 +180,9 @@ int main(int argc, char* argv[])
{ {
if (0 == txLen) if (0 == txLen)
{ {
// Write a message to the "txBuffer" memset(txBuffer, 'a', STREAM_MSG_PREFIX_SIZE);
memset(txBuffer, 'a', 1037); // Write a message into the "txBuffer" for transmission
sprintf(txBuffer+1037, "normTest says hello %d ...\n", sendCount); sprintf(txBuffer+STREAM_MSG_PREFIX_SIZE, " normTest says hello %d ...\n", sendCount);
txLen = strlen(txBuffer); txLen = strlen(txBuffer);
} }
unsigned int want = txLen - txIndex; unsigned int want = txLen - txIndex;
@ -178,18 +191,18 @@ int main(int argc, char* argv[])
txIndex += put; txIndex += put;
if (txIndex == txLen) if (txIndex == txLen)
{ {
// Instead of "NormStreamSetFlushMode(stream, NORM_FLUSH_PASSIVE)" above // _Instead_ of "NormStreamSetAutoFlush(stream, NORM_FLUSH_PASSIVE)" above
// and "NormStreamMarkEom()" here, I could have used // _and_ "NormStreamMarkEom()" here, I could have used
// "NormStreamFlush(stream, true)" here to perform explicit flushing // "NormStreamFlush(stream, true)" here to perform explicit flushing
// and EOM marking in one fell swoop. That would be a simpler approach // and EOM marking in one fell swoop. That would be a simpler approach
// for apps where big stream messages need to be written with // for apps where very big stream messages might need to be written with
// multiple calls to "NormStreamWrite()" // multiple calls to "NormStreamWrite()"
NormStreamMarkEom(stream); NormStreamMarkEom(stream);
txLen = txIndex = 0; txLen = txIndex = 0;
sendCount++; sendCount++;
if (sendCount == 15) if (sendCount == 15)
{ {
NormSetWatermark(session, stream); //NormSetWatermark(session, stream);
} }
if ((sendMax > 0) && (sendCount >= sendMax)) if ((sendMax > 0) && (sendCount >= sendMax))
{ {
@ -280,57 +293,82 @@ int main(int argc, char* argv[])
rxBuffer[rxIndex] = '\0'; rxBuffer[rxIndex] = '\0';
if (rxIndex > 0) if (rxIndex > 0)
{ {
char* ptr = strchr(rxBuffer, '\n'); // The '\n' indicates we have received an entire message
if (ptr) int parsedLen = 0;
bool searching = true;
char* startPtr = rxBuffer;
while (searching)
{ {
// Save sub-string length char* endPtr = strchr(startPtr, '\n');
len = ptr - rxBuffer + 1; if (endPtr)
// Validate string
if (memcmp(rxBuffer, refBuffer, 1037))
ptr = (char*)NULL;
else
ptr = strstr(rxBuffer, "hello");
if (NULL != ptr)
{ {
int value; // Save sub-string message length
if (1 == sscanf(ptr, "hello %d", &value)) parsedLen += (endPtr - startPtr + 1);
// Validate received message string
if (0 == memcmp(rxBuffer, msgPrefix, STREAM_MSG_PREFIX_SIZE))
{ {
if (recvCount >= 0) char* ptr = strstr(startPtr, "hello");
if (ptr)
{ {
if (1 != (value - recvCount)) int value;
TRACE("WARNING! possible break? value:%d recvCount:%d\n", if (1 == sscanf(ptr, "hello %d", &value))
value, recvCount); {
else
msgCount++; // successful recv msgCount++; // successful recv
//else if (recvCount >= 0)
// TRACE("validated recv msg len:%d\n", len); {
if (0 != (value - recvCount))
TRACE("WARNING! possible break? value:%d recvCount:%d\n",
value, recvCount);
}
//else
// TRACE("validated recv msg len:%d\n", len);
recvCount = value+1;
if (0 == msgCount % 100)
{
TRACE("normTest: status> msgCount:%d of total:%d (%lf)\n",
msgCount, recvCount, 100.0*((double)msgCount)/((double)recvCount));
}
}
else
{
TRACE("couldn't find index!? len:%d in %s\n", len, ptr);
ASSERT(0);
}
} }
recvCount = value; else
//if (0 == msgCount % 100) {
// TRACE("recv stream msg count: %d\n", msgCount); TRACE("couldn't find \"hello\"!? len:%d in %s\n", len, rxBuffer);
ASSERT(0);
}
} }
else else
{ {
TRACE("couldn't find index!?\n"); TRACE("invalid received message!?\n");
ASSERT(0); ASSERT(0);
} }
if ((unsigned int)rxIndex > len) if (parsedLen >= rxIndex)
{ {
memmove(rxBuffer, rxBuffer+len, rxIndex - len); rxIndex = 0;
rxIndex -= len; searching = false;
} }
else else
{ {
rxIndex = 0; startPtr = rxBuffer + parsedLen;
} }
} // end if (endPtr)
else if (parsedLen > 0)
{
memmove(rxBuffer, rxBuffer+parsedLen, rxIndex - parsedLen);
rxIndex -= parsedLen;
searching = false;
} }
else else
{ {
TRACE("invalid string!?\n"); searching = false;
ASSERT(0);
} }
} } // end while(searching)
} }
} }
else else

View File

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

View File

@ -3,8 +3,6 @@
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

View File

@ -11,10 +11,10 @@ $ns_ multicast
# 2) Trace files are opened and ns and nam # 2) Trace files are opened and ns and nam
# tracing is enabled: # tracing is enabled:
set f [open norm.tr w] set f [open example.tr w]
#$ns_ trace-all $f $ns_ trace-all $f
set nf [open norm.nam w] set nf [open example.nam w]
#$ns_ namtrace-all $nf $ns_ namtrace-all $nf
set numNodes 10 set numNodes 10
@ -53,11 +53,11 @@ puts "Configuring NORM agents ..."
# 5) Configure global NORM agent parameters (debugging/logging is global) # 5) Configure global NORM agent parameters (debugging/logging is global)
# (Uncomment the "log" command to direct NORM debug output to a file) # (Uncomment the "log" command to direct NORM debug output to a file)
$norm(1) debug 1 $norm(1) debug 2
#$norm(1) log normLog.txt $norm(1) log normLog.txt
# 6) Configure NORM server agent at node 1 # 6) Configure NORM server agent at node 1
$norm(1) address $group/5000 $norm(1) address $group/1
$norm(1) rate 32000 $norm(1) rate 32000
$norm(1) block 1 $norm(1) block 1
$norm(1) parity 0 $norm(1) parity 0
@ -69,7 +69,7 @@ $norm(1) txloss 0.0
# 7) Configure NORM client agents at other nodes # 7) Configure NORM client agents at other nodes
for {set i 2} {$i <= $numNodes} {incr i} { for {set i 2} {$i <= $numNodes} {incr i} {
$norm($i) address $group/5000 $norm($i) address $group/1
$norm($i) rxbuffer 100000 $norm($i) rxbuffer 100000
$norm($i) rxloss 0.0 $norm($i) rxloss 0.0
#$norm($i) trace #$norm($i) trace

View File

@ -107,9 +107,10 @@ bool NsNormAgent::ProcessCommands(int argc, const char*const* argv)
// query agent's current state of activity // query agent's current state of activity
Tcl& tcl = Tcl::instance(); Tcl& tcl = Tcl::instance();
if (IsActive()) if (IsActive())
sprintf(tcl.result(), "on"); Tcl_SetResult(tcl.interp(), "on", TCL_STATIC);
//sprintf(tcl.result(), "on");
else else
sprintf(tcl.result(), "off"); Tcl_SetResult(tcl.interp(), "off", TCL_STATIC);
i++; i++;
continue; continue;
} }

View File

@ -53,6 +53,11 @@ libnorm.a: $(LIB_OBJ)
libnorm.so: $(LIB_OBJ) libnorm.so: $(LIB_OBJ)
$(CC) $(SYSTEM_SOFLAGS) $(LIB_OBJ) $(LIBS) -o $@ $(CC) $(SYSTEM_SOFLAGS) $(LIB_OBJ) $(LIBS) -o $@
# NORM as a dynamic library for MacOS
libnorm.dylib: $(LIB_OBJ) $(LIBPROTO)
$(CC) $(SYSTEM_SOFLAGS) $(LIB_OBJ) $(LIBPROTO) $(LIBS) -o $@
SIM_SRC = $(NORM_SRC) $(COMMON)/normSimAgent.cpp SIM_SRC = $(NORM_SRC) $(COMMON)/normSimAgent.cpp
SIM_OBJ = $(SIM_SRC:.cpp=-sim.o) SIM_OBJ = $(SIM_SRC:.cpp=-sim.o)
@ -74,7 +79,7 @@ TEST_SRC = $(COMMON)/normTest.cpp
TEST_OBJ = $(TEST_SRC:.cpp=.o) TEST_OBJ = $(TEST_SRC:.cpp=.o)
normTest: $(TEST_OBJ) libnorm.a $(LIBPROTO) normTest: $(TEST_OBJ) libnorm.a $(LIBPROTO)
$(CC) $(CFLAGS) -o $@ $(TEST_OBJ) $(LDFLAGS) libnorm.a $(LIBPROTO) $(LIBS) $(CC) $(CFLAGS) -o $@ $(TEST_OBJ) $(LDFLAGS) libnorm.a $(LIBPROTO) $(LIBS)
# (raft) command-line reliable tunnel helper # (raft) command-line reliable tunnel helper
RAFT_SRC = $(COMMON)/raft.cpp RAFT_SRC = $(COMMON)/raft.cpp

View File

@ -46,7 +46,7 @@ SYSTEM = macosx
CC = g++ CC = g++
SYSTEM_CFLAGS = -fPIC -Wall -pedantic -Wcast-align SYSTEM_CFLAGS = -fPIC -Wall -pedantic -Wcast-align
SYSTEM_SOFLAGS = -shared SYSTEM_SOFLAGS = -dynamiclib
RANLIB = ranlib RANLIB = ranlib
AR = ar AR = ar

View File

@ -16,7 +16,12 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "normTest", "normTest.vcproj", "{32CF83E0-D2E0-4E43-8F7B-72BD0AB64647}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "normTest", "normTest.vcproj", "{32CF83E0-D2E0-4E43-8F7B-72BD0AB64647}"
ProjectSection(ProjectDependencies) = postProject ProjectSection(ProjectDependencies) = postProject
{50D1D52B-702A-49FE-B490-9104FC72598D} = {50D1D52B-702A-49FE-B490-9104FC72598D} {50D1D52B-702A-49FE-B490-9104FC72598D} = {50D1D52B-702A-49FE-B490-9104FC72598D}
{D7B0023C-8798-4918-8DA0-05C9054D70B9} = {D7B0023C-8798-4918-8DA0-05C9054D70B9} {182006F3-188F-466E-89FE-8421C0478691} = {182006F3-188F-466E-89FE-8421C0478691}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NormDll", "NormDll.vcproj", "{182006F3-188F-466E-89FE-8421C0478691}"
ProjectSection(ProjectDependencies) = postProject
{50D1D52B-702A-49FE-B490-9104FC72598D} = {50D1D52B-702A-49FE-B490-9104FC72598D}
EndProjectSection EndProjectSection
EndProject EndProject
Global Global
@ -41,6 +46,10 @@ Global
{32CF83E0-D2E0-4E43-8F7B-72BD0AB64647}.Debug.Build.0 = Debug|Win32 {32CF83E0-D2E0-4E43-8F7B-72BD0AB64647}.Debug.Build.0 = Debug|Win32
{32CF83E0-D2E0-4E43-8F7B-72BD0AB64647}.Release.ActiveCfg = Release|Win32 {32CF83E0-D2E0-4E43-8F7B-72BD0AB64647}.Release.ActiveCfg = Release|Win32
{32CF83E0-D2E0-4E43-8F7B-72BD0AB64647}.Release.Build.0 = Release|Win32 {32CF83E0-D2E0-4E43-8F7B-72BD0AB64647}.Release.Build.0 = Release|Win32
{182006F3-188F-466E-89FE-8421C0478691}.Debug.ActiveCfg = Debug|Win32
{182006F3-188F-466E-89FE-8421C0478691}.Debug.Build.0 = Debug|Win32
{182006F3-188F-466E-89FE-8421C0478691}.Release.ActiveCfg = Release|Win32
{182006F3-188F-466E-89FE-8421C0478691}.Release.Build.0 = Release|Win32
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection EndGlobalSection

Binary file not shown.

170
win32/NormDll.vcproj Normal file
View File

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="NormDll"
ProjectGUID="{182006F3-188F-466E-89FE-8421C0478691}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\common,..\protolib\common,..\protolib\win32"
PreprocessorDefinitions="NORM_USE_DLL;NORM_API_BUILD;_DEBUG;PROTO_DEBUG;HAVE_IPV6;HAVE_ASSERT;WIN32"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="3"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/Norm.dll"
LinkIncremental="2"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/NormDll.pdb"
SubSystem="2"
ImportLibrary="$(OutDir)/Norm.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\common,..\protolib\common,..\protolib\win32"
PreprocessorDefinitions="NORM_USE_DLL;NORM_API_BUILD;NDEBUG;PROTO_DEBUG;HAVE_IPV6;HAVE_ASSERT;WIN32"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib iphlpapi.lib"
OutputFile="$(OutDir)/Norm.dll"
LinkIncremental="1"
GenerateDebugInformation="TRUE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/Norm.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath="..\common\galois.cpp">
</File>
<File
RelativePath="..\common\normApi.cpp">
</File>
<File
RelativePath="..\common\normEncoder.cpp">
</File>
<File
RelativePath="..\common\normFile.cpp">
</File>
<File
RelativePath="..\common\normMessage.cpp">
</File>
<File
RelativePath="..\common\normNode.cpp">
</File>
<File
RelativePath="..\common\normObject.cpp">
</File>
<File
RelativePath="..\common\normSegment.cpp">
</File>
<File
RelativePath="..\common\normSession.cpp">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
<File
RelativePath=".\NormDll3.h">
</File>
<File
RelativePath=".\stdafx.h">
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
</Filter>
<File
RelativePath=".\ReadMe.txt">
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -29,7 +29,7 @@
UsePrecompiledHeader="2" UsePrecompiledHeader="2"
PrecompiledHeaderFile=".\Debug/NormLib.pch" PrecompiledHeaderFile=".\Debug/NormLib.pch"
AssemblerListingLocation=".\Debug/" AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/" ObjectFile="Norm.lib"
ProgramDataBaseFileName=".\Debug/" ProgramDataBaseFileName=".\Debug/"
WarningLevel="3" WarningLevel="3"
SuppressStartupBanner="TRUE" SuppressStartupBanner="TRUE"
@ -38,7 +38,7 @@
Name="VCCustomBuildTool"/> Name="VCCustomBuildTool"/>
<Tool <Tool
Name="VCLibrarianTool" Name="VCLibrarianTool"
OutputFile=".\Debug\NormLib.lib" OutputFile="$(OutDir)/NormLib.lib"
SuppressStartupBanner="TRUE"/> SuppressStartupBanner="TRUE"/>
<Tool <Tool
Name="VCMIDLTool"/> Name="VCMIDLTool"/>
@ -81,7 +81,6 @@
UsePrecompiledHeader="2" UsePrecompiledHeader="2"
PrecompiledHeaderFile=".\Release/NormLib.pch" PrecompiledHeaderFile=".\Release/NormLib.pch"
AssemblerListingLocation=".\Release/" AssemblerListingLocation=".\Release/"
ObjectFile=".\Release/"
ProgramDataBaseFileName=".\Release/" ProgramDataBaseFileName=".\Release/"
WarningLevel="3" WarningLevel="3"
SuppressStartupBanner="TRUE" SuppressStartupBanner="TRUE"
@ -90,7 +89,7 @@
Name="VCCustomBuildTool"/> Name="VCCustomBuildTool"/>
<Tool <Tool
Name="VCLibrarianTool" Name="VCLibrarianTool"
OutputFile=".\Release\NormLib.lib" OutputFile="$(OutDir)/NormLib.lib"
SuppressStartupBanner="TRUE"/> SuppressStartupBanner="TRUE"/>
<Tool <Tool
Name="VCMIDLTool"/> Name="VCMIDLTool"/>

View File

@ -4,6 +4,7 @@
Version="7.10" Version="7.10"
Name="normTest" Name="normTest"
ProjectGUID="{32CF83E0-D2E0-4E43-8F7B-72BD0AB64647}" ProjectGUID="{32CF83E0-D2E0-4E43-8F7B-72BD0AB64647}"
RootNamespace="normTest"
SccProjectName="" SccProjectName=""
SccLocalPath=""> SccLocalPath="">
<Platforms> <Platforms>
@ -23,7 +24,7 @@
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="0" Optimization="0"
AdditionalIncludeDirectories="..\common,..\protolib\common,..\protolib\win32" AdditionalIncludeDirectories="..\common,..\protolib\common,..\protolib\win32"
PreprocessorDefinitions="_DEBUG;PROTO_DEBUG;HAVE_IPV6;HAVE_ASSERT;WIN32;_CONSOLE" PreprocessorDefinitions="NORM_USE_DLL, PROTO_DEBUG, WIN32"
BasicRuntimeChecks="3" BasicRuntimeChecks="3"
RuntimeLibrary="3" RuntimeLibrary="3"
BufferSecurityCheck="TRUE" BufferSecurityCheck="TRUE"
@ -40,10 +41,11 @@
Name="VCCustomBuildTool"/> Name="VCCustomBuildTool"/>
<Tool <Tool
Name="VCLinkerTool" Name="VCLinkerTool"
AdditionalDependencies="iphlpapi.lib ws2_32.lib odbc32.lib odbccp32.lib" AdditionalDependencies="iphlpapi.lib ws2_32.lib odbc32.lib odbccp32.lib Norm.dll"
OutputFile=".\Debug/normTest.exe" OutputFile=".\Debug/normTest.exe"
LinkIncremental="0" LinkIncremental="0"
SuppressStartupBanner="TRUE" SuppressStartupBanner="TRUE"
AdditionalLibraryDirectories="./"
GenerateDebugInformation="TRUE" GenerateDebugInformation="TRUE"
ProgramDatabaseFile=".\Debug/normTest.pdb" ProgramDatabaseFile=".\Debug/normTest.pdb"
SubSystem="1" SubSystem="1"
@ -85,8 +87,8 @@
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="2" Optimization="2"
InlineFunctionExpansion="1" InlineFunctionExpansion="1"
AdditionalIncludeDirectories="..\common,..\protolib\common,..\protolib\win32" AdditionalIncludeDirectories="..\common;..\protolib\common;..\protolib\win32;NormDll3"
PreprocessorDefinitions="NDEBUG;PROTO_DEBUG;HAVE_IPV6;HAVE_ASSERT;WIN32;_CONSOLE" PreprocessorDefinitions="NORM_USE_DLL, PROTO_DEBUG, WIN32, HAVE_ASSERT"
StringPooling="TRUE" StringPooling="TRUE"
RuntimeLibrary="2" RuntimeLibrary="2"
EnableFunctionLevelLinking="TRUE" EnableFunctionLevelLinking="TRUE"
@ -103,10 +105,12 @@
Name="VCCustomBuildTool"/> Name="VCCustomBuildTool"/>
<Tool <Tool
Name="VCLinkerTool" Name="VCLinkerTool"
IgnoreImportLibrary="FALSE"
AdditionalDependencies="iphlpapi.lib ws2_32.lib odbc32.lib odbccp32.lib" AdditionalDependencies="iphlpapi.lib ws2_32.lib odbc32.lib odbccp32.lib"
OutputFile=".\Release/normTest.exe" OutputFile=".\Release/normTest.exe"
LinkIncremental="1" LinkIncremental="1"
SuppressStartupBanner="TRUE" SuppressStartupBanner="TRUE"
AdditionalLibraryDirectories=""
ProgramDatabaseFile=".\Release/normTest.pdb" ProgramDatabaseFile=".\Release/normTest.pdb"
SubSystem="1" SubSystem="1"
TargetMachine="1"/> TargetMachine="1"/>
@ -144,23 +148,6 @@
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"> Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
<File <File
RelativePath="..\common\normTest.cpp"> RelativePath="..\common\normTest.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
BasicRuntimeChecks="3"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="2"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""/>
</FileConfiguration>
</File> </File>
</Filter> </Filter>
<Filter <Filter