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="AUTHOR" CONTENT="Robert Adamson">
<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="KEYWORDS" CONTENT="norm object value application function ">
<STYLE>
@ -52,7 +52,7 @@
<TD WIDTH=371>
<P ALIGN=LEFT STYLE="margin-left: 0.86in; margin-top: 0.17in; font-style: normal">
<FONT FACE="Helvetica, sans-serif"><FONT SIZE=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>
</TR>
</TABLE>
@ -60,7 +60,9 @@
<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
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
general purpose reliable data transport for applications wishing to
use Internet Protocol (IP) Multicast services for group data
@ -102,8 +104,6 @@ communication needs.</P>
of Contents">Table
of Contents</A></H1>
<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.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>
@ -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-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="#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="#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>
@ -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="#NormSetTOS()">NormSetTOS()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetLoopback()">NormSetLoopback()</A></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B><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="#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>
@ -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="#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="#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="#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>
@ -234,7 +239,8 @@ protocol thread notifies the application of various protocol events
through a thread-safe event dispatching mechanism and API calls are
provided to allow the application to control NORM operation. (<I>Note:
API mechanisms for lower-level, non-threaded control and execution
of the NORM protocol engine 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
can be roughly summarized with the following categories of functions:</P>
<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
initialize, as needed, at least one instance of the NORM API. Then
one or more NORM transport sessions (where a “session”
corresponds to data exchanges on a given multicast group and host
port number) may be created and controlled. Applications may
participate as senders and/or receivers within a NORM session. NORM
senders transmit data to the session destination address (usually an
IP multicast group) while receivers are notified of incoming data.
The NORM API provides and event notification scheme to notify the
application of significant sender and receiver events. There are
also a number support functions provided for the application to
control and monitor its participation within a NORM transport
session.</P>
corresponds to data exchanges on a given multicast group (or unicast
address) and host port number) may be created and controlled.
Applications may participate as senders and/or receivers within a
NORM session. NORM senders transmit data to the session destination
address (usually an IP multicast group) while receivers are notified
of incoming data. The NORM API provides and event notification
scheme to notify the application of significant sender and receiver
events. There are also a number support functions provided for the
application to control and monitor its participation within a NORM
transport session.</P>
<H2 CLASS="western"><A NAME="API Initialization">API Initialization</A></H2>
<P CLASS="western" STYLE="font-style: normal">The NORM API requires
that an application explicitly create at least one instance of the
@ -271,9 +277,9 @@ mechanism.
single thread should access the <FONT FACE="Courier"><A HREF="#NormGetNextEvent()">NormGetNextEvent()</A></FONT>
API call for a given <FONT FACE="Courier">NormInstance</FONT>. This
function serves as the conduit for delivering NORM protocol engine
events to the application. While a NORM application can be designed
to be single-threaded, even with multiple active <I>NormSessions</I>,
multiple API instances can be created (see <FONT FACE="Courier"><A HREF="#NormCreateInstance()">NormCreateInstance()</A></FONT>)
events to the application. A NORM application can be designed to be
single-threaded, even with multiple active <I>NormSessions</I>, but
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
and controlling participation in multiple <I>NormSessions</I> from
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
an application is participating as a sender, it may enqueue data
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
as receivers will be notified via the NORM API's event dispatching
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
the compile time macro <FONT FACE="Courier"><I>WINVER=0x0400</I></FONT>
defined. This is because the version of the IP Helper API library
(<I>iphlpapi.lib</I>) used y Protolib (and hence NORM) for this
system doesn't support some of the functions defined for this
(<I>iphlpapi.lib</I>) used by <I>Protolib</I> (and hence NORM) for
this system doesn't support some of the functions defined for this
library. This may be related to IPv6 support issues so it may be
possible that the Protolib build could be tweaked to provide a single
binary executable suitable for IPv4 operation only across a large
range of Windows platforms.</P>
possible that the <I>Protolib</I> build could be tweaked to provide a
single binary executable suitable for IPv4 operation only across a
large range of Windows platforms.</P>
<H1 CLASS="western"><A NAME="API Reference">API Reference</A></H1>
<P CLASS="western" STYLE="font-style: normal">This section provides a
reference to the NORM API variable types, constants and functions.</P>
@ -702,7 +708,7 @@ description).
</P>
<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>
consist of the following enumeration:</P>
type consists of the following enumeration:</P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>enum
<A HREF="#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
@ -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>
<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>
consist of the following enumeration:</P>
type consists of the following enumeration:</P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>enum
<A HREF="#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
@ -802,6 +808,57 @@ has retained (see <FONT FACE="Courier"><A HREF="#NormObjectRetain()">NormObjectR
<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="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>
<H4 CLASS="western">Synopsis</H4>
<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
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>
events if undesired)).</P>
events if not needed by the application)).</P>
<H3 CLASS="functionheading-western"><A NAME="NormGetDescriptor()">NormGetDescriptor()</A></H3>
<H4 CLASS="western">Synopsis</H4>
<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 returned.</P>
<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>
<H4 CLASS="western">Synopsis</H4>
<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>
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function creates a
NORM reliable multicast session (<I>NormSession</I>) using the
address parameters provided. While session state is allocated and
initialized, active session participation does not begin until a call
is made to <FONT FACE="Courier"><A HREF="#NormStartSender()">NormStartSender()</A></FONT> and/or
<FONT FACE="Courier"><A HREF="#NormStartReceiver()">NormStartReceiver()</A></FONT> to join the specified
multicast group (if applicable) and start protocol operation. The
following parameters are required in this function call:</P>
NORM protocol session (<I>NormSession</I>) using the address
(multicast or unicast) parameters provided. While session state is
allocated and initialized, active session participation does not
begin until a call is made to <FONT FACE="Courier"><A HREF="#NormStartSender()">NormStartSender()</A></FONT>
and/or <FONT FACE="Courier"><A HREF="#NormStartReceiver()">NormStartReceiver()</A></FONT> to join the
specified multicast group (if applicable) and start protocol
operation. The following parameters are required in this function
call:</P>
<TABLE WIDTH=590 BORDER=0 CELLPADDING=7 CELLSPACING=0>
<COL WIDTH=101>
<COL WIDTH=461>
<TR VALIGN=TOP>
<TD WIDTH=101>
<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 WIDTH=461>
<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>
<TD WIDTH=101>
<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 WIDTH=461>
<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>
<TD WIDTH=101>
<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 WIDTH=461>
<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>
<TD WIDTH=101>
<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 WIDTH=461>
<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>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void
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
state);</FONT></FONT></P>
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
= true);</FONT></FONT></P>
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function allows
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>.
When the <FONT FACE="Courier"><U>state</U></FONT> parameter is set
to <FONT FACE="Courier"><I>true</I></FONT>:</P>
<OL>
<LI><P CLASS="western" STYLE="font-style: normal">Reuse of the
<I>NormSession</I> port number is enabled, and</P>
<LI><P CLASS="western" STYLE="font-style: normal">the underlying
socket is also bound (see the <FONT FACE="Courier">bind()</FONT>
system call) to the <I>NormSession</I> destination address instead
of the default behavior of binding to INADDR_ANY.
</P>
</OL>
<P CLASS="western" STYLE="font-style: normal">The default binding to
INADDR_ANY (<FONT FACE="Courier"><U>state</U></FONT> equals <FONT FACE="Courier"><I>false</I></FONT>)
allows the <I>NormSession</I> receive socket to receive any multicast
or unicast transmissions to the given port number. This allows a
When the <FONT FACE="Courier"><U>enable</U></FONT> parameter is set
to <FONT FACE="Courier"><I>true</I></FONT>, reuse of the <I>NormSession</I>
port number is enabled, and, if the <FONT FACE="Courier"><U>bindToSessionAddr</U></FONT>
is also set to <FONT FACE="Courier"><I>true</I></FONT> (default), the
underlying socket is also bound (see the <FONT FACE="Courier">bind()</FONT>
system call) to the <I>NormSession</I> destination address instead of
the default behavior of binding to INADDR_ANY.
</P>
<P CLASS="western" STYLE="font-style: normal">When this call is not
made, the default binding to IP address INADDR_ANY (equivalent to
when this call is made and <FONT FACE="Courier"><U>bindToSessionAddr</U></FONT>
is set to <FONT FACE="Courier"><I>false</I></FONT>) allows the
<I>NormSession</I> receive socket to receive <I>any</I> multicast or
unicast transmissions to the session port number provided in the call
to <FONT FACE="Courier"><A HREF="#NormCreateSession()">NormCreateSession()</A></FONT>. This allows a
NORM receiver to receive from senders sending to a multicast session
address or the receiver's unicast address. Enabling port reuse and
binding the session destination address allows multiple NORM sessions
@ -1531,7 +1597,16 @@ created.</P>
<H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">This function has no
return values.</P>
<H2 CLASS="western"><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>
<H4 CLASS="western">Synopsis</H4>
<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>
<P CLASS="western" STYLE="font-style: normal">This function has no
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>
<H4 CLASS="western">Synopsis</H4>
<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
reliability does not provide explicit flow control, there is some
degree of implicit flow control in limiting writing new data to the
stream against pending repairs.
</P>
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormEvent">NormEvent</A></FONT>
NORM_TX_QUEUE_VACANCY is posted with its <I><A HREF="#NormEvent">NormEvent</A>::object</I>
field set to a valid sender stream <FONT FACE="Courier"><A HREF="#NormObjectHandle">NormObjectHandle</A></FONT>
to indicate when the stream is ready for writing via this function.
Note that, after this event type is posted, the application <I>must</I>
make a call to <FONT FACE="Courier"><A HREF="#NormStreamWrite()">NormStreamWrite()</A></FONT> with a
non-zero <FONT FACE="Courier"><U>numBytes</U></FONT> value before
addition NORM_TX_QUEUE_VACANCY events are posted for the given
<FONT FACE="Courier"><U>streamHandle</U></FONT>.</P>
stream against pending repairs. Other flow control strategies are
possible using the <FONT FACE="Courier"><A HREF="#NormSetWatermark()">NormSetWatermark()</A></FONT>
function.</P>
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier">NormEvents
</FONT><FONT FACE="Courier"><I>NORM_TX_QUEUE_EMPTY</I></FONT> and
<FONT FACE="Courier"><I>NORM_TX_QUEUE_VACANCY</I></FONT> are posted
with the <I><A HREF="#NormEvent">NormEvent</A>::object</I> field set to a valid sender stream
<FONT FACE="Courier"><A HREF="#NormObjectHandle">NormObjectHandle</A></FONT> to indicate when the
stream is ready for writing via this function. Note that the
<FONT FACE="Courier"><I>NORM_TX_QUEUE_VACANCY </I></FONT>event type
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>
<P CLASS="western" STYLE="font-style: normal">This function returns
the number of bytes of data successfully enqueued for NORM stream
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>
<H3 CLASS="functionheading-western"><A NAME="NormStreamFlush()">NormStreamFlush()</A></H3>
<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
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
=============
- 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 "normSession.h"
@ -8,15 +9,23 @@
#endif // WIN32
// const defs
extern NORM_API_LINKAGE
const NormInstanceHandle NORM_INSTANCE_INVALID = ((NormInstanceHandle)0);
extern NORM_API_LINKAGE
const NormSessionHandle NORM_SESSION_INVALID = ((NormSessionHandle)0);
extern NORM_API_LINKAGE
const NormNodeHandle NORM_NODE_INVALID = ((NormNodeHandle)0);
extern NORM_API_LINKAGE
const NormNodeId NORM_NODE_NONE = ((NormNodeId)0x00000000);
extern NORM_API_LINKAGE
const NormNodeId NORM_NODE_ANY = ((NormNodeId)0xffffffff);
extern NORM_API_LINKAGE
const NormObjectHandle NORM_OBJECT_INVALID = ((NormObjectHandle)0);
extern NORM_API_LINKAGE
const NormDescriptor NORM_DESCRIPTOR_INVALID = ProtoDispatcher::INVALID_DESCRIPTOR;
/** The "NormInstance" class is a C++ helper class that keeps
* state for an instance of the NORM API. It acts as a
* "go between" the API's procedural function calls and
@ -37,6 +46,24 @@ class NormInstance : public NormController
bool Startup(bool priorityBoost = false);
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 GetNextEvent(NormEvent* theEvent);
bool SetCacheDirectory(const char* cachePath);
@ -63,7 +90,6 @@ class NormInstance : public NormController
NormSession* session = (NormSession*)sessionHandle;
NormInstance* theInstance = static_cast<NormInstance*>(session->GetSessionMgr().GetController());
return theInstance;
//return static_cast<NormInstance*>(session->GetSessionMgr().GetController());
}
static NormInstance* GetInstanceFromNode(NormNodeHandle nodeHandle)
{
@ -126,6 +152,7 @@ class NormInstance : public NormController
}; // end class NormInstance::Notification
ProtoDispatcher dispatcher;
bool priority_boost;
NormSessionMgr session_mgr;
private:
@ -165,7 +192,8 @@ void NormInstance::Notification::Queue::Destroy()
////////////////////////////////////////////////////
// NormInstance implementation
NormInstance::NormInstance()
: session_mgr(static_cast<ProtoTimerMgr&>(dispatcher),
: priority_boost(false),
session_mgr(static_cast<ProtoTimerMgr&>(dispatcher),
static_cast<ProtoSocket::Notifier&>(dispatcher)),
previous_notification(NULL), rx_cache_path(NULL)
{
@ -188,7 +216,7 @@ bool NormInstance::SetCacheDirectory(const char* cachePath)
bool result = false;
if (dispatcher.SuspendThread())
{
int length = strlen(cachePath);
size_t length = strlen(cachePath);
if (PROTO_PATH_DELIMITER != cachePath[length-1])
length += 2;
else
@ -481,6 +509,11 @@ bool NormInstance::GetNextEvent(NormEvent* theEvent)
bool NormInstance::WaitForEvent()
{
if (!dispatcher.IsThreaded())
{
DMSG(0, "NormInstance::WaitForEvent() warning: NORM thread not running!\n");
return false;
}
#ifdef WIN32
WaitForSingleObject(notify_event, INFINITE);
#else
@ -537,6 +570,7 @@ bool NormInstance::Startup(bool priorityBoost)
}
#endif // if/else WIN32/UNIX
// 2) Start thread
priority_boost = priorityBoost;
return dispatcher.StartThread(priorityBoost);
} // end NormInstance::Startup()
@ -637,6 +671,7 @@ unsigned long NormInstance::CountCompletedObjects(NormSession* session)
/** NORM API Initialization */
NORM_API_LINKAGE
NormInstanceHandle NormCreateInstance(bool priorityBoost)
{
NormInstance* normInstance = new NormInstance;
@ -650,11 +685,35 @@ NormInstanceHandle NormCreateInstance(bool priorityBoost)
return NORM_INSTANCE_INVALID;
} // end NormCreateInstance()
NORM_API_LINKAGE
void NormDestroyInstance(NormInstanceHandle instanceHandle)
{
delete ((NormInstance*)instanceHandle);
} // 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,
const char* cachePath)
{
@ -665,6 +724,7 @@ bool NormSetCacheDirectory(NormInstanceHandle instanceHandle,
return false;
} // end NormSetCacheDirectory()
NORM_API_LINKAGE
NormDescriptor NormGetDescriptor(NormInstanceHandle instanceHandle)
{
NormInstance* instance = (NormInstance*)instanceHandle;
@ -675,6 +735,7 @@ NormDescriptor NormGetDescriptor(NormInstanceHandle instanceHandle)
} // end NormGetDescriptor()
// (TBD) add a timeout option to this?
NORM_API_LINKAGE
bool NormGetNextEvent(NormInstanceHandle instanceHandle, NormEvent* theEvent)
{
bool result = false;
@ -682,7 +743,12 @@ bool NormGetNextEvent(NormInstanceHandle instanceHandle, NormEvent* theEvent)
if (instance)
{
if (instance->NotifyQueueIsEmpty()) //(TBD) perform this check???
instance->WaitForEvent();
{
if (!instance->WaitForEvent())
{
return false;
}
}
if (instance->dispatcher.SuspendThread())
{
result = instance->GetNextEvent(theEvent);
@ -695,6 +761,7 @@ bool NormGetNextEvent(NormInstanceHandle instanceHandle, NormEvent* theEvent)
/** NORM Session Creation and Control Functions */
NORM_API_LINKAGE
NormSessionHandle NormCreateSession(NormInstanceHandle instanceHandle,
const char* sessionAddr,
unsigned short sessionPort,
@ -711,6 +778,7 @@ NormSessionHandle NormCreateSession(NormInstanceHandle instanceHandle,
return NORM_SESSION_INVALID;
} // end NormCreateSession()
NORM_API_LINKAGE
void NormDestroySession(NormSessionHandle sessionHandle)
{
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
@ -729,6 +797,7 @@ void NormDestroySession(NormSessionHandle sessionHandle)
}
} // end NormDestroySession()
NORM_API_LINKAGE
void NormSetUserData(NormSessionHandle sessionHandle, const void* userData)
{
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
@ -743,6 +812,7 @@ void NormSetUserData(NormSessionHandle sessionHandle, const void* userData)
}
} // end NormSetUserData()
NORM_API_LINKAGE
const void* NormGetUserData(NormSessionHandle sessionHandle)
{
const void* userData = NULL;
@ -760,6 +830,7 @@ const void* NormGetUserData(NormSessionHandle sessionHandle)
return userData;
} // end NormGetUserData()
NORM_API_LINKAGE
NormNodeId NormGetLocalNodeId(NormSessionHandle sessionHandle)
{
NormSession* session = (NormSession*)sessionHandle;
@ -769,6 +840,7 @@ NormNodeId NormGetLocalNodeId(NormSessionHandle sessionHandle)
return NORM_NODE_NONE;
} // end NormGetLocalNodeId()
NORM_API_LINKAGE
void NormSetTxPort(NormSessionHandle sessionHandle,
unsigned short txPort)
{
@ -784,8 +856,10 @@ void NormSetTxPort(NormSessionHandle sessionHandle,
}
} // end NormSetTxPort()
NORM_API_LINKAGE
void NormSetRxPortReuse(NormSessionHandle sessionHandle,
bool state)
bool enable,
bool bindToSessionAddress)
{
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
if (NULL != instance)
@ -793,12 +867,13 @@ void NormSetRxPortReuse(NormSessionHandle sessionHandle,
if (instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
if (session) session->SetRxPortReuse(state);
if (session) session->SetRxPortReuse(enable, bindToSessionAddress);
instance->dispatcher.ResumeThread();
}
}
} // end NormSetTxPort()
NORM_API_LINKAGE
bool NormSetMulticastInterface(NormSessionHandle sessionHandle,
const char* interfaceName)
{
@ -817,6 +892,7 @@ bool NormSetMulticastInterface(NormSessionHandle sessionHandle,
return result;
} // end NormSetMulticastInterface()
NORM_API_LINKAGE
bool NormSetTTL(NormSessionHandle sessionHandle,
unsigned char ttl)
{
@ -835,6 +911,7 @@ bool NormSetTTL(NormSessionHandle sessionHandle,
return result;
} // end NormSetTTL()
NORM_API_LINKAGE
bool NormSetTOS(NormSessionHandle sessionHandle,
unsigned char tos)
{
@ -846,7 +923,7 @@ bool NormSetTOS(NormSessionHandle sessionHandle,
{
NormSession* session = (NormSession*)sessionHandle;
if (session)
result = session->SetTTL(tos);
result = session->SetTOS(tos);
instance->dispatcher.ResumeThread();
}
}
@ -855,6 +932,7 @@ bool NormSetTOS(NormSessionHandle sessionHandle,
/** Special test/debug support functions */
NORM_API_LINKAGE
bool NormSetLoopback(NormSessionHandle sessionHandle, bool state)
{
NormSession* session = (NormSession*)sessionHandle;
@ -864,18 +942,21 @@ bool NormSetLoopback(NormSessionHandle sessionHandle, bool state)
return false;
} // end NormSetLoopback()
NORM_API_LINKAGE
void NormSetMessageTrace(NormSessionHandle sessionHandle, bool state)
{
NormSession* session = (NormSession*)sessionHandle;
if (session) session->SetTrace(state);
} // end NormSetMessageTrace()
NORM_API_LINKAGE
void NormSetTxLoss(NormSessionHandle sessionHandle, double percent)
{
NormSession* session = (NormSession*)sessionHandle;
if (session) session->SetTxLoss(percent);
} // end NormSetTxLoss()
NORM_API_LINKAGE
void NormSetRxLoss(NormSessionHandle sessionHandle, double percent)
{
NormSession* session = (NormSession*)sessionHandle;
@ -885,6 +966,7 @@ void NormSetRxLoss(NormSessionHandle sessionHandle, double percent)
/** NORM Sender Functions */
NORM_API_LINKAGE
bool NormStartSender(NormSessionHandle sessionHandle,
NormSessionId sessionId,
unsigned long bufferSpace,
@ -906,6 +988,7 @@ bool NormStartSender(NormSessionHandle sessionHandle,
return result;
} // end NormStartSender()
NORM_API_LINKAGE
void NormStopSender(NormSessionHandle sessionHandle)
{
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
@ -917,6 +1000,17 @@ void NormStopSender(NormSessionHandle sessionHandle)
}
} // 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,
double bitsPerSecond)
{
@ -929,6 +1023,7 @@ void NormSetTransmitRate(NormSessionHandle sessionHandle,
}
} // end NormSetTransmitRate()
NORM_API_LINKAGE
bool NormSetTxSocketBuffer(NormSessionHandle sessionHandle,
unsigned int bufferSize)
{
@ -944,6 +1039,7 @@ bool NormSetTxSocketBuffer(NormSessionHandle sessionHandle,
return result;
} // end NormSetTxSocketBuffer()
NORM_API_LINKAGE
void NormSetCongestionControl(NormSessionHandle sessionHandle, bool enable)
{
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
@ -955,6 +1051,7 @@ void NormSetCongestionControl(NormSessionHandle sessionHandle, bool enable)
}
} // end NormSetCongestionControl()
NORM_API_LINKAGE
void NormSetTransmitRateBounds(NormSessionHandle sessionHandle,
double rateMin,
double rateMax)
@ -968,6 +1065,7 @@ void NormSetTransmitRateBounds(NormSessionHandle sessionHandle,
}
} // end NormSetTransmitRateBounds()
NORM_API_LINKAGE
void NormSetTransmitCacheBounds(NormSessionHandle sessionHandle,
NormSize sizeMax,
unsigned long countMin,
@ -983,6 +1081,7 @@ void NormSetTransmitCacheBounds(NormSessionHandle sessionHandle,
}
} // end NormSetTransmitCacheBounds()
NORM_API_LINKAGE
void NormSetAutoParity(NormSessionHandle sessionHandle, unsigned char autoParity)
{
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
@ -994,6 +1093,7 @@ void NormSetAutoParity(NormSessionHandle sessionHandle, unsigned char autoParity
}
} // end NormSetAutoParity()
NORM_API_LINKAGE
void NormSetGrttEstimate(NormSessionHandle sessionHandle,
double grttEstimate)
{
@ -1006,6 +1106,7 @@ void NormSetGrttEstimate(NormSessionHandle sessionHandle,
}
} // end NormSetGrttEstimate()
NORM_API_LINKAGE
void NormSetGrttMax(NormSessionHandle sessionHandle,
double grttMax)
{
@ -1018,6 +1119,7 @@ void NormSetGrttMax(NormSessionHandle sessionHandle,
}
} // end NormSetGrttMax()
NORM_API_LINKAGE
void NormSetGrttProbingMode(NormSessionHandle sessionHandle,
NormProbingMode probingMode)
{
@ -1025,12 +1127,12 @@ void NormSetGrttProbingMode(NormSessionHandle sessionHandle,
if (instance && instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
if (session)
session->SetGrttProbingMode((NormSession::ProbingMode)probingMode);
session->SetGrttProbingMode((NormSession::ProbingMode)probingMode);
instance->dispatcher.ResumeThread();
}
} // end NormSetGrttProbingMode()
NORM_API_LINKAGE
void NormSetGrttProbingInterval(NormSessionHandle sessionHandle,
double intervalMin,
double intervalMax)
@ -1044,6 +1146,34 @@ void NormSetGrttProbingInterval(NormSessionHandle sessionHandle,
}
} // 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,
const char* fileName,
const char* infoPtr,
@ -1064,6 +1194,7 @@ NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle,
return objectHandle;
} // end NormFileEnqueue()
NORM_API_LINKAGE
NormObjectHandle NormDataEnqueue(NormSessionHandle sessionHandle,
const char* dataPtr,
unsigned long dataLen,
@ -1085,6 +1216,7 @@ NormObjectHandle NormDataEnqueue(NormSessionHandle sessionHandle,
return objectHandle;
} // end NormDataEnqueue()
NORM_API_LINKAGE
NormObjectHandle NormStreamOpen(NormSessionHandle sessionHandle,
unsigned long bufferSize)
{
@ -1104,6 +1236,7 @@ NormObjectHandle NormStreamOpen(NormSessionHandle sessionHandle,
return objectHandle;
} // end NormStreamOpen()
NORM_API_LINKAGE
void NormStreamClose(NormObjectHandle streamHandle, bool graceful)
{
NormStreamObject* stream =
@ -1126,6 +1259,7 @@ void NormStreamClose(NormObjectHandle streamHandle, bool graceful)
}
} // end NormStreamClose()
NORM_API_LINKAGE
unsigned int NormStreamWrite(NormObjectHandle streamHandle,
const char* buffer,
unsigned int numBytes)
@ -1143,6 +1277,7 @@ unsigned int NormStreamWrite(NormObjectHandle streamHandle,
return result;
} // end NormStreamWrite()
NORM_API_LINKAGE
void NormStreamFlush(NormObjectHandle streamHandle,
bool eom,
NormFlushMode flushMode)
@ -1163,6 +1298,7 @@ void NormStreamFlush(NormObjectHandle streamHandle,
}
} // end NormStreamFlush()
NORM_API_LINKAGE
void NormStreamSetAutoFlush(NormObjectHandle streamHandle,
NormFlushMode flushMode)
{
@ -1172,6 +1308,7 @@ void NormStreamSetAutoFlush(NormObjectHandle streamHandle,
stream->SetFlushMode((NormStreamObject::FlushMode)flushMode);
} // end NormStreamSetAutoFlush()
NORM_API_LINKAGE
void NormStreamSetPushEnable(NormObjectHandle streamHandle, bool state)
{
NormStreamObject* stream =
@ -1179,6 +1316,7 @@ void NormStreamSetPushEnable(NormObjectHandle streamHandle, bool state)
if (stream) stream->SetPushMode(state);
} // end NormStreamSetPushEnable()
NORM_API_LINKAGE
bool NormStreamHasVacancy(NormObjectHandle streamHandle)
{
bool result = false;
@ -1194,6 +1332,7 @@ bool NormStreamHasVacancy(NormObjectHandle streamHandle)
return result;
} // end NormStreamHasVacancy()
NORM_API_LINKAGE
void NormStreamMarkEom(NormObjectHandle streamHandle)
{
NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle);
@ -1206,6 +1345,7 @@ void NormStreamMarkEom(NormObjectHandle streamHandle)
}
} // end NormStreamMarkEom()
NORM_API_LINKAGE
bool NormSetWatermark(NormSessionHandle sessionHandle,
NormObjectHandle objectHandle)
{
@ -1240,6 +1380,7 @@ bool NormSetWatermark(NormSessionHandle sessionHandle,
return result;
} // end NormSetWatermark()
NORM_API_LINKAGE
bool NormAddAckingNode(NormSessionHandle sessionHandle,
NormNodeId nodeId)
{
@ -1255,6 +1396,7 @@ bool NormAddAckingNode(NormSessionHandle sessionHandle,
return result;
} // end NormAddAckingNode()
NORM_API_LINKAGE
void NormRemoveAckingNode(NormSessionHandle sessionHandle,
NormNodeId nodeId)
{
@ -1267,6 +1409,7 @@ void NormRemoveAckingNode(NormSessionHandle sessionHandle,
}
} // end NormRemoveAckingNode()
NORM_API_LINKAGE
NormAckingStatus NormGetAckingStatus(NormSessionHandle sessionHandle,
NormNodeId nodeId)
{
@ -1287,6 +1430,7 @@ NormAckingStatus NormGetAckingStatus(NormSessionHandle sessionHandle,
/** NORM Receiver Functions */
NORM_API_LINKAGE
bool NormStartReceiver(NormSessionHandle sessionHandle,
unsigned long bufferSpace)
{
@ -1301,6 +1445,7 @@ bool NormStartReceiver(NormSessionHandle sessionHandle,
return result;
} // end NormStartReceiver()
NORM_API_LINKAGE
void NormStopReceiver(NormSessionHandle sessionHandle)
{
@ -1313,6 +1458,7 @@ void NormStopReceiver(NormSessionHandle sessionHandle)
}
} // end NormStopReceiver()
NORM_API_LINKAGE
bool NormSetRxSocketBuffer(NormSessionHandle sessionHandle,
unsigned int bufferSize)
{
@ -1328,6 +1474,7 @@ bool NormSetRxSocketBuffer(NormSessionHandle sessionHandle,
return result;
} // end NormSetRxSocketBuffer()
NORM_API_LINKAGE
void NormSetSilentReceiver(NormSessionHandle sessionHandle,
bool silent)
{
@ -1335,6 +1482,7 @@ void NormSetSilentReceiver(NormSessionHandle sessionHandle,
if (session) session->ClientSetSilent(silent);
} // end NormSetSilentReceiver()
NORM_API_LINKAGE
void NormSetDefaultUnicastNack(NormSessionHandle sessionHandle,
bool unicastNacks)
{
@ -1342,6 +1490,7 @@ void NormSetDefaultUnicastNack(NormSessionHandle sessionHandle,
if (session) session->ClientSetUnicastNacks(unicastNacks);
} // end NormSetDefaultUnicastNack()
NORM_API_LINKAGE
void NormNodeSetUnicastNack(NormNodeHandle nodeHandle,
bool unicastNacks)
{
@ -1349,6 +1498,7 @@ void NormNodeSetUnicastNack(NormNodeHandle nodeHandle,
if (node) node->SetUnicastNacks(unicastNacks);
} // end NormNodeSetUnicastNack()
NORM_API_LINKAGE
void NormSetDefaultNackingMode(NormSessionHandle sessionHandle,
NormNackingMode nackingMode)
{
@ -1356,6 +1506,7 @@ void NormSetDefaultNackingMode(NormSessionHandle sessionHandle,
if (session) session->ClientSetDefaultNackingMode((NormObject::NackingMode)nackingMode);
} // end NormSetDefaultNackingMode()
NORM_API_LINKAGE
void NormNodeSetNackingMode(NormNodeHandle nodeHandle,
NormNackingMode nackingMode)
{
@ -1363,6 +1514,7 @@ void NormNodeSetNackingMode(NormNodeHandle nodeHandle,
if (node) node->SetDefaultNackingMode((NormObject::NackingMode)nackingMode);
} // end NormNodeSetNackingMode()
NORM_API_LINKAGE
void NormObjectSetNackingMode(NormObjectHandle objectHandle,
NormNackingMode nackingMode)
{
@ -1370,6 +1522,7 @@ void NormObjectSetNackingMode(NormObjectHandle objectHandle,
if (object) object->SetNackingMode((NormObject::NackingMode)nackingMode);
} // end NormObjectSetNackingMode()
NORM_API_LINKAGE
void NormSetDefaultRepairBoundary(NormSessionHandle sessionHandle,
NormRepairBoundary repairBoundary)
{
@ -1378,6 +1531,7 @@ void NormSetDefaultRepairBoundary(NormSessionHandle sessionHandle,
session->ClientSetDefaultRepairBoundary((NormServerNode::RepairBoundary)repairBoundary);
} // end NormSetDefaultRepairBoundary()
NORM_API_LINKAGE
void NormNodeSetRepairBoundary(NormNodeHandle nodeHandle,
NormRepairBoundary repairBoundary)
{
@ -1386,6 +1540,7 @@ void NormNodeSetRepairBoundary(NormNodeHandle nodeHandle,
node->SetRepairBoundary((NormServerNode::RepairBoundary)repairBoundary);
} // end NormNodeSetRepairBoundary()
NORM_API_LINKAGE
bool NormStreamRead(NormObjectHandle streamHandle,
char* buffer,
unsigned int* numBytes)
@ -1402,6 +1557,7 @@ bool NormStreamRead(NormObjectHandle streamHandle,
return result;
} // end NormStreamRead()
NORM_API_LINKAGE
bool NormStreamSeekMsgStart(NormObjectHandle streamHandle)
{
bool result = false;
@ -1418,6 +1574,7 @@ bool NormStreamSeekMsgStart(NormObjectHandle streamHandle)
} // end NormStreamSeekMsgStart()
NORM_API_LINKAGE
unsigned long NormStreamGetReadOffset(NormObjectHandle streamHandle)
{
NormStreamObject* stream = static_cast<NormStreamObject*>((NormObject*)streamHandle);
@ -1430,6 +1587,7 @@ unsigned long NormStreamGetReadOffset(NormObjectHandle streamHandle)
/** NORM Object Functions */
NORM_API_LINKAGE
NormObjectType NormObjectGetType(NormObjectHandle objectHandle)
{
if (NORM_OBJECT_INVALID != objectHandle)
@ -1438,16 +1596,19 @@ NormObjectType NormObjectGetType(NormObjectHandle objectHandle)
return NORM_OBJECT_NONE;
} // end NormObjectGetType()
NORM_API_LINKAGE
bool NormObjectHasInfo(NormObjectHandle objectHandle)
{
return ((NormObject*)objectHandle)->HasInfo();
} // end NormObjectHasInfo()
NORM_API_LINKAGE
unsigned short NormObjectGetInfoLength(NormObjectHandle objectHandle)
{
return ((NormObject*)objectHandle)->GetInfoLength();
} // end NormObjectGetInfoLength()
NORM_API_LINKAGE
unsigned short NormObjectGetInfo(NormObjectHandle objectHandle,
char* buffer,
unsigned short bufferLen)
@ -1468,11 +1629,13 @@ unsigned short NormObjectGetInfo(NormObjectHandle objectHandle,
return result;
} // end NormObjectGetInfo()
NORM_API_LINKAGE
NormSize NormObjectGetSize(NormObjectHandle objectHandle)
{
return ((NormSize)((NormObject*)objectHandle)->GetSize().GetOffset());
} // end NormObjectGetSize()
NORM_API_LINKAGE
NormSize NormObjectGetBytesPending(NormObjectHandle objectHandle)
{
NormSize bytesPending = 0;
@ -1488,6 +1651,7 @@ NormSize NormObjectGetBytesPending(NormObjectHandle objectHandle)
return bytesPending;
} // end NormObjectGetBytesPending()
NORM_API_LINKAGE
void NormObjectCancel(NormObjectHandle objectHandle)
{
if (NORM_OBJECT_INVALID != objectHandle)
@ -1507,6 +1671,7 @@ void NormObjectCancel(NormObjectHandle objectHandle)
}
} // end NormObjectCancel()
NORM_API_LINKAGE
void NormObjectRetain(NormObjectHandle objectHandle)
{
if (NORM_OBJECT_INVALID != objectHandle)
@ -1521,6 +1686,7 @@ void NormObjectRetain(NormObjectHandle objectHandle)
}
} // end NormRetainObject()
NORM_API_LINKAGE
void NormObjectRelease(NormObjectHandle objectHandle)
{
if (NORM_OBJECT_INVALID != objectHandle)
@ -1536,6 +1702,7 @@ void NormObjectRelease(NormObjectHandle objectHandle)
}
} // end NormObjectRelease()
NORM_API_LINKAGE
bool NormFileGetName(NormObjectHandle fileHandle,
char* nameBuffer,
unsigned int bufferLen)
@ -1554,6 +1721,7 @@ bool NormFileGetName(NormObjectHandle fileHandle,
return result;
} // end NormFileGetName()
NORM_API_LINKAGE
bool NormFileRename(NormObjectHandle fileHandle,
const char* fileName)
{
@ -1570,6 +1738,7 @@ bool NormFileRename(NormObjectHandle fileHandle,
return result;
} // end NormFileRename()
NORM_API_LINKAGE
const char*volatile NormDataAccessData(NormObjectHandle dataHandle)
{
NormDataObject* dataObj =
@ -1577,6 +1746,7 @@ const char*volatile NormDataAccessData(NormObjectHandle dataHandle)
return dataObj->GetData();
} // end NormDataAccessData()
NORM_API_LINKAGE
char* NormDataDetachData(NormObjectHandle dataHandle)
{
NormDataObject* dataObj =
@ -1584,6 +1754,7 @@ char* NormDataDetachData(NormObjectHandle dataHandle)
return dataObj->DetachData();
} // end NormDataDetachData()
NORM_API_LINKAGE
NormNodeHandle NormObjectGetSender(NormObjectHandle objectHandle)
{
return (NormNodeHandle)(((NormObject*)objectHandle)->GetServer());
@ -1592,6 +1763,7 @@ NormNodeHandle NormObjectGetSender(NormObjectHandle objectHandle)
/** NORM Node Functions */
NORM_API_LINKAGE
NormNodeId NormNodeGetId(NormNodeHandle nodeHandle)
{
NormNode* node = (NormNode*)nodeHandle;
@ -1601,6 +1773,7 @@ NormNodeId NormNodeGetId(NormNodeHandle nodeHandle)
return NORM_NODE_NONE;
} // end NormNodeGetId()
NORM_API_LINKAGE
bool NormNodeGetAddress(NormNodeHandle nodeHandle,
char* addrBuffer,
unsigned int* bufferLen,
@ -1632,6 +1805,7 @@ bool NormNodeGetAddress(NormNodeHandle nodeHandle,
return result;
} // end NormNodeGetId()
NORM_API_LINKAGE
void NormNodeRetain(NormNodeHandle nodeHandle)
{
if (NORM_NODE_INVALID != nodeHandle)
@ -1646,6 +1820,7 @@ void NormNodeRetain(NormNodeHandle nodeHandle)
}
} // end NormNodeRetain()
NORM_API_LINKAGE
void NormNodeRelease(NormNodeHandle nodeHandle)
{
if (NORM_NODE_INVALID != nodeHandle)
@ -1675,6 +1850,7 @@ void NormNodeRelease(NormNodeHandle nodeHandle)
// events with a "NormDispatchEvents()" call ...
//
NORM_API_LINKAGE
unsigned long NormCountCompletedObjects(NormSessionHandle sessionHandle)
{
unsigned long result = 0;

View File

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

View File

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

View File

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

View File

@ -39,9 +39,9 @@ class NormEncoder
{
// Members
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
unsigned char* genPoly; // Ptr to generator polynomial
unsigned char* gen_poly; // Ptr to generator polynomial
unsigned char* scratch; // scratch space for encoding
// Methods
@ -50,7 +50,8 @@ class NormEncoder
~NormEncoder();
bool Init(int numParity, int vectorSize);
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);
int NumParity() {return npar;}
int VectorSize() {return vector_size;}
@ -64,18 +65,18 @@ class NormDecoder
{
// Members
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
unsigned char* Lambda; // Erasure location polynomial ("2*npar" ints)
unsigned char** sVec; // Syndrome vectors (pointers to "npar" vectors)
unsigned char** oVec; // Omega vectors (pointers to "npar" vectors)
unsigned char* lambda; // Erasure location polynomial ("2*npar" ints)
unsigned char** s_vec; // Syndrome vectors (pointers to "npar" vectors)
unsigned char** o_vec; // Omega vectors (pointers to "npar" vectors)
unsigned char* scratch;
// Methods
public:
NormDecoder();
~NormDecoder();
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 VectorSize() {return vector_size;}
void Destroy();

View File

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

View File

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

View File

@ -23,6 +23,11 @@ const UINT8 NORM_PROTOCOL_VERSION = 1;
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
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
// NORM protocol. (Note that our Grtt quantization routines
// are good for the range of 1.0e-06 <= 1000.0)
const double NORM_GRTT_MIN = 0.001; // 1 msec
const double NORM_GRTT_MAX = 15.0; // 15 sec
const double NORM_RTT_MIN = 1.0e-06;
@ -225,8 +231,8 @@ class NormHeaderExtension
enum Type
{
INVALID = 0,
FTI = 1, // FEC Object Transmission Information (FTI) extension
CC_FEEDBACK = 2, // NORM-CC Feedback extension
FTI = 64, // FEC Object Transmission Information (FTI) extension
CC_FEEDBACK = 3, // NORM-CC Feedback extension
CC_RATE = 128 // NORM-CC Rate extension
};
@ -350,6 +356,8 @@ class NormMsg
char* AccessBuffer() {return ((char*)buffer);}
ProtoAddress& AccessAddress() {return addr;}
NormMsg* GetNext() {return next;}
protected:
// Common message header offsets
// All of our offsets reflect their offset based on the field size!
@ -400,8 +408,8 @@ class NormObjectMsg : public NormMsg
FLAG_INFO = 0x04,
FLAG_UNRELIABLE = 0x08,
FLAG_FILE = 0x10,
FLAG_STREAM = 0x20,
FLAG_MSG_START = 0x40
FLAG_STREAM = 0x20
//FLAG_MSG_START = 0x40 deprecated
};
UINT16 GetInstanceId() const
{
@ -632,6 +640,7 @@ class NormDataMsg : public NormObjectMsg
// Some static helper routines for reading/writing embedded payload length/offsets
static UINT16 GetStreamPayloadHeaderLength() {return (PAYLOAD_DATA_OFFSET);}
/* Payload flags have deprecated in the revised NORM spec
enum PayloadFlag
{
FLAG_STREAM_END = 0x01,
@ -649,6 +658,11 @@ class NormDataMsg : public NormObjectMsg
static void SetStreamPayloadFlag(char* payload, PayloadFlag 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)
{
@ -660,6 +674,12 @@ class NormDataMsg : public NormObjectMsg
UINT32 temp32 = htonl(offset);
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)
{
UINT16 temp16;
@ -685,11 +705,11 @@ class NormDataMsg : public NormObjectMsg
};
enum
{
PAYLOAD_FLAGS_OFFSET = 0,
PAYLOAD_RESERVED_OFFSET = PAYLOAD_FLAGS_OFFSET+1, // this is not in the NORM spec!
PAYLOAD_LENGTH_OFFSET = PAYLOAD_RESERVED_OFFSET+1,
PAYLOAD_OFFSET_OFFSET = PAYLOAD_LENGTH_OFFSET+2,
PAYLOAD_DATA_OFFSET = PAYLOAD_OFFSET_OFFSET+4
//PAYLOAD_FLAGS_OFFSET = 0, // deprecated
PAYLOAD_MSG_START_OFFSET = 0,
PAYLOAD_LENGTH_OFFSET = PAYLOAD_MSG_START_OFFSET+2,
PAYLOAD_OFFSET_OFFSET = PAYLOAD_LENGTH_OFFSET+2,
PAYLOAD_DATA_OFFSET = PAYLOAD_OFFSET_OFFSET+4
};
}; // end class NormDataMsg
@ -1589,6 +1609,7 @@ class NormMessageQueue
void Remove(NormMsg* msg);
NormMsg* RemoveHead();
NormMsg* RemoveTail();
NormMsg* GetHead() {return head;}
bool IsEmpty() {return ((NormMsg*)NULL == head);}
private:

View File

@ -160,9 +160,10 @@ bool NormServerNode::AllocateBuffers(UINT16 segmentSize,
// 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
// into play when NORM would be "buffer constrained"
// (TBD) perhaps we should keep more "block state" than we can even buffer parity for ???
// (this would reduce requests for full block retransmissions when resource contrained)
double bufferFactor = 0.0;
// (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 constrained)
// (this would correspond to "bufferFactor < 0.0"
double bufferFactor = 0.0; // (TBD) let app control "bufferFactor"???
unsigned long segPerBlock =
(unsigned long) ((bufferFactor * (double)numData) +
((1.0 - bufferFactor) * (double)numParity) + 0.5);
@ -206,7 +207,8 @@ bool NormServerNode::AllocateBuffers(UINT16 segmentSize,
memset(retrieval_pool, 0, numData*sizeof(char*));
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)
{
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;
ndata = numData;
nparity = numParity;
IncrementResyncCount();
return true;
} // end NormServerNode::AllocateBuffers()
@ -326,6 +329,7 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime,
static_cast<NormStreamObject*>(obj)->Prune(blockId, true);
}
// 3) (TBD) Go ahead and discard any invalidated objects
// (those listed with id's > objectId)
// (although they will eventually get discarded anyway)
break;
}
@ -391,7 +395,6 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime,
double backoffFactor = backoff_factor;
backoffFactor = MAX(backoffFactor, 4.0);
maxBackoff = grtt_estimate*backoffFactor;
}
double backoffTime = (maxBackoff > 0.0) ?
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 "
// "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;
@ -491,7 +494,7 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime,
case NormCmdMsg::REPAIR_ADV:
{
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() &&
cc_timer.GetRepeatCount())
{
@ -507,6 +510,7 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime,
}
if (repair_timer.IsActive() && repair_timer.GetRepeatCount())
{
// (TBD) pay attention to the NORM_REPAIR_ADV_LIMIT flag
HandleRepairContent(repairAdv.GetRepairContent(),
repairAdv.GetRepairContentLength());
}
@ -522,7 +526,7 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime,
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))
{
// 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,
rtt_estimate,
LossEstimate());
// This increases our chance of being suppressed
// (but is it a good idea?)
localRate = MAX(localRate, cc_rate);
bool hasRtt = (0 != (ccFlags & NormCC::RTT));
@ -562,7 +568,9 @@ void NormServerNode::HandleCCFeedback(UINT8 ccFlags, double ccRate)
if (suppressed)
{
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);
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 or via NORM_CMD(REPAIR_ADV) messages received from the server.
// 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)
{
// Parse NACK and incorporate into repair state masks
@ -851,7 +860,8 @@ char* NormServerNode::GetFreeSegment(NormObjectId objectId, NormBlockId blockId)
break;
}
}
return segment_pool.Get();
char* result = segment_pool.Get();
return result;
} // end NormServerNode::GetFreeSegment()
void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg)
@ -1478,7 +1488,7 @@ bool NormServerNode::OnRepairTimeout(ProtoTimer& /*theTimer*/)
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",
LocalNodeId(), NormUnquantizeRate(ext.GetCCRate()) * (8.0/1000.0),
LocalNodeId(), 8.0e-03*NormUnquantizeRate(ext.GetCCRate()),
rtt_estimate, ccLoss, nominal_packet_size, slow_start);
ext.SetCCSequence(cc_sequence);
// 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)
{
recv_accumulator += msgSize;
double interval = (double)(currentTime.tv_sec - 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);
else
interval -= 1.0e-06*(double)(prev_update_time.tv_usec - currentTime.tv_usec);
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
// (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)
{
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
double minInterval = 4.0 * ((double)nominal_packet_size) / recv_rate;
// Make sure we've allowed sufficient time for a measurement at low rates
double minInterval = 4.0 * ((double)(MAX(nominal_packet_size, segment_size)))/ recv_rate;
if (measurementInterval < minInterval)
measurementInterval = minInterval;
}
@ -1701,46 +1709,28 @@ void NormServerNode::UpdateRecvRate(const struct timeval& currentTime, unsigned
{
recv_rate = currentRecvRate; //((double)(recv_accumulator)) / interval;
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
{
if (send_rate > 0.0)
/*if (send_rate > 0.0)
recv_rate = send_rate;
else
recv_rate = ((double)msgSize) / grtt_estimate;
recv_rate = ((double)msgSize) / grtt_estimate;*/
recv_rate = 0.0;
prev_update_time = currentTime;
recv_accumulator = 0;
recv_accumulator = msgSize;
}
nominal_packet_size += 0.05 * (((double)msgSize) - nominal_packet_size);
} // end NormServerNode::UpdateRecvRate()
void NormServerNode::Activate()
void NormServerNode::Activate(bool isObjectMsg)
{
if (!activity_timer.IsActive())
{
@ -1749,7 +1739,7 @@ void NormServerNode::Activate()
server_active = false;
session.Notify(NormController::REMOTE_SERVER_ACTIVE, this, NULL);
}
else
else if (isObjectMsg)
{
server_active = true;
}
@ -1797,9 +1787,19 @@ bool NormServerNode::OnActivityTimeout(ProtoTimer& /*theTimer*/)
max_pending_object, 0, 0);
}
else
RepairCheck(NormObject::TO_BLOCK, // (TBD) thru object???
{
RepairCheck(NormObject::THRU_OBJECT, // (TBD) thru object???
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;
return true;
@ -1851,11 +1851,11 @@ void NormServerNode::AttachCCFeedback(NormAckMsg& ack)
rtt_estimate, ccLoss);
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",
// LocalNodeId(), NormUnquantizeRate(ext.GetCCRate()) * (8.0/1000.0),
// rtt_estimate, ccLoss, nominal_packet_size, recv_rate*(8.0/1000.), slow_start);
//DMSG(0, "NormServerNode::AttachCCFeedback() node>%lu sending ACK rate:%lf kbps (rtt:%lf loss:%lf s:%lf recvRate:%lf) slow_start:%d\n",
// LocalNodeId(), 8.0e-03*NormUnquantizeRate(ext.GetCCRate()) ,
// rtt_estimate, ccLoss, nominal_packet_size, 8.0e-03*recv_rate, slow_start);
ext.SetCCSequence(cc_sequence);
} // end
} // end ormServerNode::AttachCCFeedback()
bool NormServerNode::OnCCTimeout(ProtoTimer& /*theTimer*/)
{
@ -1901,8 +1901,16 @@ bool NormServerNode::OnCCTimeout(ProtoTimer& /*theTimer*/)
//}
// Begin cc_timer "holdoff" phase
cc_timer.SetInterval(grtt_estimate*backoff_factor);
return true;
if (session.Address().IsMulticast())
{
cc_timer.SetInterval(grtt_estimate*backoff_factor);
return true;
}
else if (cc_timer.IsActive())
{
cc_timer.Deactivate();
}
break;
}
default:
@ -1935,7 +1943,7 @@ bool NormServerNode::OnAckTimeout(ProtoTimer& /*theTimer*/)
// Don't rate limit feedback messages
session.SendMessage(*ack);
session.ReturnMessageToPool(ack);
if (!is_clr && !is_plr)
if (!is_clr && !is_plr && session.Address().IsMulticast())
{
// Install cc feedback holdoff
if (cc_timer.IsActive()) cc_timer.Deactivate();
@ -1943,6 +1951,11 @@ bool NormServerNode::OnAckTimeout(ProtoTimer& /*theTimer*/)
session.ActivateTimer(cc_timer);
cc_timer.DecrementRepeatCount();
}
else if (cc_timer.IsActive())
{
cc_timer.Deactivate();
return false;
}
}
else
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -18,7 +18,7 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
: session_mgr(sessionMgr), notify_pending(false), tx_port(0),
tx_socket(&tx_socket_actual), tx_socket_actual(ProtoSocket::UDP),
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),
backoff_factor(DEFAULT_BACKOFF_FACTOR), is_server(false), instance_id(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),
acking_node_count(0), watermark_pending(false), advertise_repairs(false),
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_min(DEFAULT_GRTT_INTERVAL_MIN),
grtt_interval_max(DEFAULT_GRTT_INTERVAL_MAX),
@ -68,7 +68,7 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
grtt_quantized = NormQuantizeRtt(DEFAULT_GRTT_ESTIMATE);
grtt_measured = grtt_advertised = NormUnquantizeRtt(grtt_quantized);
gsize_measured = DEFAULT_GSIZE_ESTIMATE;
gsize_quantized = NormQuantizeGroupSize(DEFAULT_GSIZE_ESTIMATE);
gsize_advertised = NormUnquantizeGroupSize(gsize_quantized);
@ -114,7 +114,7 @@ bool NormSession::Open(const char* interfaceName)
Close();
return false;
}
const ProtoAddress* bindAddr = NULL;
if (rx_port_reuse)
{
// Enable port/addr reuse and bind socket to destination address
@ -124,6 +124,10 @@ bool NormSession::Open(const char* interfaceName)
Close();
return false;
}
}
const ProtoAddress* bindAddr = NULL;
if (rx_addr_bind)
{
#ifndef WIN32
if (address.IsMulticast()) // Win32 doesn't like to bind to multicast addr ???
bindAddr = &address;
@ -136,6 +140,13 @@ bool NormSession::Open(const char* interfaceName)
return false;
}
}
if (0 != tos)
{
if (!tx_socket->SetTOS(tos))
{
DMSG(0, "NormSession::Open() warning: tx_socket set tos error\n");
}
}
if (address.IsMulticast())
{
@ -238,12 +249,17 @@ bool NormSession::SetMulticastInterface(const char* interfaceName)
void NormSession::SetTxRateInternal(double txRate)
{
if (txRate < 0.0)
{
DMSG(0, "NormSession::SetTxRateInternal() invalid transmit rate!\n");
return;
}
if (tx_timer.IsActive())
{
if (txRate > 0.0)
{
double adjustInterval = (tx_rate/txRate) * tx_timer.GetTimeRemaining();
if (adjustInterval > 0.100)
if (adjustInterval > NORM_TICK_MIN)
{
tx_timer.SetInterval(adjustInterval);
tx_timer.Reschedule();
@ -254,30 +270,38 @@ void NormSession::SetTxRateInternal(double txRate)
tx_timer.Deactivate();
}
tx_rate = txRate;
}
else if ((0.0 == tx_rate) && IsOpen())
{
tx_rate = txRate;
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()
void NormSession::SetTxRateBounds(double rateMin, double rateMax)
@ -292,8 +316,11 @@ void NormSession::SetTxRateBounds(double rateMin, double rateMax)
rateMax = temp;
}
}
if (rateMin < 0.0)
tx_rate_min = -1.0;
else if (rateMin < 8.0)
tx_rate_min = 1.0; // one byte/second absolute minimum
else
tx_rate_min = rateMin/8.0; // convert to bytes/second
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
if (cc_enable)
{
if ((tx_rate_min >= 0.0) && (tx_rate < tx_rate_min))
tx_rate = tx_rate_min;
if ((tx_rate_max >= 0.0) && (tx_rate > tx_rate_max))
tx_rate = tx_rate_max;
SetTxRateInternal(tx_rate);
double txRate = tx_rate;
if ((tx_rate_min > 0.0) && (txRate < tx_rate_min))
txRate = tx_rate_min;
if ((tx_rate_max >= 0.0) && (txRate > tx_rate_max))
txRate = tx_rate_max;
if (txRate != tx_rate) SetTxRateInternal(txRate);
}
} // end NormSession::SetTxRateBounds()
@ -382,8 +410,6 @@ bool NormSession::StartServer(UINT16 instanceId,
instance_id = instanceId;
segment_size = segmentSize;
sent_rate = 0.0;
prev_update_time.tv_sec = prev_update_time.tv_usec = 0;
sent_accumulator = 0;
nominal_packet_size = (double)segmentSize;
data_active = false;
@ -394,14 +420,26 @@ bool NormSession::StartServer(UINT16 instanceId,
if (cc_enable)
{
tx_rate = segmentSize;
if ((tx_rate_min >= 0.0) && (tx_rate < tx_rate_min))
tx_rate = tx_rate_min;
double txRate;
if(tx_rate_min > 0.0)
{
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))
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;
probe_pending = false;
probe_data_check = false;
if (probe_reset)
{
probe_reset = false;
@ -428,6 +466,7 @@ void NormSession::StopServer()
NormObject* obj = tx_table.Find(tx_table.RangeLo());
ASSERT(obj);
tx_table.Remove(obj);
obj->Close();
obj->Release();
}
// Then destroy table
@ -680,7 +719,6 @@ void NormSession::Serve()
posted_tx_queue_empty = true;
Notify(NormController::TX_QUEUE_EMPTY, (NormServerNode*)NULL, obj);
// (TBD) Was session deleted?
//Serve();
return;
}
}
@ -702,13 +740,12 @@ void NormSession::Serve()
// No pending objects or positive acknowledgement request
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;
Notify(NormController::TX_QUEUE_EMPTY,
(NormServerNode*)NULL,
(NormObject*)NULL);
// (TBD) Was session deleted?
//Serve();
return;
}
if (flush_count < NORM_ROBUST_FACTOR)
@ -732,8 +769,6 @@ void NormSession::ServerSetWatermark(NormObjectId objectId,
NormBlockId blockId,
NormSegmentId segmentId)
{
TRACE("NormSession::ServerSetWatermark(%hu:%lu:%hu) ...\n",
(UINT16)objectId, (UINT32)blockId, (UINT16)segmentId);
watermark_pending = true;
watermark_active = false;
watermark_object_id = objectId;
@ -894,12 +929,14 @@ bool NormSession::ServerQueueWatermarkFlush()
}
else if (NULL != acking_node_tree.GetRoot())
{
ReturnMessageToPool(flush);
DMSG(4, "NormSession::ServeQueueWatermarkFlush() node>%lu watermark ack finished.\n");
Notify(NormController::TX_WATERMARK_COMPLETED, (NormServerNode*)NULL, (NormObject*)NULL);
return false;
}
else
{
ReturnMessageToPool(flush);
DMSG(2, "NormSession::ServeQueueWatermarkFlush() node>%lu no acking nodes specified?!\n");
return false;
}
@ -940,16 +977,21 @@ void NormSession::ServerQueueFlush()
}
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
if (ServerQueueSquelch(next_tx_object_id))
{
if (flush_count < NORM_ROBUST_FACTOR) flush_count++;
flush_timer.SetInterval(2*grtt_advertised);
flush_timer.SetInterval(4*grtt_advertised);
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;
}
NormCmdFlushMsg* flush = (NormCmdFlushMsg*)GetMessageFromPool();
@ -973,14 +1015,14 @@ void NormSession::ServerQueueFlush()
DMSG(0, "NormSession::ServerQueueFlush() node>%lu message_pool exhausted! (couldn't flush)\n",
LocalNodeId());
}
flush_timer.SetInterval(2*grtt_advertised);
flush_timer.SetInterval(4*grtt_advertised);
ActivateTimer(flush_timer);
} // end NormSession::ServerQueueFlush()
bool NormSession::OnFlushTimeout(ProtoTimer& /*theTimer*/)
{
flush_timer.Deactivate();
PromptServer();//Serve(); // (TBD) Change this to PromptServer() ??
PromptServer();
return false;
} // NormSession::OnFlushTimeout()
@ -1000,6 +1042,8 @@ void NormSession::QueueMessage(NormMsg* msg)
}
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))
{
tx_timer.SetInterval(0.0);
@ -1348,7 +1392,6 @@ void NormTrace(const struct timeval& currentTime,
const NormMsg& msg,
bool sent)
{
//if (DebugLevel() < 8) return; // (TBD) provide per-session trace on/off switch
static const char* MSG_NAME[] =
{
"INVALID",
@ -1421,15 +1464,18 @@ void NormTrace(const struct timeval& currentTime,
(UINT16)data.GetFecSymbolId());
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"
// as a "message length" header
UINT16 x;
memcpy(&x, data.GetPayloadData(), 2);
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) ");
}
break;
@ -1479,7 +1525,7 @@ void NormTrace(const struct timeval& currentTime,
if (NormHeaderExtension::CC_RATE == ext.GetType())
{
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;
}
}
@ -1620,7 +1666,7 @@ void NormSession::ClientHandleObjectMessage(const struct timeval& currentTime,
return;
}
}
theServer->Activate();
theServer->Activate(true);
theServer->UpdateLossEstimate(currentTime, msg.GetSequence());
theServer->SetAddress(msg.GetSource());
theServer->IncrementRecvTotal(msg.GetLength()); // for statistics only (TBD) #ifdef NORM_DEBUG
@ -1677,7 +1723,7 @@ void NormSession::ClientHandleCommand(const struct timeval& currentTime,
return;
}
}
theServer->Activate();
theServer->Activate(false);
theServer->UpdateLossEstimate(currentTime, cmd.GetSequence());
theServer->SetAddress(cmd.GetSource());
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)
{
grtt_response = true;
if ((clientRtt > grtt_measured) || !address.IsMulticast())
{
// Immediately incorporate bigger RTT's
grtt_decrease_delay_count = DEFAULT_GRTT_DECREASE_DELAY;
//grtt_measured = 0.25 * grtt_measured + 0.75 * clientRtt;
grtt_measured = 0.9 * grtt_measured + 0.1 * clientRtt;
grtt_measured = 0.25 * grtt_measured + 0.75 * clientRtt;
//grtt_measured = 0.9 * grtt_measured + 0.1 * clientRtt;
if (grtt_measured > grtt_max) grtt_measured = grtt_max;
UINT8 grttQuantizedOld = grtt_quantized;
double pktInterval = ((double)(44+segment_size))/tx_rate;
@ -1738,6 +1782,11 @@ void NormSession::ServerUpdateGrttEstimate(double clientRtt)
grtt_quantized = NormQuantizeRtt(grtt_measured);
// Calculate grtt_advertised since quantization rounds upward
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;
if (grttQuantizedOld != grtt_quantized)
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?
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();
bool savedRttStatus = next->HasRtt();
@ -2519,8 +2570,32 @@ void NormSession::ClientHandleNackMessage(const NormNackMsg& nack)
bool NormSession::ServerQueueSquelch(NormObjectId objectId)
{
// (TBD) if a squelch is already queued, update it if (objectId < squelch->objectId)
NormCmdSquelchMsg* squelch = (NormCmdSquelchMsg*)GetMessageFromPool();
// If a squelch is already queued, update it if (objectId < squelch->objectId)
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)
{
squelch->Init();
@ -2577,9 +2652,17 @@ bool NormSession::ServerQueueSquelch(NormObjectId objectId)
nextId++;
}
}
QueueMessage(squelch);
DMSG(4, "NormSession::ServerQueueSquelch() node>%lu server queued squelch ...\n",
LocalNodeId());
if (doEnqueue)
{
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;
}
else
@ -2637,6 +2720,8 @@ bool NormSession::ServerBuildRepairAdv(NormCmdRepairAdvMsg& cmd)
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;
}
}
@ -2669,7 +2754,13 @@ bool NormSession::ServerBuildRepairAdv(NormCmdRepairAdvMsg& cmd)
{
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;
currentObject->AppendRepairAdv(cmd);
}
@ -2684,6 +2775,7 @@ bool NormSession::ServerBuildRepairAdv(NormCmdRepairAdvMsg& cmd)
{
if (0 == cmd.PackRepairRequest(req))
DMSG(0, "NormSession::ServerBuildRepairAdv() warning: full msg\n");
// (TBD) set NORM_REPAIR_ADV_LIMIT flag in this case
}
return true;
} // end NormSession::ServerBuildRepairAdv()
@ -2716,18 +2808,20 @@ bool NormSession::OnRepairTimeout(ProtoTimer& /*theTimer*/)
}
else
{
//DMSG(6, "NormSession::OnRepairTimeout() node>%lu activating obj>%hu repairs ...\n",
// LocalNodeId(), (UINT16)objectId);
DMSG(6, "NormSession::OnRepairTimeout() node>%lu activating obj>%hu repairs ...\n",
LocalNodeId(), (UINT16)objectId);
if (obj->ActivateRepairs())
{
DMSG(6, "NormSession::OnRepairTimeout() node>%lu activated obj>%hu repairs ...\n",
LocalNodeId(), (UINT16)objectId);
DMSG(6, "NormSession::OnRepairTimeout() node>%lu activated obj>%hu repairs fd=%d...\n",
LocalNodeId(), (UINT16)objectId, static_cast<NormFileObject*>(obj)->file.fd);
if (!tx_pending_mask.Set(objectId))
DMSG(0, "NormSession::OnRepairTimeout() rx_pending_mask.Set(%hu) error (2)\n",
(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();
// BACKOFF related code
// Holdoff initiation of new repair cycle for one GRTT
@ -2800,6 +2894,8 @@ bool NormSession::OnTxTimeout(ProtoTimer& /*theTimer*/)
{
if (SendMessage(*msg))
{
if (tx_rate > 0.0)
tx_timer.SetInterval(msg->GetLength() / tx_rate);
if (advertise_repairs)
advertise_repairs = false;
else
@ -2840,10 +2936,7 @@ bool NormSession::OnTxTimeout(ProtoTimer& /*theTimer*/)
bool NormSession::SendMessage(NormMsg& msg)
{
struct timeval currentTime;
ProtoSystemTime(currentTime);
bool clientMsg = false;
bool isClientMsg = false;
bool isProbe = false;
// Fill in any last minute timestamps
@ -2860,9 +2953,15 @@ bool NormSession::SendMessage(NormMsg& msg)
switch (((NormCmdMsg&)msg).GetFlavor())
{
case NormCmdMsg::CC:
{
struct timeval currentTime;
ProtoSystemTime(currentTime);
((NormCmdCCMsg&)msg).SetSendTime(currentTime);
isProbe = true;
break;
}
case NormCmdMsg::SQUELCH:
break;
default:
break;
}
@ -2871,11 +2970,13 @@ bool NormSession::SendMessage(NormMsg& msg)
case NormMsg::NACK:
{
clientMsg = true;
isClientMsg = true;
NormNackMsg& nack = (NormNackMsg&)msg;
NormServerNode* theServer =
(NormServerNode*)server_tree.FindNodeById(nack.GetServerId());
ASSERT(theServer);
struct timeval currentTime;
ProtoSystemTime(currentTime);
struct timeval grttResponse;
theServer->CalculateGrttResponse(currentTime, grttResponse);
nack.SetGrttResponse(grttResponse);
@ -2884,12 +2985,14 @@ bool NormSession::SendMessage(NormMsg& msg)
case NormMsg::ACK:
{
clientMsg = true;
isClientMsg = true;
NormAckMsg& ack = (NormAckMsg&)msg;
NormServerNode* theServer =
(NormServerNode*)server_tree.FindNodeById(ack.GetServerId());
ASSERT(theServer);
struct timeval grttResponse;
struct timeval currentTime;
ProtoSystemTime(currentTime);
theServer->CalculateGrttResponse(currentTime, grttResponse);
ack.SetGrttResponse(grttResponse);
break;
@ -2905,7 +3008,7 @@ bool NormSession::SendMessage(NormMsg& msg)
bool result = true;
// Possibly drop some tx messages for testing purposes
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);
}
@ -2915,36 +3018,14 @@ bool NormSession::SendMessage(NormMsg& msg)
msg.GetDestination()))
{
// Separate send/recv tracing
if (trace) NormTrace(currentTime, LocalNodeId(), msg, true);
// 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)
if (trace)
{
double interval = (double)(currentTime.tv_sec - 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);
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;
struct timeval currentTime;
ProtoSystemTime(currentTime);
NormTrace(currentTime, LocalNodeId(), msg, true);
}
// To keep track of _actual_ sent rate
sent_accumulator += msgSize;
// Update nominal packet size
nominal_packet_size += 0.05 * (((double)msgSize) - nominal_packet_size);
}
@ -2954,19 +3035,36 @@ bool NormSession::SendMessage(NormMsg& msg)
result = false;
}
}
if (result && isProbe)
if (result)
{
probe_pending = false;
if (probe_reset)
if (isProbe)
{
probe_reset = false;
OnProbeTimeout(probe_timer); //we commented this out to give data a chance at low rates
// we may want to re-visit this, it might compromis high rate performance a little
ActivateTimer(probe_timer);
probe_pending = false;
probe_data_check = true;
if (probe_reset)
{
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()
void NormSession::SetGrttProbingInterval(double intervalMin, double intervalMax)
@ -2978,8 +3076,8 @@ void NormSession::SetGrttProbingInterval(double intervalMin, double intervalMax)
intervalMin = intervalMax;
intervalMax = temp;
}
if (intervalMin < 0.100) intervalMin = 0.100;
if (intervalMax < 0.100) intervalMax = 0.100;
if (intervalMin < NORM_TICK_MIN) intervalMin = NORM_TICK_MIN;
if (intervalMax < NORM_TICK_MIN) intervalMax = NORM_TICK_MIN;
grtt_interval_min = intervalMin;
grtt_interval_max = intervalMax;
if (grtt_interval < grtt_interval_min)
@ -3047,10 +3145,12 @@ void NormSession::SetGrttProbingMode(ProbingMode probingMode)
bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
{
// 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_timer.Deactivate();
if (probe_timer.IsActive())
probe_timer.Deactivate();
return false;
}
else if (0.0 == tx_rate)
@ -3100,13 +3200,17 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
// Update grtt estimate
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 +
0.5 * grtt_current_peak;
grtt_current_peak = 0.0;
grtt_decrease_delay_count = DEFAULT_GRTT_DECREASE_DELAY;
}
}*/
}
else
{
@ -3126,6 +3230,11 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
grtt_quantized = NormQuantizeRtt(grtt_measured);
// Recalculate grtt_advertise since quantization rounds upward
grtt_advertised = NormUnquantizeRtt(grtt_quantized);
if (grtt_advertised > grtt_max)
{
grtt_quantized = NormQuantizeRtt(grtt_max);
grtt_advertised = NormUnquantizeRtt(grtt_quantized);
}
if (grttQuantizedOld != grtt_quantized)
DMSG(4, "NormSession::OnProbeTimeout() node>%lu decreased to new grtt to: %lf sec\n",
LocalNodeId(), grtt_advertised);
@ -3198,8 +3307,12 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
else
feedbackAge -= 1.0e-06*((double)(feedbackTime.tv_usec - currentTime.tv_usec));
double maxFeedbackAge = 5 * grtt_advertised;
if (maxFeedbackAge < 0.100)
maxFeedbackAge = 0.100; // due computer clock coarseness
// Safety bound to compensate for 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)
next->SetActive(false);
}
@ -3223,9 +3336,10 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
// Determine next probe_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);
if (nominalInterval > probeInterval) probeInterval = nominalInterval;
if (nominalInterval > grtt_max) nominalInterval = grtt_max;
if (nominalInterval > probeInterval) probeInterval = nominalInterval; */
// Set probe_timer interval for next probe
probe_timer.SetInterval(probeInterval);
@ -3254,9 +3368,12 @@ void NormSession::AdjustRate(bool onResponse)
if (cc_slow_start)
{
txRate = clr->GetRate();
DMSG(6, "NormSession::AdjustRate(slow start) clr>%lu newRate>%lf (oldRate>%lf sentRate>%lf clrRate>%lf\n",
clr->GetId(), txRate*8.0/1000.0, tx_rate*8.0/1000.0, sent_rate*8.0/1000.0,
clr->GetRate()*8.0/1000.0);
if (GetDebugLevel() >= 6)
{
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
{
@ -3271,8 +3388,17 @@ void NormSession::AdjustRate(bool onResponse)
txRate = clrRate;
}
DMSG(6, "NormSession::AdjustRate(stdy state) clr>%lu newRate>%lf (rtt>%lf loss>%lf)\n",
clr->GetId(), txRate*8.0/1000.0, clr->GetRtt(), clr->GetLoss());
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)
@ -3305,38 +3431,30 @@ void NormSession::AdjustRate(bool onResponse)
// reduce rate if no active clr
txRate *= 0.5;
}
// Don't let txRate below MIN(one segment per grtt, one segment per 4 seconds)
double minRate = ((double)segment_size) / grtt_measured;
if (minRate > ((double)(segment_size >> 2)))
minRate = (double)(segment_size >> 2);
if (txRate < minRate)
txRate = minRate;
// Keep "tx_rate" within user set rate bounds (if any)
if ((tx_rate_min >= 0.0) && (txRate < tx_rate_min))
txRate = tx_rate_min;
// Keep "tx_rate" within default or user set rate bounds (if any)
double minRate;
if(tx_rate_min > 0.0)
{
minRate = tx_rate_min;
}
else
{
// Don't let txRate below MIN(one segment per grtt, one segment per second)
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))
txRate = tx_rate_max;
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;
::ProtoSystemTime(currentTime);
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()
bool NormSession::OnReportTimeout(ProtoTimer& /*theTimer*/)
@ -3360,16 +3478,17 @@ bool NormSession::OnReportTimeout(ProtoTimer& /*theTimer*/)
if (IsServer())
{
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",
((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)
{
const NormCCNode* clr = (const NormCCNode*)cc_node_list.Head();
if (clr)
DMSG(2, " clr>%lu rate>%9.3lf rtt>%lf loss>%lf\n", clr->GetId(),
clr->GetRate()*8.0/1000.0, clr->GetRtt(), clr->GetLoss());
}
DMSG(2, " clr>%lu rate>%9.3lf rtt>%lf loss>%lf %s\n", clr->GetId(),
8.0e-03*clr->GetRate(), clr->GetRtt(), clr->GetLoss(), cc_slow_start ? "(slow_start)" : "");
}
}
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, " rxObjects> completed>%lu pending>%lu failed:%lu\n",
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->BufferOverunCount());
DMSG(2, " resyncs>%lu nacks>%lu suppressed>%lu\n", next->ResyncCount(),
next->NackCount(),
next->SuppressCount());
DMSG(2, " resyncs>%lu nacks>%lu suppressed>%lu\n",
next->ResyncCount() ? next->ResyncCount() - 1 : 0, // "ResyncCount()" is reall "SyncCount()"
next->NackCount(),
next->SuppressCount());
}
} // end if (IsClient())

View File

@ -121,6 +121,14 @@ class NormSession
ttl = result ? theTTL : ttl;
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 result = tx_socket->IsOpen() ? tx_socket->SetLoopback(state) : true;
@ -128,7 +136,11 @@ class NormSession
return result;
}
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);
NormSessionMgr& GetSessionMgr() {return session_mgr;}
@ -139,7 +151,10 @@ class NormSession
{return rx_socket.SetRxBufferSize(bufferSize);}
// 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
void SetTxRate(double txRate)
{
@ -384,8 +399,10 @@ class NormSession
NormNodeId local_node_id;
ProtoAddress address; // session destination address & port
UINT8 ttl; // session multicast ttl
UINT8 tos; // session IPv4 TOS (or IPv6 traffic class - TBD)
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];
double tx_rate; // bytes per second
double tx_rate_min;
@ -437,6 +454,7 @@ class NormSession
bool probe_proactive;
bool probe_pending; // true while CMD(CC) enqueued
bool probe_reset;
bool probe_data_check; // refrain cc probe until data is send
struct timeval probe_time_last;
double grtt_interval; // current GRTT update interval
@ -460,9 +478,7 @@ class NormSession
UINT8 cc_sequence;
NormNodeList cc_node_list;
bool cc_slow_start;
double sent_rate; // measured sent rate
struct timeval prev_update_time; // for sent_rate measurement
unsigned long sent_accumulator; // for sent_rate measurement
unsigned long sent_accumulator; // for sentRate measurement
double nominal_packet_size;
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;
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));
}
else
@ -494,7 +494,7 @@ bool NormSimAgent::ProcessCommand(const char* cmd, const char* val)
DMSG(0, "NormSimAgent::ProcessCommand(unicastNacks) invalid argument!\n");
return false;
}
if (session) session->SetUnicastNacks(unicast_nacks);
if (session) session->ClientSetUnicastNacks(unicast_nacks);
return true;
}
else if (!strncmp("silentClient", cmd, len))
@ -590,8 +590,6 @@ bool NormSimAgent::SendMessage(unsigned int len, const char* txBuffer)
void NormSimAgent::OnInputReady()
{
//TRACE("NormSimAgent::OnInputReady() index:%lu len:%lu\n",
// tx_msg_index, tx_msg_len);
if (tx_msg_index < tx_msg_len)
{
unsigned int bytesWrote = stream->Write(tx_msg_buffer+tx_msg_index,
@ -618,6 +616,7 @@ bool NormSimAgent::FlushStream()
else
{
DMSG(0, "NormSimAgent::FlushStream() no output stream to flush\n");
return false;
}
} // end NormSimAgent::FlushStream()
@ -630,6 +629,7 @@ void NormSimAgent::Notify(NormController::Event event,
{
switch (event)
{
//case TX_QUEUE_VACANCY:
case TX_QUEUE_EMPTY:
// Can queue a new object or write to stream for transmission
if (object && (object == stream))
@ -638,8 +638,7 @@ void NormSimAgent::Notify(NormController::Event event,
{
// sending a dummy byte stream
char buffer[NormMsg::MAX_SIZE];
unsigned int count =
stream->Write(buffer, segment_size, false);
stream->Write(buffer, segment_size, false);
}
else
{
@ -663,7 +662,6 @@ void NormSimAgent::Notify(NormController::Event event,
case RX_OBJECT_NEW:
{
//TRACE("NormSimAgent::Notify(RX_OBJECT_NEW) ...\n");
// It's up to the app to "accept" the object
switch (object->GetType())
{
@ -695,23 +693,26 @@ void NormSimAgent::Notify(NormController::Event event,
case NormObject::DATA:
DMSG(0, "NormSimAgent::Notify() FILE/DATA objects not _yet_ supported...\n");
break;
default:
DMSG(0, "NormSimAgent::Notify() INVALID object type!\n");
ASSERT(0);
break;
}
break;
}
case RX_OBJECT_INFO:
//TRACE("NormSimAgent::Notify(RX_OBJECT_INFO) ...\n");
switch(object->GetType())
{
case NormObject::FILE:
case NormObject::DATA:
case NormObject::STREAM:
default:
break;
} // end switch(object->GetType())
break;
case RX_OBJECT_UPDATE:
//TRACE("NormSimAgent::Notify(RX_OBJECT_UPDATE) ...\n");
case RX_OBJECT_UPDATED:
switch (object->GetType())
{
case NormObject::FILE:
@ -830,6 +831,10 @@ void NormSimAgent::Notify(NormController::Event event,
case NormObject::DATA:
DMSG(0, "NormSimAgent::Notify() FILE/DATA objects not _yet_ supported...\n");
break;
default:
// should never occur
break;
} // end switch (object->GetType())
break;
case RX_OBJECT_COMPLETED:
@ -839,16 +844,19 @@ void NormSimAgent::Notify(NormController::Event event,
case NormObject::FILE:
//DMSG(0, "norm: Completed rx file: %s\n", ((NormFileObject*)object)->Path());
break;
case NormObject::STREAM:
ASSERT(0);
//DMSG(0, "norm: Completed rx stream ...\n");
break;
case NormObject::DATA:
ASSERT(0);
break;
default:
break;
}
break;
}
default:
DMSG(0, "NormSimAgent::Notify() unhandled NormEvent type\n");
} // end switch(event)
} // end NormSimAgent::Notify()
@ -875,7 +883,7 @@ bool NormSimAgent::OnIntervalTimeout(ProtoTimer& theTimer)
{
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);
return true;
@ -917,7 +925,8 @@ bool NormSimAgent::StartServer()
session->ServerSetGroupSize(group_size);
session->ServerSetGrtt(grtt_estimate);
// 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");
session_mgr.Destroy();
@ -961,7 +970,7 @@ bool NormSimAgent::StartClient()
session->SetTxLoss(tx_loss);
session->SetRxLoss(rx_loss);
session->SetUnicastNacks(unicast_nacks);
session->ClientSetUnicastNacks(unicast_nacks);
session->ClientSetSilent(silent_client);
// StartClient(bufferSize)

View File

@ -65,12 +65,14 @@ int main(int argc, char* argv[])
6003,
localId);
//NormSetTOS(session, 0x20);
// NOTE: These are debugging routines available (not for normal app use)
SetDebugLevel(2);
// Uncomment to turn on debug NORM message tracing
//NormSetMessageTrace(session, true);
// Uncomment to turn on some random packet loss
//NormSetTxLoss(session, 10.0); // 10% packet loss
NormSetTxLoss(session, 25.0); // 10% packet loss
//NormSetRxLoss(session, 20.0);
struct timeval currentTime;
ProtoSystemTime(currentTime);
@ -78,19 +80,21 @@ int main(int argc, char* argv[])
// (and a different sender sessionId)
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())
NormSetCongestionControl(session, true);
//NormSetCongestionControl(session, true);
NormSetTransmitRateBounds(session, 1000.0, -1.0);
NormSetDefaultRepairBoundary(session, NORM_BOUNDARY_BLOCK);
// Uncomment to use a _specific_ transmit port number
// (Can be the same as session port (rx port), but this
// is _not_ recommended when unicast feedback may be
// possible!
// is _not_ recommended when unicast feedback may be
// possible!)
//NormSetTxPort(session, 6001);
@ -101,10 +105,12 @@ int main(int argc, char* argv[])
NormSetRxPortReuse(session, true);
// Uncomment to receive your own traffic
//NormSetLoopback(session, true);
NormSetLoopback(session, true);
//NormSetSilentReceiver(session, true);
// Uncomment this line to participate as a receiver
//NormStartReceiver(session, 1024*1024);
NormStartReceiver(session, 1024*1024);
// Uncomment to set large rx socket buffer size
// (might be needed for high rate sessions)
@ -114,7 +120,9 @@ int main(int argc, char* argv[])
NormSessionId sessionId = (NormSessionId)rand();
// 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
// (might be needed for high rate sessions)
@ -128,7 +136,7 @@ int main(int argc, char* argv[])
const char* fileName = "file1.jpg";
const char* fileName2 = "file2.jpg";
// Uncomment this line to send a stream instead of the file
stream = NormStreamOpen(session, 10*1024*1024);
stream = NormStreamOpen(session, 2*1024*1024);
// NORM_FLUSH_PASSIVE automatically flushes full writes to
// the stream.
@ -139,21 +147,26 @@ int main(int argc, char* argv[])
int txIndex = 0;
int txLen = 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;
int msgCount = 0;
int recvCount = -1; // used to monitor reliable stream reception
int sendCount = 0;
int sendMax = -1; // -1 means unlimited
int sendMax = 300;//-1; // -1 means unlimited
NormEvent theEvent;
while (NormGetNextEvent(instance, &theEvent))
{
switch (theEvent.type)
{
case NORM_TX_QUEUE_VACANCY:
case NORM_TX_QUEUE_EMPTY:
fprintf(stderr, "stopping ....\n");
NormStopInstance(instance);
/*if (NORM_TX_QUEUE_VACANCY == theEvent.type)
TRACE("NORM_TX_QUEUE_VACANCY ...\n");
else
@ -167,9 +180,9 @@ int main(int argc, char* argv[])
{
if (0 == txLen)
{
// Write a message to the "txBuffer"
memset(txBuffer, 'a', 1037);
sprintf(txBuffer+1037, "normTest says hello %d ...\n", sendCount);
memset(txBuffer, 'a', STREAM_MSG_PREFIX_SIZE);
// Write a message into the "txBuffer" for transmission
sprintf(txBuffer+STREAM_MSG_PREFIX_SIZE, " normTest says hello %d ...\n", sendCount);
txLen = strlen(txBuffer);
}
unsigned int want = txLen - txIndex;
@ -178,18 +191,18 @@ int main(int argc, char* argv[])
txIndex += put;
if (txIndex == txLen)
{
// Instead of "NormStreamSetFlushMode(stream, NORM_FLUSH_PASSIVE)" above
// and "NormStreamMarkEom()" here, I could have used
// _Instead_ of "NormStreamSetAutoFlush(stream, NORM_FLUSH_PASSIVE)" above
// _and_ "NormStreamMarkEom()" here, I could have used
// "NormStreamFlush(stream, true)" here to perform explicit flushing
// 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()"
NormStreamMarkEom(stream);
txLen = txIndex = 0;
sendCount++;
if (sendCount == 15)
{
NormSetWatermark(session, stream);
//NormSetWatermark(session, stream);
}
if ((sendMax > 0) && (sendCount >= sendMax))
{
@ -280,57 +293,82 @@ int main(int argc, char* argv[])
rxBuffer[rxIndex] = '\0';
if (rxIndex > 0)
{
char* ptr = strchr(rxBuffer, '\n');
if (ptr)
// The '\n' indicates we have received an entire message
int parsedLen = 0;
bool searching = true;
char* startPtr = rxBuffer;
while (searching)
{
// Save sub-string length
len = ptr - rxBuffer + 1;
// Validate string
if (memcmp(rxBuffer, refBuffer, 1037))
ptr = (char*)NULL;
else
ptr = strstr(rxBuffer, "hello");
if (NULL != ptr)
char* endPtr = strchr(startPtr, '\n');
if (endPtr)
{
int value;
if (1 == sscanf(ptr, "hello %d", &value))
// Save sub-string message length
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))
TRACE("WARNING! possible break? value:%d recvCount:%d\n",
value, recvCount);
else
int value;
if (1 == sscanf(ptr, "hello %d", &value))
{
msgCount++; // successful recv
//else
// TRACE("validated recv msg len:%d\n", len);
if (recvCount >= 0)
{
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;
//if (0 == msgCount % 100)
// TRACE("recv stream msg count: %d\n", msgCount);
else
{
TRACE("couldn't find \"hello\"!? len:%d in %s\n", len, rxBuffer);
ASSERT(0);
}
}
else
{
TRACE("couldn't find index!?\n");
TRACE("invalid received message!?\n");
ASSERT(0);
}
if ((unsigned int)rxIndex > len)
if (parsedLen >= rxIndex)
{
memmove(rxBuffer, rxBuffer+len, rxIndex - len);
rxIndex -= len;
rxIndex = 0;
searching = false;
}
else
{
rxIndex = 0;
startPtr = rxBuffer + parsedLen;
}
} // end if (endPtr)
else if (parsedLen > 0)
{
memmove(rxBuffer, rxBuffer+parsedLen, rxIndex - parsedLen);
rxIndex -= parsedLen;
searching = false;
}
else
{
TRACE("invalid string!?\n");
ASSERT(0);
searching = false;
}
}
} // end while(searching)
}
}
else

View File

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

View File

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

View File

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

View File

@ -53,6 +53,11 @@ libnorm.a: $(LIB_OBJ)
libnorm.so: $(LIB_OBJ)
$(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_OBJ = $(SIM_SRC:.cpp=-sim.o)
@ -74,7 +79,7 @@ TEST_SRC = $(COMMON)/normTest.cpp
TEST_OBJ = $(TEST_SRC:.cpp=.o)
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_SRC = $(COMMON)/raft.cpp

View File

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

View File

@ -16,7 +16,12 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "normTest", "normTest.vcproj", "{32CF83E0-D2E0-4E43-8F7B-72BD0AB64647}"
ProjectSection(ProjectDependencies) = postProject
{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
EndProject
Global
@ -41,6 +46,10 @@ Global
{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.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
GlobalSection(ExtensibilityGlobals) = postSolution
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"
PrecompiledHeaderFile=".\Debug/NormLib.pch"
AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/"
ObjectFile="Norm.lib"
ProgramDataBaseFileName=".\Debug/"
WarningLevel="3"
SuppressStartupBanner="TRUE"
@ -38,7 +38,7 @@
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile=".\Debug\NormLib.lib"
OutputFile="$(OutDir)/NormLib.lib"
SuppressStartupBanner="TRUE"/>
<Tool
Name="VCMIDLTool"/>
@ -81,7 +81,6 @@
UsePrecompiledHeader="2"
PrecompiledHeaderFile=".\Release/NormLib.pch"
AssemblerListingLocation=".\Release/"
ObjectFile=".\Release/"
ProgramDataBaseFileName=".\Release/"
WarningLevel="3"
SuppressStartupBanner="TRUE"
@ -90,7 +89,7 @@
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile=".\Release\NormLib.lib"
OutputFile="$(OutDir)/NormLib.lib"
SuppressStartupBanner="TRUE"/>
<Tool
Name="VCMIDLTool"/>

View File

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